idk
This commit is contained in:
parent
29f12b6779
commit
6340cb0cbe
3 changed files with 162 additions and 24 deletions
|
@ -5,7 +5,7 @@ pub fn build(b: *std.Build) void {
|
|||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "master",
|
||||
.name = "httz",
|
||||
.root_source_file = b.path("src/main.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
|
|
47
src/main.zig
47
src/main.zig
|
@ -1,43 +1,44 @@
|
|||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const net = std.net;
|
||||
const http = std.http;
|
||||
const heap = std.heap;
|
||||
|
||||
pub const Application = @import("application.zig").Application;
|
||||
const Listener = @import("root.zig").Listener(Context);
|
||||
const Request = Listener.Request;
|
||||
const Response = Listener.Response;
|
||||
|
||||
const Context = struct {};
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
defer _ = gpa.deinit();
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
var router = Router.init(allocator, handleError);
|
||||
defer router.deinit();
|
||||
|
||||
try router.putRoute("/", &handle);
|
||||
// try listener.router.putRoute("/error", &handleError);
|
||||
// try listener.router.putRoute("//pee", &handleError);
|
||||
// try listener.router.putRoute("/error/*", &handleError);
|
||||
|
||||
const address = try net.Address.parseIp("0.0.0.0", 8080);
|
||||
var listener = App.init(.{
|
||||
const address = net.Address.initIp4(.{ 127, 0, 0, 1 }, 8080);
|
||||
const listener = try Listener.init(.{
|
||||
.address = address,
|
||||
.allocator = allocator,
|
||||
// .root_handler = ,
|
||||
.handler = handle,
|
||||
.errorHandler = handleError,
|
||||
});
|
||||
defer listener.deinit();
|
||||
|
||||
try std.io.getStdErr().writer().print("listening at {}\n", .{address});
|
||||
try listener.listen();
|
||||
}
|
||||
|
||||
const App = Application(DummyContext);
|
||||
const Router = @import("application.zig").Router(App.HandlerFn);
|
||||
const DummyContext = struct {};
|
||||
|
||||
fn handle(event: *App.Event) anyerror!void {
|
||||
try event.res.body.appendSlice("hello there");
|
||||
fn handle(req: *const Request) anyerror!Response {
|
||||
if (std.mem.eql(u8, req.uri.path.percent_encoded, "/")) {
|
||||
return .{ .body = "home!" };
|
||||
} else {
|
||||
return .{ .body = "somewhere else!" };
|
||||
}
|
||||
}
|
||||
|
||||
fn handleError(event: *App.Event) anyerror!void {
|
||||
try event.res.body.appendSlice("ahoy, an error occurred");
|
||||
fn handleError(_: *const Request, err: [:0]const u8) anyerror!Response {
|
||||
return .{
|
||||
.body = "oops! something went wrong on the server side.",
|
||||
.options = .{
|
||||
.status = .internal_server_error,
|
||||
.reason = err,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
137
src/root.zig
Normal file
137
src/root.zig
Normal file
|
@ -0,0 +1,137 @@
|
|||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const net = std.net;
|
||||
// const http = std.http;
|
||||
|
||||
pub fn Listener(comptime Context: type) type {
|
||||
_ = Context;
|
||||
return struct {
|
||||
// ctx: *Context,
|
||||
server: *net.Server,
|
||||
allocator: mem.Allocator,
|
||||
handler: HandlerFn,
|
||||
errorHandler: ErrorHandlerFn,
|
||||
|
||||
pub const InitOptions = struct {
|
||||
address: net.Address,
|
||||
allocator: mem.Allocator,
|
||||
listen_options: net.Address.ListenOptions = .{ .reuse_address = true },
|
||||
handler: HandlerFn,
|
||||
errorHandler: ErrorHandlerFn,
|
||||
};
|
||||
|
||||
pub fn init(options: InitOptions) !Self {
|
||||
var server = try options.address.listen(options.listen_options);
|
||||
return .{
|
||||
// .ctx = options.ctx,
|
||||
.server = &server,
|
||||
.allocator = options.allocator,
|
||||
.handler = options.handler,
|
||||
.errorHandler = options.errorHandler,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: Self) void {
|
||||
self.server.deinit();
|
||||
}
|
||||
|
||||
pub fn listen(self: Self) !void {
|
||||
while (true) {
|
||||
const read_buf = try self.allocator.alloc(u8, 1024 * 32);
|
||||
defer self.allocator.free(read_buf);
|
||||
|
||||
const connection = try self.server.accept();
|
||||
defer connection.stream.close();
|
||||
|
||||
var http = std.http.Server.init(connection, read_buf);
|
||||
http: while (true) {
|
||||
var req = http.receiveHead() catch |e| if (e == error.HttpConnectionClosing) break :http else return e;
|
||||
const request = Request{
|
||||
.uri = try std.Uri.parseAfterScheme("http://", req.head.target),
|
||||
.http = &req,
|
||||
};
|
||||
const res: Response = self.handler(&request) catch |e| blk: {
|
||||
break :blk self.errorHandler(&request, @errorName(e)) catch |err| {
|
||||
try req.respond("ahoy, an internal error occurred.", .{
|
||||
.status = .internal_server_error,
|
||||
.reason = @errorName(err),
|
||||
});
|
||||
continue :http;
|
||||
};
|
||||
};
|
||||
try req.respond(res.body, res.options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const Request = struct {
|
||||
uri: std.Uri,
|
||||
http: *std.http.Server.Request,
|
||||
};
|
||||
|
||||
pub const Response = struct {
|
||||
options: std.http.Server.Request.RespondOptions = .{},
|
||||
body: []const u8,
|
||||
};
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub const HandlerFn = *const fn (req: *const Request) anyerror!Response;
|
||||
pub const ErrorHandlerFn = *const fn (req: *const Request, err: [:0]const u8) anyerror!Response;
|
||||
|
||||
// pub const Router = struct {
|
||||
// static_routes: std.StringHashMap(HandlerFn),
|
||||
|
||||
// fallback_handler: HandlerFn,
|
||||
// error_handler: HandlerFn,
|
||||
|
||||
// allocator: mem.Allocator,
|
||||
|
||||
// pub const Options = struct {
|
||||
// allocator: mem.Allocator,
|
||||
// fallback_handler: HandlerFn,
|
||||
// error_handler: HandlerFn,
|
||||
// };
|
||||
|
||||
// pub fn init(options: Options) Router {
|
||||
// return .{
|
||||
// .allocator = options.allocator,
|
||||
// .fallback_handler = options.fallback_handler,
|
||||
// .error_handler = options.error_handler,
|
||||
// .static_routes = std.StringHashMap(HandlerFn).init(options.allocator),
|
||||
// };
|
||||
// }
|
||||
|
||||
// pub fn deinit(self: Router) void {
|
||||
// self.static_routes.deinit();
|
||||
// }
|
||||
|
||||
// pub fn get(self: Router, path: []const u8) HandlerFn {
|
||||
// if (self.static_routes.get(path)) |handler_fn|
|
||||
// return handler_fn
|
||||
// else
|
||||
// return self.fallback_handler;
|
||||
// }
|
||||
|
||||
// pub fn put(self: Router, path: []const u8, handler_fn: HandlerFn) !void {
|
||||
// if (mem.indexOfAny(u8, path, "*{}") != null) {
|
||||
// return error.UnsupportedRoute;
|
||||
// } else try self.static_routes.put(path, handler_fn);
|
||||
// }
|
||||
|
||||
// pub fn remove(self: Router, path: []const u8) void {
|
||||
// if (mem.indexOfAny(u8, path, "*{}") != null) {
|
||||
// return;
|
||||
// } else _ = self.static_routes.remove(path);
|
||||
// }
|
||||
|
||||
// pub fn handler(req: Request, ctx: Router) Response {
|
||||
// const uri = std.Uri.parseAfterScheme("http://", req.http.head.target);
|
||||
// if (ctx.get(uri.path.percent_encoded)) |handler_fn|
|
||||
// return handler_fn(req)
|
||||
// else
|
||||
// return ctx.fallback_handler(req);
|
||||
// }
|
||||
// };
|
||||
};
|
||||
}
|
Loading…
Add table
Reference in a new issue