Odin bindings for the wsServer C WebSocket library.
Odin-wsServer provides bindings to the lightweight and efficient wsServer WebSocket server library, enabling seamless WebSocket support in Odin applications. This library allows Odin developers to create WebSocket servers with minimal overhead and strong performance.
- Lightweight and efficient WebSocket server implementation.
- Direct bindings to
wsServer, maintaining C-level performance. - Supports multiple concurrent connections.
- Easy-to-use API for handling WebSocket messages.
To use odin-wsServer, ensure that you have a copy of the static wsServer library (libws.a) in your working directory.
Follow these instructions to compile the library: wsServer CMake Instructions
- Echo Server -
odin run examples/echo - Chat Server -
odin run examples/chat - Sample Server -
odin run examples/complete
Click to expand code sample
package complete
import ws "../.."
import "core:fmt"
import "core:time"
PORT :: 8080
on_open :: proc(client: ws.Client_Connection) {
client_addr := ws.getaddress(client)
client_port := ws.getport(client)
fmt.printf("Connection opened, addr: %s, port: %s\n", client_addr, client_port)
ws.send_text_frame(client, "you are now connected!")
}
on_close :: proc(client: ws.Client_Connection) {
client_addr := ws.getaddress(client)
fmt.printf("Connection closed, addr: %s\n", client_addr)
}
on_message :: proc(client: ws.Client_Connection, msg: []u8, type: ws.Frame_Type) {
client_addr := ws.getaddress(client)
message := "<not parsed>"
if type == .Text {
message = string(msg)
}
fmt.printf(
"I received a message '%s', size %d, type %s from client %s\n",
message,
len(msg),
type,
client_addr,
)
ws.send_text_frame(client, "hello")
time.sleep(2 * time.Second)
ws.send_text_frame(client, "world")
time.sleep(2 * time.Second)
out_msg := fmt.tprintf("you sent a %s message", type)
ws.send_text_frame(client, out_msg)
time.sleep(2 * time.Second)
ws.send_text_frame(client, "closing connection in 2 seconds")
time.sleep(2 * time.Second)
ws.send_text_frame(client, "bye!")
ws.close_client(client)
}
main :: proc() {
server := ws.Server {
host = "0.0.0.0",
port = PORT,
timeout_ms = 1000,
evs = {onmessage = on_message, onclose = on_close, onopen = on_open},
}
fmt.printfln("Listening on port %d", PORT)
ws.listen(&server)
fmt.printfln("Socket closed")
}For API details, I recommend checking the ws.odin file and reading the source code of the underlying library.
Represents the WebSocket server configuration.
Server :: struct {
host: string, // Server hostname or IP
port: u16, // Port to listen on
thread_loop: bool, // Run accept loop in a separate thread
timeout_ms: u32, // Connection timeout in milliseconds
evs: Events, // Event handlers
ctx: rawptr, // User-defined context
}Represents the state of a WebSocket connection.
Connection_State :: enum (c.int) {
Invalid_Client = -1,
Connecting = 0,
Open = 1,
Closing = 2,
Closed = 3,
}Defines the different WebSocket frame types.
Frame_Type :: enum (c.int) {
Continuation = 0,
Text = 1,
Binary = 2,
Close = 8,
Ping = 9,
Pong = 10,
}Starts the WebSocket server and listens for connections.
listen :: proc(server: ^Server) -> intSends a WebSocket frame to a specific client.
send_frame :: proc(client: Client_Connection, data: []byte, type: Frame_Type) -> intBroadcasts a WebSocket frame to all clients on a specified port.
send_frame_broadcast :: proc(port: u16, data: []byte, type: Frame_Type) -> intSends a text message frame to a specific client.
send_text_frame :: proc(client: Client_Connection, msg: string) -> intBroadcasts a text message frame to all clients on a specified port.
send_text_frame_broadcast :: proc(port: u16, msg: string) -> intSends a binary data frame to a specific client.
send_binary_frame :: proc(client: Client_Connection, data: []byte) -> intBroadcasts a binary data frame to all clients on a specified port.
send_binary_frame_broadcast :: proc(port: u16, data: []byte) -> intRetrieves the user-defined context from the Server struct.
get_global_context :: proc(client: Client_Connection, $T: typeid) -> ^TRetrieves the user-defined context of the current connection.
TODO: Create a wrapper function that auto casts.
get_connection_context :: proc(client: Client_Connection) -> rawptrSets the user-defined context of the current connection.
set_connection_context :: proc(client: Client_Connection, ptr: rawptr)Events can be set in the Server struct to handle client interactions.
Note: The temporary allocator is always freed after each event call. Feel free to allocate and not free.
Events :: struct {
onopen: proc(client: Client_Connection),
onclose: proc(client: Client_Connection),
onmessage: proc(client: Client_Connection, msg: []u8, type: Frame_Type),
}server := Server{
host = "0.0.0.0",
port = 8080,
thread_loop = false,
timeout_ms = 5000,
evs = Events{
onopen = proc(client: Client_Connection) {
fmt.println("Client connected")
},
onclose = proc(client: Client_Connection) {
fmt.println("Client disconnected")
},
onmessage = proc(client: Client_Connection, msg: []u8, type: Frame_Type) {
fmt.println("Received message: ", string(msg))
},
},
}
listen(&server)Contributions are welcome! Feel free to submit issues and pull requests to improve this library.
This project is licensed under the MIT License. See LICENSE for details.
For more details on wsServer, visit the official repository: Theldus/wsServer.