@gjsify/net 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 +36 -44
- package/lib/esm/server.js +138 -130
- package/lib/esm/socket.js +350 -376
- package/lib/types/index.d.ts +3 -3
- package/package.json +9 -9
- package/src/index.ts +4 -4
- package/tsconfig.tsbuildinfo +1 -1
package/lib/esm/socket.js
CHANGED
|
@@ -3,380 +3,354 @@ import GLib from "@girs/glib-2.0";
|
|
|
3
3
|
import { Duplex } from "node:stream";
|
|
4
4
|
import { Buffer } from "node:buffer";
|
|
5
5
|
import { createNodeError, gbytesToUint8Array } 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
|
-
if (this.writable)
|
|
354
|
-
this.end();
|
|
355
|
-
if (this.writableFinished)
|
|
356
|
-
this.destroy();
|
|
357
|
-
else
|
|
358
|
-
this.once("finish", this.destroy.bind(this));
|
|
359
|
-
}
|
|
360
|
-
/** Get the underlying socket address info. */
|
|
361
|
-
address() {
|
|
362
|
-
if (this.localAddress && this.localPort) {
|
|
363
|
-
return {
|
|
364
|
-
port: this.localPort,
|
|
365
|
-
family: this.remoteFamily || "IPv4",
|
|
366
|
-
address: this.localAddress
|
|
367
|
-
};
|
|
368
|
-
}
|
|
369
|
-
return {};
|
|
370
|
-
}
|
|
371
|
-
/** Reference this socket (keep event loop alive). No-op in GJS. */
|
|
372
|
-
ref() {
|
|
373
|
-
return this;
|
|
374
|
-
}
|
|
375
|
-
/** Unreference this socket. No-op in GJS. */
|
|
376
|
-
unref() {
|
|
377
|
-
return this;
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
export {
|
|
381
|
-
Socket
|
|
6
|
+
|
|
7
|
+
//#region src/socket.ts
|
|
8
|
+
var Socket = class extends Duplex {
|
|
9
|
+
remoteAddress;
|
|
10
|
+
remotePort;
|
|
11
|
+
remoteFamily;
|
|
12
|
+
localAddress;
|
|
13
|
+
localPort;
|
|
14
|
+
bytesRead = 0;
|
|
15
|
+
bytesWritten = 0;
|
|
16
|
+
connecting = false;
|
|
17
|
+
destroyed = false;
|
|
18
|
+
pending = true;
|
|
19
|
+
readyState = "closed";
|
|
20
|
+
_connection = null;
|
|
21
|
+
_ioStream = null;
|
|
22
|
+
_inputStream = null;
|
|
23
|
+
_outputStream = null;
|
|
24
|
+
_cancellable = new Gio.Cancellable();
|
|
25
|
+
_reading = false;
|
|
26
|
+
_timeout = 0;
|
|
27
|
+
_timeoutId = null;
|
|
28
|
+
constructor(options) {
|
|
29
|
+
super(options);
|
|
30
|
+
this.allowHalfOpen = options?.allowHalfOpen ?? false;
|
|
31
|
+
}
|
|
32
|
+
/** @internal Set the connection from an accepted server socket. */
|
|
33
|
+
_setConnection(connection) {
|
|
34
|
+
this._connection = connection;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* @internal Set up this socket from a raw Gio.IOStream (e.g., stolen from Soup.Server
|
|
38
|
+
* during an HTTP upgrade). Extracts I/O streams, attempts to read address info
|
|
39
|
+
* if the underlying stream is a SocketConnection, and starts reading.
|
|
40
|
+
*/
|
|
41
|
+
_setupFromIOStream(ioStream) {
|
|
42
|
+
this._ioStream = ioStream;
|
|
43
|
+
try {
|
|
44
|
+
const sockConn = ioStream;
|
|
45
|
+
if (typeof sockConn.get_socket === "function") {
|
|
46
|
+
this._connection = sockConn;
|
|
47
|
+
const remoteAddr = sockConn.get_remote_address();
|
|
48
|
+
this.remoteAddress = remoteAddr.get_address().to_string();
|
|
49
|
+
this.remotePort = remoteAddr.get_port();
|
|
50
|
+
this.remoteFamily = remoteAddr.get_address().get_family() === Gio.SocketFamily.IPV6 ? "IPv6" : "IPv4";
|
|
51
|
+
const localAddr = sockConn.get_local_address();
|
|
52
|
+
this.localAddress = localAddr.get_address().to_string();
|
|
53
|
+
this.localPort = localAddr.get_port();
|
|
54
|
+
}
|
|
55
|
+
} catch {}
|
|
56
|
+
this._inputStream = ioStream.get_input_stream();
|
|
57
|
+
this._outputStream = ioStream.get_output_stream();
|
|
58
|
+
this.connecting = false;
|
|
59
|
+
this.pending = false;
|
|
60
|
+
this.readyState = "open";
|
|
61
|
+
this.emit("connect");
|
|
62
|
+
this.emit("ready");
|
|
63
|
+
this._startReading();
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* @internal For HTTP upgrade handoff: configures write capability and address
|
|
67
|
+
* info from the IOStream but does NOT start the async read loop. Used by
|
|
68
|
+
* http.Server._handleRequest so handleUpgrade() can write the 101 response and
|
|
69
|
+
* then hand the IOStream to Soup.WebsocketConnection without a read-loop race.
|
|
70
|
+
*/
|
|
71
|
+
_attachOutputOnly(ioStream) {
|
|
72
|
+
this._ioStream = ioStream;
|
|
73
|
+
try {
|
|
74
|
+
const sockConn = ioStream;
|
|
75
|
+
if (typeof sockConn.get_socket === "function") {
|
|
76
|
+
this._connection = sockConn;
|
|
77
|
+
const remoteAddr = sockConn.get_remote_address();
|
|
78
|
+
this.remoteAddress = remoteAddr.get_address().to_string();
|
|
79
|
+
this.remotePort = remoteAddr.get_port();
|
|
80
|
+
this.remoteFamily = remoteAddr.get_address().get_family() === Gio.SocketFamily.IPV6 ? "IPv6" : "IPv4";
|
|
81
|
+
const localAddr = sockConn.get_local_address();
|
|
82
|
+
this.localAddress = localAddr.get_address().to_string();
|
|
83
|
+
this.localPort = localAddr.get_port();
|
|
84
|
+
}
|
|
85
|
+
} catch {}
|
|
86
|
+
this._inputStream = ioStream.get_input_stream();
|
|
87
|
+
this._outputStream = ioStream.get_output_stream();
|
|
88
|
+
this.connecting = false;
|
|
89
|
+
this.pending = false;
|
|
90
|
+
this.readyState = "open";
|
|
91
|
+
this.emit("connect");
|
|
92
|
+
this.emit("ready");
|
|
93
|
+
}
|
|
94
|
+
/** Release IOStream ownership to the caller (Soup.WebsocketConnection handoff).
|
|
95
|
+
* Nullifies the socket's stream references so they are not closed when the
|
|
96
|
+
* socket itself is later destroyed. */
|
|
97
|
+
_releaseIOStream() {
|
|
98
|
+
const s = this._ioStream;
|
|
99
|
+
this._ioStream = null;
|
|
100
|
+
this._inputStream = null;
|
|
101
|
+
this._outputStream = null;
|
|
102
|
+
this._connection = null;
|
|
103
|
+
return s;
|
|
104
|
+
}
|
|
105
|
+
connect(options, host, connectionListener) {
|
|
106
|
+
let opts;
|
|
107
|
+
if (typeof options === "number") {
|
|
108
|
+
opts = {
|
|
109
|
+
port: options,
|
|
110
|
+
host: typeof host === "string" ? host : "localhost"
|
|
111
|
+
};
|
|
112
|
+
if (typeof host === "function") connectionListener = host;
|
|
113
|
+
} else {
|
|
114
|
+
opts = options;
|
|
115
|
+
if (typeof host === "function") connectionListener = host;
|
|
116
|
+
}
|
|
117
|
+
if (connectionListener) {
|
|
118
|
+
this.once("connect", connectionListener);
|
|
119
|
+
}
|
|
120
|
+
this.connecting = true;
|
|
121
|
+
this.readyState = "opening";
|
|
122
|
+
this.pending = true;
|
|
123
|
+
const targetHost = opts.host || "localhost";
|
|
124
|
+
const targetPort = opts.port;
|
|
125
|
+
const client = new Gio.SocketClient();
|
|
126
|
+
if (opts.timeout) {
|
|
127
|
+
client.set_timeout(Math.ceil(opts.timeout / 1e3));
|
|
128
|
+
}
|
|
129
|
+
client.connect_to_host_async(targetHost, targetPort, this._cancellable, (_source, asyncResult) => {
|
|
130
|
+
try {
|
|
131
|
+
this._connection = client.connect_to_host_finish(asyncResult);
|
|
132
|
+
this._setupConnection(opts);
|
|
133
|
+
} catch (err) {
|
|
134
|
+
this.connecting = false;
|
|
135
|
+
this.readyState = "closed";
|
|
136
|
+
const nodeErr = createNodeError(err, "connect", {
|
|
137
|
+
address: targetHost,
|
|
138
|
+
port: targetPort
|
|
139
|
+
});
|
|
140
|
+
this.destroy(nodeErr);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
return this;
|
|
144
|
+
}
|
|
145
|
+
/** @internal Set up streams and emit connect after connection is established. */
|
|
146
|
+
_setupConnection(opts) {
|
|
147
|
+
if (!this._connection) return;
|
|
148
|
+
const sock = this._connection.get_socket();
|
|
149
|
+
this._inputStream = this._connection.get_input_stream();
|
|
150
|
+
this._outputStream = this._connection.get_output_stream();
|
|
151
|
+
if ("keepAlive" in opts && opts.keepAlive) {
|
|
152
|
+
sock.set_keepalive(true);
|
|
153
|
+
}
|
|
154
|
+
if (!("noDelay" in opts) || opts.noDelay !== false) {
|
|
155
|
+
try {
|
|
156
|
+
sock.set_option(6, 1, 1);
|
|
157
|
+
} catch {}
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
const remoteAddr = this._connection.get_remote_address();
|
|
161
|
+
this.remoteAddress = remoteAddr.get_address().to_string();
|
|
162
|
+
this.remotePort = remoteAddr.get_port();
|
|
163
|
+
this.remoteFamily = remoteAddr.get_address().get_family() === Gio.SocketFamily.IPV6 ? "IPv6" : "IPv4";
|
|
164
|
+
} catch {}
|
|
165
|
+
try {
|
|
166
|
+
const localAddr = this._connection.get_local_address();
|
|
167
|
+
this.localAddress = localAddr.get_address().to_string();
|
|
168
|
+
this.localPort = localAddr.get_port();
|
|
169
|
+
} catch {}
|
|
170
|
+
this.connecting = false;
|
|
171
|
+
this.pending = false;
|
|
172
|
+
this.readyState = "open";
|
|
173
|
+
this.emit("connect");
|
|
174
|
+
this.emit("ready");
|
|
175
|
+
this._startReading();
|
|
176
|
+
}
|
|
177
|
+
_startReading() {
|
|
178
|
+
if (this._reading || !this._inputStream) return;
|
|
179
|
+
this._reading = true;
|
|
180
|
+
this._readLoop();
|
|
181
|
+
}
|
|
182
|
+
async _readLoop() {
|
|
183
|
+
const inputStream = this._inputStream;
|
|
184
|
+
if (!inputStream) return;
|
|
185
|
+
const CHUNK_SIZE = 16384;
|
|
186
|
+
try {
|
|
187
|
+
while (this._reading && inputStream) {
|
|
188
|
+
const bytes = await new Promise((resolve, reject) => {
|
|
189
|
+
inputStream.read_bytes_async(CHUNK_SIZE, GLib.PRIORITY_DEFAULT, this._cancellable, (_source, asyncResult) => {
|
|
190
|
+
try {
|
|
191
|
+
resolve(inputStream.read_bytes_finish(asyncResult));
|
|
192
|
+
} catch (err) {
|
|
193
|
+
reject(err);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
if (!bytes || bytes.get_size() === 0) {
|
|
198
|
+
this._reading = false;
|
|
199
|
+
if (!this.allowHalfOpen) {
|
|
200
|
+
this.once("end", () => {
|
|
201
|
+
this.end();
|
|
202
|
+
this.readyState = "closed";
|
|
203
|
+
});
|
|
204
|
+
} else {
|
|
205
|
+
this.readyState = this.writable ? "writeOnly" : "closed";
|
|
206
|
+
}
|
|
207
|
+
this.push(null);
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
const data = gbytesToUint8Array(bytes);
|
|
211
|
+
this.bytesRead += data.length;
|
|
212
|
+
this._resetTimeout();
|
|
213
|
+
if (!this.push(Buffer.from(data))) {
|
|
214
|
+
this._reading = false;
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
} catch (err) {
|
|
219
|
+
if (!this._cancellable.is_cancelled()) {
|
|
220
|
+
this.destroy(createNodeError(err, "read", { address: this.remoteAddress }));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
_read(_size) {
|
|
225
|
+
if (!this._reading && this._inputStream) {
|
|
226
|
+
this._startReading();
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
_write(chunk, encoding, callback) {
|
|
230
|
+
if (!this._outputStream) {
|
|
231
|
+
callback(new Error("Socket is not connected"));
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const data = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding);
|
|
235
|
+
this._outputStream.write_bytes_async(new GLib.Bytes(data), GLib.PRIORITY_DEFAULT, this._cancellable, (_source, asyncResult) => {
|
|
236
|
+
try {
|
|
237
|
+
const written = this._outputStream.write_bytes_finish(asyncResult);
|
|
238
|
+
this.bytesWritten += written;
|
|
239
|
+
this._resetTimeout();
|
|
240
|
+
callback(null);
|
|
241
|
+
} catch (err) {
|
|
242
|
+
callback(createNodeError(err, "write", { address: this.remoteAddress }));
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
_final(callback) {
|
|
247
|
+
if (this._connection) {
|
|
248
|
+
try {
|
|
249
|
+
this._connection.get_socket().shutdown(false, true);
|
|
250
|
+
this.readyState = this.readable ? "readOnly" : "closed";
|
|
251
|
+
} catch {}
|
|
252
|
+
} else if (this._ioStream) {
|
|
253
|
+
try {
|
|
254
|
+
this._ioStream.close(null);
|
|
255
|
+
this.readyState = "closed";
|
|
256
|
+
} catch {}
|
|
257
|
+
this._ioStream = null;
|
|
258
|
+
this._inputStream = null;
|
|
259
|
+
this._outputStream = null;
|
|
260
|
+
}
|
|
261
|
+
callback();
|
|
262
|
+
}
|
|
263
|
+
_destroy(err, callback) {
|
|
264
|
+
this._reading = false;
|
|
265
|
+
this._clearTimeout();
|
|
266
|
+
this._cancellable.cancel();
|
|
267
|
+
if (this._connection) {
|
|
268
|
+
try {
|
|
269
|
+
this._connection.close(null);
|
|
270
|
+
} catch {}
|
|
271
|
+
this._connection = null;
|
|
272
|
+
} else if (this._ioStream) {
|
|
273
|
+
try {
|
|
274
|
+
this._ioStream.close(null);
|
|
275
|
+
} catch {}
|
|
276
|
+
}
|
|
277
|
+
this._ioStream = null;
|
|
278
|
+
this._inputStream = null;
|
|
279
|
+
this._outputStream = null;
|
|
280
|
+
this.readyState = "closed";
|
|
281
|
+
this.destroyed = true;
|
|
282
|
+
callback(err);
|
|
283
|
+
}
|
|
284
|
+
/** Set the socket timeout in milliseconds. 0 disables. */
|
|
285
|
+
setTimeout(timeout, callback) {
|
|
286
|
+
this._timeout = timeout;
|
|
287
|
+
this._clearTimeout();
|
|
288
|
+
if (callback) {
|
|
289
|
+
this.once("timeout", callback);
|
|
290
|
+
}
|
|
291
|
+
if (timeout > 0) {
|
|
292
|
+
this._resetTimeout();
|
|
293
|
+
}
|
|
294
|
+
return this;
|
|
295
|
+
}
|
|
296
|
+
_resetTimeout() {
|
|
297
|
+
this._clearTimeout();
|
|
298
|
+
if (this._timeout > 0) {
|
|
299
|
+
this._timeoutId = setTimeout(() => {
|
|
300
|
+
this.emit("timeout");
|
|
301
|
+
}, this._timeout);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
_clearTimeout() {
|
|
305
|
+
if (this._timeoutId !== null) {
|
|
306
|
+
clearTimeout(this._timeoutId);
|
|
307
|
+
this._timeoutId = null;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
/** Enable/disable TCP keep-alive. */
|
|
311
|
+
setKeepAlive(enable, _initialDelay) {
|
|
312
|
+
if (this._connection) {
|
|
313
|
+
try {
|
|
314
|
+
this._connection.get_socket().set_keepalive(enable ?? false);
|
|
315
|
+
} catch {}
|
|
316
|
+
}
|
|
317
|
+
return this;
|
|
318
|
+
}
|
|
319
|
+
/** Enable/disable TCP_NODELAY (disable Nagle algorithm). */
|
|
320
|
+
setNoDelay(noDelay) {
|
|
321
|
+
if (this._connection) {
|
|
322
|
+
try {
|
|
323
|
+
this._connection.get_socket().set_option(6, 1, noDelay !== false ? 1 : 0);
|
|
324
|
+
} catch {}
|
|
325
|
+
}
|
|
326
|
+
return this;
|
|
327
|
+
}
|
|
328
|
+
/** Half-close then destroy: end() if writable, destroy() once finished. */
|
|
329
|
+
destroySoon() {
|
|
330
|
+
if (this.writable) this.end();
|
|
331
|
+
if (this.writableFinished) this.destroy();
|
|
332
|
+
else this.once("finish", this.destroy.bind(this));
|
|
333
|
+
}
|
|
334
|
+
/** Get the underlying socket address info. */
|
|
335
|
+
address() {
|
|
336
|
+
if (this.localAddress && this.localPort) {
|
|
337
|
+
return {
|
|
338
|
+
port: this.localPort,
|
|
339
|
+
family: this.remoteFamily || "IPv4",
|
|
340
|
+
address: this.localAddress
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
return {};
|
|
344
|
+
}
|
|
345
|
+
/** Reference this socket (keep event loop alive). No-op in GJS. */
|
|
346
|
+
ref() {
|
|
347
|
+
return this;
|
|
348
|
+
}
|
|
349
|
+
/** Unreference this socket. No-op in GJS. */
|
|
350
|
+
unref() {
|
|
351
|
+
return this;
|
|
352
|
+
}
|
|
382
353
|
};
|
|
354
|
+
|
|
355
|
+
//#endregion
|
|
356
|
+
export { Socket };
|