basic listener
This commit is contained in:
commit
e538cbbcef
6 changed files with 302 additions and 0 deletions
107
src/main.zig
Normal file
107
src/main.zig
Normal file
|
@ -0,0 +1,107 @@
|
|||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const net = std.net;
|
||||
const http = std.http;
|
||||
const heap = std.heap;
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
defer _ = gpa.deinit();
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
const address = try net.Address.parseIp("0.0.0.0", 8080);
|
||||
var listener = Listener.init(address, allocator, &handler);
|
||||
defer listener.deinit();
|
||||
try listener.listen();
|
||||
}
|
||||
|
||||
pub fn handler(event: *Listener.Event) anyerror!void {
|
||||
try event.res.body.appendSlice("hello there");
|
||||
}
|
||||
|
||||
pub const Router = struct {};
|
||||
|
||||
pub const Listener = struct {
|
||||
address: net.Address,
|
||||
arena: heap.ArenaAllocator,
|
||||
handler: *const fn (event: *Event) anyerror!void,
|
||||
|
||||
pub fn init(address: net.Address, allocator: mem.Allocator, hand: *const fn (event: *Event) anyerror!void) Listener {
|
||||
return .{
|
||||
.address = address,
|
||||
.arena = heap.ArenaAllocator.init(allocator),
|
||||
.handler = hand,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Listener) void {
|
||||
self.arena.deinit();
|
||||
}
|
||||
|
||||
pub fn listen(self: *Listener) !void {
|
||||
var tcp = try self.address.listen(.{});
|
||||
defer tcp.deinit();
|
||||
std.debug.print("listening at: {any}\n", .{self.address});
|
||||
|
||||
while (true) {
|
||||
const read_buf = try self.arena.allocator().alloc(u8, 1024 * 32);
|
||||
const connection = try tcp.accept();
|
||||
var server = http.Server.init(connection, read_buf);
|
||||
try self.handle(&server);
|
||||
_ = self.arena.reset(.retain_capacity);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle(self: *Listener, server: *http.Server) !void {
|
||||
handler: while (true) {
|
||||
var req = server.receiveHead() catch |e| if (e == error.HttpConnectionClosing) break :handler else return e;
|
||||
|
||||
var event = Event{
|
||||
.req = .{
|
||||
.uri = try std.Uri.parseWithoutScheme(req.head.target),
|
||||
.headers = std.ArrayList(*const http.Header).init(self.arena.allocator()),
|
||||
},
|
||||
.res = .{
|
||||
.status = .ok,
|
||||
.headers = std.StringHashMap(*http.Header).init(self.arena.allocator()),
|
||||
.body = std.ArrayList(u8).init(self.arena.allocator()),
|
||||
},
|
||||
};
|
||||
|
||||
var header_it = req.iterateHeaders();
|
||||
while (header_it.next()) |header| try event.req.headers.append(&header);
|
||||
|
||||
try self.handler(&event);
|
||||
|
||||
try self.respondFromEvent(&event, &req);
|
||||
}
|
||||
}
|
||||
|
||||
fn respondFromEvent(self: *Listener, event: *Event, req: *http.Server.Request) !void {
|
||||
const res_body = try event.res.body.toOwnedSlice();
|
||||
const res_headers = try self.arena.allocator().alloc(http.Header, event.res.headers.count());
|
||||
var i: usize = 0;
|
||||
var header_it = event.res.headers.iterator();
|
||||
while (header_it.next()) |header_ptr| : (i += 1) res_headers[i] = header_ptr.value_ptr.*.*;
|
||||
try req.respond(res_body, .{
|
||||
.status = event.res.status,
|
||||
.extra_headers = res_headers,
|
||||
});
|
||||
}
|
||||
|
||||
pub const Event = struct {
|
||||
req: Request,
|
||||
res: Response,
|
||||
|
||||
pub const Request = struct {
|
||||
uri: std.Uri,
|
||||
// head: http.Server.Request.Head,
|
||||
headers: std.ArrayList(*const http.Header),
|
||||
};
|
||||
pub const Response = struct {
|
||||
status: http.Status,
|
||||
headers: std.StringHashMap(*http.Header),
|
||||
body: std.ArrayList(u8),
|
||||
};
|
||||
};
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue