An HTTP/1.1 server for zig
0

Configure Feed

Select the types of activity you want to include in your feed.

http.zig / examples / 08_websocket.zig
3.4 kB 101 lines
1const std = @import("std"); 2const httpz = @import("httpz"); 3 4const websocket = httpz.websocket; 5 6const Allocator = std.mem.Allocator; 7 8const PORT = 8808; 9 10// websocket.zig is verbose, let's limit it to err messages 11pub const std_options = std.Options{ .log_scope_levels = &[_]std.log.ScopeLevel{ 12 .{ .scope = .websocket, .level = .err }, 13} }; 14 15// This example show how to upgrade a request to websocket. 16pub fn main(init: std.process.Init) !void { 17 const allocator = init.gpa; 18 19 // For websocket support, you _must_ define a Handler, and your Handler _must_ 20 // have a WebsocketHandler declaration 21 var server = try httpz.Server(Handler).init(init.io, allocator, .{ .address = .localhost(PORT) }, Handler{}); 22 23 defer server.deinit(); 24 25 // ensures a clean shutdown, finishing off any existing requests 26 // see 09_shutdown.zig for how to to break server.listen with an interrupt 27 defer server.stop(); 28 29 var router = try server.router(.{}); 30 31 router.get("/", index, .{}); 32 33 router.get("/ws", ws, .{}); 34 35 std.debug.print("listening http://localhost:{d}/\n", .{PORT}); 36 37 // Starts the server, this is blocking. 38 try server.listen(); 39} 40 41const Handler = struct { 42 // or you could define the full structure here 43 pub const WebsocketHandler = Client; 44}; 45 46const Client = struct { 47 user_id: u32, 48 conn: *websocket.Conn, 49 50 const Context = struct { 51 user_id: u32, 52 }; 53 54 // context is any abitrary data that you want, you'll pass it to upgradeWebsocket 55 pub fn init(conn: *websocket.Conn, ctx: *const Context) !Client { 56 return .{ 57 .conn = conn, 58 .user_id = ctx.user_id, 59 }; 60 } 61 62 // at this point, it's safe to write to conn 63 pub fn afterInit(self: *Client) !void { 64 return self.conn.write("welcome!"); 65 } 66 67 pub fn clientMessage(self: *Client, data: []const u8) !void { 68 // echo back to client 69 return self.conn.write(data); 70 } 71}; 72 73fn index(_: Handler, _: *httpz.Request, res: *httpz.Response) !void { 74 res.content_type = .HTML; 75 res.body = 76 \\<!DOCTYPE html> 77 \\ <p>httpz integrates with my own <a href="https://github.com/karlseguin/websocket.zig/">websocket.zig</a>. 78 \\ <p>A websocket connection should already be established.</p> 79 \\ <p>Copy and paste the following in your browser console to have the server echo back:</p> 80 \\ <pre>ws.send("hello from the client!");</pre> 81 \\ <script> 82 \\ const ws = new WebSocket("ws://localhost:8808/ws"); 83 \\ ws.addEventListener("message", (event) => { console.log("from server: ", event.data) }); 84 \\ </script> 85 ; 86} 87 88fn ws(_: Handler, req: *httpz.Request, res: *httpz.Response) !void { 89 // Could do authentication or anything else before upgrading the connection 90 // The context is any arbitrary data you want to pass to Client.init. 91 const ctx = Client.Context{ .user_id = 9001 }; 92 93 // The first parameter, Client, ***MUST*** be the same as Handler.WebSocketHandler 94 // I'm sorry about the awkwardness of that. 95 // It's undefined behavior if they don't match, and it _will_ behave weirdly/crash. 96 if (try httpz.upgradeWebsocket(Client, req, res, &ctx) == false) { 97 res.status = 500; 98 res.body = "invalid websocket"; 99 } 100 // unsafe to use req or res at this point! 101}