### Run Zig Build Examples Source: https://cookbook.ziglang.cc/index Demonstrates how to execute Zig build examples from the cookbook. This involves using the `zig build run-{chapter-num}-{sequence-num}` command for specific recipes or `zig build run-all` to execute all available examples. ```Shell zig build run-1-1 zig build run-all ``` -------------------------------- ### Start Database Services for Zig Cookbook Source: https://cookbook.ziglang.cc/index Explains how to start necessary database services for certain Zig cookbook recipes using Docker Compose. This command ensures that databases like PostgreSQL or MySQL are running in the background. ```Shell docker-compose up -d ``` -------------------------------- ### Install Zig Cookbook Dependencies Source: https://cookbook.ziglang.cc/index Provides instructions for installing system libraries required by some Zig cookbook recipes. This typically involves using a `make` command to manage dependencies. ```Shell make install-deps ``` -------------------------------- ### Zig Database Connection and Operations Source: https://cookbook.ziglang.cc/database Demonstrates connecting to databases, defining schemas, preparing statements, inserting data, and executing join queries in Zig. This example focuses on common database operations. ```Zig // Placeholder for Zig database connection and operations // Example: Connecting to SQLite const std = @import("std"); // Define table schemas (example) const CatColors = struct { id: u32, name: [16]u8, // Assuming fixed-size string for simplicity }; const Cats = struct { id: u32, name: [16]u8, color_id: u32, }; pub fn main() !void { var g = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = g.deinit(); const allocator = g.allocator(); // Example: SQLite connection (requires a SQLite library for Zig) // const db = try Sqlite.connect(allocator, "./my_database.db")?; // defer db.disconnect(); // Example: Creating tables (SQL statements) // const create_cat_colors_table = "CREATE TABLE cat_colors (id INTEGER PRIMARY KEY, name TEXT NOT NULL)"; // const create_cats_table = "CREATE TABLE cats (id INTEGER PRIMARY KEY, name TEXT NOT NULL, color_id INTEGER, FOREIGN KEY(color_id) REFERENCES cat_colors(id))"; // Example: Preparing statements and inserting data // const insert_color_stmt = try db.prepare(allocator, "INSERT INTO cat_colors (name) VALUES (?) "); // defer insert_color_stmt.finalize(); // try insert_color_stmt.bindText(1, "Blue"); // try insert_color_stmt.step(); // Example: Executing a join query // const join_query = "SELECT c.name, cc.name FROM cats c JOIN cat_colors cc ON c.color_id = cc.id"; // var cursor = try db.exec(allocator, join_query); // defer cursor.deinit(); // Process query results... std.debug.print("Database operations example (placeholder)\n", .{}); } ``` -------------------------------- ### Zig TCP Client Example Source: https://cookbook.ziglang.cc/04-02-tcp-client This Zig code implements a basic TCP client that connects to a server at a given IP address and port. It reads the port from command-line arguments, establishes a connection, and sends a 'hello zig' message. The code also includes comments on how to use IPv6. ```Zig const std = @import("std"); const net = std.net; const print = std.debug.print; pub fn main() !void { var args = std.process.args(); // The first (0 index) Argument is the path to the program. _ = args.skip(); const port_value = args.next() orelse { print("expect port as command line argument\n", .{}); return error.NoPort; }; const port = try std.fmt.parseInt(u16, port_value, 10); const peer = try net.Address.parseIp4("127.0.0.1", port); // Connect to peer const stream = try net.tcpConnectToAddress(peer); defer stream.close(); print("Connecting to {}\n", .{peer}); // Sending data to peer const data = "hello zig"; var writer = stream.writer(); const size = try writer.write(data); print("Sending '{s}' to peer, total written: {d} bytes\n", .{ data, size }); // Or just using `writer.writeAll` // try writer.writeAll("hello zig"); } ``` -------------------------------- ### Zig Doubly Linked List Main Function Example Source: https://cookbook.ziglang.cc/12-03-doubly-linked-list Demonstrates the usage of the `DoublyLinkedList` by initializing it, inserting elements, performing insertions at specific positions, removing elements, and verifying the list's state after each operation using `ensureList`. It manages memory with `GeneralPurposeAllocator`. ```Zig pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); const allocator = gpa.allocator(); var list = DoublyLinkedList(u32).init(allocator); defer list.deinit(); const values = [_]u32{ 1, 2, 3, 4, 5 }; for (values) |value| { try list.insertLast(value); } try ensureList(list, &values); try list.insertAt(1, 100); try ensureList(list, &[_]u32{ 1, 100, 2, 3, 4, 5 }); try list.insertAt(0, 200); try ensureList(list, &[_]u32{ 200, 1, 100, 2, 3, 4, 5 }); try std.testing.expect(list.remove(100)); try ensureList(list, &[_]u32{ 200, 1, 2, 3, 4, 5 }); // delete all for (values) |value| { try std.testing.expect(list.remove(value)); } try std.testing.expect(list.remove(200)); try ensureList(list, &[_]u32{}); } ``` -------------------------------- ### Testing HTTP Server with curl Source: https://cookbook.ziglang.cc/05-03-http-server-std This command demonstrates how to test the Zig HTTP server using `curl`. It sends a GET request to the server running on localhost:8080 and displays the response, including headers and the "Hello World" message. ```Shell curl -v localhost:8080 ``` -------------------------------- ### Zig Thread Pool Example Source: https://cookbook.ziglang.cc/07-03-threadpool This Zig code snippet demonstrates the creation and usage of a thread pool. It initializes a thread pool with 4 worker threads, spawns 10 tasks to be executed concurrently by the pool, and uses a WaitGroup to ensure all tasks complete before the program exits. The tasks simply print their ID. ```zig const std = @import("std"); const print = std.debug.print; pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer if (gpa.deinit() != .ok) @panic("leak"); const allocator = gpa.allocator(); var pool: std.Thread.Pool = undefined; try pool.init(.{ .allocator = allocator, .n_jobs = 4, }); defer pool.deinit(); var wg: std.Thread.WaitGroup = .{}; for (0..10) |i| { pool.spawnWg(&wg, struct { fn run(id: usize) void { print("I'm from {d}\n", .{id}); } }.run, .{i}); } wg.wait(); print("All threads exit.\n", .{}); } ``` -------------------------------- ### Salt and Hash Password with PBKDF2 in Zig Source: https://cookbook.ziglang.cc/02-02-pbkdf2 This code snippet demonstrates how to securely salt and hash a password using the PBKDF2 algorithm in Zig. It utilizes `std.crypto.pwhash.pbkdf2` for the hashing process and `std.rand.DefaultPrng` to generate a random salt. The example includes a test case to verify the derived key against a known hash. ```zig const std = @import("std"); const print = std.debug.print; const crypto = std.crypto; const HmacSha256 = crypto.auth.hmac.sha2.HmacSha256; pub fn main() !void { const salt = [_]u8{ 'a', 'b', 'c' }; const password = "Guess Me If You Can!"; const rounds = 1_000; // Usually 16 or 32 bytes var derived_key: [16]u8 = undefined; try crypto.pwhash.pbkdf2(&derived_key, password, &salt, rounds, HmacSha256); try std.testing.expectEqualSlices( u8, &[_]u8{ 44, 184, 223, 181, 238, 128, 211, 50, 149, 114, 26, 86, 225, 172, 116, 81, }, &derived_key, ); } ``` -------------------------------- ### Serialize and Deserialize Zon Data in Zig Source: https://cookbook.ziglang.cc/10-02-zon This Zig code snippet demonstrates how to serialize a custom struct (`Student`) into Zon format and then deserialize it back. It utilizes the `std.zon` library for these operations and includes assertions to verify the correctness of the serialization and deserialization process. The example also shows how to handle memory allocation and deallocation. ```zig const std = @import("std"); const zon = std.zon; const Allocator = std.mem.Allocator; const Student = struct { name: []const u8, age: u16, favourites: []const []const u8, fn deinit(self: *Student, allocator: Allocator) void { allocator.free(self.name); for (self.favourites) |item| { allocator.free(item); } allocator.free(self.favourites); } }; pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer if (gpa.deinit() != .ok) @panic("leak"); const allocator = gpa.allocator(); const source = Student{ .name = "John", .age = 20, .favourites = &.{ "swimming", "running" }, }; var dst = std.ArrayList(u8).init(allocator); defer dst.deinit(); try zon.stringify.serialize(source, .{}, dst.writer()); const expected = \.{ \ .name = "John", \ .age = 20, \ .favourites = .{ "swimming", "running" }, \} ; try std.testing.expectEqualStrings(expected, dst.items); // Make it 0-sentinel try dst.append(0); const input = dst.items[0 .. dst.items.len - 1 :0]; var status: zon.parse.Status = .{}; defer status.deinit(allocator); var parsed = zon.parse.fromSlice( Student, allocator, input, &status, .{ .free_on_error = true }, ) catch |err| { std.debug.print("Parse status: {any}\n", .{status}); return err; }; defer parsed.deinit(allocator); try std.testing.expectEqualDeep(source, parsed); } ``` -------------------------------- ### Iterate Directory Contents in Zig Source: https://cookbook.ziglang.cc/01-05-iterate-dir This Zig code snippet shows how to open a directory and iterate over its entries using the `std.fs.walk` function. It prints the path, basename, and type of each file system entry found within the specified directory. The example uses `std.heap.GeneralPurposeAllocator` for memory management and requires the `iterate` option to be set when opening the directory. ```Zig const std = @import("std"); const fs = std.fs; const print = std.debug.print; pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer if (gpa.deinit() != .ok) @panic("leak"); const allocator = gpa.allocator(); // In order to walk the directry, `iterate` must be set to true. var dir = try fs.cwd().openDir("zig-out", .{ .iterate = true }); defer dir.close(); var walker = try dir.walk(allocator); defer walker.deinit(); while (try walker.next()) |entry| { print("path: {s}, basename:{s}, type:{s}\n", .{ entry.path, entry.basename, @tagName(entry.kind), }); } } ``` -------------------------------- ### Salt and Hash Password with Argon2id in Zig Source: https://cookbook.ziglang.cc/02-03-argon2 This Zig code snippet shows how to derive a cryptographic key from a password and salt using the Argon2id algorithm. It utilizes `std.crypto.pwhash.argon2` for hashing and `std.crypto.random` for salt generation. The example includes setting Argon2id parameters like iterations, memory cost, and threads. ```zig const std = @import("std"); pub fn main() !void { var dbg = std.heap.DebugAllocator(.{}){}; defer _ = dbg.deinit(); const allocator = dbg.allocator(); const password = "happy"; //Random salt (Must be at least 8 bytes, recommended 16+) var raw: [8]u8 = undefined; std.crypto.random.bytes(&raw); const salt = try std.fmt.allocPrint(allocator, "{s}", .{std.fmt.bytesToHex(raw, .lower)}); defer allocator.free(salt); //Parameters for Argon2id const params = std.crypto.pwhash.argon2.Params{ .t = 3, // Iterations (time cost) .m = 16, // Memory cost in KiB (here 16 MiB) .p = 1, // Threads }; const dk_len: usize = 16; // derive 16 or 32-byte key var derived: [dk_len]u8 = undefined; try std.crypto.pwhash.argon2.kdf( allocator, &derived, password, salt, params, .argon2id, //argon2i, argon2d and argon2id ); std.debug.print("Argon2id derived key: {s}\n", .{std.fmt.bytesToHex(derived, .lower)}); } ``` -------------------------------- ### Perform HTTP GET Request in Zig Source: https://cookbook.ziglang.cc/05-01-http-get This Zig code snippet demonstrates how to make a synchronous HTTP GET request. It utilizes the `std.http` module to open a connection, send a request to a specified URI, and process the response, including iterating through headers and reading the response body. It also includes an assertion to check the HTTP status code. ```zig const std = @import("std"); const print = std.debug.print; const http = std.http; pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); const allocator = gpa.allocator(); var client = http.Client{ .allocator = allocator }; defer client.deinit(); const uri = try std.Uri.parse("http://httpbin.org/headers"); const buf = try allocator.alloc(u8, 1024 * 8); defer allocator.free(buf); var req = try client.open(.GET, uri, .{ .server_header_buffer = buf, }); defer req.deinit(); try req.send(); try req.finish(); try req.wait(); var iter = req.response.iterateHeaders(); while (iter.next()) |header| { std.debug.print("Name:{s}, Value:{s}\n", .{ header.name, header.value }); } try std.testing.expectEqual(req.response.status, .ok); var rdr = req.reader(); const body = try rdr.readAllAlloc(allocator, 1024 * 1024 * 4); defer allocator.free(body); print("Body:\n{s}\n", .{body}); } ``` -------------------------------- ### Get CPU Core Count in Zig Source: https://cookbook.ziglang.cc/08-01-cpu-count This snippet shows how to get the number of logical CPU cores on the current machine using Zig's standard library. It utilizes `std.Thread.getCpuCount()` to retrieve this information and prints it to the console. ```Zig const std = @import("std"); const print = std.debug.print; pub fn main() !void { print("Number of logical cores is {}\n", .{try std.Thread.getCpuCount()}); } ``` -------------------------------- ### Zig: Initialize and connect to PostgreSQL database Source: https://cookbook.ziglang.cc/14-02-postgres This snippet shows how to initialize a database connection to a PostgreSQL server using connection information. It includes error handling for the initialization process. ```Zig const conn_info = "host=127.0.0.1 user=postgres password=postgres dbname=postgres"; const db = try DB.init(conn_info); defer db.deinit(); ``` -------------------------------- ### Zig Run Once with std.once Source: https://cookbook.ziglang.cc/07-04-run-once Ensures a function executes exactly once, regardless of thread invocations. This example uses `std.once` to safely increment a counter from multiple threads. ```Zig const std = @import("std"); var n: u8 = 0; fn incr() void { n = n + 1; } var once_incr = std.once(incr); fn onceIncr() void { // The invocations of `call` are thread-safe. once_incr.call(); once_incr.call(); } pub fn main() !void { { const t1 = try std.Thread.spawn(.{}, onceIncr, .{}); defer t1.join(); const t2 = try std.Thread.spawn(.{}, onceIncr, .{}); defer t2.join(); } try std.testing.expectEqual(1, n); } ``` -------------------------------- ### Zig: Initialize and Query MySQL Database Source: https://cookbook.ziglang.cc/14-03-mysql This snippet demonstrates initializing a MySQL connection in Zig and executing a multi-statement query to create tables. It also includes logic to consume results from multi-statements to prevent 'Commands out of sync' errors. ```Zig pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); const allocator = gpa.allocator(); const version = c.mysql_get_client_version(); print("MySQL client version is {}\n", .{version}); const db = try DB.init(allocator, ${ .database = "public", .host = "127.0.0.1", .user = "root", .password = "root", }); defer db.deinit(); try db.execute( \ CREATE TABLE IF NOT EXISTS cat_colors ( \ id INT AUTO_INCREMENT PRIMARY KEY, \ name VARCHAR(255) NOT NULL \); \ \CREATE TABLE IF NOT EXISTS cats ( \ id INT AUTO_INCREMENT PRIMARY KEY, \ name VARCHAR(255) NOT NULL, \ color_id INT NOT NULL \) ); // Since we use multi-statement, we need to consume all results. // Otherwise we will get following error when we execute next query. // Commands out of sync; you can't run this command now // // https://dev.mysql.com/doc/c-api/8.0/en/mysql-next-result.html while (c.mysql_next_result(db.conn) == 0) { const res = c.mysql_store_result(db.conn); c.mysql_free_result(res); } try db.insertTable(); try db.queryTable(); } ``` -------------------------------- ### Read File Line by Line in Zig Source: https://cookbook.ziglang.cc/01-01-read-file-line-by-line This code snippet shows how to read a file line by line in Zig. It uses `std.io.bufferedReader` for efficient reading and `streamUntilDelimiter` to split lines based on the newline character. The example also includes error handling for end-of-stream conditions. ```zig const std = @import("std"); const fs = std.fs; const print = std.debug.print; pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); const allocator = gpa.allocator(); const file = try fs.cwd().openFile("tests/zig-zen.txt", .{ }); defer file.close(); // Wrap the file reader in a buffered reader. // Since it's usually faster to read a bunch of bytes at once. var buf_reader = std.io.bufferedReader(file.reader()); const reader = buf_reader.reader(); var line = std.ArrayList(u8).init(allocator); defer line.deinit(); const writer = line.writer(); var line_no: usize = 0; while (reader.streamUntilDelimiter(writer, '\n', null)) { // Clear the line so we can reuse it. defer line.clearRetainingCapacity(); line_no += 1; print("{d}--{s}\n", .{ line_no, line.items }); } else |err| switch (err) { error.EndOfStream => { // end of file if (line.items.len > 0) { line_no += 1; print("{d}--{s}\n", .{ line_no, line.items }); } }, else => return err, // Propagate error } print("Total lines: {d}\n", .{line_no}); } ``` -------------------------------- ### Connect to MySQL Database (Zig) Source: https://cookbook.ziglang.cc/14-03-mysql Establishes a connection to a MySQL database using provided connection details. Handles initialization and connection errors. ```zig const std = @import("std"); const Allocator = std.mem.Allocator; const c = @cImport({ @cInclude("mysql.h"); }); const print = std.debug.print; pub const DBInfo = struct { host: [:0]const u8, user: [:0]const u8, password: [:0]const u8, database: [:0]const u8, port: u32 = 3306, }; pub const DB = struct { conn: *c.MYSQL, allocator: Allocator, fn init(allocator: Allocator, db_info: DBInfo) !DB { const db = c.mysql_init(null); if (db == null) { return error.initError; } if (c.mysql_real_connect( db, db_info.host, db_info.user, db_info.password, db_info.database, db_info.port, null, c.CLIENT_MULTI_STATEMENTS, ) == null) { print("Connect to database failed: {s}\n", .{c.mysql_error(db)}); return error.connectError; } return { .conn = db, .allocator = allocator, }; } fn deinit(self: DB) void { c.mysql_close(self.conn); } fn execute(self: DB, query: []const u8) !void { if (c.mysql_real_query(self.conn, query.ptr, query.len) != 0) { print("Exec query failed: {s}\n", .{c.mysql_error(self.conn)}); return error.execError; } } fn queryTable(self: DB) !void { const query = \ SELECT c.name, cc.name FROM cats c INNER JOIN cat_colors cc ON cc.id = c.color_id; \ ; try self.execute(query); const result = c.mysql_store_result(self.conn); if (result == null) { print("Store result failed: {s}\n", .{c.mysql_error(self.conn)}); return error.storeResultError; } defer c.mysql_free_result(result); while (c.mysql_fetch_row(result)) |row| { const cat_name = row[0]; const color_name = row[1]; print("Cat: {s}, Color: {s}\n", .{ cat_name, color_name }); } } fn insertTable(self: DB) !void { const cat_colors = .{ .{ "Blue", .{ "Tigger", "Sammy" }, }, .{ "Black", .{ "Oreo", "Biscuit" }, }, }; const insert_color_stmt: *c.MYSQL_STMT = blk: { const stmt = c.mysql_stmt_init(self.conn); if (stmt == null) { return error.initStmt; } errdefer _ = c.mysql_stmt_close(stmt); const insert_color_query = "INSERT INTO cat_colors (name) values (?)"; if (c.mysql_stmt_prepare(stmt, insert_color_query, insert_color_query.len) != 0) { print("Prepare color stmt failed, msg:{s}\n", .{c.mysql_error(self.conn)}); return error.prepareStmt; } break :blk stmt.?; }; defer _ = c.mysql_stmt_close(insert_color_stmt); const insert_cat_stmt = blk: { const stmt = c.mysql_stmt_init(self.conn); if (stmt == null) { return error.initStmt; } errdefer _ = c.mysql_stmt_close(stmt); const insert_cat_query = "INSERT INTO cats (name, color_id) values (?, ?)"; if (c.mysql_stmt_prepare(stmt, insert_cat_query, insert_cat_query.len) != 0) { print("Prepare cat stmt failed: {s}\n", .{c.mysql_error(self.conn)}); return error.prepareStmt; } break :blk stmt.?; }; defer _ = c.mysql_stmt_close(insert_cat_stmt); inline for (cat_colors) |row| { const color = row.@"0"; const cat_names = row.@"1"; var color_binds = [_]c.MYSQL_BIND{std.mem.zeroes(c.MYSQL_BIND)}; color_binds[0].buffer_type = c.MYSQL_TYPE_STRING; color_binds[0].buffer_length = color.len; color_binds[0].is_null = 0; color_binds[0].buffer = @constCast(@ptrCast(color.ptr)); if (c.mysql_stmt_bind_param(insert_color_stmt, &color_binds)) { print("Bind color param failed: {s}\n", .{c.mysql_error(self.conn)}); return error.bindParamError; } if (c.mysql_stmt_execute(insert_color_stmt) != 0) { ``` -------------------------------- ### Zig: Create PostgreSQL tables 'cat_colors' and 'cats' Source: https://cookbook.ziglang.cc/14-02-postgres This snippet demonstrates the creation of two PostgreSQL tables: 'cat_colors' and 'cats'. It includes definitions for primary keys, constraints, and foreign key relationships. ```Zig try db.exec( create table if not exists cat_colors ( id integer primary key generated always as identity, name text not null unique ); create table if not exists cats ( id integer primary key generated always as identity, name text not null, color_id integer not null references cat_colors(id) ); ); ``` -------------------------------- ### Find Files Modified in Last 24 Hours (Zig) Source: https://cookbook.ziglang.cc/01-03-file-modified-24h-ago This code snippet finds files modified within the last 24 hours. It gets the current working directory, iterates through files recursively, and checks their modification times using `fs.cwd()`, `walk()`, and `statFile()`. ```Zig //! Find files that have been modified in the last 24 hours const std = @import("std"); const builtin = @import("builtin"); const fs = std.fs; const print = std.debug.print; pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); const allocator = gpa.allocator(); var iter_dir = try fs.cwd().openDir("src", .{ .iterate = true }); defer iter_dir.close(); var walker = try iter_dir.walk(allocator); defer walker.deinit(); const now = std.time.nanoTimestamp(); while (try walker.next()) |entry| { if (entry.kind != .file) { continue; } const stat = try iter_dir.statFile(entry.path); const last_modified = stat.mtime; const duration = now - last_modified; if (duration < std.time.ns_per_hour * 24) { print("Last modified: {d} seconds ago, size:{d} bytes, filename: {s}\n", .{ @divTrunc(duration, std.time.ns_per_s), stat.size, entry.path, }); } } } ``` -------------------------------- ### Testing WebSocket Server with Browser Console Source: https://cookbook.ziglang.cc/05-03-http-server-std This JavaScript code snippet shows how to connect to the Zig WebSocket server from a web browser's developer console. It establishes a WebSocket connection, sets up a listener for incoming messages, and provides a way to send messages to the server. ```JavaScript var webSocket = new WebSocket('ws://localhost:8080'); webSocket.onmessage = function(data) { console.log(data); } ``` -------------------------------- ### Zig HTTP Server Implementation Source: https://cookbook.ziglang.cc/05-03-http-server-std This Zig code implements a basic HTTP server that listens on a specified IP address and port. It handles incoming TCP connections by spawning a new thread for each. The server parses HTTP requests, supports upgrading to WebSocket connections, and provides a simple HTTP response. It utilizes Zig's standard library for networking and HTTP handling. ```Zig const std = @import("std"); const log = std.log; const WebSocket = std.http.WebSocket; const Request = std.http.Server.Request; const Connection = std.net.Server.Connection; const MAX_BUF = 1024; pub fn main() !void { const addr = try std.net.Address.parseIp("127.0.0.1", 8080); var server = try std.net.Address.listen(addr, .{ .reuse_address = true }); defer server.deinit(); log.info("Start HTTP server at {any}", .{addr}); while (true) { const conn = server.accept() catch |err| { log.err("failed to accept connection: {s}", .{@errorName(err)}); continue; }; _ = std.Thread.spawn(.{}, accept, .{conn}) catch |err| { log.err("unable to spawn connection thread: {s}", .{@errorName(err)}); conn.stream.close(); continue; }; } } fn accept(conn: Connection) !void { defer conn.stream.close(); log.info("Got new client({any})!", .{conn.address}); var read_buffer: [MAX_BUF]u8 = undefined; var server = std.http.Server.init(conn, &read_buffer); while (server.state == .ready) { var request = server.receiveHead() catch |err| switch (err) { error.HttpConnectionClosing => return, else => return err, }; var ws: WebSocket = undefined; var send_buf: [MAX_BUF]u8 = undefined; var recv_buf: [MAX_BUF]u8 align(4) = undefined; if (try ws.init(&request, &send_buf, &recv_buf)) { // Upgrade to web socket successfully. serveWebSocket(&ws) catch |err| switch (err) { error.ConnectionClose => { log.info("Client({any}) closed!", .{conn.address}); break; }, else => return err, }; } else { try serveHTTP(&request); } } } fn serveHTTP(request: *Request) !void { try request.respond( "Hello World from Zig HTTP server", .{ .extra_headers = &.{ .{ .name = "custom header", .value = "custom value" }, }, }, ); } fn serveWebSocket(ws: *WebSocket) !void { try ws.writeMessage("Message from zig", .text); while (true) { const msg = try ws.readSmallMessage(); try ws.writeMessage(msg.data, msg.opcode); } } ```