UNPKG

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