
Security News
Axios Supply Chain Attack Reaches OpenAI macOS Signing Pipeline, Forces Certificate Rotation
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.
wsprocessor
Advanced tools
A lightweight processor for websocket connections, providing acknowledged messages, error handling and connection status monitoring. The same code runs on client and server.
A lightweight processor for websocket connections, providing acknowledged messages, error handling and connection status monitoring.
Written in pure javascript and without any dependency. The same code runs with any websocket implementation, e.g. ws for nodejs and the Websocket API in modern browsers.
The package can be downloaded from github or installed with npm:
npm install wsprocessor
There are mainly three files of interest:
Basically two kinds of messages can be sent with the wsProcessor:
wsProcessor.sendNote(note)): notify the receiver about something, as used e.g. for broadcasts.wsProcessor.sendRequest(request, successCB, failureCB)): request something from the receiver; a successful response will be handed over to successCB (successCB=(message)=>{}), while errors result in a call to failureCB (failureCB=(errCode, errMsg)=>{}) with distinct error codes.On the receiver, both kinds of messages are handled in their corresponding functions, which are provided to the constructor. The note callback only takes the message as a parameter. The request callback additionally provides the response function as it second parameter, which is to be called to send the response.
wsProcessor is independent of the actual websocket implementation and works as a layer between the application and the websocket connection. Therefore, the websocket connection is established outside the wsProcessor. All incoming messages shall then be directed to wsProcessor.onMessage(message). The wsProcessor processes the rawMessages and calls the note or request callback, respectively. To tell the wsProcessor how to send messages and close the connection, two functions (sendingFunc(message) and closingFunc()) must be provided to the constructor.
wsProcessor uses timeouts to raise errors when an answer to a message does not arrive within a certain period of time. By default, a request is deemed failed when there is no response within 10s. The default can be overriden separately for each request. Notes and requests provide the possibility for acknowledgements, which the answering party sends as soon as the note or request has arrived and before it is processed. the default timeout for note acknowledgements is 5s. It can be overriden for each separately for each request, response and note. By default, the request has no timeout for the acknowledgement, meaning that it times out together with the request itself.
To track the connection status, heartbeats (ping) are sent from time to time. The interval is given by the larger of opt.heartbeatMinInterval (default: 2s) and the product of the average round trip time (RTT) of the two last hearbeats and opt.heartbeatRttIntervalMultiplicator (default: 10). If the heartbeat (ping) is not responded (pong) within a certain period of time, the connection is deemed failed. The timeout is defined by the larger of opt.heartbeatMinTimeout (default: 10s) and the product of the average round trip time (RTT) of the two last hearbeats and heartbeatRttTimeoutMutiplicator.
If the connection gets closed, the failure callbacks of all hanging requests and notes are called with the corresponding error code and message.
NOTE: All error codes, parameters and options are well documented above every function in the code.
NOTE: A slightly more elaborate example can be found on github. It additionally provides an express server to deliver the browser code. On the browser, every request, response, note and log entry is displayed.
To react on incoming requests and notes, your code must provide handlers:
function requestHandler(request, responseFunc){
// ... process the request ...
// send the successful response (error code 0)
responseFunc('the response')
// OR an error:
responseFunc('The error message', errorCode)
}
function noteHandler(note){
// ... process the note ...
}
Optional: If the responder must know whether the response was successfully sent, an acknowledgement can be requested, which will then call the provided callback.:
opt = {
sendAck: true, // optional; default=false; Whether the request shall be acknowledged, i.e. cbAck callback is called with errCode=0 when the requestAck arrives.
ackTimeout: 5 // optional; default=5s; The duration in seconds to wait for an ack. If the ack did not yet arrive after this duration, the cbAck-callback is raised with code 1.
}
function cbAck(statusCode, statusMsg){
if (statusCode==0){
// ... response successfully arrived ...
} else {
// ... response not acknowledged
}
}
responseFunc(response, errorCode, opt, cbAck)
The websocket connection is established outside the wsProcessor. (The example uses ws for the Websocket server.) When the websocket connection is opened, create the wsProcessor. The constructor of the wsProcessor expects the two handler functions for requests and notes as well as a function for sending messages and a function to close the connection. Optionally, a logger function and an object with options can be provided.
const wsProcessor = require('wsprocessor')
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 3300 });
wss.on('connection', (ws)=>{
// required callbacks
let sendCB = (message)=>{
ws.send(message);
}
let closeCB = ()=>{
ws.close();
}
// optional:
let logger = (logLevel, msg)=>{
// see the definition of the log levels at the top of the code
// ... process the log messages here, eventually translate to your own codes ...
}
let opt = {
openOnConstruct: true, // optional; default=true; is the connection already open when the wsProcessor is created. If false, call wsProcessor.open() as soon as the connection is open.
heartbeatMinInterval: 2, // optional; default = 2; the minimum interval in seconds used for sending the heartbeats;
heartbeatRttIntervalMultiplicator: 10, // optional; default = 10; the minimum interval (as a multiplication with the current round trip time RTT from the last two heartbeats in seconds) used for sending the heartbeats;
heartbeatMinTimeout: 10, // optional; default = 10; the minimum time in seconds to wait for a pong, before the connection is deemed broken and is actively closed.
heartbeatRttTimeoutMutiplicator: 50 // optional; default = 50; the minimum time (as a multiplicator with the round-trip time RTT from the last two heartbeats in seconds) to wait for a pong, before the connection is deemed broken and is actively closed.
}
const processor = new wsProcessor(sendCB, closeCB, noteHandler, requestHandler, logger, opt); // the last two parameters are optional
ws.on('message', (message)=>{
processor.onMessage(message);
});
ws.on('close', ()=>{
processor.close();
})
})
The wsProcessor is included in the header:
<script src="/wsProcessorBrowser.min.js" type="text/javascript"></script>
Since the wsProcessor code is exactly the same as in nodejs, all the options mentioned above are valid in the browser as well. The following code provides a minimal exanmple on how to apply the wsProcessor in the browser. The main difference between ws for nodejs and the Websocket API in browsers is how the events (onConnection, onMessage, onClose, onError) are handled.
function requestHandler(request, responseFunc){
// ... process the request ...
// send the successful response (error code 0)
responseFunc('the response')
// OR an error:
responseFunc('The error message', errorCode)
}
function noteHandler(note){
// ... process the note ...
}
var processor;
var connection = new WebSocket("ws://localhost:3300");
let sendCB = (message)=>{connection.send(message);}
let closeCB = ()=>{connection.close();}
connection.onopen = (event)=>{
processor = new wsProcessor(sendCB, closeCB, noteHandler, requestHandler);
}
connection.onmessage = (mess)=>{processor.onMessage(mess.data);};
connection.onclose = (event)=>{processor.close();};
connection.onerror = (event)=>{processor.close();};
TCP:
WebSocket:
=> Based on those findings, the wsProcessor was created. Since there is (at least) no browser API that would expose ping/pong functionality, the wsProcessor implements its own heartbeats (ping/pong) to trace a connection loss.
FAQs
A lightweight processor for websocket connections, providing acknowledged messages, error handling and connection status monitoring. The same code runs on client and server.
We found that wsprocessor demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.

Security News
Open source is under attack because of how much value it creates. It has been the foundation of every major software innovation for the last three decades. This is not the time to walk away from it.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.