Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 34 additions & 2 deletions definitions/net.luau
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,24 @@ function net.request(url: string, metadata: Metadata?): Response
error("not implemented")
end

export type WebSocketOptions = {
headers: { [string]: string }?,
protocol: string?,
onopen: (() -> ())?,
onmessage: ((message: string, binary: boolean) -> ())?,
onclose: ((code: number, reason: string) -> ())?,
onerror: ((error: string) -> ())?,
}

export type WebSocket = {
send: (self: WebSocket, data: string, binary: boolean?) -> boolean,
close: (self: WebSocket) -> (),
}

function net.websocket(url: string, options: WebSocketOptions?): WebSocket
error("not implemented")
end

export type ReceivedRequest = {
method: string,
path: string,
Expand All @@ -31,20 +49,34 @@ export type ServerResponse = string | {
headers: { [string]: string }?,
}

export type Handler = (request: ReceivedRequest) -> ServerResponse
export type Handler = (request: ReceivedRequest, server: Server) -> ServerResponse?

export type ServerWebSocket = {
send: (self: ServerWebSocket, data: string, binary: boolean?) -> boolean,
close: (self: ServerWebSocket, code: number?, message: string?) -> (),
}

export type WebSocketHandlers = {
open: ((ws: ServerWebSocket) -> ())?,
message: ((ws: ServerWebSocket, message: string, binary: boolean) -> ())?,
close: ((ws: ServerWebSocket, code: number, message: string) -> ())?,
drain: ((ws: ServerWebSocket) -> ())?,
}

export type Configuration = {
hostname: string?,
port: number?,
reuseport: boolean?,
tls: { certfilename: string, keyfilename: string, passphrase: string?, cafilename: string? }?,
handler: Handler,
handler: Handler?,
websocket: WebSocketHandlers?,
}

export type Server = {
hostname: string,
port: number,
close: () -> (),
upgrade: (self: Server, req: ReceivedRequest) -> boolean,
}

function net.serve(config: Handler | Configuration): Server
Expand Down
38 changes: 38 additions & 0 deletions examples/serve_websocket.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
local net = require("@lute/net")

print("starting server on ws://127.0.0.1:3000")

local server = net.serve({
hostname = "127.0.0.1",
port = 3000,
handler = function(req: net.ReceivedRequest, server: net.Server): net.ServerResponse?
if server:upgrade(req) then
return nil
end
return {
status = 200,
body = "Hello over HTTP. Try websocket upgrade.",
}
end,
websocket = {
open = function(ws: net.ServerWebSocket)
print("ws open")
ws:send("welcome")
end,
message = function(ws, message, binary)
print("ws message:", message, "binary:", binary)
ws:send(message, binary)
if message == "close" then
ws:close()
end
end,
close = function(_ws, code, message)
print("ws close:", code, message)
end,
drain = function(_ws)
print("ws drain")
end,
},
})

print(`listening on {server.hostname}:{server.port}`)
27 changes: 27 additions & 0 deletions examples/websocket_echo.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
local net = require("@lute/net")

print("connecting to echo server...")

local ws: net.WebSocket
ws = net.websocket("wss://echo.websocket.org", {
onopen = function()
print("websocket opened")
ws:send("hello from lute over websockets")
ws:send("close")
end,
onmessage = function(message, binary)
print("received:", message, "binary:", binary)
if message == "close" then
print("closing...")
ws:close()
end
end,
onclose = function()
print("websocket closed")
end,
onerror = function(err)
warn("websocket error:", err)
end,
})

print("connected, waiting for messages...")
7 changes: 7 additions & 0 deletions lute/cli/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,15 @@
#include "lute/clireporter.h"
#include "lute/uvstate.h"

#include <cstdio>

int main(int argc, char** argv)
{
// Disable buffering on stdout/stderr so output appears immediately
// when running as a subprocess (e.g., from C# Process or other hosts)
setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0);

UvGlobalState uvState(argc, argv);
CLIReporter reporter;
return cliMain(argc, argv, reporter);
Expand Down
3 changes: 3 additions & 0 deletions lute/net/include/lute/net.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@ int request(lua_State* L);

int lua_serve(lua_State* L);

int websocket(lua_State* L);

static const luaL_Reg lib[] = {
{"request", request},
{"serve", lua_serve},
{"websocket", websocket},
{nullptr, nullptr},
};

Expand Down
Loading