mirror of
https://github.com/zigzap/zap.git
synced 2025-10-20 15:14:08 +00:00
Merge branch 'master' into zig-master
This commit is contained in:
commit
54c2ed64c6
6 changed files with 60 additions and 32 deletions
15
README.md
15
README.md
|
@ -58,7 +58,7 @@ master though.
|
|||
## Here's what works
|
||||
|
||||
I recommend checking out **Endpoint-based examples for more realistic
|
||||
use cases**. Most of the examples are super stripped down to only include
|
||||
use cases**. Most of the examples are super stripped down to only include
|
||||
what's necessary to show a feature.
|
||||
|
||||
**NOTE: To see API docs, run `zig build run-docserver`.** To specify a custom
|
||||
|
@ -132,10 +132,10 @@ port and docs dir: `zig build docserver && zig-out/bin/docserver --port=8989
|
|||
call `r.sendError(err, status_code)` when you catch an error and a stack trace
|
||||
will be returned to the client / browser.
|
||||
- [**HTTPS**](examples/https/https.zig): Shows how easy it is to use facil.io's
|
||||
openssl support. Must be compiled with `-Dopenssl=true` or the environment
|
||||
openssl support. Must be compiled with `-Dopenssl=true` or the environment
|
||||
variable `ZAP_USE_OPENSSL` set to `true` and requires openssl dev dependencies
|
||||
(headers, lib) to be installed on the system.
|
||||
- run it like this: `ZAP_USE_OPENSSL=true zig build run-https`
|
||||
- run it like this: `ZAP_USE_OPENSSL=true zig build run-https`
|
||||
OR like this: `zig build -Dopenssl=true run-https`
|
||||
- it will tell you how to generate certificates
|
||||
- [**simple_router**](examples/simple_router/simple_router.zig): See how you
|
||||
|
@ -181,7 +181,7 @@ simplistic testing scenario.
|
|||
|
||||
|
||||
So, being somewhere in the ballpark of basic GO performance, zig zap seems to be
|
||||
... of reasonable performance 😎.
|
||||
... of reasonable performance 😎.
|
||||
|
||||
I can rest my case that developing ZAP was a good idea because it's faster than
|
||||
both alternatives: a) staying with Python, and b) creating a GO + Zig hybrid.
|
||||
|
@ -257,7 +257,7 @@ $ git init ## (optional)
|
|||
**Note**: Nix/NixOS users are lucky; you can use the existing `flake.nix` and run
|
||||
`nix develop` to get a development shell providing zig and all
|
||||
dependencies to build and run the GO, python, and rust examples for the
|
||||
`wrk` performance tests. For the mere building of zap projects,
|
||||
`wrk` performance tests. For the mere building of zap projects,
|
||||
`nix develop .#build` will only fetch zig 0.11.0. TODO: upgrade to latest zig.
|
||||
|
||||
With an existing Zig project, adding Zap to it is easy:
|
||||
|
@ -274,9 +274,9 @@ To add zap to `build.zig.zon`:
|
|||
.version = "0.0.1",
|
||||
|
||||
.dependencies = .{
|
||||
// zap v0.7.0
|
||||
// zap v0.8.0
|
||||
.zap = .{
|
||||
.url = "https://github.com/zigzap/zap/archive/refs/tags/v0.7.0.tar.gz",
|
||||
.url = "https://github.com/zigzap/zap/archive/v0.8.0.tar.gz",
|
||||
.hash = "12209936c3333b53b53edcf453b1670babb9ae8c2197b1ca627c01e72670e20c1a21",
|
||||
},
|
||||
},
|
||||
|
@ -416,3 +416,4 @@ pub fn main() !void {
|
|||
}
|
||||
```
|
||||
|
||||
|
||||
|
|
|
@ -123,19 +123,17 @@ const SessionMiddleWare = struct {
|
|||
//
|
||||
// !!!! ENDPOINT !!!
|
||||
//
|
||||
// We define an endpoint as we usually would.
|
||||
// NO ROUTING IS PERFORMED
|
||||
// as we are just going to wrap it in a bunch of Middleware components
|
||||
// and therefore NOT using an endpoint listener that would the routing for us
|
||||
// We define an endpoint as we usually would; however,
|
||||
// NO ROUTING IS PERFORMED BY DEFAULT!
|
||||
//
|
||||
// Hence, the endpoint should check r.path in its on_request to check wether
|
||||
// it is adressed or not.
|
||||
// This can be changed using the EndpointHandlerOptions passed into the
|
||||
// EndpointHandler.init() method.
|
||||
//
|
||||
// N.B. the EndpointHandler checks if the endpoint turned the request into
|
||||
// "finished" state, e.g. by sending anything. If the endpoint didn't finish the
|
||||
// request, the EndpointHandler will pass the request on to the next handler in
|
||||
// the chain if there is one. See also the EndpointHandler's `breakOnFinish`
|
||||
// parameter.
|
||||
// the chain if there is one. See also the EndpointHandlerOptions's
|
||||
// `breakOnFinish` parameter.
|
||||
//
|
||||
const HtmlEndpoint = struct {
|
||||
ep: zap.Endpoint = undefined,
|
||||
|
@ -210,7 +208,7 @@ pub fn main() !void {
|
|||
var htmlHandler = zap.Middleware.EndpointHandler(Handler, Context).init(
|
||||
htmlEndpoint.endpoint(), // the endpoint
|
||||
null, // no other handler (we are the last in the chain)
|
||||
true, // break on finish. See EndpointHandler for this. Not applicable here.
|
||||
.{}, // We can set custom EndpointHandlerOptions here
|
||||
);
|
||||
|
||||
// we wrap it in the session Middleware component
|
||||
|
|
|
@ -11,8 +11,16 @@ pub const fio_url_s = extern struct {
|
|||
target: fio_str_info_s,
|
||||
};
|
||||
pub extern fn fio_url_parse(url: [*c]const u8, length: usize) fio_url_s;
|
||||
|
||||
/// Negative thread / worker values indicate a fraction of the number of CPU cores. i.e., -2 will normally indicate "half" (1/2) the number of cores.
|
||||
///
|
||||
/// If one value is set to zero, it will be the absolute value of the other value. i.e.: if .threads == -2 and .workers == 0, than facil.io will run 2 worker processes with (cores/2) threads per process.
|
||||
pub const struct_fio_start_args = extern struct {
|
||||
/// The number of threads to run in the thread pool.
|
||||
threads: i16,
|
||||
/// The number of worker processes to run (in addition to a root process)
|
||||
///
|
||||
/// This invokes facil.io's cluster mode, where a crashed worker will be automatically re-spawned and "hot restart" is enabled (using the USR1 signal).
|
||||
workers: i16,
|
||||
};
|
||||
pub const fio_start_args = struct_fio_start_args;
|
||||
|
|
|
@ -51,23 +51,38 @@ pub fn Handler(comptime ContextType: anytype) type {
|
|||
};
|
||||
}
|
||||
|
||||
/// Options used to change the behavior of an `EndpointHandler`
|
||||
pub const EndpointHandlerOptions = struct {
|
||||
/// If `true`, the handler will stop handing requests down the chain if the
|
||||
/// endpoint processed the request.
|
||||
breakOnFinish: bool = true,
|
||||
|
||||
/// If `true`, the handler will only execute against requests that match
|
||||
/// the endpoint's `path` setting.
|
||||
checkPath: bool = false,
|
||||
};
|
||||
|
||||
/// A convenience handler for artibrary zap.Endpoint
|
||||
pub fn EndpointHandler(comptime HandlerType: anytype, comptime ContextType: anytype) type {
|
||||
return struct {
|
||||
handler: HandlerType,
|
||||
endpoint: *zap.Endpoint,
|
||||
breakOnFinish: bool,
|
||||
options: EndpointHandlerOptions,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
/// Create an endpointhandler from an endpoint and pass in the next (other) handler in the chain.
|
||||
/// If `breakOnFinish` is `true`, the handler will stop handing requests down the chain if
|
||||
/// the endpoint processed the request.
|
||||
pub fn init(endpoint: *zap.Endpoint, other: ?*HandlerType, breakOnFinish: bool) Self {
|
||||
///
|
||||
/// By default no routing is performed on requests. This behavior can be changed by setting
|
||||
/// `checkPath` in the provided options.
|
||||
///
|
||||
/// If the `breakOnFinish` option is `true`, the handler will stop handing requests down the chain
|
||||
/// if the endpoint processed the request.
|
||||
pub fn init(endpoint: *zap.Endpoint, other: ?*HandlerType, options: EndpointHandlerOptions) Self {
|
||||
return .{
|
||||
.handler = HandlerType.init(onRequest, other),
|
||||
.endpoint = endpoint,
|
||||
.breakOnFinish = breakOnFinish,
|
||||
.options = options,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -84,10 +99,14 @@ pub fn EndpointHandler(comptime HandlerType: anytype, comptime ContextType: anyt
|
|||
pub fn onRequest(handler: *HandlerType, r: zap.Request, context: *ContextType) bool {
|
||||
const self: *Self = @fieldParentPtr("handler", handler);
|
||||
r.setUserContext(context);
|
||||
self.endpoint.onRequest(r);
|
||||
if (!self.options.checkPath or
|
||||
std.mem.startsWith(u8, r.path orelse "", self.endpoint.settings.path))
|
||||
{
|
||||
self.endpoint.onRequest(r);
|
||||
}
|
||||
|
||||
// if the request was handled by the endpoint, we may break the chain here
|
||||
if (r.isFinished() and self.breakOnFinish) {
|
||||
if (r.isFinished() and self.options.breakOnFinish) {
|
||||
return true;
|
||||
}
|
||||
return self.handler.handleOther(r, context);
|
||||
|
|
|
@ -15,7 +15,7 @@ extern fn fiobj_mustache_build2(dest: fio.FIOBJ, mustache: ?*mustache_s, data: f
|
|||
extern fn fiobj_mustache_free(mustache: ?*mustache_s) void;
|
||||
|
||||
/// Load arguments used when creating a new Mustache instance.
|
||||
pub const MustacheLoadArgs = struct {
|
||||
pub const LoadArgs = struct {
|
||||
/// Filename. This enables partial templates on filesystem.
|
||||
filename: ?[]const u8 = null,
|
||||
|
||||
|
@ -51,7 +51,7 @@ pub const Error = error{
|
|||
|
||||
/// Create a new `Mustache` instance; `deinit()` should be called to free
|
||||
/// the object after usage.
|
||||
pub fn init(load_args: MustacheLoadArgs) Error!Self {
|
||||
pub fn init(load_args: LoadArgs) Error!Self {
|
||||
var err: mustache_error_en = undefined;
|
||||
|
||||
const args: MustacheLoadArgsFio = .{
|
||||
|
@ -113,7 +113,7 @@ pub fn deinit(self: *Self) void {
|
|||
// pub extern fn fiobj_mustache_build2(dest: FIOBJ, mustache: ?*mustache_s, data: FIOBJ) FIOBJ;
|
||||
|
||||
/// The result from calling `build`.
|
||||
const MustacheBuildResult = struct {
|
||||
pub const BuildResult = struct {
|
||||
fiobj_result: fio.FIOBJ = 0,
|
||||
|
||||
/// Holds the context converted into a fiobj.
|
||||
|
@ -121,13 +121,13 @@ const MustacheBuildResult = struct {
|
|||
fiobj_context: fio.FIOBJ = 0,
|
||||
|
||||
/// Free the data backing a `MustacheBuildResult` instance.
|
||||
pub fn deinit(m: *const MustacheBuildResult) void {
|
||||
pub fn deinit(m: *const BuildResult) void {
|
||||
fio.fiobj_free_wrapped(m.fiobj_result);
|
||||
fio.fiobj_free_wrapped(m.fiobj_context);
|
||||
}
|
||||
|
||||
/// Retrieve a string representation of the built template.
|
||||
pub fn str(m: *const MustacheBuildResult) ?[]const u8 {
|
||||
pub fn str(m: *const BuildResult) ?[]const u8 {
|
||||
return util.fio2str(m.fiobj_result);
|
||||
}
|
||||
};
|
||||
|
@ -137,13 +137,13 @@ const MustacheBuildResult = struct {
|
|||
// TODO: The build may be slow because it needs to convert zig types to facil.io
|
||||
// types. However, this needs to be investigated into.
|
||||
// See `fiobjectify` for more information.
|
||||
pub fn build(self: *Self, data: anytype) MustacheBuildResult {
|
||||
pub fn build(self: *Self, data: anytype) BuildResult {
|
||||
const T = @TypeOf(data);
|
||||
if (@typeInfo(T) != .Struct) {
|
||||
@compileError("No struct: '" ++ @typeName(T) ++ "'");
|
||||
}
|
||||
|
||||
var result: MustacheBuildResult = .{};
|
||||
var result: BuildResult = .{};
|
||||
|
||||
result.fiobj_context = fiobjectify(data);
|
||||
result.fiobj_result = fiobj_mustache_build(self.handle, result.fiobj_context);
|
||||
|
|
|
@ -431,8 +431,10 @@ pub fn setContentTypeFromFilename(self: *const Self, filename: []const u8) !void
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the header value of given key name. Returned mem is temp.
|
||||
/// Do not free it.
|
||||
/// Returns the header value of given key name.
|
||||
/// NOTE that header-names are lowerased automatically while parsing the request.
|
||||
/// so please only use lowercase keys!
|
||||
/// Returned mem is temp. Do not free it.
|
||||
pub fn getHeader(self: *const Self, name: []const u8) ?[]const u8 {
|
||||
const hname = fio.fiobj_str_new(util.toCharPtr(name), name.len);
|
||||
defer fio.fiobj_free_wrapped(hname);
|
||||
|
|
Loading…
Add table
Reference in a new issue