UNPKG

17.9 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.Client = void 0;
20const call_1 = require("./call");
21const channel_1 = require("./channel");
22const connectivity_state_1 = require("./connectivity-state");
23const constants_1 = require("./constants");
24const metadata_1 = require("./metadata");
25const client_interceptors_1 = require("./client-interceptors");
26const CHANNEL_SYMBOL = Symbol();
27const INTERCEPTOR_SYMBOL = Symbol();
28const INTERCEPTOR_PROVIDER_SYMBOL = Symbol();
29const CALL_INVOCATION_TRANSFORMER_SYMBOL = Symbol();
30function isFunction(arg) {
31 return typeof arg === 'function';
32}
33/**
34 * A generic gRPC client. Primarily useful as a base class for all generated
35 * clients.
36 */
37class Client {
38 constructor(address, credentials, options = {}) {
39 var _a, _b;
40 options = Object.assign({}, options);
41 this[INTERCEPTOR_SYMBOL] = (_a = options.interceptors) !== null && _a !== void 0 ? _a : [];
42 delete options.interceptors;
43 this[INTERCEPTOR_PROVIDER_SYMBOL] = (_b = options.interceptor_providers) !== null && _b !== void 0 ? _b : [];
44 delete options.interceptor_providers;
45 if (this[INTERCEPTOR_SYMBOL].length > 0 &&
46 this[INTERCEPTOR_PROVIDER_SYMBOL].length > 0) {
47 throw new Error('Both interceptors and interceptor_providers were passed as options ' +
48 'to the client constructor. Only one of these is allowed.');
49 }
50 this[CALL_INVOCATION_TRANSFORMER_SYMBOL] =
51 options.callInvocationTransformer;
52 delete options.callInvocationTransformer;
53 if (options.channelOverride) {
54 this[CHANNEL_SYMBOL] = options.channelOverride;
55 }
56 else if (options.channelFactoryOverride) {
57 const channelFactoryOverride = options.channelFactoryOverride;
58 delete options.channelFactoryOverride;
59 this[CHANNEL_SYMBOL] = channelFactoryOverride(address, credentials, options);
60 }
61 else {
62 this[CHANNEL_SYMBOL] = new channel_1.ChannelImplementation(address, credentials, options);
63 }
64 }
65 close() {
66 this[CHANNEL_SYMBOL].close();
67 }
68 getChannel() {
69 return this[CHANNEL_SYMBOL];
70 }
71 waitForReady(deadline, callback) {
72 const checkState = (err) => {
73 if (err) {
74 callback(new Error('Failed to connect before the deadline'));
75 return;
76 }
77 let newState;
78 try {
79 newState = this[CHANNEL_SYMBOL].getConnectivityState(true);
80 }
81 catch (e) {
82 callback(new Error('The channel has been closed'));
83 return;
84 }
85 if (newState === connectivity_state_1.ConnectivityState.READY) {
86 callback();
87 }
88 else {
89 try {
90 this[CHANNEL_SYMBOL].watchConnectivityState(newState, deadline, checkState);
91 }
92 catch (e) {
93 callback(new Error('The channel has been closed'));
94 }
95 }
96 };
97 setImmediate(checkState);
98 }
99 checkOptionalUnaryResponseArguments(arg1, arg2, arg3) {
100 if (isFunction(arg1)) {
101 return { metadata: new metadata_1.Metadata(), options: {}, callback: arg1 };
102 }
103 else if (isFunction(arg2)) {
104 if (arg1 instanceof metadata_1.Metadata) {
105 return { metadata: arg1, options: {}, callback: arg2 };
106 }
107 else {
108 return { metadata: new metadata_1.Metadata(), options: arg1, callback: arg2 };
109 }
110 }
111 else {
112 if (!(arg1 instanceof metadata_1.Metadata &&
113 arg2 instanceof Object &&
114 isFunction(arg3))) {
115 throw new Error('Incorrect arguments passed');
116 }
117 return { metadata: arg1, options: arg2, callback: arg3 };
118 }
119 }
120 makeUnaryRequest(method, serialize, deserialize, argument, metadata, options, callback) {
121 var _a, _b;
122 const checkedArguments = this.checkOptionalUnaryResponseArguments(metadata, options, callback);
123 const methodDefinition = {
124 path: method,
125 requestStream: false,
126 responseStream: false,
127 requestSerialize: serialize,
128 responseDeserialize: deserialize,
129 };
130 let callProperties = {
131 argument: argument,
132 metadata: checkedArguments.metadata,
133 call: new call_1.ClientUnaryCallImpl(),
134 channel: this[CHANNEL_SYMBOL],
135 methodDefinition: methodDefinition,
136 callOptions: checkedArguments.options,
137 callback: checkedArguments.callback,
138 };
139 if (this[CALL_INVOCATION_TRANSFORMER_SYMBOL]) {
140 callProperties = this[CALL_INVOCATION_TRANSFORMER_SYMBOL](callProperties);
141 }
142 const emitter = callProperties.call;
143 const interceptorArgs = {
144 clientInterceptors: this[INTERCEPTOR_SYMBOL],
145 clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL],
146 callInterceptors: (_a = callProperties.callOptions.interceptors) !== null && _a !== void 0 ? _a : [],
147 callInterceptorProviders: (_b = callProperties.callOptions.interceptor_providers) !== null && _b !== void 0 ? _b : [],
148 };
149 const call = client_interceptors_1.getInterceptingCall(interceptorArgs, callProperties.methodDefinition, callProperties.callOptions, callProperties.channel);
150 /* This needs to happen before the emitter is used. Unfortunately we can't
151 * enforce this with the type system. We need to construct this emitter
152 * before calling the CallInvocationTransformer, and we need to create the
153 * call after that. */
154 emitter.call = call;
155 if (callProperties.callOptions.credentials) {
156 call.setCredentials(callProperties.callOptions.credentials);
157 }
158 let responseMessage = null;
159 let receivedStatus = false;
160 call.start(callProperties.metadata, {
161 onReceiveMetadata: (metadata) => {
162 emitter.emit('metadata', metadata);
163 },
164 // eslint-disable-next-line @typescript-eslint/no-explicit-any
165 onReceiveMessage(message) {
166 if (responseMessage !== null) {
167 call.cancelWithStatus(constants_1.Status.INTERNAL, 'Too many responses received');
168 }
169 responseMessage = message;
170 },
171 onReceiveStatus(status) {
172 if (receivedStatus) {
173 return;
174 }
175 receivedStatus = true;
176 if (status.code === constants_1.Status.OK) {
177 if (responseMessage === null) {
178 callProperties.callback(call_1.callErrorFromStatus({
179 code: constants_1.Status.INTERNAL,
180 details: 'No message received',
181 metadata: status.metadata
182 }));
183 }
184 else {
185 callProperties.callback(null, responseMessage);
186 }
187 }
188 else {
189 callProperties.callback(call_1.callErrorFromStatus(status));
190 }
191 emitter.emit('status', status);
192 },
193 });
194 call.sendMessage(argument);
195 call.halfClose();
196 return emitter;
197 }
198 makeClientStreamRequest(method, serialize, deserialize, metadata, options, callback) {
199 var _a, _b;
200 const checkedArguments = this.checkOptionalUnaryResponseArguments(metadata, options, callback);
201 const methodDefinition = {
202 path: method,
203 requestStream: true,
204 responseStream: false,
205 requestSerialize: serialize,
206 responseDeserialize: deserialize,
207 };
208 let callProperties = {
209 metadata: checkedArguments.metadata,
210 call: new call_1.ClientWritableStreamImpl(serialize),
211 channel: this[CHANNEL_SYMBOL],
212 methodDefinition: methodDefinition,
213 callOptions: checkedArguments.options,
214 callback: checkedArguments.callback,
215 };
216 if (this[CALL_INVOCATION_TRANSFORMER_SYMBOL]) {
217 callProperties = this[CALL_INVOCATION_TRANSFORMER_SYMBOL](callProperties);
218 }
219 const emitter = callProperties.call;
220 const interceptorArgs = {
221 clientInterceptors: this[INTERCEPTOR_SYMBOL],
222 clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL],
223 callInterceptors: (_a = callProperties.callOptions.interceptors) !== null && _a !== void 0 ? _a : [],
224 callInterceptorProviders: (_b = callProperties.callOptions.interceptor_providers) !== null && _b !== void 0 ? _b : [],
225 };
226 const call = client_interceptors_1.getInterceptingCall(interceptorArgs, callProperties.methodDefinition, callProperties.callOptions, callProperties.channel);
227 /* This needs to happen before the emitter is used. Unfortunately we can't
228 * enforce this with the type system. We need to construct this emitter
229 * before calling the CallInvocationTransformer, and we need to create the
230 * call after that. */
231 emitter.call = call;
232 if (callProperties.callOptions.credentials) {
233 call.setCredentials(callProperties.callOptions.credentials);
234 }
235 let responseMessage = null;
236 let receivedStatus = false;
237 call.start(callProperties.metadata, {
238 onReceiveMetadata: (metadata) => {
239 emitter.emit('metadata', metadata);
240 },
241 // eslint-disable-next-line @typescript-eslint/no-explicit-any
242 onReceiveMessage(message) {
243 if (responseMessage !== null) {
244 call.cancelWithStatus(constants_1.Status.INTERNAL, 'Too many responses received');
245 }
246 responseMessage = message;
247 },
248 onReceiveStatus(status) {
249 if (receivedStatus) {
250 return;
251 }
252 receivedStatus = true;
253 if (status.code === constants_1.Status.OK) {
254 if (responseMessage === null) {
255 callProperties.callback(call_1.callErrorFromStatus({
256 code: constants_1.Status.INTERNAL,
257 details: 'No message received',
258 metadata: status.metadata
259 }));
260 }
261 else {
262 callProperties.callback(null, responseMessage);
263 }
264 }
265 else {
266 callProperties.callback(call_1.callErrorFromStatus(status));
267 }
268 emitter.emit('status', status);
269 },
270 });
271 return emitter;
272 }
273 checkMetadataAndOptions(arg1, arg2) {
274 let metadata;
275 let options;
276 if (arg1 instanceof metadata_1.Metadata) {
277 metadata = arg1;
278 if (arg2) {
279 options = arg2;
280 }
281 else {
282 options = {};
283 }
284 }
285 else {
286 if (arg1) {
287 options = arg1;
288 }
289 else {
290 options = {};
291 }
292 metadata = new metadata_1.Metadata();
293 }
294 return { metadata, options };
295 }
296 makeServerStreamRequest(method, serialize, deserialize, argument, metadata, options) {
297 var _a, _b;
298 const checkedArguments = this.checkMetadataAndOptions(metadata, options);
299 const methodDefinition = {
300 path: method,
301 requestStream: false,
302 responseStream: true,
303 requestSerialize: serialize,
304 responseDeserialize: deserialize,
305 };
306 let callProperties = {
307 argument: argument,
308 metadata: checkedArguments.metadata,
309 call: new call_1.ClientReadableStreamImpl(deserialize),
310 channel: this[CHANNEL_SYMBOL],
311 methodDefinition: methodDefinition,
312 callOptions: checkedArguments.options,
313 };
314 if (this[CALL_INVOCATION_TRANSFORMER_SYMBOL]) {
315 callProperties = this[CALL_INVOCATION_TRANSFORMER_SYMBOL](callProperties);
316 }
317 const stream = callProperties.call;
318 const interceptorArgs = {
319 clientInterceptors: this[INTERCEPTOR_SYMBOL],
320 clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL],
321 callInterceptors: (_a = callProperties.callOptions.interceptors) !== null && _a !== void 0 ? _a : [],
322 callInterceptorProviders: (_b = callProperties.callOptions.interceptor_providers) !== null && _b !== void 0 ? _b : [],
323 };
324 const call = client_interceptors_1.getInterceptingCall(interceptorArgs, callProperties.methodDefinition, callProperties.callOptions, callProperties.channel);
325 /* This needs to happen before the emitter is used. Unfortunately we can't
326 * enforce this with the type system. We need to construct this emitter
327 * before calling the CallInvocationTransformer, and we need to create the
328 * call after that. */
329 stream.call = call;
330 if (callProperties.callOptions.credentials) {
331 call.setCredentials(callProperties.callOptions.credentials);
332 }
333 let receivedStatus = false;
334 call.start(callProperties.metadata, {
335 onReceiveMetadata(metadata) {
336 stream.emit('metadata', metadata);
337 },
338 // eslint-disable-next-line @typescript-eslint/no-explicit-any
339 onReceiveMessage(message) {
340 stream.push(message);
341 },
342 onReceiveStatus(status) {
343 if (receivedStatus) {
344 return;
345 }
346 receivedStatus = true;
347 stream.push(null);
348 if (status.code !== constants_1.Status.OK) {
349 stream.emit('error', call_1.callErrorFromStatus(status));
350 }
351 stream.emit('status', status);
352 },
353 });
354 call.sendMessage(argument);
355 call.halfClose();
356 return stream;
357 }
358 makeBidiStreamRequest(method, serialize, deserialize, metadata, options) {
359 var _a, _b;
360 const checkedArguments = this.checkMetadataAndOptions(metadata, options);
361 const methodDefinition = {
362 path: method,
363 requestStream: true,
364 responseStream: true,
365 requestSerialize: serialize,
366 responseDeserialize: deserialize,
367 };
368 let callProperties = {
369 metadata: checkedArguments.metadata,
370 call: new call_1.ClientDuplexStreamImpl(serialize, deserialize),
371 channel: this[CHANNEL_SYMBOL],
372 methodDefinition: methodDefinition,
373 callOptions: checkedArguments.options,
374 };
375 if (this[CALL_INVOCATION_TRANSFORMER_SYMBOL]) {
376 callProperties = this[CALL_INVOCATION_TRANSFORMER_SYMBOL](callProperties);
377 }
378 const stream = callProperties.call;
379 const interceptorArgs = {
380 clientInterceptors: this[INTERCEPTOR_SYMBOL],
381 clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL],
382 callInterceptors: (_a = callProperties.callOptions.interceptors) !== null && _a !== void 0 ? _a : [],
383 callInterceptorProviders: (_b = callProperties.callOptions.interceptor_providers) !== null && _b !== void 0 ? _b : [],
384 };
385 const call = client_interceptors_1.getInterceptingCall(interceptorArgs, callProperties.methodDefinition, callProperties.callOptions, callProperties.channel);
386 /* This needs to happen before the emitter is used. Unfortunately we can't
387 * enforce this with the type system. We need to construct this emitter
388 * before calling the CallInvocationTransformer, and we need to create the
389 * call after that. */
390 stream.call = call;
391 if (callProperties.callOptions.credentials) {
392 call.setCredentials(callProperties.callOptions.credentials);
393 }
394 let receivedStatus = false;
395 call.start(callProperties.metadata, {
396 onReceiveMetadata(metadata) {
397 stream.emit('metadata', metadata);
398 },
399 onReceiveMessage(message) {
400 stream.push(message);
401 },
402 onReceiveStatus(status) {
403 if (receivedStatus) {
404 return;
405 }
406 receivedStatus = true;
407 stream.push(null);
408 if (status.code !== constants_1.Status.OK) {
409 stream.emit('error', call_1.callErrorFromStatus(status));
410 }
411 stream.emit('status', status);
412 },
413 });
414 return stream;
415 }
416}
417exports.Client = Client;
418//# sourceMappingURL=client.js.map
\No newline at end of file