UNPKG

owltech

Version:
211 lines 8.45 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /** * @license * Copyright 2018 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ const grpc = require("grpc"); const util = require("util"); const gcp_channel_factory_1 = require("./gcp_channel_factory"); exports.GcpChannelFactory = gcp_channel_factory_1.GcpChannelFactory; const protoRoot = require("./generated/grpc_gcp"); var ApiConfig = protoRoot.grpc.gcp.ApiConfig; var AffinityConfig = protoRoot.grpc.gcp.AffinityConfig; /** * Create ApiConfig proto message from config object. * @param apiDefinition Api object that specifies channel pool configuation. * @return A protobuf message type. */ function createGcpApiConfig(apiDefinition) { return ApiConfig.fromObject(apiDefinition); } exports.createGcpApiConfig = createGcpApiConfig; /** * Function for creating a gcp channel factory. * @memberof grpc-gcp * @param address The address of the server to connect to. * @param credentials Channel credentials to use when connecting * @param options A map of channel options that will be passed to the core. * @return {GcpChannelFactory} A GcpChannelFactory instance. */ function gcpChannelFactoryOverride(address, credentials, options) { return new gcp_channel_factory_1.GcpChannelFactory(address, credentials, options); } exports.gcpChannelFactoryOverride = gcpChannelFactoryOverride; /** * Pass in call properties and return a new object with modified values. * This function will be used together with gcpChannelFactoryOverride * when constructing a grpc Client. * @memberof grpc-gcp * @param callProperties Call properties with channel factory object. * @return Modified call properties with selected grpc channel object. */ function gcpCallInvocationTransformer(callProperties) { const channelFactory = callProperties.channel; if (!channelFactory || !(channelFactory instanceof gcp_channel_factory_1.GcpChannelFactory)) { // The gcpCallInvocationTransformer needs to use gcp channel factory. return callProperties; } const argument = callProperties.argument; const metadata = callProperties.metadata; const call = callProperties.call; const methodDefinition = callProperties.methodDefinition; const path = methodDefinition.path; const callOptions = callProperties.callOptions; const callback = callProperties.callback; const preProcessResult = preProcess(channelFactory, path, argument); const channelRef = preProcessResult.channelRef; const boundKey = preProcessResult.boundKey; const postProcessInterceptor = ( // tslint:disable-next-line:no-any options can be any object options, nextCall) => { // tslint:disable-next-line:no-any protobuf message let firstMessage; const requester = { start: (metadata, listener, next) => { const newListener = { onReceiveMetadata: (metadata, next) => { next(metadata); }, // tslint:disable-next-line:no-any protobuf message onReceiveMessage: (message, next) => { if (!firstMessage) firstMessage = message; next(message); }, onReceiveStatus: (status, next) => { if (status.code === grpc.status.OK) { postProcess(channelFactory, channelRef, path, boundKey, firstMessage); } next(status); }, }; next(metadata, newListener); }, // tslint:disable-next-line:no-any protobuf message sendMessage: (message, next) => { next(message); }, halfClose: (next) => { next(); }, cancel: (next) => { next(); }, }; return new grpc.InterceptingCall(nextCall(options), requester); }; // Append interceptor to existing interceptors list. const newCallOptions = Object.assign({}, callOptions); const interceptors = callOptions.interceptors ? callOptions.interceptors : []; newCallOptions.interceptors = interceptors.concat([postProcessInterceptor]); return { argument, metadata, call, channel: channelRef.getChannel(), methodDefinition, callOptions: newCallOptions, callback, }; } exports.gcpCallInvocationTransformer = gcpCallInvocationTransformer; /** * Handle channel affinity and pick a channel before call starts. * @param channelFactory The channel management factory. * @param path Method path. * @param argument The request arguments object. * @return Result containing bound affinity key and the chosen channel ref * object. */ function preProcess(channelFactory, path, // tslint:disable-next-line:no-any protobuf message argument) { const affinityConfig = channelFactory.getAffinityConfig(path); let boundKey; if (argument && affinityConfig) { const command = affinityConfig.command; if (command === AffinityConfig.Command.BOUND || command === AffinityConfig.Command.UNBIND) { boundKey = getAffinityKeyFromMessage(affinityConfig.affinityKey, argument); } } const channelRef = channelFactory.getChannelRef(boundKey); channelRef.activeStreamsCountIncr(); return { boundKey, channelRef, }; } /** * Handle channel affinity and streams count after call is done. * @param channelFactory The channel management factory. * @param channelRef ChannelRef instance that contains a real grpc channel. * @param path Method path. * @param boundKey Affinity key bound to a channel. * @param responseMsg Response proto message. */ function postProcess(channelFactory, channelRef, path, boundKey, // tslint:disable-next-line:no-any protobuf message responseMsg) { if (!channelFactory || !responseMsg) return; const affinityConfig = channelFactory.getAffinityConfig(path); if (affinityConfig && affinityConfig.command) { const command = affinityConfig.command; if (command === AffinityConfig.Command.BIND) { const affinityKey = getAffinityKeyFromMessage(affinityConfig.affinityKey, responseMsg); channelFactory.bind(channelRef, affinityKey); } else if (command === AffinityConfig.Command.UNBIND) { channelFactory.unbind(boundKey); } } channelRef.activeStreamsCountDecr(); } /** * Retrieve affinity key specified in the proto message. * @param affinityKeyName affinity key locator. * @param message proto message that contains affinity info. * @return Affinity key string. */ function getAffinityKeyFromMessage(affinityKeyName, // tslint:disable-next-line:no-any protobuf message message) { if (affinityKeyName) { let currMessage = message; const names = affinityKeyName.split('.'); let i = 0; for (; i < names.length; i++) { if (currMessage[names[i]]) { // check if the proto message is generated by protobufjs. currMessage = currMessage[names[i]]; } else { // otherwise use jspb format. const getter = 'get' + names[i].charAt(0).toUpperCase() + names[i].substr(1); if (!currMessage || typeof currMessage[getter] !== 'function') break; currMessage = currMessage[getter](); } } if (i !== 0 && i === names.length) return currMessage; } console.error(util.format('Cannot find affinity value from proto message using affinity_key: %s.', affinityKeyName)); return ''; } //# sourceMappingURL=index.js.map