react-native-nitro-net 0.1.5 → 0.3.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/README.md +122 -12
- package/android/libs/arm64-v8a/librust_c_net.so +0 -0
- package/android/libs/armeabi-v7a/librust_c_net.so +0 -0
- package/android/libs/x86/librust_c_net.so +0 -0
- package/android/libs/x86_64/librust_c_net.so +0 -0
- package/cpp/HybridHttpParser.hpp +67 -0
- package/cpp/HybridNetDriver.hpp +74 -0
- package/cpp/HybridNetServerDriver.hpp +16 -0
- package/cpp/HybridNetSocketDriver.hpp +176 -0
- package/cpp/NetBindings.hpp +67 -1
- package/ios/Frameworks/RustCNet.xcframework/ios-arm64/RustCNet.framework/RustCNet +0 -0
- package/ios/Frameworks/RustCNet.xcframework/ios-arm64_x86_64-simulator/RustCNet.framework/RustCNet +0 -0
- package/lib/Net.nitro.d.ts +46 -1
- package/lib/Net.nitro.js +3 -1
- package/lib/http.d.ts +203 -0
- package/lib/http.js +1138 -0
- package/lib/https.d.ts +24 -0
- package/lib/https.js +144 -0
- package/lib/index.d.ts +50 -11
- package/lib/index.js +179 -31
- package/lib/tls.d.ts +145 -0
- package/lib/tls.js +521 -0
- package/nitrogen/generated/android/RustCNet+autolinking.cmake +2 -0
- package/nitrogen/generated/android/RustCNetOnLoad.cpp +2 -0
- package/nitrogen/generated/android/c++/JHybridHttpParserSpec.cpp +54 -0
- package/nitrogen/generated/android/c++/JHybridHttpParserSpec.hpp +65 -0
- package/nitrogen/generated/android/c++/JHybridNetDriverSpec.cpp +47 -1
- package/nitrogen/generated/android/c++/JHybridNetDriverSpec.hpp +9 -0
- package/nitrogen/generated/android/c++/JHybridNetServerDriverSpec.cpp +8 -0
- package/nitrogen/generated/android/c++/JHybridNetServerDriverSpec.hpp +2 -0
- package/nitrogen/generated/android/c++/JHybridNetSocketDriverSpec.cpp +79 -0
- package/nitrogen/generated/android/c++/JHybridNetSocketDriverSpec.hpp +17 -0
- package/nitrogen/generated/android/c++/JNetConfig.hpp +7 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/HybridHttpParserSpec.kt +58 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/HybridNetDriverSpec.kt +37 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/HybridNetServerDriverSpec.kt +8 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/HybridNetSocketDriverSpec.kt +68 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/NetConfig.kt +6 -3
- package/nitrogen/generated/ios/RustCNet-Swift-Cxx-Bridge.cpp +17 -0
- package/nitrogen/generated/ios/RustCNet-Swift-Cxx-Bridge.hpp +118 -41
- package/nitrogen/generated/ios/RustCNet-Swift-Cxx-Umbrella.hpp +5 -0
- package/nitrogen/generated/ios/c++/HybridHttpParserSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridHttpParserSpecSwift.hpp +79 -0
- package/nitrogen/generated/ios/c++/HybridNetDriverSpecSwift.hpp +69 -0
- package/nitrogen/generated/ios/c++/HybridNetServerDriverSpecSwift.hpp +12 -0
- package/nitrogen/generated/ios/c++/HybridNetSocketDriverSpecSwift.hpp +123 -0
- package/nitrogen/generated/ios/swift/HybridHttpParserSpec.swift +56 -0
- package/nitrogen/generated/ios/swift/HybridHttpParserSpec_cxx.swift +131 -0
- package/nitrogen/generated/ios/swift/HybridNetDriverSpec.swift +9 -0
- package/nitrogen/generated/ios/swift/HybridNetDriverSpec_cxx.swift +133 -0
- package/nitrogen/generated/ios/swift/HybridNetServerDriverSpec.swift +2 -0
- package/nitrogen/generated/ios/swift/HybridNetServerDriverSpec_cxx.swift +36 -0
- package/nitrogen/generated/ios/swift/HybridNetSocketDriverSpec.swift +17 -0
- package/nitrogen/generated/ios/swift/HybridNetSocketDriverSpec_cxx.swift +314 -0
- package/nitrogen/generated/ios/swift/NetConfig.swift +19 -1
- package/nitrogen/generated/shared/c++/HybridHttpParserSpec.cpp +21 -0
- package/nitrogen/generated/shared/c++/HybridHttpParserSpec.hpp +63 -0
- package/nitrogen/generated/shared/c++/HybridNetDriverSpec.cpp +9 -0
- package/nitrogen/generated/shared/c++/HybridNetDriverSpec.hpp +13 -0
- package/nitrogen/generated/shared/c++/HybridNetServerDriverSpec.cpp +2 -0
- package/nitrogen/generated/shared/c++/HybridNetServerDriverSpec.hpp +2 -0
- package/nitrogen/generated/shared/c++/HybridNetSocketDriverSpec.cpp +17 -0
- package/nitrogen/generated/shared/c++/HybridNetSocketDriverSpec.hpp +18 -0
- package/nitrogen/generated/shared/c++/NetConfig.hpp +6 -2
- package/package.json +7 -5
- package/react-native-nitro-net.podspec +1 -3
- package/src/Net.nitro.ts +44 -1
- package/src/http.ts +1304 -0
- package/src/https.ts +127 -0
- package/src/index.ts +167 -27
- package/src/tls.ts +608 -0
package/src/https.ts
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import * as http from './http'
|
|
2
|
+
import * as tls from './tls'
|
|
3
|
+
import { Driver } from './Driver'
|
|
4
|
+
import { Buffer } from 'react-native-nitro-buffer'
|
|
5
|
+
import { IncomingMessage } from './http'
|
|
6
|
+
|
|
7
|
+
// ========== Server ==========
|
|
8
|
+
|
|
9
|
+
export class Server extends tls.Server {
|
|
10
|
+
private _httpConnections = new Set<any>();
|
|
11
|
+
public maxHeaderSize: number = 16384;
|
|
12
|
+
public maxRequestsPerSocket: number = 0;
|
|
13
|
+
public headersTimeout: number = 60000;
|
|
14
|
+
public requestTimeout: number = 300000;
|
|
15
|
+
public keepAliveTimeout: number = 5000;
|
|
16
|
+
|
|
17
|
+
constructor(options?: any, requestListener?: (req: http.IncomingMessage, res: http.ServerResponse) => void) {
|
|
18
|
+
if (typeof options === 'function') {
|
|
19
|
+
requestListener = options;
|
|
20
|
+
options = {};
|
|
21
|
+
}
|
|
22
|
+
super(options);
|
|
23
|
+
|
|
24
|
+
if (requestListener) {
|
|
25
|
+
this.on('request', requestListener);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Initialize HTTP connection setup for secure connections
|
|
29
|
+
this.on('secureConnection', (socket: any) => {
|
|
30
|
+
// @ts-ignore - access internal http logic
|
|
31
|
+
(http.Server.prototype as any)._setupHttpConnection.call(this, socket);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public setTimeout(ms: number, callback?: () => void): this {
|
|
36
|
+
// @ts-ignore - access netServer via super's internal or cast
|
|
37
|
+
(this as any)._netServer.setTimeout(ms, callback);
|
|
38
|
+
return this;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function createServer(options?: any, requestListener?: (req: http.IncomingMessage, res: http.ServerResponse) => void): Server {
|
|
43
|
+
return new Server(options, requestListener);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ========== ClientRequest ==========
|
|
47
|
+
|
|
48
|
+
export class ClientRequest extends http.ClientRequest {
|
|
49
|
+
constructor(options: any, callback?: (res: http.IncomingMessage) => void) {
|
|
50
|
+
if (typeof options === 'string') {
|
|
51
|
+
options = new URL(options);
|
|
52
|
+
}
|
|
53
|
+
if (options instanceof URL) {
|
|
54
|
+
options = {
|
|
55
|
+
protocol: options.protocol,
|
|
56
|
+
hostname: options.hostname,
|
|
57
|
+
path: options.pathname + options.search,
|
|
58
|
+
port: options.port ? parseInt(options.port) : 443
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
options.protocol = 'https:';
|
|
62
|
+
super(options, callback);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function request(
|
|
67
|
+
urlOrOptions: string | URL | http.RequestOptions,
|
|
68
|
+
optionsOrCallback?: http.RequestOptions | ((res: http.IncomingMessage) => void),
|
|
69
|
+
callback?: (res: http.IncomingMessage) => void
|
|
70
|
+
): ClientRequest {
|
|
71
|
+
let opts: http.RequestOptions = {};
|
|
72
|
+
let cb: ((res: http.IncomingMessage) => void) | undefined = callback;
|
|
73
|
+
|
|
74
|
+
if (typeof urlOrOptions === 'string') {
|
|
75
|
+
const url = new URL(urlOrOptions);
|
|
76
|
+
opts = {
|
|
77
|
+
protocol: url.protocol,
|
|
78
|
+
hostname: url.hostname,
|
|
79
|
+
path: url.pathname + url.search,
|
|
80
|
+
port: url.port ? parseInt(url.port) : 443
|
|
81
|
+
};
|
|
82
|
+
} else if (urlOrOptions instanceof URL) {
|
|
83
|
+
opts = {
|
|
84
|
+
protocol: urlOrOptions.protocol,
|
|
85
|
+
hostname: urlOrOptions.hostname,
|
|
86
|
+
path: urlOrOptions.pathname + urlOrOptions.search,
|
|
87
|
+
port: urlOrOptions.port ? parseInt(urlOrOptions.port) : 443
|
|
88
|
+
};
|
|
89
|
+
} else {
|
|
90
|
+
opts = { ...urlOrOptions };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (typeof optionsOrCallback === 'function') {
|
|
94
|
+
cb = optionsOrCallback;
|
|
95
|
+
} else if (optionsOrCallback) {
|
|
96
|
+
opts = { ...opts, ...optionsOrCallback };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
opts.protocol = 'https:';
|
|
100
|
+
return new ClientRequest(opts, cb);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function get(
|
|
104
|
+
urlOrOptions: string | URL | http.RequestOptions,
|
|
105
|
+
optionsOrCallback?: http.RequestOptions | ((res: http.IncomingMessage) => void),
|
|
106
|
+
callback?: (res: http.IncomingMessage) => void
|
|
107
|
+
): ClientRequest {
|
|
108
|
+
const req = request(urlOrOptions, optionsOrCallback, callback);
|
|
109
|
+
req.end();
|
|
110
|
+
return req;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ========== Agent ==========
|
|
114
|
+
|
|
115
|
+
export class Agent extends http.Agent {
|
|
116
|
+
constructor(options?: any) {
|
|
117
|
+
super(options);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export const globalAgent = new Agent({
|
|
122
|
+
keepAlive: true,
|
|
123
|
+
scheduling: 'lifo',
|
|
124
|
+
timeout: 5000,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
export { IncomingMessage };
|
package/src/index.ts
CHANGED
|
@@ -33,16 +33,21 @@ let _autoSelectFamilyDefault = 4; // Node default is usually 4/6 independent, bu
|
|
|
33
33
|
let _isVerbose = false;
|
|
34
34
|
let _isInitialized = false;
|
|
35
35
|
|
|
36
|
-
function
|
|
37
|
-
|
|
38
|
-
console.log(`[NET DEBUG] ${message}`);
|
|
39
|
-
}
|
|
36
|
+
function isVerbose(): boolean {
|
|
37
|
+
return _isVerbose;
|
|
40
38
|
}
|
|
41
39
|
|
|
42
40
|
function setVerbose(enabled: boolean): void {
|
|
43
41
|
_isVerbose = enabled;
|
|
44
42
|
}
|
|
45
43
|
|
|
44
|
+
function debugLog(message: string) {
|
|
45
|
+
if (_isVerbose) {
|
|
46
|
+
const timestamp = new Date().toISOString().split('T')[1].split('Z')[0];
|
|
47
|
+
console.log(`[NET DEBUG ${timestamp}] ${message}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
46
51
|
function getDefaultAutoSelectFamily(): number {
|
|
47
52
|
return _autoSelectFamilyDefault;
|
|
48
53
|
}
|
|
@@ -79,6 +84,9 @@ function ensureInitialized(): void {
|
|
|
79
84
|
*/
|
|
80
85
|
function initWithConfig(config: NetConfig): void {
|
|
81
86
|
_isInitialized = true;
|
|
87
|
+
if (config.debug !== undefined) {
|
|
88
|
+
setVerbose(config.debug);
|
|
89
|
+
}
|
|
82
90
|
Driver.initWithConfig(config);
|
|
83
91
|
}
|
|
84
92
|
|
|
@@ -89,17 +97,69 @@ function initWithConfig(config: NetConfig): void {
|
|
|
89
97
|
// SocketAddress
|
|
90
98
|
// -----------------------------------------------------------------------------
|
|
91
99
|
|
|
100
|
+
export interface SocketAddressOptions {
|
|
101
|
+
address?: string;
|
|
102
|
+
family?: 'ipv4' | 'ipv6';
|
|
103
|
+
port?: number;
|
|
104
|
+
flowlabel?: number;
|
|
105
|
+
}
|
|
106
|
+
|
|
92
107
|
export class SocketAddress {
|
|
93
108
|
readonly address: string;
|
|
94
109
|
readonly family: 'ipv4' | 'ipv6';
|
|
95
110
|
readonly port: number;
|
|
96
111
|
readonly flowlabel: number;
|
|
97
112
|
|
|
98
|
-
constructor(options:
|
|
99
|
-
this.address = options.address;
|
|
100
|
-
this.family = options.family || (isIPv6(
|
|
101
|
-
this.port = options.port;
|
|
102
|
-
this.flowlabel = options.flowlabel
|
|
113
|
+
constructor(options: SocketAddressOptions = {}) {
|
|
114
|
+
this.address = options.address ?? (options.family === 'ipv6' ? '::' : '127.0.0.1');
|
|
115
|
+
this.family = options.family || (isIPv6(this.address) ? 'ipv6' : 'ipv4');
|
|
116
|
+
this.port = options.port ?? 0;
|
|
117
|
+
this.flowlabel = options.flowlabel ?? 0;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Attempts to parse a string containing a socket address.
|
|
122
|
+
* Returns a SocketAddress if successful, or undefined if not.
|
|
123
|
+
*
|
|
124
|
+
* Supported formats:
|
|
125
|
+
* - `ip:port` (e.g., `127.0.0.1:8080`, `[::1]:8080`)
|
|
126
|
+
* - `ip` only (port defaults to 0)
|
|
127
|
+
*/
|
|
128
|
+
static parse(input: string): SocketAddress | undefined {
|
|
129
|
+
if (!input || typeof input !== 'string') return undefined;
|
|
130
|
+
let address: string;
|
|
131
|
+
let port = 0;
|
|
132
|
+
|
|
133
|
+
// Handle IPv6 bracket notation: [::1]:port
|
|
134
|
+
const ipv6Match = input.match(/^\[([^\]]+)\]:?(\d*)$/);
|
|
135
|
+
if (ipv6Match) {
|
|
136
|
+
address = ipv6Match[1];
|
|
137
|
+
port = ipv6Match[2] ? parseInt(ipv6Match[2], 10) : 0;
|
|
138
|
+
if (!isIPv6(address)) return undefined;
|
|
139
|
+
return new SocketAddress({ address, port, family: 'ipv6' });
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Handle IPv4 or IPv6 without brackets
|
|
143
|
+
const lastColon = input.lastIndexOf(':');
|
|
144
|
+
if (lastColon === -1) {
|
|
145
|
+
// No port, just IP
|
|
146
|
+
address = input;
|
|
147
|
+
} else {
|
|
148
|
+
// Determine if the colon is a port separator or part of IPv6
|
|
149
|
+
const potentialPort = input.slice(lastColon + 1);
|
|
150
|
+
const potentialAddr = input.slice(0, lastColon);
|
|
151
|
+
if (/^\d+$/.test(potentialPort) && (isIPv4(potentialAddr) || isIPv6(potentialAddr))) {
|
|
152
|
+
address = potentialAddr;
|
|
153
|
+
port = parseInt(potentialPort, 10);
|
|
154
|
+
} else {
|
|
155
|
+
// It's an IPv6 address without port
|
|
156
|
+
address = input;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const family = isIPv6(address) ? 'ipv6' : (isIPv4(address) ? 'ipv4' : undefined);
|
|
161
|
+
if (!family) return undefined;
|
|
162
|
+
return new SocketAddress({ address, port, family });
|
|
103
163
|
}
|
|
104
164
|
}
|
|
105
165
|
|
|
@@ -107,9 +167,31 @@ export class SocketAddress {
|
|
|
107
167
|
// BlockList
|
|
108
168
|
// -----------------------------------------------------------------------------
|
|
109
169
|
|
|
170
|
+
export interface BlockListRule {
|
|
171
|
+
type: 'address' | 'range' | 'subnet';
|
|
172
|
+
address?: string;
|
|
173
|
+
start?: string;
|
|
174
|
+
end?: string;
|
|
175
|
+
prefix?: number;
|
|
176
|
+
family: 'ipv4' | 'ipv6';
|
|
177
|
+
}
|
|
178
|
+
|
|
110
179
|
export class BlockList {
|
|
111
180
|
private _rules: Array<{ type: 'address' | 'range' | 'subnet', data: any }> = [];
|
|
112
181
|
|
|
182
|
+
/** Returns an array of rules added to the blocklist. */
|
|
183
|
+
get rules(): BlockListRule[] {
|
|
184
|
+
return this._rules.map(r => {
|
|
185
|
+
if (r.type === 'address') {
|
|
186
|
+
return { type: 'address' as const, address: r.data.address, family: r.data.family };
|
|
187
|
+
} else if (r.type === 'range') {
|
|
188
|
+
return { type: 'range' as const, start: r.data.start, end: r.data.end, family: r.data.family };
|
|
189
|
+
} else {
|
|
190
|
+
return { type: 'subnet' as const, address: r.data.net, prefix: r.data.prefix, family: r.data.family };
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
113
195
|
addAddress(address: string, family?: 'ipv4' | 'ipv6'): void {
|
|
114
196
|
this._rules.push({ type: 'address', data: { address, family: family || (isIPv6(address) ? 'ipv6' : 'ipv4') } });
|
|
115
197
|
}
|
|
@@ -143,6 +225,37 @@ export class BlockList {
|
|
|
143
225
|
}
|
|
144
226
|
return false;
|
|
145
227
|
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Serializes the BlockList to a JSON-compatible format.
|
|
231
|
+
*/
|
|
232
|
+
toJSON(): BlockListRule[] {
|
|
233
|
+
return this.rules;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Creates a BlockList from a JSON array of rules.
|
|
238
|
+
*/
|
|
239
|
+
static fromJSON(json: BlockListRule[]): BlockList {
|
|
240
|
+
const list = new BlockList();
|
|
241
|
+
for (const rule of json) {
|
|
242
|
+
if (rule.type === 'address' && rule.address) {
|
|
243
|
+
list.addAddress(rule.address, rule.family);
|
|
244
|
+
} else if (rule.type === 'range' && rule.start && rule.end) {
|
|
245
|
+
list.addRange(rule.start, rule.end, rule.family);
|
|
246
|
+
} else if (rule.type === 'subnet' && rule.address && rule.prefix !== undefined) {
|
|
247
|
+
list.addSubnet(rule.address, rule.prefix, rule.family);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return list;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Checks if a given value is a BlockList instance.
|
|
255
|
+
*/
|
|
256
|
+
static isBlockList(value: unknown): value is BlockList {
|
|
257
|
+
return value instanceof BlockList;
|
|
258
|
+
}
|
|
146
259
|
}
|
|
147
260
|
|
|
148
261
|
function ipv4ToLong(ip: string): number {
|
|
@@ -165,10 +278,10 @@ export interface SocketOptions extends DuplexOptions {
|
|
|
165
278
|
}
|
|
166
279
|
|
|
167
280
|
export class Socket extends Duplex {
|
|
168
|
-
|
|
281
|
+
protected _driver: NetSocketDriver | undefined;
|
|
169
282
|
public connecting: boolean = false; // Changed from private _connecting
|
|
170
|
-
|
|
171
|
-
|
|
283
|
+
protected _connected: boolean = false;
|
|
284
|
+
protected _hadError: boolean = false; // Added
|
|
172
285
|
public remoteAddress?: string;
|
|
173
286
|
public remotePort?: number;
|
|
174
287
|
public remoteFamily?: string;
|
|
@@ -178,6 +291,7 @@ export class Socket extends Duplex {
|
|
|
178
291
|
public bytesWritten: number = 0;
|
|
179
292
|
public autoSelectFamilyAttemptedAddresses: string[] = [];
|
|
180
293
|
private _autoSelectFamily: boolean = false;
|
|
294
|
+
private _timeout: number = 0;
|
|
181
295
|
|
|
182
296
|
get localFamily(): string {
|
|
183
297
|
return this.localAddress && this.localAddress.includes(':') ? 'IPv6' : 'IPv4';
|
|
@@ -203,7 +317,9 @@ export class Socket extends Duplex {
|
|
|
203
317
|
super({
|
|
204
318
|
allowHalfOpen: options?.allowHalfOpen ?? false,
|
|
205
319
|
readable: options?.readable ?? true,
|
|
206
|
-
writable: options?.writable ?? true
|
|
320
|
+
writable: options?.writable ?? true,
|
|
321
|
+
// @ts-ignore
|
|
322
|
+
autoDestroy: false
|
|
207
323
|
});
|
|
208
324
|
|
|
209
325
|
if (options?.socketDriver) {
|
|
@@ -211,6 +327,8 @@ export class Socket extends Duplex {
|
|
|
211
327
|
this._driver = options.socketDriver;
|
|
212
328
|
this._connected = true;
|
|
213
329
|
this._setupEvents();
|
|
330
|
+
// Enable noDelay by default
|
|
331
|
+
this._driver.setNoDelay(true);
|
|
214
332
|
// Resume the socket since it starts paused on server-accept
|
|
215
333
|
this.resume();
|
|
216
334
|
// Emit connect for server-side socket? No, it's already connected.
|
|
@@ -219,8 +337,10 @@ export class Socket extends Duplex {
|
|
|
219
337
|
ensureInitialized();
|
|
220
338
|
this._driver = Driver.createSocket();
|
|
221
339
|
this._setupEvents();
|
|
222
|
-
//
|
|
223
|
-
this.
|
|
340
|
+
// Enable noDelay by default to match Node.js and reduce latency for small writes
|
|
341
|
+
this._driver.setNoDelay(true);
|
|
342
|
+
// Do NOT resume here - socket is not connected yet!
|
|
343
|
+
// resume() will be called after 'connect' event in _connect()
|
|
224
344
|
}
|
|
225
345
|
|
|
226
346
|
this.on('finish', () => {
|
|
@@ -245,13 +365,14 @@ export class Socket extends Duplex {
|
|
|
245
365
|
if (!this._driver) return;
|
|
246
366
|
const id = (this._driver as any).id ?? (this._driver as any)._id;
|
|
247
367
|
this._driver.onEvent = (eventType: number, data: ArrayBuffer) => {
|
|
368
|
+
this.emit('event', eventType, data);
|
|
248
369
|
if (eventType === 3) { // ERROR
|
|
249
370
|
const msg = new TextDecoder().decode(data);
|
|
250
371
|
debugLog(`Socket (id: ${id}) NATIVE ERROR: ${msg}`);
|
|
251
372
|
}
|
|
252
|
-
if (eventType === 9) { // DEBUG
|
|
253
|
-
|
|
254
|
-
|
|
373
|
+
if (eventType === 9) { // SESSION/DEBUG
|
|
374
|
+
debugLog(`Socket (id: ${id}) NATIVE SESSION EVENT RECEIVED`);
|
|
375
|
+
this.emit('session', data);
|
|
255
376
|
return;
|
|
256
377
|
}
|
|
257
378
|
debugLog(`Socket (id: ${id}, localPort: ${this.localPort}) Event TYPE: ${eventType}, data len: ${data?.byteLength}`);
|
|
@@ -260,6 +381,8 @@ export class Socket extends Duplex {
|
|
|
260
381
|
this.connecting = false;
|
|
261
382
|
this._connected = true;
|
|
262
383
|
this._updateAddresses();
|
|
384
|
+
// Now that we're connected, start receiving data
|
|
385
|
+
this.resume();
|
|
263
386
|
this.emit('connect');
|
|
264
387
|
this.emit('ready');
|
|
265
388
|
break;
|
|
@@ -408,6 +531,7 @@ export class Socket extends Duplex {
|
|
|
408
531
|
this._autoSelectFamily = true;
|
|
409
532
|
}
|
|
410
533
|
|
|
534
|
+
debugLog(`Socket.connect: target=${host}:${port}, autoSelectFamily=${this._autoSelectFamily}`);
|
|
411
535
|
return this._connect(port, host, connectionListener, options.signal);
|
|
412
536
|
}
|
|
413
537
|
|
|
@@ -430,6 +554,7 @@ export class Socket extends Duplex {
|
|
|
430
554
|
this.once('close', () => signal.removeEventListener('abort', abortHandler));
|
|
431
555
|
}
|
|
432
556
|
|
|
557
|
+
debugLog(`Socket._connect: Calling driver.connect(${host}, ${port})`);
|
|
433
558
|
this._driver?.connect(host, port);
|
|
434
559
|
return this;
|
|
435
560
|
}
|
|
@@ -510,6 +635,7 @@ export class Socket extends Duplex {
|
|
|
510
635
|
|
|
511
636
|
// Standard net.Socket methods
|
|
512
637
|
setTimeout(msecs: number, callback?: () => void): this {
|
|
638
|
+
this._timeout = msecs;
|
|
513
639
|
if (this._driver) {
|
|
514
640
|
this._driver.setTimeout(msecs);
|
|
515
641
|
}
|
|
@@ -533,12 +659,13 @@ export class Socket extends Duplex {
|
|
|
533
659
|
* Resume reading after a call to pause().
|
|
534
660
|
*/
|
|
535
661
|
resume(): this {
|
|
536
|
-
const
|
|
537
|
-
|
|
662
|
+
const driver = this._driver as any;
|
|
663
|
+
const id = driver?.id;
|
|
664
|
+
debugLog(`Socket.resume() called, id: ${id === undefined ? 'none' : id}, destroyed: ${this.destroyed}`);
|
|
538
665
|
super.resume();
|
|
539
|
-
if (
|
|
666
|
+
if (driver) {
|
|
540
667
|
debugLog(`Socket.resume() calling driver.resume(), id: ${id}`);
|
|
541
|
-
|
|
668
|
+
driver.resume();
|
|
542
669
|
}
|
|
543
670
|
return this;
|
|
544
671
|
}
|
|
@@ -568,8 +695,8 @@ export class Socket extends Duplex {
|
|
|
568
695
|
return this;
|
|
569
696
|
}
|
|
570
697
|
|
|
571
|
-
get timeout(): number
|
|
572
|
-
return
|
|
698
|
+
get timeout(): number {
|
|
699
|
+
return this._timeout;
|
|
573
700
|
}
|
|
574
701
|
|
|
575
702
|
get bufferSize(): number {
|
|
@@ -705,8 +832,8 @@ export class Server extends EventEmitter {
|
|
|
705
832
|
this.emit('error', new Error(data ? Buffer.from(data).toString() : 'Unknown server error'));
|
|
706
833
|
break;
|
|
707
834
|
case NetServerEvent.DEBUG: {
|
|
708
|
-
|
|
709
|
-
|
|
835
|
+
debugLog(`Server NATIVE SESSION/DEBUG EVENT RECEIVED`);
|
|
836
|
+
this.emit('session', data);
|
|
710
837
|
break;
|
|
711
838
|
}
|
|
712
839
|
case NetServerEvent.CLOSE:
|
|
@@ -726,7 +853,6 @@ export class Server extends EventEmitter {
|
|
|
726
853
|
this.close(() => resolve());
|
|
727
854
|
});
|
|
728
855
|
}
|
|
729
|
-
|
|
730
856
|
listen(port?: any, host?: any, backlog?: any, callback?: any): this {
|
|
731
857
|
let _port = 0;
|
|
732
858
|
let _host: string | undefined;
|
|
@@ -797,6 +923,13 @@ export class Server extends EventEmitter {
|
|
|
797
923
|
}
|
|
798
924
|
|
|
799
925
|
close(callback?: (err?: Error) => void): this {
|
|
926
|
+
// Destroy all active connections first
|
|
927
|
+
for (const socket of this._sockets) {
|
|
928
|
+
socket.destroy();
|
|
929
|
+
}
|
|
930
|
+
this._sockets.clear();
|
|
931
|
+
this._connections = 0;
|
|
932
|
+
|
|
800
933
|
this._driver.close();
|
|
801
934
|
if (callback) this.once('close', callback);
|
|
802
935
|
return this;
|
|
@@ -840,12 +973,17 @@ export function createServer(options?: any, connectionListener?: (socket: Socket
|
|
|
840
973
|
return new Server(options, connectionListener);
|
|
841
974
|
}
|
|
842
975
|
|
|
976
|
+
export * as tls from './tls'
|
|
977
|
+
export * as http from './http'
|
|
978
|
+
export * as https from './https'
|
|
979
|
+
|
|
843
980
|
export {
|
|
844
981
|
isIP,
|
|
845
982
|
isIPv4,
|
|
846
983
|
isIPv6,
|
|
847
984
|
getDefaultAutoSelectFamily,
|
|
848
985
|
setDefaultAutoSelectFamily,
|
|
986
|
+
isVerbose,
|
|
849
987
|
setVerbose,
|
|
850
988
|
initWithConfig,
|
|
851
989
|
};
|
|
@@ -867,4 +1005,6 @@ export default {
|
|
|
867
1005
|
setDefaultAutoSelectFamily,
|
|
868
1006
|
setVerbose,
|
|
869
1007
|
initWithConfig,
|
|
1008
|
+
http: require('./http'),
|
|
1009
|
+
https: require('./https'),
|
|
870
1010
|
};
|