summaryrefslogtreecommitdiff
path: root/frontend-old/node_modules/@grpc/grpc-js/src/resolving-call.ts
diff options
context:
space:
mode:
authoraltaf-creator <dev@altafcreator.com>2025-11-09 11:15:19 +0800
committeraltaf-creator <dev@altafcreator.com>2025-11-09 11:15:19 +0800
commit8eff962cab608341a6f2fedc640a0e32d96f26e2 (patch)
tree05534d1a720ddc3691d346c69b4972555820a061 /frontend-old/node_modules/@grpc/grpc-js/src/resolving-call.ts
pain
Diffstat (limited to 'frontend-old/node_modules/@grpc/grpc-js/src/resolving-call.ts')
-rw-r--r--frontend-old/node_modules/@grpc/grpc-js/src/resolving-call.ts331
1 files changed, 331 insertions, 0 deletions
diff --git a/frontend-old/node_modules/@grpc/grpc-js/src/resolving-call.ts b/frontend-old/node_modules/@grpc/grpc-js/src/resolving-call.ts
new file mode 100644
index 0000000..723533d
--- /dev/null
+++ b/frontend-old/node_modules/@grpc/grpc-js/src/resolving-call.ts
@@ -0,0 +1,331 @@
+/*
+ * Copyright 2022 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import { CallCredentials } from './call-credentials';
+import {
+ Call,
+ CallStreamOptions,
+ InterceptingListener,
+ MessageContext,
+ StatusObject,
+} from './call-interface';
+import { LogVerbosity, Propagate, Status } from './constants';
+import {
+ Deadline,
+ deadlineToString,
+ 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';
+
+const TRACER_NAME = 'resolving_call';
+
+export class ResolvingCall implements Call {
+ private child: Call | null = null;
+ private readPending = false;
+ private pendingMessage: { context: MessageContext; message: Buffer } | null =
+ null;
+ private pendingHalfClose = false;
+ private ended = false;
+ private readFilterPending = false;
+ private writeFilterPending = false;
+ private pendingChildStatus: StatusObject | null = null;
+ private metadata: Metadata | null = null;
+ private listener: InterceptingListener | null = null;
+ private deadline: Deadline;
+ private host: string;
+ private statusWatchers: ((status: StatusObject) => void)[] = [];
+ private deadlineTimer: NodeJS.Timeout = setTimeout(() => {}, 0);
+ private filterStack: FilterStack | null = null;
+
+ constructor(
+ private readonly channel: InternalChannel,
+ private readonly method: string,
+ options: CallStreamOptions,
+ private readonly filterStackFactory: FilterStackFactory,
+ private credentials: CallCredentials,
+ private callNumber: number
+ ) {
+ this.deadline = options.deadline;
+ this.host = options.host;
+ if (options.parentCall) {
+ if (options.flags & Propagate.CANCELLATION) {
+ options.parentCall.on('cancelled', () => {
+ this.cancelWithStatus(Status.CANCELLED, 'Cancelled by parent call');
+ });
+ }
+ if (options.flags & Propagate.DEADLINE) {
+ this.trace(
+ 'Propagating deadline from parent: ' +
+ options.parentCall.getDeadline()
+ );
+ this.deadline = minDeadline(
+ this.deadline,
+ options.parentCall.getDeadline()
+ );
+ }
+ }
+ this.trace('Created');
+ this.runDeadlineTimer();
+ }
+
+ private trace(text: string): void {
+ logging.trace(
+ LogVerbosity.DEBUG,
+ TRACER_NAME,
+ '[' + this.callNumber + '] ' + text
+ );
+ }
+
+ private runDeadlineTimer() {
+ clearTimeout(this.deadlineTimer);
+ this.trace('Deadline: ' + deadlineToString(this.deadline));
+ const timeout = getRelativeTimeout(this.deadline);
+ if (timeout !== Infinity) {
+ this.trace('Deadline will be reached in ' + timeout + 'ms');
+ const handleDeadline = () => {
+ this.cancelWithStatus(Status.DEADLINE_EXCEEDED, 'Deadline exceeded');
+ };
+ if (timeout <= 0) {
+ process.nextTick(handleDeadline);
+ } else {
+ this.deadlineTimer = setTimeout(handleDeadline, timeout);
+ }
+ }
+ }
+
+ private outputStatus(status: StatusObject) {
+ if (!this.ended) {
+ this.ended = true;
+ if (!this.filterStack) {
+ this.filterStack = this.filterStackFactory.createFilter();
+ }
+ clearTimeout(this.deadlineTimer);
+ const filteredStatus = this.filterStack.receiveTrailers(status);
+ this.trace(
+ 'ended with status: code=' +
+ filteredStatus.code +
+ ' details="' +
+ filteredStatus.details +
+ '"'
+ );
+ this.statusWatchers.forEach(watcher => watcher(filteredStatus));
+ process.nextTick(() => {
+ this.listener?.onReceiveStatus(filteredStatus);
+ });
+ }
+ }
+
+ private sendMessageOnChild(context: MessageContext, message: Buffer): void {
+ if (!this.child) {
+ throw new Error('sendMessageonChild called with child not populated');
+ }
+ const child = this.child;
+ this.writeFilterPending = true;
+ this.filterStack!.sendMessage(
+ Promise.resolve({ message: message, flags: context.flags })
+ ).then(
+ filteredMessage => {
+ this.writeFilterPending = false;
+ child.sendMessageWithContext(context, filteredMessage.message);
+ if (this.pendingHalfClose) {
+ child.halfClose();
+ }
+ },
+ (status: StatusObject) => {
+ this.cancelWithStatus(status.code, status.details);
+ }
+ );
+ }
+
+ getConfig(): void {
+ if (this.ended) {
+ return;
+ }
+ if (!this.metadata || !this.listener) {
+ throw new Error('getConfig called before start');
+ }
+ const configResult = this.channel.getConfig(this.method, this.metadata);
+ if (configResult.type === 'NONE') {
+ this.channel.queueCallForConfig(this);
+ return;
+ } else if (configResult.type === 'ERROR') {
+ if (this.metadata.getOptions().waitForReady) {
+ this.channel.queueCallForConfig(this);
+ } else {
+ this.outputStatus(configResult.error);
+ }
+ return;
+ }
+ // 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
+ );
+ this.outputStatus({
+ code: code,
+ details: details,
+ metadata: new Metadata(),
+ });
+ return;
+ }
+
+ if (config.methodConfig.timeout) {
+ const configDeadline = new Date();
+ configDeadline.setSeconds(
+ configDeadline.getSeconds() + config.methodConfig.timeout.seconds
+ );
+ configDeadline.setMilliseconds(
+ configDeadline.getMilliseconds() +
+ config.methodConfig.timeout.nanos / 1_000_000
+ );
+ this.deadline = minDeadline(this.deadline, configDeadline);
+ this.runDeadlineTimer();
+ }
+
+ 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);
+ }
+ },
+ (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.pendingMessage) {
+ this.sendMessageOnChild(
+ this.pendingMessage.context,
+ this.pendingMessage.message
+ );
+ } else if (this.pendingHalfClose) {
+ this.child.halfClose();
+ }
+ },
+ (status: StatusObject) => {
+ this.outputStatus(status);
+ }
+ );
+ }
+
+ reportResolverError(status: StatusObject) {
+ if (this.metadata?.getOptions().waitForReady) {
+ this.channel.queueCallForConfig(this);
+ } else {
+ this.outputStatus(status);
+ }
+ }
+ cancelWithStatus(status: Status, details: string): void {
+ this.trace(
+ 'cancelWithStatus code: ' + status + ' details: "' + details + '"'
+ );
+ this.child?.cancelWithStatus(status, details);
+ this.outputStatus({
+ code: status,
+ details: details,
+ metadata: new Metadata(),
+ });
+ }
+ getPeer(): string {
+ return this.child?.getPeer() ?? this.channel.getTarget();
+ }
+ start(metadata: Metadata, listener: InterceptingListener): void {
+ this.trace('start called');
+ this.metadata = metadata.clone();
+ this.listener = listener;
+ this.getConfig();
+ }
+ sendMessageWithContext(context: MessageContext, message: Buffer): void {
+ this.trace('write() called with message of length ' + message.length);
+ if (this.child) {
+ this.sendMessageOnChild(context, message);
+ } else {
+ this.pendingMessage = { context, message };
+ }
+ }
+ startRead(): void {
+ this.trace('startRead called');
+ if (this.child) {
+ this.child.startRead();
+ } else {
+ this.readPending = true;
+ }
+ }
+ halfClose(): void {
+ this.trace('halfClose called');
+ if (this.child && !this.writeFilterPending) {
+ this.child.halfClose();
+ } else {
+ this.pendingHalfClose = true;
+ }
+ }
+ setCredentials(credentials: CallCredentials): void {
+ this.credentials = this.credentials.compose(credentials);
+ }
+
+ addStatusWatcher(watcher: (status: StatusObject) => void) {
+ this.statusWatchers.push(watcher);
+ }
+
+ getCallNumber(): number {
+ return this.callNumber;
+ }
+}