This repository has no description
0

Configure Feed

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

weir / src / main.zig
3.9 kB 107 lines
1//! weir: a minimal prefect server whose database is an atproto repo. 2//! 3//! boot: load (or mint) the workspace signing key, replay the repo CAR from 4//! disk, hydrate the appview, serve. env: 5//! WEIR_PORT default 4200 6//! WEIR_DATA_DIR default ./data 7 8const std = @import("std"); 9const httpz = @import("httpz"); 10 11const repo_mod = @import("repo.zig"); 12const cache_mod = @import("cache.zig"); 13const api_mod = @import("api.zig"); 14 15const log = std.log.scoped(.main); 16 17pub fn main() !void { 18 const allocator = std.heap.smp_allocator; 19 20 var threaded = std.Io.Threaded.init(allocator, .{}); 21 defer threaded.deinit(); 22 const io = threaded.io(); 23 24 const port: u16 = if (std.c.getenv("WEIR_PORT")) |p| 25 std.fmt.parseInt(u16, std.mem.span(p), 10) catch 4200 26 else 27 4200; 28 const data_dir: []const u8 = if (std.c.getenv("WEIR_DATA_DIR")) |d| 29 std.mem.span(d) 30 else 31 "data"; 32 33 const repo = try repo_mod.Repo.boot(allocator, io, data_dir); 34 defer repo.deinit(allocator); 35 36 var cache: cache_mod.Cache = blk: { 37 const backend = if (std.c.getenv("WEIR_CACHE")) |c| std.mem.span(c) else "burner"; 38 if (std.mem.eql(u8, backend, "redis")) { 39 const host = if (std.c.getenv("WEIR_REDIS_HOST")) |h| std.mem.span(h) else "127.0.0.1"; 40 const redis_port: u16 = if (std.c.getenv("WEIR_REDIS_PORT")) |p| 41 std.fmt.parseInt(u16, std.mem.span(p), 10) catch 6379 42 else 43 6379; 44 log.info("appview backend: redis at {s}:{d}", .{ host, redis_port }); 45 break :blk try cache_mod.Cache.initRedis(allocator, io, host, redis_port); 46 } 47 log.info("appview backend: burner-redis (embedded)", .{}); 48 break :blk cache_mod.Cache.initBurner(allocator, io); 49 }; 50 defer cache.deinit(); 51 52 const commit_every: usize = if (std.c.getenv("WEIR_COMMIT_EVERY")) |c| 53 std.fmt.parseInt(usize, std.mem.span(c), 10) catch 1 54 else 55 1; 56 57 const ui_dir: ?[]const u8 = blk: { 58 const dir = if (std.c.getenv("WEIR_UI_DIR")) |d| std.mem.span(d) else "ui"; 59 var check_buf: [512]u8 = undefined; 60 const index_path = std.fmt.bufPrint(&check_buf, "{s}/index.html", .{dir}) catch break :blk null; 61 var probe: [16]u8 = undefined; 62 _ = std.Io.Dir.readFile(.cwd(), io, index_path, &probe) catch break :blk null; 63 break :blk dir; 64 }; 65 66 var api = api_mod.Api{ 67 .allocator = allocator, 68 .io = io, 69 .repo = repo, 70 .cache = &cache, 71 .commit_every = commit_every, 72 .ui_dir = ui_dir, 73 }; 74 if (ui_dir) |d| { 75 log.info("ui bundle: {s}/ (open http://127.0.0.1:{d})", .{ d, port }); 76 } else { 77 log.info("no ui bundle (run `just fetch-ui` to serve the prefect ui)", .{}); 78 } 79 if (commit_every > 1) log.info("commit cadence: every {d} writes", .{commit_every}); 80 81 log.info("workspace did: {s}", .{repo.did}); 82 log.info("repo: {d} records, data dir: {s}", .{ repo.record_count, data_dir }); 83 if (repo.record_count > 0) { 84 var hydrate_arena = std.heap.ArenaAllocator.init(allocator); 85 defer hydrate_arena.deinit(); 86 const applied = try api.hydrate(hydrate_arena.allocator()); 87 log.info("appview hydrated: {d} records replayed from the repo", .{applied}); 88 } 89 90 const ip = try std.Io.net.IpAddress.parse("127.0.0.1", port); 91 var server = try httpz.Server(*api_mod.Api).init(io, allocator, .{ 92 .address = .{ .ip = ip }, 93 .request = .{ .max_body_size = 16 * 1024 * 1024 }, 94 }, &api); 95 defer server.deinit(); 96 97 log.info("listening on http://127.0.0.1:{d} (api: /api, atproto: /xrpc)", .{port}); 98 try server.listen(); 99} 100 101test { 102 _ = @import("repo.zig"); 103 _ = @import("cache.zig"); 104 _ = @import("json_cbor.zig"); 105 _ = @import("util.zig"); 106 _ = @import("api.zig"); 107}