node-opcua-client 2.100.0 → 2.102.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/dist/client_session_keepalive_manager.d.ts +1 -1
- package/dist/client_session_keepalive_manager.js +9 -3
- package/dist/client_session_keepalive_manager.js.map +1 -1
- package/dist/private/client_base_impl.d.ts +2 -1
- package/dist/private/client_base_impl.js +35 -30
- package/dist/private/client_base_impl.js.map +1 -1
- package/dist/private/client_publish_engine.js +2 -1
- package/dist/private/client_publish_engine.js.map +1 -1
- package/dist/private/client_session_impl.d.ts +3 -0
- package/dist/private/client_session_impl.js +26 -12
- package/dist/private/client_session_impl.js.map +1 -1
- package/dist/private/i_private_client.d.ts +1 -0
- package/dist/private/opcua_client_impl.js +1 -3
- package/dist/private/opcua_client_impl.js.map +1 -1
- package/dist/reconnection.js +30 -14
- package/dist/reconnection.js.map +1 -1
- package/package.json +26 -29
- package/source/client_session_keepalive_manager.ts +48 -35
- package/source/private/client_base_impl.ts +42 -44
- package/source/private/client_publish_engine.ts +2 -1
- package/source/private/client_session_impl.ts +35 -24
- package/source/private/i_private_client.ts +2 -0
- package/source/private/opcua_client_impl.ts +10 -13
- package/source/reconnection.ts +52 -33
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* @module node-opcua-client-private
|
|
3
3
|
*/
|
|
4
4
|
import { EventEmitter } from "events";
|
|
5
|
+
import { callbackify } from "util";
|
|
5
6
|
import * as chalk from "chalk";
|
|
6
7
|
import { assert } from "node-opcua-assert";
|
|
7
8
|
import { AggregateFunction } from "node-opcua-constants";
|
|
@@ -22,7 +23,7 @@ import { ExtensionObject } from "node-opcua-extension-object";
|
|
|
22
23
|
import { coerceNodeId, NodeId, NodeIdLike, resolveNodeId } from "node-opcua-nodeid";
|
|
23
24
|
import { getBuiltInDataType, getArgumentDefinitionHelper, IBasicSession, IBasicTransportSettings } from "node-opcua-pseudo-session";
|
|
24
25
|
import { AnyConstructorFunc } from "node-opcua-schemas";
|
|
25
|
-
import { requestHandleNotSetValue, SignatureData } from "node-opcua-secure-channel";
|
|
26
|
+
import { ClientSecureChannelLayer, requestHandleNotSetValue, SignatureData } from "node-opcua-secure-channel";
|
|
26
27
|
import { BrowseDescription, BrowseRequest, BrowseResponse, BrowseResult } from "node-opcua-service-browse";
|
|
27
28
|
import { CallMethodRequest, CallMethodResult, CallRequest, CallResponse } from "node-opcua-service-call";
|
|
28
29
|
import { EndpointDescription } from "node-opcua-service-endpoints";
|
|
@@ -293,7 +294,6 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
|
|
|
293
294
|
this.timeout = 0;
|
|
294
295
|
}
|
|
295
296
|
|
|
296
|
-
|
|
297
297
|
getTransportSettings(): IBasicTransportSettings {
|
|
298
298
|
return this._client!.getTransportSettings();
|
|
299
299
|
}
|
|
@@ -546,13 +546,12 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
|
|
|
546
546
|
* ```javascript
|
|
547
547
|
* const dataValues = await session.readVariableValue(["ns=1;s=Temperature","ns=1;s=Pressure"]);
|
|
548
548
|
* ```
|
|
549
|
+
*
|
|
550
|
+
* @deprecated
|
|
549
551
|
*/
|
|
550
552
|
public readVariableValue(nodeId: NodeIdLike, callback: ResponseCallback<DataValue>): void;
|
|
551
|
-
|
|
552
553
|
public readVariableValue(nodeIds: NodeIdLike[], callback: ResponseCallback<DataValue[]>): void;
|
|
553
|
-
|
|
554
554
|
public async readVariableValue(nodeId: NodeIdLike): Promise<DataValue>;
|
|
555
|
-
|
|
556
555
|
public async readVariableValue(nodeIds: NodeIdLike[]): Promise<DataValue[]>;
|
|
557
556
|
/**
|
|
558
557
|
* @internal
|
|
@@ -1556,19 +1555,27 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
|
|
|
1556
1555
|
return this._client !== null && this._client._secureChannel !== null && this._client._secureChannel.isOpened();
|
|
1557
1556
|
}
|
|
1558
1557
|
|
|
1558
|
+
private requestReconnection() {
|
|
1559
|
+
if (this._client) {
|
|
1560
|
+
this._client.requestReconnection();
|
|
1561
|
+
assert(this._client.isReconnecting === true, "expecting client to be reconnecting now");
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1559
1565
|
public performMessageTransaction(request: Request, callback: (err: Error | null, response?: Response) => void): void {
|
|
1560
1566
|
if (!this._client) {
|
|
1561
1567
|
// session may have been closed by user ... but is still in used !!
|
|
1562
1568
|
return callback(new Error("Session has been closed and should not be used to perform a transaction anymore"));
|
|
1563
1569
|
}
|
|
1564
1570
|
|
|
1565
|
-
if (!this.isChannelValid()) {
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1571
|
+
// if (!this.isChannelValid()) {
|
|
1572
|
+
// // the secure channel is broken, may be the server has crashed or the network cable has been disconnected
|
|
1573
|
+
// // for a long time
|
|
1574
|
+
// // we may need to queue this transaction, as a secure token may be being reprocessed
|
|
1575
|
+
// errorLog(chalk.bgWhite.red("!!! Performing transaction on invalid channel !!! ", request.schema.name));
|
|
1576
|
+
// // this.requestReconnection();
|
|
1577
|
+
// return callback(new Error("!!! Performing transaction on invalid channel with " + request.schema.name + ": starting reconnection process"));
|
|
1578
|
+
// }
|
|
1572
1579
|
|
|
1573
1580
|
this._reconnecting.pendingTransactions = this._reconnecting.pendingTransactions || [];
|
|
1574
1581
|
this._reconnecting.pendingTransactionsCount = this._reconnecting.pendingTransactionsCount || 0;
|
|
@@ -2014,7 +2021,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
|
|
|
2014
2021
|
});
|
|
2015
2022
|
this._keepAliveManager.start();
|
|
2016
2023
|
}
|
|
2017
|
-
|
|
2024
|
+
|
|
2018
2025
|
public stopKeepAliveManager(): void {
|
|
2019
2026
|
if (this._keepAliveManager) {
|
|
2020
2027
|
this._keepAliveManager.stop();
|
|
@@ -2066,6 +2073,12 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
|
|
|
2066
2073
|
str += "\n reviseTokenLifetime...... " + this._client._secureChannel.securityToken.revisedLifetime;
|
|
2067
2074
|
}
|
|
2068
2075
|
}
|
|
2076
|
+
str += "\n keepAlive ................ " + this._keepAliveManager ? true: false;
|
|
2077
|
+
if (this._keepAliveManager) {
|
|
2078
|
+
str += "\n keepAlive checkInterval.. " + this._keepAliveManager.checkInterval;
|
|
2079
|
+
str += "\n defaultTransportTimeout.. " + ClientSecureChannelLayer.defaultTransportTimeout;
|
|
2080
|
+
|
|
2081
|
+
}
|
|
2069
2082
|
return str;
|
|
2070
2083
|
}
|
|
2071
2084
|
|
|
@@ -2300,19 +2313,18 @@ async function promoteOpaqueStructure2(session: IBasicSession, callMethodResult:
|
|
|
2300
2313
|
function countOpaqueStructures(callMethodResults: CallMethodResult[]): number {
|
|
2301
2314
|
const x = (a: Variant[] | null): PseudoDataValue[] => {
|
|
2302
2315
|
if (a === null) return [] as PseudoDataValue[];
|
|
2303
|
-
return a.map((value) => {
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2316
|
+
return a.map((value) => {
|
|
2317
|
+
return { value: value };
|
|
2318
|
+
});
|
|
2319
|
+
};
|
|
2320
|
+
const opaqueStructureCount = callMethodResults.reduce((prev, callMethodResult) => {
|
|
2321
|
+
return prev + extractDataValueToPromote(x(callMethodResult.outputArguments)).length;
|
|
2322
|
+
}, 0);
|
|
2309
2323
|
return opaqueStructureCount;
|
|
2310
2324
|
}
|
|
2311
2325
|
async function promoteOpaqueStructure3(session: IBasicSession, callMethodResults: CallMethodResult[]): Promise<void> {
|
|
2312
|
-
|
|
2313
2326
|
const opaqueStructureCount = countOpaqueStructures(callMethodResults);
|
|
2314
|
-
if (0 === opaqueStructureCount)
|
|
2315
|
-
return;
|
|
2327
|
+
if (0 === opaqueStructureCount) return;
|
|
2316
2328
|
|
|
2317
2329
|
// construct dataTypeManager if not already present
|
|
2318
2330
|
await getExtraDataTypeManager(session);
|
|
@@ -2324,11 +2336,11 @@ async function promoteOpaqueStructure3(session: IBasicSession, callMethodResults
|
|
|
2324
2336
|
// tslint:disable:no-var-requires
|
|
2325
2337
|
// tslint:disable:max-line-length
|
|
2326
2338
|
const thenify = require("thenify");
|
|
2327
|
-
const callbackify = require("callbackify");
|
|
2328
2339
|
const opts = { multiArgs: false };
|
|
2329
2340
|
|
|
2330
2341
|
const promoteOpaqueStructureWithCallback = callbackify(promoteOpaqueStructure);
|
|
2331
2342
|
const promoteOpaqueStructure3WithCallback = callbackify(promoteOpaqueStructure3) as promoteOpaqueStructure3WithCallbackFunc;
|
|
2343
|
+
// ClientSessionImpl.prototype.constructExtensionObject = callbackify(ClientSessionImpl.prototype.constructExtensionObject) as any;
|
|
2332
2344
|
|
|
2333
2345
|
ClientSessionImpl.prototype.browse = thenify.withCallback(ClientSessionImpl.prototype.browse, opts);
|
|
2334
2346
|
ClientSessionImpl.prototype.browseNext = thenify.withCallback(ClientSessionImpl.prototype.browseNext, opts);
|
|
@@ -2367,5 +2379,4 @@ ClientSessionImpl.prototype.registerNodes = thenify.withCallback(ClientSessionIm
|
|
|
2367
2379
|
ClientSessionImpl.prototype.unregisterNodes = thenify.withCallback(ClientSessionImpl.prototype.unregisterNodes, opts);
|
|
2368
2380
|
ClientSessionImpl.prototype.readNamespaceArray = thenify.withCallback(ClientSessionImpl.prototype.readNamespaceArray, opts);
|
|
2369
2381
|
ClientSessionImpl.prototype.getBuiltInDataType = thenify.withCallback(ClientSessionImpl.prototype.getBuiltInDataType, opts);
|
|
2370
|
-
ClientSessionImpl.prototype.constructExtensionObject = callbackify(ClientSessionImpl.prototype.constructExtensionObject);
|
|
2371
2382
|
ClientSessionImpl.prototype.changeUser = thenify.withCallback(ClientSessionImpl.prototype.changeUser, opts);
|
|
@@ -755,10 +755,10 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
755
755
|
}
|
|
756
756
|
// istanbul ignore next
|
|
757
757
|
if (!this.__resolveEndPoint() || !this.endpoint) {
|
|
758
|
-
return callback!(
|
|
758
|
+
return callback!(
|
|
759
759
|
new Error(
|
|
760
|
-
" End point must exist " + this._secureChannel!.endpointUrl +
|
|
761
|
-
" securityMode = " + MessageSecurityMode[this.securityMode] +
|
|
760
|
+
" End point must exist " + this._secureChannel!.endpointUrl +
|
|
761
|
+
" securityMode = " + MessageSecurityMode[this.securityMode] +
|
|
762
762
|
" securityPolicy = " + this.securityPolicy));
|
|
763
763
|
}
|
|
764
764
|
|
|
@@ -805,10 +805,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
805
805
|
* @private
|
|
806
806
|
*/
|
|
807
807
|
public _on_connection_reestablished(callback: (err?: Error) => void): void {
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
// call base class implementation first
|
|
811
|
-
ClientBaseImpl.prototype._on_connection_reestablished.call(this, (/*err?: Error*/) => {
|
|
808
|
+
super._on_connection_reestablished((/*err?: Error*/) => {
|
|
812
809
|
repair_client_sessions(this, callback);
|
|
813
810
|
});
|
|
814
811
|
}
|
|
@@ -849,7 +846,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
849
846
|
this.clientNonce = crypto.randomBytes(32);
|
|
850
847
|
|
|
851
848
|
// recycle session name if already exists
|
|
852
|
-
const sessionName =
|
|
849
|
+
const sessionName = session.name
|
|
853
850
|
|
|
854
851
|
const request = new CreateSessionRequest({
|
|
855
852
|
clientCertificate: this.getCertificate(),
|
|
@@ -1163,15 +1160,15 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
1163
1160
|
this._serverEndpoints.map(
|
|
1164
1161
|
(endpoint) =>
|
|
1165
1162
|
endpoint.endpointUrl + " "
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1163
|
+
+ MessageSecurityMode[endpoint.securityMode] + " "
|
|
1164
|
+
+ endpoint.securityPolicyUri + " "
|
|
1165
|
+
+ endpoint.userIdentityTokens?.map((u) => UserTokenType[u.tokenType]).join(",")
|
|
1169
1166
|
).join('\n')
|
|
1170
1167
|
);
|
|
1171
1168
|
}
|
|
1172
1169
|
return callback(new Error(
|
|
1173
|
-
" End point must exist " + this._secureChannel!.endpointUrl +
|
|
1174
|
-
" securityMode = " + MessageSecurityMode[this.securityMode] +
|
|
1170
|
+
" End point must exist " + this._secureChannel!.endpointUrl +
|
|
1171
|
+
" securityMode = " + MessageSecurityMode[this.securityMode] +
|
|
1175
1172
|
" securityPolicy = " + this.securityPolicy));
|
|
1176
1173
|
}
|
|
1177
1174
|
this.serverUri = this.endpoint.server.applicationUri || "invalid application uri";
|
package/source/reconnection.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { TransferSubscriptionsRequest, TransferSubscriptionsResponse } from "nod
|
|
|
11
11
|
import { CallbackT, StatusCode, StatusCodes } from "node-opcua-status-code";
|
|
12
12
|
import { ErrorCallback } from "node-opcua-status-code";
|
|
13
13
|
import { CloseSessionRequest } from "node-opcua-types";
|
|
14
|
+
import { invalidateExtraDataTypeManager } from "node-opcua-client-dynamic-extension-object";
|
|
14
15
|
|
|
15
16
|
import { SubscriptionId } from "./client_session";
|
|
16
17
|
import { ClientSessionImpl, Reconnectable } from "./private/client_session_impl";
|
|
@@ -139,7 +140,7 @@ function create_session_and_repeat_if_failed(
|
|
|
139
140
|
callback: CallbackT<ClientSessionImpl>
|
|
140
141
|
) {
|
|
141
142
|
if (session.hasBeenClosed()) {
|
|
142
|
-
doDebug && debugLog("Cannot complete subscription republish due to session
|
|
143
|
+
doDebug && debugLog("Cannot complete subscription republish due to session termination");
|
|
143
144
|
return callback(new Error("Cannot complete subscription republish due to session termination"));
|
|
144
145
|
}
|
|
145
146
|
doDebug && debugLog(chalk.bgWhite.red(" => creating a new session ...."));
|
|
@@ -147,7 +148,7 @@ function create_session_and_repeat_if_failed(
|
|
|
147
148
|
// so we can reuse subscriptions data
|
|
148
149
|
client.__createSession_step2(session, (err: Error | null, session1?: ClientSessionImpl) => {
|
|
149
150
|
if (err && session.hasBeenClosed()) {
|
|
150
|
-
doDebug && debugLog("Cannot complete subscription republish due to session
|
|
151
|
+
doDebug && debugLog("Cannot complete subscription republish due to session termination");
|
|
151
152
|
return callback(new Error("Cannot complete subscription republish due to session termination"));
|
|
152
153
|
}
|
|
153
154
|
if (!err && session1) {
|
|
@@ -166,6 +167,11 @@ function repair_client_session_by_recreating_a_new_session(
|
|
|
166
167
|
session: ClientSessionImpl,
|
|
167
168
|
callback: (err?: Error) => void
|
|
168
169
|
) {
|
|
170
|
+
|
|
171
|
+
// As we don"t know if server has been rebooted or not,
|
|
172
|
+
// and may be upgraded in between, we have to invalidate the extra data type manager
|
|
173
|
+
invalidateExtraDataTypeManager(session);
|
|
174
|
+
|
|
169
175
|
if (doDebug) {
|
|
170
176
|
doDebug && debugLog(" repairing client session by_recreating a new session for old session ", session.sessionId.toString());
|
|
171
177
|
}
|
|
@@ -210,13 +216,17 @@ function repair_client_session_by_recreating_a_new_session(
|
|
|
210
216
|
newSession,
|
|
211
217
|
newSession.userIdentityInfo!,
|
|
212
218
|
(err: Error | null, session1?: ClientSessionImpl) => {
|
|
213
|
-
doDebug &&
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
chalk.bgWhite.cyan(
|
|
217
|
-
"reactivation of the new session has failed: let be smart and close it before failing this repair attempt"
|
|
218
|
-
)
|
|
219
|
+
doDebug &&
|
|
220
|
+
debugLog(
|
|
221
|
+
chalk.bgWhite.cyan(" => activating a new session .... Done err=", err ? err.message : "null")
|
|
219
222
|
);
|
|
223
|
+
if (err) {
|
|
224
|
+
doDebug &&
|
|
225
|
+
debugLog(
|
|
226
|
+
chalk.bgWhite.cyan(
|
|
227
|
+
"reactivation of the new session has failed: let be smart and close it before failing this repair attempt"
|
|
228
|
+
)
|
|
229
|
+
);
|
|
220
230
|
// but just on the server side, not on the client side
|
|
221
231
|
const closeSessionRequest = new CloseSessionRequest({
|
|
222
232
|
deleteSubscriptions: true
|
|
@@ -277,10 +287,11 @@ function repair_client_session_by_recreating_a_new_session(
|
|
|
277
287
|
|
|
278
288
|
// istanbul ignore next
|
|
279
289
|
if (doDebug) {
|
|
280
|
-
doDebug &&
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
290
|
+
doDebug &&
|
|
291
|
+
debugLog(
|
|
292
|
+
chalk.cyan(" => transfer subscriptions done"),
|
|
293
|
+
results.map((x: any) => x.statusCode.toString()).join(" ")
|
|
294
|
+
);
|
|
284
295
|
}
|
|
285
296
|
|
|
286
297
|
const subscriptionsToRecreate = [];
|
|
@@ -291,22 +302,24 @@ function repair_client_session_by_recreating_a_new_session(
|
|
|
291
302
|
const statusCode = results[i].statusCode;
|
|
292
303
|
if (statusCode.equals(StatusCodes.BadSubscriptionIdInvalid)) {
|
|
293
304
|
// repair subscription
|
|
294
|
-
doDebug &&
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
305
|
+
doDebug &&
|
|
306
|
+
debugLog(
|
|
307
|
+
chalk.red(" WARNING SUBSCRIPTION "),
|
|
308
|
+
subscriptionsIds[i],
|
|
309
|
+
chalk.red(" SHOULD BE RECREATED")
|
|
310
|
+
);
|
|
299
311
|
|
|
300
312
|
subscriptionsToRecreate.push(subscriptionsIds[i]);
|
|
301
313
|
} else {
|
|
302
314
|
const availableSequenceNumbers = results[i].availableSequenceNumbers;
|
|
303
315
|
|
|
304
|
-
doDebug &&
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
316
|
+
doDebug &&
|
|
317
|
+
debugLog(
|
|
318
|
+
chalk.green(" SUBSCRIPTION "),
|
|
319
|
+
subscriptionsIds[i],
|
|
320
|
+
chalk.green(" CAN BE REPAIRED AND AVAILABLE "),
|
|
321
|
+
availableSequenceNumbers
|
|
322
|
+
);
|
|
310
323
|
// should be Good.
|
|
311
324
|
}
|
|
312
325
|
}
|
|
@@ -329,10 +342,11 @@ function repair_client_session_by_recreating_a_new_session(
|
|
|
329
342
|
doDebug && debugLog("_recreateSubscription failed !" + err1.message);
|
|
330
343
|
}
|
|
331
344
|
|
|
332
|
-
doDebug &&
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
345
|
+
doDebug &&
|
|
346
|
+
debugLog(
|
|
347
|
+
chalk.cyan(" => RECREATING SUBSCRIPTION AND MONITORED ITEM DONE "),
|
|
348
|
+
subscriptionId
|
|
349
|
+
);
|
|
336
350
|
|
|
337
351
|
next();
|
|
338
352
|
});
|
|
@@ -379,7 +393,8 @@ function repair_client_session_by_recreating_a_new_session(
|
|
|
379
393
|
|
|
380
394
|
function _repair_client_session(client: IClientBase, session: ClientSessionImpl, callback: (err?: Error) => void): void {
|
|
381
395
|
const callback2 = (err2?: Error) => {
|
|
382
|
-
doDebug &&
|
|
396
|
+
doDebug &&
|
|
397
|
+
debugLog("Session repair completed with err: ", err2 ? err2.message : "<no error>", session.sessionId.toString());
|
|
383
398
|
session.emit("session_repaired");
|
|
384
399
|
callback(err2);
|
|
385
400
|
};
|
|
@@ -433,9 +448,14 @@ export function repair_client_session(client: IClientBase, session: ClientSessio
|
|
|
433
448
|
session.sessionId.toString(),
|
|
434
449
|
" => Let's retry"
|
|
435
450
|
);
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
451
|
+
if (!session.hasBeenClosed()) {
|
|
452
|
+
setTimeout(() => {
|
|
453
|
+
_repair_client_session(client, session, callback);
|
|
454
|
+
}, 2000);
|
|
455
|
+
} else {
|
|
456
|
+
// session does not need to be repaired anymore
|
|
457
|
+
callback();
|
|
458
|
+
}
|
|
439
459
|
return;
|
|
440
460
|
}
|
|
441
461
|
doDebug && debugLog(chalk.yellow("session has been restored"), session.sessionId.toString());
|
|
@@ -452,9 +472,8 @@ export function repair_client_session(client: IClientBase, session: ClientSessio
|
|
|
452
472
|
}
|
|
453
473
|
|
|
454
474
|
export function repair_client_sessions(client: IClientBase, callback: (err?: Error) => void): void {
|
|
455
|
-
const self = client;
|
|
456
475
|
// repair session
|
|
457
|
-
const sessions =
|
|
476
|
+
const sessions = client.getSessions();
|
|
458
477
|
doDebug && debugLog(chalk.red.bgWhite(" Starting sessions reactivation", sessions.length));
|
|
459
478
|
async.map(
|
|
460
479
|
sessions,
|