Skip to content

Instantly share code, notes, and snippets.

@tommelo
Last active June 8, 2022 22:57
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tommelo/1af033ca38b442359fb006d8813f14bb to your computer and use it in GitHub Desktop.
Save tommelo/1af033ca38b442359fb006d8813f14bb to your computer and use it in GitHub Desktop.
Promisify net.Socket
const { connect } = require('./socket');
async function asyncSocket() {
let socket;
try {
socket = await connect('localhost', 3000, 30);
await socket.write('ping');
const message = await socket.recv();
console.log(message); // "pong"
} catch(e) {
console.error(e);
} finally {
if(socket) socket.close();
}
}
const { EOL } = require('os');
const { createConnection } = require('net');
const SocketError = {
IDLE_TIMEOUT: 'IDLE_TIMEOUT',
TRANSMISSION_ERROR: 'TRANSMISSION_ERROR',
CONNECTION_CLOSED: 'CONNECTION_CLOSED'
};
/**
* Creates a function to handle the socket 'close' event.
* Receiving a close event while reading or writing
* to the remote server could be a transmission error
* or the remote server terminating the connection.
*
* @param {Function} reject the reject handler
* @returns {Function} callback the calback function
*/
const onCloseEvent = reject => error => reject(
error
? { code: SocketError.TRANSMISSION_ERROR }
: { code: SocketError.CONNECTION_CLOSED }
);
/**
* Creates a function to handle idle timeouts.
*
* @param {Function} reject the reject handler
* @returns {Function} callback the calback function
*/
const onTimeoutEvent = reject => () => reject({ code: SocketError.IDLE_TIMEOUT });
/**
* Creates a function to handle write results.
*
* @param {Function} reject handler function for write failures
* @returns {Function} callback the calback function
*/
const onWriteEvent = (resolve, reject) => error => error ? reject(error) : resolve();
/**
* Creates a function to handle 'data' events.
* The promise will be fulfilled(resolve method) whenever
* the remote host send a end of line.
*
* @param {Function} resolve handler function for successful reads
* @returns {Function} callback the calback function
*/
const onDataEvent = resolve => {
const messages = [];
return data => {
const message = data.toString();
messages.push(message);
if (EOL === message.slice(-1))
resolve(messages.join(""));
}
}
/**
* Creates a socket connection with the given remote host.
* The function creates a net.Socket wrapper object that
* enables using async/await on read/write operations instead
* of listening for data or error events.
*
* @param {string} host The remote host
* @param {number} port Port number
* @param {number} timeout Idle timeout in seconds
* @returns {Promise} promise A promise object that resolves into a net.Socket
* wrapper with only read, write and close operations when
* the promise is fulfilled.
* In case of connection errors, the promise will be rejected.
*/
function connect(host, port, timeout) {
const connection = createConnection({ host, port, timeout: timeout * 1000 });
/**
* net.Socket wrapper containing only
* write, read and close functions.
*/
const socket = Object.freeze({
/**
* Writes to the remote host.
*
* @param {string} message message to be sent
* @returns {Promise} promise promise object
*/
write: message => new Promise((resolve, reject) => {
connection.removeAllListeners('data');
connection.once('close', onCloseEvent(reject));
connection.write(message, onWriteEvent(resolve, reject));
}),
/**
* Reads from the remote host.
*
* @returns {Promise} promise promise object
*/
recv: () => new Promise((resolve, reject) => {
connection.once('timeout', onTimeoutEvent(reject));
connection.once('close', onCloseEvent(reject));
connection.on('data', onDataEvent(resolve));
}),
/**
* Closes the socket connection
*/
close: () => connection.destroy()
});
return new Promise((resolve, reject) => {
connection.once('error', e => reject(e));
connection.once('ready', () => resolve(socket));
});
}
module.exports = { connect };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment