WebSocket client
A WebSocket client uses an LWSContext with no listening port and a
protocol that implements the client-side callbacks. The connection
is opened with ctx.clientConnect(url, info).
Minimal client
import { LWSContext, toString } from 'lws';
const ctx = new LWSContext({
protocols: [{
name: 'ws',
onClientEstablished(wsi) { wsi.write('hello'); },
onClientReceive(wsi, data) { console.log('recv', toString(data)); },
onClientClosed(wsi) { ctx.cancelService(); },
onClientConnectionError(wsi, msg) { console.error('fail', msg); ctx.cancelService(); },
}],
});
ctx.clientConnect('wss://echo.websocket.events/');The URI scheme:
ws:///wss://→ WebSockethttp:///https://→ HTTP (methoddefaults toGET)
For wss:// / https://, qjs-lws sets a permissive default
ssl_connection mask (see tls.md).
Subprotocols
ctx.clientConnect('wss://example.com/socket', {
protocol: 'chat,v2', // Sec-WebSocket-Protocol header
localProtocolName: 'ws', // which JS protocol handles the wsi
});localProtocolName selects the JS protocol descriptor by name. If
omitted, libwebsockets picks one based on the wsi role.
Connection info object
If you skip the URI-string form, pass an info object:
ctx.clientConnect({
address: 'example.com',
port: 443,
path: '/ws',
host: 'example.com',
origin: 'https://example.com',
protocol: 'chat',
localProtocolName: 'ws',
ssl: true,
authUsername: 'user',
authPassword: 'pass',
iface: 'eth0',
localPort: 12345,
alpn: 'h2,http/1.1',
keepWarmSecs: 30,
});See LWSContext.md for the full list.
Writing
{
name: 'ws',
onClientEstablished(wsi) {
this.queue = ['ping', 'how are you?'];
wsi.wantWrite();
},
onClientWriteable(wsi) {
const msg = this.queue.shift();
if(msg !== undefined) wsi.write(msg);
if(this.queue.length) wsi.wantWrite();
},
}Sending custom handshake headers
onClientAppendHandshakeHeader(wsi, buf, len) lets you inject
headers right before the upgrade request is sent:
import { WSI_TOKEN_HTTP_USER_AGENT, WSI_TOKEN_HTTP_COOKIE } from 'lws';
{
name: 'ws',
onClientAppendHandshakeHeader(wsi, buf, len) {
wsi.addHeader(WSI_TOKEN_HTTP_USER_AGENT, 'qjs-lws/1.0', buf, len);
wsi.addHeader(WSI_TOKEN_HTTP_COOKIE, 'session=abc', buf, len);
},
}buf is an ArrayBuffer provided by libwebsockets; len is a
single-element array [n] tracking the running offset that
addHeader updates in place.
Receiving and closing
{
name: 'ws',
onClientReceive(wsi, data, len, frame) {
if(typeof data === 'string') console.log('text:', data);
else console.log('binary:', new Uint8Array(data));
},
onWsPeerInitiatedClose(wsi, code, reason) {
console.log('server closed', code, reason);
},
onClientClosed(wsi) {
ctx.cancelService(); // exit the script
},
}onClientConnectionError(wsi, message, errno) fires for TCP / TLS
/ HTTP-handshake failures before the WebSocket is established.