Skip to content

fix: Fix createServer() to properly handle Node.js-compatible options parameter #210

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions __tests__/index.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { expect, test } from '@jest/globals';

import net from '../src/index';

test('create-client', () => {
Expand All @@ -11,15 +12,36 @@ test('create-client', () => {
// interface: "wifi"
};

const socket = net.createConnection(options, () => {});
const socket = net.createConnection(options, () => { });
expect(socket).toBeInstanceOf(net.Socket);
});

test('create-server', () => {
const server = net.createServer(() => {});
const server = net.createServer(() => { });
expect(server).toBeInstanceOf(net.Server);
});

test('create-server-with-options', () => {
const server = net.createServer({
noDelay: true,
keepAlive: true
}, () => {
console.info('server started')
});
expect(server).toBeInstanceOf(net.Server);
});

test('create-server-options-no-calback', () => {
const server = net.createServer({
noDelay: true,
keepAlive: true
});
server.on('connection', () => {
console.info('connection received');
});
});


test('isIP', () => {
expect(net.isIP('127.9.8.9')).toBe(4);
expect(net.isIP('127.9.8..')).toBe(0);
Expand Down
70 changes: 52 additions & 18 deletions lib/types/Server.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
/**
* @typedef {object} ServerOptions
* @property {boolean} [noDelay]
* @property {boolean} [keepAlive]
* @property {number} [keepAliveInitialDelay]
* @property {boolean} [allowHalfOpen]
* @property {boolean} [pauseOnConnect]
*
* @typedef {import('./TLSSocket').default} TLSSocket
*
* @typedef {object} ServerEvents
Expand All @@ -12,22 +19,27 @@
*/
export default class Server extends EventEmitter<ServerEvents, any> {
/**
* @param {ServerOptions | ((socket: Socket) => void)} [options] Server options or connection listener
* @param {(socket: Socket) => void} [connectionCallback] Automatically set as a listener for the `'connection'` event.
*/
constructor(connectionCallback?: ((socket: Socket) => void) | undefined);
constructor(options?: ServerOptions | ((socket: Socket) => void), connectionCallback?: (socket: Socket) => void);

/** @protected @readonly */
protected readonly _id: number;
/** @protected @readonly */
protected readonly _eventEmitter: import("react-native").EventEmitter;
/** @private @type {Set<Socket>} */
private _connections;
private _connections: Set<Socket>;
/** @private */
private _localAddress;
private _localAddress: string | undefined;
/** @private */
private _localPort;
private _localPort: number | undefined;
/** @private */
private _localFamily;
private _localFamily: string | undefined;
/** @private */
private _serverOptions: ServerOptions;
listening: boolean;

/**
* Start a server listening for connections.
*
Expand All @@ -38,15 +50,15 @@ export default class Server extends EventEmitter<ServerEvents, any> {
* `server.listen()` call or `server.close()` has been called. Otherwise, an `ERR_SERVER_ALREADY_LISTEN`
* error will be thrown.
*
* @param {{ port: number; host: string; reuseAddress?: boolean}} options
* @param {{ port: number; host?: string; reuseAddress?: boolean} | number} options
* @param {string | (() => void)} [callback_or_host]
* @param {() => void} [callback]
* @returns {Server}
*/
listen(options: {
port: number;
host: string;
reuseAddress?: boolean;
}, callback?: (() => void) | undefined): Server;
listen(options: { port: number; host?: string; reuseAddress?: boolean } | number,
callback_or_host?: string | (() => void),
callback?: () => void): Server;

/**
* Asynchronously get the number of concurrent connections on the server.
*
Expand All @@ -56,6 +68,7 @@ export default class Server extends EventEmitter<ServerEvents, any> {
* @returns {Server}
*/
getConnections(callback: (err: Error | null, count: number) => void): Server;

/**
* Stops the server from accepting new connections and keeps existing connections.
* This function is asynchronous, the server is finally closed when all connections are ended and the server emits a `'close'` event.
Expand All @@ -65,7 +78,8 @@ export default class Server extends EventEmitter<ServerEvents, any> {
* @param {(err?: Error) => void} [callback] Called when the server is closed.
* @returns {Server}
*/
close(callback?: ((err?: Error | undefined) => void) | undefined): Server;
close(callback?: (err?: Error) => void): Server;

/**
* Returns the bound `address`, the address `family` name, and `port` of the server as reported by the operating system if listening
* on an IP socket (useful to find which port was assigned when getting an OS-assigned address):
Expand All @@ -74,24 +88,26 @@ export default class Server extends EventEmitter<ServerEvents, any> {
* @returns {import('./Socket').AddressInfo | null}
*/
address(): import('./Socket').AddressInfo | null;

ref(): Server;
unref(): Server;

/**
* @private
*/
private _registerEvents;
_listeningListener: import("react-native").EmitterSubscription | undefined;
_errorListener: import("react-native").EmitterSubscription | undefined;
_connectionsListener: import("react-native").EmitterSubscription | undefined;
private _registerEvents(): void;

/**
* @private
*/
private _setDisconnected;
private _setDisconnected(): void;

/**
* @protected
* @param {Socket} socket
*/
protected _addConnection(socket: Socket): void;

/**
* @protected
* @param {{ id: number; connection: import('./Socket').NativeConnectionInfo; }} info
Expand All @@ -101,14 +117,32 @@ export default class Server extends EventEmitter<ServerEvents, any> {
id: number;
connection: import('./Socket').NativeConnectionInfo;
}): Socket;

/**
* Apply server socket options to a newly connected socket
* @param {Socket} socket
* @private
*/
private _applySocketOptions(socket: Socket): void;
}

export type ServerOptions = {
noDelay?: boolean;
keepAlive?: boolean;
keepAliveInitialDelay?: number;
allowHalfOpen?: boolean;
pauseOnConnect?: boolean;
};

export type TLSSocket = import("./TLSSocket").default;

export type ServerEvents = {
close: () => void;
connection: (socket: Socket) => void;
listening: () => void;
error: (err: Error) => void;
secureConnection: (tlsSocket: TLSSocket) => void;
};

import EventEmitter from "eventemitter3";
import Socket from "./Socket";
import Socket from "./Socket";
41 changes: 32 additions & 9 deletions lib/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,49 @@ export default _default;
* @param {() => void} callback
* @returns {Socket}
*/
declare function createConnection(options: import('./Socket').ConnectionOptions, callback: () => void): Socket;
declare function createConnection(
options: import('./Socket').ConnectionOptions,
callback: () => void
): Socket;
/**
* @param {(socket: Socket) => void} connectionListener
* @typedef {object} ServerOptions
* @property {boolean} [noDelay]
* @property {boolean} [keepAlive]
* @property {number} [keepAliveInitialDelay]
* @property {boolean} [allowHalfOpen]
* @property {boolean} [pauseOnConnect]
*/

/**
* @param {ServerOptions | ((socket: Socket) => void)} [options]
* @param {(socket: Socket) => void} [connectionListener]
* @returns {Server}
*/
declare function createServer(connectionListener: (socket: Socket) => void): Server;
declare function createServer(
options?: object | ((socket: Socket) => void),
connectionListener?: (socket: Socket) => void
): Server;

/**
* @param {import('./TLSServer').TLSServerOptions} options
* @param {(socket: TLSSocket) => void} connectionListener
* @returns {TLSServer}
*/
declare function createTLSServer(options: import('./TLSServer').TLSServerOptions, connectionListener: (socket: TLSSocket) => void): TLSServer;
declare function createTLSServer(
options: import('./TLSServer').TLSServerOptions,
connectionListener: (socket: TLSSocket) => void
): TLSServer;
/**
* The `callback` function, if specified, will be added as a listener for the `'secureConnect'` event.
*
* @param {import('./TLSSocket').TLSSocketOptions & import('./Socket').ConnectionOptions} options
* @param {() => void} [callback]
* @returns {TLSSocket}
*/
declare function connectTLS(options: import('./TLSSocket').TLSSocketOptions & import('./Socket').ConnectionOptions, callback?: (() => void) | undefined): TLSSocket;
declare function connectTLS(
options: import('./TLSSocket').TLSSocketOptions & import('./Socket').ConnectionOptions,
callback?: (() => void) | undefined
): TLSSocket;
/**
* Tests if input is an IP address. Returns `0` for invalid strings, returns `4` for IP version 4 addresses, and returns `6` for IP version 6 addresses.
*
Expand All @@ -56,7 +79,7 @@ declare function isIPv4(input: string): boolean;
* @param {string} input
*/
declare function isIPv6(input: string): boolean;
import Server from "./Server";
import Socket from "./Socket";
import TLSServer from "./TLSServer";
import TLSSocket from "./TLSSocket";
import Server from './Server';
import Socket from './Socket';
import TLSServer from './TLSServer';
import TLSSocket from './TLSSocket';
Loading