@tdxvolt/volt-client-grpc 0.1.1 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/grpc-call.js CHANGED
@@ -1,258 +1,285 @@
1
1
  /* eslint-disable no-underscore-dangle */
2
2
  import debug from "debug";
3
3
  import EventEmitter from "events";
4
- import {VoltCrypto} from "./volt-crypto.js";
4
+ import { VoltCredential } from "./volt-credential.js";
5
5
 
6
6
  const log = debug("volt-client-grpc:grpc-call");
7
7
 
8
- function _prepareInvokeRequest(request, method, methodType = "METHOD_TYPE_UNARY") {
9
- const meta = this._voltClient.crypto.getIdentityMetadata(
10
- this._voltClient.grpc,
11
- this._voltClient.options.id,
12
- this._voltClient.isRemote
13
- );
14
- let invokeRequest;
15
- let callMethod = method;
16
-
17
- if (this._voltClient.isVoltTunnel) {
18
- let requestPayload;
19
- if (request) {
20
- requestPayload = this._grpcClient[method].requestSerialize(request);
21
- } else if (request !== null) {
22
- log("****************LOOKOUT****************** - empty request");
23
- } else {
24
- log("explicit empty request payload");
25
- }
26
-
27
- const tunnelMethod = this._grpcClient.Tunnel;
28
-
29
- const tunnelResp = {
30
- method_invoke: {
31
- method_name: this._grpcClient[method].path,
32
- method_type: methodType,
33
- token: meta.token,
34
- request: requestPayload,
35
- },
36
- };
37
-
38
- const invokePayload = VoltCrypto.aesEncrypt(
39
- tunnelMethod.responseSerialize(tunnelResp),
40
- meta.sharedKey.key,
41
- meta.sharedKey.iv
42
- );
43
-
44
- log("target volt is %s", this._voltClient.crypto.voltFingerprint);
45
-
46
- invokeRequest = {
47
- identity_fingerprint: this._voltClient.crypto.voltFingerprint,
48
- payload: invokePayload,
49
- };
50
-
51
- callMethod = "Invoke";
52
- } else if (this._voltClient.isRemote && meta.sharedKey.key) {
53
- const requestPayload = this._grpcClient[method].requestSerializeOriginal(request);
54
- invokeRequest = VoltCrypto.aesEncrypt(requestPayload, meta.sharedKey.key, meta.sharedKey.iv);
55
- } else {
56
- invokeRequest = request;
57
- }
58
-
59
- return {
60
- meta,
61
- method: callMethod,
62
- methodName: method,
63
- request: invokeRequest,
64
- };
8
+ function _prepareInvokeRequest(
9
+ request,
10
+ method,
11
+ methodType = "METHOD_TYPE_UNARY",
12
+ ) {
13
+ const meta = this._voltClient.credential.getIdentityMetadata(
14
+ this._voltClient.grpc,
15
+ this._voltClient.voltConfig.id,
16
+ this._voltClient.isRemote,
17
+ );
18
+ let invokeRequest;
19
+ let callMethod = method;
20
+
21
+ if (this._voltClient.isVoltRelay) {
22
+ let requestPayload;
23
+ if (request) {
24
+ requestPayload = this._grpcClient[method].requestSerialize(request);
25
+ } else if (request !== null) {
26
+ log("****************LOOKOUT****************** - empty request");
27
+ } else {
28
+ log("explicit empty request payload");
29
+ }
30
+
31
+ const tunnelMethod = this._grpcClient.Tunnel;
32
+
33
+ const tunnelResp = {
34
+ method_invoke: {
35
+ method_name: this._grpcClient[method].path,
36
+ method_type: methodType,
37
+ token: meta.token,
38
+ request: requestPayload,
39
+ },
40
+ };
41
+
42
+ const invokePayload = VoltCredential.aesEncrypt(
43
+ tunnelMethod.responseSerialize(tunnelResp),
44
+ meta.sharedKey.key,
45
+ meta.sharedKey.iv,
46
+ );
47
+
48
+ log("target volt is %s", this._voltClient.credential.voltFingerprint);
49
+
50
+ invokeRequest = {
51
+ identity_fingerprint: this._voltClient.credential.voltFingerprint,
52
+ payload: invokePayload,
53
+ };
54
+
55
+ callMethod = "Invoke";
56
+ } else if (this._voltClient.isRemote && meta.sharedKey.key) {
57
+ const requestPayload =
58
+ this._grpcClient[method].requestSerializeOriginal(request);
59
+ invokeRequest = VoltCredential.aesEncrypt(
60
+ requestPayload,
61
+ meta.sharedKey.key,
62
+ meta.sharedKey.iv,
63
+ );
64
+ } else {
65
+ invokeRequest = request;
66
+ }
67
+
68
+ return {
69
+ meta,
70
+ method: callMethod,
71
+ methodName: method,
72
+ request: invokeRequest,
73
+ };
65
74
  }
66
75
 
67
76
  function _preparePayloadRequest(request, invokeInfo) {
68
- let payloadRequest;
69
-
70
- if (this._voltClient.isVoltTunnel) {
71
- const requestPayload = this._grpcClient[invokeInfo.methodName].requestSerialize(request);
72
- const tunnelMethod = this._grpcClient.Tunnel;
73
-
74
- const tunnelResp = {
75
- method_payload: {
76
- payload: requestPayload,
77
- },
78
- };
79
-
80
- const invokePayload = VoltCrypto.aesEncrypt(
81
- tunnelMethod.responseSerialize(tunnelResp),
82
- invokeInfo.meta.sharedKey.key,
83
- invokeInfo.meta.sharedKey.iv
84
- );
85
-
86
- payloadRequest = {
87
- payload: invokePayload,
88
- };
89
- } else if (this._voltClient.isRemote && invokeInfo.meta.sharedKey.key) {
90
- const requestPayload = this._grpcClient[invokeInfo.methodName].requestSerializeOriginal(request);
91
- payloadRequest = VoltCrypto.aesEncrypt(requestPayload, invokeInfo.meta.sharedKey.key, invokeInfo.meta.sharedKey.iv);
92
- } else {
93
- payloadRequest = request;
94
- }
95
-
96
- return payloadRequest;
77
+ let payloadRequest;
78
+
79
+ if (this._voltClient.isVoltRelay) {
80
+ const requestPayload =
81
+ this._grpcClient[invokeInfo.methodName].requestSerialize(request);
82
+ const tunnelMethod = this._grpcClient.Tunnel;
83
+
84
+ const tunnelResp = {
85
+ method_payload: {
86
+ payload: requestPayload,
87
+ },
88
+ };
89
+
90
+ const invokePayload = VoltCredential.aesEncrypt(
91
+ tunnelMethod.responseSerialize(tunnelResp),
92
+ invokeInfo.meta.sharedKey.key,
93
+ invokeInfo.meta.sharedKey.iv,
94
+ );
95
+
96
+ payloadRequest = {
97
+ payload: invokePayload,
98
+ };
99
+ } else if (this._voltClient.isRemote && invokeInfo.meta.sharedKey.key) {
100
+ const requestPayload =
101
+ this._grpcClient[invokeInfo.methodName].requestSerializeOriginal(request);
102
+ payloadRequest = VoltCredential.aesEncrypt(
103
+ requestPayload,
104
+ invokeInfo.meta.sharedKey.key,
105
+ invokeInfo.meta.sharedKey.iv,
106
+ );
107
+ } else {
108
+ payloadRequest = request;
109
+ }
110
+
111
+ return payloadRequest;
97
112
  }
98
113
 
99
114
  function _parseResponse(method, meta, response) {
100
- let invokeResponse = {};
101
-
102
- if (this._voltClient.isVoltTunnel) {
103
- if (response.payload) {
104
- const decryptedPayload = VoltCrypto.aesDecrypt(response.payload, meta.sharedKey.key, meta.sharedKey.iv);
105
- const tunnelMethod = this._grpcClient.Tunnel;
106
- const responsePayload = tunnelMethod.requestDeserialize(decryptedPayload);
107
- if (responsePayload.payload === "method_payload") {
108
- invokeResponse.payload = this._grpcClient[method].responseDeserialize(responsePayload.method_payload.payload);
109
- } else if (responsePayload.payload === "method_end") {
110
- invokeResponse = responsePayload.method_end;
111
- } else {
112
- log("unexpected tunnel payload type: %s", responsePayload.payload);
113
- }
114
- } else if (response.status && response.status.message) {
115
- // There's been an error in the tunnel.
116
- log(
117
- "Tunnel status received: %s, code %d, description: %s",
118
- response.status.message,
119
- response.status.code,
120
- response.status.description || "n/a"
121
- );
122
- invokeResponse = {ended: true, error: `Error in tunnel: ${response.status.message}`};
123
- } else {
124
- invokeResponse.methodId = response.invoke_id;
125
- log("started method %d for %s", invokeResponse.methodId, method);
126
- }
127
- } else if (this._voltClient.isRemote && meta.sharedKey.key) {
128
- const decryptedPayload = VoltCrypto.aesDecrypt(response, meta.sharedKey.key, meta.sharedKey.iv);
129
- invokeResponse = {payload: this._grpcClient[method].responseDeserializeOriginal(decryptedPayload)};
130
- } else {
131
- invokeResponse = {payload: response};
132
- }
133
-
134
- return invokeResponse;
115
+ let invokeResponse = {};
116
+
117
+ if (this._voltClient.isVoltRelay) {
118
+ if (response.payload) {
119
+ const decryptedPayload = VoltCredential.aesDecrypt(
120
+ response.payload,
121
+ meta.sharedKey.key,
122
+ meta.sharedKey.iv,
123
+ );
124
+ const tunnelMethod = this._grpcClient.Tunnel;
125
+ const responsePayload = tunnelMethod.requestDeserialize(decryptedPayload);
126
+ if (responsePayload.payload === "method_payload") {
127
+ invokeResponse.payload = this._grpcClient[method].responseDeserialize(
128
+ responsePayload.method_payload.payload,
129
+ );
130
+ } else if (responsePayload.payload === "method_end") {
131
+ invokeResponse = responsePayload.method_end;
132
+ } else {
133
+ log("unexpected tunnel payload type: %s", responsePayload.payload);
134
+ }
135
+ } else if (response.status?.message) {
136
+ // There's been an error in the tunnel.
137
+ log(
138
+ "Tunnel status received: %s, code %d, description: %s",
139
+ response.status.message,
140
+ response.status.code,
141
+ response.status.description || "n/a",
142
+ );
143
+ invokeResponse = {
144
+ ended: true,
145
+ error: `Error in tunnel: ${response.status.message}`,
146
+ };
147
+ } else {
148
+ invokeResponse.methodId = response.invoke_id;
149
+ log("started method %d for %s", invokeResponse.methodId, method);
150
+ }
151
+ } else if (this._voltClient.isRemote && meta.sharedKey.key) {
152
+ const decryptedPayload = VoltCredential.aesDecrypt(
153
+ response,
154
+ meta.sharedKey.key,
155
+ meta.sharedKey.iv,
156
+ );
157
+ invokeResponse = {
158
+ payload:
159
+ this._grpcClient[method].responseDeserializeOriginal(decryptedPayload),
160
+ };
161
+ } else {
162
+ invokeResponse = { payload: response };
163
+ }
164
+
165
+ return invokeResponse;
135
166
  }
136
167
 
137
168
  export default class GRPCCall extends EventEmitter {
138
- constructor(voltClient, methodName, methodType) {
139
- super();
140
- this._methodName = methodName;
141
- this._methodType = methodType;
142
- this._call = null;
143
- this._voltClient = voltClient;
144
- this._lastResponse = null;
145
- this._promise = null;
146
- this._reject = null;
147
- }
148
-
149
- reject(err) {
150
- if (this._reject) {
151
- this._reject(err);
152
- }
153
- }
154
-
155
- wait() {
156
- return this._promise;
157
- }
158
-
159
- start(grpcClient, request, responseCB) {
160
- this._promise = new Promise((resolve, reject) => {
161
- this._grpcClient = grpcClient;
162
- this._reject = reject;
163
-
164
- const callbackIntercept = (err, response) => {
165
- log("received callback for method %s", this._methodName);
166
- if (err) {
167
- reject(err);
168
- } else if (response) {
169
- this._lastResponse = response;
170
- if (responseCB) {
171
- responseCB(err, response);
172
- }
173
- } else {
174
- this.end();
175
- resolve(this._lastResponse);
176
- }
177
- };
178
-
179
- this._initialRequest = _prepareInvokeRequest.call(this, request, this._methodName, this._methodType);
180
-
181
- if (!this._grpcClient[this._initialRequest.method]) {
182
- return reject(new Error(`method not found: '${this._initialRequest.method}'`));
183
- }
184
-
185
- this._call = this._grpcClient[this._initialRequest.method](this._initialRequest.meta.metadata, callbackIntercept);
186
-
187
- this._call.on("data", (streamResponse) => {
188
- try {
189
- const parsedResponse = _parseResponse.call(this, this._methodName, this._initialRequest.meta, streamResponse);
190
- if (parsedResponse.payload) {
191
- callbackIntercept(null, parsedResponse.payload);
192
- } else if (parsedResponse.ended) {
193
- if (parsedResponse.error) {
194
- callbackIntercept(new Error(parsedResponse.error), null);
195
- } else {
196
- callbackIntercept(null, null);
197
- }
198
- } else {
199
- log("method id is %s", parsedResponse.methodId);
200
- }
201
- } catch (err) {
202
- log("failure processing connect response: %s", err.message);
203
- this.emit("error", err);
204
- }
205
- });
206
-
207
- this._call.on("error", (err) => {
208
- log("ERROR - intercepted stream error %s", err.message);
209
- callbackIntercept(err, null);
210
- });
211
-
212
- this._call.on("finish", () => {
213
- // The read side has ended (i.e. we called end()).
214
- log("finished call %s", this._methodName);
215
- this.emit("finish");
216
- });
217
-
218
- this._call.on("end", () => {
219
- // The remote peer ended the stream.
220
- log("ended call %s, method id: %s", this._methodName, this._initialRequest.methodId || "n/a - not tunnelling");
221
- this.emit("end");
222
- callbackIntercept(null, null);
223
- });
224
-
225
- if (this._initialRequest.request) {
226
- this._call.write(this._initialRequest.request);
227
- }
228
- });
229
-
230
- return this;
231
- }
232
-
233
- end() {
234
- if (!this._call) {
235
- throw new Error("call not initialised");
236
- } else {
237
- return this._call.end();
238
- }
239
- }
240
-
241
- get writable() {
242
- return this._call && this._call.writable;
243
- }
244
-
245
- write(request) {
246
- if (!this._call) {
247
- log("ERROR - call not initialised");
248
- throw new Error("call not initialised");
249
- } else if (!this._initialRequest) {
250
- this._initialRequest = _prepareInvokeRequest.call(this, request, this._methodName, this._methodType);
251
-
252
- return this._call.write(this._initialRequest.request);
253
- } else {
254
- const payloadRequest = _preparePayloadRequest.call(this, request, this._initialRequest);
255
- return this._call.write(payloadRequest);
256
- }
257
- }
169
+ constructor(voltClient, methodName, methodType) {
170
+ super();
171
+ this._methodName = methodName;
172
+ this._methodType = methodType;
173
+ this._call = null;
174
+ this._voltClient = voltClient;
175
+ }
176
+
177
+ start(grpcClient, request) {
178
+ this._grpcClient = grpcClient;
179
+
180
+ this._initialRequest = _prepareInvokeRequest.call(
181
+ this,
182
+ request,
183
+ this._methodName,
184
+ this._methodType,
185
+ );
186
+
187
+ if (!this._grpcClient[this._initialRequest.method]) {
188
+ return reject(
189
+ new Error(`method not found: '${this._initialRequest.method}'`),
190
+ );
191
+ }
192
+
193
+ this._call = this._grpcClient[this._initialRequest.method](
194
+ this._initialRequest.meta.metadata,
195
+ );
196
+
197
+ this._call.on("data", (streamResponse) => {
198
+ try {
199
+ const parsedResponse = _parseResponse.call(
200
+ this,
201
+ this._methodName,
202
+ this._initialRequest.meta,
203
+ streamResponse,
204
+ );
205
+ if (parsedResponse.payload) {
206
+ this.emit("data", parsedResponse.payload);
207
+ } else if (parsedResponse.ended) {
208
+ if (parsedResponse.error) {
209
+ this.emit("error", new Error(parsedResponse.error));
210
+ } else {
211
+ // Not sure this is necessary - we should receive "end" from grpc soon...
212
+ this.emit("end");
213
+ }
214
+ } else {
215
+ log("method id is %s", parsedResponse.methodId);
216
+ }
217
+ } catch (err) {
218
+ log("failure processing connect response: %s", err.message);
219
+ this.emit("error", err);
220
+ }
221
+ });
222
+
223
+ this._call.on("error", (err) => {
224
+ log("ERROR - intercepted stream error %s", err.message);
225
+ this.emit("error", err);
226
+ });
227
+
228
+ this._call.on("finish", () => {
229
+ // The read side has ended (i.e. we called end()).
230
+ log("finished call %s", this._methodName);
231
+ this.emit("finish");
232
+ });
233
+
234
+ this._call.on("end", () => {
235
+ // The remote peer ended the stream.
236
+ log(
237
+ "ended call %s, method id: %s",
238
+ this._methodName,
239
+ this._initialRequest.methodId || "n/a - not tunnelling",
240
+ );
241
+ this.emit("end");
242
+ });
243
+
244
+ if (this._initialRequest.request) {
245
+ this._call.write(this._initialRequest.request);
246
+ }
247
+
248
+ return this;
249
+ }
250
+
251
+ end() {
252
+ if (this._call) {
253
+ return this._call.end();
254
+ } else {
255
+ throw new Error("call not initialised");
256
+ }
257
+ }
258
+
259
+ get writable() {
260
+ return this._call?.writable;
261
+ }
262
+
263
+ write(request) {
264
+ if (!this._call) {
265
+ log("ERROR - call not initialised");
266
+ throw new Error("call not initialised");
267
+ } else if (this._initialRequest) {
268
+ const payloadRequest = _preparePayloadRequest.call(
269
+ this,
270
+ request,
271
+ this._initialRequest,
272
+ );
273
+ return this._call.write(payloadRequest);
274
+ } else {
275
+ this._initialRequest = _prepareInvokeRequest.call(
276
+ this,
277
+ request,
278
+ this._methodName,
279
+ this._methodType,
280
+ );
281
+
282
+ return this._call.write(this._initialRequest.request);
283
+ }
284
+ }
258
285
  }