mirror of
https://github.com/jetzig-framework/jetzig.git
synced 2025-05-15 06:26:07 +00:00
WIP
This commit is contained in:
parent
c84d2fcd71
commit
458ea252e7
@ -19,12 +19,12 @@
|
|||||||
.hash = "12208a1de366740d11de525db7289345949f5fd46527db3f89eecc7bb49b012c0732",
|
.hash = "12208a1de366740d11de525db7289345949f5fd46527db3f89eecc7bb49b012c0732",
|
||||||
},
|
},
|
||||||
.smtp_client = .{
|
.smtp_client = .{
|
||||||
.url = "https://github.com/karlseguin/smtp_client.zig/archive/e79e411862d4f4d41657bf41efb884efca3d67dd.tar.gz",
|
.url = "https://github.com/karlseguin/smtp_client.zig/archive/964152ad4e19dc1d22f6def6f659c86df60e7832.tar.gz",
|
||||||
.hash = "12209907c69891a38e6923308930ac43bfb40135bc609ea370b5759fc2e1c4f57284",
|
.hash = "1220d4f1c2472769b0d689ea878f41f0a66cb07f28569a138aea2c0a648a5c90dd4e",
|
||||||
},
|
},
|
||||||
.httpz = .{
|
.httpz = .{
|
||||||
.url = "https://github.com/karlseguin/http.zig/archive/bf748c6508090464213d3088a77d51faf9cd0876.tar.gz",
|
.url = "https://github.com/karlseguin/http.zig/archive/0d4a5cd520a54eaf800438e0b9093c77c90dcf11.tar.gz",
|
||||||
.hash = "12209b7426293ebe5075b930ae6029c009bfb6deb7ff92b9d69e28463abd14ad03da",
|
.hash = "12209b8216a80f21be12d43e588811150bdbbb53d35eac6a2a61c460f197350e19ad",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -16,7 +16,6 @@ pub const markdown = @import("jetzig/markdown.zig");
|
|||||||
pub const jobs = @import("jetzig/jobs.zig");
|
pub const jobs = @import("jetzig/jobs.zig");
|
||||||
pub const mail = @import("jetzig/mail.zig");
|
pub const mail = @import("jetzig/mail.zig");
|
||||||
pub const kv = @import("jetzig/kv.zig");
|
pub const kv = @import("jetzig/kv.zig");
|
||||||
pub const HttpzServer = @import("jetzig/HttpzServer.zig");
|
|
||||||
|
|
||||||
/// The primary interface for a Jetzig application. Create an `App` in your application's
|
/// The primary interface for a Jetzig application. Create an `App` in your application's
|
||||||
/// `src/main.zig` and call `start` to launch the application.
|
/// `src/main.zig` and call `start` to launch the application.
|
||||||
|
@ -1,58 +0,0 @@
|
|||||||
const std = @import("std");
|
|
||||||
|
|
||||||
const httpz = @import("httpz");
|
|
||||||
|
|
||||||
const jetzig = @import("../jetzig.zig");
|
|
||||||
|
|
||||||
allocator: std.mem.Allocator,
|
|
||||||
server: httpz.ServerCtx(void, void),
|
|
||||||
|
|
||||||
const HttpzServer = @This();
|
|
||||||
|
|
||||||
const DispatcherFn = *const fn (*jetzig.Server, *httpz.Request, *httpz.Response) anyerror!void;
|
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator, dispatcherFn: DispatcherFn) !HttpzServer {
|
|
||||||
return .{
|
|
||||||
.allocator = allocator,
|
|
||||||
.dispatcherFn = dispatcherFn,
|
|
||||||
.server = try httpz.Server().init(allocator, .{ .port = 8080 }),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *HttpzServer) void {
|
|
||||||
self.server.deinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn configure(self: *HttpzServer, dispatcherFn: DispatcherFn) void {
|
|
||||||
// Bypass router.
|
|
||||||
self.server.notFound(dispatcherFn);
|
|
||||||
}
|
|
||||||
|
|
||||||
// var server = ;
|
|
||||||
//
|
|
||||||
// // set a global dispatch for any routes defined from this point on
|
|
||||||
// server.dispatcher(mainDispatcher);
|
|
||||||
//
|
|
||||||
// // set a dispatcher for this route
|
|
||||||
// // note the use of "deleteC" the "C" is for Configuration and is used
|
|
||||||
// // since Zig doesn't have overloading or optional parameters.
|
|
||||||
// server.router().deleteC("/v1/session", logout, .{.dispatcher = loggedIn})
|
|
||||||
// ...
|
|
||||||
//
|
|
||||||
// fn mainDispatcher(action: httpz.Action(void), req: *httpz.Request, res: *httpz.Response) !void {
|
|
||||||
// res.header("cors", "isslow");
|
|
||||||
// return action(req, res);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fn loggedIn(action: httpz.Action(void), req: *httpz.Request, res: *httpz.Response) !void {
|
|
||||||
// if (req.header("authorization")) |_auth| {
|
|
||||||
// // TODO: make sure "auth" is valid!
|
|
||||||
// return mainDispatcher(action, req, res);
|
|
||||||
// }
|
|
||||||
// res.status = 401;
|
|
||||||
// res.body = "Not authorized";
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fn logout(req: *httpz.Request, res: *httpz.Response) !void {
|
|
||||||
// ...
|
|
||||||
// }
|
|
@ -169,8 +169,23 @@ pub fn process(self: *Request) !void {
|
|||||||
self.processed = true;
|
self.processed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const CallbackState = struct {
|
||||||
|
arena: *std.heap.ArenaAllocator,
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn responseCompleteCallback(ptr: *anyopaque) void {
|
||||||
|
var state: *CallbackState = @ptrCast(@alignCast(ptr));
|
||||||
|
state.arena.deinit();
|
||||||
|
state.allocator.destroy(state.arena);
|
||||||
|
state.allocator.destroy(state);
|
||||||
|
}
|
||||||
|
|
||||||
/// Set response headers, write response payload, and finalize the response.
|
/// Set response headers, write response payload, and finalize the response.
|
||||||
pub fn respond(self: *Request) !void {
|
pub fn respond(
|
||||||
|
self: *Request,
|
||||||
|
state: *CallbackState,
|
||||||
|
) !void {
|
||||||
if (!self.processed) unreachable;
|
if (!self.processed) unreachable;
|
||||||
|
|
||||||
var cookie_it = self.cookies.headerIterator();
|
var cookie_it = self.cookies.headerIterator();
|
||||||
@ -179,20 +194,14 @@ pub fn respond(self: *Request) !void {
|
|||||||
try self.response.headers.append("Set-Cookie", header);
|
try self.response.headers.append("Set-Cookie", header);
|
||||||
}
|
}
|
||||||
|
|
||||||
var std_response_headers = try self.response.headers.stdHeaders();
|
|
||||||
defer std_response_headers.deinit(self.allocator);
|
|
||||||
|
|
||||||
for (self.response.headers.headers.items) |header| {
|
for (self.response.headers.headers.items) |header| {
|
||||||
self.httpz_response.header(
|
self.httpz_response.header(header.name, header.value);
|
||||||
try self.httpz_response.arena.dupe(u8, header.name),
|
|
||||||
try self.httpz_response.arena.dupe(u8, header.value),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const status = jetzig.http.status_codes.get(self.response.status_code);
|
const status = jetzig.http.status_codes.get(self.response.status_code);
|
||||||
self.httpz_response.status = try status.getCodeInt();
|
self.httpz_response.status = try status.getCodeInt();
|
||||||
self.httpz_response.body = try self.httpz_response.arena.dupe(u8, self.response.content);
|
self.httpz_response.body = self.response.content;
|
||||||
// try self.httpz_response.write();
|
self.httpz_response.callback(responseCompleteCallback, @ptrCast(state));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Render a response. This function can only be called once per request (repeat calls will
|
/// Render a response. This function can only be called once per request (repeat calls will
|
||||||
|
@ -60,48 +60,64 @@ pub fn deinit(self: *Server) void {
|
|||||||
self.allocator.free(self.options.bind);
|
self.allocator.free(self.options.bind);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Dispatcher = struct {
|
||||||
|
server: *Server,
|
||||||
|
|
||||||
|
pub fn handle(self: Dispatcher, request: *httpz.Request, response: *httpz.Response) void {
|
||||||
|
self.server.processNextRequest(request, response) catch |err| {
|
||||||
|
self.server.errorHandlerFn(request, response, err);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
pub fn listen(self: *Server) !void {
|
pub fn listen(self: *Server) !void {
|
||||||
var httpz_server = try httpz.ServerCtx(*jetzig.http.Server, *jetzig.http.Server).init(
|
var httpz_server = try httpz.ServerCtx(Dispatcher, Dispatcher).init(
|
||||||
self.allocator,
|
self.allocator,
|
||||||
.{
|
.{
|
||||||
.port = self.options.port,
|
.port = self.options.port,
|
||||||
.address = self.options.bind,
|
.address = self.options.bind,
|
||||||
.workers = .{ .count = 20 },
|
.thread_pool = .{ .count = @intCast(try std.Thread.getCpuCount()) },
|
||||||
.thread_pool = .{ .count = 1 },
|
|
||||||
},
|
},
|
||||||
self,
|
Dispatcher{ .server = self },
|
||||||
);
|
);
|
||||||
defer httpz_server.deinit();
|
defer httpz_server.deinit();
|
||||||
httpz_server.notFound(jetzig.http.Server.dispatcherFn);
|
|
||||||
// httpz_server.dispatcher(jetzig.http.Server.dispatcherFn);
|
try self.logger.INFO("Listening on http://{s}:{} [{s}]", .{
|
||||||
|
self.options.bind,
|
||||||
|
self.options.port,
|
||||||
|
@tagName(self.options.environment),
|
||||||
|
});
|
||||||
|
|
||||||
|
self.initialized = true;
|
||||||
|
|
||||||
return try httpz_server.listen();
|
return try httpz_server.listen();
|
||||||
// const address = try std.net.Address.parseIp(self.options.bind, self.options.port);
|
|
||||||
// self.std_net_server = try address.listen(.{ .reuse_port = true });
|
|
||||||
//
|
|
||||||
// self.initialized = true;
|
|
||||||
//
|
|
||||||
// try self.logger.INFO("Listening on http://{s}:{} [{s}]", .{
|
|
||||||
// self.options.bind,
|
|
||||||
// self.options.port,
|
|
||||||
// @tagName(self.options.environment),
|
|
||||||
// });
|
|
||||||
// try self.processRequests();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dispatcherFn(self: *Server, request: *httpz.Request, response: *httpz.Response) !void {
|
pub fn errorHandlerFn(self: *Server, request: *httpz.Request, response: *httpz.Response, err: anyerror) void {
|
||||||
var arena = std.heap.ArenaAllocator.init(self.allocator);
|
if (isBadHttpError(err)) return;
|
||||||
defer arena.deinit();
|
|
||||||
const allocator = arena.allocator();
|
self.logger.ERROR("Encountered error: {s} {s}", .{ @errorName(err), request.url.raw }) catch {};
|
||||||
try self.processNextRequest(allocator, request, response);
|
response.body = "500 Internal Server Error";
|
||||||
}
|
}
|
||||||
|
|
||||||
fn processNextRequest(
|
fn processNextRequest(
|
||||||
self: *Server,
|
self: *Server,
|
||||||
allocator: std.mem.Allocator,
|
|
||||||
httpz_request: *httpz.Request,
|
httpz_request: *httpz.Request,
|
||||||
httpz_response: *httpz.Response,
|
httpz_response: *httpz.Response,
|
||||||
) !void {
|
) !void {
|
||||||
|
const state = try self.allocator.create(jetzig.http.Request.CallbackState);
|
||||||
|
const arena = try self.allocator.create(std.heap.ArenaAllocator);
|
||||||
|
arena.* = std.heap.ArenaAllocator.init(self.allocator);
|
||||||
|
state.* = .{
|
||||||
|
.arena = arena,
|
||||||
|
.allocator = self.allocator,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Regular arena deinit occurs in jetzig.http.Request.responseCompletCallback
|
||||||
|
errdefer state.arena.deinit();
|
||||||
|
|
||||||
|
const allocator = state.arena.allocator();
|
||||||
|
|
||||||
const start_time = std.time.nanoTimestamp();
|
const start_time = std.time.nanoTimestamp();
|
||||||
|
|
||||||
var response = try jetzig.http.Response.init(allocator);
|
var response = try jetzig.http.Response.init(allocator);
|
||||||
@ -123,12 +139,12 @@ fn processNextRequest(
|
|||||||
|
|
||||||
try jetzig.http.middleware.beforeResponse(&middleware_data, &request);
|
try jetzig.http.middleware.beforeResponse(&middleware_data, &request);
|
||||||
|
|
||||||
try request.respond();
|
try request.respond(state);
|
||||||
|
|
||||||
try jetzig.http.middleware.afterResponse(&middleware_data, &request);
|
try jetzig.http.middleware.afterResponse(&middleware_data, &request);
|
||||||
jetzig.http.middleware.deinit(&middleware_data, &request);
|
jetzig.http.middleware.deinit(&middleware_data, &request);
|
||||||
|
|
||||||
// try self.logger.logRequest(&request);
|
try self.logger.logRequest(&request);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn renderResponse(self: *Server, request: *jetzig.http.Request) !void {
|
fn renderResponse(self: *Server, request: *jetzig.http.Request) !void {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user