mirror of
https://github.com/zigzap/zap.git
synced 2025-10-20 15:14:08 +00:00
add on_uncaught_error behavior to zap.App, add on_error callbacks
zap.Endpont.Listener and zap.App now support on_error callbacks: zap.Endpont.Listener.Settings contains an `on_error` optional callback field. zap.App supports those two callbacks: /// ```zig /// const MyContext = struct { /// // You may (optionally) define the following global handlers: /// pub fn unhandledRequest(_: *MyContext, _: Allocator, _: Request) anyerror!void {} /// pub fn unhandledError(_: *MyContext, _: Request, _: anyerror) void {} /// }; /// ``` The `endpoint` example has been updated to showcase `on_error`, and the new example `app_errors` showcases `Context.unhandledError`.
This commit is contained in:
parent
4591f4048b
commit
8078b96d3f
6 changed files with 267 additions and 31 deletions
|
@ -52,6 +52,7 @@ pub fn build(b: *std.Build) !void {
|
||||||
}{
|
}{
|
||||||
.{ .name = "app_basic", .src = "examples/app/basic.zig" },
|
.{ .name = "app_basic", .src = "examples/app/basic.zig" },
|
||||||
.{ .name = "app_auth", .src = "examples/app/auth.zig" },
|
.{ .name = "app_auth", .src = "examples/app/auth.zig" },
|
||||||
|
.{ .name = "app_errors", .src = "examples/app/errors.zig" },
|
||||||
.{ .name = "hello", .src = "examples/hello/hello.zig" },
|
.{ .name = "hello", .src = "examples/hello/hello.zig" },
|
||||||
.{ .name = "https", .src = "examples/https/https.zig" },
|
.{ .name = "https", .src = "examples/https/https.zig" },
|
||||||
.{ .name = "hello2", .src = "examples/hello2/hello2.zig" },
|
.{ .name = "hello2", .src = "examples/hello2/hello2.zig" },
|
||||||
|
|
124
examples/app/errors.zig
Normal file
124
examples/app/errors.zig
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
//!
|
||||||
|
//! Part of the Zap examples.
|
||||||
|
//!
|
||||||
|
//! Build me with `zig build app_errors`.
|
||||||
|
//! Run me with `zig build run-app_errors`.
|
||||||
|
//!
|
||||||
|
const std = @import("std");
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
const zap = @import("zap");
|
||||||
|
|
||||||
|
// The global Application Context
|
||||||
|
const MyContext = struct {
|
||||||
|
db_connection: []const u8,
|
||||||
|
|
||||||
|
// we don't use this
|
||||||
|
pub fn unhandledRequest(_: *MyContext, _: Allocator, _: zap.Request) anyerror!void {}
|
||||||
|
|
||||||
|
pub fn unhandledError(_: *MyContext, _: zap.Request, err: anyerror) void {
|
||||||
|
std.debug.print("\n\n\nUNHANDLED ERROR: {} !!! \n\n\n", .{err});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// A very simple endpoint handling only GET requests
|
||||||
|
const ErrorEndpoint = struct {
|
||||||
|
|
||||||
|
// zap.App.Endpoint Interface part
|
||||||
|
path: []const u8,
|
||||||
|
error_strategy: zap.Endpoint.ErrorStrategy = .raise,
|
||||||
|
|
||||||
|
// data specific for this endpoint
|
||||||
|
some_data: []const u8,
|
||||||
|
|
||||||
|
pub fn init(path: []const u8, data: []const u8) ErrorEndpoint {
|
||||||
|
return .{
|
||||||
|
.path = path,
|
||||||
|
.some_data = data,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle GET requests
|
||||||
|
pub fn get(_: *ErrorEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {
|
||||||
|
|
||||||
|
// we just return an error
|
||||||
|
// our error_strategy = .raise
|
||||||
|
// -> error will be raised and dispatched to MyContext.unhandledError
|
||||||
|
return error.@"Oh-No!";
|
||||||
|
}
|
||||||
|
|
||||||
|
// empty stubs for all other request methods
|
||||||
|
pub fn post(_: *ErrorEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
|
||||||
|
pub fn put(_: *ErrorEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
|
||||||
|
pub fn delete(_: *ErrorEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
|
||||||
|
pub fn patch(_: *ErrorEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
|
||||||
|
pub fn options(_: *ErrorEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
|
||||||
|
};
|
||||||
|
|
||||||
|
const StopEndpoint = struct {
|
||||||
|
path: []const u8,
|
||||||
|
error_strategy: zap.Endpoint.ErrorStrategy = .log_to_response,
|
||||||
|
|
||||||
|
pub fn get(_: *StopEndpoint, _: Allocator, context: *MyContext, _: zap.Request) !void {
|
||||||
|
std.debug.print(
|
||||||
|
\\Before I stop, let me dump the app context:
|
||||||
|
\\db_connection='{s}'
|
||||||
|
\\
|
||||||
|
\\
|
||||||
|
, .{context.*.db_connection});
|
||||||
|
zap.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn post(_: *StopEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
|
||||||
|
pub fn put(_: *StopEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
|
||||||
|
pub fn delete(_: *StopEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
|
||||||
|
pub fn patch(_: *StopEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
|
||||||
|
pub fn options(_: *StopEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
// setup allocations
|
||||||
|
var gpa: std.heap.GeneralPurposeAllocator(.{
|
||||||
|
// just to be explicit
|
||||||
|
.thread_safe = true,
|
||||||
|
}) = .{};
|
||||||
|
defer std.debug.print("\n\nLeaks detected: {}\n\n", .{gpa.deinit() != .ok});
|
||||||
|
const allocator = gpa.allocator();
|
||||||
|
|
||||||
|
// create an app context
|
||||||
|
var my_context: MyContext = .{ .db_connection = "db connection established!" };
|
||||||
|
|
||||||
|
// create an App instance
|
||||||
|
const App = zap.App.Create(MyContext);
|
||||||
|
var app = try App.init(allocator, &my_context, .{});
|
||||||
|
defer app.deinit();
|
||||||
|
|
||||||
|
// create the endpoints
|
||||||
|
var my_endpoint = ErrorEndpoint.init("/error", "some endpoint specific data");
|
||||||
|
var stop_endpoint: StopEndpoint = .{ .path = "/stop" };
|
||||||
|
//
|
||||||
|
// register the endpoints with the app
|
||||||
|
try app.register(&my_endpoint);
|
||||||
|
try app.register(&stop_endpoint);
|
||||||
|
|
||||||
|
// listen on the network
|
||||||
|
try app.listen(.{
|
||||||
|
.interface = "0.0.0.0",
|
||||||
|
.port = 3000,
|
||||||
|
});
|
||||||
|
std.debug.print("Listening on 0.0.0.0:3000\n", .{});
|
||||||
|
|
||||||
|
std.debug.print(
|
||||||
|
\\ Try me via:
|
||||||
|
\\ curl http://localhost:3000/error
|
||||||
|
\\ Stop me via:
|
||||||
|
\\ curl http://localhost:3000/stop
|
||||||
|
\\
|
||||||
|
, .{});
|
||||||
|
|
||||||
|
// start worker threads -- only 1 process!!!
|
||||||
|
zap.start(.{
|
||||||
|
.threads = 2,
|
||||||
|
.workers = 1,
|
||||||
|
});
|
||||||
|
}
|
|
@ -9,6 +9,8 @@ path: []const u8 = "/error",
|
||||||
error_strategy: zap.Endpoint.ErrorStrategy = .log_to_response,
|
error_strategy: zap.Endpoint.ErrorStrategy = .log_to_response,
|
||||||
|
|
||||||
pub fn get(_: *ErrorEndpoint, _: zap.Request) !void {
|
pub fn get(_: *ErrorEndpoint, _: zap.Request) !void {
|
||||||
|
// error_strategy is set to .log_to_response
|
||||||
|
// --> this error will be shown in the browser, with a nice error trace
|
||||||
return error.@"Oh-no!";
|
return error.@"Oh-no!";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,11 @@ fn on_request(r: zap.Request) !void {
|
||||||
try r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>");
|
try r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this is just to demo that we could catch arbitrary errors as fallback
|
||||||
|
fn on_error(_: zap.Request, err: anyerror) void {
|
||||||
|
std.debug.print("\n\n\nOh no!!! We didn't chatch this error: {}\n\n\n", .{err});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{
|
var gpa = std.heap.GeneralPurposeAllocator(.{
|
||||||
.thread_safe = true,
|
.thread_safe = true,
|
||||||
|
@ -33,6 +38,8 @@ pub fn main() !void {
|
||||||
.{
|
.{
|
||||||
.port = 3000,
|
.port = 3000,
|
||||||
.on_request = on_request,
|
.on_request = on_request,
|
||||||
|
// optional
|
||||||
|
.on_error = on_error,
|
||||||
.log = true,
|
.log = true,
|
||||||
.public_folder = "examples/endpoint/html",
|
.public_folder = "examples/endpoint/html",
|
||||||
.max_clients = 100000,
|
.max_clients = 100000,
|
||||||
|
@ -47,11 +54,13 @@ pub fn main() !void {
|
||||||
|
|
||||||
var stopEp = StopEndpoint.init("/stop");
|
var stopEp = StopEndpoint.init("/stop");
|
||||||
var errorEp: ErrorEndpoint = .{};
|
var errorEp: ErrorEndpoint = .{};
|
||||||
|
var unhandledErrorEp: ErrorEndpoint = .{ .error_strategy = .raise, .path = "/unhandled" };
|
||||||
|
|
||||||
// register endpoints with the listener
|
// register endpoints with the listener
|
||||||
try listener.register(&userWeb);
|
try listener.register(&userWeb);
|
||||||
try listener.register(&stopEp);
|
try listener.register(&stopEp);
|
||||||
try listener.register(&errorEp);
|
try listener.register(&errorEp);
|
||||||
|
try listener.register(&unhandledErrorEp);
|
||||||
|
|
||||||
// fake some users
|
// fake some users
|
||||||
var uid: usize = undefined;
|
var uid: usize = undefined;
|
||||||
|
|
80
src/App.zig
80
src/App.zig
|
@ -29,6 +29,16 @@ pub const AppOpts = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
/// creates an App with custom app context
|
/// creates an App with custom app context
|
||||||
|
///
|
||||||
|
/// About App Contexts:
|
||||||
|
///
|
||||||
|
/// ```zig
|
||||||
|
/// const MyContext = struct {
|
||||||
|
/// // You may (optionally) define the following global handlers:
|
||||||
|
/// pub fn unhandledRequest(_: *MyContext, _: Allocator, _: Request) anyerror!void {}
|
||||||
|
/// pub fn unhandledError(_: *MyContext, _: Request, _: anyerror) void {}
|
||||||
|
/// };
|
||||||
|
/// ```
|
||||||
pub fn Create(
|
pub fn Create(
|
||||||
/// Your user-defined "Global App Context" type
|
/// Your user-defined "Global App Context" type
|
||||||
comptime Context: type,
|
comptime Context: type,
|
||||||
|
@ -51,19 +61,21 @@ pub fn Create(
|
||||||
/// the internal http listener
|
/// the internal http listener
|
||||||
listener: HttpListener = undefined,
|
listener: HttpListener = undefined,
|
||||||
|
|
||||||
/// function pointer to handler for otherwise unhandled requests
|
/// function pointer to handler for otherwise unhandled requests.
|
||||||
/// Will automatically be set if your Context provides an unhandled
|
/// Will automatically be set if your Context provides an
|
||||||
/// function of type `fn(*Context, Allocator, Request)`
|
/// `unhandledRequest` function of type `fn(*Context, Allocator,
|
||||||
///
|
/// Request) !void`.
|
||||||
unhandled: ?*const fn (*Context, Allocator, Request) anyerror!void = null,
|
unhandled_request: ?*const fn (*Context, Allocator, Request) anyerror!void = null,
|
||||||
|
|
||||||
|
/// function pointer to handler for unhandled errors.
|
||||||
|
/// Errors are unhandled if they are not logged but raised by the
|
||||||
|
/// ErrorStrategy. Will automatically be set if your Context
|
||||||
|
/// provides an `unhandledError` function of type `fn(*Context,
|
||||||
|
/// Allocator, Request, anyerror) void`.
|
||||||
|
unhandled_error: ?*const fn (*Context, Request, anyerror) void = null,
|
||||||
};
|
};
|
||||||
var _static: InstanceData = .{};
|
var _static: InstanceData = .{};
|
||||||
|
|
||||||
/// Internal, static request handler callback. Will be set to the optional,
|
|
||||||
/// user-defined request callback that only gets called if no endpoints match
|
|
||||||
/// a request.
|
|
||||||
var on_request: ?*const fn (Allocator, *Context, Request) anyerror!void = null;
|
|
||||||
|
|
||||||
pub const Endpoint = struct {
|
pub const Endpoint = struct {
|
||||||
pub const Interface = struct {
|
pub const Interface = struct {
|
||||||
call: *const fn (*Interface, Request) anyerror!void = undefined,
|
call: *const fn (*Interface, Request) anyerror!void = undefined,
|
||||||
|
@ -113,7 +125,7 @@ pub fn Create(
|
||||||
switch (self.endpoint.*.error_strategy) {
|
switch (self.endpoint.*.error_strategy) {
|
||||||
.raise => return err,
|
.raise => return err,
|
||||||
.log_to_response => return r.sendError(err, if (@errorReturnTrace()) |t| t.* else null, 505),
|
.log_to_response => return r.sendError(err, if (@errorReturnTrace()) |t| t.* else null, 505),
|
||||||
.log_to_console => zap.debug(
|
.log_to_console => zap.log.err(
|
||||||
"Error in {} {s} : {}",
|
"Error in {} {s} : {}",
|
||||||
.{ Bound, r.method orelse "(no method)", err },
|
.{ Bound, r.method orelse "(no method)", err },
|
||||||
),
|
),
|
||||||
|
@ -318,15 +330,24 @@ pub fn Create(
|
||||||
_static.opts = opts_;
|
_static.opts = opts_;
|
||||||
_static.there_can_be_only_one = true;
|
_static.there_can_be_only_one = true;
|
||||||
|
|
||||||
// set unhandled callback if provided by Context
|
// set unhandled_request callback if provided by Context
|
||||||
if (@hasDecl(Context, "unhandled")) {
|
if (@hasDecl(Context, "unhandledRequest")) {
|
||||||
// try if we can use it
|
// try if we can use it
|
||||||
const Unhandled = @TypeOf(@field(Context, "unhandled"));
|
const Unhandled = @TypeOf(@field(Context, "unhandledRequest"));
|
||||||
const Expected = fn (_: *Context, _: Allocator, _: Request) anyerror!void;
|
const Expected = fn (_: *Context, _: Allocator, _: Request) anyerror!void;
|
||||||
if (Unhandled != Expected) {
|
if (Unhandled != Expected) {
|
||||||
@compileError("`unhandled` method of " ++ @typeName(Context) ++ " has wrong type:\n" ++ @typeName(Unhandled) ++ "\nexpected:\n" ++ @typeName(Expected));
|
@compileError("`unhandledRequest` method of " ++ @typeName(Context) ++ " has wrong type:\n" ++ @typeName(Unhandled) ++ "\nexpected:\n" ++ @typeName(Expected));
|
||||||
}
|
}
|
||||||
_static.unhandled = Context.unhandled;
|
_static.unhandled_request = Context.unhandledRequest;
|
||||||
|
}
|
||||||
|
if (@hasDecl(Context, "unhandledError")) {
|
||||||
|
// try if we can use it
|
||||||
|
const Unhandled = @TypeOf(@field(Context, "unhandledError"));
|
||||||
|
const Expected = fn (_: *Context, _: Request, _: anyerror) void;
|
||||||
|
if (Unhandled != Expected) {
|
||||||
|
@compileError("`unhandledError` method of " ++ @typeName(Context) ++ " has wrong type:\n" ++ @typeName(Unhandled) ++ "\nexpected:\n" ++ @typeName(Expected));
|
||||||
|
}
|
||||||
|
_static.unhandled_error = Context.unhandledError;
|
||||||
}
|
}
|
||||||
return .{};
|
return .{};
|
||||||
}
|
}
|
||||||
|
@ -419,17 +440,34 @@ pub fn Create(
|
||||||
if (r.path) |p| {
|
if (r.path) |p| {
|
||||||
for (_static.endpoints.items) |interface| {
|
for (_static.endpoints.items) |interface| {
|
||||||
if (std.mem.startsWith(u8, p, interface.path)) {
|
if (std.mem.startsWith(u8, p, interface.path)) {
|
||||||
return try interface.call(interface, r);
|
return interface.call(interface, r) catch |err| {
|
||||||
|
// if error is not dealt with in the interface, e.g.
|
||||||
|
// if error strategy is .raise:
|
||||||
|
if (_static.unhandled_error) |error_cb| {
|
||||||
|
error_cb(_static.context, r, err);
|
||||||
|
} else {
|
||||||
|
zap.log.err(
|
||||||
|
"App.Endpoint onRequest error {} in endpoint interface {}\n",
|
||||||
|
.{ err, interface },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (on_request) |foo| {
|
|
||||||
|
// this is basically the "not found" handler
|
||||||
|
if (_static.unhandled_request) |foo| {
|
||||||
var arena = try get_arena();
|
var arena = try get_arena();
|
||||||
foo(arena.allocator(), _static.context, r) catch |err| {
|
foo(_static.context, arena.allocator(), r) catch |err| {
|
||||||
switch (_static.opts.default_error_strategy) {
|
switch (_static.opts.default_error_strategy) {
|
||||||
.raise => return err,
|
.raise => if (_static.unhandled_error) |error_cb| {
|
||||||
|
error_cb(_static.context, r, err);
|
||||||
|
} else {
|
||||||
|
zap.Logging.on_uncaught_error("App on_request", err);
|
||||||
|
},
|
||||||
.log_to_response => return r.sendError(err, if (@errorReturnTrace()) |t| t.* else null, 505),
|
.log_to_response => return r.sendError(err, if (@errorReturnTrace()) |t| t.* else null, 505),
|
||||||
.log_to_console => zap.debug("Error in {} {s} : {}", .{ App, r.method orelse "(no method)", err }),
|
.log_to_console => zap.log.err("Error in {} {s} : {}", .{ App, r.method orelse "(no method)", err }),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -313,6 +313,33 @@ pub const Listener = struct {
|
||||||
listener: HttpListener,
|
listener: HttpListener,
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
|
|
||||||
|
pub const Settings = struct {
|
||||||
|
port: usize,
|
||||||
|
interface: [*c]const u8 = null,
|
||||||
|
|
||||||
|
/// User-defined request callback that only gets called if no endpoints
|
||||||
|
/// match a request.
|
||||||
|
on_request: ?zap.HttpRequestFn,
|
||||||
|
on_response: ?zap.HttpRequestFn = null,
|
||||||
|
on_upgrade: ?zap.HttpUpgradeFn = null,
|
||||||
|
on_finish: ?zap.HttpFinishFn = null,
|
||||||
|
|
||||||
|
/// Callback, called if an error is raised and not caught by the
|
||||||
|
/// ErrorStrategy
|
||||||
|
on_error: ?*const fn (Request, anyerror) void = null,
|
||||||
|
|
||||||
|
// provide any pointer in there for "user data". it will be passed pack in
|
||||||
|
// on_finish()'s copy of the struct_http_settings_s
|
||||||
|
udata: ?*anyopaque = null,
|
||||||
|
public_folder: ?[]const u8 = null,
|
||||||
|
max_clients: ?isize = null,
|
||||||
|
max_body_size: ?usize = null,
|
||||||
|
timeout: ?u8 = null,
|
||||||
|
log: bool = false,
|
||||||
|
ws_timeout: u8 = 40,
|
||||||
|
ws_max_msg_size: usize = 262144,
|
||||||
|
tls: ?zap.Tls = null,
|
||||||
|
};
|
||||||
/// Internal static interface struct of member endpoints
|
/// Internal static interface struct of member endpoints
|
||||||
var endpoints: std.ArrayListUnmanaged(*Binder.Interface) = .empty;
|
var endpoints: std.ArrayListUnmanaged(*Binder.Interface) = .empty;
|
||||||
|
|
||||||
|
@ -321,23 +348,46 @@ pub const Listener = struct {
|
||||||
/// a request.
|
/// a request.
|
||||||
var on_request: ?zap.HttpRequestFn = null;
|
var on_request: ?zap.HttpRequestFn = null;
|
||||||
|
|
||||||
|
/// Callback, called if an error is raised and not caught by the ErrorStrategy
|
||||||
|
var on_error: ?*const fn (Request, anyerror) void = null;
|
||||||
|
|
||||||
/// Initialize a new endpoint listener. Note, if you pass an `on_request`
|
/// Initialize a new endpoint listener. Note, if you pass an `on_request`
|
||||||
/// callback in the provided ListenerSettings, this request callback will be
|
/// callback in the provided ListenerSettings, this request callback will be
|
||||||
/// called every time a request arrives that no endpoint matches.
|
/// called every time a request arrives that no endpoint matches.
|
||||||
pub fn init(a: std.mem.Allocator, l: ListenerSettings) Listener {
|
pub fn init(a: std.mem.Allocator, settings: Settings) Listener {
|
||||||
// reset the global in case init is called multiple times, as is the
|
// reset the global in case init is called multiple times, as is the
|
||||||
// case in the authentication tests
|
// case in the authentication tests
|
||||||
endpoints = .empty;
|
endpoints = .empty;
|
||||||
|
|
||||||
// take copy of listener settings before modifying the callback field
|
var ls: zap.HttpListenerSettings = .{
|
||||||
var ls = l;
|
.port = settings.port,
|
||||||
|
.interface = settings.interface,
|
||||||
|
|
||||||
|
// we set to our own handler
|
||||||
|
.on_request = onRequest,
|
||||||
|
|
||||||
|
.on_response = settings.on_response,
|
||||||
|
.on_upgrade = settings.on_upgrade,
|
||||||
|
.on_finish = settings.on_finish,
|
||||||
|
.udata = settings.udata,
|
||||||
|
.public_folder = settings.public_folder,
|
||||||
|
.max_clients = settings.max_clients,
|
||||||
|
.max_body_size = settings.max_body_size,
|
||||||
|
.timeout = settings.timeout,
|
||||||
|
.log = settings.log,
|
||||||
|
.ws_timeout = settings.ws_timeout,
|
||||||
|
.ws_max_msg_size = settings.ws_max_msg_size,
|
||||||
|
.tls = settings.tls,
|
||||||
|
};
|
||||||
|
|
||||||
// override the settings with our internal, actual callback function
|
// override the settings with our internal, actual callback function
|
||||||
// so that "we" will be called on request
|
// so that "we" will be called on request
|
||||||
ls.on_request = Listener.onRequest;
|
ls.on_request = Listener.onRequest;
|
||||||
|
|
||||||
// store the settings-provided request callback for later use
|
// store the settings-provided request callbacks for later use
|
||||||
on_request = l.on_request;
|
on_request = settings.on_request;
|
||||||
|
on_error = settings.on_error;
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.listener = HttpListener.init(ls),
|
.listener = HttpListener.init(ls),
|
||||||
.allocator = a,
|
.allocator = a,
|
||||||
|
@ -390,10 +440,16 @@ pub const Listener = struct {
|
||||||
for (endpoints.items) |interface| {
|
for (endpoints.items) |interface| {
|
||||||
if (std.mem.startsWith(u8, p, interface.path)) {
|
if (std.mem.startsWith(u8, p, interface.path)) {
|
||||||
return interface.call(interface, r) catch |err| {
|
return interface.call(interface, r) catch |err| {
|
||||||
zap.log.err(
|
// if error is not dealt with in the entpoint, e.g.
|
||||||
"Endpoint onRequest error {} in endpoint interface {}\n",
|
// if error strategy is .raise:
|
||||||
.{ err, interface },
|
if (on_error) |error_cb| {
|
||||||
);
|
error_cb(r, err);
|
||||||
|
} else {
|
||||||
|
zap.log.err(
|
||||||
|
"Endpoint onRequest error {} in endpoint interface {}\n",
|
||||||
|
.{ err, interface },
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -401,7 +457,13 @@ pub const Listener = struct {
|
||||||
// if set, call the user-provided default callback
|
// if set, call the user-provided default callback
|
||||||
if (on_request) |foo| {
|
if (on_request) |foo| {
|
||||||
foo(r) catch |err| {
|
foo(r) catch |err| {
|
||||||
zap.Logging.on_uncaught_error("Endpoint on_request", err);
|
// if error is not dealt with in the entpoint, e.g.
|
||||||
|
// if error strategy is .raise:
|
||||||
|
if (on_error) |error_cb| {
|
||||||
|
error_cb(r, err);
|
||||||
|
} else {
|
||||||
|
zap.Logging.on_uncaught_error("Endpoint on_request", err);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue