Skip to content

Commit

Permalink
Merge branch 'master' into zig-master
Browse files Browse the repository at this point in the history
  • Loading branch information
renerocksai committed Oct 14, 2024
2 parents f6799be + 29b923f commit 54c2ed6
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 32 deletions.
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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:
Expand All @@ -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",
},
},
Expand Down Expand Up @@ -416,3 +416,4 @@ pub fn main() !void {
}
```


16 changes: 7 additions & 9 deletions examples/middleware_with_endpoint/middleware_with_endpoint.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions src/fio.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
33 changes: 26 additions & 7 deletions src/middleware.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
}

Expand All @@ -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);
Expand Down
14 changes: 7 additions & 7 deletions src/mustache.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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,

Expand Down Expand Up @@ -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 = .{
Expand Down Expand Up @@ -113,21 +113,21 @@ 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.
/// This is used in `build`.
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);
}
};
Expand All @@ -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);
Expand Down
6 changes: 4 additions & 2 deletions src/request.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 54c2ed6

Please sign in to comment.