WebSocket¶
A connection to a service that stays open, so that both sides can send at any time.
A spell only reaches the hosts that the owner of the server has listed in
config/wizards-of-lua/net.luaconf. See Http.
What the other side sends waits in the socket until the spell reads it with receive, from the
moment the socket is connected, so a spell can't miss a message. When 1024 messages or 16 MB are
waiting, the socket stops reading and the other side has to wait.
A socket belongs to the spell that connected it, and closes when that spell ends. Other spells can use it until then.
To read or send data as JSON, see Json.
Example: Ask a service and print the answer
local socket = assert(WebSocket:connect("wss://chat.example.org/"))
socket:send(Json:encode({ op = "hello", name = spell.owner.name }))
local answer, why = socket:receive(100)
if answer then
print(Json:decode(answer).text)
else
print("No answer: " .. why)
end
socket:close()
Example: Serve a socket and events in one loop
queue:next(0) and socket:receive(0) return at once, so a short wait in one of them lets a
single loop serve both.
local socket = assert(WebSocket:connect("wss://chat.example.org/"))
local queue = spell:collect("ChatMessageEvent")
while true do
local text, why, code = socket:receive(0)
if text then
spell:execute("/say " .. text)
elseif why == "closed" then
print("The connection ended: " .. code)
break
end
local event = queue:next(text and 0 or 1) --[[@as ChatMessageEvent?]]
if event then
socket:send(event.senderName .. ": " .. event.message)
end
end
Fields¶
host: string — Read-Only¶
The name of the host this socket is connected to. Never the whole URL, which can hold a password.
open: boolean — Read-Only¶
true while the socket can send: until close is called or the connection ends. Messages may still wait in the socket after that.
Methods¶
connect(url: string, options?: WebSocketOptions) → socket: WebSocket?, reason: NetReason?¶
Connects to a URL, and waits until the connection stands or the timeout has passed. Call it on the
class: WebSocket:connect(url, options).
nil means that no connection was made, and the reason says why. Because it waits, this function
can't be called in an event interceptor.
A wrong option raises an error. Error messages never show the URL or a header's value, as they can hold a password.
Example
local socket, reason = WebSocket:connect("wss://chat.example.org/", {
headers = { Authorization = "Bearer " .. token },
timeout = 100,
})
if not socket then
print("Can't connect: " .. reason)
end
Parameters
- url: string — Where to connect to, starting with
ws://orwss://. - options?: WebSocketOptions — How to connect.
Returns
- socket: WebSocket? — The socket, or
nilif there is no connection. - reason: NetReason? — Why there is no connection.
close(code?: integer, reason?: string)¶
Closes the socket: sends what is still waiting to be sent, then tells the other side. The other side has 3 seconds to answer, and then the connection just ends. The function doesn't wait for that, so it can be called in an event interceptor. Closing a closed socket does nothing.
Messages that have arrived can still be read. After them, receive tells that the socket is
closed.
Example
Parameters
- code?: integer — Why it closes: 1000, 1001, 1011, or from 3000 to 4999. What the numbers from 3000 on mean is up to the service. Defaults to 1000, which means "all done".
- reason?: string — Why it closes, in words, up to 123 bytes.
receive(timeout?: integer) → message: string?, why: "closed"|"timeout"|nil, code: integer?, reason: string?¶
Returns the next message, and waits for it if necessary.
Without a timeout it waits for as long as it takes. With a timeout of 0 it doesn't wait at all, so that is the only way to call this function in an event interceptor.
Text arrives as a string in UTF-8. Bytes arrive as a string of bytes. A message may have up to 16 MB, and a larger one ends the connection with the code 1009.
When the connection has ended, the messages that arrived before that come first, and from then on
every call returns nil, "closed" with the code and the reason. The code 1006 means that the
connection broke off, without a word from the other side.
Example
local text, why, code, reason = socket:receive(20)
if text then
print("Got: " .. text)
elseif why == "timeout" then
print("Nothing for a second")
else
print("Closed: " .. code .. " " .. reason)
end
Parameters
- timeout?: integer — How many game ticks to wait at most. If omitted, it waits until a message arrives or the socket is closed.
Returns
- message: string? — The message, or
nilif there is none. - why: "closed"|"timeout"|nil — Why there is no message.
- code: integer? — The close code, if the socket is closed.
- reason: string? — The other side's words for it, if the socket is closed. May be empty.
send(text: string) → ok: boolean?, reason: "busy"|"closed"|"too_large"|nil¶
Sends a text. It returns at once and the text goes out in the background, so it can be called in an event interceptor. Messages go out in the order they were sent.
The text must be valid UTF-8: that's the rule for text in a WebSocket, and anything else raises an error.
nil means that this text won't go out. "closed" is the end of the connection. "busy" means that
16 MB are already waiting to be sent because the other side doesn't read fast enough, and sending
can work again later. "too_large" is a text of more than 16 MB.
Example
local ok, reason = socket:send(Json:encode({ op = "ping" }))
if not ok then
print("Not sent: " .. reason)
end
Parameters
- text: string — What to send.
Returns
- ok: boolean? —
trueif the text will go out,nilif it won't. - reason: "busy"|"closed"|"too_large"|nil — Why it won't.