1const std = @import("std");
2const pkt = @import("packet.zig");
3const opts = @import("opts.zig");
4const codes = @import("codes.zig");
5
6pub const ResourceHandler = fn (resp: *pkt.Response, req: *pkt.Request) codes.Code;
7
8// Size for reply buffer
9const REPLY_BUFSIZ = 256;
10
11pub const Resource = struct {
12 path: []const u8,
13 handler: ResourceHandler,
14
15 pub fn matchPath(self: Resource, path: []const u8) bool {
16 return std.mem.eql(u8, self.path, path);
17 }
18};
19
20pub const Dispatcher = struct {
21 resources: []const Resource,
22 rbuf: [REPLY_BUFSIZ]u8 = undefined,
23
24 pub fn reply(self: *Dispatcher, req: *const pkt.Request, mt: pkt.Msg, code: codes.Code) !pkt.Response {
25 return pkt.Response.reply(&self.rbuf, req, mt, code);
26 }
27
28 pub fn dispatch(self: *Dispatcher, req: *pkt.Request) !pkt.Response {
29 const hdr = req.header;
30 if (hdr.type == pkt.Msg.con) {
31 // We are not able to process confirmable message presently
32 // thus *always* answer those with a reset with NOT_IMPL.
33 return self.reply(req, pkt.Msg.rst, codes.NOT_IMPL);
34 }
35
36 const path_opt = try req.findOption(opts.URIPath);
37 const path = path_opt.value;
38
39 for (self.resources) |res| {
40 if (!res.matchPath(path))
41 continue;
42
43 var resp = try self.reply(req, pkt.Msg.non, .{ .class = 0, .detail = 0 });
44 resp.setCode(res.handler(&resp, req));
45
46 return resp;
47 }
48
49 return self.reply(req, pkt.Msg.non, codes.NOT_FOUND);
50 }
51};