@gjsify/net 0.3.13 → 0.3.15

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