node-opcua-utils 2.55.0 → 2.62.5
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/.mocharc.yml +10 -10
- package/LICENSE +20 -20
- package/dist/function_variadic.d.ts +1 -0
- package/dist/function_variadic.js +3 -0
- package/dist/function_variadic.js.map +1 -0
- package/dist/get_function_parameters_name.d.ts +2 -1
- package/dist/get_function_parameters_name.js +0 -1
- package/dist/get_function_parameters_name.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/line_file.d.ts +1 -1
- package/dist/line_file.js +3 -3
- package/dist/line_file.js.map +1 -1
- package/dist/object_classname.d.ts +1 -1
- package/dist/object_classname.js.map +1 -1
- package/dist/replace_buffer_with_hex_dump.d.ts +3 -1
- package/dist/replace_buffer_with_hex_dump.js +1 -1
- package/dist/replace_buffer_with_hex_dump.js.map +1 -1
- package/dist/set_deprecated.d.ts +2 -1
- package/dist/set_deprecated.js +2 -2
- package/dist/set_deprecated.js.map +1 -1
- package/dist/string_utils.d.ts +4 -4
- package/dist/string_utils.js +5 -5
- package/dist/string_utils.js.map +1 -1
- package/dist/timestamp.js +1 -4
- package/dist/timestamp.js.map +1 -1
- package/dist/watchdog.d.ts +1 -0
- package/dist/watchdog.js +5 -2
- package/dist/watchdog.js.map +1 -1
- package/package.json +6 -4
- package/source/buffer_ellipsis.ts +13 -13
- package/source/compare_buffers.ts +23 -23
- package/source/function_variadic.ts +1 -0
- package/source/get_clock_tick.ts +18 -18
- package/source/get_function_parameters_name.ts +15 -13
- package/source/index.ts +46 -46
- package/source/line_file.ts +24 -24
- package/source/match_uri.ts +19 -19
- package/source/object_classname.ts +11 -11
- package/source/replace_buffer_with_hex_dump.ts +15 -15
- package/source/set_deprecated.ts +29 -28
- package/source/string_utils.ts +12 -12
- package/source/timestamp.ts +11 -15
- package/source/watchdog.ts +205 -200
package/source/watchdog.ts
CHANGED
|
@@ -1,200 +1,205 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module node-opcua-utils
|
|
3
|
-
*/
|
|
4
|
-
import { EventEmitter } from "events";
|
|
5
|
-
import { assert } from "node-opcua-assert";
|
|
6
|
-
|
|
7
|
-
type ArbitraryClockTick = number; // in millisecond
|
|
8
|
-
type DurationInMillisecond = number;
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* a arbitrary clock which is system dependant and
|
|
12
|
-
* insensible to clock drifts ....
|
|
13
|
-
*
|
|
14
|
-
*/
|
|
15
|
-
function _getCurrentSystemTick(): ArbitraryClockTick {
|
|
16
|
-
if (process && process.hrtime) {
|
|
17
|
-
const h = process.hrtime();
|
|
18
|
-
const n = h[1] / 1000000;
|
|
19
|
-
assert(n <= 1000);
|
|
20
|
-
return h[0] * 1000 + n;
|
|
21
|
-
} else {
|
|
22
|
-
// fallback to Date as process.hrtime doesn't exit
|
|
23
|
-
return Date.now();
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface IWatchdogData2 {
|
|
28
|
-
key: number;
|
|
29
|
-
subscriber: ISubscriber;
|
|
30
|
-
timeout: DurationInMillisecond;
|
|
31
|
-
lastSeen: ArbitraryClockTick;
|
|
32
|
-
visitCount: number;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface ISubscriber {
|
|
36
|
-
_watchDog?: WatchDog;
|
|
37
|
-
_watchDogData?: IWatchdogData2;
|
|
38
|
-
|
|
39
|
-
watchdogReset: () => void;
|
|
40
|
-
keepAlive?: () => void;
|
|
41
|
-
onClientSeen?: () => void;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function hasExpired(watchDogData: IWatchdogData2, currentTime: ArbitraryClockTick) {
|
|
45
|
-
const elapsedTime = currentTime - watchDogData.lastSeen;
|
|
46
|
-
return elapsedTime > watchDogData.timeout;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function keepAliveFunc(this: ISubscriber) {
|
|
50
|
-
assert(this._watchDog instanceof WatchDog);
|
|
51
|
-
// istanbul ignore next
|
|
52
|
-
if (!this._watchDogData || !this._watchDog) {
|
|
53
|
-
throw new Error("Internal error");
|
|
54
|
-
}
|
|
55
|
-
assert(typeof this._watchDogData.key === "number");
|
|
56
|
-
this._watchDogData.lastSeen = this._watchDog.getCurrentSystemTick();
|
|
57
|
-
if (this.onClientSeen) {
|
|
58
|
-
this.onClientSeen();
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export class WatchDog extends EventEmitter {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
subscriber.
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
private
|
|
194
|
-
assert(this._timer
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @module node-opcua-utils
|
|
3
|
+
*/
|
|
4
|
+
import { EventEmitter } from "events";
|
|
5
|
+
import { assert } from "node-opcua-assert";
|
|
6
|
+
|
|
7
|
+
type ArbitraryClockTick = number; // in millisecond
|
|
8
|
+
type DurationInMillisecond = number;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* a arbitrary clock which is system dependant and
|
|
12
|
+
* insensible to clock drifts ....
|
|
13
|
+
*
|
|
14
|
+
*/
|
|
15
|
+
function _getCurrentSystemTick(): ArbitraryClockTick {
|
|
16
|
+
if (process && process.hrtime) {
|
|
17
|
+
const h = process.hrtime();
|
|
18
|
+
const n = h[1] / 1000000;
|
|
19
|
+
assert(n <= 1000);
|
|
20
|
+
return h[0] * 1000 + n;
|
|
21
|
+
} else {
|
|
22
|
+
// fallback to Date as process.hrtime doesn't exit
|
|
23
|
+
return Date.now();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface IWatchdogData2 {
|
|
28
|
+
key: number;
|
|
29
|
+
subscriber: ISubscriber;
|
|
30
|
+
timeout: DurationInMillisecond;
|
|
31
|
+
lastSeen: ArbitraryClockTick;
|
|
32
|
+
visitCount: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface ISubscriber {
|
|
36
|
+
_watchDog?: WatchDog;
|
|
37
|
+
_watchDogData?: IWatchdogData2;
|
|
38
|
+
|
|
39
|
+
watchdogReset: () => void;
|
|
40
|
+
keepAlive?: () => void;
|
|
41
|
+
onClientSeen?: () => void;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function hasExpired(watchDogData: IWatchdogData2, currentTime: ArbitraryClockTick) {
|
|
45
|
+
const elapsedTime = currentTime - watchDogData.lastSeen;
|
|
46
|
+
return elapsedTime > watchDogData.timeout;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function keepAliveFunc(this: ISubscriber) {
|
|
50
|
+
assert(this._watchDog instanceof WatchDog);
|
|
51
|
+
// istanbul ignore next
|
|
52
|
+
if (!this._watchDogData || !this._watchDog) {
|
|
53
|
+
throw new Error("Internal error");
|
|
54
|
+
}
|
|
55
|
+
assert(typeof this._watchDogData.key === "number");
|
|
56
|
+
this._watchDogData.lastSeen = this._watchDog.getCurrentSystemTick();
|
|
57
|
+
if (this.onClientSeen) {
|
|
58
|
+
this.onClientSeen();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export class WatchDog extends EventEmitter {
|
|
63
|
+
|
|
64
|
+
static lastSeenToDuration(lastSeen: number): number {
|
|
65
|
+
return _getCurrentSystemTick() - lastSeen;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
static emptyKeepAlive = (): void => {
|
|
69
|
+
/* */
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* returns the number of subscribers using the WatchDog object.
|
|
73
|
+
*/
|
|
74
|
+
get subscriberCount(): number {
|
|
75
|
+
return Object.keys(this._watchdogDataMap).length;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private readonly _watchdogDataMap: { [id: number]: IWatchdogData2 };
|
|
79
|
+
private _counter: number;
|
|
80
|
+
private _currentTime: ArbitraryClockTick;
|
|
81
|
+
private _timer: NodeJS.Timer | null;
|
|
82
|
+
private readonly _visitSubscriberB: (...args: any[]) => void;
|
|
83
|
+
|
|
84
|
+
constructor() {
|
|
85
|
+
super();
|
|
86
|
+
|
|
87
|
+
this._watchdogDataMap = {};
|
|
88
|
+
this._counter = 0;
|
|
89
|
+
this._currentTime = this.getCurrentSystemTick();
|
|
90
|
+
this._visitSubscriberB = this._visit_subscriber.bind(this);
|
|
91
|
+
this._timer = null; // as NodeJS.Timer;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* add a subscriber to the WatchDog.
|
|
96
|
+
* @method addSubscriber
|
|
97
|
+
*
|
|
98
|
+
* add a subscriber to the WatchDog.
|
|
99
|
+
*
|
|
100
|
+
* This method modifies the subscriber be adding a
|
|
101
|
+
* new method to it called 'keepAlive'
|
|
102
|
+
* The subscriber must also provide a "watchdogReset". watchdogReset will be called
|
|
103
|
+
* if the subscriber failed to call keepAlive withing the timeout period.
|
|
104
|
+
* @param subscriber
|
|
105
|
+
* @param timeout
|
|
106
|
+
* @return the numerical key associated with this subscriber
|
|
107
|
+
*/
|
|
108
|
+
public addSubscriber(subscriber: ISubscriber, timeout: number): number {
|
|
109
|
+
this._currentTime = this.getCurrentSystemTick();
|
|
110
|
+
timeout = timeout || 1000;
|
|
111
|
+
assert(typeof timeout === "number", " invalid timeout ");
|
|
112
|
+
assert(typeof subscriber.watchdogReset === "function", " the subscriber must provide a watchdogReset method ");
|
|
113
|
+
assert(typeof subscriber.keepAlive !== "function" || subscriber.keepAlive === WatchDog.emptyKeepAlive);
|
|
114
|
+
|
|
115
|
+
this._counter += 1;
|
|
116
|
+
const key = this._counter;
|
|
117
|
+
|
|
118
|
+
subscriber._watchDog = this;
|
|
119
|
+
subscriber._watchDogData = {
|
|
120
|
+
key,
|
|
121
|
+
lastSeen: this._currentTime,
|
|
122
|
+
subscriber,
|
|
123
|
+
timeout,
|
|
124
|
+
visitCount: 0
|
|
125
|
+
} as IWatchdogData2;
|
|
126
|
+
|
|
127
|
+
this._watchdogDataMap[key] = subscriber._watchDogData;
|
|
128
|
+
|
|
129
|
+
if (subscriber.onClientSeen) {
|
|
130
|
+
subscriber.onClientSeen();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
subscriber.keepAlive = keepAliveFunc.bind(subscriber);
|
|
134
|
+
|
|
135
|
+
// start timer when the first subscriber comes in
|
|
136
|
+
if (this.subscriberCount === 1) {
|
|
137
|
+
assert(this._timer === null);
|
|
138
|
+
this._start_timer();
|
|
139
|
+
}
|
|
140
|
+
assert(this._timer !== null);
|
|
141
|
+
return key;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
public removeSubscriber(subscriber: ISubscriber): void {
|
|
145
|
+
if (!subscriber._watchDog) {
|
|
146
|
+
return; // already removed !!!
|
|
147
|
+
}
|
|
148
|
+
if (!subscriber._watchDogData) {
|
|
149
|
+
throw new Error("Internal error");
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
assert(subscriber._watchDog instanceof WatchDog);
|
|
153
|
+
assert(typeof subscriber._watchDogData.key === "number");
|
|
154
|
+
assert(typeof subscriber.keepAlive === "function");
|
|
155
|
+
assert(Object.prototype.hasOwnProperty.call(this._watchdogDataMap, subscriber._watchDogData.key));
|
|
156
|
+
|
|
157
|
+
delete this._watchdogDataMap[subscriber._watchDogData.key];
|
|
158
|
+
delete subscriber._watchDog;
|
|
159
|
+
// leave it as it might be usefull, delete subscriber._watchDogData;
|
|
160
|
+
subscriber.keepAlive = WatchDog.emptyKeepAlive;
|
|
161
|
+
|
|
162
|
+
// delete timer when the last subscriber comes out
|
|
163
|
+
if (this.subscriberCount === 0) {
|
|
164
|
+
this._stop_timer();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
public shutdown(): void {
|
|
169
|
+
assert(this._timer === null && Object.keys(this._watchdogDataMap).length === 0, " leaking subscriber in watchdog");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
public getCurrentSystemTick(): ArbitraryClockTick {
|
|
173
|
+
return _getCurrentSystemTick();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private _visit_subscriber() {
|
|
177
|
+
this._currentTime = this.getCurrentSystemTick();
|
|
178
|
+
|
|
179
|
+
const expiredSubscribers = Object.values(this._watchdogDataMap).filter((watchDogData: IWatchdogData2) => {
|
|
180
|
+
watchDogData.visitCount += 1;
|
|
181
|
+
return hasExpired(watchDogData, this._currentTime);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
if (expiredSubscribers.length) {
|
|
185
|
+
this.emit("timeout", expiredSubscribers);
|
|
186
|
+
}
|
|
187
|
+
expiredSubscribers.forEach((watchDogData: IWatchdogData2) => {
|
|
188
|
+
this.removeSubscriber(watchDogData.subscriber);
|
|
189
|
+
watchDogData.subscriber.watchdogReset();
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
private _start_timer(): void {
|
|
194
|
+
assert(this._timer === null, " setInterval already called ?");
|
|
195
|
+
this._timer = setInterval(this._visitSubscriberB, 1000);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
private _stop_timer(): void {
|
|
199
|
+
assert(this._timer !== null, "_stop_timer already called ?");
|
|
200
|
+
if (this._timer !== null) {
|
|
201
|
+
clearInterval(this._timer);
|
|
202
|
+
this._timer = null;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|