@e-mc/watch 0.5.3 → 0.7.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/filegroup/index.js +36 -17
- package/index.js +455 -429
- package/package.json +6 -6
package/filegroup/index.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var _a, _b, _c, _d, _e;
|
|
2
|
+
var _a, _b, _c, _d, _e, _f;
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const util = require("util");
|
|
5
|
+
const ws = require("ws");
|
|
4
6
|
const types_1 = require("../../types");
|
|
5
7
|
const core_1 = require("../../core");
|
|
6
|
-
const kPaused = Symbol('paused');
|
|
7
8
|
const kServer = Symbol('server');
|
|
9
|
+
const kStarted = Symbol('started');
|
|
10
|
+
const kPaused = Symbol('paused');
|
|
8
11
|
const kAssets = Symbol('assets');
|
|
9
12
|
const kSockets = Symbol('sockets');
|
|
10
13
|
const kStartTime = Symbol('startTime');
|
|
@@ -24,21 +27,23 @@ class SocketRequest {
|
|
|
24
27
|
}
|
|
25
28
|
class FileGroup extends core_1.AbortComponent {
|
|
26
29
|
static checkTimeout(client) {
|
|
27
|
-
if (client.readyState
|
|
28
|
-
|
|
29
|
-
if (!lastTime) {
|
|
30
|
-
FileGroup.CLIENT_SESSION.set(client, Date.now());
|
|
31
|
-
}
|
|
32
|
-
else if (FileGroup.CONNECTION_TIMEOUT > 0 && lastTime + FileGroup.CONNECTION_TIMEOUT <= Date.now()) {
|
|
33
|
-
client.terminate();
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
return true;
|
|
30
|
+
if (client.readyState !== ws.OPEN) {
|
|
31
|
+
return false;
|
|
37
32
|
}
|
|
38
|
-
|
|
33
|
+
const session = this.CLIENT_SESSION;
|
|
34
|
+
const lastTime = session.get(client);
|
|
35
|
+
if (!lastTime) {
|
|
36
|
+
session.set(client, Date.now());
|
|
37
|
+
}
|
|
38
|
+
else if (lastTime + this.CONNECTION_TIMEOUT <= Date.now() && this.CONNECTION_TIMEOUT > 0) {
|
|
39
|
+
client.terminate();
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
39
43
|
}
|
|
40
44
|
static cloneAsset(file) {
|
|
41
|
-
|
|
45
|
+
const watch = file.watch;
|
|
46
|
+
return (0, types_1.cloneObject)(file, (0, types_1.isPlainObject)(watch) && (0, types_1.isArray)(watch.assets) ? new WeakSet([watch.assets]) : true);
|
|
42
47
|
}
|
|
43
48
|
constructor(uri, assets, startTime, abortable) {
|
|
44
49
|
super();
|
|
@@ -51,9 +56,10 @@ class FileGroup extends core_1.AbortComponent {
|
|
|
51
56
|
this._abortable = false;
|
|
52
57
|
this[_a] = null;
|
|
53
58
|
this[_b] = false;
|
|
54
|
-
this[_c] =
|
|
59
|
+
this[_c] = false;
|
|
55
60
|
this[_d] = '';
|
|
56
|
-
this[_e] =
|
|
61
|
+
this[_e] = '';
|
|
62
|
+
this[_f] = [];
|
|
57
63
|
this[kUri] = uri;
|
|
58
64
|
this[kAssets] = assets;
|
|
59
65
|
if (typeof startTime === 'boolean') {
|
|
@@ -94,6 +100,16 @@ class FileGroup extends core_1.AbortComponent {
|
|
|
94
100
|
if (server && (data.socketId = this.socketId)) {
|
|
95
101
|
data.event = event;
|
|
96
102
|
data.always ?? (data.always = this.always);
|
|
103
|
+
const value = data.value;
|
|
104
|
+
if (value && (util.types.isAnyArrayBuffer(value) || util.types.isArrayBufferView(value))) {
|
|
105
|
+
try {
|
|
106
|
+
data.value = Buffer.from(value).toString('base64');
|
|
107
|
+
data.encoding = 'base64';
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
delete data.value;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
97
113
|
const outgoing = JSON.stringify(data);
|
|
98
114
|
server.clients.forEach(client => {
|
|
99
115
|
if (FileGroup.checkTimeout(client)) {
|
|
@@ -126,6 +142,9 @@ class FileGroup extends core_1.AbortComponent {
|
|
|
126
142
|
get startTime() {
|
|
127
143
|
return this[kStartTime];
|
|
128
144
|
}
|
|
145
|
+
get started() {
|
|
146
|
+
return this[kStarted] || (this[kStarted] = Date.now() >= this.startTime);
|
|
147
|
+
}
|
|
129
148
|
get assets() {
|
|
130
149
|
return this[kAssets];
|
|
131
150
|
}
|
|
@@ -186,7 +205,7 @@ class FileGroup extends core_1.AbortComponent {
|
|
|
186
205
|
return this._abortable;
|
|
187
206
|
}
|
|
188
207
|
}
|
|
189
|
-
_a = kServer, _b =
|
|
208
|
+
_a = kServer, _b = kStarted, _c = kPaused, _d = kEtag, _e = kLastModified, _f = kSockets;
|
|
190
209
|
FileGroup.CONNECTION_TIMEOUT = 10 * 60000 /* TIME.m */;
|
|
191
210
|
FileGroup.CLIENT_SESSION = new Map();
|
|
192
211
|
exports.default = FileGroup;
|
package/index.js
CHANGED
|
@@ -21,11 +21,11 @@ const kTlsVersion = Symbol('tlsVersion');
|
|
|
21
21
|
const kTlsPassphrase = Symbol('tlsPassphrase');
|
|
22
22
|
const kTlsConfig = Symbol('tlsConfig');
|
|
23
23
|
const PLATFORM_WIN32 = process.platform === 'win32';
|
|
24
|
+
const HTTP_MAP = new Map();
|
|
25
|
+
const DISK_MAP = new Map();
|
|
26
|
+
const PORT_MAP = new Map();
|
|
27
|
+
const SECURE_MAP = new Map();
|
|
24
28
|
let STATE_MAP = new WeakSet();
|
|
25
|
-
let HTTP_MAP = {};
|
|
26
|
-
let DISK_MAP = {};
|
|
27
|
-
let PORT_MAP = {};
|
|
28
|
-
let SECURE_MAP = {};
|
|
29
29
|
function isConnectionTimeout(err) {
|
|
30
30
|
switch (err instanceof Error && err.code) {
|
|
31
31
|
case 'ETIMEDOUT':
|
|
@@ -37,12 +37,39 @@ function isConnectionTimeout(err) {
|
|
|
37
37
|
}
|
|
38
38
|
function abortTimeout(group) {
|
|
39
39
|
group.timeout.aborted = true;
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
const watcher = group.watcher;
|
|
41
|
+
if (watcher) {
|
|
42
|
+
watcher.close();
|
|
42
43
|
group.watcher = null;
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
|
-
|
|
46
|
+
function getInterval({ watch }) {
|
|
47
|
+
let interval;
|
|
48
|
+
if ((0, types_1.isObject)(watch) && (interval = watch.interval)) {
|
|
49
|
+
if (typeof interval === 'string') {
|
|
50
|
+
interval = (0, types_1.parseTime)(interval);
|
|
51
|
+
}
|
|
52
|
+
if (interval > 0) {
|
|
53
|
+
return interval;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return 0;
|
|
57
|
+
}
|
|
58
|
+
function closeFileGroup(map) {
|
|
59
|
+
for (const item of map.values()) {
|
|
60
|
+
for (const group of item.values()) {
|
|
61
|
+
abortTimeout(group);
|
|
62
|
+
}
|
|
63
|
+
item.clear();
|
|
64
|
+
}
|
|
65
|
+
map.clear();
|
|
66
|
+
}
|
|
67
|
+
function closeServer(map) {
|
|
68
|
+
for (const [port, value] of map) {
|
|
69
|
+
value.close(err => err && Watch.writeFail([`Unable to shutdown ${map === PORT_MAP ? 'WS' : 'WSS'} server`, 'port: ' + port], err));
|
|
70
|
+
}
|
|
71
|
+
map.clear();
|
|
72
|
+
}
|
|
46
73
|
const formatDate = (value) => new Date(value).toLocaleString().replace(/\/20\d+, /, '@').replace(/:\d+ (AM|PM)$/, (...match) => match[1]);
|
|
47
74
|
class Watch extends core_1.Client {
|
|
48
75
|
static createServer(port, secure, active) {
|
|
@@ -53,7 +80,7 @@ class Watch extends core_1.Client {
|
|
|
53
80
|
let wss;
|
|
54
81
|
try {
|
|
55
82
|
if ((0, types_1.isPlainObject)(secure)) {
|
|
56
|
-
if (wss = SECURE_MAP
|
|
83
|
+
if (wss = SECURE_MAP.get(port.toString())) {
|
|
57
84
|
return wss;
|
|
58
85
|
}
|
|
59
86
|
const { ca, passphrase, version, config } = secure;
|
|
@@ -68,7 +95,7 @@ class Watch extends core_1.Client {
|
|
|
68
95
|
});
|
|
69
96
|
server.listen(port);
|
|
70
97
|
wss = new ws.Server({ server });
|
|
71
|
-
SECURE_MAP
|
|
98
|
+
SECURE_MAP.set(port.toString(), wss);
|
|
72
99
|
if (active) {
|
|
73
100
|
STATE_MAP.add(wss);
|
|
74
101
|
}
|
|
@@ -77,12 +104,12 @@ class Watch extends core_1.Client {
|
|
|
77
104
|
this.writeFail('TLS/SSL key and cert not found', (0, types_1.errorMessage)('ws', 'Missing TLS/SSL credentials'));
|
|
78
105
|
}
|
|
79
106
|
}
|
|
80
|
-
else if (wss = PORT_MAP
|
|
107
|
+
else if (wss = PORT_MAP.get(port.toString())) {
|
|
81
108
|
return wss;
|
|
82
109
|
}
|
|
83
110
|
else {
|
|
84
111
|
wss = new ws.Server({ port });
|
|
85
|
-
PORT_MAP
|
|
112
|
+
PORT_MAP.set(port.toString(), wss);
|
|
86
113
|
if (active) {
|
|
87
114
|
STATE_MAP.add(wss);
|
|
88
115
|
}
|
|
@@ -91,44 +118,33 @@ class Watch extends core_1.Client {
|
|
|
91
118
|
catch (err) {
|
|
92
119
|
this.writeFail("Unknown" /* ERR_MESSAGE.UNKNOWN */, err);
|
|
93
120
|
}
|
|
94
|
-
if (wss) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
filegroup_1.default.CLIENT_SESSION.delete(this);
|
|
101
|
-
});
|
|
102
|
-
this.clients.forEach(client => filegroup_1.default.checkTimeout(client));
|
|
103
|
-
});
|
|
104
|
-
wss.on('error', function (err) {
|
|
105
|
-
const data = JSON.stringify({ event: types_1.WATCH_EVENT.ERROR, errors: [err.message] });
|
|
106
|
-
this.clients.forEach(client => filegroup_1.default.checkTimeout(client) && client.send(data));
|
|
121
|
+
if (!wss) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
wss.on('connection', function (socket) {
|
|
125
|
+
socket.on('message', function () {
|
|
126
|
+
filegroup_1.default.CLIENT_SESSION.delete(this);
|
|
107
127
|
});
|
|
108
|
-
|
|
109
|
-
|
|
128
|
+
socket.on('close', function () {
|
|
129
|
+
filegroup_1.default.CLIENT_SESSION.delete(this);
|
|
110
130
|
});
|
|
111
|
-
|
|
112
|
-
}
|
|
131
|
+
this.clients.forEach(client => filegroup_1.default.checkTimeout(client));
|
|
132
|
+
});
|
|
133
|
+
wss.on('error', function (err) {
|
|
134
|
+
const data = JSON.stringify({ event: types_1.WATCH_EVENT.ERROR, errors: [err.message] });
|
|
135
|
+
this.clients.forEach(client => filegroup_1.default.checkTimeout(client) && client.send(data));
|
|
136
|
+
});
|
|
137
|
+
wss.on('close', function () {
|
|
138
|
+
this.clients.forEach(client => client.terminate());
|
|
139
|
+
});
|
|
140
|
+
return wss;
|
|
113
141
|
}
|
|
114
142
|
static shutdown() {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
for (const item of [PORT_MAP, SECURE_MAP]) {
|
|
123
|
-
for (const port in item) {
|
|
124
|
-
item[port].close(err => err && this.writeFail([`Unable to shutdown ${item === PORT_MAP ? 'WS' : 'WSS'} server`, 'port: ' + port], err));
|
|
125
|
-
}
|
|
126
|
-
}
|
|
143
|
+
closeFileGroup(HTTP_MAP);
|
|
144
|
+
closeFileGroup(DISK_MAP);
|
|
145
|
+
closeServer(PORT_MAP);
|
|
146
|
+
closeServer(SECURE_MAP);
|
|
127
147
|
filegroup_1.default.CLIENT_SESSION.clear();
|
|
128
|
-
HTTP_MAP = {};
|
|
129
|
-
DISK_MAP = {};
|
|
130
|
-
PORT_MAP = {};
|
|
131
|
-
SECURE_MAP = {};
|
|
132
148
|
STATE_MAP = new WeakSet();
|
|
133
149
|
}
|
|
134
150
|
static checkTimeout(client) {
|
|
@@ -158,7 +174,7 @@ class Watch extends core_1.Client {
|
|
|
158
174
|
let interval;
|
|
159
175
|
if ((0, types_1.isPlainObject)(data)) {
|
|
160
176
|
let secure;
|
|
161
|
-
({ interval, port, secure } = data);
|
|
177
|
+
({ interval, port, secure, extensions } = data);
|
|
162
178
|
if (secure) {
|
|
163
179
|
securePort = secure.port;
|
|
164
180
|
if (secure.cert && secure.key) {
|
|
@@ -169,7 +185,7 @@ class Watch extends core_1.Client {
|
|
|
169
185
|
this.interval = (0, util_1.asInt)(interval);
|
|
170
186
|
this.port = (0, util_1.asInt)(port);
|
|
171
187
|
this.securePort = (0, util_1.asInt)(securePort);
|
|
172
|
-
if (
|
|
188
|
+
if (Array.isArray(extensions)) {
|
|
173
189
|
this.module.extensions = extensions;
|
|
174
190
|
}
|
|
175
191
|
}
|
|
@@ -181,7 +197,6 @@ class Watch extends core_1.Client {
|
|
|
181
197
|
if (permission) {
|
|
182
198
|
this.permission = permission;
|
|
183
199
|
}
|
|
184
|
-
const startTime = Date.now();
|
|
185
200
|
const username = this.host?.username;
|
|
186
201
|
const destMap = Object.create(null);
|
|
187
202
|
for (const item of assets) {
|
|
@@ -214,8 +229,8 @@ class Watch extends core_1.Client {
|
|
|
214
229
|
const related = [];
|
|
215
230
|
for (let i = 0, length = items.length; i < length; ++i) {
|
|
216
231
|
const watch = items[i].watch;
|
|
217
|
-
if ((0, types_1.isObject)(watch)
|
|
218
|
-
watch.assets
|
|
232
|
+
if ((0, types_1.isObject)(watch)) {
|
|
233
|
+
watch.assets?.forEach(other => {
|
|
219
234
|
if (items.includes(other)) {
|
|
220
235
|
return;
|
|
221
236
|
}
|
|
@@ -236,391 +251,401 @@ class Watch extends core_1.Client {
|
|
|
236
251
|
}
|
|
237
252
|
for (const item of items) {
|
|
238
253
|
let { watch, sourceFiles } = item;
|
|
239
|
-
if (watch) {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
return
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
}
|
|
266
|
-
if (!watch && localUri && !(watch = settings[localUri])) {
|
|
267
|
-
for (const pattern in settings) {
|
|
268
|
-
if ((0, types_1.hasGlob)(pattern) && pm.isMatch(localUri, pattern, { nocase: PLATFORM_WIN32 }) && (watch = settings[pattern])) {
|
|
269
|
-
break;
|
|
270
|
-
}
|
|
254
|
+
if (!watch) {
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
const fatalError = (map, target, err) => {
|
|
258
|
+
const uri = target.value.uri;
|
|
259
|
+
map.delete(uri);
|
|
260
|
+
abortTimeout(target);
|
|
261
|
+
this.writeFail(["Unable to watch file" /* ERR_MESSAGE.WATCH_FILE */, uri], err, 16 /* LOG_TYPE.WATCH */);
|
|
262
|
+
};
|
|
263
|
+
const watchExpired = (map, target, message = 'Expired') => {
|
|
264
|
+
this.formatMessage(16 /* LOG_TYPE.WATCH */, 'WATCH', [message, target.startTime ? 'since ' + formatDate(target.startTime) : ''], target.uri, { titleColor: 'grey' });
|
|
265
|
+
const data = map.get(target.uri);
|
|
266
|
+
if (!data?.size) {
|
|
267
|
+
map.delete(target.uri);
|
|
268
|
+
return true;
|
|
269
|
+
}
|
|
270
|
+
return false;
|
|
271
|
+
};
|
|
272
|
+
let expires = 0, status = 0, wss = null, main, id, socketId, port, secure, hot, always, watched, message, settings;
|
|
273
|
+
if (watch === true && username && (settings = this.settings.users?.[username])) {
|
|
274
|
+
const { uri, localUri, mimeType } = item;
|
|
275
|
+
watch = false;
|
|
276
|
+
if (uri && !(watch = settings[uri])) {
|
|
277
|
+
for (const pattern in settings) {
|
|
278
|
+
if ((0, types_1.hasGlob)(pattern) && pm.isMatch(uri, pattern, { matchBase: true }) && (watch = settings[pattern])) {
|
|
279
|
+
break;
|
|
271
280
|
}
|
|
272
281
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
282
|
+
}
|
|
283
|
+
if (!watch && localUri && !(watch = settings[localUri])) {
|
|
284
|
+
for (const pattern in settings) {
|
|
285
|
+
if ((0, types_1.hasGlob)(pattern) && pm.isMatch(localUri, pattern, { nocase: PLATFORM_WIN32 }) && (watch = settings[pattern])) {
|
|
286
|
+
break;
|
|
278
287
|
}
|
|
279
288
|
}
|
|
280
289
|
}
|
|
281
|
-
if (
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
main = item;
|
|
286
|
-
}
|
|
287
|
-
if (watch.expires) {
|
|
288
|
-
expires = (0, types_1.parseExpires)(watch.expires, startTime);
|
|
289
|
-
}
|
|
290
|
-
if (reload && (socketId = reload.socketId)) {
|
|
291
|
-
({ port, module: hot, always } = reload);
|
|
292
|
-
if (reload.secure) {
|
|
293
|
-
const key = this[kTlsKey];
|
|
294
|
-
const cert = this[kTlsCert];
|
|
295
|
-
if (key && cert) {
|
|
296
|
-
wss = Watch.createServer(port || (port = this.securePort), { ca: this[kCa], key, cert, passphrase: this[kTlsPassphrase], version: this[kTlsVersion], config: this[kTlsConfig] });
|
|
297
|
-
}
|
|
298
|
-
secure = true;
|
|
299
|
-
}
|
|
300
|
-
else {
|
|
301
|
-
wss = Watch.createServer(port || (port = this.port));
|
|
302
|
-
}
|
|
303
|
-
if (!wss) {
|
|
304
|
-
this.writeFail('Unable to create WebSocket server', (0, types_1.errorMessage)(secure ? 'wss' : 'ws', "Invalid parameters" /* ERR_MESSAGE.PARAMETERS */, 'port: ' + (port || "Unknown" /* ERR_MESSAGE.UNKNOWN */)), 16 /* LOG_TYPE.WATCH */);
|
|
305
|
-
socketId = undefined;
|
|
306
|
-
port = undefined;
|
|
307
|
-
secure = undefined;
|
|
308
|
-
hot = undefined;
|
|
309
|
-
always = undefined;
|
|
290
|
+
if (!watch && mimeType && !(watch = settings[mimeType])) {
|
|
291
|
+
for (const pattern in settings) {
|
|
292
|
+
if (/^[^*/]+\/\*+$/.test(pattern) && pm.isMatch(mimeType, pattern) && (watch = settings[pattern])) {
|
|
293
|
+
break;
|
|
310
294
|
}
|
|
311
295
|
}
|
|
312
|
-
item.watch = watch;
|
|
313
296
|
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
if (
|
|
325
|
-
|
|
326
|
-
}
|
|
327
|
-
if (item.document) {
|
|
328
|
-
group.document = item.document;
|
|
297
|
+
}
|
|
298
|
+
let startTime = Date.now();
|
|
299
|
+
if ((0, types_1.isPlainObject)(watch)) {
|
|
300
|
+
const { start, expires: expired, reload } = watch;
|
|
301
|
+
id = watch.id;
|
|
302
|
+
if (watch.main) {
|
|
303
|
+
main = item;
|
|
304
|
+
}
|
|
305
|
+
if (start) {
|
|
306
|
+
const offset = (0, types_1.parseTime)(start);
|
|
307
|
+
if (offset > 0) {
|
|
308
|
+
startTime += offset;
|
|
329
309
|
}
|
|
330
|
-
|
|
331
|
-
|
|
310
|
+
}
|
|
311
|
+
if (expired) {
|
|
312
|
+
expires = (0, types_1.parseExpires)(expired, startTime);
|
|
313
|
+
}
|
|
314
|
+
if (reload && (socketId = reload.socketId)) {
|
|
315
|
+
({ port, module: hot, always } = reload);
|
|
316
|
+
if (reload.secure) {
|
|
317
|
+
const key = this[kTlsKey];
|
|
318
|
+
const cert = this[kTlsCert];
|
|
319
|
+
if (key && cert) {
|
|
320
|
+
wss = Watch.createServer(port || (port = this.securePort), { ca: this[kCa], key, cert, passphrase: this[kTlsPassphrase], version: this[kTlsVersion], config: this[kTlsConfig] });
|
|
321
|
+
}
|
|
322
|
+
secure = true;
|
|
332
323
|
}
|
|
333
|
-
|
|
334
|
-
|
|
324
|
+
else {
|
|
325
|
+
wss = Watch.createServer(port || (port = this.port));
|
|
335
326
|
}
|
|
336
|
-
if (
|
|
337
|
-
|
|
327
|
+
if (!wss) {
|
|
328
|
+
this.writeFail('Unable to create WebSocket server', (0, types_1.errorMessage)(secure ? 'wss' : 'ws', "Invalid parameters" /* ERR_MESSAGE.PARAMETERS */, 'port: ' + (port || "Unknown" /* ERR_MESSAGE.UNKNOWN */)), 16 /* LOG_TYPE.WATCH */);
|
|
329
|
+
socketId = undefined;
|
|
330
|
+
port = undefined;
|
|
331
|
+
secure = undefined;
|
|
332
|
+
hot = undefined;
|
|
333
|
+
always = undefined;
|
|
338
334
|
}
|
|
339
|
-
|
|
340
|
-
|
|
335
|
+
}
|
|
336
|
+
item.watch = watch;
|
|
337
|
+
}
|
|
338
|
+
const interval = getInterval(item) || watchInterval || this.interval;
|
|
339
|
+
const watching = (uri, esm) => {
|
|
340
|
+
const group = new filegroup_1.default(uri, main ? assets : items, startTime, this.willAbort("(watch)" /* ABORT_NAME.WATCH */));
|
|
341
|
+
group.add(expires, socketId, id);
|
|
342
|
+
if (main) {
|
|
343
|
+
group.main = main;
|
|
344
|
+
}
|
|
345
|
+
else if (related.length) {
|
|
346
|
+
group.related = related;
|
|
347
|
+
}
|
|
348
|
+
if (bundleMain) {
|
|
349
|
+
group.bundleMain = bundleMain;
|
|
350
|
+
}
|
|
351
|
+
if (item.document) {
|
|
352
|
+
group.document = item.document;
|
|
353
|
+
}
|
|
354
|
+
if (hot) {
|
|
355
|
+
group.hot = true;
|
|
356
|
+
}
|
|
357
|
+
if (always) {
|
|
358
|
+
group.always = true;
|
|
359
|
+
}
|
|
360
|
+
if (sourceFiles) {
|
|
361
|
+
group.sourceFiles = sourceFiles.filter(file => file !== uri);
|
|
362
|
+
}
|
|
363
|
+
if (wss) {
|
|
364
|
+
group.connection(wss, port, secure);
|
|
365
|
+
}
|
|
366
|
+
const timeout = { interval, retries: 0, aborted: false };
|
|
367
|
+
const target = { value: group, timeout, watcher: null };
|
|
368
|
+
const isMap = (value) => value ? value.size > 0 : false;
|
|
369
|
+
const checkAborted = (result, current) => result?.aborted && current.abortable && current.abort();
|
|
370
|
+
const checkPreceding = (map) => {
|
|
371
|
+
const data = map.get(uri);
|
|
372
|
+
if (!data) {
|
|
373
|
+
return;
|
|
341
374
|
}
|
|
342
|
-
const
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
if (current && !current.expired) {
|
|
353
|
-
let reset;
|
|
354
|
-
if (id) {
|
|
355
|
-
const sockets = current.sockets;
|
|
356
|
-
for (let i = 0, active; i < sockets.length; ++i) {
|
|
357
|
-
const socket = sockets[i];
|
|
358
|
-
if (socket.id === id) {
|
|
359
|
-
if (active) {
|
|
360
|
-
sockets.splice(i, 1);
|
|
361
|
-
}
|
|
362
|
-
else {
|
|
363
|
-
reset = true;
|
|
364
|
-
}
|
|
365
|
-
break;
|
|
375
|
+
const current = data.get(dest)?.value;
|
|
376
|
+
if (current && !current.expired) {
|
|
377
|
+
let reset;
|
|
378
|
+
if (id) {
|
|
379
|
+
const sockets = current.sockets;
|
|
380
|
+
for (let i = 0, active; i < sockets.length; ++i) {
|
|
381
|
+
const socket = sockets[i];
|
|
382
|
+
if (socket.id === id) {
|
|
383
|
+
if (active) {
|
|
384
|
+
sockets.splice(i, 1);
|
|
366
385
|
}
|
|
367
|
-
|
|
368
|
-
|
|
386
|
+
else {
|
|
387
|
+
reset = true;
|
|
369
388
|
}
|
|
389
|
+
break;
|
|
390
|
+
}
|
|
391
|
+
if (!socket.expired) {
|
|
392
|
+
active = true;
|
|
370
393
|
}
|
|
371
394
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
wss.close();
|
|
395
|
+
}
|
|
396
|
+
if (!reset) {
|
|
397
|
+
if (wss) {
|
|
398
|
+
const server = current.server;
|
|
399
|
+
if (!server) {
|
|
400
|
+
current.connection(wss, port, secure);
|
|
401
|
+
}
|
|
402
|
+
else if (server !== wss) {
|
|
403
|
+
if (wss.clients.size === 0 && !STATE_MAP.has(wss)) {
|
|
404
|
+
if (secure) {
|
|
405
|
+
SECURE_MAP.delete(port.toString());
|
|
406
|
+
}
|
|
407
|
+
else {
|
|
408
|
+
PORT_MAP.delete(port.toString());
|
|
387
409
|
}
|
|
388
|
-
|
|
389
|
-
return 3 /* ERR.SERVER */;
|
|
410
|
+
wss.close();
|
|
390
411
|
}
|
|
412
|
+
message = 'Destination already watched @ ' + (current.secure ? 'wss' : 'ws') + '://hostname:' + current.port;
|
|
413
|
+
return 3 /* ERR.SERVER */;
|
|
391
414
|
}
|
|
392
|
-
const socket = socketId && current.find(socketId);
|
|
393
|
-
if (socket) {
|
|
394
|
-
socket.expires = expires;
|
|
395
|
-
}
|
|
396
|
-
else {
|
|
397
|
-
current.add(expires, socketId, id);
|
|
398
|
-
}
|
|
399
|
-
return 0 /* ERR.NONE */;
|
|
400
415
|
}
|
|
416
|
+
const socket = socketId && current.find(socketId);
|
|
417
|
+
if (socket) {
|
|
418
|
+
socket.expires = expires;
|
|
419
|
+
}
|
|
420
|
+
else {
|
|
421
|
+
current.add(expires, socketId, id);
|
|
422
|
+
}
|
|
423
|
+
return 0 /* ERR.NONE */;
|
|
401
424
|
}
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
425
|
+
}
|
|
426
|
+
data.set(dest, target);
|
|
427
|
+
return 0 /* ERR.NONE */;
|
|
428
|
+
};
|
|
429
|
+
if (core_1.Client.isFile(uri, 'http/s')) {
|
|
430
|
+
group.url = item.url;
|
|
431
|
+
group.etag = item.etag;
|
|
432
|
+
group.lastModified = item.lastModified;
|
|
433
|
+
if (!group.etag && !group.lastModified) {
|
|
434
|
+
return 1 /* ERR.ETAG */;
|
|
435
|
+
}
|
|
436
|
+
if ((status = checkPreceding(HTTP_MAP)) !== undefined) {
|
|
437
|
+
return status;
|
|
438
|
+
}
|
|
439
|
+
const url = group.url || (group.url = new URL(uri));
|
|
440
|
+
const request = this.host?.Request || new request_1.default();
|
|
441
|
+
const agentTimeout = Math.max(timeout.interval * 10, this.connectTimeout);
|
|
442
|
+
const opts = request.opts(url, { method: 'HEAD', httpVersion: 1, timeout: agentTimeout, agentTimeout });
|
|
443
|
+
(function recurse() {
|
|
444
|
+
let client = null;
|
|
445
|
+
new Promise((resolve, reject) => {
|
|
446
|
+
client = request.open(uri, opts)
|
|
447
|
+
.on('response', res => {
|
|
448
|
+
if (group.aborted) {
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
if (this.aborted) {
|
|
452
|
+
reject((0, types_1.createAbortError)());
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
const statusCode = res.statusCode;
|
|
456
|
+
const valid = statusCode >= 200 /* HTTP_STATUS.OK */ && statusCode < 300 /* HTTP_STATUS.MULTIPLE_CHOICES */;
|
|
457
|
+
const map = HTTP_MAP.get(uri);
|
|
458
|
+
const etag = res.headers.etag;
|
|
459
|
+
const lastModified = res.headers['last-modified'];
|
|
460
|
+
if (valid && map?.size && (etag || lastModified)) {
|
|
461
|
+
for (const [destUrl, input] of map) {
|
|
462
|
+
const value = input.value;
|
|
463
|
+
if (value.paused) {
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
let aborted = value.aborted;
|
|
467
|
+
if (!aborted) {
|
|
468
|
+
if (value.expired) {
|
|
469
|
+
aborted = true;
|
|
441
470
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
else if (value.etag) {
|
|
448
|
-
if (etag) {
|
|
449
|
-
if (etag !== value.etag) {
|
|
450
|
-
value.etag = etag;
|
|
471
|
+
else if (value.etag) {
|
|
472
|
+
if (etag) {
|
|
473
|
+
if (etag !== value.etag) {
|
|
474
|
+
value.etag = etag;
|
|
475
|
+
if (value.started) {
|
|
451
476
|
this.modified(value).then(result => checkAborted(result, value));
|
|
452
477
|
}
|
|
453
478
|
}
|
|
454
479
|
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
480
|
+
}
|
|
481
|
+
else if (value.lastModified && lastModified) {
|
|
482
|
+
if (lastModified !== value.lastModified) {
|
|
483
|
+
value.lastModified = lastModified;
|
|
484
|
+
if (value.started) {
|
|
458
485
|
this.modified(value).then(result => checkAborted(result, value));
|
|
459
486
|
}
|
|
460
487
|
}
|
|
461
488
|
}
|
|
462
|
-
if (aborted) {
|
|
463
|
-
map.delete(destUrl);
|
|
464
|
-
if (watchExpired(HTTP_MAP, value)) {
|
|
465
|
-
abortTimeout(target);
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
489
|
}
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
490
|
+
if (aborted) {
|
|
491
|
+
map.delete(destUrl);
|
|
492
|
+
if (watchExpired(HTTP_MAP, value)) {
|
|
493
|
+
abortTimeout(target);
|
|
494
|
+
}
|
|
474
495
|
}
|
|
475
|
-
watchExpired(HTTP_MAP, group);
|
|
476
|
-
abortTimeout(target);
|
|
477
|
-
}
|
|
478
|
-
if (client) {
|
|
479
|
-
client.destroy();
|
|
480
496
|
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
.on('error', err => {
|
|
484
|
-
if (!timeout.aborted && !(isConnectionTimeout(err) && ++timeout.retries <= 10 /* HTTP.TIMEOUT_LIMIT */)) {
|
|
485
|
-
reject(err);
|
|
486
|
-
return;
|
|
487
|
-
}
|
|
488
|
-
resolve();
|
|
489
|
-
})
|
|
490
|
-
.on('timeout', () => {
|
|
491
|
-
if (!timeout.aborted && ++timeout.retries > 10 /* HTTP.TIMEOUT_LIMIT */) {
|
|
492
|
-
reject((0, types_1.errorMessage)(408 /* HTTP_STATUS.REQUEST_TIMEOUT */, 'HTTP request timeout'));
|
|
493
|
-
return;
|
|
494
|
-
}
|
|
495
|
-
resolve();
|
|
496
|
-
});
|
|
497
|
-
})
|
|
498
|
-
.then(() => {
|
|
499
|
-
if (!timeout.aborted) {
|
|
500
|
-
const map = HTTP_MAP[uri];
|
|
497
|
+
}
|
|
498
|
+
else {
|
|
501
499
|
if (isMap(map)) {
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
ms = Math.min(session.timeout.interval, ms);
|
|
505
|
-
}
|
|
506
|
-
setTimeout(recurse.bind(this), timeout.interval = ms);
|
|
507
|
-
}
|
|
508
|
-
else {
|
|
509
|
-
delete HTTP_MAP[uri];
|
|
500
|
+
reject(valid ? (0, types_1.errorValue)('ETag not supported', uri) : (0, types_1.errorMessage)(statusCode, 'Invalid HTTP request', uri));
|
|
501
|
+
return;
|
|
510
502
|
}
|
|
503
|
+
watchExpired(HTTP_MAP, group);
|
|
504
|
+
abortTimeout(target);
|
|
511
505
|
}
|
|
512
|
-
})
|
|
513
|
-
.catch(err => {
|
|
514
|
-
fatalError(HTTP_MAP, target, err);
|
|
515
506
|
if (client) {
|
|
516
507
|
client.destroy();
|
|
517
508
|
}
|
|
509
|
+
resolve();
|
|
510
|
+
})
|
|
511
|
+
.on('error', err => {
|
|
512
|
+
if (!timeout.aborted && !(isConnectionTimeout(err) && ++timeout.retries <= 10 /* HTTP.TIMEOUT_LIMIT */)) {
|
|
513
|
+
reject(err);
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
resolve();
|
|
517
|
+
})
|
|
518
|
+
.on('timeout', () => {
|
|
519
|
+
if (!timeout.aborted && ++timeout.retries > 10 /* HTTP.TIMEOUT_LIMIT */) {
|
|
520
|
+
reject((0, types_1.errorMessage)(408 /* HTTP_STATUS.REQUEST_TIMEOUT */, 'HTTP request timeout'));
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
resolve();
|
|
518
524
|
});
|
|
519
|
-
})
|
|
520
|
-
|
|
525
|
+
})
|
|
526
|
+
.then(() => {
|
|
527
|
+
if (!timeout.aborted) {
|
|
528
|
+
const map = HTTP_MAP.get(uri);
|
|
529
|
+
if (isMap(map)) {
|
|
530
|
+
let ms = Watch.MAX_TIMEOUT;
|
|
531
|
+
for (const session of map.values()) {
|
|
532
|
+
ms = Math.min(session.timeout.interval, ms);
|
|
533
|
+
}
|
|
534
|
+
setTimeout(recurse.bind(this), timeout.interval = ms);
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
HTTP_MAP.delete(uri);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
})
|
|
541
|
+
.catch(err => {
|
|
542
|
+
fatalError(HTTP_MAP, target, err);
|
|
543
|
+
client?.destroy();
|
|
544
|
+
});
|
|
545
|
+
}).call(this);
|
|
546
|
+
HTTP_MAP.set(uri, new Map([[dest, target]]));
|
|
547
|
+
}
|
|
548
|
+
else if (esm || path.isAbsolute(uri = core_1.Client.resolveFile(uri)) && this.canRead(uri, { hostPermissionOnly: !!this.host })) {
|
|
549
|
+
if ((status = checkPreceding(DISK_MAP)) !== undefined) {
|
|
550
|
+
return status;
|
|
521
551
|
}
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
552
|
+
let ptime = 0;
|
|
553
|
+
target.watcher = fs.watch(uri, (event, filename) => {
|
|
554
|
+
if (this.aborted || group.aborted) {
|
|
555
|
+
fatalError(DISK_MAP, target, (0, types_1.createAbortError)());
|
|
556
|
+
return;
|
|
525
557
|
}
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
for (const [key, input] of map) {
|
|
540
|
-
const value = input.value;
|
|
541
|
-
if (value.expired) {
|
|
542
|
-
map.delete(key);
|
|
543
|
-
if (watchExpired(DISK_MAP, value)) {
|
|
544
|
-
abortTimeout(target);
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
else if (value.aborted) {
|
|
548
|
-
map.delete(key);
|
|
549
|
-
if (map.size === 0) {
|
|
550
|
-
abortTimeout(target);
|
|
551
|
-
}
|
|
558
|
+
const map = DISK_MAP.get(uri);
|
|
559
|
+
switch (event) {
|
|
560
|
+
case 'change': {
|
|
561
|
+
if (isMap(map)) {
|
|
562
|
+
try {
|
|
563
|
+
const mtime = Math.floor(fs.statSync(uri).mtimeMs);
|
|
564
|
+
if (mtime > ptime) {
|
|
565
|
+
for (const [key, input] of map) {
|
|
566
|
+
const value = input.value;
|
|
567
|
+
if (value.expired) {
|
|
568
|
+
map.delete(key);
|
|
569
|
+
if (watchExpired(DISK_MAP, value)) {
|
|
570
|
+
abortTimeout(target);
|
|
552
571
|
}
|
|
553
|
-
|
|
554
|
-
|
|
572
|
+
}
|
|
573
|
+
else if (value.aborted) {
|
|
574
|
+
map.delete(key);
|
|
575
|
+
if (map.size === 0) {
|
|
576
|
+
abortTimeout(target);
|
|
555
577
|
}
|
|
556
578
|
}
|
|
557
|
-
|
|
579
|
+
else if (value.started) {
|
|
580
|
+
this.modified(value).then(result => checkAborted(result, value));
|
|
581
|
+
}
|
|
558
582
|
}
|
|
559
|
-
|
|
560
|
-
}
|
|
561
|
-
catch (err) {
|
|
562
|
-
this.writeFail(["Unable to read file" /* ERR_MESSAGE.READ_FILE */, path.basename(uri)], err, { type: 32 /* LOG_TYPE.FILE */, fatal: false });
|
|
583
|
+
ptime = mtime + types_1.THRESHOLD.WATCH_CHANGE;
|
|
563
584
|
}
|
|
585
|
+
break;
|
|
564
586
|
}
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
if (map) {
|
|
568
|
-
map.clear();
|
|
587
|
+
catch (err) {
|
|
588
|
+
this.writeFail(["Unable to read file" /* ERR_MESSAGE.READ_FILE */, path.basename(uri)], err, { type: 32 /* LOG_TYPE.FILE */, fatal: false });
|
|
569
589
|
}
|
|
570
|
-
|
|
571
|
-
abortTimeout(target);
|
|
572
|
-
break;
|
|
590
|
+
}
|
|
573
591
|
}
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
};
|
|
582
|
-
if ((0, types_1.isArray)(sourceFiles) && sourceFiles.some(file => this.canRead(file, { hostPermissionOnly: !!this.host }))) {
|
|
583
|
-
let index = 0;
|
|
584
|
-
for (const file of new Set(sourceFiles)) {
|
|
585
|
-
if (index++ > 0) {
|
|
586
|
-
watching(file, true);
|
|
587
|
-
}
|
|
588
|
-
else if ((status = watching(watched = file, true)) > 0) {
|
|
589
|
-
break;
|
|
592
|
+
case 'rename':
|
|
593
|
+
if (map) {
|
|
594
|
+
map.clear();
|
|
595
|
+
}
|
|
596
|
+
watchExpired(DISK_MAP, group, event === 'rename' ? 'File renamed: ' + filename : undefined);
|
|
597
|
+
abortTimeout(target);
|
|
598
|
+
break;
|
|
590
599
|
}
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
else if (watched = item.uri) {
|
|
594
|
-
status = watching(watched, false);
|
|
600
|
+
});
|
|
601
|
+
DISK_MAP.set(uri, new Map([[dest, target]]));
|
|
595
602
|
}
|
|
596
603
|
else {
|
|
597
|
-
|
|
604
|
+
return 2 /* ERR.LOCAL_ACCESS */;
|
|
598
605
|
}
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
message = 'No read permission';
|
|
610
|
-
break;
|
|
611
|
-
case 3 /* ERR.SERVER */:
|
|
612
|
-
message = 'Server already in use';
|
|
613
|
-
break;
|
|
614
|
-
default:
|
|
615
|
-
message = "Unknown" /* ERR_MESSAGE.UNKNOWN */;
|
|
616
|
-
break;
|
|
617
|
-
}
|
|
606
|
+
return 0 /* ERR.NONE */;
|
|
607
|
+
};
|
|
608
|
+
if ((0, types_1.isArray)(sourceFiles) && sourceFiles.some(file => this.canRead(file, { hostPermissionOnly: !!this.host }))) {
|
|
609
|
+
let index = 0;
|
|
610
|
+
for (const file of new Set(sourceFiles)) {
|
|
611
|
+
if (index++ > 0) {
|
|
612
|
+
watching(file, true);
|
|
613
|
+
}
|
|
614
|
+
else if ((status = watching(watched = file, true)) > 0) {
|
|
615
|
+
break;
|
|
618
616
|
}
|
|
619
|
-
this.formatFail((16 /* LOG_TYPE.WATCH */ | (status === 2 /* ERR.LOCAL_ACCESS */ ? 8192 /* LOG_TYPE.PERMISSION */ : 0)), 'WATCH', ["Unable to watch file" /* ERR_MESSAGE.WATCH_FILE */, watched && path.basename(watched)], (0, types_1.errorValue)(message, watched));
|
|
620
617
|
}
|
|
621
|
-
|
|
622
|
-
|
|
618
|
+
}
|
|
619
|
+
else if (watched = item.uri) {
|
|
620
|
+
status = watching(watched, false);
|
|
621
|
+
}
|
|
622
|
+
else {
|
|
623
|
+
continue;
|
|
624
|
+
}
|
|
625
|
+
if (status > 0) {
|
|
626
|
+
if (!message) {
|
|
627
|
+
switch (status) {
|
|
628
|
+
case 1 /* ERR.ETAG */:
|
|
629
|
+
if ((0, types_1.existsFlag)(item.flags)) {
|
|
630
|
+
continue;
|
|
631
|
+
}
|
|
632
|
+
message = 'ETag unavailable';
|
|
633
|
+
break;
|
|
634
|
+
case 2 /* ERR.LOCAL_ACCESS */:
|
|
635
|
+
message = 'No read permission';
|
|
636
|
+
break;
|
|
637
|
+
case 3 /* ERR.SERVER */:
|
|
638
|
+
message = 'Server already in use';
|
|
639
|
+
break;
|
|
640
|
+
default:
|
|
641
|
+
message = "Unknown" /* ERR_MESSAGE.UNKNOWN */;
|
|
642
|
+
break;
|
|
643
|
+
}
|
|
623
644
|
}
|
|
645
|
+
this.formatFail((16 /* LOG_TYPE.WATCH */ | (status === 2 /* ERR.LOCAL_ACCESS */ ? 8192 /* LOG_TYPE.PERMISSION */ : 0)), 'WATCH', ["Unable to watch file" /* ERR_MESSAGE.WATCH_FILE */, watched && path.basename(watched)], (0, types_1.errorValue)(message, watched));
|
|
646
|
+
}
|
|
647
|
+
else {
|
|
648
|
+
this.formatMessage(16 /* LOG_TYPE.WATCH */, 'WATCH', ['Start', interval + 'ms ' + (expires ? formatDate(expires) : 'never')], watched, { titleColor: 'blue' });
|
|
624
649
|
}
|
|
625
650
|
}
|
|
626
651
|
}
|
|
@@ -676,72 +701,73 @@ class Watch extends core_1.Client {
|
|
|
676
701
|
catch {
|
|
677
702
|
}
|
|
678
703
|
}
|
|
679
|
-
if (manager) {
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
const document = manager.find(instance.moduleName);
|
|
690
|
-
if (document) {
|
|
691
|
-
document.dataSource = result.dataSource;
|
|
692
|
-
}
|
|
693
|
-
}
|
|
704
|
+
if (!manager) {
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
if (host && watch.document) {
|
|
708
|
+
for (const { instance } of host.Document) {
|
|
709
|
+
if (host.hasDocument(instance, watch.document)) {
|
|
710
|
+
const result = instance.watchInit?.(watch, items, sanitize);
|
|
711
|
+
if (result) {
|
|
712
|
+
if ((0, types_1.isArray)(result.using)) {
|
|
713
|
+
manager.using(...result.using);
|
|
694
714
|
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
715
|
+
if (Array.isArray(result.dataSource)) {
|
|
716
|
+
const document = manager.find(instance.moduleName);
|
|
717
|
+
if (document) {
|
|
718
|
+
document.dataSource = result.dataSource;
|
|
719
|
+
}
|
|
698
720
|
}
|
|
699
721
|
}
|
|
722
|
+
const listener = instance.watchModified?.(watch, items);
|
|
723
|
+
if (typeof listener === 'function') {
|
|
724
|
+
manager.on('end', listener);
|
|
725
|
+
}
|
|
700
726
|
}
|
|
701
727
|
}
|
|
702
|
-
return await manager.start();
|
|
703
728
|
}
|
|
729
|
+
return await manager.start();
|
|
704
730
|
}
|
|
705
731
|
catch (err) {
|
|
706
732
|
this.writeFail(["Unknown" /* ERR_MESSAGE.UNKNOWN */, watch.url?.pathname || path.basename(watch.uri)], err);
|
|
707
733
|
}
|
|
708
734
|
}
|
|
709
735
|
configureServer({ ca, key, cert, passphrase, version, config }) {
|
|
710
|
-
if ((0, types_1.isString)(key)
|
|
711
|
-
|
|
712
|
-
this.setCA(ca);
|
|
713
|
-
}
|
|
714
|
-
if (request_1.default.isCert(key) || core_1.Client.isPath(key = path.resolve(key = key.trim())) && this.canRead(key, { ownPermissionOnly: true })) {
|
|
715
|
-
this[kTlsKey] = key.trim();
|
|
716
|
-
}
|
|
717
|
-
if (request_1.default.isCert(cert) || core_1.Client.isPath(cert = path.resolve(cert = cert.trim())) && this.canRead(cert, { ownPermissionOnly: true })) {
|
|
718
|
-
this[kTlsCert] = cert.trim();
|
|
719
|
-
}
|
|
720
|
-
if ((0, types_1.isString)(passphrase)) {
|
|
721
|
-
this[kTlsPassphrase] = passphrase;
|
|
722
|
-
}
|
|
723
|
-
if (!(0, types_1.isPlainObject)(config)) {
|
|
724
|
-
config = undefined;
|
|
725
|
-
}
|
|
726
|
-
else if (version || (version = config.minVersion)) {
|
|
727
|
-
delete config.minVersion;
|
|
728
|
-
delete config.secureProtocol;
|
|
729
|
-
}
|
|
730
|
-
switch (version) {
|
|
731
|
-
case 'TLSv1':
|
|
732
|
-
case 'TLSv1.1':
|
|
733
|
-
case 'TLSv1.2':
|
|
734
|
-
case 'TLSv1.3':
|
|
735
|
-
break;
|
|
736
|
-
default:
|
|
737
|
-
version = undefined;
|
|
738
|
-
break;
|
|
739
|
-
}
|
|
740
|
-
this[kTlsConfig] = config;
|
|
741
|
-
this[kTlsVersion] = version;
|
|
742
|
-
return this.hasSecureProtocol();
|
|
736
|
+
if (!(0, types_1.isString)(key) || !(0, types_1.isString)(cert)) {
|
|
737
|
+
return false;
|
|
743
738
|
}
|
|
744
|
-
|
|
739
|
+
if (ca) {
|
|
740
|
+
this.setCA(ca);
|
|
741
|
+
}
|
|
742
|
+
if (request_1.default.isCert(key) || core_1.Client.isPath(key = path.resolve(key = key.trim())) && this.canRead(key, { ownPermissionOnly: true })) {
|
|
743
|
+
this[kTlsKey] = key.trim();
|
|
744
|
+
}
|
|
745
|
+
if (request_1.default.isCert(cert) || core_1.Client.isPath(cert = path.resolve(cert = cert.trim())) && this.canRead(cert, { ownPermissionOnly: true })) {
|
|
746
|
+
this[kTlsCert] = cert.trim();
|
|
747
|
+
}
|
|
748
|
+
if ((0, types_1.isString)(passphrase)) {
|
|
749
|
+
this[kTlsPassphrase] = passphrase;
|
|
750
|
+
}
|
|
751
|
+
if (!(0, types_1.isPlainObject)(config)) {
|
|
752
|
+
config = undefined;
|
|
753
|
+
}
|
|
754
|
+
else if (version || (version = config.minVersion)) {
|
|
755
|
+
delete config.minVersion;
|
|
756
|
+
delete config.secureProtocol;
|
|
757
|
+
}
|
|
758
|
+
switch (version) {
|
|
759
|
+
case 'TLSv1':
|
|
760
|
+
case 'TLSv1.1':
|
|
761
|
+
case 'TLSv1.2':
|
|
762
|
+
case 'TLSv1.3':
|
|
763
|
+
break;
|
|
764
|
+
default:
|
|
765
|
+
version = undefined;
|
|
766
|
+
break;
|
|
767
|
+
}
|
|
768
|
+
this[kTlsConfig] = config;
|
|
769
|
+
this[kTlsVersion] = version;
|
|
770
|
+
return this.hasSecureProtocol();
|
|
745
771
|
}
|
|
746
772
|
setCA(value) {
|
|
747
773
|
if ((0, types_1.isString)(value) && core_1.Client.isPath(value = path.resolve(value = value.trim())) && this.canRead(value, { ownPermissionOnly: true })) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e-mc/watch",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Watch constructor for E-mc.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -20,10 +20,10 @@
|
|
|
20
20
|
"license": "BSD 3-Clause",
|
|
21
21
|
"homepage": "https://github.com/anpham6/e-mc#readme",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@e-mc/core": "0.
|
|
24
|
-
"@e-mc/request": "0.
|
|
25
|
-
"@e-mc/types": "0.
|
|
26
|
-
"picomatch": "^
|
|
27
|
-
"ws": "^8.
|
|
23
|
+
"@e-mc/core": "0.7.0",
|
|
24
|
+
"@e-mc/request": "0.7.0",
|
|
25
|
+
"@e-mc/types": "0.7.0",
|
|
26
|
+
"picomatch": "^3.0.1",
|
|
27
|
+
"ws": "^8.14.2"
|
|
28
28
|
}
|
|
29
29
|
}
|