node-opcua-client 2.122.0 → 2.124.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/private/client_base_impl.d.ts +11 -4
- package/dist/private/client_base_impl.js +130 -70
- package/dist/private/client_base_impl.js.map +1 -1
- package/dist/private/client_publish_engine.d.ts +9 -4
- package/dist/private/client_publish_engine.js +4 -98
- package/dist/private/client_publish_engine.js.map +1 -1
- package/dist/private/client_session_impl.d.ts +20 -4
- package/dist/private/client_session_impl.js +2 -21
- package/dist/private/client_session_impl.js.map +1 -1
- package/dist/private/client_subscription_impl.d.ts +5 -8
- package/dist/private/client_subscription_impl.js +83 -174
- package/dist/private/client_subscription_impl.js.map +1 -1
- package/dist/private/i_private_client.d.ts +0 -1
- package/dist/private/opcua_client_impl.js +1 -1
- package/dist/private/opcua_client_impl.js.map +1 -1
- package/dist/private/reconnection/client_publish_engine_reconnection.d.ts +2 -0
- package/dist/private/reconnection/client_publish_engine_reconnection.js +118 -0
- package/dist/private/reconnection/client_publish_engine_reconnection.js.map +1 -0
- package/dist/private/reconnection/client_reconnection.d.ts +2 -0
- package/dist/private/reconnection/client_reconnection.js +20 -0
- package/dist/private/reconnection/client_reconnection.js.map +1 -0
- package/dist/private/reconnection/client_subscription_reconnection.d.ts +7 -0
- package/dist/private/reconnection/client_subscription_reconnection.js +124 -0
- package/dist/private/reconnection/client_subscription_reconnection.js.map +1 -0
- package/dist/private/reconnection/reconnection.d.ts +12 -0
- package/dist/private/reconnection/reconnection.js +564 -0
- package/dist/private/reconnection/reconnection.js.map +1 -0
- package/dist/reconnection.js.map +1 -1
- package/package.json +24 -24
- package/source/private/client_base_impl.ts +142 -83
- package/source/private/client_publish_engine.ts +13 -129
- package/source/private/client_session_impl.ts +23 -30
- package/source/private/client_subscription_impl.ts +85 -207
- package/source/private/i_private_client.ts +0 -2
- package/source/private/opcua_client_impl.ts +1 -1
- package/source/private/reconnection/client_publish_engine_reconnection.ts +146 -0
- package/source/private/reconnection/client_reconnection.ts +17 -0
- package/source/private/reconnection/client_subscription_reconnection.ts +147 -0
- package/source/{reconnection.ts → private/reconnection/reconnection.ts} +120 -72
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import async from "async";
|
|
2
|
+
import assert from "node-opcua-assert";
|
|
3
|
+
import { TimestampsToReturn } from "node-opcua-data-value";
|
|
4
|
+
import { make_debugLog, checkDebugFlag } from "node-opcua-debug";
|
|
5
|
+
import { warningLog } from "node-opcua-pki";
|
|
6
|
+
import { MonitoredItemCreateRequestOptions, CreateMonitoredItemsRequest, CreateMonitoredItemsResponse } from "node-opcua-types";
|
|
7
|
+
import { ErrorCallback } from "node-opcua-status-code";
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
IBasicSessionReadAsync,
|
|
11
|
+
IBasicSessionWithSubscription,
|
|
12
|
+
createMonitoredItemsLimit,
|
|
13
|
+
readOperationLimits
|
|
14
|
+
} from "node-opcua-pseudo-session";
|
|
15
|
+
import { ClientSubscription } from "../../client_subscription";
|
|
16
|
+
import { ClientMonitoredItemImpl } from "../client_monitored_item_impl";
|
|
17
|
+
import { ClientSubscriptionImpl, TERMINATED_SUBSCRIPTION_ID, __create_subscription } from "../client_subscription_impl";
|
|
18
|
+
import { _shouldNotContinue } from "./reconnection";
|
|
19
|
+
|
|
20
|
+
const debugLog = make_debugLog("RECONNECTION");
|
|
21
|
+
const doDebug = checkDebugFlag("RECONNECTION");
|
|
22
|
+
|
|
23
|
+
function createMonitoredItemsAndRespectOperationalLimits(
|
|
24
|
+
session: IBasicSessionReadAsync & IBasicSessionWithSubscription,
|
|
25
|
+
createMonitorItemsRequest: CreateMonitoredItemsRequest,
|
|
26
|
+
callback: (err: Error | null, response?: CreateMonitoredItemsResponse) => void
|
|
27
|
+
) {
|
|
28
|
+
readOperationLimits(session)
|
|
29
|
+
.then((operationalLimits) => {
|
|
30
|
+
createMonitoredItemsLimit(operationalLimits.maxMonitoredItemsPerCall || 0, session, createMonitorItemsRequest)
|
|
31
|
+
.then((createMonitoredItemResponse) => callback(null, createMonitoredItemResponse))
|
|
32
|
+
.catch(callback);
|
|
33
|
+
})
|
|
34
|
+
.catch(callback);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* utility function to recreate new subscription
|
|
39
|
+
* @method recreateSubscriptionAndMonitoredItem
|
|
40
|
+
*/
|
|
41
|
+
export function recreateSubscriptionAndMonitoredItem(_subscription: ClientSubscription, callback: ErrorCallback): void {
|
|
42
|
+
debugLog("recreateSubscriptionAndMonitoredItem", _subscription.subscriptionId.toString());
|
|
43
|
+
|
|
44
|
+
const subscription = _subscription as ClientSubscriptionImpl;
|
|
45
|
+
if (subscription.subscriptionId === TERMINATED_SUBSCRIPTION_ID) {
|
|
46
|
+
debugLog("Subscription is not in a valid state");
|
|
47
|
+
return callback();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const oldMonitoredItems = subscription.monitoredItems;
|
|
51
|
+
const oldSubscriptionId = subscription.subscriptionId;
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
subscription.publishEngine.unregisterSubscription(oldSubscriptionId);
|
|
56
|
+
|
|
57
|
+
async.series(
|
|
58
|
+
[
|
|
59
|
+
(innerCallback: ErrorCallback) => {
|
|
60
|
+
__create_subscription(subscription, innerCallback);
|
|
61
|
+
},
|
|
62
|
+
(innerCallback: ErrorCallback) => {
|
|
63
|
+
// prettier-ignore
|
|
64
|
+
{ const _err = _shouldNotContinue(subscription.session); if (_err) { return innerCallback(_err); } }
|
|
65
|
+
|
|
66
|
+
const test = subscription.publishEngine.getSubscription(subscription.subscriptionId);
|
|
67
|
+
|
|
68
|
+
debugLog("recreating ", Object.keys(oldMonitoredItems).length, " monitored Items");
|
|
69
|
+
// re-create monitored items
|
|
70
|
+
const itemsToCreate: MonitoredItemCreateRequestOptions[] = [];
|
|
71
|
+
|
|
72
|
+
for (const monitoredItem of Object.values(oldMonitoredItems)) {
|
|
73
|
+
assert(monitoredItem.monitoringParameters.clientHandle > 0);
|
|
74
|
+
itemsToCreate.push({
|
|
75
|
+
itemToMonitor: monitoredItem.itemToMonitor,
|
|
76
|
+
monitoringMode: monitoredItem.monitoringMode,
|
|
77
|
+
requestedParameters: monitoredItem.monitoringParameters
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const createMonitorItemsRequest = new CreateMonitoredItemsRequest({
|
|
82
|
+
itemsToCreate,
|
|
83
|
+
subscriptionId: subscription.subscriptionId,
|
|
84
|
+
timestampsToReturn: TimestampsToReturn.Both // this.timestampsToReturn,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const session = subscription.session;
|
|
88
|
+
// istanbul ignore next
|
|
89
|
+
if (!session) {
|
|
90
|
+
return innerCallback(new Error("no session"));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
debugLog("Recreating ", itemsToCreate.length, " monitored items");
|
|
94
|
+
|
|
95
|
+
createMonitoredItemsAndRespectOperationalLimits(
|
|
96
|
+
session,
|
|
97
|
+
createMonitorItemsRequest,
|
|
98
|
+
(err: Error | null, response?: CreateMonitoredItemsResponse) => {
|
|
99
|
+
if (err) {
|
|
100
|
+
debugLog("Recreating monitored item has failed with ", err.message);
|
|
101
|
+
return innerCallback(err);
|
|
102
|
+
}
|
|
103
|
+
/* istanbul ignore next */
|
|
104
|
+
if (!response) {
|
|
105
|
+
return innerCallback(new Error("Internal Error"));
|
|
106
|
+
}
|
|
107
|
+
const monitoredItemResults = response.results || [];
|
|
108
|
+
|
|
109
|
+
let _errCount = 0;
|
|
110
|
+
monitoredItemResults.forEach((monitoredItemResult, index) => {
|
|
111
|
+
const itemToCreate = itemsToCreate[index];
|
|
112
|
+
/* istanbul ignore next */
|
|
113
|
+
if (!itemToCreate || !itemToCreate.requestedParameters) {
|
|
114
|
+
_errCount++;
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const clientHandle = itemToCreate.requestedParameters.clientHandle;
|
|
118
|
+
/* istanbul ignore next */
|
|
119
|
+
if (!clientHandle) {
|
|
120
|
+
_errCount++;
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const monitoredItem = subscription.monitoredItems[clientHandle] as ClientMonitoredItemImpl;
|
|
124
|
+
if (monitoredItem) {
|
|
125
|
+
monitoredItem._applyResult(monitoredItemResult);
|
|
126
|
+
} else {
|
|
127
|
+
_errCount++;
|
|
128
|
+
warningLog("cannot find monitored item for clientHandle !:", clientHandle);
|
|
129
|
+
warningLog("itemsToCreate = ", itemsToCreate[index].toString());
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
if (_errCount > 0) {
|
|
133
|
+
warningLog("Warning: some monitored items have not been recreated properly");
|
|
134
|
+
}
|
|
135
|
+
innerCallback();
|
|
136
|
+
}
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
],
|
|
140
|
+
(err) => {
|
|
141
|
+
if (err) {
|
|
142
|
+
warningLog("!!recreateSubscriptionAndMonitoredItem has failed", err.message);
|
|
143
|
+
}
|
|
144
|
+
callback(err!);
|
|
145
|
+
}
|
|
146
|
+
);
|
|
147
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
// tslint:disable:only-arrow-functions
|
|
6
|
-
import
|
|
6
|
+
import async from "async";
|
|
7
7
|
import chalk from "chalk";
|
|
8
8
|
import { assert } from "node-opcua-assert";
|
|
9
9
|
import { checkDebugFlag, make_debugLog, make_errorLog, make_warningLog } from "node-opcua-debug";
|
|
@@ -13,16 +13,37 @@ import { ErrorCallback } from "node-opcua-status-code";
|
|
|
13
13
|
import { CloseSessionRequest } from "node-opcua-types";
|
|
14
14
|
import { invalidateExtraDataTypeManager } from "node-opcua-client-dynamic-extension-object";
|
|
15
15
|
|
|
16
|
-
import { SubscriptionId } from "
|
|
17
|
-
import { ClientSessionImpl, Reconnectable } from "
|
|
18
|
-
import { ClientSubscriptionImpl } from "
|
|
19
|
-
import { IClientBase } from "
|
|
16
|
+
import { SubscriptionId } from "../../client_session";
|
|
17
|
+
import { ClientSessionImpl, Reconnectable } from "../client_session_impl";
|
|
18
|
+
import { ClientSubscriptionImpl } from "../client_subscription_impl";
|
|
19
|
+
import { IClientBase } from "../i_private_client";
|
|
20
|
+
import { republish } from "./client_publish_engine_reconnection";
|
|
21
|
+
import { recreateSubscriptionAndMonitoredItem } from "./client_subscription_reconnection";
|
|
20
22
|
|
|
21
23
|
const debugLog = make_debugLog("RECONNECTION");
|
|
22
24
|
const doDebug = checkDebugFlag("RECONNECTION");
|
|
23
25
|
const errorLog = make_errorLog("RECONNECTION");
|
|
24
26
|
const warningLog = make_warningLog("RECONNECTION");
|
|
25
27
|
|
|
28
|
+
function _shouldNotContinue3(client: IClientBase) {
|
|
29
|
+
if (!client._secureChannel) {
|
|
30
|
+
return new Error("Failure during reconnection : client or session is not usable anymore");
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function _shouldNotContinue(session: ClientSessionImpl) {
|
|
36
|
+
if (!session._client || session.hasBeenClosed() || !session._client._secureChannel || session._client.isUnusable()) {
|
|
37
|
+
return new Error("Failure during reconnection : client or session is not usable anymore");
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
export function _shouldNotContinue2(subscription: ClientSubscriptionImpl) {
|
|
42
|
+
if (!subscription.hasSession) {
|
|
43
|
+
return new Error("Failure during reconnection : client or session is not usable anymore");
|
|
44
|
+
}
|
|
45
|
+
return _shouldNotContinue(subscription.session);
|
|
46
|
+
}
|
|
26
47
|
//
|
|
27
48
|
// a new secure channel has be created, we need to reactivate the corresponding session,
|
|
28
49
|
// and reestablish the subscription and restart the publish engine.
|
|
@@ -109,29 +130,26 @@ const warningLog = make_warningLog("RECONNECTION");
|
|
|
109
130
|
// +-------------------------------+
|
|
110
131
|
|
|
111
132
|
function _ask_for_subscription_republish(session: ClientSessionImpl, callback: (err?: Error) => void) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
return callback(new Error("askForSubscriptionRepublish => canceled because session is closed"));
|
|
115
|
-
}
|
|
133
|
+
// prettier-ignore
|
|
134
|
+
{ const err = _shouldNotContinue(session); if (err) { return callback(err); } }
|
|
116
135
|
|
|
117
136
|
doDebug && debugLog(chalk.bgCyan.yellow.bold("_ask_for_subscription_republish "));
|
|
118
137
|
// assert(session.getPublishEngine().nbPendingPublishRequests === 0,
|
|
119
138
|
// "at this time, publish request queue shall still be empty");
|
|
120
139
|
|
|
121
|
-
session.getPublishEngine()
|
|
140
|
+
const engine = session.getPublishEngine();
|
|
141
|
+
republish(engine, (err?: Error) => {
|
|
122
142
|
doDebug && debugLog("_ask_for_subscription_republish : republish sent");
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
143
|
+
// prettier-ignore
|
|
144
|
+
{ const err = _shouldNotContinue(session); if (err) { return callback(err); } }
|
|
145
|
+
|
|
126
146
|
doDebug && debugLog(chalk.bgCyan.green.bold("_ask_for_subscription_republish done "), err ? err.message : "OK");
|
|
127
147
|
if (err) {
|
|
128
148
|
warningLog("republish has failed with error :", err.message);
|
|
129
|
-
|
|
130
149
|
doDebug && debugLog("_ask_for_subscription_republish has : recreating subscription");
|
|
131
150
|
return repair_client_session_by_recreating_a_new_session(session._client!, session, callback);
|
|
132
151
|
}
|
|
133
|
-
|
|
134
|
-
session.resumePublishEngine();
|
|
152
|
+
|
|
135
153
|
callback(err);
|
|
136
154
|
});
|
|
137
155
|
}
|
|
@@ -141,18 +159,16 @@ function create_session_and_repeat_if_failed(
|
|
|
141
159
|
session: ClientSessionImpl,
|
|
142
160
|
callback: CallbackT<ClientSessionImpl>
|
|
143
161
|
) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
162
|
+
// prettier-ignore
|
|
163
|
+
{ const err = _shouldNotContinue(session); if (err) { return callback(err); } }
|
|
164
|
+
|
|
148
165
|
doDebug && debugLog(chalk.bgWhite.red(" => creating a new session ...."));
|
|
149
166
|
// create new session, based on old session,
|
|
150
167
|
// so we can reuse subscriptions data
|
|
151
168
|
client.__createSession_step2(session, (err: Error | null, session1?: ClientSessionImpl) => {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
169
|
+
// prettier-ignore
|
|
170
|
+
{ const err = _shouldNotContinue(session); if (err) { return callback(err); } }
|
|
171
|
+
|
|
156
172
|
if (!err && session1) {
|
|
157
173
|
assert(session === session1, "session should have been recycled");
|
|
158
174
|
callback(err, session);
|
|
@@ -169,9 +185,9 @@ function repair_client_session_by_recreating_a_new_session(
|
|
|
169
185
|
session: ClientSessionImpl,
|
|
170
186
|
callback: (err?: Error) => void
|
|
171
187
|
) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
188
|
+
// prettier-ignore
|
|
189
|
+
{ const err = _shouldNotContinue(session); if (err) { return callback(err); } }
|
|
190
|
+
|
|
175
191
|
// As we don"t know if server has been rebooted or not,
|
|
176
192
|
// and may be upgraded in between, we have to invalidate the extra data type manager
|
|
177
193
|
invalidateExtraDataTypeManager(session);
|
|
@@ -181,13 +197,6 @@ function repair_client_session_by_recreating_a_new_session(
|
|
|
181
197
|
debugLog(" repairing client session by_recreating a new session for old session ", session.sessionId.toString());
|
|
182
198
|
}
|
|
183
199
|
|
|
184
|
-
// TO DO : it is possible that session is already closed while we get there
|
|
185
|
-
if (session.hasBeenClosed()) {
|
|
186
|
-
// istanbul ignore next
|
|
187
|
-
doDebug && debugLog(chalk.bgWhite.red("Aborting reactivation of old session because user requested session to be closed"));
|
|
188
|
-
return callback(new Error("reconnection cancelled due to session termination"));
|
|
189
|
-
}
|
|
190
|
-
|
|
191
200
|
let newSession: ClientSessionImpl;
|
|
192
201
|
|
|
193
202
|
const listenerCountBefore = session.listenerCount("");
|
|
@@ -196,27 +205,40 @@ function repair_client_session_by_recreating_a_new_session(
|
|
|
196
205
|
async.forEach(
|
|
197
206
|
subscriptionsToRecreate,
|
|
198
207
|
(subscriptionId: SubscriptionId, next: ErrorCallback) => {
|
|
208
|
+
// prettier-ignore
|
|
209
|
+
{ const err = _shouldNotContinue(session); if (err) { return next(err); } }
|
|
210
|
+
|
|
199
211
|
if (!session.getPublishEngine().hasSubscription(subscriptionId)) {
|
|
200
212
|
doDebug && debugLog(chalk.red(" => CANNOT RECREATE SUBSCRIPTION "), subscriptionId);
|
|
201
213
|
return next();
|
|
202
214
|
}
|
|
203
215
|
const subscription = session.getPublishEngine().getSubscription(subscriptionId);
|
|
204
|
-
assert(subscription.constructor.name === "ClientSubscriptionImpl");
|
|
205
216
|
doDebug && debugLog(chalk.red(" => RECREATING SUBSCRIPTION "), subscriptionId);
|
|
206
|
-
assert(subscription.session === newSession, "must have the session");
|
|
217
|
+
assert(subscription.session === newSession, "must have the new session");
|
|
218
|
+
|
|
219
|
+
recreateSubscriptionAndMonitoredItem(subscription, (err1?: Error) => {
|
|
220
|
+
// prettier-ignore
|
|
221
|
+
{ const err = _shouldNotContinue(session); if (err) { return next(err); } }
|
|
207
222
|
|
|
208
|
-
(subscription as ClientSubscriptionImpl).recreateSubscriptionAndMonitoredItem((err1?: Error) => {
|
|
209
223
|
if (err1) {
|
|
210
224
|
doDebug && debugLog("_recreateSubscription failed !" + err1.message);
|
|
211
225
|
}
|
|
212
226
|
|
|
213
227
|
doDebug &&
|
|
214
|
-
debugLog(
|
|
228
|
+
debugLog(
|
|
229
|
+
chalk.cyan(" => RECREATING SUBSCRIPTION AND MONITORED ITEM DONE subscriptionId="),
|
|
230
|
+
subscriptionId
|
|
231
|
+
);
|
|
215
232
|
|
|
216
233
|
next();
|
|
217
234
|
});
|
|
218
235
|
},
|
|
219
236
|
(err1?: Error | null) => {
|
|
237
|
+
// prettier-ignore
|
|
238
|
+
{ const err = _shouldNotContinue(session); if (err) { return innerCallback(err); } }
|
|
239
|
+
if (!err1) {
|
|
240
|
+
// prettier-ignore
|
|
241
|
+
}
|
|
220
242
|
innerCallback(err1!);
|
|
221
243
|
}
|
|
222
244
|
);
|
|
@@ -225,9 +247,9 @@ function repair_client_session_by_recreating_a_new_session(
|
|
|
225
247
|
async.series(
|
|
226
248
|
[
|
|
227
249
|
function suspend_old_session_publish_engine(innerCallback: ErrorCallback) {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
250
|
+
// prettier-ignore
|
|
251
|
+
{ const err = _shouldNotContinue(session); if (err) { return innerCallback(err); } }
|
|
252
|
+
|
|
231
253
|
// istanbul ignore next
|
|
232
254
|
doDebug && debugLog(chalk.bgWhite.red(" => suspend old session publish engine...."));
|
|
233
255
|
session.getPublishEngine().suspend(true);
|
|
@@ -236,6 +258,9 @@ function repair_client_session_by_recreating_a_new_session(
|
|
|
236
258
|
|
|
237
259
|
function create_new_session(innerCallback: ErrorCallback) {
|
|
238
260
|
create_session_and_repeat_if_failed(client, session, (err?: Error | null, _newSession?: ClientSessionImpl) => {
|
|
261
|
+
// prettier-ignore
|
|
262
|
+
{ const err = _shouldNotContinue(session); if (err) { return innerCallback(err); } }
|
|
263
|
+
|
|
239
264
|
if (_newSession) {
|
|
240
265
|
newSession = _newSession;
|
|
241
266
|
}
|
|
@@ -244,9 +269,9 @@ function repair_client_session_by_recreating_a_new_session(
|
|
|
244
269
|
},
|
|
245
270
|
|
|
246
271
|
function activate_new_session(innerCallback: ErrorCallback) {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
272
|
+
// prettier-ignore
|
|
273
|
+
{ const err = _shouldNotContinue(session); if (err) { return innerCallback(err); } }
|
|
274
|
+
|
|
250
275
|
doDebug && debugLog(chalk.bgWhite.red(" => activating a new session ...."));
|
|
251
276
|
|
|
252
277
|
client._activateSession(
|
|
@@ -285,9 +310,9 @@ function repair_client_session_by_recreating_a_new_session(
|
|
|
285
310
|
},
|
|
286
311
|
|
|
287
312
|
function attempt_subscription_transfer(innerCallback: ErrorCallback) {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
313
|
+
// prettier-ignore
|
|
314
|
+
{ const err = _shouldNotContinue(session); if (err) { return innerCallback(err); } }
|
|
315
|
+
|
|
291
316
|
// get the old subscriptions id from the old session
|
|
292
317
|
const subscriptionsIds = session.getPublishEngine().getSubscriptionIds();
|
|
293
318
|
|
|
@@ -310,8 +335,11 @@ function repair_client_session_by_recreating_a_new_session(
|
|
|
310
335
|
newSession.transferSubscriptions(
|
|
311
336
|
subscriptionsToTransfer,
|
|
312
337
|
(err: Error | null, transferSubscriptionsResponse?: TransferSubscriptionsResponse) => {
|
|
338
|
+
// may be the connection with server has been disconnected
|
|
339
|
+
// prettier-ignore
|
|
340
|
+
{ const err = _shouldNotContinue(session); if (err) { return innerCallback(err); } }
|
|
341
|
+
|
|
313
342
|
if (err || !transferSubscriptionsResponse) {
|
|
314
|
-
warningLog(chalk.bgCyan("Warning TransferSubscription has failed " + err?.message));
|
|
315
343
|
warningLog(chalk.bgCyan("May be the server is not supporting this feature"));
|
|
316
344
|
// when transfer subscription has failed, we have no other choice but
|
|
317
345
|
// recreate the subscriptions on the server side
|
|
@@ -367,9 +395,9 @@ function repair_client_session_by_recreating_a_new_session(
|
|
|
367
395
|
},
|
|
368
396
|
|
|
369
397
|
function ask_for_subscription_republish(innerCallback: ErrorCallback) {
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
398
|
+
// prettier-ignore
|
|
399
|
+
{ const err = _shouldNotContinue(session); if (err) { return innerCallback(err); } }
|
|
400
|
+
|
|
373
401
|
// assert(newSession.getPublishEngine().nbPendingPublishRequests === 0, "we should not be publishing here");
|
|
374
402
|
// call Republish
|
|
375
403
|
return _ask_for_subscription_republish(newSession, (err) => {
|
|
@@ -381,10 +409,11 @@ function repair_client_session_by_recreating_a_new_session(
|
|
|
381
409
|
},
|
|
382
410
|
|
|
383
411
|
function start_publishing_as_normal(innerCallback: ErrorCallback) {
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
412
|
+
// prettier-ignore
|
|
413
|
+
{ const err = _shouldNotContinue(session); if (err) { return innerCallback(err); } }
|
|
414
|
+
|
|
387
415
|
newSession.getPublishEngine().suspend(false);
|
|
416
|
+
|
|
388
417
|
const listenerCountAfter = session.listenerCount("");
|
|
389
418
|
assert(newSession === session);
|
|
390
419
|
doDebug && debugLog("listenerCountBefore =", listenerCountBefore, "listenerCountAfter = ", listenerCountAfter);
|
|
@@ -404,6 +433,8 @@ function _repair_client_session(client: IClientBase, session: ClientSessionImpl,
|
|
|
404
433
|
debugLog("Session repair completed with err: ", err2 ? err2.message : "<no error>", session.sessionId.toString());
|
|
405
434
|
if (!err2) {
|
|
406
435
|
session.emit("session_repaired");
|
|
436
|
+
} else {
|
|
437
|
+
session.emit("session_repaired_failed", err2);
|
|
407
438
|
}
|
|
408
439
|
callback(err2);
|
|
409
440
|
};
|
|
@@ -412,7 +443,13 @@ function _repair_client_session(client: IClientBase, session: ClientSessionImpl,
|
|
|
412
443
|
doDebug && debugLog(chalk.yellow(" TRYING TO REACTIVATE EXISTING SESSION"), session.sessionId.toString());
|
|
413
444
|
doDebug && debugLog(" SubscriptionIds :", session.getPublishEngine().getSubscriptionIds());
|
|
414
445
|
}
|
|
446
|
+
|
|
447
|
+
// prettier-ignore
|
|
448
|
+
{ const err = _shouldNotContinue(session); if (err) { return callback(err); } }
|
|
449
|
+
|
|
415
450
|
client._activateSession(session, session.userIdentityInfo!, (err: Error | null, session2?: ClientSessionImpl) => {
|
|
451
|
+
// prettier-ignore
|
|
452
|
+
{ const err = _shouldNotContinue(session); if (err) { return callback(err); } }
|
|
416
453
|
//
|
|
417
454
|
// Note: current limitation :
|
|
418
455
|
// - The reconnection doesn't work yet, if connection break is caused by a server that crashes and restarts.
|
|
@@ -435,14 +472,18 @@ export function repair_client_session(client: IClientBase, session: ClientSessio
|
|
|
435
472
|
doDebug && debugLog("Aborting reactivation of old session because user requested session to be close");
|
|
436
473
|
return callback();
|
|
437
474
|
}
|
|
438
|
-
|
|
439
475
|
doDebug && debugLog(chalk.yellow("Starting client session repair"));
|
|
440
476
|
|
|
441
477
|
const privateSession = session as any as Reconnectable;
|
|
442
478
|
privateSession._reconnecting = privateSession._reconnecting || { reconnecting: false, pendingCallbacks: [] };
|
|
443
479
|
|
|
480
|
+
if (session.hasBeenClosed()) {
|
|
481
|
+
privateSession._reconnecting.reconnecting = false;
|
|
482
|
+
doDebug && debugLog("Aborting reactivation of old session because session has been closed");
|
|
483
|
+
return callback();
|
|
484
|
+
}
|
|
444
485
|
if (privateSession._reconnecting.reconnecting) {
|
|
445
|
-
doDebug && debugLog(chalk.bgCyan("
|
|
486
|
+
doDebug && debugLog(chalk.bgCyan("Reconnection is already happening for session"), session.sessionId.toString());
|
|
446
487
|
privateSession._reconnecting.pendingCallbacks.push(callback);
|
|
447
488
|
return;
|
|
448
489
|
}
|
|
@@ -453,7 +494,13 @@ export function repair_client_session(client: IClientBase, session: ClientSessio
|
|
|
453
494
|
const transactionQueue = privateSession.pendingTransactions ? privateSession.pendingTransactions.splice(0) : [];
|
|
454
495
|
|
|
455
496
|
const repeatedAction = (callback: EmptyCallback) => {
|
|
497
|
+
// prettier-ignore
|
|
498
|
+
{ const err = _shouldNotContinue(session); if (err) { return callback(err); }}
|
|
499
|
+
|
|
456
500
|
_repair_client_session(client, session, (err) => {
|
|
501
|
+
// prettier-ignore
|
|
502
|
+
{ const err = _shouldNotContinue(session); if (err) { return callback(err); } }
|
|
503
|
+
|
|
457
504
|
if (err) {
|
|
458
505
|
errorLog(
|
|
459
506
|
chalk.red("session restoration has failed! err ="),
|
|
@@ -471,32 +518,30 @@ export function repair_client_session(client: IClientBase, session: ClientSessio
|
|
|
471
518
|
return;
|
|
472
519
|
} else {
|
|
473
520
|
errorLog(chalk.red("session restoration should be interrupted because session has been closed forcefully"));
|
|
474
|
-
// session does not need to be repaired anymore
|
|
475
|
-
callback();
|
|
476
521
|
}
|
|
522
|
+
// session does not need to be repaired anymore
|
|
523
|
+
callback();
|
|
477
524
|
return;
|
|
478
525
|
}
|
|
479
526
|
|
|
480
|
-
privateSession._reconnecting.reconnecting = false;
|
|
481
|
-
|
|
482
527
|
// istanbul ignore next
|
|
483
528
|
doDebug && debugLog(chalk.yellow("session has been restored"), session.sessionId.toString());
|
|
484
|
-
|
|
485
529
|
session.emit("session_restored");
|
|
486
|
-
const otherCallbacks = privateSession._reconnecting.pendingCallbacks;
|
|
487
|
-
privateSession._reconnecting.pendingCallbacks = [];
|
|
488
|
-
|
|
489
|
-
// re-inject element in queue
|
|
490
|
-
|
|
491
|
-
// istanbul ignore next
|
|
492
|
-
doDebug && debugLog(chalk.yellow("re-injecting transaction queue"), transactionQueue.length);
|
|
493
|
-
|
|
494
|
-
transactionQueue.forEach((e: any) => privateSession.pendingTransactions.push(e));
|
|
495
|
-
otherCallbacks.forEach((c: EmptyCallback) => c(err));
|
|
496
530
|
callback(err);
|
|
497
531
|
});
|
|
498
532
|
};
|
|
499
|
-
repeatedAction(
|
|
533
|
+
repeatedAction((err) => {
|
|
534
|
+
privateSession._reconnecting.reconnecting = false;
|
|
535
|
+
|
|
536
|
+
const otherCallbacks = privateSession._reconnecting.pendingCallbacks;
|
|
537
|
+
privateSession._reconnecting.pendingCallbacks = [];
|
|
538
|
+
// re-inject element in queue
|
|
539
|
+
// istanbul ignore next
|
|
540
|
+
doDebug && debugLog(chalk.yellow("re-injecting transaction queue"), transactionQueue.length);
|
|
541
|
+
transactionQueue.forEach((e: any) => privateSession.pendingTransactions.push(e));
|
|
542
|
+
otherCallbacks.forEach((c: EmptyCallback) => c(err));
|
|
543
|
+
callback(err);
|
|
544
|
+
});
|
|
500
545
|
}
|
|
501
546
|
|
|
502
547
|
export function repair_client_sessions(client: IClientBase, callback: (err?: Error) => void): void {
|
|
@@ -512,6 +557,9 @@ export function repair_client_sessions(client: IClientBase, callback: (err?: Err
|
|
|
512
557
|
},
|
|
513
558
|
(err, allErrors: (undefined | Error | null)[] | undefined) => {
|
|
514
559
|
err && errorLog("sessions reactivation completed with err: err ", err ? err.message : "null");
|
|
560
|
+
// prettier-ignore
|
|
561
|
+
{ const err = _shouldNotContinue3(client); if (err) { return callback(err); } }
|
|
562
|
+
|
|
515
563
|
return callback(err!);
|
|
516
564
|
}
|
|
517
565
|
);
|