Move to using zig master apis

This commit is contained in:
jaina heartles 2022-05-23 19:05:28 -07:00
parent e456a0aa13
commit c141d537c8
3 changed files with 26 additions and 37 deletions

View file

@ -5,8 +5,9 @@ const ciutf8 = @import("./util.zig").ciutf8;
const Reader = std.net.Stream.Reader; const Reader = std.net.Stream.Reader;
const Writer = std.net.Stream.Writer; const Writer = std.net.Stream.Writer;
pub const Handler = fn (*Context) HttpError!void; const Status = std.http.Status;
pub const HttpError = error{Http404}; const Method = std.http.Method;
pub const Handler = fn (*Context) anyerror!void;
const HeaderMap = std.HashMap([]const u8, []const u8, struct { const HeaderMap = std.HashMap([]const u8, []const u8, struct {
pub fn eql(_: @This(), a: []const u8, b: []const u8) bool { pub fn eql(_: @This(), a: []const u8, b: []const u8) bool {
@ -33,17 +34,6 @@ fn handleInternalError(writer: Writer) !void {
try writer.writeAll("HTTP/1.1 500 Internal Server Error"); try writer.writeAll("HTTP/1.1 500 Internal Server Error");
} }
pub const Method = enum {
GET,
//HEAD,
POST,
//PUT,
//DELETE,
//CONNECT,
//OPTIONS,
//TRACE,
};
fn parseHttpMethod(reader: Reader) !Method { fn parseHttpMethod(reader: Reader) !Method {
var buf: [8]u8 = undefined; var buf: [8]u8 = undefined;
const str = reader.readUntilDelimiter(&buf, ' ') catch |err| switch (err) { const str = reader.readUntilDelimiter(&buf, ' ') catch |err| switch (err) {

View file

@ -8,13 +8,13 @@ pub const routing = @import("./routing.zig");
pub const Uuid = util.Uuid; pub const Uuid = util.Uuid;
pub const ciutf8 = util.ciutf8; pub const ciutf8 = util.ciutf8;
pub const io_mode = .evented; //pub const io_mode = .evented;
pub const router = routing.makeRouter(*http.Context, [_]routing.RouteFn(*http.Context){ pub const router = routing.makeRouter(*http.Context, &[_]routing.RouteFn(*http.Context){
routing.makeRoute(.GET, "/", staticString("Index Page")), routing.makeRoute(.GET, "/", staticString("Index Page")),
routing.makeRoute(.GET, "/abc", staticString("abc")), routing.makeRoute(.GET, "/abc", staticString("abc")),
routing.makeRoute(.GET, "/user/:id", getUser), //routing.makeRoute(.GET, "/user/:id", getUser),
routing.makeRoute(.POST, "/note/", postNote), //routing.makeRoute(.POST, "/note/", postNote),
}); });
const this_scheme = "http"; const this_scheme = "http";
@ -58,9 +58,10 @@ fn getUser(ctx: *http.Context, args: struct { id: []const u8 }) anyerror!void {
try writer.writeAll("}"); try writer.writeAll("}");
} }
fn staticString(comptime str: []const u8) routing.RouteFn(http.Context) { const DummyArgs = struct {};
fn staticString(comptime str: []const u8) fn (*http.Context, DummyArgs) anyerror!void {
return (struct { return (struct {
fn func(ctx: *http.Context, _: struct {}) http.HttpError!void { fn func(ctx: *http.Context, _: DummyArgs) anyerror!void {
try ctx.response.headers.put("Content-Type", "text/plain"); try ctx.response.headers.put("Content-Type", "text/plain");
try ctx.response.write(200, str); try ctx.response.write(200, str);
} }
@ -80,8 +81,8 @@ pub fn main() anyerror!void {
// todo: keep track of connections // todo: keep track of connections
_ = async http.handleConnection(conn, struct { _ = async http.handleConnection(conn, struct {
fn func(ctx: *http.Context) http.HttpError!void { fn func(ctx: *http.Context) anyerror!void {
//try router(ctx, ctx.method, ctx.path); try router(ctx.request.method, ctx.request.path, ctx);
_ = ctx; _ = ctx;
return; return;
} }
@ -91,4 +92,6 @@ pub fn main() anyerror!void {
test { test {
_ = http; _ = http;
_ = util;
_ = routing;
} }

View file

@ -1,5 +1,4 @@
const std = @import("std"); const std = @import("std");
const http = @import("./http.zig");
const ciutf8 = @import("./util.zig").ciutf8; const ciutf8 = @import("./util.zig").ciutf8;
const PathIter = struct { const PathIter = struct {
@ -70,42 +69,39 @@ const RouteSegment = union(enum) {
param: []const u8, param: []const u8,
}; };
// convention: return http.HttpError IFF a situation you can't finish the request in happens.
// If status line/headers were written, always return void
pub fn RouteFn(comptime Context: type) type { pub fn RouteFn(comptime Context: type) type {
return fn (Context, http.Method, []const u8) http.HttpError!void; return fn (Context, std.http.Method, []const u8) anyerror!void;
} }
/// `makeRoute` takes a route definition and a handler of the form `fn(<Context>, <Params>) http.HttpError!void` /// `makeRoute` takes a route definition and a handler of the form `fn(<Context>, <Params>) anyerror!void`
/// where `Params` is a struct containing one field of type `[]const u8` for each path parameter /// where `Params` is a struct containing one field of type `[]const u8` for each path parameter
/// ///
/// Arguments: /// Arguments:
/// method: The HTTP method to match /// method: The HTTP method to match
/// path: The path spec to match against. Path segments beginning with a `:` will cause the rest of /// path: The path spec to match against. Path segments beginning with a `:` will cause the rest of
/// the segment to be treated as the name of a path parameter /// the segment to be treated as the name of a path parameter
/// handler: The code to execute on route match. This must be a function of form `fn(<Context>, <Params>) http.HttpError!void` /// handler: The code to execute on route match. This must be a function of form `fn(<Context>, <Params>) anyerror!void`
/// ///
/// Implicit Arguments: /// Implicit Arguments:
/// Context: the type of a user-supplied Context that is passed through the route. typically `http.Context` but /// Context: the type of a user-supplied Context that is passed through the route. typically `std.http.Context` but
/// made generic for ease of testing. There are no restrictions on this type /// made generic for ease of testing. There are no restrictions on this type
/// Params: the type of a struct representing the path parameters expressed in `<path>`. This must be /// Params: the type of a struct representing the path parameters expressed in `<path>`. This must be
/// a struct, with a one-one map between fields and path parameters. Each field must be of type /// a struct, with a one-one map between fields and path parameters. Each field must be of type
/// `[]const u8` and it must have the same name as a single path parameter. /// `[]const u8` and it must have the same name as a single path parameter.
/// ///
/// Returns: /// Returns:
/// A new route function of type `fn(<Context>, http.Method, []const u8) http.HttpError!void`. When called, /// A new route function of type `fn(<Context>, std.http.Method, []const u8) anyerror!void`. When called,
/// this function will test the provided values against its specification. If they match, then /// this function will test the provided values against its specification. If they match, then
/// this function will parse path parameters and <handler> will be called with the supplied /// this function will parse path parameters and <handler> will be called with the supplied
/// context and params. If they do not match, this function will return error.Http404 /// context and params. If they do not match, this function will return error.Http404
/// ///
/// Example: /// Example:
/// route(.GET, "/user/:id/followers", struct{ /// route(.GET, "/user/:id/followers", struct{
/// fn getFollowers(ctx: http.Context, params: struct{ id: []const u8 } http.HttpError { ... } /// fn getFollowers(ctx: std.http.Context, params: struct{ id: []const u8 } anyerror { ... }
/// ).getFollowers) /// ).getFollowers)
/// ///
pub fn makeRoute( pub fn makeRoute(
comptime method: http.Method, comptime method: std.http.Method,
comptime path: []const u8, comptime path: []const u8,
comptime handler: anytype, comptime handler: anytype,
) return_type: { ) return_type: {
@ -114,7 +110,7 @@ pub fn makeRoute(
break :return_type RouteFn(@typeInfo(@TypeOf(handler)).Fn.args[0].arg_type.?); break :return_type RouteFn(@typeInfo(@TypeOf(handler)).Fn.args[0].arg_type.?);
} { } {
const handler_args = @typeInfo(@TypeOf(handler)).Fn.args; const handler_args = @typeInfo(@TypeOf(handler)).Fn.args;
if (handler_args.len != 2) @compileError("handler function must have signature fn(Context, Params) http.HttpError"); if (handler_args.len != 2) @compileError("handler function must have signature fn(Context, Params) anyerror");
if (@typeInfo(handler_args[1].arg_type.?) != .Struct) @compileError("Params in handler(Context, Params) must be struct"); if (@typeInfo(handler_args[1].arg_type.?) != .Struct) @compileError("Params in handler(Context, Params) must be struct");
const Context = handler_args[0].arg_type.?; const Context = handler_args[0].arg_type.?;
@ -142,7 +138,7 @@ pub fn makeRoute(
} }
return struct { return struct {
fn func(ctx: Context, req_method: http.Method, req_path: []const u8) http.HttpError!void { fn func(ctx: Context, req_method: std.http.Method, req_path: []const u8) anyerror!void {
if (req_method != method) return error.Http404; if (req_method != method) return error.Http404;
var params: Params = undefined; var params: Params = undefined;
@ -168,7 +164,7 @@ pub fn makeRoute(
} }
pub fn RouterFn(comptime Context: type) type { pub fn RouterFn(comptime Context: type) type {
return fn (http.Method, path: []const u8, Context) http.HttpError!void; return fn (std.http.Method, path: []const u8, Context) anyerror!void;
} }
pub fn makeRouter( pub fn makeRouter(
@ -176,7 +172,7 @@ pub fn makeRouter(
comptime routes: []const RouteFn(Context), comptime routes: []const RouteFn(Context),
) RouterFn(Context) { ) RouterFn(Context) {
return struct { return struct {
fn dispatch(method: http.Method, path: []const u8, ctx: Context) http.HttpError!void { fn dispatch(method: std.http.Method, path: []const u8, ctx: Context) anyerror!void {
for (routes) |r| { for (routes) |r| {
return r(ctx, method, path) catch |err| switch (err) { return r(ctx, method, path) catch |err| switch (err) {
error.Http404 => continue, error.Http404 => continue,
@ -302,7 +298,7 @@ const _tests = struct {
fn dummyHandler(comptime Args: type) type { fn dummyHandler(comptime Args: type) type {
comptime { comptime {
return struct { return struct {
fn func(_: TestContext, _: Args) http.HttpError!void {} fn func(_: TestContext, _: Args) anyerror!void {}
}; };
} }
} }