Something went wrong. Try again.
semantic bufo search find-bufo.com
bufo
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136//! bufo-server — zig port of the find-bufo backend.//!//! env: PORT (8080), VOYAGE_API_TOKEN, TURBOPUFFER_API_KEY,//! TURBOPUFFER_NAMESPACE (bufos-v3), STATIC_DIR (../static),//! BOT_STATS_URL, PUBLIC_URL, LOGFIRE_TOKEN (optional), BUFO_ENV.
const std = @import("std");const Io = std.Io;const Thread = std.Thread;const logfire = @import("logfire");
const server = @import("server.zig");const search = @import("search.zig");const voyage = @import("voyage.zig");const tpuf = @import("tpuf");const ratelimit = @import("ratelimit.zig");
const SOCKET_TIMEOUT_SECS = 30;
var threaded_io: Io.Threaded = undefined;pub const std_options_debug_threaded_io: ?*Io.Threaded = &threaded_io;
pub const std_options: std.Options = .{ .log_level = .info, .logFn = logfire.logFn,};
pub const panic = std.debug.FullPanic(logfire.panicFn);
fn getenv(name: [*:0]const u8) ?[]const u8 { return if (std.c.getenv(name)) |p| std.mem.span(p) else null;}
pub fn main(init: std.process.Init) !void { _ = init; const allocator = std.heap.smp_allocator;
threaded_io = Io.Threaded.init(allocator, .{}); const io = threaded_io.io();
const maybe_logfire: ?*logfire.Logfire = logfire.configure(.{ .service_name = "find-bufo", .service_version = "0.0.1", .environment = getenv("BUFO_ENV") orelse "development", .pending_spans = false, }) catch |err| blk: { std.debug.print("logfire init failed: {t}, continuing without observability\n", .{err}); break :blk null; }; defer if (maybe_logfire) |lf| lf.shutdown();
const port: u16 = std.fmt.parseInt(u16, getenv("PORT") orelse "8080", 10) catch 8080; const voyage_key = getenv("VOYAGE_API_TOKEN") orelse { std.log.err("VOYAGE_API_TOKEN not set", .{}); return error.MissingConfig; }; const tpuf_key = getenv("TURBOPUFFER_API_KEY") orelse { std.log.err("TURBOPUFFER_API_KEY not set", .{}); return error.MissingConfig; }; const namespace = getenv("TURBOPUFFER_NAMESPACE") orelse "bufos-v3"; const static_dir = getenv("STATIC_DIR") orelse "../static"; const bot_stats_url = getenv("BOT_STATS_URL") orelse "https://bot-stats.find-bufo.com/"; const public_url = getenv("PUBLIC_URL") orelse "https://find-bufo.com";
// one connection-pooled client shared by every request thread; a fresh // client per request meant three TLS handshakes per search var http_client: std.http.Client = .{ .allocator = allocator, .io = io }; defer http_client.deinit();
var tpuf_transport = tpuf.zttp.Client.initWithUserAgent(io, allocator, "find-bufo/0.0.1-zig (+https://find-bufo.com)"); defer tpuf_transport.deinit(); const tpuf_client: tpuf.Client = .init(&tpuf_transport, .{ .api_key = tpuf_key }); const bufos = try tpuf_client.namespace(namespace);
var limiter = ratelimit.Limiter.init(allocator); var upload_gate: server.UploadGate = .{};
var app = server.App{ .io = io, .allocator = allocator, .deps = .{ .io = io, .base_allocator = allocator, .voyage = .{ .http = &http_client, .api_key = voyage_key, .user_agent = "find-bufo/0.0.1-zig" }, .tpuf = bufos, }, .resolver = .{ .io = io, .http = &http_client, .static_dir = static_dir }, .botm = .{ .io = io, .http = &http_client, .bot_stats_url = bot_stats_url, .public_url = public_url }, .limiter = &limiter, .upload_gate = &upload_gate, .static_dir = static_dir, };
var addr = try Io.net.IpAddress.parse("::", port); var listener = addr.listen(io, .{ .reuse_address = true }) catch |err| { std.log.err("failed to listen on port {d}: {t}", .{ port, err }); return err; }; defer listener.deinit(io);
std.log.info("bufo-server listening on :{d} (namespace={s}, static={s})", .{ port, namespace, static_dir });
while (true) { const stream = listener.accept(io) catch |err| { std.log.err("accept error: {t}", .{err}); continue; }; setSocketTimeout(stream.socket.handle, SOCKET_TIMEOUT_SECS) catch {}; const t = Thread.spawn(.{}, server.handleConnection, .{ stream, &app }) catch |err| { std.log.err("spawn error: {t}", .{err}); stream.close(io); continue; }; t.detach(); }}
fn setSocketTimeout(fd: std.posix.fd_t, secs: u32) !void { const timeout = std.mem.toBytes(std.posix.timeval{ .sec = @intCast(secs), .usec = 0 }); try std.posix.setsockopt(fd, std.posix.SOL.SOCKET, std.posix.SO.RCVTIMEO, &timeout); try std.posix.setsockopt(fd, std.posix.SOL.SOCKET, std.posix.SO.SNDTIMEO, &timeout);}
test { std.testing.refAllDecls(@This()); _ = search; _ = server; _ = @import("fusion.zig"); _ = @import("filter.zig"); _ = @import("resolver.zig"); _ = @import("botm.zig"); _ = @import("ratelimit.zig"); _ = @import("image.zig");}