polls on atproto pollz.waow.tech
atproto zig
at main 69 lines 2.3 kB view raw
1const std = @import("std"); 2const net = std.net; 3const posix = std.posix; 4const Thread = std.Thread; 5const db = @import("db.zig"); 6const http_server = @import("http.zig"); 7const tap = @import("tap.zig"); 8 9// max concurrent http connections (prevents resource exhaustion) 10const MAX_HTTP_WORKERS = 16; 11 12// socket timeout in seconds 13const SOCKET_TIMEOUT_SECS = 30; 14 15pub fn main() !void { 16 var gpa = std.heap.GeneralPurposeAllocator(.{}){}; 17 defer _ = gpa.deinit(); 18 const allocator = gpa.allocator(); 19 20 // init sqlite - use DATA_PATH env or default to /data/pollz.db 21 const db_path = posix.getenv("DATA_PATH") orelse "/data/pollz.db"; 22 try db.init(db_path); 23 defer db.close(); 24 25 // start tap consumer in background 26 const tap_thread = try Thread.spawn(.{}, tap.consumer, .{allocator}); 27 defer tap_thread.join(); 28 29 // init thread pool for http connections 30 var pool: Thread.Pool = undefined; 31 try pool.init(.{ 32 .allocator = allocator, 33 .n_jobs = MAX_HTTP_WORKERS, 34 }); 35 defer pool.deinit(); 36 37 // start http server (bind to 0.0.0.0 for containerized deployments) 38 const address = try net.Address.parseIp("0.0.0.0", 3000); 39 var server = try address.listen(.{ .reuse_address = true }); 40 defer server.deinit(); 41 42 std.debug.print("pollz backend listening on http://127.0.0.1:3000 (max {} workers)\n", .{MAX_HTTP_WORKERS}); 43 44 while (true) { 45 const conn = server.accept() catch |err| { 46 std.debug.print("accept error: {}\n", .{err}); 47 continue; 48 }; 49 50 // set socket timeouts to prevent slow client attacks 51 setSocketTimeout(conn.stream.handle, SOCKET_TIMEOUT_SECS) catch |err| { 52 std.debug.print("failed to set socket timeout: {}\n", .{err}); 53 }; 54 55 pool.spawn(http_server.handleConnection, .{conn}) catch |err| { 56 std.debug.print("pool spawn error: {}\n", .{err}); 57 conn.stream.close(); 58 }; 59 } 60} 61 62fn setSocketTimeout(fd: posix.fd_t, secs: u32) !void { 63 const timeout = std.mem.toBytes(posix.timeval{ 64 .sec = @intCast(secs), 65 .usec = 0, 66 }); 67 try posix.setsockopt(fd, posix.SOL.SOCKET, posix.SO.RCVTIMEO, &timeout); 68 try posix.setsockopt(fd, posix.SOL.SOCKET, posix.SO.SNDTIMEO, &timeout); 69}