const std = @import("std"); const zzz = @import("zzz"); const tardy = @import("tardy"); const _dispatchers = @import("dispatchers.zig"); const log = std.log.scoped(.@"pgmql/http"); /// HTTP API server structure. pub const Server = struct { const Self = @This(); const Tardy = tardy.Tardy(.auto); const Http = zzz.HTTP.Server(.plain); const Router = Http.Router; const Route = Http.Route; const Context = Http.Context; allocator: std.mem.Allocator, dispatchers: []const _dispatchers.Dispatcher, /// Host to use. host: []const u8 = "127.0.0.1", /// Port to use. port: u16 = 8122, /// Tardy runtime, if initialized. ta: ?Tardy = null, /// HTTP router, if initialized. router: ?Router = null, /// Initialize a new HTTP API server. pub fn init(allocator: std.mem.Allocator, dispatchers: []const _dispatchers.Dispatcher) Self { return Self{ .allocator = allocator, .dispatchers = dispatchers, }; } /// Deinitialize the HTTP API server. pub fn deinit(self: *Self) void { if (self.ta) |*_ta| { _ta.deinit(); } if (self.router) |*_router| { _router.deinit(); } } /// Setup Tardy and ZZZ. fn setup(self: *Self) !void { self.ta = try Tardy.init(.{ .allocator = self.allocator, .threading = .auto, }); self.router = Router.init(self.allocator); // Set error JSON response. //TODO Improve zzz to allow this. // Set not found JSON response. self.router.?.serve_not_found(Route.init().get({}, struct { fn f(context: *Context, _: void) !void { // Return a "not found" error as JSON. try context.respond(.{ .status = zzz.HTTP.Status.@"Not Found", .body = "{\"error\": \"not found\"}", .mime = zzz.HTTP.Mime.JSON, }); } }.f)); } /// Add API endpoints for the given dispatchers. fn addApi(self: *Self) !void { for (self.dispatchers) |dispatcher| { // Add an endpoint of each dispatcher. _ = dispatcher; } } /// Start the HTTP API server. pub fn start(self: *Self) !void { try self.setup(); try self.ta.?.entry( self, struct { fn f(runtime: *tardy.Runtime, server: *const Server) !void { // Start a new HTTP server with the provided configuration. var http = Http.init(runtime.allocator, .{}); try http.bind(.{ .ip = .{ .host = server.host, .port = server.port } }); try http.serve(&server.router.?, runtime); } }.f, {}, struct { fn f(runtime: *tardy.Runtime, _: void) !void { try Http.clean(runtime); } }.f ); } };