UNPKG

16.8 kBJavaScriptView Raw
1"use strict";
2/*
3 * Copyright 2019 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18Object.defineProperty(exports, "__esModule", { value: true });
19exports.getInterceptingCall = exports.InterceptingCall = exports.RequesterBuilder = exports.ListenerBuilder = exports.InterceptorConfigurationError = void 0;
20const metadata_1 = require("./metadata");
21const call_stream_1 = require("./call-stream");
22const constants_1 = require("./constants");
23/**
24 * Error class associated with passing both interceptors and interceptor
25 * providers to a client constructor or as call options.
26 */
27class InterceptorConfigurationError extends Error {
28 constructor(message) {
29 super(message);
30 this.name = 'InterceptorConfigurationError';
31 Error.captureStackTrace(this, InterceptorConfigurationError);
32 }
33}
34exports.InterceptorConfigurationError = InterceptorConfigurationError;
35class ListenerBuilder {
36 constructor() {
37 this.metadata = undefined;
38 this.message = undefined;
39 this.status = undefined;
40 }
41 withOnReceiveMetadata(onReceiveMetadata) {
42 this.metadata = onReceiveMetadata;
43 return this;
44 }
45 withOnReceiveMessage(onReceiveMessage) {
46 this.message = onReceiveMessage;
47 return this;
48 }
49 withOnReceiveStatus(onReceiveStatus) {
50 this.status = onReceiveStatus;
51 return this;
52 }
53 build() {
54 return {
55 onReceiveMetadata: this.metadata,
56 onReceiveMessage: this.message,
57 onReceiveStatus: this.status,
58 };
59 }
60}
61exports.ListenerBuilder = ListenerBuilder;
62class RequesterBuilder {
63 constructor() {
64 this.start = undefined;
65 this.message = undefined;
66 this.halfClose = undefined;
67 this.cancel = undefined;
68 }
69 withStart(start) {
70 this.start = start;
71 return this;
72 }
73 withSendMessage(sendMessage) {
74 this.message = sendMessage;
75 return this;
76 }
77 withHalfClose(halfClose) {
78 this.halfClose = halfClose;
79 return this;
80 }
81 withCancel(cancel) {
82 this.cancel = cancel;
83 return this;
84 }
85 build() {
86 return {
87 start: this.start,
88 sendMessage: this.message,
89 halfClose: this.halfClose,
90 cancel: this.cancel,
91 };
92 }
93}
94exports.RequesterBuilder = RequesterBuilder;
95/**
96 * A Listener with a default pass-through implementation of each method. Used
97 * for filling out Listeners with some methods omitted.
98 */
99const defaultListener = {
100 onReceiveMetadata: (metadata, next) => {
101 next(metadata);
102 },
103 onReceiveMessage: (message, next) => {
104 next(message);
105 },
106 onReceiveStatus: (status, next) => {
107 next(status);
108 },
109};
110/**
111 * A Requester with a default pass-through implementation of each method. Used
112 * for filling out Requesters with some methods omitted.
113 */
114const defaultRequester = {
115 start: (metadata, listener, next) => {
116 next(metadata, listener);
117 },
118 sendMessage: (message, next) => {
119 next(message);
120 },
121 halfClose: (next) => {
122 next();
123 },
124 cancel: (next) => {
125 next();
126 },
127};
128class InterceptingCall {
129 constructor(nextCall, requester) {
130 var _a, _b, _c, _d;
131 this.nextCall = nextCall;
132 /**
133 * Indicates that a message has been passed to the listener's onReceiveMessage
134 * method it has not been passed to the corresponding next callback
135 */
136 this.processingMessage = false;
137 /**
138 * Indicates that a status was received but could not be propagated because
139 * a message was still being processed.
140 */
141 this.pendingHalfClose = false;
142 if (requester) {
143 this.requester = {
144 start: (_a = requester.start) !== null && _a !== void 0 ? _a : defaultRequester.start,
145 sendMessage: (_b = requester.sendMessage) !== null && _b !== void 0 ? _b : defaultRequester.sendMessage,
146 halfClose: (_c = requester.halfClose) !== null && _c !== void 0 ? _c : defaultRequester.halfClose,
147 cancel: (_d = requester.cancel) !== null && _d !== void 0 ? _d : defaultRequester.cancel,
148 };
149 }
150 else {
151 this.requester = defaultRequester;
152 }
153 }
154 cancelWithStatus(status, details) {
155 this.requester.cancel(() => {
156 this.nextCall.cancelWithStatus(status, details);
157 });
158 }
159 getPeer() {
160 return this.nextCall.getPeer();
161 }
162 start(metadata, interceptingListener) {
163 var _a, _b, _c, _d, _e, _f;
164 const fullInterceptingListener = {
165 onReceiveMetadata: (_b = (_a = interceptingListener === null || interceptingListener === void 0 ? void 0 : interceptingListener.onReceiveMetadata) === null || _a === void 0 ? void 0 : _a.bind(interceptingListener)) !== null && _b !== void 0 ? _b : ((metadata) => { }),
166 onReceiveMessage: (_d = (_c = interceptingListener === null || interceptingListener === void 0 ? void 0 : interceptingListener.onReceiveMessage) === null || _c === void 0 ? void 0 : _c.bind(interceptingListener)) !== null && _d !== void 0 ? _d : ((message) => { }),
167 onReceiveStatus: (_f = (_e = interceptingListener === null || interceptingListener === void 0 ? void 0 : interceptingListener.onReceiveStatus) === null || _e === void 0 ? void 0 : _e.bind(interceptingListener)) !== null && _f !== void 0 ? _f : ((status) => { }),
168 };
169 this.requester.start(metadata, fullInterceptingListener, (md, listener) => {
170 var _a, _b, _c;
171 let finalInterceptingListener;
172 if (call_stream_1.isInterceptingListener(listener)) {
173 finalInterceptingListener = listener;
174 }
175 else {
176 const fullListener = {
177 onReceiveMetadata: (_a = listener.onReceiveMetadata) !== null && _a !== void 0 ? _a : defaultListener.onReceiveMetadata,
178 onReceiveMessage: (_b = listener.onReceiveMessage) !== null && _b !== void 0 ? _b : defaultListener.onReceiveMessage,
179 onReceiveStatus: (_c = listener.onReceiveStatus) !== null && _c !== void 0 ? _c : defaultListener.onReceiveStatus,
180 };
181 finalInterceptingListener = new call_stream_1.InterceptingListenerImpl(fullListener, fullInterceptingListener);
182 }
183 this.nextCall.start(md, finalInterceptingListener);
184 });
185 }
186 // eslint-disable-next-line @typescript-eslint/no-explicit-any
187 sendMessageWithContext(context, message) {
188 this.processingMessage = true;
189 this.requester.sendMessage(message, (finalMessage) => {
190 this.processingMessage = false;
191 this.nextCall.sendMessageWithContext(context, finalMessage);
192 if (this.pendingHalfClose) {
193 this.nextCall.halfClose();
194 }
195 });
196 }
197 // eslint-disable-next-line @typescript-eslint/no-explicit-any
198 sendMessage(message) {
199 this.sendMessageWithContext({}, message);
200 }
201 startRead() {
202 this.nextCall.startRead();
203 }
204 halfClose() {
205 this.requester.halfClose(() => {
206 if (this.processingMessage) {
207 this.pendingHalfClose = true;
208 }
209 else {
210 this.nextCall.halfClose();
211 }
212 });
213 }
214 setCredentials(credentials) {
215 this.nextCall.setCredentials(credentials);
216 }
217}
218exports.InterceptingCall = InterceptingCall;
219function getCall(channel, path, options) {
220 var _a, _b;
221 const deadline = (_a = options.deadline) !== null && _a !== void 0 ? _a : Infinity;
222 const host = options.host;
223 const parent = (_b = options.parent) !== null && _b !== void 0 ? _b : null;
224 const propagateFlags = options.propagate_flags;
225 const credentials = options.credentials;
226 const call = channel.createCall(path, deadline, host, parent, propagateFlags);
227 if (credentials) {
228 call.setCredentials(credentials);
229 }
230 return call;
231}
232/**
233 * InterceptingCall implementation that directly owns the underlying Call
234 * object and handles serialization and deseraizliation.
235 */
236class BaseInterceptingCall {
237 constructor(call,
238 // eslint-disable-next-line @typescript-eslint/no-explicit-any
239 methodDefinition) {
240 this.call = call;
241 this.methodDefinition = methodDefinition;
242 }
243 cancelWithStatus(status, details) {
244 this.call.cancelWithStatus(status, details);
245 }
246 getPeer() {
247 return this.call.getPeer();
248 }
249 setCredentials(credentials) {
250 this.call.setCredentials(credentials);
251 }
252 // eslint-disable-next-line @typescript-eslint/no-explicit-any
253 sendMessageWithContext(context, message) {
254 let serialized;
255 try {
256 serialized = this.methodDefinition.requestSerialize(message);
257 }
258 catch (e) {
259 this.call.cancelWithStatus(constants_1.Status.INTERNAL, `Request message serialization failure: ${e.message}`);
260 return;
261 }
262 this.call.sendMessageWithContext(context, serialized);
263 }
264 // eslint-disable-next-line @typescript-eslint/no-explicit-any
265 sendMessage(message) {
266 this.sendMessageWithContext({}, message);
267 }
268 start(metadata, interceptingListener) {
269 let readError = null;
270 this.call.start(metadata, {
271 onReceiveMetadata: (metadata) => {
272 var _a;
273 (_a = interceptingListener === null || interceptingListener === void 0 ? void 0 : interceptingListener.onReceiveMetadata) === null || _a === void 0 ? void 0 : _a.call(interceptingListener, metadata);
274 },
275 onReceiveMessage: (message) => {
276 var _a;
277 // eslint-disable-next-line @typescript-eslint/no-explicit-any
278 let deserialized;
279 try {
280 deserialized = this.methodDefinition.responseDeserialize(message);
281 }
282 catch (e) {
283 readError = {
284 code: constants_1.Status.INTERNAL,
285 details: `Response message parsing error: ${e.message}`,
286 metadata: new metadata_1.Metadata(),
287 };
288 this.call.cancelWithStatus(readError.code, readError.details);
289 return;
290 }
291 (_a = interceptingListener === null || interceptingListener === void 0 ? void 0 : interceptingListener.onReceiveMessage) === null || _a === void 0 ? void 0 : _a.call(interceptingListener, deserialized);
292 },
293 onReceiveStatus: (status) => {
294 var _a, _b;
295 if (readError) {
296 (_a = interceptingListener === null || interceptingListener === void 0 ? void 0 : interceptingListener.onReceiveStatus) === null || _a === void 0 ? void 0 : _a.call(interceptingListener, readError);
297 }
298 else {
299 (_b = interceptingListener === null || interceptingListener === void 0 ? void 0 : interceptingListener.onReceiveStatus) === null || _b === void 0 ? void 0 : _b.call(interceptingListener, status);
300 }
301 },
302 });
303 }
304 startRead() {
305 this.call.startRead();
306 }
307 halfClose() {
308 this.call.halfClose();
309 }
310}
311/**
312 * BaseInterceptingCall with special-cased behavior for methods with unary
313 * responses.
314 */
315class BaseUnaryInterceptingCall extends BaseInterceptingCall {
316 // eslint-disable-next-line @typescript-eslint/no-explicit-any
317 constructor(call, methodDefinition) {
318 super(call, methodDefinition);
319 }
320 start(metadata, listener) {
321 var _a, _b;
322 let receivedMessage = false;
323 const wrapperListener = {
324 onReceiveMetadata: (_b = (_a = listener === null || listener === void 0 ? void 0 : listener.onReceiveMetadata) === null || _a === void 0 ? void 0 : _a.bind(listener)) !== null && _b !== void 0 ? _b : ((metadata) => { }),
325 // eslint-disable-next-line @typescript-eslint/no-explicit-any
326 onReceiveMessage: (message) => {
327 var _a;
328 receivedMessage = true;
329 (_a = listener === null || listener === void 0 ? void 0 : listener.onReceiveMessage) === null || _a === void 0 ? void 0 : _a.call(listener, message);
330 },
331 onReceiveStatus: (status) => {
332 var _a, _b;
333 if (!receivedMessage) {
334 (_a = listener === null || listener === void 0 ? void 0 : listener.onReceiveMessage) === null || _a === void 0 ? void 0 : _a.call(listener, null);
335 }
336 (_b = listener === null || listener === void 0 ? void 0 : listener.onReceiveStatus) === null || _b === void 0 ? void 0 : _b.call(listener, status);
337 },
338 };
339 super.start(metadata, wrapperListener);
340 this.call.startRead();
341 }
342}
343/**
344 * BaseInterceptingCall with special-cased behavior for methods with streaming
345 * responses.
346 */
347class BaseStreamingInterceptingCall extends BaseInterceptingCall {
348}
349function getBottomInterceptingCall(channel, options,
350// eslint-disable-next-line @typescript-eslint/no-explicit-any
351methodDefinition) {
352 const call = getCall(channel, methodDefinition.path, options);
353 if (methodDefinition.responseStream) {
354 return new BaseStreamingInterceptingCall(call, methodDefinition);
355 }
356 else {
357 return new BaseUnaryInterceptingCall(call, methodDefinition);
358 }
359}
360function getInterceptingCall(interceptorArgs,
361// eslint-disable-next-line @typescript-eslint/no-explicit-any
362methodDefinition, options, channel) {
363 if (interceptorArgs.clientInterceptors.length > 0 &&
364 interceptorArgs.clientInterceptorProviders.length > 0) {
365 throw new InterceptorConfigurationError('Both interceptors and interceptor_providers were passed as options ' +
366 'to the client constructor. Only one of these is allowed.');
367 }
368 if (interceptorArgs.callInterceptors.length > 0 &&
369 interceptorArgs.callInterceptorProviders.length > 0) {
370 throw new InterceptorConfigurationError('Both interceptors and interceptor_providers were passed as call ' +
371 'options. Only one of these is allowed.');
372 }
373 let interceptors = [];
374 // Interceptors passed to the call override interceptors passed to the client constructor
375 if (interceptorArgs.callInterceptors.length > 0 ||
376 interceptorArgs.callInterceptorProviders.length > 0) {
377 interceptors = []
378 .concat(interceptorArgs.callInterceptors, interceptorArgs.callInterceptorProviders.map((provider) => provider(methodDefinition)))
379 .filter((interceptor) => interceptor);
380 // Filter out falsy values when providers return nothing
381 }
382 else {
383 interceptors = []
384 .concat(interceptorArgs.clientInterceptors, interceptorArgs.clientInterceptorProviders.map((provider) => provider(methodDefinition)))
385 .filter((interceptor) => interceptor);
386 // Filter out falsy values when providers return nothing
387 }
388 const interceptorOptions = Object.assign({}, options, {
389 method_definition: methodDefinition,
390 });
391 /* For each interceptor in the list, the nextCall function passed to it is
392 * based on the next interceptor in the list, using a nextCall function
393 * constructed with the following interceptor in the list, and so on. The
394 * initialValue, which is effectively at the end of the list, is a nextCall
395 * function that invokes getBottomInterceptingCall, the result of which
396 * handles (de)serialization and also gets the underlying call from the
397 * channel. */
398 const getCall = interceptors.reduceRight((nextCall, nextInterceptor) => {
399 return (currentOptions) => nextInterceptor(currentOptions, nextCall);
400 }, (finalOptions) => getBottomInterceptingCall(channel, finalOptions, methodDefinition));
401 return getCall(interceptorOptions);
402}
403exports.getInterceptingCall = getInterceptingCall;
404//# sourceMappingURL=client-interceptors.js.map
\No newline at end of file