@eryx/websocket Module

JSON

WebSocket client and server library (RFC 6455).

Client - connect to a WebSocket server:

local websocket = require("@eryx/websocket")

local ws = websocket.connect("ws://localhost:8080/chat")
ws:send("hello")

local msg = ws:receive()
if msg then
	print(msg.data)
end

ws:close()

Client - secure WebSocket (wss://):

local ws = websocket.connect("wss://echo.example.com/ws")

Client - with compression and heartbeat:

local ws = websocket.connect("wss://echo.example.com/ws", {
    compress = true,       -- negotiate permessage-deflate
    heartbeat = 30,        -- send a ping every 30 seconds
})

Server - upgrade inside an HTTP handler:

local http = require("@eryx/http")
local websocket = require("@eryx/websocket")

local server = http.createServer(function(req, res)
    if req.path == "/ws" then
        local ws = websocket.upgrade(req, res, { compress = true })
        while true do
            local msg = ws:receive()
            if not msg then break end
            ws:send("echo: " .. msg.data)
        end
        return
    end
    res:send(200, "Hello!")
end)
server:listen()

The server upgrade works with both HTTP and HTTPS servers - TLS is already handled by the HTTP server before the request arrives, so the upgraded WebSocket transparently inherits the encrypted transport.

Summary

Classes

_sock: any
_isClient: boolean
_closed: boolean
_closeSent: boolean
_closeReceived: boolean
_deflate: DeflateState?
_heartbeatThread: thread?
WebSocket._new(sock: any, isClient: boolean, deflate: DeflateState?, heartbeatInterval: number?)WebSocket
WebSocket:send(data: string | buffer, binary: boolean?)()
WebSocket:ping(data: (string | buffer)?)()
WebSocket:pong(data: (string | buffer)?)()
WebSocket:close(code: number?, reason: string?)()

API Reference

Classes

WebSocket

A WebSocket connection.

Obtained from connect (client) or upgrade (server). Provides methods to send and receive messages, send pings, and perform the close handshake.

Properties

_sock: any
_isClient: boolean
_closed: boolean
_closeSent: boolean
_closeReceived: boolean
_deflate: DeflateState?
_heartbeatThread: thread?

WebSocket._new

WebSocket._new(sock: any, isClient: boolean, deflate: DeflateState?, heartbeatInterval: number?)WebSocket

WebSocket:send

Sends a text or binary message.

If permessage-deflate was negotiated, the message is automatically compressed before sending.

WebSocket:send(data: string | buffer, binary: boolean?)()

Parameters

data: string | buffer

The payload to send. Strings are sent as-is; buffers are converted with buffer.tostring.

binary: boolean?

When true, sends a binary frame (opcode 0x2) instead of a text frame (opcode 0x1). Defaults to false.

WebSocket:ping

Sends a Ping control frame.

WebSocket:ping(data: (string | buffer)?)()

Parameters

data: (string | buffer)?

Optional payload (≤ 125 bytes).

WebSocket:pong

Sends a Pong control frame.

WebSocket:pong(data: (string | buffer)?)()

Parameters

data: (string | buffer)?

Optional payload (≤ 125 bytes). Typically the same data received in the corresponding Ping.

WebSocket:receive

Blocks until a complete data message arrives, or the connection closes.

Handles fragmented messages, automatically responds to Ping frames with Pong, and performs the close handshake when a close frame is received. If permessage-deflate was negotiated, compressed messages (RSV1 set) are automatically decompressed.

WebSocket:receive()Message?

Returns

The received message, or nil when the connection has been closed.

WebSocket:close

Initiates the WebSocket close handshake.

Sends a close frame, waits for the server's close reply (if not already received), then shuts down the underlying socket. Also cancels any active heartbeat.

WebSocket:close(code: number?, reason: string?)()

Parameters

code: number?

Optional status code (e.g. 1000 for normal closure).

reason: string?

Optional human-readable close reason.

Types

Message

A message returned by WebSocket.receive.

@interface Message .data string -- The payload. For text frames this is a UTF-8 string; for binary frames it contains raw bytes. .binary boolean -- true when the message was sent as a binary frame.

data: string
binary: boolean

ConnectOptions

Options for connect.

@interface ConnectOptions .headers { [string]: string }? -- Extra headers to include in the upgrade request. .timeout number? -- Socket timeout in seconds. .subprotocols { string }? -- Requested sub-protocols (Sec-WebSocket-Protocol). .compress boolean? -- When true, negotiates permessage-deflate compression (RFC 7692). .heartbeat number? -- Interval in seconds between automatic ping frames. nil or 0 disables.

headers: { [string]: string }?
timeout: number?
subprotocols: { string }?
compress: boolean?
heartbeat: number?

UpgradeOptions

Options for upgrade.

@interface UpgradeOptions .subprotocol string? -- The sub-protocol to select. Sent back in Sec-WebSocket-Protocol. .compress boolean? -- When true, accepts permessage-deflate if the client offered it. .heartbeat number? -- Interval in seconds between automatic ping frames. nil or 0 disables.

subprotocol: string?
compress: boolean?
heartbeat: number?