HOOZiDocs
Skip to content

net

HTTP + WebSocket. Fully async — callbacks are dispatched on the menu thread, Lua-safe, and may directly call gui.set / notify.*. No synchronous API (e.g. get_sync) is provided — it would block the menu thread.

Lifecycle

ResourceBehavior on script unload
HTTP pending callbacks (net.http:*)Queued responses are silently discarded; your callback is not invoked.
WebSocket client (net.ws:connect)All connections opened by the script are closed.
WebSocket server (net.ws_server:listen)All servers opened by the script are closed; every client is forcibly disconnected.

When a WS client fails to reach its server (port closed, timeout, bad URL), background resources are cleaned up automatically. Reconnecting in a loop will not leak memory or threads — net.ws:connect is fire-and-forget; you do not need to :close on failure.


net.http

resp fields passed to the callback: status : int, body : string, error : string, ok : bool

net.http:get(url, callback, timeout?)

Parameters: url : string, callback : function(resp), timeout? : int = 10 (seconds)

net.http:get(url, options, callback) — headers / file download

Parameters: url : string, options : table, callback : function(resp)

net.http:post(url, body, content_type, callback, timeout?)

Parameters: url : string, body : string, content_type : string, callback : function(resp), timeout? : int = 10

net.http:post(url, options, callback) — headers / custom body

Parameters: url : string, options : table, callback : function(resp)

net.http:request(url, method, options, callback) — any method

Parameters: url : string, method : string (GET / POST / PUT / DELETE / PATCH / ...), options : table, callback : function(resp)

options table (all fields optional):

FieldTypeDescription
headerstable<string,string>Custom request headers
bodystringRequest body (may be empty for GET)
content_typestringSynthesises a Content-Type header
save_to_filestringNon-empty = stream to file instead of resp.body (large download)
timeoutintSeconds, default 10

net.ws

net.ws:connect(url, callbacks) → ws_id : int

Parameters: url : string, callbacks : table

Optional fields in the callbacks table (each is a function):

FieldSignature
on_openfunction(id : int)
on_messagefunction(id : int, msg : string)
on_errorfunction(id : int, err : string)
on_closefunction(id : int, code : int, reason : string)

net.ws:send(id, msg) → bool

net.ws:close(id)

net.ws:is_open(id) → bool


net.ws_server

WebSocket server. Listens only on 127.0.0.1 (local web dashboard / IPC; not exposed externally). On script unload, every server opened by that script is closed and every client is forcibly disconnected.

net.ws_server:listen(port, callbacks) → WsServer | nil

Parameters:

  • port : int — local port (returns nil if busy)
  • callbacks : table — callback table
FieldSignatureDescription
on_openfn(client : int)New client finished handshake
on_messagefn(client : int, msg : string)Received text / binary message
on_errorfn(client : int, err : string)Error
on_closefn(client : int, code : int, reason : string)Client disconnected (remote or local)

Returns a WsServer userdata (nil on failure).

WsServer methods

MethodDescription
srv:send(client, msg) → boolSend a text message to a specific client
srv:broadcast(msg)Broadcast to every client on this server
srv:disconnect(client, code?, reason?)Disconnect a client; code defaults to 1000, reason defaults to empty
srv:close()Close server + all clients; joins internal threads. Idempotent.
srv:is_open() → boolWhether the server is still running
srv:client_count() → intNumber of currently connected clients
srv.idNumeric server id (read-only)

Constraints

  • 64MB max per message (protects against giant payloads)
  • Only sends text (opcode 0x1); accepts both text and binary on receive
  • No wss:// (TLS) — local-only use case
  • No fragmented-frame subprotocol
  • Auto replies ping → pong without invoking user callbacks
lua
-- Local dashboard on port 8080 (browser connects ws://127.0.0.1:8080/)
local srv = net.ws_server:listen(8080, {
    on_open    = function(c) print("client", c, "joined") end,
    on_message = function(c, msg) print("got from", c, ":", msg) end,
    on_close   = function(c, code, reason) print("client", c, "left", code) end,
})

if not srv then return end

-- Broadcast game state every frame
event.on("frame_update", function(e)
    local lp = game.localplayer
    if lp then
        srv:broadcast(json.encode({hp=lp.health, sh=lp.shield, vel=lp.abs_velocity}))
    end
end)

event.on("script_unloaded", function(ue)
    if ue.script_path == _SCRIPT_PATH then srv:close() end
end)

Example

lua
-- HTTP GET (async)
net.http:get("https://example.com", function(resp)
    if resp.ok then
        log.info("OK " .. resp.status .. ", body len=" .. #resp.body)
    else
        log.warn("HTTP fail: " .. (resp.error or ""))
    end
end, 3)

-- HTTP POST JSON (legacy signature)
net.http:post("https://api.example.com/log",
    [[{"event":"hello"}]], "application/json",
    function(resp) print(resp.status, resp.ok) end, 5)

-- GET with Authorization (options style)
net.http:get("https://api.example.com/me", {
    headers = { ["Authorization"] = "Bearer " .. token, ["X-Trace-Id"] = "abc" },
    timeout = 5,
}, function(resp) log.info(resp.body) end)

-- POST JSON with custom header
net.http:post("https://api.example.com/log", {
    headers = { ["Authorization"] = "Bearer " .. token },
    body = json.encode({ event = "hello" }),
    content_type = "application/json",
}, function(resp) print(resp.status) end)

-- Streaming download (no memory cost)
net.http:get("https://example.com/big.zip", {
    save_to_file = "downloads/big.zip",
    timeout = 60,
}, function(resp) log.info("downloaded, status=" .. resp.status) end)

-- PUT / DELETE
net.http:request("https://api.example.com/item/42", "DELETE", {
    headers = { ["Authorization"] = "Bearer " .. token },
}, function(resp) print(resp.ok) end)

-- WebSocket with 4 callbacks
local ws_id = net.ws:connect("wss://echo.example.com", {
    on_open    = function(id) net.ws:send(id, "hi") end,
    on_message = function(id, msg) log.info("recv " .. msg) end,
    on_error   = function(id, err) log.warn("err " .. err) end,
    on_close   = function(id, code, reason) log.info("close " .. code) end,
})