From 1880faf8a005a712f5c3e2e52fdbf04b87067066 Mon Sep 17 00:00:00 2001 From: Dan Rumney Date: Thu, 15 Jun 2023 12:52:45 -0500 Subject: [PATCH 1/5] fix(packages/grpc-js/test/assert2): move assert2 into its own file Moving from exporting a namespace to just putting assert2 functions into their own files Fixes #2464 --- packages/grpc-js/test/assert2.ts | 93 ++++++++++++++++++++++++++++++++ packages/grpc-js/test/common.ts | 83 ++-------------------------- 2 files changed, 96 insertions(+), 80 deletions(-) create mode 100644 packages/grpc-js/test/assert2.ts diff --git a/packages/grpc-js/test/assert2.ts b/packages/grpc-js/test/assert2.ts new file mode 100644 index 000000000..d3912a928 --- /dev/null +++ b/packages/grpc-js/test/assert2.ts @@ -0,0 +1,93 @@ +/* + * 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'; + +const toCall = new Map<() => void, number>(); +const afterCallsQueue: Array<() => void> = []; + +/** + * Assert that the given function doesn't throw an error, and then return + * its value. + * @param fn The function to evaluate. + */ +export function noThrowAndReturn(fn: () => T): T { + try { + return fn(); + } catch (e) { + assert.throws(() => { + throw e; + }); + throw e; // for type safety only + } +} + +/** + * Helper function that returns true when every function wrapped with + * mustCall has been called. + */ +function mustCallsSatisfied(): boolean { + let result = true; + toCall.forEach(value => { + result = result && value === 0; + }); + return result; +} + +export function clearMustCalls(): void { + afterCallsQueue.length = 0; +} + +/** + * 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 { + const existingValue = toCall.get(fn); + if (existingValue !== undefined) { + toCall.set(fn, existingValue + 1); + } else { + toCall.set(fn, 1); + } + return (...args: any[]) => { + const result = fn(...args); + const existingValue = toCall.get(fn); + if (existingValue !== undefined) { + toCall.set(fn, existingValue - 1); + } + if (mustCallsSatisfied()) { + afterCallsQueue.forEach(fn => fn()); + afterCallsQueue.length = 0; + } + return result; + }; +} + +/** + * Calls the given function when every function that was wrapped with + * mustCall has been called. + * @param fn The function to call once all mustCall-wrapped functions have + * been called. + */ +export function afterMustCallsSatisfied(fn: () => void): void { + if (!mustCallsSatisfied()) { + afterCallsQueue.push(fn); + } else { + fn(); + } +} diff --git a/packages/grpc-js/test/common.ts b/packages/grpc-js/test/common.ts index 24cb71650..16b393b55 100644 --- a/packages/grpc-js/test/common.ts +++ b/packages/grpc-js/test/common.ts @@ -16,7 +16,7 @@ */ import * as loader from '@grpc/proto-loader'; -import * as assert from 'assert'; +import * as assert2 from './assert2'; import { GrpcObject, loadPackageDefinition } from '../src/make-client'; @@ -32,86 +32,9 @@ export function mockFunction(): never { throw new Error('Not implemented'); } -export namespace assert2 { - const toCall = new Map<() => void, number>(); - const afterCallsQueue: Array<() => void> = []; - - /** - * Assert that the given function doesn't throw an error, and then return - * its value. - * @param fn The function to evaluate. - */ - export function noThrowAndReturn(fn: () => T): T { - try { - return fn(); - } catch (e) { - assert.throws(() => { - throw e; - }); - throw e; // for type safety only - } - } - - /** - * Helper function that returns true when every function wrapped with - * mustCall has been called. - */ - function mustCallsSatisfied(): boolean { - let result = true; - toCall.forEach(value => { - result = result && value === 0; - }); - return result; - } - - export function clearMustCalls(): void { - afterCallsQueue.length = 0; - } - - /** - * 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 { - const existingValue = toCall.get(fn); - if (existingValue !== undefined) { - toCall.set(fn, existingValue + 1); - } else { - toCall.set(fn, 1); - } - return (...args: any[]) => { - const result = fn(...args); - const existingValue = toCall.get(fn); - if (existingValue !== undefined) { - toCall.set(fn, existingValue - 1); - } - if (mustCallsSatisfied()) { - afterCallsQueue.forEach(fn => fn()); - afterCallsQueue.length = 0; - } - return result; - }; - } - - /** - * Calls the given function when every function that was wrapped with - * mustCall has been called. - * @param fn The function to call once all mustCall-wrapped functions have - * been called. - */ - export function afterMustCallsSatisfied(fn: () => void): void { - if (!mustCallsSatisfied()) { - afterCallsQueue.push(fn); - } else { - fn(); - } - } -} - export function loadProtoFile(file: string): GrpcObject { const packageDefinition = loader.loadSync(file, protoLoaderOptions); return loadPackageDefinition(packageDefinition); } + +export { assert2 }; From e3522bb53bbd42ea81fedffa9015e4987ecb8fe0 Mon Sep 17 00:00:00 2001 From: Dan Rumney Date: Thu, 15 Jun 2023 12:54:15 -0500 Subject: [PATCH 2/5] refactor(grpc-js): convert from gts to eslint/prettier/tsconfig GTS provides config for ESLint, Prettier and TSConfig; this commit removes GTS, but brings over the configuration details Fixes #2464 --- packages/grpc-js/.eslintrc | 58 +++++++++++++++++++++++++++-- packages/grpc-js/package.json | 19 +++++++--- packages/grpc-js/prettier.config.js | 2 + packages/grpc-js/tsconfig.json | 14 ++++++- 4 files changed, 82 insertions(+), 11 deletions(-) diff --git a/packages/grpc-js/.eslintrc b/packages/grpc-js/.eslintrc index 64585682c..2f6bfd62d 100644 --- a/packages/grpc-js/.eslintrc +++ b/packages/grpc-js/.eslintrc @@ -1,11 +1,61 @@ { "root": true, - "extends": "./node_modules/gts", + + "extends": [ + "eslint:recommended", + "plugin:node/recommended", + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended" + ], + "plugins": ["node", "prettier", "@typescript-eslint"], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 2018, + "sourceType": "module" + }, + "ignorePatterns": ["**/generated/**", "**/node_modules/**", "**/build/**"], "rules": { - "node/no-unpublished-import": ["error", { + "node/no-unpublished-import": [ + "error", + { "tryExtensions": [".ts", ".js", ".json", ".node"] - }], + } + ], "@typescript-eslint/no-unused-vars": "off", - "node/no-unpublished-require": "off" + "node/no-unpublished-require": "off", + "prettier/prettier": "error", + "block-scoped-var": "error", + "eqeqeq": "error", + "no-var": "error", + "prefer-const": "error", + "no-case-declarations": "warn", + "no-restricted-properties": [ + "error", + { + "object": "describe", + "property": "only" + }, + { + "object": "it", + "property": "only" + } + ], + + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-warning-comments": "off", + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/no-var-requires": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/ban-types": "off", + "@typescript-eslint/camelcase": "off", + "node/no-missing-import": "off", + "node/no-empty-function": "off", + "node/no-unsupported-features/es-syntax": "off", + "node/no-missing-require": "off", + "node/shebang": "off", + "no-dupe-class-members": "off", + "require-atomic-updates": "off" } } diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index dd341ef03..c068b0e95 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -22,9 +22,15 @@ "@types/ncp": "^2.0.1", "@types/pify": "^3.0.2", "@types/semver": "^7.3.9", + "@typescript-eslint/eslint-plugin": "^5.59.11", + "@typescript-eslint/parser": "^5.59.11", + "@typescript-eslint/typescript-estree": "^5.59.11", "clang-format": "^1.0.55", + "eslint": "^8.42.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-prettier": "^4.2.1", "execa": "^2.0.3", - "gts": "^3.1.1", "gulp": "^4.0.2", "gulp-mocha": "^6.0.0", "lodash": "^4.17.4", @@ -32,10 +38,11 @@ "mocha-jenkins-reporter": "^0.4.1", "ncp": "^2.0.0", "pify": "^4.0.1", + "prettier": "^2.8.8", "rimraf": "^3.0.2", "semver": "^7.3.5", - "ts-node": "^8.3.0", - "typescript": "^4.8.4" + "ts-node": "^10.9.1", + "typescript": "^5.1.3" }, "contributors": [ { @@ -47,11 +54,11 @@ "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", + "lint": "eslint src/*.ts test/*.ts", "prepare": "npm run generate-types && npm run compile", "test": "gulp test", - "check": "gts check src/**/*.ts", - "fix": "gts fix src/*.ts", + "check": "npm run lint", + "fix": "eslint --fix src/*.ts test/*.ts", "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", diff --git a/packages/grpc-js/prettier.config.js b/packages/grpc-js/prettier.config.js index 92747c8cc..ecd1f4854 100644 --- a/packages/grpc-js/prettier.config.js +++ b/packages/grpc-js/prettier.config.js @@ -2,4 +2,6 @@ module.exports = { proseWrap: 'always', singleQuote: true, trailingComma: 'es5', + bracketSpacing: true, + arrowParens: 'avoid', }; diff --git a/packages/grpc-js/tsconfig.json b/packages/grpc-js/tsconfig.json index 310b633c7..d678782ce 100644 --- a/packages/grpc-js/tsconfig.json +++ b/packages/grpc-js/tsconfig.json @@ -1,6 +1,15 @@ { - "extends": "./node_modules/gts/tsconfig-google.json", "compilerOptions": { + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "declaration": true, + "forceConsistentCasingInFileNames": true, + "noEmitOnError": true, + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "pretty": true, + "sourceMap": true, + "strict": true, "lib": ["es2017"], "outDir": "build", "target": "es2017", @@ -12,5 +21,8 @@ "include": [ "src/**/*.ts", "test/**/*.ts" + ], + "exclude": [ + "node_modules" ] } From 208b79e6254540d818a8d560ef8e5760adbb421f Mon Sep 17 00:00:00 2001 From: Dan Rumney Date: Thu, 15 Jun 2023 13:01:38 -0500 Subject: [PATCH 3/5] refactor(packages/grpc-js/log.txt): remove extraneous file --- packages/grpc-js/log.txt | 971 --------------------------------------- 1 file changed, 971 deletions(-) delete mode 100644 packages/grpc-js/log.txt diff --git a/packages/grpc-js/log.txt b/packages/grpc-js/log.txt deleted file mode 100644 index 7a6bbc2c8..000000000 --- a/packages/grpc-js/log.txt +++ /dev/null @@ -1,971 +0,0 @@ -{ - 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 From 3bf2af1d70117f9f0ced8758b25e27a30776ae14 Mon Sep 17 00:00:00 2001 From: Dan Rumney Date: Thu, 15 Jun 2023 13:03:26 -0500 Subject: [PATCH 4/5] docs(apache-notice.md): add a notice acknowledging the use of GTS config settings This might actually be unnecessary; since I've copied over configuration settings from the GTS package, I figured I'd add this notice. It's in a file, since there's no capacity for adding comments in a JSON or .rc file. It feels doubtful that configuration settings fall under the auspices of the Apache License, but I'll leave that to the maintainers to decide. --- packages/grpc-js/apache-notice.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 packages/grpc-js/apache-notice.md diff --git a/packages/grpc-js/apache-notice.md b/packages/grpc-js/apache-notice.md new file mode 100644 index 000000000..703afce80 --- /dev/null +++ b/packages/grpc-js/apache-notice.md @@ -0,0 +1,4 @@ +The following files contain configuration settings that were derived from [the this commit](https://github.com/google/gts/commit/3b9ab6dd59691f77f5c5c632a44c6762ba4ef7c6) in the Google GTS repository: + - .eslintrc + - prettier.config.js + - tsconfig.json From cd24d6956d19015c58d661faca1155ee76428314 Mon Sep 17 00:00:00 2001 From: Dan Rumney Date: Thu, 15 Jun 2023 13:04:57 -0500 Subject: [PATCH 5/5] style: run eslint fix on codebase Fixes #2464 --- packages/grpc-js/src/admin.ts | 20 +- packages/grpc-js/src/call-credentials.ts | 6 +- packages/grpc-js/src/call-interface.ts | 22 +- packages/grpc-js/src/call-number.ts | 4 +- packages/grpc-js/src/call.ts | 25 +- packages/grpc-js/src/channel-credentials.ts | 46 +- packages/grpc-js/src/channel.ts | 17 +- packages/grpc-js/src/channelz.ts | 452 +++++++----- packages/grpc-js/src/client-interceptors.ts | 38 +- packages/grpc-js/src/client.ts | 140 ++-- .../grpc-js/src/compression-algorithms.ts | 4 +- packages/grpc-js/src/compression-filter.ts | 63 +- packages/grpc-js/src/control-plane-status.ts | 17 +- packages/grpc-js/src/deadline.ts | 8 +- packages/grpc-js/src/duration.ts | 6 +- packages/grpc-js/src/error.ts | 2 +- packages/grpc-js/src/experimental.ts | 14 +- packages/grpc-js/src/filter-stack.ts | 2 +- packages/grpc-js/src/http_proxy.ts | 24 +- packages/grpc-js/src/index.ts | 17 +- packages/grpc-js/src/internal-channel.ts | 244 +++++-- .../src/load-balancer-child-handler.ts | 7 +- .../src/load-balancer-outlier-detection.ts | 446 +++++++++--- .../grpc-js/src/load-balancer-pick-first.ts | 30 +- .../grpc-js/src/load-balancer-round-robin.ts | 25 +- packages/grpc-js/src/load-balancer.ts | 28 +- packages/grpc-js/src/load-balancing-call.ts | 301 +++++--- packages/grpc-js/src/logging.ts | 7 +- packages/grpc-js/src/make-client.ts | 2 +- .../grpc-js/src/max-message-size-filter.ts | 11 +- packages/grpc-js/src/metadata.ts | 17 +- packages/grpc-js/src/object-stream.ts | 22 +- packages/grpc-js/src/picker.ts | 4 +- packages/grpc-js/src/resolver-dns.ts | 29 +- packages/grpc-js/src/resolving-call.ts | 193 +++-- .../grpc-js/src/resolving-load-balancer.ts | 26 +- packages/grpc-js/src/retrying-call.ts | 308 ++++++-- packages/grpc-js/src/server-call.ts | 63 +- packages/grpc-js/src/server.ts | 484 ++++++++----- packages/grpc-js/src/service-config.ts | 145 +++- packages/grpc-js/src/subchannel-address.ts | 13 +- packages/grpc-js/src/subchannel-call.ts | 37 +- packages/grpc-js/src/subchannel-interface.ts | 10 +- packages/grpc-js/src/subchannel-pool.ts | 2 +- packages/grpc-js/src/subchannel.ts | 161 +++-- packages/grpc-js/src/transport.ts | 266 ++++--- .../grpc-js/test/test-call-credentials.ts | 37 +- .../grpc-js/test/test-call-propagation.ts | 244 ++++--- .../grpc-js/test/test-channel-credentials.ts | 70 +- packages/grpc-js/test/test-channelz.ts | 679 ++++++++++++------ packages/grpc-js/test/test-client.ts | 79 +- packages/grpc-js/test/test-deadline.ts | 55 +- .../test/test-global-subchannel-pool.ts | 97 ++- .../test/test-local-subchannel-pool.ts | 14 +- .../grpc-js/test/test-outlier-detection.ts | 237 +++--- .../grpc-js/test/test-prototype-pollution.ts | 8 +- packages/grpc-js/test/test-resolver.ts | 268 ++++--- packages/grpc-js/test/test-retry-config.ts | 176 +++-- packages/grpc-js/test/test-retry.ts | 192 +++-- .../grpc-js/test/test-server-deadlines.ts | 6 +- packages/grpc-js/test/test-server-errors.ts | 5 +- packages/grpc-js/test/test-server.ts | 168 +++-- packages/grpc-js/test/test-uri-parser.ts | 148 +++- 63 files changed, 4096 insertions(+), 2195 deletions(-) diff --git a/packages/grpc-js/src/admin.ts b/packages/grpc-js/src/admin.ts index 7745d07d8..4d26b89bd 100644 --- a/packages/grpc-js/src/admin.ts +++ b/packages/grpc-js/src/admin.ts @@ -15,8 +15,8 @@ * */ -import { ServiceDefinition } from "./make-client"; -import { Server, UntypedServiceImplementation } from "./server"; +import { ServiceDefinition } from './make-client'; +import { Server, UntypedServiceImplementation } from './server'; interface GetServiceDefinition { (): ServiceDefinition; @@ -26,14 +26,20 @@ interface GetHandlers { (): UntypedServiceImplementation; } -const registeredAdminServices: {getServiceDefinition: GetServiceDefinition, getHandlers: GetHandlers}[] = []; +const registeredAdminServices: { + getServiceDefinition: GetServiceDefinition; + getHandlers: GetHandlers; +}[] = []; -export function registerAdminService(getServiceDefinition: GetServiceDefinition, getHandlers: GetHandlers) { - registeredAdminServices.push({getServiceDefinition, getHandlers}); +export function registerAdminService( + getServiceDefinition: GetServiceDefinition, + getHandlers: GetHandlers +) { + registeredAdminServices.push({ getServiceDefinition, getHandlers }); } export function addAdminServicesToServer(server: Server): void { - for (const {getServiceDefinition, getHandlers} of registeredAdminServices) { + for (const { getServiceDefinition, getHandlers } of registeredAdminServices) { server.addService(getServiceDefinition(), getHandlers()); } -} \ 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 b98624ee2..b0013eeae 100644 --- a/packages/grpc-js/src/call-credentials.ts +++ b/packages/grpc-js/src/call-credentials.ts @@ -125,14 +125,14 @@ export abstract class CallCredentials { }); } 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); } ); @@ -152,7 +152,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-interface.ts b/packages/grpc-js/src/call-interface.ts index 283cb9b54..15035aeac 100644 --- a/packages/grpc-js/src/call-interface.ts +++ b/packages/grpc-js/src/call-interface.ts @@ -15,11 +15,11 @@ * */ -import { CallCredentials } from "./call-credentials"; -import { Status } from "./constants"; -import { Deadline } from "./deadline"; -import { Metadata } from "./metadata"; -import { ServerSurfaceCall } from "./server-call"; +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; @@ -38,7 +38,7 @@ export interface StatusObject { export type PartialStatusObject = Pick & { metadata: Metadata | null; -} +}; export const enum WriteFlags { BufferHint = 1, @@ -118,7 +118,7 @@ export class InterceptingListenerImpl implements InterceptingListener { onReceiveMetadata(metadata: Metadata): void { this.processingMetadata = true; - this.listener.onReceiveMetadata(metadata, (metadata) => { + this.listener.onReceiveMetadata(metadata, metadata => { this.processingMetadata = false; this.nextListener.onReceiveMetadata(metadata); this.processPendingMessage(); @@ -128,9 +128,9 @@ export class InterceptingListenerImpl implements InterceptingListener { // 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 */ + * be reordered with respect to the status */ this.processingMessage = true; - this.listener.onReceiveMessage(message, (msg) => { + this.listener.onReceiveMessage(message, msg => { this.processingMessage = false; if (this.processingMetadata) { this.pendingMessage = msg; @@ -142,7 +142,7 @@ export class InterceptingListenerImpl implements InterceptingListener { }); } onReceiveStatus(status: StatusObject): void { - this.listener.onReceiveStatus(status, (processedStatus) => { + this.listener.onReceiveStatus(status, processedStatus => { if (this.processingMetadata || this.processingMessage) { this.pendingStatus = processedStatus; } else { @@ -170,4 +170,4 @@ export interface Call { 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 index 48d34fac5..8c37d3f91 100644 --- a/packages/grpc-js/src/call-number.ts +++ b/packages/grpc-js/src/call-number.ts @@ -18,5 +18,5 @@ let nextCallNumber = 0; export function getNextCallNumber() { - return nextCallNumber++; -} \ No newline at end of file + return nextCallNumber++; +} diff --git a/packages/grpc-js/src/call.ts b/packages/grpc-js/src/call.ts index bb6d74ccf..a147c98bc 100644 --- a/packages/grpc-js/src/call.ts +++ b/packages/grpc-js/src/call.ts @@ -65,10 +65,8 @@ export type ClientWritableStream = { /** * A type representing the return value of a bidirectional stream method call. */ -export type ClientDuplexStream< - RequestType, - ResponseType -> = ClientWritableStream & ClientReadableStream; +export type ClientDuplexStream = + ClientWritableStream & ClientReadableStream; /** * Construct a ServiceError from a StatusObject. This function exists primarily @@ -76,16 +74,20 @@ export type ClientDuplexStream< * error is not necessarily a problem in gRPC itself. * @param status */ -export function callErrorFromStatus(status: StatusObject, callerStack: string): ServiceError { +export function callErrorFromStatus( + status: StatusObject, + callerStack: string +): ServiceError { const message = `${status.code} ${Status[status.code]}: ${status.details}`; const error = new Error(message); const stack = `${error.stack}\nfor call at\n${callerStack}`; - return Object.assign(new Error(message), status, {stack}); + return Object.assign(new Error(message), status, { stack }); } export class ClientUnaryCallImpl extends EventEmitter - implements ClientUnaryCall { + implements ClientUnaryCall +{ public call?: InterceptingCallInterface; constructor() { super(); @@ -102,7 +104,8 @@ export class ClientUnaryCallImpl export class ClientReadableStreamImpl extends Readable - implements ClientReadableStream { + implements ClientReadableStream +{ public call?: InterceptingCallInterface; constructor(readonly deserialize: (chunk: Buffer) => ResponseType) { super({ objectMode: true }); @@ -123,7 +126,8 @@ export class ClientReadableStreamImpl export class ClientWritableStreamImpl extends Writable - implements ClientWritableStream { + implements ClientWritableStream +{ public call?: InterceptingCallInterface; constructor(readonly serialize: (value: RequestType) => Buffer) { super({ objectMode: true }); @@ -156,7 +160,8 @@ export class ClientWritableStreamImpl export class ClientDuplexStreamImpl extends Duplex - implements ClientDuplexStream { + implements ClientDuplexStream +{ public call?: InterceptingCallInterface; constructor( readonly serialize: (value: RequestType) => Buffer, diff --git a/packages/grpc-js/src/channel-credentials.ts b/packages/grpc-js/src/channel-credentials.ts index fd9d7b571..dc6069c84 100644 --- a/packages/grpc-js/src/channel-credentials.ts +++ b/packages/grpc-js/src/channel-credentials.ts @@ -15,7 +15,12 @@ * */ -import { ConnectionOptions, createSecureContext, PeerCertificate, SecureContext } from 'tls'; +import { + ConnectionOptions, + createSecureContext, + PeerCertificate, + SecureContext, +} from 'tls'; import { CallCredentials } from './call-credentials'; import { CIPHER_SUITES, getDefaultRootsData } from './tls-helpers'; @@ -137,10 +142,7 @@ export abstract class ChannelCredentials { cert: certChain ?? undefined, ciphers: CIPHER_SUITES, }); - return new SecureChannelCredentialsImpl( - secureContext, - verifyOptions ?? {} - ); + return new SecureChannelCredentialsImpl(secureContext, verifyOptions ?? {}); } /** @@ -153,11 +155,11 @@ export abstract class ChannelCredentials { * @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 ?? {} - ) + static createFromSecureContext( + secureContext: SecureContext, + verifyOptions?: VerifyOptions + ): ChannelCredentials { + return new SecureChannelCredentialsImpl(secureContext, verifyOptions ?? {}); } /** @@ -196,19 +198,19 @@ class SecureChannelCredentialsImpl extends ChannelCredentials { private verifyOptions: VerifyOptions ) { super(); - this.connectionOptions = { - secureContext + this.connectionOptions = { + secureContext, }; // Node asserts that this option is a function, so we cannot pass undefined if (verifyOptions?.checkServerIdentity) { - this.connectionOptions.checkServerIdentity = verifyOptions.checkServerIdentity; + this.connectionOptions.checkServerIdentity = + verifyOptions.checkServerIdentity; } } compose(callCredentials: CallCredentials): ChannelCredentials { - const combinedCallCredentials = this.callCredentials.compose( - callCredentials - ); + const combinedCallCredentials = + this.callCredentials.compose(callCredentials); return new ComposedChannelCredentialsImpl(this, combinedCallCredentials); } @@ -225,9 +227,10 @@ class SecureChannelCredentialsImpl extends ChannelCredentials { } if (other instanceof SecureChannelCredentialsImpl) { return ( - this.secureContext === other.secureContext && - this.verifyOptions.checkServerIdentity === other.verifyOptions.checkServerIdentity - ); + this.secureContext === other.secureContext && + this.verifyOptions.checkServerIdentity === + other.verifyOptions.checkServerIdentity + ); } else { return false; } @@ -242,9 +245,8 @@ class ComposedChannelCredentialsImpl extends ChannelCredentials { super(callCreds); } compose(callCredentials: CallCredentials) { - const combinedCallCredentials = this.callCredentials.compose( - callCredentials - ); + const combinedCallCredentials = + this.callCredentials.compose(callCredentials); return new ComposedChannelCredentialsImpl( this.channelCredentials, combinedCallCredentials diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index aaf14bb22..7ce5a15f7 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -91,7 +91,6 @@ export interface Channel { } export class ChannelImplementation implements Channel { - private internalChannel: InternalChannel; constructor( @@ -133,13 +132,17 @@ export class ChannelImplementation implements Channel { deadline: Date | number, callback: (error?: Error) => void ): void { - this.internalChannel.watchConnectivityState(currentState, deadline, callback); + this.internalChannel.watchConnectivityState( + currentState, + deadline, + callback + ); } /** * 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.internalChannel.getChannelzRef(); @@ -160,6 +163,12 @@ export class ChannelImplementation implements Channel { 'Channel#createCall: deadline must be a number or Date' ); } - return this.internalChannel.createCall(method, deadline, host, parentCall, propagateFlags); + return this.internalChannel.createCall( + method, + deadline, + host, + parentCall, + propagateFlags + ); } } diff --git a/packages/grpc-js/src/channelz.ts b/packages/grpc-js/src/channelz.ts index 5a7a54760..1e2627a97 100644 --- a/packages/grpc-js/src/channelz.ts +++ b/packages/grpc-js/src/channelz.ts @@ -15,45 +15,55 @@ * */ -import { isIPv4, isIPv6 } from "net"; -import { ConnectivityState } from "./connectivity-state"; -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 { isIPv4, isIPv6 } from 'net'; +import { ConnectivityState } from './connectivity-state'; +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'; -import { registerAdminService } from "./admin"; -import { loadPackageDefinition } from "./make-client"; +import { registerAdminService } from './admin'; +import { loadPackageDefinition } from './make-client'; -export type TraceSeverity = 'CT_UNKNOWN' | 'CT_INFO' | 'CT_WARNING' | 'CT_ERROR'; +export type TraceSeverity = + | 'CT_UNKNOWN' + | 'CT_INFO' + | 'CT_WARNING' + | 'CT_ERROR'; export interface ChannelRef { kind: 'channel'; @@ -81,28 +91,28 @@ export interface SocketRef { function channelRefToMessage(ref: ChannelRef): ChannelRefMessage { return { channel_id: ref.id, - name: ref.name + name: ref.name, }; } function subchannelRefToMessage(ref: SubchannelRef): SubchannelRefMessage { return { subchannel_id: ref.id, - name: ref.name - } + name: ref.name, + }; } function serverRefToMessage(ref: ServerRef): ServerRefMessage { return { - server_id: ref.id - } + server_id: ref.id, + }; } function socketRefToMessage(ref: SocketRef): SocketRefMessage { return { socket_id: ref.id, - name: ref.name - } + name: ref.name, + }; } interface TraceEvent { @@ -124,20 +134,24 @@ const TARGET_RETAINED_TRACES = 32; export class ChannelzTrace { events: TraceEvent[] = []; creationTimestamp: Date; - eventsLogged: number = 0; + eventsLogged = 0; constructor() { this.creationTimestamp = new Date(); } - addTrace(severity: TraceSeverity, description: string, child?: ChannelRef | SubchannelRef) { + 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 + 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) { @@ -155,35 +169,53 @@ export class ChannelzTrace { 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 - } - }) + channel_ref: event.childChannel + ? channelRefToMessage(event.childChannel) + : null, + subchannel_ref: event.childSubchannel + ? subchannelRefToMessage(event.childSubchannel) + : null, + }; + }), }; } } export class ChannelzChildrenTracker { - private channelChildren: Map = new Map(); - private subchannelChildren: Map = new Map(); - private socketChildren: Map = new Map(); + private channelChildren: Map = + new Map(); + private subchannelChildren: Map< + number, + { ref: SubchannelRef; count: number } + > = 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}; + const 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}; + case 'subchannel': { + const 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}; + case 'socket': { + const trackedChild = this.socketChildren.get(child.id) ?? { + ref: child, + count: 0, + }; trackedChild.count += 1; this.socketChildren.set(child.id, trackedChild); break; @@ -194,7 +226,7 @@ export class ChannelzChildrenTracker { unrefChild(child: ChannelRef | SubchannelRef | SocketRef) { switch (child.kind) { case 'channel': { - let trackedChild = this.channelChildren.get(child.id); + const trackedChild = this.channelChildren.get(child.id); if (trackedChild !== undefined) { trackedChild.count -= 1; if (trackedChild.count === 0) { @@ -206,7 +238,7 @@ export class ChannelzChildrenTracker { break; } case 'subchannel': { - let trackedChild = this.subchannelChildren.get(child.id); + const trackedChild = this.subchannelChildren.get(child.id); if (trackedChild !== undefined) { trackedChild.count -= 1; if (trackedChild.count === 0) { @@ -218,7 +250,7 @@ export class ChannelzChildrenTracker { break; } case 'socket': { - let trackedChild = this.socketChildren.get(child.id); + const trackedChild = this.socketChildren.get(child.id); if (trackedChild !== undefined) { trackedChild.count -= 1; if (trackedChild.count === 0) { @@ -234,25 +266,25 @@ export class ChannelzChildrenTracker { getChildLists(): ChannelzChildren { const channels: ChannelRef[] = []; - for (const {ref} of this.channelChildren.values()) { + for (const { ref } of this.channelChildren.values()) { channels.push(ref); } const subchannels: SubchannelRef[] = []; - for (const {ref} of this.subchannelChildren.values()) { + for (const { ref } of this.subchannelChildren.values()) { subchannels.push(ref); } const sockets: SocketRef[] = []; - for (const {ref} of this.socketChildren.values()) { + for (const { ref } of this.socketChildren.values()) { sockets.push(ref); } - return {channels, subchannels, sockets}; + return { channels, subchannels, sockets }; } } export class ChannelzCallTracker { - callsStarted: number = 0; - callsSucceeded: number = 0; - callsFailed: number = 0; + callsStarted = 0; + callsSucceeded = 0; + callsFailed = 0; lastCallStartedTimestamp: Date | null = null; addCallStarted() { @@ -281,7 +313,7 @@ export interface ChannelInfo { children: ChannelzChildren; } -export interface SubchannelInfo extends ChannelInfo {} +export type SubchannelInfo = ChannelInfo; export interface ServerInfo { trace: ChannelzTrace; @@ -347,43 +379,60 @@ const subchannels: (SubchannelEntry | undefined)[] = []; const servers: (ServerEntry | undefined)[] = []; const sockets: (SocketEntry | undefined)[] = []; -export function registerChannelzChannel(name: string, getInfo: () => ChannelInfo, channelzEnabled: boolean): ChannelRef { +export function registerChannelzChannel( + name: string, + getInfo: () => ChannelInfo, + channelzEnabled: boolean +): ChannelRef { const id = getNextId(); - const ref: ChannelRef = {id, name, kind: 'channel'}; + const ref: ChannelRef = { id, name, kind: 'channel' }; if (channelzEnabled) { channels[id] = { ref, getInfo }; } return ref; } -export function registerChannelzSubchannel(name: string, getInfo:() => SubchannelInfo, channelzEnabled: boolean): SubchannelRef { +export function registerChannelzSubchannel( + name: string, + getInfo: () => SubchannelInfo, + channelzEnabled: boolean +): SubchannelRef { const id = getNextId(); - const ref: SubchannelRef = {id, name, kind: 'subchannel'}; + const ref: SubchannelRef = { id, name, kind: 'subchannel' }; if (channelzEnabled) { subchannels[id] = { ref, getInfo }; } return ref; } -export function registerChannelzServer(getInfo: () => ServerInfo, channelzEnabled: boolean): ServerRef { +export function registerChannelzServer( + getInfo: () => ServerInfo, + channelzEnabled: boolean +): ServerRef { const id = getNextId(); - const ref: ServerRef = {id, kind: 'server'}; + const ref: ServerRef = { id, kind: 'server' }; if (channelzEnabled) { servers[id] = { ref, getInfo }; } return ref; } -export function registerChannelzSocket(name: string, getInfo: () => SocketInfo, channelzEnabled: boolean): SocketRef { +export function registerChannelzSocket( + name: string, + getInfo: () => SocketInfo, + channelzEnabled: boolean +): SocketRef { const id = getNextId(); - const ref: SocketRef = {id, name, kind: 'socket'}; + const ref: SocketRef = { id, name, kind: 'socket' }; if (channelzEnabled) { - sockets[id] = { ref, getInfo}; + sockets[id] = { ref, getInfo }; } return ref; } -export function unregisterChannelzRef(ref: ChannelRef | SubchannelRef | ServerRef | SocketRef) { +export function unregisterChannelzRef( + ref: ChannelRef | SubchannelRef | ServerRef | SocketRef +) { switch (ref.kind) { case 'channel': delete channels[ref.id]; @@ -407,7 +456,7 @@ export function unregisterChannelzRef(ref: ChannelRef | SubchannelRef | ServerRe */ function parseIPv6Section(addressSection: string): [number, number] { const numberValue = Number.parseInt(addressSection, 16); - return [numberValue / 256 | 0, numberValue % 256]; + return [(numberValue / 256) | 0, numberValue % 256]; } /** @@ -420,7 +469,9 @@ function parseIPv6Chunk(addressChunk: string): number[] { if (addressChunk === '') { return []; } - const bytePairs = addressChunk.split(':').map(section => parseIPv6Section(section)); + const bytePairs = addressChunk + .split(':') + .map(section => parseIPv6Section(section)); const result: number[] = []; return result.concat(...bytePairs); } @@ -429,11 +480,15 @@ function parseIPv6Chunk(addressChunk: string): number[] { * 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 + * @returns */ function ipAddressStringToBuffer(ipAddress: string): Buffer | null { if (isIPv4(ipAddress)) { - return Buffer.from(Uint8Array.from(ipAddress.split('.').map(segment => Number.parseInt(segment)))); + return Buffer.from( + Uint8Array.from( + ipAddress.split('.').map(segment => Number.parseInt(segment)) + ) + ); } else if (isIPv6(ipAddress)) { let leftSection: string; let rightSection: string; @@ -447,38 +502,43 @@ function ipAddressStringToBuffer(ipAddress: string): Buffer | null { } const leftBuffer = Buffer.from(parseIPv6Chunk(leftSection)); const rightBuffer = Buffer.from(parseIPv6Chunk(rightSection)); - const middleBuffer = Buffer.alloc(16 - leftBuffer.length - rightBuffer.length, 0); + const middleBuffer = Buffer.alloc( + 16 - leftBuffer.length - rightBuffer.length, + 0 + ); return Buffer.concat([leftBuffer, middleBuffer, rightBuffer]); } else { return null; } } -function connectivityStateToMessage(state: ConnectivityState): ChannelConnectivityState__Output { +function connectivityStateToMessage( + state: ConnectivityState +): ChannelConnectivityState__Output { switch (state) { case ConnectivityState.CONNECTING: return { - state: 'CONNECTING' + state: 'CONNECTING', }; case ConnectivityState.IDLE: return { - state: 'IDLE' + state: 'IDLE', }; case ConnectivityState.READY: return { - state: 'READY' + state: 'READY', }; case ConnectivityState.SHUTDOWN: return { - state: 'SHUTDOWN' + state: 'SHUTDOWN', }; case ConnectivityState.TRANSIENT_FAILURE: return { - state: 'TRANSIENT_FAILURE' + state: 'TRANSIENT_FAILURE', }; default: return { - state: 'UNKNOWN' + state: 'UNKNOWN', }; } } @@ -490,8 +550,8 @@ function dateToProtoTimestamp(date?: Date | null): Timestamp | null { const millisSinceEpoch = date.getTime(); return { seconds: (millisSinceEpoch / 1000) | 0, - nanos: (millisSinceEpoch % 1000) * 1_000_000 - } + nanos: (millisSinceEpoch % 1000) * 1_000_000, + }; } function getChannelMessage(channelEntry: ChannelEntry): ChannelMessage { @@ -504,28 +564,40 @@ function getChannelMessage(channelEntry: ChannelEntry): ChannelMessage { 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() + 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)) + 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 { +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 + code: Status.NOT_FOUND, + details: 'No channel data found for id ' + channelId, }); return; } - callback(null, {channel: getChannelMessage(channelEntry)}); + callback(null, { channel: getChannelMessage(channelEntry) }); } -function GetTopChannels(call: ServerUnaryCall, callback: sendUnaryData): void { +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); @@ -541,7 +613,7 @@ function GetTopChannels(call: ServerUnaryCall= servers.length + end: i >= servers.length, }); } @@ -553,27 +625,37 @@ function getServerMessage(serverEntry: ServerEntry): ServerMessage { 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() + last_call_started_timestamp: dateToProtoTimestamp( + resolvedInfo.callTracker.lastCallStartedTimestamp + ), + trace: resolvedInfo.trace.getTraceMessage(), }, - listen_socket: resolvedInfo.listenerChildren.sockets.map(ref => socketRefToMessage(ref)) + listen_socket: resolvedInfo.listenerChildren.sockets.map(ref => + socketRefToMessage(ref) + ), }; } -function GetServer(call: ServerUnaryCall, callback: sendUnaryData): void { +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 + code: Status.NOT_FOUND, + details: 'No server data found for id ' + serverId, }); return; } - callback(null, {server: getServerMessage(serverEntry)}); + callback(null, { server: getServerMessage(serverEntry) }); } -function GetServers(call: ServerUnaryCall, callback: sendUnaryData): void { +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); @@ -589,17 +671,20 @@ function GetServers(call: ServerUnaryCall= servers.length + end: i >= servers.length, }); } -function GetSubchannel(call: ServerUnaryCall, callback: sendUnaryData): void { +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 + code: Status.NOT_FOUND, + details: 'No subchannel data found for id ' + subchannelId, }); return; } @@ -612,58 +697,79 @@ function GetSubchannel(call: ServerUnaryCall socketRefToMessage(ref)) + socket_ref: resolvedInfo.children.sockets.map(ref => + socketRefToMessage(ref) + ), }; - callback(null, {subchannel: subchannelMessage}); + callback(null, { subchannel: subchannelMessage }); } -function subchannelAddressToAddressMessage(subchannelAddress: SubchannelAddress): Address { +function subchannelAddressToAddressMessage( + subchannelAddress: SubchannelAddress +): Address { if (isTcpSubchannelAddress(subchannelAddress)) { return { address: 'tcpip_address', tcpip_address: { - ip_address: ipAddressStringToBuffer(subchannelAddress.host) ?? undefined, - port: subchannelAddress.port - } + ip_address: + ipAddressStringToBuffer(subchannelAddress.host) ?? undefined, + port: subchannelAddress.port, + }, }; } else { return { address: 'uds_address', uds_address: { - filename: subchannelAddress.path - } + filename: subchannelAddress.path, + }, }; } } -function GetSocket(call: ServerUnaryCall, callback: sendUnaryData): void { +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 + 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 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: resolvedInfo.localAddress ? subchannelAddressToAddressMessage(resolvedInfo.localAddress) : null, - remote: resolvedInfo.remoteAddress ? subchannelAddressToAddressMessage(resolvedInfo.remoteAddress) : null, + local: resolvedInfo.localAddress + ? subchannelAddressToAddressMessage(resolvedInfo.localAddress) + : null, + remote: resolvedInfo.remoteAddress + ? subchannelAddressToAddressMessage(resolvedInfo.remoteAddress) + : null, remote_name: resolvedInfo.remoteName ?? undefined, security: securityMessage, data: { @@ -671,26 +777,44 @@ function GetSocket(call: ServerUnaryCall, callback: sendUnaryData): void { +function GetServerSockets( + call: ServerUnaryCall< + GetServerSocketsRequest__Output, + GetServerSocketsResponse + >, + 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 + code: Status.NOT_FOUND, + details: 'No server data found for id ' + serverId, }); return; } @@ -700,7 +824,9 @@ function GetServerSockets(call: ServerUnaryCall ref1.id - ref2.id); - const allSockets = 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++) { @@ -713,7 +839,7 @@ function GetServerSockets(call: ServerUnaryCall= allSockets.length + end: i >= allSockets.length, }); } @@ -725,7 +851,7 @@ export function getChannelzHandlers(): ChannelzHandlers { GetServers, GetSubchannel, GetSocket, - GetServerSockets + GetServerSockets, }; } @@ -737,22 +863,24 @@ export function getChannelzServiceDefinition(): ChannelzDefinition { } /* 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 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: [ - `${__dirname}/../../proto` - ] + includeDirs: [`${__dirname}/../../proto`], }); - const channelzGrpcObject = loadPackageDefinition(loadedProto) as unknown as ChannelzProtoGrpcType; - loadedChannelzDefinition = channelzGrpcObject.grpc.channelz.v1.Channelz.service; + const channelzGrpcObject = loadPackageDefinition( + loadedProto + ) as unknown as ChannelzProtoGrpcType; + loadedChannelzDefinition = + channelzGrpcObject.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/client-interceptors.ts b/packages/grpc-js/src/client-interceptors.ts index d95828550..56175ed80 100644 --- a/packages/grpc-js/src/client-interceptors.ts +++ b/packages/grpc-js/src/client-interceptors.ts @@ -176,10 +176,10 @@ const defaultRequester: FullRequester = { sendMessage: (message, next) => { next(message); }, - halfClose: (next) => { + halfClose: next => { next(); }, - cancel: (next) => { + cancel: next => { next(); }, }; @@ -254,7 +254,10 @@ export class InterceptingCall implements InterceptingCallInterface { private processPendingMessage() { if (this.pendingMessageContext) { - this.nextCall.sendMessageWithContext(this.pendingMessageContext, this.pendingMessage); + this.nextCall.sendMessageWithContext( + this.pendingMessageContext, + this.pendingMessage + ); this.pendingMessageContext = null; this.pendingMessage = null; } @@ -273,13 +276,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.processingMetadata = true; this.requester.start(metadata, fullInterceptingListener, (md, listener) => { @@ -309,7 +312,7 @@ export class InterceptingCall implements InterceptingCallInterface { // eslint-disable-next-line @typescript-eslint/no-explicit-any sendMessageWithContext(context: MessageContext, message: any): void { this.processingMessage = true; - this.requester.sendMessage(message, (finalMessage) => { + this.requester.sendMessage(message, finalMessage => { this.processingMessage = false; if (this.processingMetadata) { this.pendingMessageContext = context; @@ -391,10 +394,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 => { // eslint-disable-next-line @typescript-eslint/no-explicit-any let deserialized: any; try { @@ -410,7 +413,7 @@ class BaseInterceptingCall implements InterceptingCallInterface { } interceptingListener?.onReceiveMessage?.(deserialized); }, - onReceiveStatus: (status) => { + onReceiveStatus: status => { if (readError) { interceptingListener?.onReceiveStatus?.(readError); } else { @@ -433,7 +436,8 @@ class BaseInterceptingCall implements InterceptingCallInterface { */ class BaseUnaryInterceptingCall extends BaseInterceptingCall - implements InterceptingCallInterface { + implements InterceptingCallInterface +{ // eslint-disable-next-line @typescript-eslint/no-explicit-any constructor(call: Call, methodDefinition: ClientMethodDefinition) { super(call, methodDefinition); @@ -442,7 +446,7 @@ class BaseUnaryInterceptingCall let receivedMessage = false; const wrapperListener: InterceptingListener = { onReceiveMetadata: - listener?.onReceiveMetadata?.bind(listener) ?? ((metadata) => {}), + listener?.onReceiveMetadata?.bind(listener) ?? (metadata => {}), // eslint-disable-next-line @typescript-eslint/no-explicit-any onReceiveMessage: (message: any) => { receivedMessage = true; @@ -536,21 +540,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, { @@ -565,7 +569,7 @@ 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) diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index f96f8fdf0..61f986661 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -273,21 +273,20 @@ export class Client { options?: CallOptions | UnaryCallback, callback?: UnaryCallback ): ClientUnaryCall { - const checkedArguments = this.checkOptionalUnaryResponseArguments( - metadata, - options, - callback - ); - const methodDefinition: ClientMethodDefinition< - RequestType, - ResponseType - > = { - path: method, - requestStream: false, - responseStream: false, - requestSerialize: serialize, - responseDeserialize: deserialize, - }; + const checkedArguments = + this.checkOptionalUnaryResponseArguments( + metadata, + options, + callback + ); + const methodDefinition: ClientMethodDefinition = + { + path: method, + requestStream: false, + responseStream: false, + requestSerialize: serialize, + responseDeserialize: deserialize, + }; let callProperties: CallProperties = { argument: argument, metadata: checkedArguments.metadata, @@ -325,7 +324,7 @@ export class Client { let receivedStatus = false; const callerStackError = new Error(); call.start(callProperties.metadata, { - onReceiveMetadata: (metadata) => { + onReceiveMetadata: metadata => { emitter.emit('metadata', metadata); }, // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -343,11 +342,16 @@ export class Client { if (status.code === Status.OK) { if (responseMessage === null) { const callerStack = getErrorStackString(callerStackError); - callProperties.callback!(callErrorFromStatus({ - code: Status.INTERNAL, - details: 'No message received', - metadata: status.metadata - }, callerStack)); + callProperties.callback!( + callErrorFromStatus( + { + code: Status.INTERNAL, + details: 'No message received', + metadata: status.metadata, + }, + callerStack + ) + ); } else { callProperties.callback!(null, responseMessage); } @@ -399,21 +403,20 @@ export class Client { options?: CallOptions | UnaryCallback, callback?: UnaryCallback ): ClientWritableStream { - const checkedArguments = this.checkOptionalUnaryResponseArguments( - metadata, - options, - callback - ); - const methodDefinition: ClientMethodDefinition< - RequestType, - ResponseType - > = { - path: method, - requestStream: true, - responseStream: false, - requestSerialize: serialize, - responseDeserialize: deserialize, - }; + const checkedArguments = + this.checkOptionalUnaryResponseArguments( + metadata, + options, + callback + ); + const methodDefinition: ClientMethodDefinition = + { + path: method, + requestStream: true, + responseStream: false, + requestSerialize: serialize, + responseDeserialize: deserialize, + }; let callProperties: CallProperties = { metadata: checkedArguments.metadata, call: new ClientWritableStreamImpl(serialize), @@ -427,7 +430,8 @@ export class Client { callProperties ) as CallProperties; } - const emitter: ClientWritableStream = callProperties.call as ClientWritableStream; + const emitter: ClientWritableStream = + callProperties.call as ClientWritableStream; const interceptorArgs: InterceptorArguments = { clientInterceptors: this[INTERCEPTOR_SYMBOL], clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL], @@ -450,7 +454,7 @@ export class Client { let receivedStatus = false; const callerStackError = new Error(); call.start(callProperties.metadata, { - onReceiveMetadata: (metadata) => { + onReceiveMetadata: metadata => { emitter.emit('metadata', metadata); }, // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -468,11 +472,16 @@ export class Client { if (status.code === Status.OK) { if (responseMessage === null) { const callerStack = getErrorStackString(callerStackError); - callProperties.callback!(callErrorFromStatus({ - code: Status.INTERNAL, - details: 'No message received', - metadata: status.metadata - }, callerStack)); + callProperties.callback!( + callErrorFromStatus( + { + code: Status.INTERNAL, + details: 'No message received', + metadata: status.metadata, + }, + callerStack + ) + ); } else { callProperties.callback!(null, responseMessage); } @@ -534,16 +543,14 @@ export class Client { options?: CallOptions ): ClientReadableStream { const checkedArguments = this.checkMetadataAndOptions(metadata, options); - const methodDefinition: ClientMethodDefinition< - RequestType, - ResponseType - > = { - path: method, - requestStream: false, - responseStream: true, - requestSerialize: serialize, - responseDeserialize: deserialize, - }; + const methodDefinition: ClientMethodDefinition = + { + path: method, + requestStream: false, + responseStream: true, + requestSerialize: serialize, + responseDeserialize: deserialize, + }; let callProperties: CallProperties = { argument: argument, metadata: checkedArguments.metadata, @@ -557,7 +564,8 @@ export class Client { callProperties ) as CallProperties; } - const stream: ClientReadableStream = callProperties.call as ClientReadableStream; + const stream: ClientReadableStream = + callProperties.call as ClientReadableStream; const interceptorArgs: InterceptorArguments = { clientInterceptors: this[INTERCEPTOR_SYMBOL], clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL], @@ -625,16 +633,14 @@ export class Client { options?: CallOptions ): ClientDuplexStream { const checkedArguments = this.checkMetadataAndOptions(metadata, options); - const methodDefinition: ClientMethodDefinition< - RequestType, - ResponseType - > = { - path: method, - requestStream: true, - responseStream: true, - requestSerialize: serialize, - responseDeserialize: deserialize, - }; + const methodDefinition: ClientMethodDefinition = + { + path: method, + requestStream: true, + responseStream: true, + requestSerialize: serialize, + responseDeserialize: deserialize, + }; let callProperties: CallProperties = { metadata: checkedArguments.metadata, call: new ClientDuplexStreamImpl( @@ -650,10 +656,8 @@ export class Client { callProperties ) as CallProperties; } - const stream: ClientDuplexStream< - RequestType, - ResponseType - > = callProperties.call as ClientDuplexStream; + const stream: ClientDuplexStream = + callProperties.call as ClientDuplexStream; const interceptorArgs: InterceptorArguments = { clientInterceptors: this[INTERCEPTOR_SYMBOL], clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL], diff --git a/packages/grpc-js/src/compression-algorithms.ts b/packages/grpc-js/src/compression-algorithms.ts index ca2c7a624..67fdcf14c 100644 --- a/packages/grpc-js/src/compression-algorithms.ts +++ b/packages/grpc-js/src/compression-algorithms.ts @@ -18,5 +18,5 @@ export enum CompressionAlgorithms { identity = 0, deflate = 1, - gzip = 2 -}; + gzip = 2, +} diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index f87614114..3fd5604cd 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -26,9 +26,13 @@ import { BaseFilter, Filter, FilterFactory } from './filter'; import * as logging from './logging'; import { Metadata, MetadataValue } from './metadata'; -const isCompressionAlgorithmKey = (key: number): key is CompressionAlgorithms => { - return typeof key === 'number' && typeof CompressionAlgorithms[key] === 'string'; -} +const isCompressionAlgorithmKey = ( + key: number +): key is CompressionAlgorithms => { + return ( + typeof key === 'number' && typeof CompressionAlgorithms[key] === 'string' + ); +}; type CompressionAlgorithm = keyof typeof CompressionAlgorithms; @@ -183,14 +187,21 @@ export class CompressionFilter extends BaseFilter implements Filter { private receiveCompression: CompressionHandler = new IdentityHandler(); private currentCompressionAlgorithm: CompressionAlgorithm = 'identity'; - constructor(channelOptions: ChannelOptions, private sharedFilterConfig: SharedCompressionFilterConfig) { + constructor( + channelOptions: ChannelOptions, + private sharedFilterConfig: SharedCompressionFilterConfig + ) { super(); - const compressionAlgorithmKey = channelOptions['grpc.default_compression_algorithm']; + const compressionAlgorithmKey = + channelOptions['grpc.default_compression_algorithm']; if (compressionAlgorithmKey !== undefined) { if (isCompressionAlgorithmKey(compressionAlgorithmKey)) { - const clientSelectedEncoding = CompressionAlgorithms[compressionAlgorithmKey] as CompressionAlgorithm; - const serverSupportedEncodings = sharedFilterConfig.serverSupportedEncodingHeader?.split(','); + const clientSelectedEncoding = CompressionAlgorithms[ + compressionAlgorithmKey + ] as CompressionAlgorithm; + 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 @@ -198,12 +209,20 @@ export class CompressionFilter extends BaseFilter implements Filter { * 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)) { + if ( + !serverSupportedEncodings || + serverSupportedEncodings.includes(clientSelectedEncoding) + ) { this.currentCompressionAlgorithm = clientSelectedEncoding; - this.sendCompression = getCompressionHandler(this.currentCompressionAlgorithm); + this.sendCompression = getCompressionHandler( + this.currentCompressionAlgorithm + ); } } else { - logging.log(LogVerbosity.ERROR, `Invalid value provided for grpc.default_compression_algorithm option: ${compressionAlgorithmKey}`); + logging.log( + LogVerbosity.ERROR, + `Invalid value provided for grpc.default_compression_algorithm option: ${compressionAlgorithmKey}` + ); } } } @@ -235,12 +254,18 @@ export class CompressionFilter extends BaseFilter implements Filter { /* 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; + const serverSupportedEncodingsHeader = metadata.get( + 'grpc-accept-encoding' + )[0] as string | undefined; if (serverSupportedEncodingsHeader) { - this.sharedFilterConfig.serverSupportedEncodingHeader = serverSupportedEncodingsHeader; - const serverSupportedEncodings = serverSupportedEncodingsHeader.split(','); + this.sharedFilterConfig.serverSupportedEncodingHeader = + serverSupportedEncodingsHeader; + const serverSupportedEncodings = + serverSupportedEncodingsHeader.split(','); - if (!serverSupportedEncodings.includes(this.currentCompressionAlgorithm)) { + if ( + !serverSupportedEncodings.includes(this.currentCompressionAlgorithm) + ) { this.sendCompression = new IdentityHandler(); this.currentCompressionAlgorithm = 'identity'; } @@ -280,9 +305,13 @@ export class CompressionFilter extends BaseFilter implements Filter { } export class CompressionFilterFactory - implements FilterFactory { - private sharedFilterConfig: SharedCompressionFilterConfig = {}; - constructor(private readonly channel: Channel, private readonly options: ChannelOptions) {} + implements FilterFactory +{ + private sharedFilterConfig: SharedCompressionFilterConfig = {}; + constructor( + private readonly channel: Channel, + private readonly options: ChannelOptions + ) {} createFilter(): CompressionFilter { return new CompressionFilter(this.options, this.sharedFilterConfig); } diff --git a/packages/grpc-js/src/control-plane-status.ts b/packages/grpc-js/src/control-plane-status.ts index 808d695b2..1d10cb3d9 100644 --- a/packages/grpc-js/src/control-plane-status.ts +++ b/packages/grpc-js/src/control-plane-status.ts @@ -25,16 +25,19 @@ const INAPPROPRIATE_CONTROL_PLANE_CODES: Status[] = [ Status.FAILED_PRECONDITION, Status.ABORTED, Status.OUT_OF_RANGE, - Status.DATA_LOSS -] + Status.DATA_LOSS, +]; -export function restrictControlPlaneStatusCode(code: Status, details: string): {code: Status, details: string} { +export function restrictControlPlaneStatusCode( + code: Status, + details: string +): { code: Status; details: string } { if (INAPPROPRIATE_CONTROL_PLANE_CODES.includes(code)) { return { code: Status.INTERNAL, - details: `Invalid status from control plane: ${code} ${Status[code]} ${details}` - } + details: `Invalid status from control plane: ${code} ${Status[code]} ${details}`, + }; } else { - return {code, details}; + return { code, details }; } -} \ No newline at end of file +} diff --git a/packages/grpc-js/src/deadline.ts b/packages/grpc-js/src/deadline.ts index be1f3c3b0..8f8fe67b7 100644 --- a/packages/grpc-js/src/deadline.ts +++ b/packages/grpc-js/src/deadline.ts @@ -48,7 +48,7 @@ export function getDeadlineTimeoutString(deadline: Deadline) { return String(Math.ceil(amount)) + unit; } } - throw new Error('Deadline is too far in the future') + throw new Error('Deadline is too far in the future'); } /** @@ -65,7 +65,7 @@ const MAX_TIMEOUT_TIME = 2147483647; * 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 + * @param deadline * @returns */ export function getRelativeTimeout(deadline: Deadline) { @@ -75,7 +75,7 @@ export function getRelativeTimeout(deadline: Deadline) { if (timeout < 0) { return 0; } else if (timeout > MAX_TIMEOUT_TIME) { - return Infinity + return Infinity; } else { return timeout; } @@ -92,4 +92,4 @@ export function deadlineToString(deadline: Deadline): string { return dateDeadline.toISOString(); } } -} \ No newline at end of file +} diff --git a/packages/grpc-js/src/duration.ts b/packages/grpc-js/src/duration.ts index 278c9ae54..ff77dba25 100644 --- a/packages/grpc-js/src/duration.ts +++ b/packages/grpc-js/src/duration.ts @@ -23,7 +23,7 @@ export interface Duration { export function msToDuration(millis: number): Duration { return { seconds: (millis / 1000) | 0, - nanos: (millis % 1000) * 1_000_000 | 0 + nanos: ((millis % 1000) * 1_000_000) | 0, }; } @@ -32,5 +32,5 @@ export function durationToMs(duration: Duration): number { } export function isDuration(value: any): value is Duration { - return (typeof value.seconds === 'number') && (typeof value.nanos === 'number'); -} \ No newline at end of file + return typeof value.seconds === 'number' && typeof value.nanos === 'number'; +} diff --git a/packages/grpc-js/src/error.ts b/packages/grpc-js/src/error.ts index b973128a7..105a3eef3 100644 --- a/packages/grpc-js/src/error.ts +++ b/packages/grpc-js/src/error.ts @@ -34,4 +34,4 @@ export function getErrorCode(error: unknown): number | null { } else { return null; } -} \ No newline at end of file +} diff --git a/packages/grpc-js/src/experimental.ts b/packages/grpc-js/src/experimental.ts index 26c9596ed..9e4bbf45b 100644 --- a/packages/grpc-js/src/experimental.ts +++ b/packages/grpc-js/src/experimental.ts @@ -4,7 +4,7 @@ export { ResolverListener, registerResolver, ConfigSelector, - createResolver + createResolver, } from './resolver'; export { GrpcUri, uriToString } from './uri-parser'; export { Duration, durationToMs } from './duration'; @@ -36,5 +36,13 @@ export { Call as CallStream } from './call-interface'; export { Filter, BaseFilter, FilterFactory } from './filter'; export { FilterStackFactory } from './filter-stack'; export { registerAdminService } from './admin'; -export { SubchannelInterface, BaseSubchannelWrapper, ConnectivityStateListener } from './subchannel-interface'; -export { OutlierDetectionLoadBalancingConfig, SuccessRateEjectionConfig, FailurePercentageEjectionConfig } from './load-balancer-outlier-detection'; +export { + SubchannelInterface, + BaseSubchannelWrapper, + ConnectivityStateListener, +} from './subchannel-interface'; +export { + OutlierDetectionLoadBalancingConfig, + SuccessRateEjectionConfig, + FailurePercentageEjectionConfig, +} from './load-balancer-outlier-detection'; diff --git a/packages/grpc-js/src/filter-stack.ts b/packages/grpc-js/src/filter-stack.ts index 4733c8218..910f5aa36 100644 --- a/packages/grpc-js/src/filter-stack.ts +++ b/packages/grpc-js/src/filter-stack.ts @@ -94,7 +94,7 @@ export class FilterStackFactory implements FilterFactory { createFilter(): FilterStack { return new FilterStack( - this.factories.map((factory) => factory.createFilter()) + this.factories.map(factory => factory.createFilter()) ); } } diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index 6faa1976d..3aed28c85 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -206,11 +206,11 @@ export function getProxiedConnection( if ('grpc.http_connect_creds' in channelOptions) { headers['Proxy-Authorization'] = 'Basic ' + - Buffer.from( - channelOptions['grpc.http_connect_creds'] as string - ).toString('base64'); + Buffer.from(channelOptions['grpc.http_connect_creds'] as string).toString( + 'base64' + ); } - options.headers = headers + options.headers = headers; const proxyAddressString = subchannelAddressToString(address); trace('Using proxy ' + proxyAddressString + ' to connect to ' + options.path); return new Promise((resolve, reject) => { @@ -252,12 +252,14 @@ export function getProxiedConnection( } ); cts.on('error', (error: Error) => { - trace('Failed to establish a TLS connection to ' + - options.path + - ' through proxy ' + - proxyAddressString + - ' with error ' + - error.message); + trace( + 'Failed to establish a TLS connection to ' + + options.path + + ' through proxy ' + + proxyAddressString + + ' with error ' + + error.message + ); reject(); }); } else { @@ -285,7 +287,7 @@ export function getProxiedConnection( reject(); } }); - request.once('error', (err) => { + request.once('error', err => { request.removeAllListeners(); log( LogVerbosity.ERROR, diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 51f394785..9363a37b7 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -128,7 +128,7 @@ export { Status as status, ConnectivityState as connectivityState, Propagate as propagate, - CompressionAlgorithms as compressionAlgorithms + CompressionAlgorithms as compressionAlgorithms, // TODO: Other constants as well }; @@ -248,21 +248,18 @@ export { InterceptorProvider, InterceptingCall, InterceptorConfigurationError, - NextCall + NextCall, } from './client-interceptors'; export { GrpcObject, ServiceClientConstructor, - ProtobufTypeDefinition + ProtobufTypeDefinition, } from './make-client'; export { ChannelOptions } from './channel-options'; -export { - getChannelzServiceDefinition, - getChannelzHandlers -} from './channelz'; +export { getChannelzServiceDefinition, getChannelzHandlers } from './channelz'; export { addAdminServicesToServer } from './admin'; @@ -281,7 +278,11 @@ import { Deadline } from './deadline'; const clientVersion = require('../../package.json').version; (() => { - logging.trace(LogVerbosity.DEBUG, 'index', 'Loading @grpc/grpc-js version ' + clientVersion); + logging.trace( + LogVerbosity.DEBUG, + 'index', + 'Loading @grpc/grpc-js version ' + clientVersion + ); resolver_dns.setup(); resolver_uds.setup(); resolver_ip.setup(); diff --git a/packages/grpc-js/src/internal-channel.ts b/packages/grpc-js/src/internal-channel.ts index 14038bd3f..3f3ca5d7f 100644 --- a/packages/grpc-js/src/internal-channel.ts +++ b/packages/grpc-js/src/internal-channel.ts @@ -40,18 +40,45 @@ 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 { + 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 { + Call, + CallStreamOptions, + InterceptingListener, + MessageContext, + StatusObject, +} from './call-interface'; import { SubchannelCall } from './subchannel-call'; -import { Deadline, deadlineToString, 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'; -import { MessageBufferTracker, RetryingCall, RetryThrottler } from './retrying-call'; -import { BaseSubchannelWrapper, ConnectivityStateListener, SubchannelInterface } from './subchannel-interface'; +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 @@ -78,19 +105,33 @@ interface ErrorConfigResult { error: StatusObject; } -type GetConfigResult = NoneConfigResult | SuccessConfigResult | 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 +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 { +class ChannelSubchannelWrapper + extends BaseSubchannelWrapper + implements SubchannelInterface +{ private refCount = 0; private subchannelStateListener: ConnectivityStateListener; - constructor(childSubchannel: SubchannelInterface, private channel: InternalChannel) { + constructor( + childSubchannel: SubchannelInterface, + private channel: InternalChannel + ) { super(childSubchannel); - this.subchannelStateListener = (subchannel, previousState, newState, keepaliveTime) => { + this.subchannelStateListener = ( + subchannel, + previousState, + newState, + keepaliveTime + ) => { channel.throttleKeepalive(keepaliveTime); }; childSubchannel.addConnectivityStateListener(this.subchannelStateListener); @@ -112,7 +153,6 @@ class ChannelSubchannelWrapper extends BaseSubchannelWrapper implements Subchann } export class InternalChannel { - private resolvingLoadBalancer: ResolvingLoadBalancer; private subchannelPool: SubchannelPool; private connectivityState: ConnectivityState = ConnectivityState.IDLE; @@ -196,7 +236,11 @@ export class InternalChannel { } this.channelzTrace = new ChannelzTrace(); - this.channelzRef = registerChannelzChannel(target, () => this.getChannelzInfo(), this.channelzEnabled); + this.channelzRef = registerChannelzChannel( + target, + () => this.getChannelzInfo(), + this.channelzEnabled + ); if (this.channelzEnabled) { this.channelzTrace.addTrace('CT_INFO', 'Channel created'); } @@ -217,7 +261,8 @@ export class InternalChannel { ); 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 + 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 = { @@ -233,9 +278,16 @@ export class InternalChannel { ); subchannel.throttleKeepalive(this.keepaliveTime); if (this.channelzEnabled) { - this.channelzTrace.addTrace('CT_INFO', 'Created subchannel or used existing subchannel', subchannel.getChannelzRef()); + this.channelzTrace.addTrace( + 'CT_INFO', + 'Created subchannel or used existing subchannel', + subchannel.getChannelzRef() + ); } - const wrappedSubchannel = new ChannelSubchannelWrapper(subchannel, this); + const wrappedSubchannel = new ChannelSubchannelWrapper( + subchannel, + this + ); this.wrappedSubchannels.add(wrappedSubchannel); return wrappedSubchannel; }, @@ -264,7 +316,7 @@ export class InternalChannel { if (this.channelzEnabled) { this.childrenTracker.unrefChild(child); } - } + }, }; this.resolvingLoadBalancer = new ResolvingLoadBalancer( this.target, @@ -272,12 +324,22 @@ export class InternalChannel { options, (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()))); + 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'); + this.channelzTrace.addTrace( + 'CT_INFO', + 'Address resolution succeeded' + ); } this.configSelector = configSelector; this.currentResolutionError = null; @@ -292,17 +354,28 @@ export class InternalChannel { } this.configSelectionQueue = []; }); - }, - (status) => { + status => { if (this.channelzEnabled) { - this.channelzTrace.addTrace('CT_WARNING', 'Address resolution failed with code ' + status.code + ' and details "' + status.details + '"'); + 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'); + this.trace( + 'Name resolution failed with calls queued for config selection' + ); } if (this.configSelector === null) { - this.currentResolutionError = {...restrictControlPlaneStatusCode(status.code, status.details), metadata: status.metadata}; + this.currentResolutionError = { + ...restrictControlPlaneStatusCode(status.code, status.details), + metadata: status.metadata, + }; } const localQueue = this.configSelectionQueue; this.configSelectionQueue = []; @@ -316,9 +389,20 @@ export class InternalChannel { new MaxMessageSizeFilterFactory(this.options), new CompressionFilterFactory(this, this.options), ]); - this.trace('Channel constructed with options ' + JSON.stringify(options, undefined, 2)); + 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)); + trace( + LogVerbosity.DEBUG, + 'channel_stacktrace', + '(' + + this.channelzRef.id + + ') ' + + 'Channel constructed \n' + + error.stack?.substring(error.stack.indexOf('\n') + 1) + ); } private getChannelzInfo(): ChannelInfo { @@ -327,12 +411,16 @@ export class InternalChannel { state: this.connectivityState, trace: this.channelzTrace, callTracker: this.callTracker, - children: this.childrenTracker.getChildLists() + children: this.childrenTracker.getChildLists(), }; } private trace(text: string, verbosityOverride?: LogVerbosity) { - trace(verbosityOverride ?? LogVerbosity.DEBUG, 'channel', '(' + this.channelzRef.id + ') ' + uriToString(this.target) + ' ' + text); + trace( + verbosityOverride ?? LogVerbosity.DEBUG, + 'channel', + '(' + this.channelzRef.id + ') ' + uriToString(this.target) + ' ' + text + ); } private callRefTimerRef() { @@ -365,7 +453,7 @@ export class InternalChannel { watcherObject: ConnectivityStateWatcher ) { const watcherIndex = this.connectivityStateWatchers.findIndex( - (value) => value === watcherObject + value => value === watcherObject ); if (watcherIndex >= 0) { this.connectivityStateWatchers.splice(watcherIndex, 1); @@ -376,7 +464,9 @@ export class InternalChannel { trace( LogVerbosity.DEBUG, 'connectivity_state', - '(' + this.channelzRef.id + ') ' + + '(' + + this.channelzRef.id + + ') ' + uriToString(this.target) + ' ' + ConnectivityState[this.connectivityState] + @@ -384,7 +474,12 @@ export class InternalChannel { ConnectivityState[newState] ); if (this.channelzEnabled) { - this.channelzTrace.addTrace('CT_INFO', ConnectivityState[this.connectivityState] + ' -> ' + ConnectivityState[newState]); + this.channelzTrace.addTrace( + 'CT_INFO', + ConnectivityState[this.connectivityState] + + ' -> ' + + ConnectivityState[newState] + ); } this.connectivityState = newState; const watchersCopy = this.connectivityStateWatchers.slice(); @@ -415,8 +510,11 @@ export class InternalChannel { this.wrappedSubchannels.delete(wrappedSubchannel); } - doPick(metadata: Metadata, extraPickInfo: {[key: string]: string}) { - return this.currentPicker.pick({metadata: metadata, extraPickInfo: extraPickInfo}); + doPick(metadata: Metadata, extraPickInfo: { [key: string]: string }) { + return this.currentPicker.pick({ + metadata: metadata, + extraPickInfo: extraPickInfo, + }); } queueCallForPick(call: LoadBalancingCall) { @@ -429,18 +527,18 @@ export class InternalChannel { if (this.configSelector) { return { type: 'SUCCESS', - config: this.configSelector(method, metadata) + config: this.configSelector(method, metadata), }; } else { if (this.currentResolutionError) { return { type: 'ERROR', - error: this.currentResolutionError - } + error: this.currentResolutionError, + }; } else { return { - type: 'NONE' - } + type: 'NONE', + }; } } } @@ -459,13 +557,17 @@ export class InternalChannel { ): LoadBalancingCall { const callNumber = getNextCallNumber(); this.trace( - 'createLoadBalancingCall [' + - callNumber + - '] method="' + - method + - '"' + 'createLoadBalancingCall [' + callNumber + '] method="' + method + '"' + ); + return new LoadBalancingCall( + this, + callConfig, + method, + host, + credentials, + deadline, + callNumber ); - return new LoadBalancingCall(this, callConfig, method, host, credentials, deadline, callNumber); } createRetryingCall( @@ -477,13 +579,19 @@ export class InternalChannel { ): RetryingCall { const callNumber = getNextCallNumber(); this.trace( - 'createRetryingCall [' + - callNumber + - '] method="' + - method + - '"' + 'createRetryingCall [' + callNumber + '] method="' + method + '"' + ); + return new RetryingCall( + this, + callConfig, + method, + host, + credentials, + deadline, + callNumber, + this.retryBufferTracker, + RETRY_THROTTLER_MAP.get(this.getTarget()) ); - return new RetryingCall(this, callConfig, method, host, credentials, deadline, callNumber, this.retryBufferTracker, RETRY_THROTTLER_MAP.get(this.getTarget())) } createInnerCall( @@ -495,9 +603,21 @@ export class InternalChannel { ): Call { // Create a RetryingCall if retries are enabled if (this.options['grpc.enable_retries'] === 0) { - return this.createLoadBalancingCall(callConfig, method, host, credentials, deadline); + return this.createLoadBalancingCall( + callConfig, + method, + host, + credentials, + deadline + ); } else { - return this.createRetryingCall(callConfig, method, host, credentials, deadline); + return this.createRetryingCall( + callConfig, + method, + host, + credentials, + deadline + ); } } @@ -524,7 +644,14 @@ export class InternalChannel { parentCall: parentCall, }; - const call = new ResolvingCall(this, method, finalOptions, this.filterStackFactory.clone(), this.credentials._getCallCredentials(), callNumber); + const call = new ResolvingCall( + this, + method, + finalOptions, + this.filterStackFactory.clone(), + this.credentials._getCallCredentials(), + callNumber + ); if (this.channelzEnabled) { this.callTracker.addCallStarted(); @@ -537,7 +664,6 @@ export class InternalChannel { }); } return call; - } close() { @@ -601,7 +727,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; @@ -625,6 +751,12 @@ export class InternalChannel { if (this.connectivityState === ConnectivityState.SHUTDOWN) { throw new Error('Channel has been shut down'); } - return this.createResolvingCall(method, deadline, host, parentCall, propagateFlags); + return this.createResolvingCall( + method, + deadline, + host, + parentCall, + propagateFlags + ); } } diff --git a/packages/grpc-js/src/load-balancer-child-handler.ts b/packages/grpc-js/src/load-balancer-child-handler.ts index 595d411a0..b556db0c6 100644 --- a/packages/grpc-js/src/load-balancer-child-handler.ts +++ b/packages/grpc-js/src/load-balancer-child-handler.ts @@ -75,7 +75,7 @@ export class ChildLoadBalancerHandler implements LoadBalancer { removeChannelzChild(child: ChannelRef | SubchannelRef) { this.parent.channelControlHelper.removeChannelzChild(child); } - + private calledByPendingChild(): boolean { return this.child === this.parent.pendingChild; } @@ -86,7 +86,10 @@ export class ChildLoadBalancerHandler implements LoadBalancer { constructor(private readonly channelControlHelper: ChannelControlHelper) {} - protected configUpdateRequiresNewPolicyInstance(oldConfig: LoadBalancingConfig, newConfig: LoadBalancingConfig): boolean { + protected configUpdateRequiresNewPolicyInstance( + oldConfig: LoadBalancingConfig, + newConfig: LoadBalancingConfig + ): boolean { return oldConfig.getLoadBalancerName() !== newConfig.getLoadBalancerName(); } diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index 2f72a9625..0c61065ec 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -15,18 +15,41 @@ * */ -import { ChannelOptions } from "./channel-options"; -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 { SubchannelAddress, subchannelAddressToString } from "./subchannel-address"; -import { BaseSubchannelWrapper, ConnectivityStateListener, SubchannelInterface } from "./subchannel-interface"; +import { ChannelOptions } from './channel-options'; +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 { + SubchannelAddress, + subchannelAddressToString, +} from './subchannel-address'; +import { + BaseSubchannelWrapper, + ConnectivityStateListener, + SubchannelInterface, +} from './subchannel-interface'; import * as logging from './logging'; const TRACER_NAME = 'outlier_detection'; @@ -37,7 +60,8 @@ function trace(text: string): void { const TYPE_NAME = 'outlier_detection'; -const OUTLIER_DETECTION_ENABLED = (process.env.GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION ?? 'true') === 'true'; +const OUTLIER_DETECTION_ENABLED = + (process.env.GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION ?? 'true') === 'true'; export interface SuccessRateEjectionConfig { readonly stdev_factor: number; @@ -57,33 +81,66 @@ const defaultSuccessRateEjectionConfig: SuccessRateEjectionConfig = { stdev_factor: 1900, enforcement_percentage: 100, minimum_hosts: 5, - request_volume: 100 + 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) { +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]}`); + throw new Error( + `outlier detection config ${fullFieldName} parse error: expected ${expectedType}, got ${typeof obj[ + fieldName + ]}` + ); } } -function validatePositiveDuration(obj: any, fieldName: string, objectName?: string) { +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`); + 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` + ); } } } @@ -92,11 +149,15 @@ 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)`); + throw new Error( + `outlier detection config ${fullFieldName} parse error: value out of range for percentage (0-100)` + ); } } -export class OutlierDetectionLoadBalancingConfig implements LoadBalancingConfig { +export class OutlierDetectionLoadBalancingConfig + implements LoadBalancingConfig +{ private readonly intervalMs: number; private readonly baseEjectionTimeMs: number; private readonly maxEjectionTimeMs: number; @@ -117,8 +178,15 @@ export class OutlierDetectionLoadBalancingConfig implements LoadBalancingConfig 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; + this.successRateEjection = successRateEjection + ? { ...defaultSuccessRateEjectionConfig, ...successRateEjection } + : null; + this.failurePercentageEjection = failurePercentageEjection + ? { + ...defaultFailurePercentageEjectionConfig, + ...failurePercentageEjection, + } + : null; } getLoadBalancerName(): string { return TYPE_NAME; @@ -131,7 +199,7 @@ export class OutlierDetectionLoadBalancingConfig implements LoadBalancingConfig max_ejection_percent: this.maxEjectionPercent, success_rate_ejection: this.successRateEjection, failure_percentage_ejection: this.failurePercentageEjection, - child_policy: this.childPolicy.map(policy => policy.toJsonObject()) + child_policy: this.childPolicy.map(policy => policy.toJsonObject()), }; } @@ -157,8 +225,18 @@ export class OutlierDetectionLoadBalancingConfig implements LoadBalancingConfig return this.childPolicy; } - copyWithChildPolicy(childPolicy: LoadBalancingConfig[]): OutlierDetectionLoadBalancingConfig { - return new OutlierDetectionLoadBalancingConfig(this.intervalMs, this.baseEjectionTimeMs, this.maxEjectionTimeMs, this.maxEjectionPercent, this.successRateEjection, this.failurePercentageEjection, 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 { @@ -168,21 +246,62 @@ export class OutlierDetectionLoadBalancingConfig implements LoadBalancingConfig 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'); + 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'); + 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'); + 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'); + 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( @@ -197,22 +316,30 @@ export class OutlierDetectionLoadBalancingConfig implements LoadBalancingConfig } } -class OutlierDetectionSubchannelWrapper extends BaseSubchannelWrapper implements SubchannelInterface { +class OutlierDetectionSubchannelWrapper + extends BaseSubchannelWrapper + implements SubchannelInterface +{ private childSubchannelState: ConnectivityState; private stateListeners: ConnectivityStateListener[] = []; - private ejected: boolean = false; - private refCount: number = 0; - constructor(childSubchannel: SubchannelInterface, private mapEntry?: MapEntry) { + private ejected = false; + private refCount = 0; + constructor( + childSubchannel: SubchannelInterface, + private mapEntry?: MapEntry + ) { super(childSubchannel); this.childSubchannelState = childSubchannel.getConnectivityState(); - childSubchannel.addConnectivityStateListener((subchannel, previousState, newState, keepaliveTime) => { - this.childSubchannelState = newState; - if (!this.ejected) { - for (const listener of this.stateListeners) { - listener(this, previousState, newState, keepaliveTime); + childSubchannel.addConnectivityStateListener( + (subchannel, previousState, newState, keepaliveTime) => { + this.childSubchannelState = newState; + if (!this.ejected) { + for (const listener of this.stateListeners) { + listener(this, previousState, newState, keepaliveTime); + } } } - }); + ); } getConnectivityState(): ConnectivityState { @@ -265,14 +392,24 @@ class OutlierDetectionSubchannelWrapper extends BaseSubchannelWrapper implements eject() { this.ejected = true; for (const listener of this.stateListeners) { - listener(this, this.childSubchannelState, ConnectivityState.TRANSIENT_FAILURE, -1); + 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, -1); + listener( + this, + ConnectivityState.TRANSIENT_FAILURE, + this.childSubchannelState, + -1 + ); } } @@ -293,8 +430,8 @@ interface CallCountBucket { function createEmptyBucket(): CallCountBucket { return { success: 0, - failure: 0 - } + failure: 0, + }; } class CallCounter { @@ -330,7 +467,8 @@ class OutlierDetectionPicker implements Picker { pick(pickArgs: PickArgs): PickResult { const wrappedPick = this.wrappedPicker.pick(pickArgs); if (wrappedPick.pickResultType === PickResultType.COMPLETE) { - const subchannelWrapper = wrappedPick.subchannel as OutlierDetectionSubchannelWrapper; + const subchannelWrapper = + wrappedPick.subchannel as OutlierDetectionSubchannelWrapper; const mapEntry = subchannelWrapper.getMapEntry(); if (mapEntry) { let onCallEnded = wrappedPick.onCallEnded; @@ -347,19 +485,18 @@ class OutlierDetectionPicker implements Picker { return { ...wrappedPick, subchannel: subchannelWrapper.getWrappedSubchannel(), - onCallEnded: onCallEnded + onCallEnded: onCallEnded, }; } else { return { ...wrappedPick, - subchannel: subchannelWrapper.getWrappedSubchannel() - } + subchannel: subchannelWrapper.getWrappedSubchannel(), + }; } } else { return wrappedPick; } } - } export class OutlierDetectionLoadBalancer implements LoadBalancer { @@ -370,34 +507,52 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { private timerStartTime: Date | null = null; 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); - if (mapEntry?.currentEjectionTimestamp !== null) { - // If the address is ejected, propagate that to the new subchannel wrapper - subchannelWrapper.eject(); - } - mapEntry?.subchannelWrappers.push(subchannelWrapper); - return subchannelWrapper; - }, - updateState: (connectivityState: ConnectivityState, picker: Picker) => { - if (connectivityState === ConnectivityState.READY) { - channelControlHelper.updateState(connectivityState, new OutlierDetectionPicker(picker, this.isCountingEnabled())); - } else { - channelControlHelper.updateState(connectivityState, picker); - } - } - })); + 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 + ); + if (mapEntry?.currentEjectionTimestamp !== null) { + // If the address is ejected, propagate that to the new subchannel wrapper + subchannelWrapper.eject(); + } + mapEntry?.subchannelWrappers.push(subchannelWrapper); + return subchannelWrapper; + }, + updateState: (connectivityState: ConnectivityState, picker: Picker) => { + if (connectivityState === ConnectivityState.READY) { + channelControlHelper.updateState( + connectivityState, + new OutlierDetectionPicker(picker, this.isCountingEnabled()) + ); + } else { + channelControlHelper.updateState(connectivityState, picker); + } + }, + }) + ); this.ejectionTimer = setInterval(() => {}, 0); clearInterval(this.ejectionTimer); } private isCountingEnabled(): boolean { - return this.latestConfig !== null && - (this.latestConfig.getSuccessRateEjectionConfig() !== null || - this.latestConfig.getFailurePercentageEjectionConfig() !== null); + return ( + this.latestConfig !== null && + (this.latestConfig.getSuccessRateEjectionConfig() !== null || + this.latestConfig.getFailurePercentageEjectionConfig() !== null) + ); } private getCurrentEjectionPercent() { @@ -422,23 +577,41 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { // Step 1 const targetRequestVolume = successRateConfig.request_volume; let addresesWithTargetVolume = 0; - const successRates: number[] = [] + const successRates: number[] = []; 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); + trace( + 'Stats for ' + + address + + ': successes=' + + successes + + ' failures=' + + failures + + ' targetRequestVolume=' + + targetRequestVolume + ); if (successes + failures >= targetRequestVolume) { addresesWithTargetVolume += 1; - successRates.push(successes/(successes + failures)); + successRates.push(successes / (successes + failures)); } } - trace('Found ' + addresesWithTargetVolume + ' success rate candidates; currentEjectionPercent=' + this.getCurrentEjectionPercent() + ' successRates=[' + successRates + ']'); + trace( + 'Found ' + + addresesWithTargetVolume + + ' success rate candidates; currentEjectionPercent=' + + this.getCurrentEjectionPercent() + + ' successRates=[' + + successRates + + ']' + ); if (addresesWithTargetVolume < successRateConfig.minimum_hosts) { return; } // Step 2 - const successRateMean = successRates.reduce((a, b) => a + b) / successRates.length; + const successRateMean = + successRates.reduce((a, b) => a + b) / successRates.length; let successRateDeviationSum = 0; for (const rate of successRates) { const deviation = rate - successRateMean; @@ -446,13 +619,20 @@ 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); + const ejectionThreshold = + successRateMean - + successRateStdev * (successRateConfig.stdev_factor / 1000); + trace( + 'stdev=' + successRateStdev + ' ejectionThreshold=' + ejectionThreshold + ); // 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 @@ -466,7 +646,14 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { trace('Checking candidate ' + address + ' successRate=' + successRate); if (successRate < ejectionThreshold) { const randomNumber = Math.random() * 100; - trace('Candidate ' + address + ' randomNumber=' + randomNumber + ' enforcement_percentage=' + successRateConfig.enforcement_percentage); + trace( + 'Candidate ' + + address + + ' randomNumber=' + + randomNumber + + ' enforcement_percentage=' + + successRateConfig.enforcement_percentage + ); if (randomNumber < successRateConfig.enforcement_percentage) { trace('Ejecting candidate ' + address); this.eject(mapEntry, ejectionTimestamp); @@ -479,11 +666,17 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { if (!this.latestConfig) { return; } - const failurePercentageConfig = this.latestConfig.getFailurePercentageEjectionConfig() + const failurePercentageConfig = + this.latestConfig.getFailurePercentageEjectionConfig(); if (!failurePercentageConfig) { return; } - trace('Running failure percentage check. threshold=' + failurePercentageConfig.threshold + ' request volume threshold=' + failurePercentageConfig.request_volume); + trace( + 'Running failure percentage check. threshold=' + + failurePercentageConfig.threshold + + ' request volume threshold=' + + failurePercentageConfig.request_volume + ); // Step 1 let addressesWithTargetVolume = 0; for (const mapEntry of this.addressMap.values()) { @@ -496,11 +689,14 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { if (addressesWithTargetVolume < failurePercentageConfig.minimum_hosts) { return; } - + // 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 @@ -514,7 +710,14 @@ 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); + trace( + 'Candidate ' + + address + + ' randomNumber=' + + randomNumber + + ' enforcement_percentage=' + + failurePercentageConfig.enforcement_percentage + ); if (randomNumber < failurePercentageConfig.enforcement_percentage) { trace('Ejecting candidate ' + address); this.eject(mapEntry, ejectionTimestamp); @@ -572,8 +775,16 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { } 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))); + 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); @@ -582,7 +793,11 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { } } - updateAddressList(addressList: SubchannelAddress[], lbConfig: LoadBalancingConfig, attributes: { [key: string]: unknown; }): void { + updateAddressList( + addressList: SubchannelAddress[], + lbConfig: LoadBalancingConfig, + attributes: { [key: string]: unknown } + ): void { if (!(lbConfig instanceof OutlierDetectionLoadBalancingConfig)) { return; } @@ -597,7 +812,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { counter: new CallCounter(), currentEjectionTimestamp: null, ejectionTimeMultiplier: 0, - subchannelWrappers: [] + subchannelWrappers: [], }); } } @@ -613,11 +828,16 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { ); this.childBalancer.updateAddressList(addressList, childPolicy, attributes); - if (lbConfig.getSuccessRateEjectionConfig() || lbConfig.getFailurePercentageEjectionConfig()) { + 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()); + const remainingDelay = + lbConfig.getIntervalMs() - + (new Date().getTime() - this.timerStartTime.getTime()); this.startTimer(remainingDelay); } else { trace('Starting new timer'); @@ -654,6 +874,10 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { export function setup() { if (OUTLIER_DETECTION_ENABLED) { - registerLoadBalancerType(TYPE_NAME, OutlierDetectionLoadBalancer, OutlierDetectionLoadBalancingConfig); + registerLoadBalancerType( + TYPE_NAME, + OutlierDetectionLoadBalancer, + OutlierDetectionLoadBalancingConfig + ); } -} \ 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 41d21a2ea..e91bb3c5a 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -38,7 +38,10 @@ import { } from './subchannel-address'; import * as logging from './logging'; import { LogVerbosity } from './constants'; -import { SubchannelInterface, ConnectivityStateListener } from './subchannel-interface'; +import { + SubchannelInterface, + ConnectivityStateListener, +} from './subchannel-interface'; const TRACER_NAME = 'pick_first'; @@ -86,7 +89,7 @@ class PickFirstPicker implements Picker { subchannel: this.subchannel, status: null, onCallStarted: null, - onCallEnded: null + onCallEnded: null, }; } } @@ -169,7 +172,8 @@ export class PickFirstLoadBalancer implements LoadBalancer { * connecting to the next one instead of waiting for the connection * delay timer. */ if ( - subchannel.getRealSubchannel() === this.subchannels[this.currentSubchannelIndex].getRealSubchannel() && + subchannel.getRealSubchannel() === + this.subchannels[this.currentSubchannelIndex].getRealSubchannel() && newState === ConnectivityState.TRANSIENT_FAILURE ) { this.startNextSubchannelConnecting(); @@ -232,7 +236,9 @@ export class PickFirstLoadBalancer implements LoadBalancer { subchannel.removeConnectivityStateListener( this.pickedSubchannelStateListener ); - this.channelControlHelper.removeChannelzChild(subchannel.getChannelzRef()); + this.channelControlHelper.removeChannelzChild( + subchannel.getChannelzRef() + ); if (this.subchannels.length > 0) { if (this.triedAllSubchannels) { let newLBState: ConnectivityState; @@ -344,7 +350,9 @@ export class PickFirstLoadBalancer implements LoadBalancer { for (const subchannel of this.subchannels) { subchannel.removeConnectivityStateListener(this.subchannelStateListener); subchannel.unref(); - this.channelControlHelper.removeChannelzChild(subchannel.getChannelzRef()); + this.channelControlHelper.removeChannelzChild( + subchannel.getChannelzRef() + ); } this.currentSubchannelIndex = 0; this.subchannelStateCounts = { @@ -368,11 +376,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) { @@ -422,7 +430,9 @@ export class PickFirstLoadBalancer implements LoadBalancer { this.subchannels.length === 0 || this.latestAddressList.length !== addressList.length || !this.latestAddressList.every( - (value, index) => addressList[index] && subchannelAddressEqual(addressList[index], value) + (value, index) => + addressList[index] && + subchannelAddressEqual(addressList[index], value) ) ) { this.latestAddressList = addressList; @@ -463,7 +473,9 @@ export class PickFirstLoadBalancer implements LoadBalancer { currentPick.removeConnectivityStateListener( this.pickedSubchannelStateListener ); - this.channelControlHelper.removeChannelzChild(currentPick.getChannelzRef()); + this.channelControlHelper.removeChannelzChild( + 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 9e91038ff..f389fefc0 100644 --- a/packages/grpc-js/src/load-balancer-round-robin.ts +++ b/packages/grpc-js/src/load-balancer-round-robin.ts @@ -36,7 +36,10 @@ import { } from './subchannel-address'; import * as logging from './logging'; import { LogVerbosity } from './constants'; -import { ConnectivityStateListener, SubchannelInterface } from './subchannel-interface'; +import { + ConnectivityStateListener, + SubchannelInterface, +} from './subchannel-interface'; const TRACER_NAME = 'round_robin'; @@ -79,7 +82,7 @@ class RoundRobinPicker implements Picker { subchannel: pickedSubchannel, status: null, onCallStarted: null, - onCallEnded: null + onCallEnded: null, }; } @@ -121,13 +124,15 @@ export class RoundRobinLoadBalancer implements LoadBalancer { } private countSubchannelsWithState(state: ConnectivityState) { - return this.subchannels.filter(subchannel => subchannel.getConnectivityState() === state).length; + return this.subchannels.filter( + subchannel => subchannel.getConnectivityState() === state + ).length; } private calculateAndUpdateState() { if (this.countSubchannelsWithState(ConnectivityState.READY) > 0) { const readySubchannels = this.subchannels.filter( - (subchannel) => + subchannel => subchannel.getConnectivityState() === ConnectivityState.READY ); let index = 0; @@ -143,7 +148,9 @@ export class RoundRobinLoadBalancer implements LoadBalancer { ConnectivityState.READY, new RoundRobinPicker(readySubchannels, index) ); - } else if (this.countSubchannelsWithState(ConnectivityState.CONNECTING) > 0) { + } else if ( + this.countSubchannelsWithState(ConnectivityState.CONNECTING) > 0 + ) { this.updateState(ConnectivityState.CONNECTING, new QueuePicker(this)); } else if ( this.countSubchannelsWithState(ConnectivityState.TRANSIENT_FAILURE) > 0 @@ -176,7 +183,9 @@ export class RoundRobinLoadBalancer implements LoadBalancer { for (const subchannel of this.subchannels) { subchannel.removeConnectivityStateListener(this.subchannelStateListener); subchannel.unref(); - this.channelControlHelper.removeChannelzChild(subchannel.getChannelzRef()); + this.channelControlHelper.removeChannelzChild( + subchannel.getChannelzRef() + ); } this.subchannels = []; } @@ -188,9 +197,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/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts index 48930c7db..8e859495e 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -58,16 +58,28 @@ 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 { +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) + 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), }; } diff --git a/packages/grpc-js/src/load-balancing-call.ts b/packages/grpc-js/src/load-balancing-call.ts index f74933983..1a97c89fc 100644 --- a/packages/grpc-js/src/load-balancing-call.ts +++ b/packages/grpc-js/src/load-balancing-call.ts @@ -15,20 +15,25 @@ * */ -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 { 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'; -import { restrictControlPlaneStatusCode } from "./control-plane-status"; +import { restrictControlPlaneStatusCode } from './control-plane-status'; import * as http2 from 'http2'; const TRACER_NAME = 'load_balancing_call'; @@ -39,14 +44,16 @@ export interface StatusObjectWithProgress extends StatusObject { progress: RpcProgress; } -export interface LoadBalancingCallInterceptingListener extends InterceptingListener { +export interface LoadBalancingCallInterceptingListener + extends InterceptingListener { onReceiveStatus(status: StatusObjectWithProgress): void; } export class LoadBalancingCall implements Call { private child: SubchannelCall | null = null; private readPending = false; - private pendingMessage: {context: MessageContext, message: Buffer} | null = null; + private pendingMessage: { context: MessageContext; message: Buffer } | null = + null; private pendingHalfClose = false; private pendingChildStatus: StatusObject | null = null; private ended = false; @@ -58,7 +65,7 @@ export class LoadBalancingCall implements Call { private readonly channel: InternalChannel, private readonly callConfig: CallConfig, private readonly methodName: string, - private readonly host : string, + private readonly host: string, private readonly credentials: CallCredentials, private readonly deadline: Deadline, private readonly callNumber: number @@ -88,8 +95,14 @@ export class LoadBalancingCall implements Call { private outputStatus(status: StatusObject, progress: RpcProgress) { if (!this.ended) { this.ended = true; - this.trace('ended with status: code=' + status.code + ' details="' + status.details + '"'); - const finalStatus = {...status, progress}; + this.trace( + 'ended with status: code=' + + status.code + + ' details="' + + status.details + + '"' + ); + const finalStatus = { ...status, progress }; this.listener?.onReceiveStatus(finalStatus); this.onCallEnded?.(finalStatus.code); } @@ -102,11 +115,17 @@ 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() : - '' + pickResult.subchannel; + 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; this.trace( 'Pick result: ' + PickResultType[pickResult.pickResultType] + @@ -119,111 +138,147 @@ export class LoadBalancingCall implements Call { ); 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; - } + 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.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.rstCode === http2.constants.NGHTTP2_REFUSED_STREAM) { - this.outputStatus(status, 'REFUSED'); - } else { - this.outputStatus(status, 'PROCESSED'); - } - } - }); - } catch (error) { + 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.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.rstCode === + http2.constants.NGHTTP2_REFUSED_STREAM + ) { + this.outputStatus(status, 'REFUSED'); + } else { + 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( - 'Failed to start call on picked subchannel ' + - subchannelString + - ' with error ' + - (error as Error).message + '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.child.halfClose(); + } + }, + (error: Error & { code: number }) => { + // We assume the error code isn't 0 (Status.OK) + const { code, details } = restrictControlPlaneStatusCode( + typeof error.code === 'number' ? error.code : Status.UNKNOWN, + `Getting metadata from plugin failed with error: ${error.message}` ); this.outputStatus( { - code: Status.INTERNAL, - details: 'Failed to start HTTP/2 stream with error ' + (error as Error).message, - metadata: new Metadata() + code: code, + details: details, + metadata: new Metadata(), }, - 'NOT_STARTED' + 'PROCESSED' ); - 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.child.halfClose(); - } - }, (error: Error & { code: number }) => { - // We assume the error code isn't 0 (Status.OK) - const {code, details} = restrictControlPlaneStatusCode( - typeof error.code === 'number' ? error.code : Status.UNKNOWN, - `Getting metadata from plugin failed with error: ${error.message}` - ) - this.outputStatus( - { - code: code, - details: details, - metadata: new Metadata() - }, - 'PROCESSED' - ); - } - ); + ); break; case PickResultType.DROP: - const {code, details} = restrictControlPlaneStatusCode(pickResult.status!.code, pickResult.status!.details); - this.outputStatus({code, details, metadata: pickResult.status!.metadata}, 'DROP'); + const { code, details } = restrictControlPlaneStatusCode( + pickResult.status!.code, + pickResult.status!.details + ); + 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'); + const { code, details } = restrictControlPlaneStatusCode( + pickResult.status!.code, + pickResult.status!.details + ); + this.outputStatus( + { code, details, metadata: pickResult.status!.metadata }, + 'PROCESSED' + ); } break; case PickResultType.QUEUE: @@ -232,14 +287,22 @@ export class LoadBalancingCall implements Call { } cancelWithStatus(status: Status, details: string): void { - this.trace('cancelWithStatus code: ' + status + ' details: "' + details + '"'); + this.trace( + 'cancelWithStatus code: ' + status + ' details: "' + details + '"' + ); this.child?.cancelWithStatus(status, details); - this.outputStatus({code: status, details: details, metadata: new Metadata()}, 'PROCESSED'); + this.outputStatus( + { code: status, details: details, metadata: new Metadata() }, + 'PROCESSED' + ); } getPeer(): string { return this.child?.getPeer() ?? this.channel.getTarget(); } - start(metadata: Metadata, listener: LoadBalancingCallInterceptingListener): void { + start( + metadata: Metadata, + listener: LoadBalancingCallInterceptingListener + ): void { this.trace('start called'); this.listener = listener; this.metadata = metadata; @@ -250,7 +313,7 @@ export class LoadBalancingCall implements Call { if (this.child) { this.child.sendMessageWithContext(context, message); } else { - this.pendingMessage = {context, message}; + this.pendingMessage = { context, message }; } } startRead(): void { @@ -270,10 +333,10 @@ export class LoadBalancingCall implements Call { } } setCredentials(credentials: CallCredentials): void { - throw new Error("Method not implemented."); + throw new Error('Method not implemented.'); } getCallNumber(): number { return this.callNumber; } -} \ No newline at end of file +} diff --git a/packages/grpc-js/src/logging.ts b/packages/grpc-js/src/logging.ts index ec845c1a5..83438ef73 100644 --- a/packages/grpc-js/src/logging.ts +++ b/packages/grpc-js/src/logging.ts @@ -27,7 +27,7 @@ const DEFAULT_LOGGER: Partial = { debug: (message?: any, ...optionalParams: any[]) => { console.error('D ' + message, ...optionalParams); }, -} +}; let _logger: Partial = DEFAULT_LOGGER; let _logVerbosity: LogVerbosity = LogVerbosity.ERROR; @@ -114,6 +114,7 @@ export function trace( } export function isTracerEnabled(tracer: string): boolean { - return !disabledTracers.has(tracer) && - (allEnabled || enabledTracers.has(tracer)); + return ( + !disabledTracers.has(tracer) && (allEnabled || enabledTracers.has(tracer)) + ); } diff --git a/packages/grpc-js/src/make-client.ts b/packages/grpc-js/src/make-client.ts index 7d08fee20..10d1e959c 100644 --- a/packages/grpc-js/src/make-client.ts +++ b/packages/grpc-js/src/make-client.ts @@ -132,7 +132,7 @@ export function makeClientConstructor( [methodName: string]: Function; } - Object.keys(methods).forEach((name) => { + Object.keys(methods).forEach(name => { if (isPrototypePolluted(name)) { return; } diff --git a/packages/grpc-js/src/max-message-size-filter.ts b/packages/grpc-js/src/max-message-size-filter.ts index 62d01077c..d0f791624 100644 --- a/packages/grpc-js/src/max-message-size-filter.ts +++ b/packages/grpc-js/src/max-message-size-filter.ts @@ -28,9 +28,7 @@ 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 - ) { + constructor(private readonly options: ChannelOptions) { super(); if ('grpc.max_send_message_length' in options) { this.maxSendMessageSize = options['grpc.max_send_message_length']!; @@ -51,7 +49,7 @@ export class MaxMessageSizeFilter extends BaseFilter implements Filter { throw { code: Status.RESOURCE_EXHAUSTED, details: `Sent message larger than max (${concreteMessage.message.length} vs. ${this.maxSendMessageSize})`, - metadata: new Metadata() + metadata: new Metadata(), }; } else { return concreteMessage; @@ -70,7 +68,7 @@ export class MaxMessageSizeFilter extends BaseFilter implements Filter { throw { code: Status.RESOURCE_EXHAUSTED, details: `Received message larger than max (${concreteMessage.length} vs. ${this.maxReceiveMessageSize})`, - metadata: new Metadata() + metadata: new Metadata(), }; } else { return concreteMessage; @@ -80,7 +78,8 @@ export class MaxMessageSizeFilter extends BaseFilter implements Filter { } export class MaxMessageSizeFilterFactory - implements FilterFactory { + implements FilterFactory +{ constructor(private readonly options: ChannelOptions) {} createFilter(): MaxMessageSizeFilter { diff --git a/packages/grpc-js/src/metadata.ts b/packages/grpc-js/src/metadata.ts index 0dddd9465..f5ab6bd3f 100644 --- a/packages/grpc-js/src/metadata.ts +++ b/packages/grpc-js/src/metadata.ts @@ -118,7 +118,8 @@ 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]); @@ -174,7 +175,7 @@ export class Metadata { const newInternalRepr = newMetadata.internalRepr; for (const [key, value] of this.internalRepr) { - const clonedValue: MetadataValue[] = value.map((v) => { + const clonedValue: MetadataValue[] = value.map(v => { if (Buffer.isBuffer(v)) { return Buffer.from(v); } else { @@ -264,12 +265,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 { @@ -278,7 +279,7 @@ export class Metadata { } } else { if (Array.isArray(values)) { - values.forEach((value) => { + values.forEach(value => { result.add(key, value); }); } else if (values !== undefined) { @@ -286,7 +287,9 @@ export class Metadata { } } } catch (error) { - const message = `Failed to add metadata entry ${key}: ${values}. ${getErrorMessage(error)}. 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); } } @@ -296,5 +299,5 @@ export class Metadata { } const bufToString = (val: string | Buffer): string => { - return Buffer.isBuffer(val) ? val.toString('base64') : val + return Buffer.isBuffer(val) ? val.toString('base64') : val; }; diff --git a/packages/grpc-js/src/object-stream.ts b/packages/grpc-js/src/object-stream.ts index 22ab8a41f..946d4afed 100644 --- a/packages/grpc-js/src/object-stream.ts +++ b/packages/grpc-js/src/object-stream.ts @@ -37,8 +37,15 @@ export interface IntermediateObjectWritable extends Writable { write(chunk: any & T, encoding?: any, cb?: WriteCallback): boolean; setDefaultEncoding(encoding: string): 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; + 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 { @@ -47,6 +54,13 @@ export interface ObjectWritable extends IntermediateObjectWritable { write(chunk: T, encoding?: any, cb?: Function): boolean; setDefaultEncoding(encoding: string): 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; + end( + chunk: T, + cb?: Function + ): ReturnType extends Writable ? this : void; + end( + chunk: T, + encoding?: any, + cb?: Function + ): ReturnType extends Writable ? this : void; } diff --git a/packages/grpc-js/src/picker.ts b/packages/grpc-js/src/picker.ts index 162596ef5..d95eca21b 100644 --- a/packages/grpc-js/src/picker.ts +++ b/packages/grpc-js/src/picker.ts @@ -114,7 +114,7 @@ export class UnavailablePicker implements Picker { subchannel: null, status: this.status, onCallStarted: null, - onCallEnded: null + onCallEnded: null, }; } } @@ -143,7 +143,7 @@ export class QueuePicker { subchannel: null, status: null, onCallStarted: null, - onCallEnded: null + onCallEnded: null, }; } } diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 355ce2dfd..f5ea6ad4b 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -61,7 +61,7 @@ function mergeArrays(...arrays: T[][]): T[] { i < Math.max.apply( null, - arrays.map((array) => array.length) + arrays.map(array => array.length) ); i++ ) { @@ -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'], @@ -150,7 +150,9 @@ 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.minTimeBetweenResolutionsMs = + channelOptions['grpc.dns_min_time_between_resolutions_ms'] ?? + DEFAULT_MIN_TIME_BETWEEN_RESOLUTIONS_MS; this.nextResolutionTimer = setTimeout(() => {}, 0); clearTimeout(this.nextResolutionTimer); } @@ -204,24 +206,23 @@ class DnsResolver implements Resolver { * error is indistinguishable from other kinds of errors */ this.pendingLookupPromise = dnsLookupPromise(hostname, { all: true }); this.pendingLookupPromise.then( - (addressList) => { + addressList => { this.pendingLookupPromise = null; this.backoff.reset(); this.backoff.stop(); const ip4Addresses: dns.LookupAddress[] = addressList.filter( - (addr) => addr.family === 4 + addr => addr.family === 4 ); const ip6Addresses: dns.LookupAddress[] = addressList.filter( - (addr) => addr.family === 6 + addr => addr.family === 6 + ); + this.latestLookupResult = mergeArrays(ip6Addresses, ip4Addresses).map( + addr => ({ host: addr.address, port: +this.port! }) ); - this.latestLookupResult = mergeArrays( - ip6Addresses, - ip4Addresses - ).map((addr) => ({ host: addr.address, port: +this.port! })); const allAddressesString: string = '[' + this.latestLookupResult - .map((addr) => addr.host + ':' + addr.port) + .map(addr => addr.host + ':' + addr.port) .join(',') + ']'; trace( @@ -246,7 +247,7 @@ class DnsResolver implements Resolver { {} ); }, - (err) => { + err => { trace( 'Resolution error for target ' + uriToString(this.target) + @@ -266,7 +267,7 @@ class DnsResolver implements Resolver { * lookup fails */ this.pendingTxtPromise = resolveTxtPromise(hostname); this.pendingTxtPromise.then( - (txtRecord) => { + txtRecord => { this.pendingTxtPromise = null; try { this.latestServiceConfig = extractAndSelectServiceConfig( @@ -294,7 +295,7 @@ class DnsResolver implements Resolver { ); } }, - (err) => { + err => { /* 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 diff --git a/packages/grpc-js/src/resolving-call.ts b/packages/grpc-js/src/resolving-call.ts index f29fb7fd7..9c4b18913 100644 --- a/packages/grpc-js/src/resolving-call.ts +++ b/packages/grpc-js/src/resolving-call.ts @@ -15,22 +15,35 @@ * */ -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 { FilterStack, FilterStackFactory } from "./filter-stack"; -import { InternalChannel } from "./internal-channel"; -import { Metadata } from "./metadata"; +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 { FilterStack, FilterStackFactory } from './filter-stack'; +import { InternalChannel } from './internal-channel'; +import { Metadata } from './metadata'; import * as logging from './logging'; -import { restrictControlPlaneStatusCode } from "./control-plane-status"; +import { restrictControlPlaneStatusCode } from './control-plane-status'; 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 pendingMessage: { context: MessageContext; message: Buffer } | null = + null; private pendingHalfClose = false; private ended = false; private readFilterPending = false; @@ -61,8 +74,14 @@ export class ResolvingCall implements 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( + 'Propagating deadline from parent: ' + + options.parentCall.getDeadline() + ); + this.deadline = minDeadline( + this.deadline, + options.parentCall.getDeadline() + ); } } this.trace('Created'); @@ -84,11 +103,8 @@ export class ResolvingCall implements Call { if (timeout !== Infinity) { this.trace('Deadline will be reached in ' + timeout + 'ms'); const handleDeadline = () => { - this.cancelWithStatus( - Status.DEADLINE_EXCEEDED, - 'Deadline exceeded' - ); - } + this.cancelWithStatus(Status.DEADLINE_EXCEEDED, 'Deadline exceeded'); + }; if (timeout <= 0) { process.nextTick(handleDeadline); } else { @@ -105,7 +121,13 @@ export class ResolvingCall implements Call { } clearTimeout(this.deadlineTimer); const filteredStatus = this.filterStack.receiveTrailers(status); - this.trace('ended with status: code=' + filteredStatus.code + ' details="' + filteredStatus.details + '"'); + this.trace( + 'ended with status: code=' + + filteredStatus.code + + ' details="' + + filteredStatus.details + + '"' + ); this.statusWatchers.forEach(watcher => watcher(filteredStatus)); process.nextTick(() => { this.listener?.onReceiveStatus(filteredStatus); @@ -119,15 +141,20 @@ export class ResolvingCall implements Call { } 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(); + 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); } - }, (status: StatusObject) => { - this.cancelWithStatus(status.code, status.details); - }); + ); } getConfig(): void { @@ -152,11 +179,14 @@ export class ResolvingCall implements Call { // configResult.type === 'SUCCESS' const config = configResult.config; if (config.status !== Status.OK) { - const {code, details} = restrictControlPlaneStatusCode(config.status, 'Failed to route call to method ' + this.method); + const { code, details } = restrictControlPlaneStatusCode( + config.status, + 'Failed to route call to method ' + this.method + ); this.outputStatus({ code: code, details: details, - metadata: new Metadata() + metadata: new Metadata(), }); return; } @@ -176,48 +206,65 @@ export class ResolvingCall implements Call { this.filterStackFactory.push(config.dynamicFilterFactories); 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) { - this.outputStatus(this.pendingChildStatus); + 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) { + this.outputStatus(this.pendingChildStatus); + } + }, + (status: StatusObject) => { + this.cancelWithStatus(status.code, status.details); + } + ); + }, + onReceiveStatus: status => { + this.trace('Received status'); + if (this.readFilterPending) { + this.pendingChildStatus = status; + } else { + this.outputStatus(status); } - }, (status: StatusObject) => { - this.cancelWithStatus(status.code, status.details); - }); - }, - onReceiveStatus: status => { - this.trace('Received 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.sendMessageOnChild(this.pendingMessage.context, this.pendingMessage.message); - } else 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); } - }, (status: StatusObject) => { - this.outputStatus(status); - }) + ); } reportResolverError(status: StatusObject) { @@ -228,9 +275,15 @@ export class ResolvingCall implements Call { } } cancelWithStatus(status: Status, details: string): void { - this.trace('cancelWithStatus code: ' + status + ' details: "' + details + '"'); + this.trace( + 'cancelWithStatus code: ' + status + ' details: "' + details + '"' + ); this.child?.cancelWithStatus(status, details); - this.outputStatus({code: status, details: details, metadata: new Metadata()}); + this.outputStatus({ + code: status, + details: details, + metadata: new Metadata(), + }); } getPeer(): string { return this.child?.getPeer() ?? this.channel.getTarget(); @@ -246,7 +299,7 @@ export class ResolvingCall implements Call { if (this.child) { this.sendMessageOnChild(context, message); } else { - this.pendingMessage = {context, message}; + this.pendingMessage = { context, message }; } } startRead(): void { @@ -276,4 +329,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..064053bc9 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -53,7 +53,7 @@ function getDefaultConfigSelector( methodName: string, metadata: Metadata ) { - const splitName = methodName.split('/').filter((x) => x.length > 0); + const splitName = methodName.split('/').filter(x => x.length > 0); const service = splitName[0] ?? ''; const method = splitName[1] ?? ''; if (serviceConfig && serviceConfig.methodConfig) { @@ -67,7 +67,7 @@ function getDefaultConfigSelector( methodConfig: methodConfig, pickInformation: {}, status: Status.OK, - dynamicFilterFactories: [] + dynamicFilterFactories: [], }; } } @@ -77,7 +77,7 @@ function getDefaultConfigSelector( methodConfig: { name: [] }, pickInformation: {}, status: Status.OK, - dynamicFilterFactories: [] + dynamicFilterFactories: [], }; }; } @@ -153,9 +153,8 @@ 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. @@ -172,12 +171,10 @@ export class ResolvingLoadBalancer implements LoadBalancer { this.latestChildPicker = picker; this.updateState(newState, picker); }, - addChannelzChild: channelControlHelper.addChannelzChild.bind( - channelControlHelper - ), - removeChannelzChild: channelControlHelper.removeChannelzChild.bind( - channelControlHelper - ) + addChannelzChild: + channelControlHelper.addChannelzChild.bind(channelControlHelper), + removeChannelzChild: + channelControlHelper.removeChannelzChild.bind(channelControlHelper), }); this.innerResolver = createResolver( target, @@ -299,7 +296,10 @@ export class ResolvingLoadBalancer implements LoadBalancer { } exitIdle() { - if (this.currentState === ConnectivityState.IDLE || this.currentState === ConnectivityState.TRANSIENT_FAILURE) { + if ( + this.currentState === ConnectivityState.IDLE || + this.currentState === ConnectivityState.TRANSIENT_FAILURE + ) { if (this.backoffTimeout.isRunning()) { this.continueResolving = true; } else { diff --git a/packages/grpc-js/src/retrying-call.ts b/packages/grpc-js/src/retrying-call.ts index 5ae585b9e..c329161c3 100644 --- a/packages/grpc-js/src/retrying-call.ts +++ b/packages/grpc-js/src/retrying-call.ts @@ -15,25 +15,41 @@ * */ -import { CallCredentials } from "./call-credentials"; -import { LogVerbosity, Status } from "./constants"; -import { Deadline } from "./deadline"; -import { Metadata } from "./metadata"; -import { CallConfig } from "./resolver"; +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"; +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) { + 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); + this.tokens = + previousRetryThrottler.tokens * + (maxTokens / previousRetryThrottler.maxTokens); } else { this.tokens = maxTokens; } @@ -53,14 +69,17 @@ export class RetryThrottler { } export class MessageBufferTracker { - private totalAllocated: number = 0; + private totalAllocated = 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) { + if ( + this.limitPerCall - currentPerCall < size || + this.totalLimit - this.totalAllocated < size + ) { return false; } this.allocatedPerCall.set(callId, currentPerCall + size); @@ -70,12 +89,16 @@ export class MessageBufferTracker { free(size: number, callId: number) { if (this.totalAllocated < size) { - throw new Error(`Invalid buffer allocation state: call ${callId} freed ${size} > total allocated ${this.totalAllocated}`); + 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}`); + throw new Error( + `Invalid buffer allocation state: call ${callId} freed ${size} > allocated for call ${currentPerCall}` + ); } this.allocatedPerCall.set(callId, currentPerCall - size); } @@ -83,7 +106,9 @@ export class MessageBufferTracker { 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}`); + throw new Error( + `Invalid buffer allocation state: call ${callId} allocated ${currentPerCall} > total allocated ${this.totalAllocated}` + ); } this.totalAllocated -= currentPerCall; this.allocatedPerCall.delete(callId); @@ -164,11 +189,11 @@ export class RetryingCall implements Call { * be no new child calls. */ private readStarted = false; - private transparentRetryUsed: boolean = false; + private transparentRetryUsed = false; /** * Number of attempts so far */ - private attempts: number = 0; + private attempts = 0; private hedgingTimer: NodeJS.Timer | null = null; private committedCallIndex: number | null = null; private initialRetryBackoffSec = 0; @@ -187,7 +212,12 @@ export class RetryingCall implements Call { 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)); + this.nextRetryBackoffSec = this.initialRetryBackoffSec = Number( + retryPolicy.initialBackoff.substring( + 0, + retryPolicy.initialBackoff.length - 1 + ) + ); } else if (callConfig.methodConfig.hedgingPolicy) { this.state = 'HEDGING'; } else { @@ -207,7 +237,13 @@ export class RetryingCall implements Call { } private reportStatus(statusObject: StatusObject) { - this.trace('ended with status: code=' + statusObject.code + ' details="' + statusObject.details + '"'); + this.trace( + 'ended with status: code=' + + statusObject.code + + ' details="' + + statusObject.details + + '"' + ); this.bufferTracker.freeAll(this.callNumber); this.writeBufferOffset = this.writeBufferOffset + this.writeBuffer.length; this.writeBuffer = []; @@ -216,15 +252,17 @@ export class RetryingCall implements Call { this.listener?.onReceiveStatus({ code: statusObject.code, details: statusObject.details, - metadata: statusObject.metadata + metadata: statusObject.metadata, }); }); } 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) { + 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); } } @@ -237,7 +275,12 @@ export class RetryingCall implements Call { } private getBufferEntry(messageIndex: number): WriteBufferEntry { - return this.writeBuffer[messageIndex - this.writeBufferOffset] ?? {entryType: 'FREED', allocated: false}; + return ( + this.writeBuffer[messageIndex - this.writeBufferOffset] ?? { + entryType: 'FREED', + allocated: false, + } + ); } private getNextBufferIndex() { @@ -248,14 +291,24 @@ export class RetryingCall implements Call { if (this.state !== 'COMMITTED') { return; } - const earliestNeededMessageIndex = this.underlyingCalls[this.committedCallIndex!].nextMessageToSend; - for (let messageIndex = this.writeBufferOffset; messageIndex < earliestNeededMessageIndex; messageIndex++) { + 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.bufferTracker.free( + bufferEntry.message!.message.length, + this.callNumber + ); } } - this.writeBuffer = this.writeBuffer.slice(earliestNeededMessageIndex - this.writeBufferOffset); + this.writeBuffer = this.writeBuffer.slice( + earliestNeededMessageIndex - this.writeBufferOffset + ); this.writeBufferOffset = earliestNeededMessageIndex; } @@ -266,7 +319,12 @@ export class RetryingCall implements Call { if (this.underlyingCalls[index].state === 'COMPLETED') { return; } - this.trace('Committing call [' + this.underlyingCalls[index].call.getCallNumber() + '] at index ' + index); + 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++) { @@ -277,7 +335,10 @@ export class RetryingCall implements Call { continue; } this.underlyingCalls[i].state = 'COMPLETED'; - this.underlyingCalls[i].call.cancelWithStatus(Status.CANCELLED, 'Discarded in favor of other hedged attempt'); + this.underlyingCalls[i].call.cancelWithStatus( + Status.CANCELLED, + 'Discarded in favor of other hedged attempt' + ); } this.clearSentMessages(); } @@ -289,7 +350,10 @@ export class RetryingCall implements Call { let mostMessages = -1; let callWithMostMessages = -1; for (const [index, childCall] of this.underlyingCalls.entries()) { - if (childCall.state === 'ACTIVE' && childCall.nextMessageToSend > mostMessages) { + if ( + childCall.state === 'ACTIVE' && + childCall.nextMessageToSend > mostMessages + ) { mostMessages = childCall.nextMessageToSend; callWithMostMessages = index; } @@ -304,7 +368,11 @@ export class RetryingCall implements Call { } private isStatusCodeInList(list: (Status | string)[], code: Status) { - return list.some((value => value === code || value.toString().toLowerCase() === Status[code].toLowerCase())); + return list.some( + value => + value === code || + value.toString().toLowerCase() === Status[code].toLowerCase() + ); } private getNextRetryBackoffMs() { @@ -313,12 +381,20 @@ export class RetryingCall implements Call { 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 + 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) { + private maybeRetryCall( + pushback: number | null, + callback: (retried: boolean) => void + ) { if (this.state !== 'RETRY') { callback(false); return; @@ -362,7 +438,11 @@ export class RetryingCall implements Call { return count; } - private handleProcessedStatus(status: StatusObject, callIndex: number, pushback: number | null) { + private handleProcessedStatus( + status: StatusObject, + callIndex: number, + pushback: number | null + ) { switch (this.state) { case 'COMMITTED': case 'TRANSPARENT_ONLY': @@ -370,7 +450,13 @@ 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) { @@ -397,9 +483,14 @@ export class RetryingCall implements Call { } break; case 'RETRY': - if (this.isStatusCodeInList(this.callConfig!.methodConfig.retryPolicy!.retryableStatusCodes, status.code)) { + if ( + this.isStatusCodeInList( + this.callConfig!.methodConfig.retryPolicy!.retryableStatusCodes, + status.code + ) + ) { this.retryThrottler?.addCallFailed(); - this.maybeRetryCall(pushback, (retried) => { + this.maybeRetryCall(pushback, retried => { if (!retried) { this.commitCall(callIndex); this.reportStatus(status); @@ -425,11 +516,23 @@ export class RetryingCall implements Call { } } - private handleChildStatus(status: StatusObjectWithProgress, callIndex: number) { + private handleChildStatus( + status: StatusObjectWithProgress, + callIndex: number + ) { if (this.underlyingCalls[callIndex].state === 'COMPLETED') { return; } - 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.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(); @@ -454,7 +557,7 @@ export class RetryingCall implements Call { } else { this.transparentRetryUsed = true; this.startNewAttempt(); - }; + } break; case 'DROP': this.commitCall(callIndex); @@ -497,7 +600,9 @@ export class RetryingCall implements Call { return; } const hedgingDelayString = hedgingPolicy.hedgingDelay ?? '0s'; - const hedgingDelaySec = Number(hedgingDelayString.substring(0, hedgingDelayString.length - 1)); + const hedgingDelaySec = Number( + hedgingDelayString.substring(0, hedgingDelayString.length - 1) + ); this.hedgingTimer = setTimeout(() => { this.maybeStartHedgingAttempt(); }, hedgingDelaySec * 1000); @@ -505,42 +610,72 @@ export class RetryingCall implements Call { } 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 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}); + 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}`); + initialMetadata.set( + PREVIONS_RPC_ATTEMPTS_METADATA_KEY, + `${previousAttempts}` + ); } let receivedMetadata = false; child.start(initialMetadata, { onReceiveMetadata: metadata => { - this.trace('Received metadata from child [' + child.getCallNumber() + ']'); + this.trace( + 'Received metadata from child [' + child.getCallNumber() + ']' + ); this.commitCall(index); receivedMetadata = true; if (previousAttempts > 0) { - metadata.set(PREVIONS_RPC_ATTEMPTS_METADATA_KEY, `${previousAttempts}`); + metadata.set( + PREVIONS_RPC_ATTEMPTS_METADATA_KEY, + `${previousAttempts}` + ); } if (this.underlyingCalls[index].state === 'ACTIVE') { this.listener!.onReceiveMetadata(metadata); } }, onReceiveMessage: message => { - this.trace('Received message from child [' + child.getCallNumber() + ']'); + 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() + ']'); + this.trace( + 'Received status from child [' + child.getCallNumber() + ']' + ); if (!receivedMetadata && previousAttempts > 0) { - status.metadata.set(PREVIONS_RPC_ATTEMPTS_METADATA_KEY, `${previousAttempts}`); + status.metadata.set( + PREVIONS_RPC_ATTEMPTS_METADATA_KEY, + `${previousAttempts}` + ); } this.handleChildStatus(status, index); - } + }, }); this.sendNextChildMessage(index); if (this.readStarted) { @@ -575,12 +710,15 @@ export class RetryingCall implements Call { const bufferEntry = this.getBufferEntry(childCall.nextMessageToSend); switch (bufferEntry.entryType) { case 'MESSAGE': - childCall.call.sendMessageWithContext({ - callback: (error) => { - // Ignore error - this.handleChildWriteCompleted(childIndex); - } - }, bufferEntry.message!.message); + childCall.call.sendMessageWithContext( + { + callback: error => { + // Ignore error + this.handleChildWriteCompleted(childIndex); + }, + }, + bufferEntry.message!.message + ); break; case 'HALF_CLOSE': childCall.nextMessageToSend += 1; @@ -603,19 +741,25 @@ export class RetryingCall implements Call { const bufferEntry: WriteBufferEntry = { entryType: 'MESSAGE', message: writeObj, - allocated: this.bufferTracker.allocate(message.length, this.callNumber) + allocated: this.bufferTracker.allocate(message.length, this.callNumber), }; this.writeBuffer.push(bufferEntry); 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 - this.handleChildWriteCompleted(callIndex); - } - }, message); + if ( + call.state === 'ACTIVE' && + call.nextMessageToSend === messageIndex + ) { + call.call.sendMessageWithContext( + { + callback: error => { + // Ignore error + this.handleChildWriteCompleted(callIndex); + }, + }, + message + ); } } } else { @@ -625,14 +769,17 @@ 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) => { - // Ignore error - this.handleChildWriteCompleted(this.committedCallIndex!); - } - }, message); + call.call.sendMessageWithContext( + { + callback: error => { + // Ignore error + this.handleChildWriteCompleted(this.committedCallIndex!); + }, + }, + message + ); } } } @@ -650,17 +797,20 @@ export class RetryingCall implements Call { const halfCloseIndex = this.getNextBufferIndex(); this.writeBuffer.push({ entryType: 'HALF_CLOSE', - allocated: false + allocated: false, }); for (const call of this.underlyingCalls) { - if (call?.state === 'ACTIVE' && call.nextMessageToSend === halfCloseIndex) { + if ( + call?.state === 'ACTIVE' && + call.nextMessageToSend === halfCloseIndex + ) { call.nextMessageToSend += 1; call.call.halfClose(); } } } setCredentials(newCredentials: CallCredentials): void { - throw new Error("Method not implemented."); + throw new Error('Method not implemented.'); } getMethod(): string { return this.methodName; @@ -668,4 +818,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 48186bc29..c03258308 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -68,7 +68,7 @@ const defaultCompressionHeaders = { // 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', @@ -199,7 +199,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(); }); @@ -237,7 +237,7 @@ export class ServerWritableStreamImpl } catch (err) { this.emit('error', { details: getErrorMessage(err), - code: Status.INTERNAL + code: Status.INTERNAL, }); } @@ -283,7 +283,7 @@ export class ServerDuplexStreamImpl this.call.setupSurfaceCall(this); this.call.setupReadable(this, encoding); - this.on('error', (err) => { + this.on('error', err => { this.call.sendError(err); this.end(); }); @@ -502,7 +502,11 @@ export class Http2ServerCallStream< this.metadataSent = true; const custom = customMetadata ? customMetadata.toHttp2Headers() : null; // TODO(cjihrig): Include compression headers. - const headers = { ...defaultResponseHeaders, ...defaultCompressionHeaders, ...custom }; + const headers = { + ...defaultResponseHeaders, + ...defaultCompressionHeaders, + ...custom, + }; this.stream.respond(headers, defaultResponseOptions); } @@ -559,6 +563,8 @@ export class Http2ServerCallStream< const { stream } = this; let receivedLength = 0; + + // eslint-disable-next-line @typescript-eslint/no-this-alias const call = this; const body: Buffer[] = []; const limit = this.maxReceiveMessageSize; @@ -595,7 +601,10 @@ export class Http2ServerCallStream< } if (receivedLength === 0) { - next({ code: Status.INTERNAL, details: 'received empty unary message' }) + next({ + code: Status.INTERNAL, + details: 'received empty unary message', + }); return; } @@ -615,29 +624,33 @@ export class Http2ServerCallStream< } 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`, - } - ) - ) + 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 + next: ( + err: Partial | null, + request?: RequestType + ) => void ) { try { next(null, this.deserializeMessage(buffer)); } catch (err) { next({ details: getErrorMessage(err), - code: Status.INTERNAL + code: Status.INTERNAL, }); } } @@ -688,7 +701,7 @@ export class Http2ServerCallStream< } catch (err) { this.sendError({ details: getErrorMessage(err), - code: Status.INTERNAL + code: Status.INTERNAL, }); } } @@ -720,7 +733,7 @@ export class Http2ServerCallStream< [GRPC_MESSAGE_HEADER]: encodeURI(statusObj.details), ...statusObj.metadata?.toHttp2Headers(), }; - + this.stream.sendTrailers(trailersToSend); this.statusSent = true; }); @@ -734,7 +747,7 @@ export class Http2ServerCallStream< ...defaultResponseHeaders, ...statusObj.metadata?.toHttp2Headers(), }; - this.stream.respond(trailersToSend, {endStream: true}); + this.stream.respond(trailersToSend, { endStream: true }); this.statusSent = true; } } @@ -790,12 +803,12 @@ export class Http2ServerCallStream< } setupSurfaceCall(call: ServerSurfaceCall) { - this.once('cancelled', (reason) => { + this.once('cancelled', reason => { call.cancelled = true; call.emit('cancelled', reason); }); - this.once('callEnd', (status) => call.emit('callEnd', status)); + this.once('callEnd', status => call.emit('callEnd', status)); } setupReadable( @@ -931,12 +944,12 @@ export class Http2ServerCallStream< this.bufferedMessages.length = 0; let code = getErrorCode(error); if (code === null || code < Status.OK || code > Status.UNAUTHENTICATED) { - code = Status.INTERNAL + code = Status.INTERNAL; } readable.emit('error', { details: getErrorMessage(error), - code: code + code: code, }); } diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index d19186a75..b9ad8096d 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -59,17 +59,27 @@ import { stringToSubchannelAddress, } from './subchannel-address'; import { parseUri } from './uri-parser'; -import { ChannelzCallTracker, ChannelzChildrenTracker, ChannelzTrace, registerChannelzServer, registerChannelzSocket, ServerInfo, ServerRef, SocketInfo, SocketRef, TlsInfo, unregisterChannelzRef } from './channelz'; +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); +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 +const { HTTP2_HEADER_PATH } = http2.constants; const TRACER_NAME = 'server'; @@ -101,9 +111,8 @@ export interface UntypedServiceImplementation { } function getDefaultHandler(handlerType: HandlerType, methodName: string) { - const unimplementedStatusResponse = getUnimplementedStatusResponse( - methodName - ); + const unimplementedStatusResponse = + getUnimplementedStatusResponse(methodName); switch (handlerType) { case 'unary': return ( @@ -146,7 +155,10 @@ interface ChannelzListenerInfo { } export class Server { - private http2ServerList: { server: (http2.Http2Server | http2.Http2SecureServer), channelzRef: SocketRef }[] = []; + private http2ServerList: { + server: http2.Http2Server | http2.Http2SecureServer; + channelzRef: SocketRef; + }[] = []; private handlers: Map = new Map< string, @@ -155,7 +167,7 @@ export class Server { private sessions = new Map(); private started = false; private options: ChannelOptions; - private serverAddressString: string = 'null' + private serverAddressString = 'null'; // Channelz Info private readonly channelzEnabled: boolean = true; @@ -176,14 +188,22 @@ export class Server { if (this.options['grpc.enable_channelz'] === 0) { this.channelzEnabled = false; } - this.channelzRef = registerChannelzServer(() => this.getChannelzInfo(), this.channelzEnabled); + this.channelzRef = registerChannelzServer( + () => this.getChannelzInfo(), + this.channelzEnabled + ); 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.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'); } @@ -192,27 +212,46 @@ export class Server { trace: this.channelzTrace, callTracker: this.callTracker, listenerChildren: this.listenerChildrenTracker.getChildLists(), - sessionChildren: this.sessionChildrenTracker.getChildLists() + sessionChildren: this.sessionChildrenTracker.getChildLists(), }; } - private getChannelzSessionInfoGetter(session: http2.ServerHttp2Session): () => SocketInfo { + 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 = sessionSocket.localAddress ? stringToSubchannelAddress(sessionSocket.localAddress!, sessionSocket.localPort) : null; + 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 (session.encrypted) { const tlsSocket: TLSSocket = sessionSocket as TLSSocket; - const cipherInfo: CipherNameAndProtocol & {standardName?: string} = tlsSocket.getCipher(); + 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 + 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; @@ -229,20 +268,24 @@ export class Server { messagesReceived: sessionInfo.messagesReceived, keepAlivesSent: 0, lastLocalStreamCreatedTimestamp: null, - lastRemoteStreamCreatedTimestamp: sessionInfo.streamTracker.lastCallStartedTimestamp, + lastRemoteStreamCreatedTimestamp: + sessionInfo.streamTracker.lastCallStartedTimestamp, lastMessageSentTimestamp: sessionInfo.lastMessageSentTimestamp, lastMessageReceivedTimestamp: sessionInfo.lastMessageReceivedTimestamp, localFlowControlWindow: session.state.localWindowSize ?? null, - remoteFlowControlWindow: session.state.remoteWindowSize ?? null + remoteFlowControlWindow: session.state.remoteWindowSize ?? null, }; return socketInfo; }; } private trace(text: string): void { - logging.trace(LogVerbosity.DEBUG, TRACER_NAME, '(' + this.channelzRef.id + ') ' + text); + logging.trace( + LogVerbosity.DEBUG, + TRACER_NAME, + '(' + this.channelzRef.id + ') ' + text + ); } - addProtoService(): never { throw new Error('Not implemented. Use addService() instead'); @@ -267,7 +310,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; @@ -318,7 +361,7 @@ export class Server { } const serviceKeys = Object.keys(service); - serviceKeys.forEach((name) => { + serviceKeys.forEach(name => { const attrs = service[name]; this.unregister(attrs.path); }); @@ -362,9 +405,8 @@ export class Server { 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']; } else { /* By default, set a very large max session memory limit, to effectively * disable enforcement of the limit. Some testing indicates that Node's @@ -380,7 +422,7 @@ 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; @@ -394,7 +436,9 @@ export class Server { /* 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); + this.trace( + 'An incoming TLS connection closed with error: ' + e.message + ); }); }); } else { @@ -415,8 +459,10 @@ export class Server { return Promise.resolve({ port: portNum, count: previousCount }); } return Promise.all( - addressList.map((address) => { - this.trace('Attempting to bind ' + subchannelAddressToString(address)); + addressList.map(address => { + this.trace( + 'Attempting to bind ' + subchannelAddressToString(address) + ); let addr: SubchannelAddress; if (isTcpSubchannelAddress(address)) { addr = { @@ -430,9 +476,14 @@ export class Server { const http2Server = setupServer(); return new Promise((resolve, reject) => { const onError = (err: Error) => { - this.trace('Failed to bind ' + subchannelAddressToString(address) + ' with error ' + err.message); + this.trace( + 'Failed to bind ' + + subchannelAddressToString(address) + + ' with error ' + + err.message + ); resolve(err); - } + }; http2Server.once('error', onError); @@ -441,46 +492,60 @@ export class Server { let boundSubchannelAddress: SubchannelAddress; if (typeof boundAddress === 'string') { boundSubchannelAddress = { - path: boundAddress + path: boundAddress, }; } else { boundSubchannelAddress = { host: boundAddress.address, - 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 + port: boundAddress.port, }; - }, this.channelzEnabled); + } + + 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.channelzEnabled + ); if (this.channelzEnabled) { this.listenerChildrenTracker.refChild(channelzRef); } - this.http2ServerList.push({server: http2Server, channelzRef: channelzRef}); - this.trace('Successfully bound ' + subchannelAddressToString(boundSubchannelAddress)); - resolve('port' in boundSubchannelAddress ? boundSubchannelAddress.port : portNum); + this.http2ServerList.push({ + server: http2Server, + channelzRef: channelzRef, + }); + this.trace( + 'Successfully bound ' + + subchannelAddressToString(boundSubchannelAddress) + ); + resolve( + 'port' in boundSubchannelAddress + ? boundSubchannelAddress.port + : portNum + ); http2Server.removeListener('error', onError); }); }); }) - ).then((results) => { + ).then(results => { let count = 0; for (const result of results) { if (typeof result === 'number') { @@ -509,9 +574,14 @@ export class Server { const http2Server = setupServer(); return new Promise((resolve, reject) => { const onError = (err: Error) => { - this.trace('Failed to bind ' + subchannelAddressToString(address) + ' with error ' + err.message); + this.trace( + 'Failed to bind ' + + subchannelAddressToString(address) + + ' with error ' + + err.message + ); resolve(bindWildcardPort(addressList.slice(1))); - } + }; http2Server.once('error', onError); @@ -519,41 +589,44 @@ export class Server { const boundAddress = http2Server.address() as AddressInfo; const boundSubchannelAddress: SubchannelAddress = { host: boundAddress.address, - port: boundAddress.port + 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); + 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.channelzEnabled + ); if (this.channelzEnabled) { this.listenerChildrenTracker.refChild(channelzRef); } - this.http2ServerList.push({server: http2Server, channelzRef: channelzRef}); - this.trace('Successfully bound ' + subchannelAddressToString(boundSubchannelAddress)); - resolve( - bindSpecificPort( - addressList.slice(1), - boundAddress.port, - 1 - ) + this.http2ServerList.push({ + server: http2Server, + channelzRef: channelzRef, + }); + this.trace( + 'Successfully bound ' + + subchannelAddressToString(boundSubchannelAddress) ); + resolve(bindSpecificPort(addressList.slice(1), boundAddress.port, 1)); http2Server.removeListener('error', onError); }); }); @@ -568,7 +641,10 @@ export class Server { // We only want one resolution result. Discard all future results resolverListener.onSuccessfulResolution = () => {}; if (addressList.length === 0) { - deferredCallback(new Error(`No addresses resolved for port ${port}`), 0); + deferredCallback( + new Error(`No addresses resolved for port ${port}`), + 0 + ); return; } let bindResultPromise: Promise; @@ -587,7 +663,7 @@ export class Server { bindResultPromise = bindSpecificPort(addressList, 1, 0); } bindResultPromise.then( - (bindResult) => { + bindResult => { if (bindResult.count === 0) { const errorString = `No address added out of total ${addressList.length} resolved`; logging.log(LogVerbosity.ERROR, errorString); @@ -602,14 +678,14 @@ export class Server { deferredCallback(null, bindResult.port); } }, - (error) => { + error => { const errorString = `No address added out of total ${addressList.length} resolved`; logging.log(LogVerbosity.ERROR, errorString); deferredCallback(new Error(errorString), 0); } ); }, - onError: (error) => { + onError: error => { deferredCallback(new Error(error.details), 0); }, }; @@ -621,7 +697,8 @@ export class Server { forceShutdown(): void { // Close the server if it is still running. - for (const {server: http2Server, channelzRef: ref} of this.http2ServerList) { + for (const { server: http2Server, channelzRef: ref } of this + .http2ServerList) { if (http2Server.listening) { http2Server.close(() => { if (this.channelzEnabled) { @@ -677,7 +754,7 @@ export class Server { if ( this.http2ServerList.length === 0 || this.http2ServerList.every( - ({server: http2Server}) => http2Server.listening !== true + ({ server: http2Server }) => http2Server.listening !== true ) ) { throw new Error('server must be bound in order to start'); @@ -712,7 +789,8 @@ export class Server { // Close the server if necessary. this.started = false; - for (const {server: http2Server, channelzRef: ref} of this.http2ServerList) { + for (const { server: http2Server, channelzRef: ref } of this + .http2ServerList) { if (http2Server.listening) { pendingChecks++; http2Server.close(() => { @@ -743,13 +821,16 @@ 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; } - private _verifyContentType(stream: http2.ServerHttp2Stream, headers: http2.IncomingHttpHeaders): boolean { + private _verifyContentType( + stream: http2.ServerHttp2Stream, + headers: http2.IncomingHttpHeaders + ): boolean { const contentType = headers[http2.constants.HTTP2_HEADER_CONTENT_TYPE]; if ( @@ -763,20 +844,22 @@ export class Server { }, { endStream: true } ); - return false + return false; } - return true + return true; } - private _retrieveHandler(headers: http2.IncomingHttpHeaders): Handler { - const path = headers[HTTP2_HEADER_PATH] as string + private _retrieveHandler( + headers: http2.IncomingHttpHeaders + ): Handler { + const path = headers[HTTP2_HEADER_PATH] as string; this.trace( 'Received call to method ' + - path + - ' at address ' + - this.serverAddressString + path + + ' at address ' + + this.serverAddressString ); const handler = this.handlers.get(path); @@ -784,59 +867,68 @@ export class Server { if (handler === undefined) { this.trace( 'No handler registered for method ' + - path + - '. Sending UNIMPLEMENTED status.' + path + + '. Sending UNIMPLEMENTED status.' ); throw getUnimplementedStatusResponse(path); } - return handler + 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; } if (this.channelzEnabled) { this.callTracker.addCallFailed(); - channelzSessionInfo?.streamTracker.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); - + 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 + return; } - let handler: Handler + let handler: Handler; try { - handler = this._retrieveHandler(headers) + handler = this._retrieveHandler(headers); } catch (err) { - this._respondWithError({ - details: getErrorMessage(err), - code: getErrorCode(err) ?? undefined - }, stream, channelzSessionInfo) - return + this._respondWithError( + { + details: getErrorMessage(err), + code: getErrorCode(err) ?? undefined, + }, + 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 +936,7 @@ export class Server { this.callTracker.addCallFailed(); } }); - + if (channelzSessionInfo) { call.once('streamEnd', (success: boolean) => { if (success) { @@ -865,46 +957,58 @@ export class Server { if (!this._runHandlerForCall(call, handler, headers)) { this.callTracker.addCallFailed(); - channelzSessionInfo?.streamTracker.addCallFailed() + channelzSessionInfo?.streamTracker.addCallFailed(); call.sendError({ code: Status.INTERNAL, - details: `Unknown handler type: ${handler.type}` + details: `Unknown handler type: ${handler.type}`, }); } } - private _streamHandler(stream: http2.ServerHttp2Stream, headers: http2.IncomingHttpHeaders) { + private _streamHandler( + stream: http2.ServerHttp2Stream, + headers: http2.IncomingHttpHeaders + ) { if (this._verifyContentType(stream, headers) !== true) { - return + return; } - let handler: Handler + let handler: Handler; try { - handler = this._retrieveHandler(headers) + handler = this._retrieveHandler(headers); } catch (err) { - this._respondWithError({ - details: getErrorMessage(err), - code: getErrorCode(err) ?? undefined - }, stream, null) - return + this._respondWithError( + { + details: getErrorMessage(err), + code: getErrorCode(err) ?? undefined, + }, + stream, + null + ); + return; } - const call = new Http2ServerCallStream(stream, handler, this.options) + 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}` + details: `Unknown handler type: ${handler.type}`, }); } } - private _runHandlerForCall(call: Http2ServerCallStream, handler: Handler, headers: http2.IncomingHttpHeaders): boolean { + 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'; + const encoding = + (metadata.get('grpc-encoding')[0] as string | undefined) ?? 'identity'; metadata.remove('grpc-encoding'); - const { type } = handler + const { type } = handler; if (type === 'unary') { handleUnary(call, handler as UntypedUnaryHandler, metadata, encoding); } else if (type === 'clientStream') { @@ -929,10 +1033,10 @@ export class Server { encoding ); } else { - return false + return false; } - return true + return true; } private _setupHandlers( @@ -943,30 +1047,32 @@ export class Server { } const serverAddress = http2Server.address(); - let serverAddressString = 'null' + let serverAddressString = 'null'; if (serverAddress) { if (typeof serverAddress === 'string') { - serverAddressString = serverAddress + serverAddressString = serverAddress; } else { - serverAddressString = - serverAddress.address + ':' + serverAddress.port + serverAddressString = serverAddress.address + ':' + serverAddress.port; } } - this.serverAddressString = serverAddressString + this.serverAddressString = serverAddressString; - const handler = this.channelzEnabled - ? this._channelzHandler - : this._streamHandler + const handler = this.channelzEnabled + ? this._channelzHandler + : this._streamHandler; - http2Server.on('stream', handler.bind(this)) - http2Server.on('session', (session) => { + http2Server.on('stream', handler.bind(this)); + http2Server.on('session', session => { if (!this.started) { session.destroy(); return; } - let channelzRef: SocketRef; - channelzRef = registerChannelzSocket(session.socket.remoteAddress ?? 'unknown', this.getChannelzSessionInfoGetter(session), this.channelzEnabled); + const channelzRef = registerChannelzSocket( + session.socket.remoteAddress ?? 'unknown', + this.getChannelzSessionInfoGetter(session), + this.channelzEnabled + ); const channelzSessionInfo: ChannelzSessionInfo = { ref: channelzRef, @@ -974,13 +1080,16 @@ export class Server { messagesSent: 0, messagesReceived: 0, lastMessageSentTimestamp: null, - lastMessageReceivedTimestamp: null + lastMessageReceivedTimestamp: null, }; this.sessions.set(session, channelzSessionInfo); const clientAddress = session.socket.remoteAddress; if (this.channelzEnabled) { - this.channelzTrace.addTrace('CT_INFO', 'Connection established by client ' + clientAddress); + this.channelzTrace.addTrace( + 'CT_INFO', + 'Connection established by client ' + clientAddress + ); this.sessionChildrenTracker.refChild(channelzRef); } let connectionAgeTimer: NodeJS.Timer | null = null; @@ -993,10 +1102,17 @@ export class Server { connectionAgeTimer = setTimeout(() => { sessionClosedByServer = true; if (this.channelzEnabled) { - this.channelzTrace.addTrace('CT_INFO', 'Connection dropped by max connection age from ' + clientAddress); + 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')); + 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(); @@ -1016,14 +1132,19 @@ export class Server { const timeoutTImer = setTimeout(() => { sessionClosedByServer = true; if (this.channelzEnabled) { - this.channelzTrace.addTrace('CT_INFO', 'Connection dropped by keepalive timeout from ' + clientAddress); + 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); - }); + 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(); @@ -1032,7 +1153,10 @@ export class Server { session.on('close', () => { if (this.channelzEnabled) { if (!sessionClosedByServer) { - this.channelzTrace.addTrace('CT_INFO', 'Connection dropped by client ' + clientAddress); + this.channelzTrace.addTrace( + 'CT_INFO', + 'Connection dropped by client ' + clientAddress + ); } this.sessionChildrenTracker.unrefChild(channelzRef); unregisterChannelzRef(channelzRef); @@ -1060,8 +1184,8 @@ function handleUnary( ): void { call.receiveUnaryMessage(encoding, (err, request) => { if (err) { - call.sendError(err) - return + call.sendError(err); + return; } if (request === undefined || call.cancelled) { @@ -1127,8 +1251,8 @@ function handleServerStreaming( ): void { call.receiveUnaryMessage(encoding, (err, request) => { if (err) { - call.sendError(err) - return + call.sendError(err); + return; } if (request === undefined || call.cancelled) { diff --git a/packages/grpc-js/src/service-config.ts b/packages/grpc-js/src/service-config.ts index 201c0c648..91bee52c2 100644 --- a/packages/grpc-js/src/service-config.ts +++ b/packages/grpc-js/src/service-config.ts @@ -112,35 +112,71 @@ function validateName(obj: any): MethodConfigName { } 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))) { - throw new Error('Invalid method config retry policy: retryableStatusCodes is required'); + 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)) + ) { + 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'); + 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('Invalid 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('Invalid 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('Invalid 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 { @@ -148,35 +184,53 @@ function validateRetryPolicy(obj: any): RetryPolicy { initialBackoff: obj.initialBackoff, maxBackoff: obj.maxBackoff, backoffMultiplier: obj.backoffMultiplier, - retryableStatusCodes: obj.retryableStatusCodes + 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)) { + 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'); + 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'); + 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'); + throw new Error( + 'Invlid method config hedging policy: nonFatalStatusCodes value must be a string or number' + ); } } } const result: HedgingPolicy = { - maxAttempts: obj.maxAttempts - } + maxAttempts: obj.maxAttempts, + }; if (obj.hedgingDelay) { result.hedgingDelay = obj.hedgingDelay; } @@ -246,7 +300,9 @@ function validateMethodConfig(obj: any): MethodConfig { } if ('retryPolicy' in obj) { if ('hedgingPolicy' in obj) { - throw new Error('Invalid method config: retryPolicy and hedgingPolicy cannot both be specified'); + throw new Error( + 'Invalid method config: retryPolicy and hedgingPolicy cannot both be specified' + ); } else { result.retryPolicy = validateRetryPolicy(obj.retryPolicy); } @@ -257,15 +313,28 @@ function validateMethodConfig(obj: any): MethodConfig { } 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'); + 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) + tokenRatio: +(obj.tokenRatio as number).toFixed(3), }; } diff --git a/packages/grpc-js/src/subchannel-address.ts b/packages/grpc-js/src/subchannel-address.ts index e542e645e..1ab88f45d 100644 --- a/packages/grpc-js/src/subchannel-address.ts +++ b/packages/grpc-js/src/subchannel-address.ts @@ -15,7 +15,7 @@ * */ -import { isIP } from "net"; +import { isIP } from 'net'; export interface TcpSubchannelAddress { port: number; @@ -71,15 +71,18 @@ export function subchannelAddressToString(address: SubchannelAddress): string { const DEFAULT_PORT = 443; -export function stringToSubchannelAddress(addressString: string, port?: number): SubchannelAddress { +export function stringToSubchannelAddress( + addressString: string, + port?: number +): SubchannelAddress { if (isIP(addressString)) { return { host: addressString, - port: port ?? DEFAULT_PORT + port: port ?? DEFAULT_PORT, }; } else { return { - path: addressString + path: addressString, }; } -} \ No newline at end of file +} diff --git a/packages/grpc-js/src/subchannel-call.ts b/packages/grpc-js/src/subchannel-call.ts index 969282e19..5d87fc80d 100644 --- a/packages/grpc-js/src/subchannel-call.ts +++ b/packages/grpc-js/src/subchannel-call.ts @@ -25,16 +25,18 @@ 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 { + 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; +const { HTTP2_HEADER_STATUS, HTTP2_HEADER_CONTENT_TYPE, NGHTTP2_CANCEL } = + http2.constants; /** * https://nodejs.org/api/errors.html#errors_class_systemerror @@ -79,7 +81,8 @@ export interface StatusObjectWithRstCode extends StatusObject { rstCode?: number; } -export interface SubchannelCallInterceptingListener extends InterceptingListener { +export interface SubchannelCallInterceptingListener + extends InterceptingListener { onReceiveStatus(status: StatusObjectWithRstCode): void; } @@ -235,7 +238,10 @@ export class Http2SubchannelCall implements SubchannelCall { * "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') { + if ( + this.internalError.code === 'ECONNRESET' || + this.internalError.code === 'ETIMEDOUT' + ) { code = Status.UNAVAILABLE; details = this.internalError.message; } else { @@ -255,7 +261,12 @@ 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(), rstCode: http2Stream.rstCode }); + this.endCall({ + code, + details, + metadata: new Metadata(), + rstCode: http2Stream.rstCode, + }); }); }); http2Stream.on('error', (err: SystemError) => { @@ -488,7 +499,7 @@ export class Http2SubchannelCall implements SubchannelCall { return; } /* Only resume reading from the http2Stream if we don't have any pending - * messages to emit */ + * messages to emit */ this.http2Stream.resume(); } @@ -496,7 +507,9 @@ export class Http2SubchannelCall implements SubchannelCall { 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') { + if ( + (error as NodeJS.ErrnoException)?.code === 'ERR_STREAM_WRITE_AFTER_END' + ) { code = Status.INTERNAL; } if (error) { @@ -512,7 +525,7 @@ export class Http2SubchannelCall implements SubchannelCall { this.endCall({ code: Status.UNAVAILABLE, details: `Write failed with error ${(error as Error).message}`, - metadata: new Metadata() + metadata: new Metadata(), }); } } diff --git a/packages/grpc-js/src/subchannel-interface.ts b/packages/grpc-js/src/subchannel-interface.ts index 165ebc3e1..557d62870 100644 --- a/packages/grpc-js/src/subchannel-interface.ts +++ b/packages/grpc-js/src/subchannel-interface.ts @@ -15,9 +15,9 @@ * */ -import { SubchannelRef } from "./channelz"; -import { ConnectivityState } from "./connectivity-state"; -import { Subchannel } from "./subchannel"; +import { SubchannelRef } from './channelz'; +import { ConnectivityState } from './connectivity-state'; +import { Subchannel } from './subchannel'; export type ConnectivityStateListener = ( subchannel: SubchannelInterface, @@ -30,7 +30,7 @@ export type ConnectivityStateListener = ( * 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. @@ -84,4 +84,4 @@ export abstract class BaseSubchannelWrapper implements SubchannelInterface { getRealSubchannel(): Subchannel { return this.child.getRealSubchannel(); } -} \ 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 bbfbea02b..0cbc028ed 100644 --- a/packages/grpc-js/src/subchannel-pool.ts +++ b/packages/grpc-js/src/subchannel-pool.ts @@ -68,7 +68,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 307f6b81e..480314e4a 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -27,7 +27,15 @@ import { SubchannelAddress, subchannelAddressToString, } from './subchannel-address'; -import { SubchannelRef, ChannelzTrace, ChannelzChildrenTracker, SubchannelInfo, registerChannelzSubchannel, ChannelzCallTracker, unregisterChannelzRef } from './channelz'; +import { + SubchannelRef, + ChannelzTrace, + ChannelzChildrenTracker, + SubchannelInfo, + registerChannelzSubchannel, + ChannelzCallTracker, + unregisterChannelzRef, +} from './channelz'; import { ConnectivityStateListener } from './subchannel-interface'; import { SubchannelCallInterceptingListener } from './subchannel-call'; import { SubchannelCall } from './subchannel-call'; @@ -117,11 +125,18 @@ export class Subchannel { this.channelzEnabled = false; } this.channelzTrace = new ChannelzTrace(); - this.channelzRef = registerChannelzSubchannel(this.subchannelAddressString, () => this.getChannelzInfo(), this.channelzEnabled); + this.channelzRef = registerChannelzSubchannel( + this.subchannelAddressString, + () => this.getChannelzInfo(), + this.channelzEnabled + ); if (this.channelzEnabled) { this.channelzTrace.addTrace('CT_INFO', 'Subchannel created'); } - this.trace('Subchannel constructed with options ' + JSON.stringify(options, undefined, 2)); + this.trace( + 'Subchannel constructed with options ' + + JSON.stringify(options, undefined, 2) + ); } private getChannelzInfo(): SubchannelInfo { @@ -130,16 +145,34 @@ export class Subchannel { trace: this.channelzTrace, callTracker: this.callTracker, children: this.childrenTracker.getChildLists(), - target: this.subchannelAddressString + target: this.subchannelAddressString, }; } private trace(text: string): void { - logging.trace(LogVerbosity.DEBUG, TRACER_NAME, '(' + this.channelzRef.id + ') ' + this.subchannelAddressString + ' ' + text); + 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); + logging.trace( + LogVerbosity.DEBUG, + 'subchannel_refcount', + '(' + + this.channelzRef.id + + ') ' + + this.subchannelAddressString + + ' ' + + text + ); } private handleBackoffTimer() { @@ -171,36 +204,52 @@ export class Subchannel { private startConnectingInternal() { let options = this.options; if (options['grpc.keepalive_time_ms']) { - const adjustedKeepaliveTime = Math.min(this.keepaliveTime, KEEPALIVE_MAX_TIME_MS); - options = {...options, 'grpc.keepalive_time_ms': adjustedKeepaliveTime}; + 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( - transport => { - if (this.transitionToState([ConnectivityState.CONNECTING], ConnectivityState.READY)) { - this.transport = transport; - if (this.channelzEnabled) { - this.childrenTracker.refChild(transport.getChannelzRef()); - } - transport.addDisconnectListener((tooManyPings) => { - this.transitionToState([ConnectivityState.READY], ConnectivityState.IDLE); - 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 to ${ - this.keepaliveTime - } 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()); } - }); + transport.addDisconnectListener(tooManyPings => { + this.transitionToState( + [ConnectivityState.READY], + ConnectivityState.IDLE + ); + 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 to ${ + this.keepaliveTime + } ms` + ); + } + }); + } + }, + error => { + this.transitionToState( + [ConnectivityState.CONNECTING], + ConnectivityState.TRANSIENT_FAILURE + ); } - }, - error => { - this.transitionToState([ConnectivityState.CONNECTING], ConnectivityState.TRANSIENT_FAILURE); - } - ) + ); } /** @@ -223,7 +272,12 @@ export class Subchannel { ConnectivityState[newState] ); if (this.channelzEnabled) { - this.channelzTrace.addTrace('CT_INFO', ConnectivityState[this.connectivityState] + ' -> ' + ConnectivityState[newState]); + this.channelzTrace.addTrace( + 'CT_INFO', + ConnectivityState[this.connectivityState] + + ' -> ' + + ConnectivityState[newState] + ); } const previousState = this.connectivityState; this.connectivityState = newState; @@ -268,22 +322,12 @@ export class Subchannel { } ref() { - this.refTrace( - 'refcount ' + - this.refcount + - ' -> ' + - (this.refcount + 1) - ); + this.refTrace('refcount ' + this.refcount + ' -> ' + (this.refcount + 1)); this.refcount += 1; } unref() { - this.refTrace( - 'refcount ' + - this.refcount + - ' -> ' + - (this.refcount - 1) - ); + this.refTrace('refcount ' + this.refcount + ' -> ' + (this.refcount - 1)); this.refcount -= 1; if (this.refcount === 0) { if (this.channelzEnabled) { @@ -309,7 +353,12 @@ export class Subchannel { return false; } - createCall(metadata: Metadata, host: string, method: string, listener: SubchannelCallInterceptingListener): SubchannelCall { + createCall( + metadata: Metadata, + host: string, + method: string, + listener: SubchannelCallInterceptingListener + ): SubchannelCall { if (!this.transport) { throw new Error('Cannot create call, subchannel not READY'); } @@ -324,12 +373,18 @@ export class Subchannel { } else { this.callTracker.addCallFailed(); } - } - } + }, + }; } else { statsTracker = {}; } - return this.transport.createCall(metadata, host, method, listener, statsTracker); + return this.transport.createCall( + metadata, + host, + method, + listener, + statsTracker + ); } /** @@ -341,9 +396,9 @@ export class Subchannel { startConnecting() { 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 */ + * 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], diff --git a/packages/grpc-js/src/transport.ts b/packages/grpc-js/src/transport.ts index 8abc13aba..bfdc11480 100644 --- a/packages/grpc-js/src/transport.ts +++ b/packages/grpc-js/src/transport.ts @@ -16,19 +16,40 @@ */ import * as http2 from 'http2'; -import { checkServerIdentity, CipherNameAndProtocol, ConnectionOptions, PeerCertificate, TLSSocket } from 'tls'; +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, unregisterChannelzRef } 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'; import { getDefaultAuthority } from './resolver'; -import { stringToSubchannelAddress, SubchannelAddress, subchannelAddressToString } from './subchannel-address'; +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 { + Http2SubchannelCall, + SubchannelCall, + SubchannelCallInterceptingListener, +} from './subchannel-call'; import { Metadata } from './metadata'; import { getNextCallNumber } from './call-number'; @@ -66,7 +87,13 @@ export interface TransportDisconnectListener { export interface Transport { getChannelzRef(): SocketRef; getPeerName(): string; - createCall(metadata: Metadata, host: string, method: string, listener: SubchannelCallInterceptingListener, subchannelCallStatsTracker: Partial): SubchannelCall; + createCall( + metadata: Metadata, + host: string, + method: string, + listener: SubchannelCallInterceptingListener, + subchannelCallStatsTracker: Partial + ): SubchannelCall; addDisconnectListener(listener: TransportDisconnectListener): void; shutdown(): void; } @@ -77,7 +104,7 @@ class Http2Transport implements Transport { /** * The amount of time in between sending pings */ - private keepaliveTimeMs: number = -1; + private keepaliveTimeMs = -1; /** * The amount of time to wait for an acknowledgement after sending a ping */ @@ -131,9 +158,9 @@ class Http2Transport implements Transport { `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) { this.keepaliveTimeMs = options['grpc.keepalive_time_ms']!; } @@ -157,36 +184,37 @@ class Http2Transport implements Transport { if (options['grpc.enable_channelz'] === 0) { this.channelzEnabled = false; } - this.channelzRef = registerChannelzSocket(this.subchannelAddressString, () => this.getChannelzInfo(), this.channelzEnabled); + this.channelzRef = registerChannelzSocket( + this.subchannelAddressString, + () => this.getChannelzInfo(), + this.channelzEnabled + ); session.once('close', () => { this.trace('session closed'); this.stopKeepalivePings(); this.handleDisconnect(); }); - 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; + 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.reportDisconnectToOwner(tooManyPings); } - this.trace( - 'connection closed by GOAWAY with code ' + - errorCode - ); - this.reportDisconnectToOwner(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 - ); + this.trace('connection closed with error ' + (error as Error).message); }); if (logging.isTracerEnabled(TRACER_NAME)) { session.on('remoteSettings', (settings: http2.Settings) => { @@ -210,19 +238,34 @@ class Http2Transport implements Transport { 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; + 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 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 + localCertificate: + certificate && 'raw' in certificate ? certificate.raw : null, + remoteCertificate: + peerCertificate && 'raw' in peerCertificate + ? peerCertificate.raw + : null, }; } else { tlsInfo = null; @@ -238,30 +281,67 @@ class Http2Transport implements Transport { messagesSent: this.messagesSent, messagesReceived: this.messagesReceived, keepAlivesSent: this.keepalivesSent, - lastLocalStreamCreatedTimestamp: this.streamTracker.lastCallStartedTimestamp, + lastLocalStreamCreatedTimestamp: + this.streamTracker.lastCallStartedTimestamp, lastRemoteStreamCreatedTimestamp: null, lastMessageSentTimestamp: this.lastMessageSentTimestamp, lastMessageReceivedTimestamp: this.lastMessageReceivedTimestamp, localFlowControlWindow: this.session.state.localWindowSize ?? null, - remoteFlowControlWindow: this.session.state.remoteWindowSize ?? 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); + 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); + 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); + 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); + logging.trace( + LogVerbosity.DEBUG, + 'transport_internals', + '(' + + this.channelzRef.id + + ') ' + + this.subchannelAddressString + + ' ' + + text + ); } /** @@ -271,7 +351,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) { @@ -311,7 +391,9 @@ class Http2Transport implements Transport { if (this.channelzEnabled) { this.keepalivesSent += 1; } - this.keepaliveTrace('Sending ping with timeout ' + this.keepaliveTimeoutMs + 'ms'); + this.keepaliveTrace( + 'Sending ping with timeout ' + this.keepaliveTimeoutMs + 'ms' + ); if (!this.keepaliveTimeoutId) { this.keepaliveTimeoutId = setTimeout(() => { this.keepaliveTrace('Ping timeout passed without response'); @@ -375,7 +457,13 @@ class Http2Transport implements Transport { this.activeCalls.add(call); } - createCall(metadata: Metadata, host: string, method: string, listener: SubchannelCallInterceptingListener, subchannelCallStatsTracker: Partial): Http2SubchannelCall { + 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; @@ -405,13 +493,15 @@ class Http2Transport implements Transport { this.session.state.remoteWindowSize ); this.internalsTrace( - 'session.closed=' + - this.session.closed + - ' session.destroyed=' + - this.session.destroyed + - ' session.socket.destroyed=' + - this.session.socket.destroyed); + 'session.closed=' + + this.session.closed + + ' session.destroyed=' + + this.session.destroyed + + ' session.socket.destroyed=' + + this.session.socket.destroyed + ); let eventTracker: CallEventTracker; + // eslint-disable-next-line prefer-const let call: Http2SubchannelCall; if (this.channelzEnabled) { this.streamTracker.addCallStarted(); @@ -437,8 +527,8 @@ class Http2Transport implements Transport { this.streamTracker.addCallFailed(); } subchannelCallStatsTracker.onStreamEnd?.(success); - } - } + }, + }; } else { eventTracker = { addMessageSent: () => { @@ -447,16 +537,22 @@ class Http2Transport implements Transport { addMessageReceived: () => { subchannelCallStatsTracker.addMessageReceived?.(); }, - onCallEnd: (status) => { + onCallEnd: status => { subchannelCallStatsTracker.onCallEnd?.(status); this.removeActiveCall(call); }, - onStreamEnd: (success) => { + onStreamEnd: success => { subchannelCallStatsTracker.onStreamEnd?.(success); - } - } + }, + }; } - call = new Http2SubchannelCall(http2Stream, eventTracker, listener, this, getNextCallNumber()); + call = new Http2SubchannelCall( + http2Stream, + eventTracker, + listener, + this, + getNextCallNumber() + ); this.addActiveCall(call); return call; } @@ -476,7 +572,11 @@ class Http2Transport implements Transport { } export interface SubchannelConnector { - connect(address: SubchannelAddress, credentials: ChannelCredentials, options: ChannelOptions): Promise; + connect( + address: SubchannelAddress, + credentials: ChannelCredentials, + options: ChannelOptions + ): Promise; shutdown(): void; } @@ -484,10 +584,13 @@ 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 { + private trace(text: string) {} + private createSession( + address: SubchannelAddress, + credentials: ChannelCredentials, + options: ChannelOptions, + proxyConnectionResult: ProxyConnectionResult + ): Promise { if (this.isShutdown) { return Promise.reject(); } @@ -495,10 +598,15 @@ export class Http2SubchannelConnector implements SubchannelConnector { let remoteName: string | null; if (proxyConnectionResult.realTarget) { remoteName = uriToString(proxyConnectionResult.realTarget); - this.trace('creating HTTP/2 session through proxy to ' + 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)); + this.trace( + 'creating HTTP/2 session to ' + subchannelAddressToString(address) + ); } const targetAuthority = getDefaultAuthority( proxyConnectionResult.realTarget ?? this.channelTarget @@ -507,9 +615,8 @@ export class Http2SubchannelConnector implements SubchannelConnector { credentials._getConnectionOptions() || {}; connectionOptions.maxSendHeaderBlockLength = Number.MAX_SAFE_INTEGER; if ('grpc-node.max_session_memory' in options) { - connectionOptions.maxSessionMemory = options[ - 'grpc-node.max_session_memory' - ]; + 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 @@ -524,9 +631,8 @@ export class Http2SubchannelConnector implements SubchannelConnector { // 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' - ]!; + const sslTargetNameOverride = + options['grpc.ssl_target_name_override']!; connectionOptions.checkServerIdentity = ( host: string, cert: PeerCertificate @@ -565,12 +671,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 @@ -604,11 +710,15 @@ export class Http2SubchannelConnector implements SubchannelConnector { reject(); }); session.once('error', error => { - this.trace('connection failed with error ' + (error as Error).message) + this.trace('connection failed with error ' + (error as Error).message); }); }); } - connect(address: SubchannelAddress, credentials: ChannelCredentials, options: ChannelOptions): Promise { + connect( + address: SubchannelAddress, + credentials: ChannelCredentials, + options: ChannelOptions + ): Promise { if (this.isShutdown) { return Promise.reject(); } @@ -625,9 +735,7 @@ export class Http2SubchannelConnector implements SubchannelConnector { // 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' - ]!; + const sslTargetNameOverride = options['grpc.ssl_target_name_override']!; connectionOptions.checkServerIdentity = ( host: string, cert: PeerCertificate @@ -652,11 +760,7 @@ export class Http2SubchannelConnector implements SubchannelConnector { } } - return getProxiedConnection( - address, - options, - connectionOptions - ).then( + return getProxiedConnection(address, options, connectionOptions).then( result => this.createSession(address, credentials, options, result) ); } @@ -666,4 +770,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-credentials.ts b/packages/grpc-js/test/test-call-credentials.ts index e952c5a10..007ed4847 100644 --- a/packages/grpc-js/test/test-call-credentials.ts +++ b/packages/grpc-js/test/test-call-credentials.ts @@ -86,21 +86,16 @@ describe('CallCredentials', () => { const callCredentials = CallCredentials.createFromMetadataGenerator( generateFromServiceURL ); - let metadata: Metadata; - try { - metadata = await callCredentials.generateMetadata({ - service_url: 'foo', - }); - } catch (err) { - throw err; - } + const metadata: Metadata = await callCredentials.generateMetadata({ + service_url: 'foo', + }); + assert.deepStrictEqual(metadata.get('service_url'), ['foo']); }); it('should emit an error if the associated metadataGenerator does', async () => { - const callCredentials = CallCredentials.createFromMetadataGenerator( - generateWithError - ); + const callCredentials = + CallCredentials.createFromMetadataGenerator(generateWithError); let metadata: Metadata | null = null; try { metadata = await callCredentials.generateMetadata({ service_url: '' }); @@ -112,14 +107,10 @@ describe('CallCredentials', () => { it('should combine metadata from multiple generators', async () => { const [callCreds1, callCreds2, callCreds3, callCreds4] = [ - 50, - 100, - 150, - 200, + 50, 100, 150, 200, ].map(ms => { - const generator: CallMetadataGenerator = makeAfterMsElapsedGenerator( - ms - ); + const generator: CallMetadataGenerator = + makeAfterMsElapsedGenerator(ms); return CallCredentials.createFromMetadataGenerator(generator); }); const testCases = [ @@ -147,12 +138,10 @@ describe('CallCredentials', () => { 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; - } + const metadata: Metadata = await credentials.generateMetadata({ + service_url: '', + }); + assert.deepStrictEqual(metadata.get('msElapsed'), expected); }) ); diff --git a/packages/grpc-js/test/test-call-propagation.ts b/packages/grpc-js/test/test-call-propagation.ts index 3ce57be17..9ede91318 100644 --- a/packages/grpc-js/test/test-call-propagation.ts +++ b/packages/grpc-js/test/test-call-propagation.ts @@ -29,7 +29,7 @@ function multiDone(done: () => void, target: number) { if (count >= target) { done(); } - } + }; } describe('Call propagation', () => { @@ -39,33 +39,48 @@ describe('Call propagation', () => { let proxyServer: grpc.Server; let proxyClient: ServiceClient; - before((done) => { - Client = loadProtoFile(__dirname + '/fixtures/test_service.proto').TestService as ServiceClientConstructor; + before(done => { + Client = loadProtoFile(__dirname + '/fixtures/test_service.proto') + .TestService as ServiceClientConstructor; server = new grpc.Server(); server.addService(Client.service, { unary: () => {}, clientStream: () => {}, serverStream: () => {}, - bidiStream: () => {} + 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) => { + server.bindAsync( + 'localhost:0', + grpc.ServerCredentials.createInsecure(), + (error, port) => { if (error) { done(error); return; } - proxyServer.start(); - proxyClient = new Client(`localhost:${proxyPort}`, grpc.credentials.createInsecure()); - done(); - }); - }); + 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); @@ -75,63 +90,84 @@ describe('Call propagation', () => { proxyServer.forceShutdown(); }); describe('Cancellation', () => { - it('should work with unary requests', (done) => { + it('should work with unary requests', done => { done = multiDone(done, 2); + // eslint-disable-next-line prefer-const 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(); - }); + 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(); + }, }); + 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) => { + it('Should work with client streaming requests', done => { done = multiDone(done, 2); + // eslint-disable-next-line prefer-const 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(); - }); + 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(); + }, }); + 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) => { + it('Should work with server streaming requests', done => { done = multiDone(done, 2); + // eslint-disable-next-line prefer-const let call: grpc.ClientReadableStream; proxyServer.addService(Client.service, { serverStream: (parent: grpc.ServerWritableStream) => { - const child = client.serverStream(parent.request, {parent: parent}); + 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', () => {}); @@ -140,19 +176,20 @@ describe('Call propagation', () => { done(); }); }); - it('Should work with bidi streaming requests', (done) => { + it('Should work with bidi streaming requests', done => { done = multiDone(done, 2); + // eslint-disable-next-line prefer-const let call: grpc.ClientDuplexStream; proxyServer.addService(Client.service, { bidiStream: (parent: grpc.ServerDuplexStream) => { - const child = client.bidiStream({parent: parent}); + 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', () => {}); @@ -163,86 +200,113 @@ describe('Call propagation', () => { }); }); describe('Deadlines', () => { - it('should work with unary requests', (done) => { + 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(); - }); - } + 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(); - }); + 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) => { + 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(); - }); - } + 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(); - }); + 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) => { + 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}); + 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}); + // eslint-disable-next-line prefer-const + 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) => { + 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}); + 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}); + // eslint-disable-next-line prefer-const + call = proxyClient.bidiStream({ deadline }); call.on('error', () => {}); call.on('status', (status: grpc.StatusObject) => { assert.strictEqual(status.code, grpc.status.DEADLINE_EXCEEDED); @@ -250,4 +314,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..d52bb59d0 100644 --- a/packages/grpc-js/test/test-channel-credentials.ts +++ b/packages/grpc-js/test/test-channel-credentials.ts @@ -25,14 +25,18 @@ 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 { + 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'; const protoFile = path.join(__dirname, 'fixtures', 'echo_service.proto'); -const echoService = loadProtoFile(protoFile).EchoService as ServiceClientConstructor; +const echoService = loadProtoFile(protoFile) + .EchoService as ServiceClientConstructor; class CallCredentialsMock implements CallCredentials { child: CallCredentialsMock | null = null; @@ -153,17 +157,20 @@ 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 { 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 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) { @@ -171,31 +178,26 @@ describe('ChannelCredentials usage', () => { 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(); + + 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) => { + 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) => { @@ -203,10 +205,12 @@ describe('ChannelCredentials usage', () => { assert.deepStrictEqual(response, { value: 'test value', value2: 3 }); }) ); - call.on('metadata', assert2.mustCall((metadata: grpc.Metadata) => { - assert.deepStrictEqual(metadata.get('test-key'), ['test-value']); - - })); + 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 +}); diff --git a/packages/grpc-js/test/test-channelz.ts b/packages/grpc-js/test/test-channelz.ts index f14145c37..86c90b771 100644 --- a/packages/grpc-js/test/test-channelz.ts +++ b/packages/grpc-js/test/test-channelz.ts @@ -19,7 +19,7 @@ import * as assert from 'assert'; import * as protoLoader from '@grpc/proto-loader'; import * as grpc from '../src'; -import { ProtoGrpcType } from '../src/generated/channelz' +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'; @@ -32,28 +32,33 @@ const loadedChannelzProto = protoLoader.loadSync('channelz.proto', { enums: String, defaults: true, oneofs: true, - includeDirs: [ - `${__dirname}/../../proto` - ] + includeDirs: [`${__dirname}/../../proto`], }); -const channelzGrpcObject = grpc.loadPackageDefinition(loadedChannelzProto) as unknown as ProtoGrpcType; +const channelzGrpcObject = grpc.loadPackageDefinition( + loadedChannelzProto +) as unknown as ProtoGrpcType; -const TestServiceClient = loadProtoFile(`${__dirname}/fixtures/test_service.proto`).TestService as ServiceClientConstructor; +const TestServiceClient = loadProtoFile( + `${__dirname}/fixtures/test_service.proto` +).TestService as ServiceClientConstructor; const testServiceImpl: grpc.UntypedServiceImplementation = { - unary(call: grpc.ServerUnaryCall, callback: grpc.sendUnaryData) { + unary( + call: grpc.ServerUnaryCall, + callback: grpc.sendUnaryData + ) { if (call.request.error) { setTimeout(() => { callback({ code: grpc.status.INVALID_ARGUMENT, - details: call.request.message + details: call.request.message, }); - }, call.request.errorAfter) + }, call.request.errorAfter); } else { - callback(null, {count: 1}); + callback(null, { count: 1 }); } - } -} + }, +}; describe('Channelz', () => { let channelzServer: grpc.Server; @@ -61,18 +66,28 @@ describe('Channelz', () => { let testServer: grpc.Server; let testClient: ServiceClient; - before((done) => { + 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.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(); } - channelzServer.start(); - channelzClient = new channelzGrpcObject.grpc.channelz.v1.Channelz(`localhost:${port}`, grpc.credentials.createInsecure()); - done(); - }); + ); }); after(() => { @@ -80,18 +95,25 @@ describe('Channelz', () => { channelzServer.forceShutdown(); }); - beforeEach((done) => { + 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.bindAsync( + 'localhost:0', + grpc.ServerCredentials.createInsecure(), + (error, port) => { + if (error) { + done(error); + return; + } + testServer.start(); + testClient = new TestServiceClient( + `localhost:${port}`, + grpc.credentials.createInsecure() + ); + done(); } - testServer.start(); - testClient = new TestServiceClient(`localhost:${port}`, grpc.credentials.createInsecure()); - done(); - }); + ); }); afterEach(() => { @@ -99,210 +121,439 @@ describe('Channelz', () => { testServer.forceShutdown(); }); - it('should see a newly created channel', (done) => { + 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) => { + channelzClient.GetChannel( + { channel_id: testClient.getChannel().getChannelzRef().id }, + (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(); - }); - }); + 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) => { + 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) => { + channelzClient.getServer( + { server_id: testServer.getChannelzRef().id }, + (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(); - }); - }); + 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) => { + 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) => { + channelzClient.GetChannel( + { channel_id: testClient.getChannel().getChannelzRef().id }, + (error, channelResult) => { 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(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(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(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(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(); - }); - }); - }); - }); - }); - }); + 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) => { + 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(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(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(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(); - }); - }); - }); - }); - }); - }); - }); + 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(); + } + ); + } + ); + } + ); + } + ); + } + ); + } + ); + } + ); }); }); describe('Disabling channelz', () => { let testServer: grpc.Server; let testClient: ServiceClient; - beforeEach((done) => { - testServer = new grpc.Server({'grpc.enable_channelz': 0}); + 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.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(); } - testServer.start(); - testClient = new TestServiceClient(`localhost:${port}`, grpc.credentials.createInsecure(), {'grpc.enable_channelz': 0}); - done(); - }); + ); }); afterEach(() => { @@ -310,12 +561,16 @@ describe('Disabling channelz', () => { testServer.forceShutdown(); }); - it('Should still work', (done) => { + 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(); - }); + testClient.unary( + {}, + { deadline }, + (error: grpc.ServiceError, value: unknown) => { + assert.ifError(error); + done(); + } + ); }); -}); \ No newline at end of file +}); diff --git a/packages/grpc-js/test/test-client.ts b/packages/grpc-js/test/test-client.ts index 21dad99f1..67b396015 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/connectivity-state"; +import { ConnectivityState } from '../src/connectivity-state'; const clientInsecureCreds = grpc.credentials.createInsecure(); const serverInsecureCreds = ServerCredentials.createInsecure(); @@ -32,19 +32,12 @@ describe('Client', () => { before(done => { server = new Server(); - server.bindAsync( - 'localhost:0', - serverInsecureCreds, - (err, port) => { - assert.ifError(err); - client = new Client( - `localhost:${port}`, - clientInsecureCreds - ); - server.start(); - done(); - } - ); + server.bindAsync('localhost:0', serverInsecureCreds, (err, port) => { + assert.ifError(err); + client = new Client(`localhost:${port}`, clientInsecureCreds); + server.start(); + done(); + }); }); after(done => { @@ -79,18 +72,30 @@ describe('Client without a server', () => { after(() => { client.close(); }); - it('should fail multiple calls to the nonexistent server', function(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); - assert.strictEqual(error?.code, grpc.status.UNAVAILABLE); - client.makeUnaryRequest('/service/method', x => x, x => x, Buffer.from([]), (error, value) => { + client.makeUnaryRequest( + '/service/method', + x => x, + x => x, + Buffer.from([]), + (error, value) => { assert(error); assert.strictEqual(error?.code, grpc.status.UNAVAILABLE); - done(); - }); - }); + client.makeUnaryRequest( + '/service/method', + x => x, + x => x, + Buffer.from([]), + (error, value) => { + assert(error); + assert.strictEqual(error?.code, grpc.status.UNAVAILABLE); + done(); + } + ); + } + ); }); }); @@ -103,17 +108,29 @@ describe('Client with a nonexistent target domain', () => { after(() => { client.close(); }); - it('should fail multiple calls', function(done) { + 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) => { + client.makeUnaryRequest( + '/service/method', + x => x, + x => x, + Buffer.from([]), + (error, value) => { assert(error); assert.strictEqual(error?.code, grpc.status.UNAVAILABLE); - done(); - }); - }); + 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 +}); diff --git a/packages/grpc-js/test/test-deadline.ts b/packages/grpc-js/test/test-deadline.ts index bb6b3ba9b..315f8b3cf 100644 --- a/packages/grpc-js/test/test-deadline.ts +++ b/packages/grpc-js/test/test-deadline.ts @@ -29,40 +29,49 @@ const serverInsecureCreds = ServerCredentials.createInsecure(); const TIMEOUT_SERVICE_CONFIG: ServiceConfig = { loadBalancingConfig: [], - methodConfig: [{ - name: [ - {service: 'TestService'} - ], - timeout: { - seconds: 1, - nanos: 0 - } - }] + 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; + Client = loadProtoFile(__dirname + '/fixtures/test_service.proto') + .TestService as ServiceClientConstructor; server = new grpc.Server(); server.addService(Client.service, { unary: () => {}, clientStream: () => {}, serverStream: () => {}, - bidiStream: () => {} + bidiStream: () => {}, }); - server.bindAsync('localhost:0', grpc.ServerCredentials.createInsecure(), (error, port) => { - if (error) { - done(error); - return; + 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(); } - server.start(); - client = new Client(`localhost:${port}`, grpc.credentials.createInsecure(), {'grpc.service_config': JSON.stringify(TIMEOUT_SERVICE_CONFIG)}); - done(); - }); + ); }); after(done => { @@ -71,7 +80,7 @@ describe('Client with configured timeout', () => { }); it('Should end calls without explicit deadline with DEADLINE_EXCEEDED', done => { - client.unary({}, (error: grpc.ServiceError, value: unknown) =>{ + client.unary({}, (error: grpc.ServiceError, value: unknown) => { assert(error); assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED); done(); @@ -81,10 +90,10 @@ describe('Client with configured timeout', () => { 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) =>{ + 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/packages/grpc-js/test/test-global-subchannel-pool.ts b/packages/grpc-js/test/test-global-subchannel-pool.ts index 999a11bf7..f49221446 100644 --- a/packages/grpc-js/test/test-global-subchannel-pool.ts +++ b/packages/grpc-js/test/test-global-subchannel-pool.ts @@ -19,13 +19,20 @@ 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 { + sendUnaryData, + Server, + ServerCredentials, + ServerUnaryCall, + ServiceClientConstructor, + ServiceError, +} from '../src'; -import {loadProtoFile} from './common'; +import { loadProtoFile } from './common'; const protoFile = path.join(__dirname, 'fixtures', 'echo_service.proto'); -const echoService = - loadProtoFile(protoFile).EchoService as ServiceClientConstructor; +const echoService = loadProtoFile(protoFile) + .EchoService as ServiceClientConstructor; describe('Global subchannel pool', () => { let server: Server; @@ -45,72 +52,84 @@ describe('Global subchannel pool', () => { }); server.bindAsync( - 'localhost:0', ServerCredentials.createInsecure(), (err, port) => { - assert.ifError(err); - serverPort = port; - server.start(); - done(); - }); + '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}; + 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); + `127.0.0.1:${serverPort}`, + grpc.credentials.createInsecure(), + grpcOptions + ); client2 = new echoService( - `127.0.0.1:${serverPort}`, grpc.credentials.createInsecure(), - grpcOptions); + `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) => { + 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(); - }); - })) + }); + }) + ); - Promise.all(promises).then(() => {done()}); - }) + 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)); @@ -118,13 +137,13 @@ describe('Global subchannel pool', () => { Promise.all(promises).then(() => { done(); }); - }) + }); it('Should complete the client lifecycle without error', done => { setTimeout(() => { client1.close(); client2.close(); - done() + done(); }, 500); }); }); diff --git a/packages/grpc-js/test/test-local-subchannel-pool.ts b/packages/grpc-js/test/test-local-subchannel-pool.ts index 081b2d3dc..00da9c64e 100644 --- a/packages/grpc-js/test/test-local-subchannel-pool.ts +++ b/packages/grpc-js/test/test-local-subchannel-pool.ts @@ -18,7 +18,14 @@ 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 { + sendUnaryData, + Server, + ServerCredentials, + ServerUnaryCall, + ServiceClientConstructor, + ServiceError, +} from '../src'; import { loadProtoFile } from './common'; const protoFile = path.join(__dirname, 'fixtures', 'echo_service.proto'); @@ -30,7 +37,6 @@ describe('Local subchannel pool', () => { let serverPort: number; before(done => { - server = new Server(); server.addService(echoService.service, { echo(call: ServerUnaryCall, callback: sendUnaryData) { @@ -58,7 +64,7 @@ describe('Local subchannel pool', () => { const client = new echoService( `localhost:${serverPort}`, grpc.credentials.createInsecure(), - {'grpc.use_local_subchannel_pool': 1} + { 'grpc.use_local_subchannel_pool': 1 } ); client.echo( { value: 'test value', value2: 3 }, @@ -70,4 +76,4 @@ describe('Local subchannel pool', () => { } ); }); -}); \ 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 c9021e605..aa35f45e6 100644 --- a/packages/grpc-js/test/test-outlier-detection.ts +++ b/packages/grpc-js/test/test-outlier-detection.ts @@ -19,7 +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' +import { OutlierDetectionLoadBalancingConfig } from '../src/load-balancer-outlier-detection'; import { ServiceClient } from '../src/make-client'; function multiDone(done: Mocha.Done, target: number) { @@ -32,7 +32,7 @@ function multiDone(done: Mocha.Done, target: number) { if (count >= target) { done(); } - } + }; } const defaultOutlierDetectionServiceConfig = { @@ -42,13 +42,15 @@ const defaultOutlierDetectionServiceConfig = { outlier_detection: { success_rate_ejection: {}, failure_percentage_ejection: {}, - child_policy: [{round_robin: {}}] - } - } - ] + child_policy: [{ round_robin: {} }], + }, + }, + ], }; -const defaultOutlierDetectionServiceConfigString = JSON.stringify(defaultOutlierDetectionServiceConfig); +const defaultOutlierDetectionServiceConfigString = JSON.stringify( + defaultOutlierDetectionServiceConfig +); const successRateOutlierDetectionServiceConfig = { methodConfig: [], @@ -57,22 +59,24 @@ const successRateOutlierDetectionServiceConfig = { outlier_detection: { interval: { seconds: 1, - nanos: 0 + nanos: 0, }, base_ejection_time: { seconds: 3, - nanos: 0 + nanos: 0, }, success_rate_ejection: { - request_volume: 5 + request_volume: 5, }, - child_policy: [{round_robin: {}}] - } - } - ] + child_policy: [{ round_robin: {} }], + }, + }, + ], }; -const successRateOutlierDetectionServiceConfigString = JSON.stringify(successRateOutlierDetectionServiceConfig); +const successRateOutlierDetectionServiceConfigString = JSON.stringify( + successRateOutlierDetectionServiceConfig +); const failurePercentageOutlierDetectionServiceConfig = { methodConfig: [], @@ -81,37 +85,45 @@ const failurePercentageOutlierDetectionServiceConfig = { outlier_detection: { interval: { seconds: 1, - nanos: 0 + nanos: 0, }, base_ejection_time: { seconds: 3, - nanos: 0 + nanos: 0, }, failure_percentage_ejection: { - request_volume: 5 + request_volume: 5, }, - child_policy: [{round_robin: {}}] - } - } - ] + child_policy: [{ round_robin: {} }], + }, + }, + ], }; -const falurePercentageOutlierDetectionServiceConfigString = JSON.stringify(failurePercentageOutlierDetectionServiceConfig); +const falurePercentageOutlierDetectionServiceConfigString = JSON.stringify( + failurePercentageOutlierDetectionServiceConfig +); const goodService = { - echo: (call: grpc.ServerUnaryCall, callback: grpc.sendUnaryData) => { - callback(null, call.request) - } + echo: ( + call: grpc.ServerUnaryCall, + callback: grpc.sendUnaryData + ) => { + callback(null, call.request); + }, }; const badService = { - echo: (call: grpc.ServerUnaryCall, callback: grpc.sendUnaryData) => { + echo: ( + call: grpc.ServerUnaryCall, + callback: grpc.sendUnaryData + ) => { callback({ code: grpc.status.PERMISSION_DENIED, - details: 'Permission denied' - }) - } -} + details: 'Permission denied', + }); + }, +}; const protoFile = path.join(__dirname, 'fixtures', 'echo_service.proto'); const EchoService = loadProtoFile(protoFile) @@ -123,9 +135,9 @@ describe('Outlier detection config validation', () => { const loadBalancingConfig = { interval: { seconds: -1, - nanos: 0 + nanos: 0, }, - child_policy: [{round_robin: {}}] + child_policy: [{ round_robin: {} }], }; assert.throws(() => { OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); @@ -135,9 +147,9 @@ describe('Outlier detection config validation', () => { const loadBalancingConfig = { interval: { seconds: 1e12, - nanos: 0 + nanos: 0, }, - child_policy: [{round_robin: {}}] + child_policy: [{ round_robin: {} }], }; assert.throws(() => { OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); @@ -147,9 +159,9 @@ describe('Outlier detection config validation', () => { const loadBalancingConfig = { interval: { seconds: 0, - nanos: -1 + nanos: -1, }, - child_policy: [{round_robin: {}}] + child_policy: [{ round_robin: {} }], }; assert.throws(() => { OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); @@ -159,9 +171,9 @@ describe('Outlier detection config validation', () => { const loadBalancingConfig = { interval: { seconds: 0, - nanos: 1e12 + nanos: 1e12, }, - child_policy: [{round_robin: {}}] + child_policy: [{ round_robin: {} }], }; assert.throws(() => { OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); @@ -173,9 +185,9 @@ describe('Outlier detection config validation', () => { const loadBalancingConfig = { base_ejection_time: { seconds: -1, - nanos: 0 + nanos: 0, }, - child_policy: [{round_robin: {}}] + child_policy: [{ round_robin: {} }], }; assert.throws(() => { OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); @@ -185,9 +197,9 @@ describe('Outlier detection config validation', () => { const loadBalancingConfig = { base_ejection_time: { seconds: 1e12, - nanos: 0 + nanos: 0, }, - child_policy: [{round_robin: {}}] + child_policy: [{ round_robin: {} }], }; assert.throws(() => { OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); @@ -197,9 +209,9 @@ describe('Outlier detection config validation', () => { const loadBalancingConfig = { base_ejection_time: { seconds: 0, - nanos: -1 + nanos: -1, }, - child_policy: [{round_robin: {}}] + child_policy: [{ round_robin: {} }], }; assert.throws(() => { OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); @@ -209,9 +221,9 @@ describe('Outlier detection config validation', () => { const loadBalancingConfig = { base_ejection_time: { seconds: 0, - nanos: 1e12 + nanos: 1e12, }, - child_policy: [{round_robin: {}}] + child_policy: [{ round_robin: {} }], }; assert.throws(() => { OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); @@ -223,9 +235,9 @@ describe('Outlier detection config validation', () => { const loadBalancingConfig = { max_ejection_time: { seconds: -1, - nanos: 0 + nanos: 0, }, - child_policy: [{round_robin: {}}] + child_policy: [{ round_robin: {} }], }; assert.throws(() => { OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); @@ -235,9 +247,9 @@ describe('Outlier detection config validation', () => { const loadBalancingConfig = { max_ejection_time: { seconds: 1e12, - nanos: 0 + nanos: 0, }, - child_policy: [{round_robin: {}}] + child_policy: [{ round_robin: {} }], }; assert.throws(() => { OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); @@ -247,9 +259,9 @@ describe('Outlier detection config validation', () => { const loadBalancingConfig = { max_ejection_time: { seconds: 0, - nanos: -1 + nanos: -1, }, - child_policy: [{round_robin: {}}] + child_policy: [{ round_robin: {} }], }; assert.throws(() => { OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); @@ -259,9 +271,9 @@ describe('Outlier detection config validation', () => { const loadBalancingConfig = { max_ejection_time: { seconds: 0, - nanos: 1e12 + nanos: 1e12, }, - child_policy: [{round_robin: {}}] + child_policy: [{ round_robin: {} }], }; assert.throws(() => { OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); @@ -272,7 +284,7 @@ describe('Outlier detection config validation', () => { it('Should reject a value above 100', () => { const loadBalancingConfig = { max_ejection_percent: 101, - child_policy: [{round_robin: {}}] + child_policy: [{ round_robin: {} }], }; assert.throws(() => { OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); @@ -281,7 +293,7 @@ describe('Outlier detection config validation', () => { it('Should reject a negative value', () => { const loadBalancingConfig = { max_ejection_percent: -1, - child_policy: [{round_robin: {}}] + child_policy: [{ round_robin: {} }], }; assert.throws(() => { OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); @@ -292,9 +304,9 @@ describe('Outlier detection config validation', () => { it('Should reject a value above 100', () => { const loadBalancingConfig = { success_rate_ejection: { - enforcement_percentage: 101 + enforcement_percentage: 101, }, - child_policy: [{round_robin: {}}] + child_policy: [{ round_robin: {} }], }; assert.throws(() => { OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); @@ -303,9 +315,9 @@ describe('Outlier detection config validation', () => { it('Should reject a negative value', () => { const loadBalancingConfig = { success_rate_ejection: { - enforcement_percentage: -1 + enforcement_percentage: -1, }, - child_policy: [{round_robin: {}}] + child_policy: [{ round_robin: {} }], }; assert.throws(() => { OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); @@ -316,9 +328,9 @@ describe('Outlier detection config validation', () => { it('Should reject a value above 100', () => { const loadBalancingConfig = { failure_percentage_ejection: { - threshold: 101 + threshold: 101, }, - child_policy: [{round_robin: {}}] + child_policy: [{ round_robin: {} }], }; assert.throws(() => { OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); @@ -327,9 +339,9 @@ describe('Outlier detection config validation', () => { it('Should reject a negative value', () => { const loadBalancingConfig = { failure_percentage_ejection: { - threshold: -1 + threshold: -1, }, - child_policy: [{round_robin: {}}] + child_policy: [{ round_robin: {} }], }; assert.throws(() => { OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); @@ -340,9 +352,9 @@ describe('Outlier detection config validation', () => { it('Should reject a value above 100', () => { const loadBalancingConfig = { failure_percentage_ejection: { - enforcement_percentage: 101 + enforcement_percentage: 101, }, - child_policy: [{round_robin: {}}] + child_policy: [{ round_robin: {} }], }; assert.throws(() => { OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); @@ -351,9 +363,9 @@ describe('Outlier detection config validation', () => { it('Should reject a negative value', () => { const loadBalancingConfig = { failure_percentage_ejection: { - enforcement_percentage: -1 + enforcement_percentage: -1, }, - child_policy: [{round_robin: {}}] + child_policy: [{ round_robin: {} }], }; assert.throws(() => { OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); @@ -377,32 +389,44 @@ describe('Outlier detection', () => { 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) => { + 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; } - goodPorts.push(port); + badPort = 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(); }); - function makeManyRequests(makeOneRequest: (callback: (error?: Error) => void) => void, total: number, callback: (error?: Error) => void) { + function makeManyRequests( + makeOneRequest: (callback: (error?: Error) => void) => void, + total: number, + callback: (error?: Error) => void + ) { if (total === 0) { callback(); return; @@ -417,7 +441,11 @@ describe('Outlier detection', () => { } it('Should allow normal operation with one server', done => { - const client = new EchoService(`localhost:${goodPorts[0]}`, grpc.credentials.createInsecure(), {'grpc.service_config': defaultOutlierDetectionServiceConfigString}); + 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) => { @@ -429,10 +457,19 @@ describe('Outlier detection', () => { }); describe('Success rate', () => { let makeCheckedRequest: (callback: () => void) => void; - let makeUncheckedRequest:(callback: (error?: Error) => 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}); + 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 }, @@ -460,7 +497,7 @@ describe('Outlier detection', () => { }, 1000); }); }); - it('Should uneject a server after the ejection period', function(done) { + it('Should uneject a server after the ejection period', function (done) { this.timeout(5000); makeManyRequests(makeUncheckedRequest, 50, () => { setTimeout(() => { @@ -477,15 +514,25 @@ describe('Outlier detection', () => { }, 3000); }); }, 1000); - }) + }); }); }); describe('Failure percentage', () => { let makeCheckedRequest: (callback: () => void) => void; - let makeUncheckedRequest:(callback: (error?: Error) => 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}); + 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 }, @@ -513,7 +560,7 @@ describe('Outlier detection', () => { }, 1000); }); }); - it('Should uneject a server after the ejection period', function(done) { + it('Should uneject a server after the ejection period', function (done) { this.timeout(5000); makeManyRequests(makeUncheckedRequest, 50, () => { setTimeout(() => { @@ -530,7 +577,7 @@ describe('Outlier detection', () => { }, 3000); }); }, 1000); - }) + }); }); }); -}); \ No newline at end of file +}); diff --git a/packages/grpc-js/test/test-prototype-pollution.ts b/packages/grpc-js/test/test-prototype-pollution.ts index 6dc4b293c..0d4bdd68c 100644 --- a/packages/grpc-js/test/test-prototype-pollution.ts +++ b/packages/grpc-js/test/test-prototype-pollution.ts @@ -21,11 +21,11 @@ import { loadPackageDefinition } from '../src'; describe('loadPackageDefinition', () => { it('Should not allow prototype pollution', () => { - loadPackageDefinition({'__proto__.polluted': true} as any); - assert.notStrictEqual(({} as any).polluted, true); + 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); + loadPackageDefinition({ 'constructor.prototype.polluted': true } as any); + assert.notStrictEqual(({} as any).polluted, true); }); }); diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index 1d458125b..98d74823b 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -24,7 +24,11 @@ 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-interface'; -import { SubchannelAddress, isTcpSubchannelAddress, subchannelAddressToString } from "../src/subchannel-address"; +import { + SubchannelAddress, + isTcpSubchannelAddress, + subchannelAddressToString, +} from '../src/subchannel-address'; import { parseUri, GrpcUri } from '../src/uri-parser'; describe('Name Resolver', () => { @@ -33,11 +37,13 @@ describe('Name Resolver', () => { resolver_uds.setup(); resolver_ip.setup(); }); - describe('DNS Names', function() { + describe('DNS Names', function () { // For some reason DNS queries sometimes take a long time on Windows this.timeout(4000); it('Should resolve localhost properly', done => { - const target = resolverManager.mapUriDefaultScheme(parseUri('localhost:50051')!)!; + const target = resolverManager.mapUriDefaultScheme( + parseUri('localhost:50051')! + )!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -72,7 +78,9 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); it('Should default to port 443', done => { - const target = resolverManager.mapUriDefaultScheme(parseUri('localhost')!)!; + const target = resolverManager.mapUriDefaultScheme( + parseUri('localhost')! + )!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -161,7 +169,9 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); it('Should correctly represent a bracketed ipv6 address', done => { - const target = resolverManager.mapUriDefaultScheme(parseUri('[::1]:50051')!)!; + const target = resolverManager.mapUriDefaultScheme( + parseUri('[::1]:50051')! + )!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -188,7 +198,9 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); it('Should resolve a public address', done => { - const target = resolverManager.mapUriDefaultScheme(parseUri('example.com')!)!; + const target = resolverManager.mapUriDefaultScheme( + parseUri('example.com')! + )!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -210,7 +222,9 @@ describe('Name Resolver', () => { // 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 target = resolverManager.mapUriDefaultScheme( + parseUri('grpctest.kleinsch.com')! + )!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -232,39 +246,36 @@ describe('Name Resolver', () => { 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); - } - ); + 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 @@ -274,7 +285,9 @@ describe('Name Resolver', () => { * 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 target = resolverManager.mapUriDefaultScheme( + parseUri('loopback4.unittest.grpc.io')! + )!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -289,7 +302,10 @@ 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'` + ), + `None of [${addressList.map(addr => + subchannelAddressToString(addr) + )}] matched '127.0.0.1:443'` ); done(); }, @@ -303,7 +319,9 @@ 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 = resolverManager.mapUriDefaultScheme(parseUri('loopback6.unittest.grpc.io')!)!; + const target = resolverManager.mapUriDefaultScheme( + parseUri('loopback6.unittest.grpc.io')! + )!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -333,7 +351,9 @@ describe('Name Resolver', () => { * 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 target = resolverManager.mapUriDefaultScheme( + parseUri('loopback46.unittest.grpc.io')! + )!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -348,7 +368,10 @@ 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'` + ), + `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 */ @@ -364,7 +387,9 @@ 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 = resolverManager.mapUriDefaultScheme(parseUri('network-tools.com')!)!; + const target = resolverManager.mapUriDefaultScheme( + parseUri('network-tools.com')! + )!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -389,8 +414,12 @@ describe('Name Resolver', () => { * 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')!)!; - const target2 = resolverManager.mapUriDefaultScheme(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[], @@ -415,39 +444,45 @@ describe('Name Resolver', () => { resolver2.updateResolution(); }); it('should not keep repeating successful resolutions', done => { - const target = resolverManager.mapUriDefaultScheme(parseUri('localhost')!)!; + 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); + 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}); + { 'grpc.dns_min_time_between_resolutions_ms': 2000 } + ); resolver.updateResolution(); setTimeout(() => { assert.strictEqual(resultCount, 2, `resultCount ${resultCount} !== 2`); @@ -455,23 +490,29 @@ describe('Name Resolver', () => { }, 10_000); }).timeout(15_000); it('should not keep repeating failed resolutions', done => { - const target = resolverManager.mapUriDefaultScheme(parseUri('host.invalid')!)!; + 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()); - } + 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`); @@ -481,7 +522,9 @@ describe('Name Resolver', () => { }); describe('UDS Names', () => { it('Should handle a relative Unix Domain Socket name', done => { - const target = resolverManager.mapUriDefaultScheme(parseUri('unix:socket')!)!; + const target = resolverManager.mapUriDefaultScheme( + parseUri('unix:socket')! + )!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -505,7 +548,9 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); it('Should handle an absolute Unix Domain Socket name', done => { - const target = resolverManager.mapUriDefaultScheme(parseUri('unix:///tmp/socket')!)!; + const target = resolverManager.mapUriDefaultScheme( + parseUri('unix:///tmp/socket')! + )!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -532,7 +577,9 @@ describe('Name Resolver', () => { }); describe('IP Addresses', () => { it('should handle one IPv4 address with no port', done => { - const target = resolverManager.mapUriDefaultScheme(parseUri('ipv4:127.0.0.1')!)!; + const target = resolverManager.mapUriDefaultScheme( + parseUri('ipv4:127.0.0.1')! + )!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -559,7 +606,9 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); it('should handle one IPv4 address with a port', done => { - const target = resolverManager.mapUriDefaultScheme(parseUri('ipv4:127.0.0.1:50051')!)!; + const target = resolverManager.mapUriDefaultScheme( + parseUri('ipv4:127.0.0.1:50051')! + )!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -586,7 +635,9 @@ describe('Name Resolver', () => { 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 target = resolverManager.mapUriDefaultScheme( + parseUri('ipv4:127.0.0.1:50051,127.0.0.1:50052')! + )!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -621,7 +672,9 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); it('should handle one IPv6 address with no port', done => { - const target = resolverManager.mapUriDefaultScheme(parseUri('ipv6:::1')!)!; + const target = resolverManager.mapUriDefaultScheme( + parseUri('ipv6:::1')! + )!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -648,7 +701,9 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); it('should handle one IPv6 address with a port', done => { - const target = resolverManager.mapUriDefaultScheme(parseUri('ipv6:[::1]:50051')!)!; + const target = resolverManager.mapUriDefaultScheme( + parseUri('ipv6:[::1]:50051')! + )!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -675,7 +730,9 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); it('should handle multiple IPv6 addresses with different ports', done => { - const target = resolverManager.mapUriDefaultScheme(parseUri('ipv6:[::1]:50051,[::1]:50052')!)!; + const target = resolverManager.mapUriDefaultScheme( + parseUri('ipv6:[::1]:50051,[::1]:50052')! + )!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -716,8 +773,7 @@ describe('Name Resolver', () => { return []; } - destroy() { - } + destroy() {} static getDefaultAuthority(target: GrpcUri): string { return 'other'; @@ -726,7 +782,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')!)!; + const target = resolverManager.mapUriDefaultScheme( + parseUri('other:name')! + )!; console.log(target); const authority = resolverManager.getDefaultAuthority(target); diff --git a/packages/grpc-js/test/test-retry-config.ts b/packages/grpc-js/test/test-retry-config.ts index e27f236e2..77952e668 100644 --- a/packages/grpc-js/test/test-retry-config.ts +++ b/packages/grpc-js/test/test-retry-config.ts @@ -15,22 +15,24 @@ * */ -import assert = require("assert"); -import { validateServiceConfig } from "../src/service-config"; +import assert = require('assert'); +import { validateServiceConfig } from '../src/service-config'; function createRetryServiceConfig(retryConfig: object): object { return { loadBalancingConfig: [], methodConfig: [ { - name: [{ - service: 'A', - method: 'B' - }], + name: [ + { + service: 'A', + method: 'B', + }, + ], - retryPolicy: retryConfig - } - ] + retryPolicy: retryConfig, + }, + ], }; } @@ -39,14 +41,16 @@ function createHedgingServiceConfig(hedgingConfig: object): object { loadBalancingConfig: [], methodConfig: [ { - name: [{ - service: 'A', - method: 'B' - }], + name: [ + { + service: 'A', + method: 'B', + }, + ], - hedgingPolicy: hedgingConfig - } - ] + hedgingPolicy: hedgingConfig, + }, + ], }; } @@ -54,7 +58,7 @@ function createThrottlingServiceConfig(retryThrottling: object): object { return { loadBalancingConfig: [], methodConfig: [], - retryThrottling: retryThrottling + retryThrottling: retryThrottling, }; } @@ -69,7 +73,7 @@ const validRetryConfig = { initialBackoff: '1s', maxBackoff: '1s', backoffMultiplier: 1, - retryableStatusCodes: [14, 'RESOURCE_EXHAUSTED'] + retryableStatusCodes: [14, 'RESOURCE_EXHAUSTED'], }; const RETRY_TEST_CASES: TestCase[] = [ @@ -79,14 +83,14 @@ const RETRY_TEST_CASES: TestCase[] = [ initialBackoff: '1s', maxBackoff: '1s', backoffMultiplier: 1, - retryableStatusCodes: [14] + retryableStatusCodes: [14], }, - error: /retry policy: maxAttempts must be an integer at least 2/ + 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/ + config: { ...validRetryConfig, maxAttempts: 1 }, + error: /retry policy: maxAttempts must be an integer at least 2/, }, { description: 'omitted initialBackoff', @@ -94,19 +98,22 @@ const RETRY_TEST_CASES: TestCase[] = [ maxAttempts: 2, maxBackoff: '1s', backoffMultiplier: 1, - retryableStatusCodes: [14] + retryableStatusCodes: [14], }, - error: /retry policy: initialBackoff must be a string consisting of a positive integer followed by s/ + 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/ + 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/ + config: { ...validRetryConfig, initialBackoff: '123' }, + error: + /retry policy: initialBackoff must be a string consisting of a positive integer followed by s/, }, { description: 'omitted maxBackoff', @@ -114,19 +121,22 @@ const RETRY_TEST_CASES: TestCase[] = [ maxAttempts: 2, initialBackoff: '1s', backoffMultiplier: 1, - retryableStatusCodes: [14] + retryableStatusCodes: [14], }, - error: /retry policy: maxBackoff must be a string consisting of a positive integer followed by s/ + 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/ + 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/ + config: { ...validRetryConfig, maxBackoff: '123' }, + error: + /retry policy: maxBackoff must be a string consisting of a positive integer followed by s/, }, { description: 'omitted backoffMultiplier', @@ -134,14 +144,14 @@ const RETRY_TEST_CASES: TestCase[] = [ maxAttempts: 2, initialBackoff: '1s', maxBackoff: '1s', - retryableStatusCodes: [14] + retryableStatusCodes: [14], }, - error: /retry policy: backoffMultiplier must be a number greater than 0/ + 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/ + config: { ...validRetryConfig, backoffMultiplier: -1 }, + error: /retry policy: backoffMultiplier must be a number greater than 0/, }, { description: 'omitted retryableStatusCodes', @@ -149,95 +159,97 @@ const RETRY_TEST_CASES: TestCase[] = [ maxAttempts: 2, initialBackoff: '1s', maxBackoff: '1s', - backoffMultiplier: 1 + backoffMultiplier: 1, }, - error: /retry policy: retryableStatusCodes is required/ + error: /retry policy: retryableStatusCodes is required/, }, { description: 'empty retryableStatusCodes', - config: {...validRetryConfig, retryableStatusCodes: []}, - error: /retry policy: retryableStatusCodes must be non-empty/ + 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/ + 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/ - } + config: { ...validRetryConfig, retryableStatusCodes: [12345] }, + error: /retry policy: retryableStatusCodes value not in status code range/, + }, ]; const validHedgingConfig = { - maxAttempts: 2 + maxAttempts: 2, }; const HEDGING_TEST_CASES: TestCase[] = [ { description: 'omitted maxAttempts', config: {}, - error: /hedging policy: maxAttempts must be an integer at least 2/ + 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/ + 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/ + 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/ + 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/ + 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/ - } + config: { ...validHedgingConfig, nonFatalStatusCodes: [12345] }, + error: /hedging policy: nonFatalStatusCodes value not in status code range/, + }, ]; const validThrottlingConfig = { maxTokens: 100, - tokenRatio: 0.1 + 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\]/ + 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\]/ + 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\]/ + 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/ + 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/ - } + config: { ...validThrottlingConfig, tokenRatio: 0 }, + error: /retryThrottling: tokenRatio must be a number greater than 0/, + }, ]; describe('Retry configs', () => { @@ -261,10 +273,20 @@ describe('Retry configs', () => { validateServiceConfig(createHedgingServiceConfig(validHedgingConfig)); }); assert.doesNotThrow(() => { - validateServiceConfig(createHedgingServiceConfig({...validHedgingConfig, hedgingDelay: '1s'})); + validateServiceConfig( + createHedgingServiceConfig({ + ...validHedgingConfig, + hedgingDelay: '1s', + }) + ); }); assert.doesNotThrow(() => { - validateServiceConfig(createHedgingServiceConfig({...validHedgingConfig, nonFatalStatusCodes: [14, 'RESOURCE_EXHAUSTED']})); + validateServiceConfig( + createHedgingServiceConfig({ + ...validHedgingConfig, + nonFatalStatusCodes: [14, 'RESOURCE_EXHAUSTED'], + }) + ); }); }); for (const testCase of HEDGING_TEST_CASES) { @@ -278,7 +300,9 @@ describe('Retry configs', () => { describe('Throttling', () => { it('Should accept a valid config', () => { assert.doesNotThrow(() => { - validateServiceConfig(createThrottlingServiceConfig(validThrottlingConfig)); + validateServiceConfig( + createThrottlingServiceConfig(validThrottlingConfig) + ); }); }); for (const testCase of THROTTLING_TEST_CASES) { @@ -289,4 +313,4 @@ describe('Retry configs', () => { }); } }); -}); \ No newline at end of file +}); diff --git a/packages/grpc-js/test/test-retry.ts b/packages/grpc-js/test/test-retry.ts index 66c0f7941..e66e96eb0 100644 --- a/packages/grpc-js/test/test-retry.ts +++ b/packages/grpc-js/test/test-retry.ts @@ -25,37 +25,50 @@ const EchoService = loadProtoFile(protoFile) .EchoService as grpc.ServiceClientConstructor; const serviceImpl = { - echo: (call: grpc.ServerUnaryCall, callback: grpc.sendUnaryData) => { + 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])) { + 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; + const code = statusCode[0] + ? Number.parseInt(statusCode[0] as string) + : grpc.status.UNKNOWN; callback({ code: code, - details: `Failed on retry ${previousAttempts[0] ?? 0}` + details: `Failed on retry ${previousAttempts[0] ?? 0}`, }); } - } -} + }, +}; describe('Retries', () => { let server: grpc.Server; let port: number; - before((done) => { + 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; + server.bindAsync( + 'localhost:0', + grpc.ServerCredentials.createInsecure(), + (error, portNumber) => { + if (error) { + done(error); + return; + } + port = portNumber; + server.start(); + done(); } - port = portNumber; - server.start(); - done(); - }); + ); }); after(() => { @@ -65,14 +78,18 @@ describe('Retries', () => { describe('Client with retries disabled', () => { let client: InstanceType; before(() => { - client = new EchoService(`localhost:${port}`, grpc.credentials.createInsecure(), {'grpc.enable_retries': 0}); + client = new EchoService( + `localhost:${port}`, + grpc.credentials.createInsecure(), + { 'grpc.enable_retries': 0 } + ); }); - after(() =>{ + after(() => { client.close(); }); - it('Should be able to make a basic request', (done) => { + it('Should be able to make a basic request', done => { client.echo( { value: 'test value', value2: 3 }, (error: grpc.ServiceError, response: any) => { @@ -83,7 +100,7 @@ describe('Retries', () => { ); }); - it('Should fail if the server fails the first request', (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( @@ -101,14 +118,17 @@ describe('Retries', () => { describe('Client with retries enabled but not configured', () => { let client: InstanceType; before(() => { - client = new EchoService(`localhost:${port}`, grpc.credentials.createInsecure()); + client = new EchoService( + `localhost:${port}`, + grpc.credentials.createInsecure() + ); }); - after(() =>{ + after(() => { client.close(); }); - it('Should be able to make a basic request', (done) => { + it('Should be able to make a basic request', done => { client.echo( { value: 'test value', value2: 3 }, (error: grpc.ServiceError, response: any) => { @@ -119,7 +139,7 @@ describe('Retries', () => { ); }); - it('Should fail if the server fails the first request', (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( @@ -141,27 +161,33 @@ describe('Retries', () => { loadBalancingConfig: [], methodConfig: [ { - name: [{ - service: 'EchoService' - }], + 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)}); + retryableStatusCodes: [14, 'RESOURCE_EXHAUSTED'], + }, + }, + ], + }; + client = new EchoService( + `localhost:${port}`, + grpc.credentials.createInsecure(), + { 'grpc.service_config': JSON.stringify(serviceConfig) } + ); }); - after(() =>{ + after(() => { client.close(); }); - it('Should be able to make a basic request', (done) => { + it('Should be able to make a basic request', done => { client.echo( { value: 'test value', value2: 3 }, (error: grpc.ServiceError, response: any) => { @@ -172,7 +198,7 @@ describe('Retries', () => { ); }); - it('Should succeed with few required attempts', (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}`); @@ -187,7 +213,7 @@ describe('Retries', () => { ); }); - it('Should fail with many required attempts', (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}`); @@ -202,7 +228,7 @@ describe('Retries', () => { ); }); - it('Should fail with a fatal status code', (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}`); @@ -217,25 +243,31 @@ describe('Retries', () => { ); }); - it('Should not be able to make more than 5 attempts', (done) => { + it('Should not be able to make more than 5 attempts', done => { const serviceConfig = { loadBalancingConfig: [], methodConfig: [ { - name: [{ - service: 'EchoService' - }], + 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)}); + 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}`); @@ -248,7 +280,7 @@ describe('Retries', () => { done(); } ); - }) + }); }); describe('Client with hedging configured', () => { @@ -258,24 +290,30 @@ describe('Retries', () => { loadBalancingConfig: [], methodConfig: [ { - name: [{ - service: 'EchoService' - }], + name: [ + { + service: 'EchoService', + }, + ], hedgingPolicy: { maxAttempts: 3, - nonFatalStatusCodes: [14, 'RESOURCE_EXHAUSTED'] - } - } - ] - } - client = new EchoService(`localhost:${port}`, grpc.credentials.createInsecure(), {'grpc.service_config': JSON.stringify(serviceConfig)}); + nonFatalStatusCodes: [14, 'RESOURCE_EXHAUSTED'], + }, + }, + ], + }; + client = new EchoService( + `localhost:${port}`, + grpc.credentials.createInsecure(), + { 'grpc.service_config': JSON.stringify(serviceConfig) } + ); }); - after(() =>{ + after(() => { client.close(); }); - it('Should be able to make a basic request', (done) => { + it('Should be able to make a basic request', done => { client.echo( { value: 'test value', value2: 3 }, (error: grpc.ServiceError, response: any) => { @@ -286,7 +324,7 @@ describe('Retries', () => { ); }); - it('Should succeed with few required attempts', (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}`); @@ -301,7 +339,7 @@ describe('Retries', () => { ); }); - it('Should fail with many required attempts', (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}`); @@ -316,7 +354,7 @@ describe('Retries', () => { ); }); - it('Should fail with a fatal status code', (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}`); @@ -331,22 +369,28 @@ describe('Retries', () => { ); }); - it('Should not be able to make more than 5 attempts', (done) => { + it('Should not be able to make more than 5 attempts', done => { const serviceConfig = { loadBalancingConfig: [], methodConfig: [ { - name: [{ - service: 'EchoService' - }], + 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)}); + 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}`); @@ -359,6 +403,6 @@ describe('Retries', () => { done(); } ); - }) + }); }); -}); \ No newline at end of file +}); diff --git a/packages/grpc-js/test/test-server-deadlines.ts b/packages/grpc-js/test/test-server-deadlines.ts index c1152309d..2a966e664 100644 --- a/packages/grpc-js/test/test-server-deadlines.ts +++ b/packages/grpc-js/test/test-server-deadlines.ts @@ -42,7 +42,8 @@ describe('Server deadlines', () => { before(done => { const protoFile = path.join(__dirname, 'fixtures', 'test_service.proto'); const testServiceDef = loadProtoFile(protoFile); - const testServiceClient = testServiceDef.TestService as ServiceClientConstructor; + const testServiceClient = + testServiceDef.TestService as ServiceClientConstructor; server = new Server(); server.addService(testServiceClient.service, { @@ -126,7 +127,8 @@ describe('Cancellation', () => { before(done => { const protoFile = path.join(__dirname, 'fixtures', 'test_service.proto'); const testServiceDef = loadProtoFile(protoFile); - const testServiceClient = testServiceDef.TestService as ServiceClientConstructor; + const testServiceClient = + testServiceDef.TestService as ServiceClientConstructor; server = new Server(); server.addService(testServiceClient.service, { diff --git a/packages/grpc-js/test/test-server-errors.ts b/packages/grpc-js/test/test-server-errors.ts index 91b7c196c..24ccfeef3 100644 --- a/packages/grpc-js/test/test-server-errors.ts +++ b/packages/grpc-js/test/test-server-errors.ts @@ -36,7 +36,8 @@ 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(); @@ -723,7 +724,7 @@ describe('Other conditions', () => { }); describe('should handle server stream errors correctly', () => { - it('should emit data for all messages before error', (done) => { + it('should emit data for all messages before error', done => { const expectedDataCount = 2; const call = client.serverStream({ errorAfter: expectedDataCount }); diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index c67ebc4d6..7a0fb412c 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -27,23 +27,35 @@ 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, ServerDuplexStream } from '../src/server-call'; +import { + sendUnaryData, + ServerUnaryCall, + ServerDuplexStream, +} from '../src/server-call'; import { assert2, loadProtoFile } from './common'; -import { TestServiceClient, TestServiceHandlers } from './generated/TestService'; +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(path.join(__dirname, 'fixtures/test_service.proto'), { - keepCase: true, - longs: String, - enums: String, - defaults: true, - oneofs: true -}); +const loadedTestServiceProto = protoLoader.loadSync( + path.join(__dirname, 'fixtures/test_service.proto'), + { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true, + } +); -const testServiceGrpcObject = grpc.loadPackageDefinition(loadedTestServiceProto) as unknown as TestServiceGrpcType; +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')); @@ -134,7 +146,11 @@ describe('Server', () => { }, /creds must be a ServerCredentials object/); assert.throws(() => { - server.bindAsync('localhost:0', grpc.credentials.createInsecure() as any, noop); + server.bindAsync( + 'localhost:0', + grpc.credentials.createInsecure() as any, + noop + ); }, /creds must be a ServerCredentials object/); assert.throws(() => { @@ -286,7 +302,7 @@ describe('Server', () => { } }; - methodsToVerify.forEach((method) => { + methodsToVerify.forEach(method => { const call = client[method]({}, assertFailsWithUnimplementedError); // for unary call.on('error', assertFailsWithUnimplementedError); // for streamed }); @@ -294,14 +310,12 @@ describe('Server', () => { it('fails for non-object service definition argument', () => { assert.throws(() => { - server.removeService('upsie' as any) - }, /removeService.*requires object as argument/ - ); + server.removeService('upsie' as any); + }, /removeService.*requires object as argument/); }); }); describe('unregister', () => { - let server: Server; let client: ServiceClient; @@ -313,7 +327,7 @@ describe('Server', () => { server = new Server(); server.addService(mathServiceAttrs, { div(call: ServerUnaryCall, callback: sendUnaryData) { - callback(null, {quotient: '42'}); + callback(null, { quotient: '42' }); }, }); server.bindAsync( @@ -338,7 +352,11 @@ describe('Server', () => { 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'); + assert.strictEqual( + server.unregister(name), + true, + 'Server#unregister should return true on success' + ); client.div( { divisor: 4, dividend: 3 }, @@ -351,7 +369,11 @@ describe('Server', () => { }); it('returns false for unknown handler', () => { - assert.strictEqual(server.unregister('noOneHere'), false, 'Server#unregister should return false on failure'); + assert.strictEqual( + server.unregister('noOneHere'), + false, + 'Server#unregister should return false on failure' + ); }); }); @@ -473,11 +495,10 @@ describe('Echo service', () => { call.on('end', () => { call.end(); }); - } + }, }; before(done => { - server = new Server(); server.addService(echoService.service, serviceImplementation); @@ -517,36 +538,46 @@ describe('Echo service', () => { 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; + server2.bindAsync( + 'localhost:0', + ServerCredentials.createInsecure(), + (err, port) => { + if (err) { + done(err); + return; } - }); - 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); - }); + 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); + } + ); }); }); @@ -703,7 +734,7 @@ describe('Compressed requests', () => { call.on('end', () => { call.end(); }); - } + }, }; describe('Test service client and server with deflate', () => { @@ -728,7 +759,8 @@ describe('Compressed requests', () => { `localhost:${assignedPort}`, grpc.credentials.createInsecure(), { - 'grpc.default_compression_algorithm': CompressionAlgorithms.deflate + 'grpc.default_compression_algorithm': + CompressionAlgorithms.deflate, } ); done(); @@ -772,7 +804,7 @@ describe('Compressed requests', () => { timesResponded += 1; }); - serverStream.on('error', (err) => { + serverStream.on('error', err => { assert.ifError(err); done(); }); @@ -792,7 +824,7 @@ describe('Compressed requests', () => { timesResponded += 1; }); - bidiStream.on('error', (err) => { + bidiStream.on('error', err => { assert.ifError(err); done(); }); @@ -809,8 +841,8 @@ describe('Compressed requests', () => { bidiStream.write({ message: 'baz' }, () => { timesRequested += 1; setTimeout(() => bidiStream.end(), 10); - }) - }) + }); + }); }); }); @@ -819,7 +851,7 @@ describe('Compressed requests', () => { `localhost:${assignedPort}`, grpc.credentials.createInsecure(), { - 'grpc.default_compression_algorithm': CompressionAlgorithms.gzip + 'grpc.default_compression_algorithm': CompressionAlgorithms.gzip, } ); @@ -853,7 +885,7 @@ describe('Compressed requests', () => { timesResponded += 1; }); - serverStream.on('error', (err) => { + serverStream.on('error', err => { assert.ifError(err); done(); }); @@ -873,7 +905,7 @@ describe('Compressed requests', () => { timesResponded += 1; }); - bidiStream.on('error', (err) => { + bidiStream.on('error', err => { assert.ifError(err); done(); }); @@ -890,25 +922,27 @@ describe('Compressed requests', () => { bidiStream.write({ message: 'baz' }, () => { timesRequested += 1; setTimeout(() => bidiStream.end(), 10); - }) - }) + }); + }); }); }); it('Should handle large messages', done => { let longMessage = ''; for (let i = 0; i < 400000; i++) { - const letter = 'abcdefghijklmnopqrstuvwxyz'[Math.floor(Math.random() * 26)]; + const letter = 'abcdefghijklmnopqrstuvwxyz'[ + Math.floor(Math.random() * 26) + ]; longMessage = longMessage + letter.repeat(10); } - client.unary({message: longMessage}, (err, response) => { + 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 * valid. We don't currently have an alternative way to pass that flag @@ -922,7 +956,7 @@ describe('Compressed requests', () => { timesResponded += 1; }); - bidiStream.on('error', (err) => { + bidiStream.on('error', err => { assert.ifError(err); done(); }); diff --git a/packages/grpc-js/test/test-uri-parser.ts b/packages/grpc-js/test/test-uri-parser.ts index d04cae539..1e20e5e26 100644 --- a/packages/grpc-js/test/test-uri-parser.ts +++ b/packages/grpc-js/test/test-uri-parser.ts @@ -19,59 +19,129 @@ 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() { - const expectationList: {target: string, result: uriParser.GrpcUri | null}[] = [ - {target: 'localhost', result: {scheme: undefined, authority: undefined, path: 'localhost'}}, +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'}}, + { + 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'}} + { + 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() { + for (const { target, result } of expectationList) { + it(target, function () { assert.deepStrictEqual(uriParser.parseUri(target), result); }); } }); - 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'}} + 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); - }) + 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}[] = [ - {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}, + + 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'}} + { + 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() { + for (const { path, result } of expectationList) { + it(path, function () { assert.deepStrictEqual(uriParser.splitHostPort(path), result); }); } }); -}); \ No newline at end of file +});