@ecobridge.xyz/devicemanager 3.1.0 → 3.2.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/.gitea/workflows/default_tags.yaml +0 -21
- package/.smartconfig.json +69 -0
- package/changelog.md +38 -1
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/device/device.classes.device.d.ts +2 -2
- package/dist_ts/device/device.classes.device.js +3 -3
- package/dist_ts/devicemanager.classes.devicemanager.d.ts +17 -4
- package/dist_ts/devicemanager.classes.devicemanager.js +99 -11
- package/dist_ts/discovery/discovery.classes.mdns.js +46 -11
- package/dist_ts/discovery/discovery.classes.networkscanner.d.ts +5 -1
- package/dist_ts/discovery/discovery.classes.networkscanner.js +44 -3
- package/dist_ts/discovery/discovery.classes.ssdp.d.ts +52 -21
- package/dist_ts/discovery/discovery.classes.ssdp.js +407 -117
- package/dist_ts/events/events.observable.d.ts +15 -0
- package/dist_ts/events/events.observable.js +22 -0
- package/dist_ts/events/index.d.ts +1 -0
- package/dist_ts/events/index.js +2 -0
- package/dist_ts/factories/index.js +7 -5
- package/dist_ts/features/feature.abstract.d.ts +2 -2
- package/dist_ts/features/feature.abstract.js +3 -3
- package/dist_ts/features/feature.print.d.ts +3 -0
- package/dist_ts/features/feature.print.js +17 -2
- package/dist_ts/features/feature.scan.d.ts +5 -2
- package/dist_ts/features/feature.scan.js +98 -27
- package/dist_ts/index.d.ts +4 -2
- package/dist_ts/index.js +4 -2
- package/dist_ts/interfaces/feature.interfaces.d.ts +22 -2
- package/dist_ts/interfaces/index.d.ts +22 -4
- package/dist_ts/interfaces/index.js +1 -1
- package/dist_ts/plugins.d.ts +6 -15
- package/dist_ts/plugins.js +7 -19
- package/dist_ts/protocols/index.d.ts +2 -1
- package/dist_ts/protocols/index.js +4 -2
- package/dist_ts/protocols/protocol.brother.d.ts +67 -0
- package/dist_ts/protocols/protocol.brother.js +560 -0
- package/dist_ts/protocols/protocol.escl.d.ts +13 -4
- package/dist_ts/protocols/protocol.escl.js +345 -178
- package/dist_ts/protocols/protocol.ipp.d.ts +2 -0
- package/dist_ts/protocols/protocol.ipp.js +22 -2
- package/dist_ts/providers/index.d.ts +1 -0
- package/dist_ts/providers/index.js +2 -0
- package/dist_ts/providers/provider.smb.d.ts +60 -0
- package/dist_ts/providers/provider.smb.js +224 -0
- package/license.md +21 -0
- package/package.json +15 -20
- package/pnpm-workspace.yaml +6 -0
- package/readme.md +157 -78
- package/test/test.brother.node.ts +306 -0
- package/test/test.escl.node.ts +233 -0
- package/test/test.ipp.node.ts +75 -0
- package/test/{test.ts → test.node.ts} +37 -45
- package/test/test.smb.node.ts +123 -0
- package/test/test.ssdp.node.ts +978 -0
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/device/device.classes.device.ts +2 -2
- package/ts/devicemanager.classes.devicemanager.ts +125 -12
- package/ts/discovery/discovery.classes.mdns.ts +40 -11
- package/ts/discovery/discovery.classes.networkscanner.ts +51 -2
- package/ts/discovery/discovery.classes.ssdp.ts +493 -130
- package/ts/events/events.observable.ts +31 -0
- package/ts/events/index.ts +4 -0
- package/ts/factories/index.ts +7 -5
- package/ts/features/feature.abstract.ts +2 -2
- package/ts/features/feature.print.ts +16 -1
- package/ts/features/feature.scan.ts +93 -27
- package/ts/index.ts +21 -0
- package/ts/interfaces/feature.interfaces.ts +23 -2
- package/ts/interfaces/index.ts +23 -4
- package/ts/plugins.ts +6 -25
- package/ts/protocols/index.ts +11 -1
- package/ts/protocols/protocol.brother.ts +648 -0
- package/ts/protocols/protocol.escl.ts +348 -191
- package/ts/protocols/protocol.ipp.ts +24 -1
- package/ts/providers/index.ts +7 -0
- package/ts/providers/provider.smb.ts +326 -0
- package/dist_ts/protocols/protocol.ipp.old.d.ts +0 -45
- package/dist_ts/protocols/protocol.ipp.old.js +0 -284
- package/npmextra.json +0 -24
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import * as plugins from '../plugins.js';
|
|
2
|
+
const SSDP_ADDRESS = '239.255.255.250';
|
|
3
|
+
const SSDP_PORT = 1900;
|
|
4
|
+
const SSDP_MULTICAST_TTL = 4;
|
|
5
|
+
const SEARCH_INTERVAL_MS = 30000;
|
|
6
|
+
const DESCRIPTION_TIMEOUT_MS = 5000;
|
|
7
|
+
const SOAP_TIMEOUT_MS = 10000;
|
|
2
8
|
/**
|
|
3
9
|
* SSDP service types for device discovery
|
|
4
10
|
*/
|
|
@@ -14,160 +20,380 @@ export const SSDP_SERVICE_TYPES = {
|
|
|
14
20
|
BASIC_DEVICE: 'urn:schemas-upnp-org:device:Basic:1',
|
|
15
21
|
INTERNET_GATEWAY: 'urn:schemas-upnp-org:device:InternetGatewayDevice:1',
|
|
16
22
|
};
|
|
23
|
+
const DEFAULT_SERVICE_TYPES = [
|
|
24
|
+
SSDP_SERVICE_TYPES.ROOT,
|
|
25
|
+
SSDP_SERVICE_TYPES.MEDIA_RENDERER,
|
|
26
|
+
SSDP_SERVICE_TYPES.MEDIA_SERVER,
|
|
27
|
+
SSDP_SERVICE_TYPES.SONOS_ZONE_PLAYER,
|
|
28
|
+
];
|
|
17
29
|
/**
|
|
18
|
-
* SSDP
|
|
30
|
+
* Focused SSDP discovery client backed by native Node.js UDP sockets.
|
|
19
31
|
*/
|
|
20
32
|
export class SsdpDiscovery extends plugins.events.EventEmitter {
|
|
21
|
-
|
|
33
|
+
dependencies;
|
|
22
34
|
devices = new Map();
|
|
23
|
-
|
|
35
|
+
foundUsns = new Set();
|
|
36
|
+
pendingDescriptions = new Map();
|
|
37
|
+
sockets = [];
|
|
38
|
+
lifecycleState = 'stopped';
|
|
39
|
+
lifecycleTail = Promise.resolve();
|
|
40
|
+
generation = 0;
|
|
41
|
+
startupError = null;
|
|
24
42
|
searchInterval = null;
|
|
25
|
-
|
|
43
|
+
serviceTypes = [...DEFAULT_SERVICE_TYPES];
|
|
44
|
+
constructor(dependencies = {}) {
|
|
26
45
|
super();
|
|
46
|
+
this.dependencies = {
|
|
47
|
+
createSocket: dependencies.createSocket ?? (() => plugins.dgram.createSocket({
|
|
48
|
+
type: 'udp4',
|
|
49
|
+
reuseAddr: true,
|
|
50
|
+
})),
|
|
51
|
+
networkInterfaces: dependencies.networkInterfaces ?? plugins.os.networkInterfaces,
|
|
52
|
+
fetch: dependencies.fetch ?? globalThis.fetch,
|
|
53
|
+
setInterval: dependencies.setInterval ?? globalThis.setInterval,
|
|
54
|
+
clearInterval: dependencies.clearInterval ?? globalThis.clearInterval,
|
|
55
|
+
setTimeout: dependencies.setTimeout ?? globalThis.setTimeout,
|
|
56
|
+
clearTimeout: dependencies.clearTimeout ?? globalThis.clearTimeout,
|
|
57
|
+
};
|
|
27
58
|
}
|
|
28
59
|
/**
|
|
29
|
-
* Start SSDP discovery
|
|
60
|
+
* Start SSDP discovery.
|
|
30
61
|
*/
|
|
31
62
|
async start(serviceTypes) {
|
|
32
|
-
|
|
33
|
-
|
|
63
|
+
const typesToSearch = [...(serviceTypes ?? DEFAULT_SERVICE_TYPES)];
|
|
64
|
+
for (const serviceType of typesToSearch) {
|
|
65
|
+
this.validateServiceType(serviceType);
|
|
34
66
|
}
|
|
35
|
-
this.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
this.client.on('response', (headers, statusCode, rinfo) => {
|
|
39
|
-
this.handleSsdpResponse(headers, rinfo);
|
|
40
|
-
});
|
|
41
|
-
// Search for devices
|
|
42
|
-
const typesToSearch = serviceTypes ?? [
|
|
43
|
-
SSDP_SERVICE_TYPES.ROOT,
|
|
44
|
-
SSDP_SERVICE_TYPES.MEDIA_RENDERER,
|
|
45
|
-
SSDP_SERVICE_TYPES.MEDIA_SERVER,
|
|
46
|
-
SSDP_SERVICE_TYPES.SONOS_ZONE_PLAYER,
|
|
47
|
-
];
|
|
48
|
-
// Initial search
|
|
49
|
-
for (const st of typesToSearch) {
|
|
50
|
-
this.client.search(st);
|
|
51
|
-
}
|
|
52
|
-
// Periodic re-search (every 30 seconds)
|
|
53
|
-
this.searchInterval = setInterval(() => {
|
|
54
|
-
if (this.client) {
|
|
55
|
-
for (const st of typesToSearch) {
|
|
56
|
-
this.client.search(st);
|
|
57
|
-
}
|
|
67
|
+
return this.queueLifecycle(async () => {
|
|
68
|
+
if (this.lifecycleState === 'running') {
|
|
69
|
+
return;
|
|
58
70
|
}
|
|
59
|
-
|
|
60
|
-
|
|
71
|
+
await this.startInternal(typesToSearch);
|
|
72
|
+
});
|
|
61
73
|
}
|
|
62
74
|
/**
|
|
63
|
-
* Stop SSDP discovery
|
|
75
|
+
* Stop SSDP discovery.
|
|
64
76
|
*/
|
|
65
77
|
async stop() {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
this.client = null;
|
|
77
|
-
}
|
|
78
|
-
this.emit('stopped');
|
|
78
|
+
return this.queueLifecycle(async () => {
|
|
79
|
+
if (this.lifecycleState === 'stopped') {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const shouldEmitStopped = this.lifecycleState === 'running';
|
|
83
|
+
await this.cleanupResources();
|
|
84
|
+
if (shouldEmitStopped) {
|
|
85
|
+
this.emit('stopped');
|
|
86
|
+
}
|
|
87
|
+
});
|
|
79
88
|
}
|
|
80
89
|
/**
|
|
81
|
-
* Check if discovery is running
|
|
90
|
+
* Check if discovery is running.
|
|
82
91
|
*/
|
|
83
92
|
get isRunning() {
|
|
84
|
-
return this.running;
|
|
93
|
+
return this.lifecycleState === 'running';
|
|
85
94
|
}
|
|
86
95
|
/**
|
|
87
|
-
* Get all discovered devices
|
|
96
|
+
* Get all discovered devices.
|
|
88
97
|
*/
|
|
89
98
|
getDevices() {
|
|
90
99
|
return Array.from(this.devices.values());
|
|
91
100
|
}
|
|
92
101
|
/**
|
|
93
|
-
* Get devices by service type
|
|
102
|
+
* Get devices by service type.
|
|
94
103
|
*/
|
|
95
104
|
getDevicesByType(serviceType) {
|
|
96
|
-
return this.getDevices().filter((
|
|
105
|
+
return this.getDevices().filter((device) => device.serviceType === serviceType);
|
|
97
106
|
}
|
|
98
107
|
/**
|
|
99
|
-
* Search for a specific service type
|
|
108
|
+
* Search for a specific service type.
|
|
100
109
|
*/
|
|
101
110
|
search(serviceType) {
|
|
102
|
-
|
|
103
|
-
|
|
111
|
+
this.validateServiceType(serviceType);
|
|
112
|
+
if (this.lifecycleState !== 'running') {
|
|
113
|
+
return;
|
|
104
114
|
}
|
|
115
|
+
const activeGeneration = this.generation;
|
|
116
|
+
void this.sendSearches([serviceType], activeGeneration).catch((error) => {
|
|
117
|
+
this.handleRuntimeError(this.toError(error), activeGeneration);
|
|
118
|
+
});
|
|
105
119
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
120
|
+
queueLifecycle(operation) {
|
|
121
|
+
const result = this.lifecycleTail.then(operation);
|
|
122
|
+
this.lifecycleTail = result.catch(() => { });
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
async startInternal(typesToSearch) {
|
|
126
|
+
this.lifecycleState = 'starting';
|
|
127
|
+
this.startupError = null;
|
|
128
|
+
const activeGeneration = ++this.generation;
|
|
129
|
+
try {
|
|
130
|
+
const addresses = this.getInterfaceAddresses();
|
|
131
|
+
if (addresses.length === 0) {
|
|
132
|
+
throw new Error('No non-internal IPv4 interfaces available for SSDP discovery.');
|
|
133
|
+
}
|
|
134
|
+
for (const address of addresses) {
|
|
135
|
+
const resource = this.createSocketResource(address, activeGeneration);
|
|
136
|
+
this.sockets.push(resource);
|
|
137
|
+
await this.bindSocket(resource);
|
|
138
|
+
}
|
|
139
|
+
await this.sendSearches(typesToSearch, activeGeneration);
|
|
140
|
+
if (this.startupError) {
|
|
141
|
+
throw this.startupError;
|
|
142
|
+
}
|
|
143
|
+
this.serviceTypes = typesToSearch;
|
|
144
|
+
this.lifecycleState = 'running';
|
|
145
|
+
this.searchInterval = this.dependencies.setInterval(() => {
|
|
146
|
+
const intervalGeneration = this.generation;
|
|
147
|
+
void this.sendSearches(this.serviceTypes, intervalGeneration).catch((error) => {
|
|
148
|
+
this.handleRuntimeError(this.toError(error), intervalGeneration);
|
|
149
|
+
});
|
|
150
|
+
}, SEARCH_INTERVAL_MS);
|
|
151
|
+
this.unrefTimer(this.searchInterval);
|
|
152
|
+
this.emit('started');
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
await this.cleanupResources();
|
|
156
|
+
throw error;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
getInterfaceAddresses() {
|
|
160
|
+
const addresses = new Set();
|
|
161
|
+
const interfaces = this.dependencies.networkInterfaces();
|
|
162
|
+
for (const [, interfaceInfos] of Object.entries(interfaces).sort(([a], [b]) => a.localeCompare(b))) {
|
|
163
|
+
for (const interfaceInfo of interfaceInfos ?? []) {
|
|
164
|
+
if (!interfaceInfo.internal && interfaceInfo.family === 'IPv4') {
|
|
165
|
+
addresses.add(interfaceInfo.address);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return Array.from(addresses).sort((a, b) => a.localeCompare(b));
|
|
170
|
+
}
|
|
171
|
+
createSocketResource(address, activeGeneration) {
|
|
172
|
+
const socket = this.dependencies.createSocket();
|
|
173
|
+
const onMessage = (message, rinfo) => {
|
|
174
|
+
if (this.lifecycleState === 'running' && this.generation === activeGeneration) {
|
|
175
|
+
this.handleSsdpMessage(message, rinfo, activeGeneration);
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
const onError = (error) => {
|
|
179
|
+
if (this.lifecycleState === 'starting' && this.generation === activeGeneration) {
|
|
180
|
+
this.startupError ??= error;
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
this.handleRuntimeError(error, activeGeneration);
|
|
184
|
+
};
|
|
185
|
+
socket.on('message', onMessage);
|
|
186
|
+
socket.on('error', onError);
|
|
187
|
+
return { address, socket, onMessage, onError };
|
|
188
|
+
}
|
|
189
|
+
async bindSocket(resource) {
|
|
190
|
+
const { address, socket } = resource;
|
|
191
|
+
await new Promise((resolve, reject) => {
|
|
192
|
+
const cleanupBindListeners = () => {
|
|
193
|
+
socket.off('listening', onListening);
|
|
194
|
+
socket.off('error', onBindError);
|
|
195
|
+
};
|
|
196
|
+
const onListening = () => {
|
|
197
|
+
cleanupBindListeners();
|
|
198
|
+
resolve();
|
|
199
|
+
};
|
|
200
|
+
const onBindError = (error) => {
|
|
201
|
+
cleanupBindListeners();
|
|
202
|
+
reject(error);
|
|
203
|
+
};
|
|
204
|
+
socket.once('listening', onListening);
|
|
205
|
+
socket.once('error', onBindError);
|
|
206
|
+
try {
|
|
207
|
+
socket.bind({ port: 0, address, exclusive: true });
|
|
208
|
+
}
|
|
209
|
+
catch (error) {
|
|
210
|
+
cleanupBindListeners();
|
|
211
|
+
reject(error);
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
if (this.startupError) {
|
|
215
|
+
throw this.startupError;
|
|
216
|
+
}
|
|
217
|
+
socket.setMulticastInterface(address);
|
|
218
|
+
socket.setMulticastTTL(SSDP_MULTICAST_TTL);
|
|
219
|
+
// M-SEARCH responses are unicast to this bound socket, so membership is not needed.
|
|
220
|
+
socket.unref();
|
|
221
|
+
}
|
|
222
|
+
async sendSearches(serviceTypes, activeGeneration) {
|
|
223
|
+
if (this.generation !== activeGeneration ||
|
|
224
|
+
(this.lifecycleState !== 'starting' && this.lifecycleState !== 'running')) {
|
|
114
225
|
return;
|
|
115
226
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
port = parseInt(url.port) || (url.protocol === 'https:' ? 443 : 80);
|
|
227
|
+
const sends = [];
|
|
228
|
+
for (const serviceType of serviceTypes) {
|
|
229
|
+
const packet = this.createSearchPacket(serviceType);
|
|
230
|
+
for (const resource of this.sockets) {
|
|
231
|
+
sends.push(this.sendPacket(resource.socket, packet));
|
|
232
|
+
}
|
|
123
233
|
}
|
|
124
|
-
|
|
125
|
-
|
|
234
|
+
const results = await Promise.allSettled(sends);
|
|
235
|
+
const failure = results.find((result) => result.status === 'rejected');
|
|
236
|
+
if (failure) {
|
|
237
|
+
throw failure.reason;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
createSearchPacket(serviceType) {
|
|
241
|
+
return Buffer.from([
|
|
242
|
+
'M-SEARCH * HTTP/1.1',
|
|
243
|
+
`HOST: ${SSDP_ADDRESS}:${SSDP_PORT}`,
|
|
244
|
+
'MAN: "ssdp:discover"',
|
|
245
|
+
'MX: 3',
|
|
246
|
+
`ST: ${serviceType}`,
|
|
247
|
+
'',
|
|
248
|
+
'',
|
|
249
|
+
].join('\r\n'), 'ascii');
|
|
250
|
+
}
|
|
251
|
+
async sendPacket(socket, packet) {
|
|
252
|
+
await new Promise((resolve, reject) => {
|
|
253
|
+
try {
|
|
254
|
+
socket.send(packet, SSDP_PORT, SSDP_ADDRESS, (error) => {
|
|
255
|
+
if (error) {
|
|
256
|
+
reject(error);
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
resolve();
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
reject(error);
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
handleRuntimeError(error, activeGeneration) {
|
|
269
|
+
if (this.lifecycleState !== 'running' || this.generation !== activeGeneration) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
void this.stop();
|
|
273
|
+
if (this.listenerCount('error') > 0) {
|
|
274
|
+
this.emit('error', error);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
handleSsdpMessage(message, rinfo, activeGeneration) {
|
|
278
|
+
const response = this.parseSsdpResponse(message);
|
|
279
|
+
if (!response || response.statusCode !== 200) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
this.handleSsdpResponse(response.headers, rinfo, activeGeneration);
|
|
283
|
+
}
|
|
284
|
+
parseSsdpResponse(message) {
|
|
285
|
+
const lines = message.toString('utf8').split(/\r?\n/);
|
|
286
|
+
const statusLine = lines.shift()?.trim() ?? '';
|
|
287
|
+
const statusMatch = statusLine.match(/^HTTP\/\d\.\d\s+(\d{3})(?:\s|$)/i);
|
|
288
|
+
if (!statusMatch) {
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
const headers = {};
|
|
292
|
+
for (const line of lines) {
|
|
293
|
+
if (line.trim() === '') {
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
const separatorIndex = line.indexOf(':');
|
|
297
|
+
if (separatorIndex <= 0) {
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
const name = line.slice(0, separatorIndex).trim().toUpperCase();
|
|
301
|
+
if (name) {
|
|
302
|
+
headers[name] = line.slice(separatorIndex + 1).trim();
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return {
|
|
306
|
+
statusCode: Number.parseInt(statusMatch[1], 10),
|
|
307
|
+
headers,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
handleSsdpResponse(headers, rinfo, activeGeneration) {
|
|
311
|
+
const usn = headers.USN;
|
|
312
|
+
const location = headers.LOCATION;
|
|
313
|
+
if (!usn || !location) {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
const locationInfo = this.parseLocation(location, rinfo.address);
|
|
317
|
+
const existing = this.devices.get(usn);
|
|
318
|
+
if (existing) {
|
|
319
|
+
existing.serviceType = headers.ST || 'unknown';
|
|
320
|
+
existing.location = location;
|
|
321
|
+
existing.address = locationInfo.address;
|
|
322
|
+
existing.port = locationInfo.port;
|
|
323
|
+
existing.headers = { ...headers };
|
|
324
|
+
if (this.foundUsns.has(usn)) {
|
|
325
|
+
this.emit('device:updated', existing);
|
|
326
|
+
}
|
|
327
|
+
return;
|
|
126
328
|
}
|
|
127
329
|
const device = {
|
|
128
330
|
usn,
|
|
129
|
-
serviceType:
|
|
331
|
+
serviceType: headers.ST || 'unknown',
|
|
130
332
|
location,
|
|
131
|
-
address,
|
|
132
|
-
port,
|
|
333
|
+
address: locationInfo.address,
|
|
334
|
+
port: locationInfo.port,
|
|
133
335
|
headers: { ...headers },
|
|
134
336
|
};
|
|
135
|
-
const isNew = !this.devices.has(usn);
|
|
136
337
|
this.devices.set(usn, device);
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
338
|
+
this.startDescriptionFetch(device, activeGeneration);
|
|
339
|
+
}
|
|
340
|
+
parseLocation(location, fallbackAddress) {
|
|
341
|
+
try {
|
|
342
|
+
const url = new URL(location);
|
|
343
|
+
return {
|
|
344
|
+
address: url.hostname,
|
|
345
|
+
port: Number.parseInt(url.port, 10) || (url.protocol === 'https:' ? 443 : 80),
|
|
346
|
+
};
|
|
145
347
|
}
|
|
146
|
-
|
|
147
|
-
|
|
348
|
+
catch {
|
|
349
|
+
return { address: fallbackAddress, port: 80 };
|
|
148
350
|
}
|
|
149
351
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
352
|
+
startDescriptionFetch(device, activeGeneration) {
|
|
353
|
+
const abortController = new AbortController();
|
|
354
|
+
const timeout = this.dependencies.setTimeout(() => {
|
|
355
|
+
abortController.abort();
|
|
356
|
+
}, DESCRIPTION_TIMEOUT_MS);
|
|
357
|
+
this.unrefTimer(timeout);
|
|
358
|
+
const pending = {
|
|
359
|
+
device,
|
|
360
|
+
abortController,
|
|
361
|
+
timeout,
|
|
362
|
+
promise: Promise.resolve(),
|
|
363
|
+
};
|
|
364
|
+
pending.promise = (async () => {
|
|
365
|
+
await this.fetchDeviceDescription(device, abortController.signal);
|
|
366
|
+
if (this.lifecycleState === 'running' &&
|
|
367
|
+
this.generation === activeGeneration &&
|
|
368
|
+
this.devices.get(device.usn) === device &&
|
|
369
|
+
!this.foundUsns.has(device.usn)) {
|
|
370
|
+
this.foundUsns.add(device.usn);
|
|
371
|
+
this.emit('device:found', device);
|
|
372
|
+
}
|
|
373
|
+
})().finally(() => {
|
|
374
|
+
this.dependencies.clearTimeout(timeout);
|
|
375
|
+
if (this.pendingDescriptions.get(device.usn) === pending) {
|
|
376
|
+
this.pendingDescriptions.delete(device.usn);
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
this.pendingDescriptions.set(device.usn, pending);
|
|
380
|
+
}
|
|
381
|
+
async fetchDeviceDescription(device, signal) {
|
|
154
382
|
try {
|
|
155
|
-
const response = await fetch(device.location, {
|
|
156
|
-
signal: AbortSignal.timeout(5000),
|
|
157
|
-
});
|
|
383
|
+
const response = await this.dependencies.fetch(device.location, { signal });
|
|
158
384
|
if (!response.ok) {
|
|
385
|
+
await this.cancelResponseBody(response);
|
|
159
386
|
return;
|
|
160
387
|
}
|
|
161
388
|
const xml = await response.text();
|
|
162
|
-
|
|
389
|
+
if (!signal.aborted) {
|
|
390
|
+
device.description = this.parseDeviceDescription(xml);
|
|
391
|
+
}
|
|
163
392
|
}
|
|
164
393
|
catch {
|
|
165
|
-
//
|
|
394
|
+
// Devices without a reachable description are still valid SSDP results.
|
|
166
395
|
}
|
|
167
396
|
}
|
|
168
|
-
/**
|
|
169
|
-
* Parse UPnP device description XML
|
|
170
|
-
*/
|
|
171
397
|
parseDeviceDescription(xml) {
|
|
172
398
|
const getTagContent = (tag, source = xml) => {
|
|
173
399
|
const regex = new RegExp(`<${tag}[^>]*>([^<]*)</${tag}>`, 'i');
|
|
@@ -179,7 +405,6 @@ export class SsdpDiscovery extends plugins.events.EventEmitter {
|
|
|
179
405
|
const match = source.match(regex);
|
|
180
406
|
return match?.[1] ?? '';
|
|
181
407
|
};
|
|
182
|
-
// Parse services
|
|
183
408
|
const services = [];
|
|
184
409
|
const serviceListBlock = getTagBlock('serviceList');
|
|
185
410
|
const serviceMatches = serviceListBlock.match(/<service>[\s\S]*?<\/service>/gi) || [];
|
|
@@ -192,16 +417,15 @@ export class SsdpDiscovery extends plugins.events.EventEmitter {
|
|
|
192
417
|
eventSubURL: getTagContent('eventSubURL', serviceXml),
|
|
193
418
|
});
|
|
194
419
|
}
|
|
195
|
-
// Parse icons
|
|
196
420
|
const icons = [];
|
|
197
421
|
const iconListBlock = getTagBlock('iconList');
|
|
198
422
|
const iconMatches = iconListBlock.match(/<icon>[\s\S]*?<\/icon>/gi) || [];
|
|
199
423
|
for (const iconXml of iconMatches) {
|
|
200
424
|
icons.push({
|
|
201
425
|
mimetype: getTagContent('mimetype', iconXml),
|
|
202
|
-
width: parseInt(getTagContent('width', iconXml)) || 0,
|
|
203
|
-
height: parseInt(getTagContent('height', iconXml)) || 0,
|
|
204
|
-
depth: parseInt(getTagContent('depth', iconXml)) || 0,
|
|
426
|
+
width: Number.parseInt(getTagContent('width', iconXml), 10) || 0,
|
|
427
|
+
height: Number.parseInt(getTagContent('height', iconXml), 10) || 0,
|
|
428
|
+
depth: Number.parseInt(getTagContent('depth', iconXml), 10) || 0,
|
|
205
429
|
url: getTagContent('url', iconXml),
|
|
206
430
|
});
|
|
207
431
|
}
|
|
@@ -220,11 +444,66 @@ export class SsdpDiscovery extends plugins.events.EventEmitter {
|
|
|
220
444
|
icons: icons.length > 0 ? icons : undefined,
|
|
221
445
|
};
|
|
222
446
|
}
|
|
447
|
+
async cleanupResources() {
|
|
448
|
+
this.lifecycleState = 'stopping';
|
|
449
|
+
++this.generation;
|
|
450
|
+
if (this.searchInterval) {
|
|
451
|
+
this.dependencies.clearInterval(this.searchInterval);
|
|
452
|
+
this.searchInterval = null;
|
|
453
|
+
}
|
|
454
|
+
const pendingDescriptions = Array.from(this.pendingDescriptions.values());
|
|
455
|
+
for (const pending of pendingDescriptions) {
|
|
456
|
+
this.dependencies.clearTimeout(pending.timeout);
|
|
457
|
+
pending.abortController.abort();
|
|
458
|
+
}
|
|
459
|
+
await Promise.allSettled(pendingDescriptions.map((pending) => pending.promise));
|
|
460
|
+
for (const pending of pendingDescriptions) {
|
|
461
|
+
if (!this.foundUsns.has(pending.device.usn) && this.devices.get(pending.device.usn) === pending.device) {
|
|
462
|
+
this.devices.delete(pending.device.usn);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
this.pendingDescriptions.clear();
|
|
466
|
+
const sockets = this.sockets;
|
|
467
|
+
this.sockets = [];
|
|
468
|
+
await Promise.all(sockets.map(async (resource) => {
|
|
469
|
+
resource.socket.off('message', resource.onMessage);
|
|
470
|
+
resource.socket.off('error', resource.onError);
|
|
471
|
+
await new Promise((resolve) => {
|
|
472
|
+
try {
|
|
473
|
+
resource.socket.close(resolve);
|
|
474
|
+
}
|
|
475
|
+
catch {
|
|
476
|
+
resolve();
|
|
477
|
+
}
|
|
478
|
+
});
|
|
479
|
+
}));
|
|
480
|
+
this.startupError = null;
|
|
481
|
+
this.lifecycleState = 'stopped';
|
|
482
|
+
}
|
|
483
|
+
validateServiceType(serviceType) {
|
|
484
|
+
if (!serviceType || /[\r\n]/.test(serviceType)) {
|
|
485
|
+
throw new Error('SSDP service type must be non-empty and cannot contain line breaks.');
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
unrefTimer(timer) {
|
|
489
|
+
const unref = timer.unref;
|
|
490
|
+
unref?.call(timer);
|
|
491
|
+
}
|
|
492
|
+
toError(error) {
|
|
493
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
494
|
+
}
|
|
495
|
+
async cancelResponseBody(response) {
|
|
496
|
+
try {
|
|
497
|
+
await response.body?.cancel();
|
|
498
|
+
}
|
|
499
|
+
catch {
|
|
500
|
+
// The fetch timeout/abort remains the final cleanup path for a failed body.
|
|
501
|
+
}
|
|
502
|
+
}
|
|
223
503
|
/**
|
|
224
|
-
* Make a UPnP SOAP request
|
|
504
|
+
* Make a UPnP SOAP request.
|
|
225
505
|
*/
|
|
226
506
|
async soapRequest(controlUrl, serviceType, action, args = {}) {
|
|
227
|
-
// Build SOAP body
|
|
228
507
|
let argsXml = '';
|
|
229
508
|
for (const [key, value] of Object.entries(args)) {
|
|
230
509
|
argsXml += `<${key}>${value}</${key}>`;
|
|
@@ -237,19 +516,30 @@ export class SsdpDiscovery extends plugins.events.EventEmitter {
|
|
|
237
516
|
</u:${action}>
|
|
238
517
|
</s:Body>
|
|
239
518
|
</s:Envelope>`;
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
519
|
+
const abortController = new AbortController();
|
|
520
|
+
const timeout = this.dependencies.setTimeout(() => {
|
|
521
|
+
abortController.abort();
|
|
522
|
+
}, SOAP_TIMEOUT_MS);
|
|
523
|
+
this.unrefTimer(timeout);
|
|
524
|
+
try {
|
|
525
|
+
const response = await this.dependencies.fetch(controlUrl, {
|
|
526
|
+
method: 'POST',
|
|
527
|
+
headers: {
|
|
528
|
+
'Content-Type': 'text/xml; charset=utf-8',
|
|
529
|
+
'SOAPACTION': `"${serviceType}#${action}"`,
|
|
530
|
+
},
|
|
531
|
+
body: soapBody,
|
|
532
|
+
signal: abortController.signal,
|
|
533
|
+
});
|
|
534
|
+
if (!response.ok) {
|
|
535
|
+
await this.cancelResponseBody(response);
|
|
536
|
+
throw new Error(`SOAP request failed: ${response.status}`);
|
|
537
|
+
}
|
|
538
|
+
return await response.text();
|
|
539
|
+
}
|
|
540
|
+
finally {
|
|
541
|
+
this.dependencies.clearTimeout(timeout);
|
|
251
542
|
}
|
|
252
|
-
return response.text();
|
|
253
543
|
}
|
|
254
544
|
}
|
|
255
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGlzY292ZXJ5LmNsYXNzZXMuc3NkcC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2Rpc2NvdmVyeS9kaXNjb3ZlcnkuY2xhc3Nlcy5zc2RwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sZUFBZSxDQUFDO0FBRXpDOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sa0JBQWtCLEdBQUc7SUFDaEMsY0FBYztJQUNkLElBQUksRUFBRSxpQkFBaUI7SUFFdkIsZUFBZTtJQUNmLGNBQWMsRUFBRSw2Q0FBNkM7SUFDN0QsWUFBWSxFQUFFLDJDQUEyQztJQUV6RCxRQUFRO0lBQ1IsaUJBQWlCLEVBQUUsMENBQTBDO0lBRTdELFVBQVU7SUFDVixZQUFZLEVBQUUscUNBQXFDO0lBQ25ELGdCQUFnQixFQUFFLHFEQUFxRDtDQUN4RSxDQUFDO0FBd0RGOztHQUVHO0FBQ0gsTUFBTSxPQUFPLGFBQWMsU0FBUSxPQUFPLENBQUMsTUFBTSxDQUFDLFlBQVk7SUFDcEQsTUFBTSxHQUF3RCxJQUFJLENBQUM7SUFDbkUsT0FBTyxHQUE2QixJQUFJLEdBQUcsRUFBRSxDQUFDO0lBQzlDLE9BQU8sR0FBRyxLQUFLLENBQUM7SUFDaEIsY0FBYyxHQUEwQixJQUFJLENBQUM7SUFFckQ7UUFDRSxLQUFLLEVBQUUsQ0FBQztJQUNWLENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyxLQUFLLENBQUMsWUFBdUI7UUFDeEMsSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDakIsT0FBTztRQUNULENBQUM7UUFFRCxJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQztRQUNwQixJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksT0FBTyxDQUFDLFFBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUU1Qyx3QkFBd0I7UUFDeEIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsVUFBVSxFQUFFLENBQUMsT0FB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
|
|
545
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGlzY292ZXJ5LmNsYXNzZXMuc3NkcC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2Rpc2NvdmVyeS9kaXNjb3ZlcnkuY2xhc3Nlcy5zc2RwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sZUFBZSxDQUFDO0FBRXpDLE1BQU0sWUFBWSxHQUFHLGlCQUFpQixDQUFDO0FBQ3ZDLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQztBQUN2QixNQUFNLGtCQUFrQixHQUFHLENBQUMsQ0FBQztBQUM3QixNQUFNLGtCQUFrQixHQUFHLEtBQUssQ0FBQztBQUNqQyxNQUFNLHNCQUFzQixHQUFHLElBQUksQ0FBQztBQUNwQyxNQUFNLGVBQWUsR0FBRyxLQUFLLENBQUM7QUFLOUI7O0dBRUc7QUFDSCxNQUFNLENBQUMsTUFBTSxrQkFBa0IsR0FBRztJQUNoQyxjQUFjO0lBQ2QsSUFBSSxFQUFFLGlCQUFpQjtJQUV2QixlQUFlO0lBQ2YsY0FBYyxFQUFFLDZDQUE2QztJQUM3RCxZQUFZLEVBQUUsMkNBQTJDO0lBRXpELFFBQVE7SUFDUixpQkFBaUIsRUFBRSwwQ0FBMEM7SUFFN0QsVUFBVTtJQUNWLFlBQVksRUFBRSxxQ0FBcUM7SUFDbkQsZ0JBQWdCLEVBQUUscURBQXFEO0NBQ3hFLENBQUM7QUFFRixNQUFNLHFCQUFxQixHQUFHO0lBQzVCLGtCQUFrQixDQUFDLElBQUk7SUFDdkIsa0JBQWtCLENBQUMsY0FBYztJQUNqQyxrQkFBa0IsQ0FBQyxZQUFZO0lBQy9CLGtCQUFrQixDQUFDLGlCQUFpQjtDQUNyQyxDQUFDO0FBeUZGOztHQUVHO0FBQ0gsTUFBTSxPQUFPLGFBQWMsU0FBUSxPQUFPLENBQUMsTUFBTSxDQUFDLFlBQVk7SUFDM0MsWUFBWSxDQUF1QztJQUNuRCxPQUFPLEdBQUcsSUFBSSxHQUFHLEVBQXVCLENBQUM7SUFDekMsU0FBUyxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7SUFDOUIsbUJB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
|