binance 3.0.0-beta.1 → 3.0.0-beta.11
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/README.md +305 -75
- package/index.js +1 -1
- package/lib/coinm-client.d.ts +40 -22
- package/lib/coinm-client.js +4 -16
- package/lib/coinm-client.js.map +1 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -1
- package/lib/main-client.d.ts +94 -30
- package/lib/main-client.js +68 -36
- package/lib/main-client.js.map +1 -1
- package/lib/portfolio-client.js.map +1 -1
- package/lib/types/coin.d.ts +1 -0
- package/lib/types/futures.d.ts +15 -5
- package/lib/types/futures.js.map +1 -1
- package/lib/types/portfolio-margin.d.ts +0 -9
- package/lib/types/shared.d.ts +14 -13
- package/lib/types/spot.d.ts +174 -11
- package/lib/types/spot.js.map +1 -1
- package/lib/types/websockets/ws-api-requests.d.ts +480 -2
- package/lib/types/websockets/ws-api-responses.d.ts +565 -1
- package/lib/types/websockets/ws-api.d.ts +157 -60
- package/lib/types/websockets/ws-api.js +47 -3
- package/lib/types/websockets/ws-api.js.map +1 -1
- package/lib/types/websockets/ws-events-formatted.d.ts +18 -14
- package/lib/types/websockets/ws-events-raw.d.ts +4 -2
- package/lib/types/websockets/ws-general.d.ts +8 -18
- package/lib/usdm-client.d.ts +45 -27
- package/lib/usdm-client.js +7 -19
- package/lib/usdm-client.js.map +1 -1
- package/lib/util/BaseRestClient.js +20 -6
- package/lib/util/BaseRestClient.js.map +1 -1
- package/lib/util/BaseWSClient.d.ts +14 -3
- package/lib/util/BaseWSClient.js +87 -30
- package/lib/util/BaseWSClient.js.map +1 -1
- package/lib/util/beautifier-maps.d.ts +32 -0
- package/lib/util/beautifier-maps.js +41 -0
- package/lib/util/beautifier-maps.js.map +1 -1
- package/lib/util/beautifier.d.ts +1 -0
- package/lib/util/beautifier.js +44 -9
- package/lib/util/beautifier.js.map +1 -1
- package/lib/util/browser-support.d.ts +1 -1
- package/lib/util/browser-support.js +1 -41
- package/lib/util/browser-support.js.map +1 -1
- package/lib/util/node-support.js +7 -5
- package/lib/util/node-support.js.map +1 -1
- package/lib/util/requestUtils.d.ts +23 -5
- package/lib/util/requestUtils.js +130 -29
- package/lib/util/requestUtils.js.map +1 -1
- package/lib/util/rounding.d.ts +8 -0
- package/lib/util/rounding.js +41 -0
- package/lib/util/rounding.js.map +1 -0
- package/lib/util/typeGuards.d.ts +31 -3
- package/lib/util/typeGuards.js +105 -8
- package/lib/util/typeGuards.js.map +1 -1
- package/lib/util/webCryptoAPI.js +20 -45
- package/lib/util/webCryptoAPI.js.map +1 -1
- package/lib/util/websockets/WsStore.js +7 -2
- package/lib/util/websockets/WsStore.js.map +1 -1
- package/lib/util/websockets/enum.d.ts +11 -0
- package/lib/util/websockets/enum.js +24 -0
- package/lib/util/websockets/enum.js.map +1 -0
- package/lib/util/websockets/rest-client-cache.d.ts +3 -3
- package/lib/util/websockets/rest-client-cache.js +9 -9
- package/lib/util/websockets/rest-client-cache.js.map +1 -1
- package/lib/util/websockets/user-data-stream-manager.js +7 -8
- package/lib/util/websockets/user-data-stream-manager.js.map +1 -1
- package/lib/util/websockets/websocket-util.d.ts +36 -8
- package/lib/util/websockets/websocket-util.js +176 -74
- package/lib/util/websockets/websocket-util.js.map +1 -1
- package/lib/websocket-api-client.d.ts +401 -0
- package/lib/websocket-api-client.js +647 -0
- package/lib/websocket-api-client.js.map +1 -0
- package/lib/websocket-client-legacy.d.ts +5 -3
- package/lib/websocket-client-legacy.js +14 -13
- package/lib/websocket-client-legacy.js.map +1 -1
- package/lib/websocket-client.d.ts +26 -11
- package/lib/websocket-client.js +269 -174
- package/lib/websocket-client.js.map +1 -1
- package/package.json +3 -3
package/lib/websocket-client.js
CHANGED
|
@@ -8,6 +8,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
12
|
+
var t = {};
|
|
13
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
14
|
+
t[p] = s[p];
|
|
15
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
16
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
17
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
18
|
+
t[p[i]] = s[p[i]];
|
|
19
|
+
}
|
|
20
|
+
return t;
|
|
21
|
+
};
|
|
11
22
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
23
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
24
|
};
|
|
@@ -15,9 +26,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
15
26
|
exports.WebsocketClient = void 0;
|
|
16
27
|
const BaseWSClient_1 = require("./util/BaseWSClient");
|
|
17
28
|
const beautifier_1 = __importDefault(require("./util/beautifier"));
|
|
29
|
+
const node_support_1 = require("./util/node-support");
|
|
18
30
|
const requestUtils_1 = require("./util/requestUtils");
|
|
19
31
|
const typeGuards_1 = require("./util/typeGuards");
|
|
20
|
-
const webCryptoAPI_1 = require("./util/webCryptoAPI");
|
|
21
32
|
const rest_client_cache_1 = require("./util/websockets/rest-client-cache");
|
|
22
33
|
const user_data_stream_manager_1 = require("./util/websockets/user-data-stream-manager");
|
|
23
34
|
const websocket_util_1 = require("./util/websockets/websocket-util");
|
|
@@ -44,16 +55,36 @@ class WebsocketClient extends BaseWSClient_1.BaseWebsocketClient {
|
|
|
44
55
|
super(options, logger);
|
|
45
56
|
this.restClientCache = new rest_client_cache_1.RestClientCache();
|
|
46
57
|
this.beautifier = new beautifier_1.default({
|
|
47
|
-
warnKeyMissingInMap:
|
|
58
|
+
warnKeyMissingInMap: false,
|
|
48
59
|
});
|
|
49
60
|
this.respawnTimeoutCache = {};
|
|
61
|
+
if (options === null || options === void 0 ? void 0 : options.beautifyWarnIfMissing) {
|
|
62
|
+
this.beautifier.setWarnIfMissing(options.beautifyWarnIfMissing);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Binance uses native WebSocket ping/pong frames, which cannot be directly used in
|
|
66
|
+
* some environents (e.g. most browsers do not support sending raw ping/pong frames).
|
|
67
|
+
*
|
|
68
|
+
* This disables heartbeats in those environments, if ping/pong frames are unavailable.
|
|
69
|
+
*
|
|
70
|
+
* Some browsers may still handle these automatically. Some discussion around this can
|
|
71
|
+
* be found here: https://stackoverflow.com/questions/10585355/sending-websocket-ping-pong-frame-from-browser
|
|
72
|
+
*/
|
|
73
|
+
if (!(0, websocket_util_1.isWSPingFrameAvailable)()) {
|
|
74
|
+
this.logger.info('Disabled WS heartbeats. WS.ping() is not available in your environment.');
|
|
75
|
+
this.options.disableHeartbeat = true;
|
|
76
|
+
}
|
|
50
77
|
this.userDataStreamManager = new user_data_stream_manager_1.UserDataStreamManager({
|
|
51
78
|
logger: this.logger,
|
|
52
79
|
wsStore: this.getWsStore(),
|
|
53
80
|
restClientCache: this.restClientCache,
|
|
54
81
|
// fn pointers:
|
|
55
|
-
respawnUserDataFn: (wsKey, market, context = {}) =>
|
|
56
|
-
|
|
82
|
+
respawnUserDataFn: (wsKey, market, context = {}) => {
|
|
83
|
+
return this.respawnUserDataStream(wsKey, market, context);
|
|
84
|
+
},
|
|
85
|
+
getWsUrlFn: (wsKey, connectionType) => {
|
|
86
|
+
return this.getWsUrl(wsKey, connectionType);
|
|
87
|
+
},
|
|
57
88
|
getRestClientOptionsFn: () => this.getRestClientOptions(),
|
|
58
89
|
getWsClientOptionsfn: () => this.options,
|
|
59
90
|
closeWsFn: (wsKey, force) => this.close(wsKey, force),
|
|
@@ -64,25 +95,17 @@ class WebsocketClient extends BaseWSClient_1.BaseWebsocketClient {
|
|
|
64
95
|
return this.userDataStreamManager;
|
|
65
96
|
}
|
|
66
97
|
getRestClientOptions() {
|
|
67
|
-
return Object.assign(Object.assign(Object.assign({}, this.options), this.options.restOptions), { api_key: this.options.api_key, api_secret: this.options.api_secret });
|
|
98
|
+
return Object.assign(Object.assign(Object.assign({}, this.options), this.options.restOptions), { testnet: this.options.testnet, api_key: this.options.api_key, api_secret: this.options.api_secret });
|
|
68
99
|
}
|
|
69
100
|
/**
|
|
70
101
|
* Request connection of all dependent (public & WS API) websockets in prod, instead of waiting
|
|
71
|
-
* for automatic connection by SDK.
|
|
102
|
+
* for automatic connection by SDK.
|
|
103
|
+
*
|
|
104
|
+
* For the Binance SDK, this will only open public connections (without auth), but is almost definitely overkill if you're only working with one product group.
|
|
72
105
|
*/
|
|
73
106
|
connectAll() {
|
|
74
107
|
return this.connectPublic();
|
|
75
108
|
}
|
|
76
|
-
/**
|
|
77
|
-
* Ensures the WS API connection is active and ready.
|
|
78
|
-
*
|
|
79
|
-
* You do not need to call this, but if you call this before making any WS API requests,
|
|
80
|
-
* it can accelerate the first request (by preparing the connection in advance).
|
|
81
|
-
*/
|
|
82
|
-
connectWSAPI(wsKey) {
|
|
83
|
-
/** This call automatically ensures the connection is active AND authenticated before resolving */
|
|
84
|
-
return this.assertIsAuthenticated(wsKey);
|
|
85
|
-
}
|
|
86
109
|
/**
|
|
87
110
|
* Request connection to all public websockets in prod (spot, margin, futures, options). Overkill if
|
|
88
111
|
* you're only working with one product group.
|
|
@@ -95,18 +118,24 @@ class WebsocketClient extends BaseWSClient_1.BaseWebsocketClient {
|
|
|
95
118
|
this.connect(websocket_util_1.WS_KEY_MAP.eoptions),
|
|
96
119
|
];
|
|
97
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* This function serves no purpose in the Binance SDK
|
|
123
|
+
*/
|
|
98
124
|
connectPrivate() {
|
|
99
125
|
return __awaiter(this, void 0, void 0, function* () {
|
|
100
|
-
// switch (this.options.market) {
|
|
101
|
-
// case 'v5':
|
|
102
|
-
// default: {
|
|
103
|
-
// return this.connect(WS_KEY_MAP.v5Private);
|
|
104
|
-
// }
|
|
105
|
-
// }
|
|
106
|
-
// TODO:
|
|
107
126
|
return;
|
|
108
127
|
});
|
|
109
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Ensures the WS API connection is active and ready.
|
|
131
|
+
*
|
|
132
|
+
* You do not need to call this, but if you call this before making any WS API requests,
|
|
133
|
+
* it can accelerate the first request (by preparing the connection in advance).
|
|
134
|
+
*/
|
|
135
|
+
connectWSAPI(wsKey) {
|
|
136
|
+
/** This call automatically ensures the connection is active AND authenticated before resolving */
|
|
137
|
+
return this.assertIsAuthenticated(wsKey);
|
|
138
|
+
}
|
|
110
139
|
/**
|
|
111
140
|
* Request subscription to one or more topics. Pass topics as either an array of strings,
|
|
112
141
|
* or array of objects (if the topic has parameters).
|
|
@@ -135,54 +164,75 @@ class WebsocketClient extends BaseWSClient_1.BaseWebsocketClient {
|
|
|
135
164
|
const normalisedTopicRequests = (0, websocket_util_1.getNormalisedTopicRequests)(topicRequests);
|
|
136
165
|
return this.unsubscribeTopicsForWsKey(normalisedTopicRequests, wsKey);
|
|
137
166
|
}
|
|
138
|
-
// These overloads give stricter types than mapped generics, since generic constraints
|
|
139
|
-
// do not trigger excess property checks
|
|
140
|
-
// Without these overloads, TypeScript won't complain if you include an
|
|
141
|
-
// unexpected property with your request (if it doesn't clash with an existing property)
|
|
142
|
-
// sendWSAPIRequest<TWSOpreation extends WSAPIOperation = 'order.create'>(
|
|
143
|
-
// wsKey: typeof WS_KEY_MAP.v5PrivateTrade,
|
|
144
|
-
// operation: TWSOpreation,
|
|
145
|
-
// params: WsAPITopicRequestParamMap[TWSOpreation],
|
|
146
|
-
// ): Promise<WsAPIOperationResponseMap[TWSOpreation]>;
|
|
147
|
-
// sendWSAPIRequest<TWSOpreation extends WSAPIOperation = 'order.amend'>(
|
|
148
|
-
// wsKey: typeof WS_KEY_MAP.v5PrivateTrade,
|
|
149
|
-
// operation: TWSOpreation,
|
|
150
|
-
// params: WsAPITopicRequestParamMap[TWSOpreation],
|
|
151
|
-
// ): Promise<WsAPIOperationResponseMap[TWSOpreation]>;
|
|
152
|
-
// sendWSAPIRequest<TWSOpreation extends WSAPIOperation = 'order.cancel'>(
|
|
153
|
-
// wsKey: typeof WS_KEY_MAP.v5PrivateTrade,
|
|
154
|
-
// operation: TWSOpreation,
|
|
155
|
-
// params: WsAPITopicRequestParamMap[TWSOpreation],
|
|
156
|
-
// ): Promise<WsAPIOperationResponseMap[TWSOpreation]>;
|
|
157
167
|
sendWSAPIRequest(wsKey, operation, params) {
|
|
158
168
|
return __awaiter(this, void 0, void 0, function* () {
|
|
159
|
-
//WsAPIOperationResponseMap[TWSOperation]> {
|
|
160
169
|
/**
|
|
161
|
-
* Spot: https://developers.binance.com/docs/binance-spot-api-docs/
|
|
170
|
+
* Spot: https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/general-api-information
|
|
171
|
+
* USDM Futures: https://developers.binance.com/docs/derivatives/usds-margined-futures/websocket-api-general-info
|
|
172
|
+
* COINM Futures: https://developers.binance.com/docs/derivatives/coin-margined-futures/websocket-api-general-info
|
|
162
173
|
*/
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
174
|
+
var _a, _b;
|
|
175
|
+
// If testnet, enforce testnet wskey for WS API calls
|
|
176
|
+
const resolvedWsKey = this.options.testnet ? (0, websocket_util_1.getTestnetWsKey)(wsKey) : wsKey;
|
|
177
|
+
// this.logger.trace(`sendWSAPIRequest(): assertIsConnected("${wsKey}")...`);
|
|
178
|
+
const timestampBeforeAuth = Date.now();
|
|
179
|
+
yield this.assertIsConnected(resolvedWsKey);
|
|
180
|
+
// this.logger.trace('sendWSAPIRequest(): assertIsConnected(${wsKey}) ok');
|
|
181
|
+
// this.logger.trace('sendWSAPIRequest(): assertIsAuthenticated(${wsKey})...');
|
|
182
|
+
yield this.assertIsAuthenticated(resolvedWsKey);
|
|
183
|
+
const timestampAfterAuth = Date.now();
|
|
184
|
+
// this.logger.trace('sendWSAPIRequest(): assertIsAuthenticated(${wsKey}) ok');
|
|
168
185
|
const request = {
|
|
169
186
|
id: this.getNewRequestId(),
|
|
170
187
|
method: operation,
|
|
171
|
-
params: Object.assign({
|
|
188
|
+
params: Object.assign({}, params),
|
|
172
189
|
};
|
|
173
|
-
|
|
174
|
-
|
|
190
|
+
/**
|
|
191
|
+
* Some WS API requests require a timestamp to be included. assertIsConnected and assertIsAuthenticated
|
|
192
|
+
* can introduce a small delay before the actual request is sent, if not connected before that request is
|
|
193
|
+
* made. This can lead to a curious race condition, where the request timestamp is before
|
|
194
|
+
* the "authorizedSince" timestamp - as such, binance does not recognise the session as already authenticated.
|
|
195
|
+
*
|
|
196
|
+
* The below mechanism measures any delay introduced from the assert calls, and if the request includes a timestamp,
|
|
197
|
+
* it offsets that timestamp by the delay.
|
|
198
|
+
*/
|
|
199
|
+
const delayFromAuthAssert = timestampAfterAuth - timestampBeforeAuth;
|
|
200
|
+
if (delayFromAuthAssert && ((_a = request.params) === null || _a === void 0 ? void 0 : _a.timestamp)) {
|
|
201
|
+
request.params.timestamp += delayFromAuthAssert;
|
|
202
|
+
this.logger.trace(`sendWSAPIRequest(): adjust timestamp - delay seen by connect/auth assert and delayed request includes timestamp, adjusting timestamp by ${delayFromAuthAssert}ms`);
|
|
203
|
+
}
|
|
204
|
+
if ((0, requestUtils_1.requiresWSAPINewClientOID)(request, resolvedWsKey)) {
|
|
205
|
+
(0, requestUtils_1.validateWSAPINewClientOID)(request, resolvedWsKey);
|
|
175
206
|
}
|
|
176
207
|
// Sign, if needed
|
|
177
208
|
const signedEvent = yield this.signWSAPIRequest(request);
|
|
178
209
|
// Store deferred promise, resolved within the "resolveEmittableEvents" method while parsing incoming events
|
|
179
|
-
const promiseRef = (0, websocket_util_1.getPromiseRefForWSAPIRequest)(
|
|
180
|
-
const deferredPromise = this.getWsStore().createDeferredPromise(
|
|
210
|
+
const promiseRef = (0, websocket_util_1.getPromiseRefForWSAPIRequest)(resolvedWsKey, signedEvent);
|
|
211
|
+
const deferredPromise = this.getWsStore().createDeferredPromise(resolvedWsKey, promiseRef, false);
|
|
212
|
+
(_b = deferredPromise.promise) === null || _b === void 0 ? void 0 : _b.then((res) => {
|
|
213
|
+
if (!Array.isArray(res)) {
|
|
214
|
+
res.request = Object.assign({ wsKey: resolvedWsKey }, signedEvent);
|
|
215
|
+
}
|
|
216
|
+
return res;
|
|
217
|
+
}).catch((e) => {
|
|
218
|
+
if (typeof e === 'string') {
|
|
219
|
+
this.logger.error('unexpcted string', { e });
|
|
220
|
+
return e;
|
|
221
|
+
}
|
|
222
|
+
e.request = {
|
|
223
|
+
wsKey: resolvedWsKey,
|
|
224
|
+
operation,
|
|
225
|
+
params: signedEvent.params,
|
|
226
|
+
};
|
|
227
|
+
// throw e;
|
|
228
|
+
return e;
|
|
229
|
+
});
|
|
181
230
|
// this.logger.trace(
|
|
182
231
|
// `sendWSAPIRequest(): sending raw request: ${JSON.stringify(signedEvent)} with promiseRef(${promiseRef})`,
|
|
183
232
|
// );
|
|
184
|
-
// Send event
|
|
185
|
-
|
|
233
|
+
// Send event.
|
|
234
|
+
const throwExceptions = true;
|
|
235
|
+
this.tryWsSend(resolvedWsKey, JSON.stringify(signedEvent), throwExceptions);
|
|
186
236
|
this.logger.trace(`sendWSAPIRequest(): sent "${operation}" event with promiseRef(${promiseRef})`);
|
|
187
237
|
// Return deferred promise, so caller can await this call
|
|
188
238
|
return deferredPromise.promise;
|
|
@@ -210,13 +260,35 @@ class WebsocketClient extends BaseWSClient_1.BaseWebsocketClient {
|
|
|
210
260
|
if (typeof this.options.customSignMessageFn === 'function') {
|
|
211
261
|
return this.options.customSignMessageFn(paramsStr, secret);
|
|
212
262
|
}
|
|
213
|
-
return yield (0,
|
|
263
|
+
return yield (0, node_support_1.signMessage)(paramsStr, secret, method, algorithm);
|
|
264
|
+
// return await signMessageWebCryptoAPI(paramsStr, secret, method, algorithm);
|
|
214
265
|
});
|
|
215
266
|
}
|
|
216
267
|
signWSAPIRequest(requestEvent) {
|
|
217
268
|
return __awaiter(this, void 0, void 0, function* () {
|
|
218
|
-
|
|
269
|
+
if (!requestEvent.params) {
|
|
270
|
+
return requestEvent;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
*
|
|
274
|
+
*/
|
|
275
|
+
// Not needed for most commands on binance Binance. Auth happens only on connection open, automatically.
|
|
219
276
|
// Faster than performing auth for every request
|
|
277
|
+
// However, some commands don't work without this for some reason...
|
|
278
|
+
const _a = requestEvent.params, { signRequest } = _a, otherParams = __rest(_a, ["signRequest"]);
|
|
279
|
+
if (signRequest) {
|
|
280
|
+
const strictParamValidation = true;
|
|
281
|
+
const encodeValues = true;
|
|
282
|
+
const filterUndefinedParams = true;
|
|
283
|
+
const semiFinalRequestParams = Object.assign({ apiKey: this.options.api_key }, otherParams);
|
|
284
|
+
const serialisedParams = (0, requestUtils_1.serialiseParams)(semiFinalRequestParams, strictParamValidation, encodeValues, filterUndefinedParams);
|
|
285
|
+
const signature = yield this.signMessage(serialisedParams, this.options.api_secret, 'base64', 'SHA-256');
|
|
286
|
+
console.log('signWSAPIRequest()', {
|
|
287
|
+
semiFinalRequestParams,
|
|
288
|
+
serialisedParams,
|
|
289
|
+
});
|
|
290
|
+
return Object.assign(Object.assign({}, requestEvent), { params: Object.assign(Object.assign({}, semiFinalRequestParams), { signature }) });
|
|
291
|
+
}
|
|
220
292
|
return requestEvent;
|
|
221
293
|
});
|
|
222
294
|
}
|
|
@@ -227,22 +299,21 @@ class WebsocketClient extends BaseWSClient_1.BaseWebsocketClient {
|
|
|
227
299
|
// If you do not want to specify apiKey and signature in each individual request, you can authenticate your API key for the active WebSocket session.
|
|
228
300
|
// Once authenticated, you no longer have to specify apiKey and signature for those requests that need them. Requests will be performed on behalf of the account owning the authenticated API key.
|
|
229
301
|
// Note: You still have to specify the timestamp parameter for SIGNED requests.
|
|
230
|
-
const recvWindow = this.options.recvWindow || 0;
|
|
231
|
-
const timestamp = Date.now() + (this.getTimeOffsetMs() || 0) + recvWindow;
|
|
302
|
+
// const recvWindow = this.options.recvWindow || 0;
|
|
303
|
+
const timestamp = Date.now() + (this.getTimeOffsetMs() || 0); // + recvWindow;
|
|
232
304
|
const strictParamValidation = true;
|
|
233
305
|
const encodeValues = true;
|
|
234
306
|
const filterUndefinedParams = true;
|
|
235
|
-
const
|
|
307
|
+
const params = {
|
|
236
308
|
apiKey: this.options.api_key,
|
|
237
309
|
timestamp,
|
|
238
310
|
};
|
|
239
|
-
const serialisedParams = (0, requestUtils_1.serialiseParams)(
|
|
311
|
+
const serialisedParams = (0, requestUtils_1.serialiseParams)(params, strictParamValidation, encodeValues, filterUndefinedParams);
|
|
240
312
|
const signature = yield this.signMessage(serialisedParams, this.options.api_secret, 'base64', 'SHA-256');
|
|
241
|
-
// https://developers.binance.com/docs/binance-spot-api-docs/web-socket-api/request-security#signed-request-example-ed25519
|
|
242
313
|
const request = {
|
|
243
314
|
id: this.getNewRequestId(),
|
|
244
315
|
method: 'session.logon',
|
|
245
|
-
params: Object.assign(Object.assign({},
|
|
316
|
+
params: Object.assign(Object.assign({}, params), { signature }),
|
|
246
317
|
};
|
|
247
318
|
return request;
|
|
248
319
|
}
|
|
@@ -252,36 +323,12 @@ class WebsocketClient extends BaseWSClient_1.BaseWebsocketClient {
|
|
|
252
323
|
}
|
|
253
324
|
});
|
|
254
325
|
}
|
|
255
|
-
// private async getWsAuthSignature(
|
|
256
|
-
// wsKey: WsKey,
|
|
257
|
-
// ): Promise<{ expiresAt: number; signature: string }> {
|
|
258
|
-
// const { api_key, api_secret } = this.options;
|
|
259
|
-
// if (!api_key || !api_secret) {
|
|
260
|
-
// this.logger.error(
|
|
261
|
-
// 'Cannot authenticate websocket, either api or private keys missing.',
|
|
262
|
-
// { ...WS_LOGGER_CATEGORY, wsKey },
|
|
263
|
-
// );
|
|
264
|
-
// throw new Error('Cannot auth - missing api or secret in config');
|
|
265
|
-
// }
|
|
266
|
-
// this.logger.trace("Getting auth'd request params", {
|
|
267
|
-
// ...WS_LOGGER_CATEGORY,
|
|
268
|
-
// wsKey,
|
|
269
|
-
// });
|
|
270
|
-
// const recvWindow = this.options.recvWindow || 5000;
|
|
271
|
-
// const signatureExpiresAt = Date.now() + this.getTimeOffsetMs() + recvWindow;
|
|
272
|
-
// // const signature = await this.signMessage(
|
|
273
|
-
// // 'GET/realtime' + signatureExpiresAt,
|
|
274
|
-
// // api_secret,
|
|
275
|
-
// // 'hex',
|
|
276
|
-
// // 'SHA-256',
|
|
277
|
-
// // );
|
|
278
|
-
// return {
|
|
279
|
-
// expiresAt: signatureExpiresAt,
|
|
280
|
-
// signature: '',
|
|
281
|
-
// };
|
|
282
|
-
// }
|
|
283
326
|
sendPingEvent(wsKey) {
|
|
284
327
|
try {
|
|
328
|
+
if (!(0, websocket_util_1.isWSPingFrameAvailable)()) {
|
|
329
|
+
this.logger.trace('Unable to send WS ping frame. Not available in this environment.', Object.assign(Object.assign({}, WS_LOGGER_CATEGORY), { wsKey }));
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
285
332
|
// this.logger.trace(`Sending upstream ping: `, { ...loggerCategory, wsKey });
|
|
286
333
|
if (!wsKey) {
|
|
287
334
|
throw new Error('No wsKey provided');
|
|
@@ -304,8 +351,11 @@ class WebsocketClient extends BaseWSClient_1.BaseWebsocketClient {
|
|
|
304
351
|
}
|
|
305
352
|
}
|
|
306
353
|
sendPongEvent(wsKey) {
|
|
307
|
-
// ws.pong();
|
|
308
354
|
try {
|
|
355
|
+
if (!(0, websocket_util_1.isWSPongFrameAvailable)()) {
|
|
356
|
+
this.logger.trace('Unable to send WS pong frame. Not available in this environment.', Object.assign(Object.assign({}, WS_LOGGER_CATEGORY), { wsKey }));
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
309
359
|
// this.logger.trace(`Sending upstream ping: `, { ...loggerCategory, wsKey });
|
|
310
360
|
if (!wsKey) {
|
|
311
361
|
throw new Error('No wsKey provided');
|
|
@@ -347,6 +397,8 @@ class WebsocketClient extends BaseWSClient_1.BaseWebsocketClient {
|
|
|
347
397
|
params: topics,
|
|
348
398
|
id: req_id,
|
|
349
399
|
};
|
|
400
|
+
// Cache midflight subs on the req ID
|
|
401
|
+
// Enrich response with subs for that req ID
|
|
350
402
|
const midflightWsEvent = {
|
|
351
403
|
requestKey: wsEvent.id,
|
|
352
404
|
requestEvent: wsEvent,
|
|
@@ -354,9 +406,6 @@ class WebsocketClient extends BaseWSClient_1.BaseWebsocketClient {
|
|
|
354
406
|
wsRequestEvents.push(Object.assign({}, midflightWsEvent));
|
|
355
407
|
break;
|
|
356
408
|
}
|
|
357
|
-
// default: {
|
|
358
|
-
// throw neverGuard(wsKey, `Unhandled wsKey "${wsKey}"`);
|
|
359
|
-
// }
|
|
360
409
|
}
|
|
361
410
|
if (wsRequestBuildingErrors.length) {
|
|
362
411
|
const label = wsRequestBuildingErrors.length === requests.length ? 'all' : 'some';
|
|
@@ -402,28 +451,71 @@ class WebsocketClient extends BaseWSClient_1.BaseWebsocketClient {
|
|
|
402
451
|
* Abstraction called to sort ws events into emittable event types (response to a request, data update, etc)
|
|
403
452
|
*/
|
|
404
453
|
resolveEmittableEvents(wsKey, event) {
|
|
405
|
-
var _a, _b
|
|
454
|
+
var _a, _b;
|
|
455
|
+
this.logger.trace(`resolveEmittableEvents(${wsKey}): `, event === null || event === void 0 ? void 0 : event.data);
|
|
406
456
|
const results = [];
|
|
407
457
|
try {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
458
|
+
/**
|
|
459
|
+
*
|
|
460
|
+
* Extract event from JSON
|
|
461
|
+
*
|
|
462
|
+
*/
|
|
463
|
+
const parsedEvent = (0, websocket_util_1.parseRawWsMessage)(event);
|
|
464
|
+
/**
|
|
465
|
+
*
|
|
466
|
+
* Minor data normalisation & preparation
|
|
467
|
+
*
|
|
468
|
+
*/
|
|
469
|
+
// ws consumers: { data: ... }
|
|
470
|
+
// ws api consumers (user data): { event: ... }
|
|
471
|
+
// other responses: { ... }
|
|
472
|
+
const eventData = (parsedEvent === null || parsedEvent === void 0 ? void 0 : parsedEvent.data) || (parsedEvent === null || parsedEvent === void 0 ? void 0 : parsedEvent.event) || parsedEvent;
|
|
473
|
+
const parsedEventId = parsedEvent === null || parsedEvent === void 0 ? void 0 : parsedEvent.id;
|
|
474
|
+
const parsedEventErrorCode = (_a = parsedEvent === null || parsedEvent === void 0 ? void 0 : parsedEvent.error) === null || _a === void 0 ? void 0 : _a.code;
|
|
475
|
+
const streamName = parsedEvent === null || parsedEvent === void 0 ? void 0 : parsedEvent.stream;
|
|
476
|
+
const eventType =
|
|
477
|
+
// First try, the child node
|
|
478
|
+
(0, websocket_util_1.parseEventTypeFromMessage)(wsKey, eventData) ||
|
|
479
|
+
// Second try, the parent
|
|
480
|
+
(0, websocket_util_1.parseEventTypeFromMessage)(wsKey, parsedEvent);
|
|
411
481
|
// Some events don't include the topic (event name)
|
|
412
482
|
// This tries to extract and append it, using available context
|
|
413
|
-
(0, requestUtils_1.appendEventIfMissing)(
|
|
483
|
+
(0, requestUtils_1.appendEventIfMissing)(eventData, wsKey, eventType);
|
|
414
484
|
const legacyContext = (0, websocket_util_1.getLegacyWsKeyContext)(wsKey);
|
|
415
|
-
|
|
416
|
-
|
|
485
|
+
const wsMarket = legacyContext
|
|
486
|
+
? legacyContext.market
|
|
487
|
+
: (0, websocket_util_1.resolveUserDataMarketForWsKey)(wsKey);
|
|
488
|
+
// This attaches `wsMarket` and `streamName` to incoming events
|
|
489
|
+
// If the event is an array, it's attached to each element in the array
|
|
490
|
+
if (Array.isArray(eventData)) {
|
|
491
|
+
for (const row of eventData) {
|
|
492
|
+
row.wsMarket = wsMarket;
|
|
493
|
+
if (streamName && !row.streamName) {
|
|
494
|
+
row.streamName = streamName;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
417
497
|
}
|
|
418
|
-
|
|
419
|
-
|
|
498
|
+
else {
|
|
499
|
+
eventData.wsMarket = wsMarket;
|
|
500
|
+
if (streamName && !eventData.streamName) {
|
|
501
|
+
eventData.streamName = streamName;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
*
|
|
506
|
+
*
|
|
507
|
+
* Main parsing logic below:
|
|
508
|
+
*
|
|
509
|
+
*
|
|
510
|
+
*/
|
|
420
511
|
const traceEmittable = false;
|
|
421
512
|
if (traceEmittable) {
|
|
422
|
-
this.logger.trace('resolveEmittableEvents', Object.assign(Object.assign({}, WS_LOGGER_CATEGORY), { wsKey,
|
|
423
|
-
|
|
513
|
+
this.logger.trace('resolveEmittableEvents', Object.assign(Object.assign({}, WS_LOGGER_CATEGORY), { wsKey, parsedEvent: JSON.stringify(parsedEvent), parsedEventData: JSON.stringify(eventData), eventType, properties: {
|
|
514
|
+
parsedEventId,
|
|
515
|
+
parsedEventErrorCode,
|
|
516
|
+
} }));
|
|
424
517
|
}
|
|
425
|
-
const
|
|
426
|
-
const isWSAPIResponse = typeof parsed.id === 'number';
|
|
518
|
+
const isWSAPIResponse = typeof parsedEventId === 'number';
|
|
427
519
|
const EVENTS_AUTHENTICATED = ['auth'];
|
|
428
520
|
const EVENTS_RESPONSES = [
|
|
429
521
|
'subscribe',
|
|
@@ -433,9 +525,7 @@ class WebsocketClient extends BaseWSClient_1.BaseWebsocketClient {
|
|
|
433
525
|
'pong',
|
|
434
526
|
];
|
|
435
527
|
// WS API response
|
|
436
|
-
// TODO: after
|
|
437
528
|
if (isWSAPIResponse) {
|
|
438
|
-
const retCode = parsed.status;
|
|
439
529
|
/**
|
|
440
530
|
* Responses to "subscribe" are quite basic, with no indication of errors (e.g. bad topic):
|
|
441
531
|
*
|
|
@@ -444,86 +534,92 @@ class WebsocketClient extends BaseWSClient_1.BaseWebsocketClient {
|
|
|
444
534
|
* id: 1,
|
|
445
535
|
* };
|
|
446
536
|
*
|
|
447
|
-
*
|
|
537
|
+
* Currently there's no simple way to tell this apart from an actual WS API response with
|
|
538
|
+
* error. So subscribe/unsubscribe requests will simply look like a WS API response internally,
|
|
539
|
+
* but that will not affect usage.
|
|
448
540
|
*
|
|
449
|
-
*
|
|
541
|
+
* Unrelated, example wsapi error for reference:
|
|
450
542
|
*
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
543
|
+
{
|
|
544
|
+
id: 1,
|
|
545
|
+
status: 400,
|
|
546
|
+
error: {
|
|
547
|
+
code: -1021,
|
|
548
|
+
msg: "Timestamp for this request was 1000ms ahead of the server's time."
|
|
549
|
+
},
|
|
550
|
+
rateLimits: [
|
|
551
|
+
{
|
|
552
|
+
rateLimitType: 'REQUEST_WEIGHT',
|
|
553
|
+
interval: 'MINUTE',
|
|
554
|
+
intervalNum: 1,
|
|
555
|
+
limit: 6000,
|
|
556
|
+
count: 4
|
|
557
|
+
}
|
|
558
|
+
],
|
|
559
|
+
wsKey: 'mainWSAPI',
|
|
560
|
+
isWSAPIResponse: true
|
|
561
|
+
}
|
|
470
562
|
*/
|
|
471
|
-
const isError = typeof
|
|
563
|
+
const isError = typeof parsedEventErrorCode === 'number' &&
|
|
564
|
+
parsedEventErrorCode !== 0;
|
|
472
565
|
// This is the counterpart to getPromiseRefForWSAPIRequest
|
|
473
|
-
const promiseRef = [wsKey,
|
|
474
|
-
if (!
|
|
566
|
+
const promiseRef = [wsKey, parsedEventId].join('_');
|
|
567
|
+
if (!parsedEventId) {
|
|
475
568
|
this.logger.error('WS API response is missing reqId - promisified workflow could get stuck. If this happens, please get in touch with steps to reproduce. Trace:', {
|
|
476
569
|
wsKey,
|
|
477
570
|
promiseRef,
|
|
478
|
-
parsedEvent:
|
|
571
|
+
parsedEvent: eventData,
|
|
479
572
|
});
|
|
480
573
|
}
|
|
481
574
|
// WS API Exception
|
|
482
575
|
if (isError) {
|
|
483
576
|
try {
|
|
484
|
-
this.getWsStore().rejectDeferredPromise(wsKey, promiseRef, Object.assign({ wsKey },
|
|
577
|
+
this.getWsStore().rejectDeferredPromise(wsKey, promiseRef, Object.assign({ wsKey }, eventData), true);
|
|
485
578
|
}
|
|
486
579
|
catch (e) {
|
|
487
580
|
this.logger.error('Exception trying to reject WSAPI promise', {
|
|
488
581
|
wsKey,
|
|
489
582
|
promiseRef,
|
|
490
|
-
parsedEvent:
|
|
583
|
+
parsedEvent: eventData,
|
|
584
|
+
e,
|
|
491
585
|
});
|
|
492
586
|
}
|
|
493
587
|
results.push({
|
|
494
588
|
eventType: 'exception',
|
|
495
|
-
event:
|
|
589
|
+
event: eventData,
|
|
496
590
|
isWSAPIResponse: isWSAPIResponse,
|
|
497
591
|
});
|
|
498
592
|
return results;
|
|
499
593
|
}
|
|
500
594
|
// authenticated
|
|
501
|
-
if ((
|
|
502
|
-
// Note: Without this check, this will also trigger "
|
|
595
|
+
if ((_b = eventData.result) === null || _b === void 0 ? void 0 : _b.apiKey) {
|
|
596
|
+
// Note: Without this check, this will also trigger "onWsAuthenticated()" for session.status requests
|
|
503
597
|
if (this.getWsStore().getAuthenticationInProgressPromise(wsKey)) {
|
|
504
598
|
results.push({
|
|
505
599
|
eventType: 'authenticated',
|
|
506
|
-
event:
|
|
600
|
+
event: eventData,
|
|
507
601
|
isWSAPIResponse: isWSAPIResponse,
|
|
508
602
|
});
|
|
509
603
|
}
|
|
510
604
|
}
|
|
511
605
|
// WS API Success
|
|
512
606
|
try {
|
|
513
|
-
this.getWsStore().resolveDeferredPromise(wsKey, promiseRef, Object.assign({ wsKey },
|
|
607
|
+
this.getWsStore().resolveDeferredPromise(wsKey, promiseRef, Object.assign({ wsKey }, eventData), true);
|
|
514
608
|
}
|
|
515
609
|
catch (e) {
|
|
516
610
|
this.logger.error('Exception trying to resolve WSAPI promise', {
|
|
517
611
|
wsKey,
|
|
518
612
|
promiseRef,
|
|
519
|
-
parsedEvent:
|
|
613
|
+
parsedEvent: eventData,
|
|
614
|
+
e,
|
|
520
615
|
});
|
|
521
616
|
}
|
|
522
617
|
results.push({
|
|
523
618
|
eventType: 'response',
|
|
524
|
-
event:
|
|
619
|
+
event: Object.assign(Object.assign({}, eventData), { request: this.getCachedMidFlightRequest(wsKey, `${parsedEventId}`) }),
|
|
525
620
|
isWSAPIResponse: isWSAPIResponse,
|
|
526
621
|
});
|
|
622
|
+
this.removeCachedMidFlightRequest(wsKey, `${parsedEventId}`);
|
|
527
623
|
return results;
|
|
528
624
|
}
|
|
529
625
|
// Handle incoming event that listen key expired
|
|
@@ -533,16 +629,16 @@ class WebsocketClient extends BaseWSClient_1.BaseWebsocketClient {
|
|
|
533
629
|
// handle this how?
|
|
534
630
|
throw new Error('No context found within wsKey - fatal error with expired listen key');
|
|
535
631
|
}
|
|
536
|
-
this.logger.info(`${legacyContext.market} listenKey EXPIRED - attempting to respawn user data stream: ${wsKey}`,
|
|
632
|
+
this.logger.info(`${legacyContext.market} listenKey EXPIRED - attempting to respawn user data stream: ${wsKey}`, eventData);
|
|
537
633
|
// Just closing the connection (with the last parameter as true) will handle cleanup and respawn
|
|
538
634
|
// Automatically leads to triggerCustomReconnectionWorkflow() to handle fresh user data respawn
|
|
539
635
|
this.getUserDataStreamManager().teardownUserDataListenKey(legacyContext.listenKey, this.getWsStore().getWs(wsKey));
|
|
540
636
|
this.executeReconnectableClose(wsKey, 'listenKeyExpired');
|
|
541
637
|
}
|
|
542
638
|
if (this.options.beautify) {
|
|
543
|
-
const beautifiedMessage = this.beautifier.beautifyWsMessage(
|
|
639
|
+
const beautifiedMessage = this.beautifier.beautifyWsMessage(eventData, eventType, false,
|
|
544
640
|
// Suffix all events for the beautifier, if market is options
|
|
545
|
-
// Options has some conflicting keys with different intentions
|
|
641
|
+
// Options has some conflicting keys with different intentions, so will be suffixed
|
|
546
642
|
wsKey === 'eoptions' ? 'Options' : '');
|
|
547
643
|
results.push({
|
|
548
644
|
eventType: 'formattedMessage',
|
|
@@ -551,19 +647,7 @@ class WebsocketClient extends BaseWSClient_1.BaseWebsocketClient {
|
|
|
551
647
|
});
|
|
552
648
|
// emit an additional event for user data messages
|
|
553
649
|
if (!Array.isArray(beautifiedMessage) && eventType) {
|
|
554
|
-
if (
|
|
555
|
-
'balanceUpdate',
|
|
556
|
-
'executionReport',
|
|
557
|
-
'listStatus',
|
|
558
|
-
'listenKeyExpired',
|
|
559
|
-
'outboundAccountPosition',
|
|
560
|
-
'ACCOUNT_CONFIG_UPDATE',
|
|
561
|
-
'ACCOUNT_UPDATE',
|
|
562
|
-
'MARGIN_CALL',
|
|
563
|
-
'ORDER_TRADE_UPDATE',
|
|
564
|
-
'TRADE_LITE',
|
|
565
|
-
'CONDITIONAL_ORDER_TRIGGER_REJECT',
|
|
566
|
-
].includes(eventType)) {
|
|
650
|
+
if (websocket_util_1.EVENT_TYPES_USER_DATA.includes(eventType)) {
|
|
567
651
|
results.push({
|
|
568
652
|
eventType: 'formattedUserDataMessage',
|
|
569
653
|
event: beautifiedMessage,
|
|
@@ -576,17 +660,17 @@ class WebsocketClient extends BaseWSClient_1.BaseWebsocketClient {
|
|
|
576
660
|
if (typeof eventType === 'string') {
|
|
577
661
|
results.push({
|
|
578
662
|
eventType: 'message',
|
|
579
|
-
event: (
|
|
663
|
+
event: (eventData === null || eventData === void 0 ? void 0 : eventData.data) ? eventData.data : eventData,
|
|
580
664
|
});
|
|
581
665
|
return results;
|
|
582
666
|
}
|
|
583
667
|
// Messages that are a "reply" to a request/command (e.g. subscribe to these topics) typically include the "op" property
|
|
584
668
|
if (typeof eventType === 'string') {
|
|
585
669
|
// Failed request
|
|
586
|
-
if (
|
|
670
|
+
if (eventData.success === false) {
|
|
587
671
|
results.push({
|
|
588
672
|
eventType: 'exception',
|
|
589
|
-
event:
|
|
673
|
+
event: eventData,
|
|
590
674
|
});
|
|
591
675
|
return results;
|
|
592
676
|
}
|
|
@@ -594,7 +678,7 @@ class WebsocketClient extends BaseWSClient_1.BaseWebsocketClient {
|
|
|
594
678
|
if (EVENTS_RESPONSES.includes(eventType)) {
|
|
595
679
|
results.push({
|
|
596
680
|
eventType: 'response',
|
|
597
|
-
event:
|
|
681
|
+
event: eventData,
|
|
598
682
|
});
|
|
599
683
|
return results;
|
|
600
684
|
}
|
|
@@ -602,19 +686,19 @@ class WebsocketClient extends BaseWSClient_1.BaseWebsocketClient {
|
|
|
602
686
|
if (EVENTS_AUTHENTICATED.includes(eventType)) {
|
|
603
687
|
results.push({
|
|
604
688
|
eventType: 'authenticated',
|
|
605
|
-
event:
|
|
689
|
+
event: eventData,
|
|
606
690
|
});
|
|
607
691
|
return results;
|
|
608
692
|
}
|
|
609
|
-
this.logger.error(`!! Unhandled string operation type "${eventType}". Defaulting to "update" channel
|
|
693
|
+
this.logger.error(`!! Unhandled string operation type "${eventType}". Defaulting to "update" channel... raw event:`, JSON.stringify(parsedEvent));
|
|
610
694
|
}
|
|
611
695
|
else {
|
|
612
|
-
this.logger.error(`!!!! Unhandled non-string event type "${eventType}". Defaulting to "update" channel
|
|
696
|
+
this.logger.error(`!!!! Unhandled non-string event type "${eventType}". Defaulting to "update" channel... raw event:`, JSON.stringify(parsedEvent));
|
|
613
697
|
}
|
|
614
698
|
// In case of catastrophic failure, fallback to noisy emit update
|
|
615
699
|
results.push({
|
|
616
700
|
eventType: 'message',
|
|
617
|
-
event:
|
|
701
|
+
event: eventData,
|
|
618
702
|
});
|
|
619
703
|
}
|
|
620
704
|
catch (e) {
|
|
@@ -748,7 +832,6 @@ class WebsocketClient extends BaseWSClient_1.BaseWebsocketClient {
|
|
|
748
832
|
}
|
|
749
833
|
triggerCustomReconnectionWorkflow(legacyWsKey) {
|
|
750
834
|
return __awaiter(this, void 0, void 0, function* () {
|
|
751
|
-
console.log(`triggerCustomReconnectionWorkflow(${legacyWsKey})`);
|
|
752
835
|
if (legacyWsKey.includes('userData')) {
|
|
753
836
|
return this.getUserDataStreamManager().triggerUserDataReconnectionWorkflow(legacyWsKey);
|
|
754
837
|
}
|
|
@@ -790,13 +873,13 @@ class WebsocketClient extends BaseWSClient_1.BaseWebsocketClient {
|
|
|
790
873
|
ws = yield this.subscribeUsdFuturesUserDataStream(realWsKey, forceNewConnection, miscConnectionState);
|
|
791
874
|
break;
|
|
792
875
|
case 'usdmTestnet':
|
|
793
|
-
ws = yield this.subscribeUsdFuturesUserDataStream(
|
|
876
|
+
ws = yield this.subscribeUsdFuturesUserDataStream(realWsKey, forceNewConnection, miscConnectionState);
|
|
794
877
|
break;
|
|
795
878
|
case 'coinm':
|
|
796
879
|
ws = yield this.subscribeCoinFuturesUserDataStream(realWsKey, forceNewConnection, miscConnectionState);
|
|
797
880
|
break;
|
|
798
881
|
case 'coinmTestnet':
|
|
799
|
-
ws = yield this.subscribeCoinFuturesUserDataStream(
|
|
882
|
+
ws = yield this.subscribeCoinFuturesUserDataStream(realWsKey, forceNewConnection, miscConnectionState);
|
|
800
883
|
break;
|
|
801
884
|
case 'portfoliom':
|
|
802
885
|
ws = yield this.subscribePortfolioMarginUserDataStream(realWsKey, forceNewConnection, miscConnectionState);
|
|
@@ -849,7 +932,7 @@ class WebsocketClient extends BaseWSClient_1.BaseWebsocketClient {
|
|
|
849
932
|
forceNewConnection, miscState) {
|
|
850
933
|
try {
|
|
851
934
|
const isTestnet = wsKey === websocket_util_1.WS_KEY_MAP.usdmTestnet;
|
|
852
|
-
const restClient = this.restClientCache.getUSDMRestClient(this.getRestClientOptions(), this.options.requestOptions
|
|
935
|
+
const restClient = this.restClientCache.getUSDMRestClient(this.getRestClientOptions(), this.options.requestOptions);
|
|
853
936
|
const { listenKey } = yield restClient.getFuturesUserDataListenKey();
|
|
854
937
|
const market = isTestnet ? 'usdmTestnet' : 'usdm';
|
|
855
938
|
return this.getUserDataStreamManager().subscribeGeneralUserDataStreamWithListenKey(wsKey, market, listenKey, forceNewConnection, miscState);
|
|
@@ -861,6 +944,18 @@ class WebsocketClient extends BaseWSClient_1.BaseWebsocketClient {
|
|
|
861
944
|
}
|
|
862
945
|
});
|
|
863
946
|
}
|
|
947
|
+
closeUserDataStream() {
|
|
948
|
+
return __awaiter(this, arguments, void 0, function* (wsKey = 'usdm') {
|
|
949
|
+
const wsKeys = this.getWsStore().getKeys();
|
|
950
|
+
const userDataWsKey = wsKeys.find((key) => {
|
|
951
|
+
return key === wsKey || key.startsWith(wsKey + '_userData');
|
|
952
|
+
});
|
|
953
|
+
if (!userDataWsKey) {
|
|
954
|
+
throw new Error(`No matching connection found with wsKey "${wsKey}". Active connections: [${JSON.stringify(wsKey)}]`);
|
|
955
|
+
}
|
|
956
|
+
this.close(userDataWsKey);
|
|
957
|
+
});
|
|
958
|
+
}
|
|
864
959
|
/**
|
|
865
960
|
* Subscribe to COIN-M Futures user data stream - listen key is automatically generated.
|
|
866
961
|
*/
|
|
@@ -870,7 +965,7 @@ class WebsocketClient extends BaseWSClient_1.BaseWebsocketClient {
|
|
|
870
965
|
try {
|
|
871
966
|
const isTestnet = wsKey === websocket_util_1.WS_KEY_MAP.coinmTestnet;
|
|
872
967
|
const { listenKey } = yield this.restClientCache
|
|
873
|
-
.getCOINMRestClient(this.getRestClientOptions(), this.options.requestOptions
|
|
968
|
+
.getCOINMRestClient(this.getRestClientOptions(), this.options.requestOptions)
|
|
874
969
|
.getFuturesUserDataListenKey();
|
|
875
970
|
const market = isTestnet ? 'coinmTestnet' : 'coinm';
|
|
876
971
|
return this.getUserDataStreamManager().subscribeGeneralUserDataStreamWithListenKey(wsKey, market, listenKey, forceNewConnection, miscState);
|