@gjsify/dgram 0.3.13 → 0.3.14
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/lib/esm/index.js +444 -434
- package/package.json +8 -8
package/lib/esm/index.js
CHANGED
|
@@ -3,440 +3,450 @@ import GLib from "@girs/glib-2.0";
|
|
|
3
3
|
import { EventEmitter } from "node:events";
|
|
4
4
|
import { Buffer } from "node:buffer";
|
|
5
5
|
import { deferEmit, ensureMainLoop } from "@gjsify/utils";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
|
|
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
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
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
|
-
}
|
|
6
|
+
|
|
7
|
+
//#region src/index.ts
|
|
8
|
+
const _activeSockets = new Set();
|
|
9
|
+
var Socket = class extends EventEmitter {
|
|
10
|
+
type;
|
|
11
|
+
_socket = null;
|
|
12
|
+
_bound = false;
|
|
13
|
+
_closed = false;
|
|
14
|
+
_receiving = false;
|
|
15
|
+
_address = {
|
|
16
|
+
address: "0.0.0.0",
|
|
17
|
+
family: "IPv4",
|
|
18
|
+
port: 0
|
|
19
|
+
};
|
|
20
|
+
_cancellable = new Gio.Cancellable();
|
|
21
|
+
_readSource = null;
|
|
22
|
+
_reuseAddr;
|
|
23
|
+
_connected = false;
|
|
24
|
+
_remoteAddress = null;
|
|
25
|
+
constructor(options) {
|
|
26
|
+
super();
|
|
27
|
+
if (typeof options === "string") {
|
|
28
|
+
this.type = options;
|
|
29
|
+
this._reuseAddr = false;
|
|
30
|
+
} else {
|
|
31
|
+
this.type = options.type;
|
|
32
|
+
this._reuseAddr = options.reuseAddr ?? false;
|
|
33
|
+
}
|
|
34
|
+
const family = this.type === "udp6" ? Gio.SocketFamily.IPV6 : Gio.SocketFamily.IPV4;
|
|
35
|
+
try {
|
|
36
|
+
this._socket = Gio.Socket.new(family, Gio.SocketType.DATAGRAM, Gio.SocketProtocol.UDP);
|
|
37
|
+
this._socket.set_blocking(false);
|
|
38
|
+
} catch (err) {
|
|
39
|
+
this._socket = null;
|
|
40
|
+
deferEmit(this, "error", err);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Bind the socket to a port and optional address.
|
|
45
|
+
*/
|
|
46
|
+
bind(port, address, callback) {
|
|
47
|
+
if (this._closed || !this._socket) return this;
|
|
48
|
+
let bindPort = 0;
|
|
49
|
+
let bindAddress = this.type === "udp6" ? "::" : "0.0.0.0";
|
|
50
|
+
if (typeof port === "object") {
|
|
51
|
+
const opts = port;
|
|
52
|
+
bindPort = opts.port || 0;
|
|
53
|
+
bindAddress = opts.address || bindAddress;
|
|
54
|
+
if (typeof address === "function") callback = address;
|
|
55
|
+
} else if (typeof port === "number") {
|
|
56
|
+
bindPort = port;
|
|
57
|
+
if (typeof address === "string") bindAddress = address;
|
|
58
|
+
else if (typeof address === "function") callback = address;
|
|
59
|
+
} else if (typeof port === "function") {
|
|
60
|
+
callback = port;
|
|
61
|
+
}
|
|
62
|
+
if (callback) this.once("listening", callback);
|
|
63
|
+
try {
|
|
64
|
+
const family = this.type === "udp6" ? Gio.SocketFamily.IPV6 : Gio.SocketFamily.IPV4;
|
|
65
|
+
const inetAddr = Gio.InetAddress.new_from_string(bindAddress) || (family === Gio.SocketFamily.IPV6 ? Gio.InetAddress.new_any(Gio.SocketFamily.IPV6) : Gio.InetAddress.new_any(Gio.SocketFamily.IPV4));
|
|
66
|
+
const sockAddr = new Gio.InetSocketAddress({
|
|
67
|
+
address: inetAddr,
|
|
68
|
+
port: bindPort
|
|
69
|
+
});
|
|
70
|
+
this._socket.bind(sockAddr, this._reuseAddr);
|
|
71
|
+
this._bound = true;
|
|
72
|
+
_activeSockets.add(this);
|
|
73
|
+
ensureMainLoop();
|
|
74
|
+
const localAddr = this._socket.get_local_address();
|
|
75
|
+
if (localAddr) {
|
|
76
|
+
this._address = {
|
|
77
|
+
address: localAddr.get_address().to_string(),
|
|
78
|
+
family: this.type === "udp6" ? "IPv6" : "IPv4",
|
|
79
|
+
port: localAddr.get_port()
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
setTimeout(() => {
|
|
83
|
+
this.emit("listening");
|
|
84
|
+
this._startReceiving();
|
|
85
|
+
}, 0);
|
|
86
|
+
} catch (err) {
|
|
87
|
+
deferEmit(this, "error", err);
|
|
88
|
+
}
|
|
89
|
+
return this;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Send a message.
|
|
93
|
+
*/
|
|
94
|
+
send(msg, offset, length, port, address, callback) {
|
|
95
|
+
if (this._closed || !this._socket) return;
|
|
96
|
+
let buf;
|
|
97
|
+
let destPort;
|
|
98
|
+
let destAddress;
|
|
99
|
+
let cb;
|
|
100
|
+
if (typeof offset === "function") {
|
|
101
|
+
cb = offset;
|
|
102
|
+
buf = this._toBuffer(msg);
|
|
103
|
+
destPort = this._address.port;
|
|
104
|
+
destAddress = this._address.address;
|
|
105
|
+
} else if (typeof offset === "number" && typeof length === "string") {
|
|
106
|
+
destPort = offset;
|
|
107
|
+
destAddress = length;
|
|
108
|
+
cb = port;
|
|
109
|
+
buf = this._toBuffer(msg);
|
|
110
|
+
} else if (typeof offset === "number" && typeof length === "number" && typeof address === "function") {
|
|
111
|
+
cb = address;
|
|
112
|
+
destPort = port;
|
|
113
|
+
destAddress = this.type === "udp6" ? "::1" : "127.0.0.1";
|
|
114
|
+
buf = this._toBufferSlice(msg, offset, length);
|
|
115
|
+
} else if (typeof offset === "number" && typeof length === "number") {
|
|
116
|
+
destPort = port;
|
|
117
|
+
destAddress = address || (this.type === "udp6" ? "::1" : "127.0.0.1");
|
|
118
|
+
cb = callback;
|
|
119
|
+
buf = this._toBufferSlice(msg, offset, length);
|
|
120
|
+
} else {
|
|
121
|
+
destPort = Number(offset) || 0;
|
|
122
|
+
destAddress = this.type === "udp6" ? "::1" : "127.0.0.1";
|
|
123
|
+
buf = this._toBuffer(msg);
|
|
124
|
+
}
|
|
125
|
+
this._resolveAndSend(destAddress, destPort, buf, cb);
|
|
126
|
+
}
|
|
127
|
+
_autoBind() {
|
|
128
|
+
if (this._bound || !this._socket) return;
|
|
129
|
+
const anyAddr = this.type === "udp6" ? Gio.InetAddress.new_any(Gio.SocketFamily.IPV6) : Gio.InetAddress.new_any(Gio.SocketFamily.IPV4);
|
|
130
|
+
const anySockAddr = new Gio.InetSocketAddress({
|
|
131
|
+
address: anyAddr,
|
|
132
|
+
port: 0
|
|
133
|
+
});
|
|
134
|
+
this._socket.bind(anySockAddr, false);
|
|
135
|
+
this._bound = true;
|
|
136
|
+
_activeSockets.add(this);
|
|
137
|
+
ensureMainLoop();
|
|
138
|
+
}
|
|
139
|
+
/** Socket family that matches `this.type` (udp4 → IPv4, udp6 → IPv6). */
|
|
140
|
+
_socketFamily() {
|
|
141
|
+
return this.type === "udp6" ? Gio.SocketFamily.IPV6 : Gio.SocketFamily.IPV4;
|
|
142
|
+
}
|
|
143
|
+
/** True when `addr` can be sent to from a socket bound with `this._socketFamily()`. */
|
|
144
|
+
_isAddressCompatible(addr) {
|
|
145
|
+
return addr.get_family() === this._socketFamily();
|
|
146
|
+
}
|
|
147
|
+
/** Build an EINVAL error for a destination whose family doesn't match the socket.
|
|
148
|
+
* Matches Node.js dgram behavior (node reports EINVAL from sendto(2) when the
|
|
149
|
+
* destination address family is incompatible with the bound socket). */
|
|
150
|
+
_mismatchError(destAddress) {
|
|
151
|
+
const want = this.type === "udp6" ? "IPv6" : "IPv4";
|
|
152
|
+
const err = new Error(`EINVAL: cannot send to ${destAddress} from a ${want} socket (address-family mismatch)`);
|
|
153
|
+
err.code = "EINVAL";
|
|
154
|
+
err.syscall = "send";
|
|
155
|
+
return err;
|
|
156
|
+
}
|
|
157
|
+
_resolveAndSend(destAddress, destPort, buf, cb) {
|
|
158
|
+
if (this._closed || !this._socket) {
|
|
159
|
+
if (cb) cb(new Error("Socket is closed"), 0);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
let inetAddr = Gio.InetAddress.new_from_string(destAddress);
|
|
163
|
+
const doSend = (addr) => {
|
|
164
|
+
if (!this._isAddressCompatible(addr)) {
|
|
165
|
+
const err = this._mismatchError(destAddress);
|
|
166
|
+
if (cb) cb(err, 0);
|
|
167
|
+
else this.emit("error", err);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
try {
|
|
171
|
+
this._autoBind();
|
|
172
|
+
const sockAddr = new Gio.InetSocketAddress({
|
|
173
|
+
address: addr,
|
|
174
|
+
port: destPort
|
|
175
|
+
});
|
|
176
|
+
const bytesSent = this._socket.send_to(sockAddr, buf, this._cancellable);
|
|
177
|
+
if (cb) cb(null, bytesSent);
|
|
178
|
+
} catch (err) {
|
|
179
|
+
if (cb) cb(err instanceof Error ? err : new Error(String(err)), 0);
|
|
180
|
+
else this.emit("error", err);
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
if (inetAddr) {
|
|
184
|
+
doSend(inetAddr);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const resolver = Gio.Resolver.get_default();
|
|
188
|
+
resolver.lookup_by_name_async(destAddress, this._cancellable, (_obj, res) => {
|
|
189
|
+
try {
|
|
190
|
+
const addresses = resolver.lookup_by_name_finish(res);
|
|
191
|
+
if (!addresses || addresses.length === 0) {
|
|
192
|
+
const err = new Error(`ENOTFOUND ${destAddress}`);
|
|
193
|
+
err.code = "ENOTFOUND";
|
|
194
|
+
if (cb) cb(err, 0);
|
|
195
|
+
else this.emit("error", err);
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const compatible = addresses.find((a) => this._isAddressCompatible(a));
|
|
199
|
+
if (!compatible) {
|
|
200
|
+
const err = this._mismatchError(destAddress);
|
|
201
|
+
if (cb) cb(err, 0);
|
|
202
|
+
else this.emit("error", err);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
doSend(compatible);
|
|
206
|
+
} catch (err) {
|
|
207
|
+
if (cb) cb(err instanceof Error ? err : new Error(String(err)), 0);
|
|
208
|
+
else this.emit("error", err);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
_toBuffer(msg) {
|
|
213
|
+
if (Array.isArray(msg)) {
|
|
214
|
+
return Buffer.concat(msg.map((m) => typeof m === "string" ? Buffer.from(m) : Buffer.from(m)));
|
|
215
|
+
}
|
|
216
|
+
return typeof msg === "string" ? Buffer.from(msg) : Buffer.from(msg);
|
|
217
|
+
}
|
|
218
|
+
_toBufferSlice(msg, offset, length) {
|
|
219
|
+
const buf = this._toBuffer(msg);
|
|
220
|
+
return Buffer.from(buf.buffer, buf.byteOffset + offset, length);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Close the socket.
|
|
224
|
+
*/
|
|
225
|
+
close(callback) {
|
|
226
|
+
if (this._closed) {
|
|
227
|
+
throw new Error("Not running");
|
|
228
|
+
}
|
|
229
|
+
this._closed = true;
|
|
230
|
+
_activeSockets.delete(this);
|
|
231
|
+
if (callback) this.once("close", callback);
|
|
232
|
+
if (this._readSource) {
|
|
233
|
+
try {
|
|
234
|
+
this._readSource.destroy();
|
|
235
|
+
} catch (_e) {}
|
|
236
|
+
this._readSource = null;
|
|
237
|
+
}
|
|
238
|
+
this._cancellable.cancel();
|
|
239
|
+
if (this._socket) {
|
|
240
|
+
try {
|
|
241
|
+
this._socket.close();
|
|
242
|
+
} catch (_e) {}
|
|
243
|
+
this._socket = null;
|
|
244
|
+
}
|
|
245
|
+
deferEmit(this, "close");
|
|
246
|
+
return this;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Associate the socket with a remote address/port (connected UDP).
|
|
250
|
+
* After connect(), send() can omit address and port.
|
|
251
|
+
*/
|
|
252
|
+
connect(port, address, callback) {
|
|
253
|
+
if (this._connected) {
|
|
254
|
+
const err = new Error("Already connected");
|
|
255
|
+
err.code = "ERR_SOCKET_DGRAM_IS_CONNECTED";
|
|
256
|
+
throw err;
|
|
257
|
+
}
|
|
258
|
+
if (!port || port <= 0 || port >= 65536) {
|
|
259
|
+
const err = new RangeError(`Port should be > 0 and < 65536. Received ${port}.`);
|
|
260
|
+
err.code = "ERR_SOCKET_BAD_PORT";
|
|
261
|
+
throw err;
|
|
262
|
+
}
|
|
263
|
+
let resolvedAddr;
|
|
264
|
+
let cb;
|
|
265
|
+
if (typeof address === "function") {
|
|
266
|
+
cb = address;
|
|
267
|
+
resolvedAddr = this.type === "udp6" ? "::1" : "127.0.0.1";
|
|
268
|
+
} else {
|
|
269
|
+
resolvedAddr = address || (this.type === "udp6" ? "::1" : "127.0.0.1");
|
|
270
|
+
cb = callback;
|
|
271
|
+
}
|
|
272
|
+
this._connected = true;
|
|
273
|
+
this._remoteAddress = {
|
|
274
|
+
address: resolvedAddr,
|
|
275
|
+
family: this.type === "udp6" ? "IPv6" : "IPv4",
|
|
276
|
+
port
|
|
277
|
+
};
|
|
278
|
+
if (cb) {
|
|
279
|
+
Promise.resolve().then(() => {
|
|
280
|
+
this.emit("connect");
|
|
281
|
+
cb();
|
|
282
|
+
});
|
|
283
|
+
} else {
|
|
284
|
+
Promise.resolve().then(() => this.emit("connect"));
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Dissociate a connected socket from its remote address.
|
|
289
|
+
*/
|
|
290
|
+
disconnect() {
|
|
291
|
+
if (!this._connected) {
|
|
292
|
+
const err = new Error("Not connected");
|
|
293
|
+
err.code = "ERR_SOCKET_DGRAM_NOT_CONNECTED";
|
|
294
|
+
throw err;
|
|
295
|
+
}
|
|
296
|
+
this._connected = false;
|
|
297
|
+
this._remoteAddress = null;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Returns the remote address of a connected socket.
|
|
301
|
+
* Throws ERR_SOCKET_DGRAM_NOT_CONNECTED if not connected.
|
|
302
|
+
*/
|
|
303
|
+
remoteAddress() {
|
|
304
|
+
if (!this._connected || !this._remoteAddress) {
|
|
305
|
+
const err = new Error("Not connected");
|
|
306
|
+
err.code = "ERR_SOCKET_DGRAM_NOT_CONNECTED";
|
|
307
|
+
throw err;
|
|
308
|
+
}
|
|
309
|
+
return { ...this._remoteAddress };
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Get the bound address info.
|
|
313
|
+
*/
|
|
314
|
+
address() {
|
|
315
|
+
return { ...this._address };
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Set the broadcast flag.
|
|
319
|
+
*/
|
|
320
|
+
setBroadcast(flag) {
|
|
321
|
+
if (this._socket) {
|
|
322
|
+
this._socket.set_broadcast(flag);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Set the TTL.
|
|
327
|
+
*/
|
|
328
|
+
setTTL(ttl) {
|
|
329
|
+
if (this._socket) {
|
|
330
|
+
this._socket.set_ttl(ttl);
|
|
331
|
+
}
|
|
332
|
+
return ttl;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Set multicast TTL.
|
|
336
|
+
*/
|
|
337
|
+
setMulticastTTL(ttl) {
|
|
338
|
+
if (this._socket) {
|
|
339
|
+
this._socket.set_multicast_ttl(ttl);
|
|
340
|
+
}
|
|
341
|
+
return ttl;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Set multicast loopback.
|
|
345
|
+
*/
|
|
346
|
+
setMulticastLoopback(flag) {
|
|
347
|
+
if (this._socket) {
|
|
348
|
+
this._socket.set_multicast_loopback(flag);
|
|
349
|
+
}
|
|
350
|
+
return flag;
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Add multicast group membership.
|
|
354
|
+
*/
|
|
355
|
+
addMembership(multicastAddress, multicastInterface) {
|
|
356
|
+
if (!this._socket) return;
|
|
357
|
+
try {
|
|
358
|
+
const mcastAddr = Gio.InetAddress.new_from_string(multicastAddress);
|
|
359
|
+
this._socket.join_multicast_group(mcastAddr, false, multicastInterface || null);
|
|
360
|
+
} catch (err) {
|
|
361
|
+
this.emit("error", err);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Drop multicast group membership.
|
|
366
|
+
*/
|
|
367
|
+
dropMembership(multicastAddress, multicastInterface) {
|
|
368
|
+
if (!this._socket) return;
|
|
369
|
+
try {
|
|
370
|
+
const mcastAddr = Gio.InetAddress.new_from_string(multicastAddress);
|
|
371
|
+
this._socket.leave_multicast_group(mcastAddr, false, multicastInterface || null);
|
|
372
|
+
} catch (err) {
|
|
373
|
+
this.emit("error", err);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Set multicast interface.
|
|
378
|
+
*/
|
|
379
|
+
setMulticastInterface(_interfaceAddress) {}
|
|
380
|
+
/** Ref the socket (keep event loop alive). */
|
|
381
|
+
ref() {
|
|
382
|
+
return this;
|
|
383
|
+
}
|
|
384
|
+
/** Unref the socket (allow event loop to exit). */
|
|
385
|
+
unref() {
|
|
386
|
+
return this;
|
|
387
|
+
}
|
|
388
|
+
/** Get/Set receive buffer size. */
|
|
389
|
+
getRecvBufferSize() {
|
|
390
|
+
return 65536;
|
|
391
|
+
}
|
|
392
|
+
setRecvBufferSize(_size) {}
|
|
393
|
+
/** Get/Set send buffer size. */
|
|
394
|
+
getSendBufferSize() {
|
|
395
|
+
return 65536;
|
|
396
|
+
}
|
|
397
|
+
setSendBufferSize(_size) {}
|
|
398
|
+
/**
|
|
399
|
+
* Start receiving messages in background.
|
|
400
|
+
*/
|
|
401
|
+
_startReceiving() {
|
|
402
|
+
if (this._receiving || this._closed || !this._socket) return;
|
|
403
|
+
this._receiving = true;
|
|
404
|
+
this._receiveLoop();
|
|
405
|
+
}
|
|
406
|
+
_receiveLoop() {
|
|
407
|
+
if (this._closed || !this._socket || this._readSource) return;
|
|
408
|
+
const source = this._socket.create_source(GLib.IOCondition.IN, this._cancellable);
|
|
409
|
+
this._readSource = source;
|
|
410
|
+
source.set_callback(() => {
|
|
411
|
+
if (this._closed || !this._socket) return GLib.SOURCE_REMOVE;
|
|
412
|
+
try {
|
|
413
|
+
const [bytes, srcAddr] = this._socket.receive_bytes_from(65536, 0, this._cancellable);
|
|
414
|
+
if (bytes && srcAddr) {
|
|
415
|
+
const data = Buffer.from(bytes.get_data());
|
|
416
|
+
const inetSockAddr = srcAddr;
|
|
417
|
+
const rinfo = {
|
|
418
|
+
address: inetSockAddr.get_address().to_string(),
|
|
419
|
+
family: this.type === "udp6" ? "IPv6" : "IPv4",
|
|
420
|
+
port: inetSockAddr.get_port()
|
|
421
|
+
};
|
|
422
|
+
if (data.length > 0) this.emit("message", data, rinfo);
|
|
423
|
+
}
|
|
424
|
+
} catch (err) {
|
|
425
|
+
const errObj = err;
|
|
426
|
+
if (!this._closed && errObj.code !== Gio.IOErrorEnum.CANCELLED) {
|
|
427
|
+
this.emit("error", err);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
return GLib.SOURCE_CONTINUE;
|
|
431
|
+
});
|
|
432
|
+
source.attach(null);
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
/**
|
|
436
|
+
* Create a UDP socket.
|
|
437
|
+
*/
|
|
429
438
|
function createSocket(type, callback) {
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
439
|
+
const opts = typeof type === "string" ? { type } : type;
|
|
440
|
+
const socket = new Socket(opts);
|
|
441
|
+
if (callback) {
|
|
442
|
+
socket.on("message", callback);
|
|
443
|
+
}
|
|
444
|
+
return socket;
|
|
436
445
|
}
|
|
437
|
-
var
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
createSocket,
|
|
441
|
-
index_default as default
|
|
446
|
+
var src_default = {
|
|
447
|
+
Socket,
|
|
448
|
+
createSocket
|
|
442
449
|
};
|
|
450
|
+
|
|
451
|
+
//#endregion
|
|
452
|
+
export { Socket, createSocket, src_default as default };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/dgram",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.14",
|
|
4
4
|
"description": "Node.js dgram module for Gjs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "lib/esm/index.js",
|
|
@@ -30,15 +30,15 @@
|
|
|
30
30
|
"dgram"
|
|
31
31
|
],
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@girs/gio-2.0": "
|
|
34
|
-
"@girs/glib-2.0": "
|
|
35
|
-
"@gjsify/buffer": "^0.3.
|
|
36
|
-
"@gjsify/events": "^0.3.
|
|
37
|
-
"@gjsify/utils": "^0.3.
|
|
33
|
+
"@girs/gio-2.0": "2.88.0-4.0.0-rc.9",
|
|
34
|
+
"@girs/glib-2.0": "2.88.0-4.0.0-rc.9",
|
|
35
|
+
"@gjsify/buffer": "^0.3.14",
|
|
36
|
+
"@gjsify/events": "^0.3.14",
|
|
37
|
+
"@gjsify/utils": "^0.3.14"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@gjsify/cli": "^0.3.
|
|
41
|
-
"@gjsify/unit": "^0.3.
|
|
40
|
+
"@gjsify/cli": "^0.3.14",
|
|
41
|
+
"@gjsify/unit": "^0.3.14",
|
|
42
42
|
"@types/node": "^25.6.0",
|
|
43
43
|
"typescript": "^6.0.3"
|
|
44
44
|
}
|