mirror of
https://github.com/zigzap/zap.git
synced 2025-10-21 15:44:10 +00:00
Update build system to latest Zig master
Builds with Zig 0.12.0-dev.2341 on x86_64-linux Also ran 'mdformat' on README.md
This commit is contained in:
parent
9ce4b4438d
commit
21d8afb21a
4 changed files with 219 additions and 266 deletions
364
README.md
364
README.md
|
@ -1,224 +1,189 @@
|
||||||
|
|
||||||
|
|
||||||
# ⚡zap⚡ - blazingly fast backends in zig
|
# ⚡zap⚡ - blazingly fast backends in zig
|
||||||
|
|
||||||
 [](https://discord.gg/jQAAN6Ubyj)
|

|
||||||
|
[](https://discord.gg/jQAAN6Ubyj)
|
||||||
|
|
||||||
Zap is the [zig](https://ziglang.org) replacement for the REST APIs I used to
|
Zap is the [zig](https://ziglang.org) replacement for the REST APIs I used to write in
|
||||||
write in [python](https://python.org) with
|
[python](https://python.org) with [Flask](https://flask.palletsprojects.com) and
|
||||||
[Flask](https://flask.palletsprojects.com) and
|
[mongodb](https://www.mongodb.com), etc. It can be considered to be a microframework for web
|
||||||
[mongodb](https://www.mongodb.com), etc. It can be considered to be a
|
applications.
|
||||||
microframework for web applications.
|
|
||||||
|
|
||||||
What I needed as a replacement was a blazingly fast and robust HTTP server that
|
What I needed as a replacement was a blazingly fast and robust HTTP server that I could use with
|
||||||
I could use with Zig, and I chose to wrap the superb evented networking C
|
Zig, and I chose to wrap the superb evented networking C library [facil.io](https://facil.io). Zap
|
||||||
library [facil.io](https://facil.io). Zap wraps and patches [facil.io - the C web application
|
wraps and patches [facil.io - the C web application framework](https://facil.io).
|
||||||
framework](https://facil.io).
|
|
||||||
|
|
||||||
## **⚡ZAP⚡ IS FAST, ROBUST, AND STABLE**
|
## **⚡ZAP⚡ IS FAST, ROBUST, AND STABLE**
|
||||||
|
|
||||||
|
After having used ZAP in production for over 6 months, I can confidently assert that it proved to
|
||||||
After having used ZAP in production for over 6 months, I can confidently assert
|
be:
|
||||||
that it proved to be:
|
|
||||||
|
|
||||||
- ⚡ **blazingly fast** ⚡
|
- ⚡ **blazingly fast** ⚡
|
||||||
- 💪 **extremely robust** 💪
|
- 💪 **extremely robust** 💪
|
||||||
|
|
||||||
Exactly the goals I set out to achieve!
|
Exactly the goals I set out to achieve!
|
||||||
|
|
||||||
|
|
||||||
## Most FAQ:
|
## Most FAQ:
|
||||||
|
|
||||||
- Q: **Where is the API documentation?**
|
- Q: **Where is the API documentation?**
|
||||||
- A: Docs are a work in progress. You can check them out [here](https://zigzap.org/zap). The docs are based on the `zig-0.12.0` branch but apply to the current release (zig 0.11.0), too.
|
- A: Docs are a work in progress. You can check them out [here](https://zigzap.org/zap). The docs
|
||||||
|
are based on the `zig-0.12.0` branch but apply to the current release (zig 0.11.0), too.
|
||||||
- Q: **Zap doesn't build with Zig master?**
|
- Q: **Zap doesn't build with Zig master?**
|
||||||
- A: See the 0.12.0 branch. An example of how to use it is
|
- A: See the 0.12.0 branch. An example of how to use it is
|
||||||
[here](https://github.com/zigzap/hello-0.12.0). Please note that the 0.12.0
|
[here](https://github.com/zigzap/hello-0.12.0). Please note that the 0.12.0 branch is not the
|
||||||
branch is not the official master branch of ZAP. Yet. Until zig 0.12.0 is
|
official master branch of ZAP. Yet. Until zig 0.12.0 is released.
|
||||||
released.
|
|
||||||
- Q: **Does ZAP work on Windows?**
|
- Q: **Does ZAP work on Windows?**
|
||||||
- A: No. This is due to the underlying facil.io C library. Future versions of
|
- A: No. This is due to the underlying facil.io C library. Future versions of facil.io might
|
||||||
facil.io might support Windows but there is no timeline yet. Your best options
|
support Windows but there is no timeline yet. Your best options on Windows are WSL2 or a docker
|
||||||
on Windows are WSL2 or a docker container.
|
container.
|
||||||
- Q: **Does ZAP support TLS / HTTPS?**
|
- Q: **Does ZAP support TLS / HTTPS?**
|
||||||
- A: Yes, ZAP supports using the system's openssl. See the
|
- A: Yes, ZAP supports using the system's openssl. See the [https](./examples/https/https.zig)
|
||||||
[https](./examples/https/https.zig) example and make sure to build with the
|
example and make sure to build with the `-Dopenssl` flag or the environment variable
|
||||||
`-Dopenssl` flag or the environment variable `ZAP_USE_OPENSSL=true`:
|
`ZAP_USE_OPENSSL=true`:
|
||||||
- `.openssl = true,` (in dependent projects' build.zig, `b.dependency("zap"
|
- `.openssl = true,` (in dependent projects' build.zig, `b.dependency("zap" .{...})`)
|
||||||
.{...})`)
|
|
||||||
- `ZAP_USE_OPENSSL=true zig build https`
|
- `ZAP_USE_OPENSSL=true zig build https`
|
||||||
- `zig build -Dopenssl=true https`
|
- `zig build -Dopenssl=true https`
|
||||||
|
|
||||||
## Here's what works
|
## Here's what works
|
||||||
|
|
||||||
I recommend checking out **Endpoint-based examples for more realistic
|
I recommend checking out **Endpoint-based examples for more realistic use cases**. Most of the
|
||||||
use cases**. Most of the examples are super stripped down to only include
|
examples are super stripped down to only include what's necessary to show a feature.
|
||||||
what's necessary to show a feature.
|
|
||||||
|
|
||||||
- **Super easy build process**: Zap's `build.zig` now uses the new Zig package
|
- **Super easy build process**: Zap's `build.zig` now uses the new Zig package manager for its
|
||||||
manager for its C-dependencies, no git submodules anymore.
|
C-dependencies, no git submodules anymore.
|
||||||
- _tested on Linux and macOS (arm, M1)_
|
- _tested on Linux and macOS (arm, M1)_
|
||||||
- **[hello](examples/hello/hello.zig)**: welcomes you with some static HTML
|
- **[hello](examples/hello/hello.zig)**: welcomes you with some static HTML
|
||||||
- **[routes](examples/routes/routes.zig)**: a super easy example dispatching on
|
- **[routes](examples/routes/routes.zig)**: a super easy example dispatching on the HTTP path.
|
||||||
the HTTP path. **NOTE**: The dispatch in the example is a super-basic
|
**NOTE**: The dispatch in the example is a super-basic DIY-style dispatch. See endpoint-based
|
||||||
DIY-style dispatch. See endpoint-based examples for more realistic use cases.
|
examples for more realistic use cases.
|
||||||
- **[serve](examples/serve/serve.zig)**: the traditional static web server with
|
- **[serve](examples/serve/serve.zig)**: the traditional static web server with optional dynamic
|
||||||
optional dynamic request handling
|
request handling
|
||||||
- **[sendfile](examples/sendfile/sendfile.zig)**: simple example of how to send
|
- **[sendfile](examples/sendfile/sendfile.zig)**: simple example of how to send a file, honoring
|
||||||
a file, honoring compression headers, etc.
|
compression headers, etc.
|
||||||
- **[bindataformpost](examples/bindataformpost/bindataformpost.zig)**: example
|
- **[bindataformpost](examples/bindataformpost/bindataformpost.zig)**: example to receive binary
|
||||||
to receive binary files via form post.
|
files via form post.
|
||||||
- **[hello_json](examples/hello_json/hello_json.zig)**: serves you json
|
- **[hello_json](examples/hello_json/hello_json.zig)**: serves you json dependent on HTTP path
|
||||||
dependent on HTTP path
|
- **[endpoint](examples/endpoint/)**: a simple JSON REST API example featuring a `/users` endpoint
|
||||||
- **[endpoint](examples/endpoint/)**: a simple JSON REST API example featuring a
|
for performing PUT/DELETE/GET/POST operations and listing users, together with a simple frontend
|
||||||
`/users` endpoint for performing PUT/DELETE/GET/POST operations and listing
|
to play with. **It also introduces a `/stop` endpoint** that shuts down Zap, so **memory leak
|
||||||
users, together with a simple frontend to play with. **It also introduces a
|
detection** can be performed in main().
|
||||||
`/stop` endpoint** that shuts down Zap, so **memory leak detection** can be
|
|
||||||
performed in main().
|
|
||||||
- Check out how [main.zig](examples/endpoint/main.zig) uses ZIG's awesome
|
- Check out how [main.zig](examples/endpoint/main.zig) uses ZIG's awesome
|
||||||
`GeneralPurposeAllocator` to report memory leaks when ZAP is shut down.
|
`GeneralPurposeAllocator` to report memory leaks when ZAP is shut down. The
|
||||||
The [StopEndpoint](examples/endpoint/stopendpoint.zig) just stops ZAP when
|
[StopEndpoint](examples/endpoint/stopendpoint.zig) just stops ZAP when receiving a request on
|
||||||
receiving a request on the `/stop` route.
|
the `/stop` route.
|
||||||
- **[mustache](examples/mustache/mustache.zig)**: a simple example using
|
- **[mustache](examples/mustache/mustache.zig)**: a simple example using
|
||||||
[mustache](https://mustache.github.io/) templating.
|
[mustache](https://mustache.github.io/) templating.
|
||||||
- **[endpoint authentication](examples/endpoint_auth/endpoint_auth.zig)**: a
|
- **[endpoint authentication](examples/endpoint_auth/endpoint_auth.zig)**: a simple authenticated
|
||||||
simple authenticated endpoint. Read more about authentication
|
endpoint. Read more about authentication [here](./doc/authentication.md).
|
||||||
[here](./doc/authentication.md).
|
- **[http parameters](examples/http_params/http_params.zig)**: a simple example sending itself query
|
||||||
- **[http parameters](examples/http_params/http_params.zig)**: a simple example
|
parameters of all supported types.
|
||||||
sending itself query parameters of all supported types.
|
- **[cookies](examples/cookies/cookies.zig)**: a simple example sending itself a cookie and
|
||||||
- **[cookies](examples/cookies/cookies.zig)**: a simple example sending itself a
|
responding with a session cookie.
|
||||||
cookie and responding with a session cookie.
|
- **[websockets](examples/websockets/)**: a simple websockets chat for the browser.
|
||||||
- **[websockets](examples/websockets/)**: a simple websockets chat for the
|
- **[Username/Password Session Authentication](./examples/userpass_session_auth/)**: A convenience
|
||||||
browser.
|
authenticator that redirects un-authenticated requests to a login page and sends cookies
|
||||||
- **[Username/Password Session
|
containing session tokens based on username/password pairs received via POST request.
|
||||||
Authentication](./examples/userpass_session_auth/)**: A convenience
|
- **[MIDDLEWARE support](examples/middleware/middleware.zig)**: chain together request handlers in
|
||||||
authenticator that redirects un-authenticated requests to a login page and
|
middleware style. Provide custom context structs, totally type-safe, using
|
||||||
sends cookies containing session tokens based on username/password pairs
|
**[ZIG-CEPTION](doc/zig-ception.md)**. If you come from GO this might appeal to you.
|
||||||
received via POST request.
|
- **[MIDDLEWARE with endpoint support](examples/middleware_with_endpoint/middleware_with_endpoint.zig)**:
|
||||||
- **[MIDDLEWARE support](examples/middleware/middleware.zig)**: chain together
|
Same as the example above, but this time we use an endpoint at the end of the chain, by wrapping
|
||||||
request handlers in middleware style. Provide custom context structs, totally
|
it via `zap.Middleware.EndpointHandler`. Mixing endpoints in your middleware chain allows for
|
||||||
type-safe, using **[ZIG-CEPTION](doc/zig-ception.md)**. If you come from GO
|
usage of Zap's authenticated endpoints and your custom endpoints. Since Endpoints use a simpler
|
||||||
this might appeal to you.
|
API, you have to use `r.setUserContext()` and `r.getUserContext()` with the request if you want to
|
||||||
- **[MIDDLEWARE with endpoint
|
access the middleware context from a wrapped endpoint. Since this mechanism uses an `*anyopaque`
|
||||||
support](examples/middleware_with_endpoint/middleware_with_endpoint.zig)**:
|
pointer underneath (to not break the Endpoint API), it is less type-safe than `zap.Middleware`'s
|
||||||
Same as the example above, but this time we use an endpoint at the end of the
|
use of contexts.
|
||||||
chain, by wrapping it via `zap.Middleware.EndpointHandler`. Mixing endpoints
|
- [**Per Request Contexts**](./src/zap.zig#L102) : With the introduction of `setUserContext()` and
|
||||||
in your middleware chain allows for usage of Zap's authenticated endpoints and
|
`getUserContext()`, you can, of course use those two in projects that don't use `zap.Endpoint` or
|
||||||
your custom endpoints. Since Endpoints use a simpler API, you have to use
|
`zap.Middleware`, too, if you really, really, absolutely don't find another way to solve your
|
||||||
`r.setUserContext()` and `r.getUserContext()` with the request if you want to
|
context problem. **We recommend using a `zap.Endpoint`** inside of a struct that can provide all
|
||||||
access the middleware context from a wrapped endpoint. Since this mechanism
|
the context you need **instead**. You get access to your struct in the callbacks via the
|
||||||
uses an `*anyopaque` pointer underneath (to not break the Endpoint API), it is
|
`@fieldParentPtr()` trick that is used extensively in Zap's examples, like the
|
||||||
less type-safe than `zap.Middleware`'s use of contexts.
|
[endpoint example](examples/endpoint/endpoint.zig).
|
||||||
- [**Per Request Contexts**](./src/zap.zig#L102) : With the introduction of
|
- [**Error Trace Responses**](./examples/senderror/senderror.zig): You can now call
|
||||||
`setUserContext()` and `getUserContext()`, you can, of course use those two in
|
`r.sendError(err, status_code)` when you catch an error and a stack trace will be returned to the
|
||||||
projects that don't use `zap.Endpoint` or `zap.Middleware`, too, if you
|
client / browser.
|
||||||
really, really, absolutely don't find another way to solve your context
|
- [**HTTPS**](examples/https/https.zig): Shows how easy it is to use facil.io's openssl support.
|
||||||
problem. **We recommend using a `zap.Endpoint`** inside of a struct that
|
Must be compiled with `-Dopenssl=true` or the environment variable `ZAP_USE_OPENSSL` set to `true`
|
||||||
can provide all the context you need **instead**. You get access to your
|
and requires openssl dev dependencies (headers, lib) to be installed on the system.
|
||||||
struct in the callbacks via the `@fieldParentPtr()` trick that is used
|
- run it like this: `ZAP_USE_OPENSSL=true zig build run-https`\
|
||||||
extensively in Zap's examples, like the [endpoint
|
OR like this:
|
||||||
example](examples/endpoint/endpoint.zig).
|
`zig build -Dopenssl=true run-https`
|
||||||
- [**Error Trace Responses**](./examples/senderror/senderror.zig): You can now
|
|
||||||
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
|
|
||||||
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`
|
|
||||||
OR like this: `zig build -Dopenssl=true run-https`
|
|
||||||
- it will tell you how to generate certificates
|
- it will tell you how to generate certificates
|
||||||
- [**simple_router**](examples/simple_router/simple_router.zig): See how you
|
- [**simple_router**](examples/simple_router/simple_router.zig): See how you can use `zap.Router` to
|
||||||
can use `zap.Router` to dispatch to handlers by HTTP path. It also features
|
dispatch to handlers by HTTP path. It also features `zap.RequestHandler` to capture the "self"
|
||||||
`zap.RequestHandler` to capture the "self" pointer of the container of the
|
pointer of the container of the handler functions.
|
||||||
handler functions.
|
|
||||||
|
|
||||||
I'll continue wrapping more of facil.io's functionality and adding stuff to zap
|
|
||||||
to a point where I can use it as the JSON REST API backend for real research
|
|
||||||
projects, serving thousands of concurrent clients.
|
|
||||||
|
|
||||||
|
I'll continue wrapping more of facil.io's functionality and adding stuff to zap to a point where I
|
||||||
|
can use it as the JSON REST API backend for real research projects, serving thousands of concurrent
|
||||||
|
clients.
|
||||||
|
|
||||||
## ⚡blazingly fast⚡
|
## ⚡blazingly fast⚡
|
||||||
|
|
||||||
Claiming to be blazingly fast is the new black. At least, Zap doesn't slow you
|
Claiming to be blazingly fast is the new black. At least, Zap doesn't slow you down and if your
|
||||||
down and if your server performs poorly, it's probably not exactly Zap's fault.
|
server performs poorly, it's probably not exactly Zap's fault. Zap relies on the
|
||||||
Zap relies on the [facil.io](https://facil.io) framework and so it can't really
|
[facil.io](https://facil.io) framework and so it can't really claim any performance fame for itself.
|
||||||
claim any performance fame for itself. In this initial implementation of Zap,
|
In this initial implementation of Zap, I didn't care about optimizations at all.
|
||||||
I didn't care about optimizations at all.
|
|
||||||
|
|
||||||
But, how fast is it? Being blazingly fast is relative. When compared with a
|
But, how fast is it? Being blazingly fast is relative. When compared with a simple GO HTTP server, a
|
||||||
simple GO HTTP server, a simple Zig Zap HTTP server performed really good on my
|
simple Zig Zap HTTP server performed really good on my machine (x86_64-linux):
|
||||||
machine (x86_64-linux):
|
|
||||||
|
|
||||||
- Zig Zap was nearly 30% faster than GO
|
- Zig Zap was nearly 30% faster than GO
|
||||||
- Zig Zap had over 50% more throughput than GO
|
- Zig Zap had over 50% more throughput than GO
|
||||||
|
|
||||||
**Update**: Thanks to @felipetrz, I got to test against more realistic Python
|
**Update**: Thanks to @felipetrz, I got to test against more realistic Python and Rust examples.
|
||||||
and Rust examples. Both python `sanic` and rust `axum` were easy enough to
|
Both python `sanic` and rust `axum` were easy enough to integrate.
|
||||||
integrate.
|
|
||||||
|
|
||||||
**Update**: I have automated the benchmarks. See
|
**Update**: I have automated the benchmarks. See [blazingly-fast.md](./blazingly-fast.md) for more
|
||||||
[blazingly-fast.md](./blazingly-fast.md) for more information. Also, thanks to
|
information. Also, thanks to @alexpyattaev, the benchmarks are fairer now, pinning server and client
|
||||||
@alexpyattaev, the benchmarks are fairer now, pinning server and client to
|
to specific CPU cores.
|
||||||
specific CPU cores.
|
|
||||||
|
|
||||||
**Update**: I have consolidated the benchmarks to one good representative per
|
**Update**: I have consolidated the benchmarks to one good representative per language. See more
|
||||||
language. See more details in [blazingly-fast.md](./blazingly-fast.md). It
|
details in [blazingly-fast.md](./blazingly-fast.md). It contains rust implementations that come
|
||||||
contains rust implementations that come pretty close to Zap's performance in the
|
pretty close to Zap's performance in the simplistic testing scenario.
|
||||||
simplistic testing scenario.
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
So, being somewhere in the ballpark of basic GO performance, zig zap seems to be ... of reasonable
|
||||||
|
performance 😎.
|
||||||
|
|
||||||
So, being somewhere in the ballpark of basic GO performance, zig zap seems to be
|
I can rest my case that developing ZAP was a good idea because it's faster than both alternatives:
|
||||||
... of reasonable performance 😎.
|
a) staying with Python, and b) creating a GO + Zig hybrid.
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
See more details in [blazingly-fast.md](blazingly-fast.md).
|
See more details in [blazingly-fast.md](blazingly-fast.md).
|
||||||
|
|
||||||
## 💪 Robust
|
## 💪 Robust
|
||||||
|
|
||||||
ZAP is **very robust**. In fact, it is so robust that I was confidently able to
|
ZAP is **very robust**. In fact, it is so robust that I was confidently able to only work with
|
||||||
only work with in-memory data (RAM) in all my ZAP projects so far: over 5 large
|
in-memory data (RAM) in all my ZAP projects so far: over 5 large online research experiments. No
|
||||||
online research experiments. No database, no file persistence, until I hit
|
database, no file persistence, until I hit "save" at the end 😊.
|
||||||
"save" at the end 😊.
|
|
||||||
|
|
||||||
So I was able to postpone my cunning data persistence strategy that's similar to
|
So I was able to postpone my cunning data persistence strategy that's similar to a mark-and-sweep
|
||||||
a mark-and-sweep garbage collector and would only persist "dirty" data when
|
garbage collector and would only persist "dirty" data when traffic is low, in favor of getting stuff
|
||||||
traffic is low, in favor of getting stuff online more quickly. But even if
|
online more quickly. But even if implemented, such a persistence strategy is risky because when
|
||||||
implemented, such a persistence strategy is risky because when traffic is not
|
traffic is not low, it means the system is under (heavy) load. Would you confidently NOT save data
|
||||||
low, it means the system is under (heavy) load. Would you confidently NOT save
|
when load is high and the data changes most frequently -> the potential data loss is maximized?
|
||||||
data when load is high and the data changes most frequently -> the potential
|
|
||||||
data loss is maximized?
|
|
||||||
|
|
||||||
To answer that question, I just skipped it. I skipped saving any data until
|
To answer that question, I just skipped it. I skipped saving any data until receiving a "save"
|
||||||
receiving a "save" signal via API. And it worked. ZAP just kept on zapping. When
|
signal via API. And it worked. ZAP just kept on zapping. When traffic calmed down or all experiment
|
||||||
traffic calmed down or all experiment participants had finished, I hit "save"
|
participants had finished, I hit "save" and went on analyzing the data.
|
||||||
and went on analyzing the data.
|
|
||||||
|
|
||||||
Handling all errors does pay off after all. No hidden control flow, no hidden
|
Handling all errors does pay off after all. No hidden control flow, no hidden errors or exceptions
|
||||||
errors or exceptions is one of Zig's strengths.
|
is one of Zig's strengths.
|
||||||
|
|
||||||
To be honest: There are still pitfalls. E.g. if you request large stack sizes
|
|
||||||
for worker threads, Zig won't like that and panic. So make sure you don't have
|
|
||||||
local variables that require tens of megabytes of stack space.
|
|
||||||
|
|
||||||
|
To be honest: There are still pitfalls. E.g. if you request large stack sizes for worker threads,
|
||||||
|
Zig won't like that and panic. So make sure you don't have local variables that require tens of
|
||||||
|
megabytes of stack space.
|
||||||
|
|
||||||
### 🛡️ Memory-safe
|
### 🛡️ Memory-safe
|
||||||
|
|
||||||
See the [StopEndpoint](examples/endpoint/stopendpoint.zig) in the
|
See the [StopEndpoint](examples/endpoint/stopendpoint.zig) in the [endpoint](examples/endpoint)
|
||||||
[endpoint](examples/endpoint) example. That example uses ZIG's awesome
|
example. That example uses ZIG's awesome `GeneralPurposeAllocator` to report memory leaks when ZAP
|
||||||
`GeneralPurposeAllocator` to report memory leaks when ZAP is shut down. The
|
is shut down. The `StopEndpoint` just stops ZAP when receiving a request on the `/stop` route.
|
||||||
`StopEndpoint` just stops ZAP when receiving a request on the `/stop` route.
|
|
||||||
|
|
||||||
You can use the same strategy in your debug builds and tests to check if your
|
|
||||||
code leaks memory.
|
|
||||||
|
|
||||||
|
|
||||||
|
You can use the same strategy in your debug builds and tests to check if your code leaks memory.
|
||||||
|
|
||||||
## Getting started
|
## Getting started
|
||||||
|
|
||||||
|
@ -246,20 +211,21 @@ $ mkdir zaptest && cd zaptest
|
||||||
$ zig init-exe
|
$ zig init-exe
|
||||||
$ git init ## (optional)
|
$ 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
|
**Note**: Nix/NixOS users are lucky; you can use the existing `flake.nix` and run `nix develop` to
|
||||||
dependencies to build and run the GO, python, and rust examples for the
|
get a development shell providing zig and all dependencies to build and run the GO, python, and rust
|
||||||
`wrk` performance tests. For the mere building of zap projects,
|
examples for the `wrk` performance tests. For the mere building of zap projects,
|
||||||
`nix develop .#build` will only fetch zig 0.11.0.
|
`nix develop .#build` will only fetch zig 0.11.0.
|
||||||
|
|
||||||
With an existing Zig project, adding Zap to it is easy:
|
With an existing Zig project, adding Zap to it is easy:
|
||||||
|
|
||||||
1. Add zap to your `build.zig.zon`
|
1. Add zap to your `build.zig.zon`
|
||||||
2. Add zap to your `build.zig`
|
1. Add zap to your `build.zig`
|
||||||
|
|
||||||
To add zap to `build.zig.zon`:
|
To add zap to `build.zig.zon`:
|
||||||
|
|
||||||
<!-- INSERT_DEP_BEGIN -->
|
<!-- INSERT_DEP_BEGIN -->
|
||||||
|
|
||||||
```zig
|
```zig
|
||||||
.{
|
.{
|
||||||
.name = "My example project",
|
.name = "My example project",
|
||||||
|
@ -274,10 +240,10 @@ To add zap to `build.zig.zon`:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- INSERT_DEP_END -->
|
<!-- INSERT_DEP_END -->
|
||||||
|
|
||||||
Then, in your `build.zig`'s `build` function, add the following before
|
Then, in your `build.zig`'s `build` function, add the following before `b.installArtifact(exe)`:
|
||||||
`b.installArtifact(exe)`:
|
|
||||||
|
|
||||||
```zig
|
```zig
|
||||||
const zap = b.dependency("zap", .{
|
const zap = b.dependency("zap", .{
|
||||||
|
@ -289,8 +255,8 @@ Then, in your `build.zig`'s `build` function, add the following before
|
||||||
exe.linkLibrary(zap.artifact("facil.io"));
|
exe.linkLibrary(zap.artifact("facil.io"));
|
||||||
```
|
```
|
||||||
|
|
||||||
From then on, you can use the Zap package in your project. Check out the
|
From then on, you can use the Zap package in your project. Check out the examples to see how to use
|
||||||
examples to see how to use Zap.
|
Zap.
|
||||||
|
|
||||||
## Updating your project to the latest version of zap
|
## Updating your project to the latest version of zap
|
||||||
|
|
||||||
|
@ -302,9 +268,8 @@ You can change the URL to Zap in your `build.zig.zon`
|
||||||
|
|
||||||
### Using a tagged release
|
### Using a tagged release
|
||||||
|
|
||||||
Go to the [release page](https://github.com/zigzap/zap/releases). Every release
|
Go to the [release page](https://github.com/zigzap/zap/releases). Every release will state its
|
||||||
will state its version number and also provide instructions for changing
|
version number and also provide instructions for changing `build.zig.zon` and `build.zig`.
|
||||||
`build.zig.zon` and `build.zig`.
|
|
||||||
|
|
||||||
### Using other versions
|
### Using other versions
|
||||||
|
|
||||||
|
@ -312,32 +277,28 @@ See [here](./doc/other-versions.md).
|
||||||
|
|
||||||
## Contribute to ⚡zap⚡ - blazingly fast
|
## Contribute to ⚡zap⚡ - blazingly fast
|
||||||
|
|
||||||
At the current time, I can only add to zap what I need for my personal and
|
At the current time, I can only add to zap what I need for my personal and professional projects.
|
||||||
professional projects. While this happens **blazingly fast**, some if not all
|
While this happens **blazingly fast**, some if not all nice-to-have additions will have to wait. You
|
||||||
nice-to-have additions will have to wait. You are very welcome to help make the
|
are very welcome to help make the world a blazingly fast place by providing patches or pull
|
||||||
world a blazingly fast place by providing patches or pull requests, add
|
requests, add documentation or examples, or interesting issues and bug reports - you'll know what to
|
||||||
documentation or examples, or interesting issues and bug reports - you'll know
|
do when you receive your calling 👼.
|
||||||
what to do when you receive your calling 👼.
|
|
||||||
|
|
||||||
Check out [CONTRIBUTING.md](CONTRIBUTING.md) for more details.
|
Check out [CONTRIBUTING.md](CONTRIBUTING.md) for more details.
|
||||||
|
|
||||||
See also [introducing.md](introducing.md) for more on the state and progress of
|
See also [introducing.md](introducing.md) for more on the state and progress of this project.
|
||||||
this project.
|
|
||||||
|
|
||||||
**We now have our own [ZAP discord](https://discord.gg/jQAAN6Ubyj) server!!!**
|
**We now have our own [ZAP discord](https://discord.gg/jQAAN6Ubyj) server!!!**
|
||||||
|
|
||||||
You can also reach me on [the zig showtime discord
|
You can also reach me on [the zig showtime discord server](https://discord.gg/CBzE3VMb) under the
|
||||||
server](https://discord.gg/CBzE3VMb) under the handle renerocksai
|
handle renerocksai (renerocksai#1894).
|
||||||
(renerocksai#1894).
|
|
||||||
|
|
||||||
## Support ⚡zap⚡
|
## Support ⚡zap⚡
|
||||||
|
|
||||||
Being blazingly fast requires a constant feed of caffeine. I usually manage to
|
Being blazingly fast requires a constant feed of caffeine. I usually manage to provide that to
|
||||||
provide that to myself for myself. However, to support keeping the juices
|
myself for myself. However, to support keeping the juices flowing and putting a smile on my face and
|
||||||
flowing and putting a smile on my face and that warm and cozy feeling into my
|
that warm and cozy feeling into my heart, you can always
|
||||||
heart, you can always [buy me a coffee](https://buymeacoffee.com/renerocksai)
|
[buy me a coffee](https://buymeacoffee.com/renerocksai) ☕. All donations are welcomed 🙏 blazingly
|
||||||
☕. All donations are welcomed 🙏 blazingly fast! That being said, just saying
|
fast! That being said, just saying "hi" also works wonders with the smiles, warmth, and coziness 😊.
|
||||||
"hi" also works wonders with the smiles, warmth, and coziness 😊.
|
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
|
@ -348,8 +309,8 @@ $ zig build [EXAMPLE]
|
||||||
$ ./zig-out/bin/[EXAMPLE]
|
$ ./zig-out/bin/[EXAMPLE]
|
||||||
```
|
```
|
||||||
|
|
||||||
... where `[EXAMPLE]` is one of `hello`, `routes`, `serve`, ... see the [list of
|
... where `[EXAMPLE]` is one of `hello`, `routes`, `serve`, ... see the
|
||||||
examples above](#heres-what-works).
|
[list of examples above](#heres-what-works).
|
||||||
|
|
||||||
Example: building and running the hello example:
|
Example: building and running the hello example:
|
||||||
|
|
||||||
|
@ -404,26 +365,3 @@ pub fn main() !void {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
37
build.zig
37
build.zig
|
@ -1,7 +1,7 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const build_facilio = @import("facil.io/build.zig").build_facilio;
|
const build_facilio = @import("facil.io/build.zig").build_facilio;
|
||||||
|
|
||||||
pub fn build(b: *std.build.Builder) !void {
|
pub fn build(b: *std.Build) !void {
|
||||||
const target = b.standardTargetOptions(.{});
|
const target = b.standardTargetOptions(.{});
|
||||||
// Standard release options allow the person running `zig build` to select
|
// Standard release options allow the person running `zig build` to select
|
||||||
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
|
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
|
||||||
|
@ -15,16 +15,16 @@ pub fn build(b: *std.build.Builder) !void {
|
||||||
break :blk false;
|
break :blk false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// create a module to be used internally.
|
// Build Facil.IO as a static library
|
||||||
var zap_module = b.createModule(.{
|
|
||||||
.source_file = .{ .path = "src/zap.zig" },
|
|
||||||
});
|
|
||||||
|
|
||||||
// register the module so it can be referenced using the package manager.
|
|
||||||
try b.modules.put(b.dupe("zap"), zap_module);
|
|
||||||
|
|
||||||
const facilio = try build_facilio("facil.io", b, target, optimize, use_openssl);
|
const facilio = try build_facilio("facil.io", b, target, optimize, use_openssl);
|
||||||
|
|
||||||
|
// Create the Zap module and attach the facilio lib to it.
|
||||||
|
// This will enable all users of Zap to simply import the "zap" module and be on their way.
|
||||||
|
const zap_module = b.addModule("zap", .{
|
||||||
|
.root_source_file = .{ .path = "src/zap.zig" },
|
||||||
|
});
|
||||||
|
zap_module.linkLibrary(facilio);
|
||||||
|
|
||||||
const all_step = b.step("all", "build all examples");
|
const all_step = b.step("all", "build all examples");
|
||||||
|
|
||||||
inline for ([_]struct {
|
inline for ([_]struct {
|
||||||
|
@ -81,8 +81,7 @@ pub fn build(b: *std.build.Builder) !void {
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
|
|
||||||
example.linkLibrary(facilio);
|
example.root_module.addImport("zap", zap_module);
|
||||||
example.addModule("zap", zap_module);
|
|
||||||
|
|
||||||
// const example_run = example.run();
|
// const example_run = example.run();
|
||||||
const example_run = b.addRunArtifact(example);
|
const example_run = b.addRunArtifact(example);
|
||||||
|
@ -120,8 +119,7 @@ pub fn build(b: *std.build.Builder) !void {
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
auth_tests.linkLibrary(facilio);
|
auth_tests.root_module.addImport("zap", zap_module);
|
||||||
auth_tests.addModule("zap", zap_module);
|
|
||||||
|
|
||||||
const run_auth_tests = b.addRunArtifact(auth_tests);
|
const run_auth_tests = b.addRunArtifact(auth_tests);
|
||||||
const install_auth_tests = b.addInstallArtifact(auth_tests, .{});
|
const install_auth_tests = b.addInstallArtifact(auth_tests, .{});
|
||||||
|
@ -133,8 +131,7 @@ pub fn build(b: *std.build.Builder) !void {
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
mustache_tests.linkLibrary(facilio);
|
mustache_tests.root_module.addImport("zap", zap_module);
|
||||||
mustache_tests.addModule("zap", zap_module);
|
|
||||||
|
|
||||||
const run_mustache_tests = b.addRunArtifact(mustache_tests);
|
const run_mustache_tests = b.addRunArtifact(mustache_tests);
|
||||||
const install_mustache_tests = b.addInstallArtifact(mustache_tests, .{});
|
const install_mustache_tests = b.addInstallArtifact(mustache_tests, .{});
|
||||||
|
@ -147,8 +144,7 @@ pub fn build(b: *std.build.Builder) !void {
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
|
|
||||||
httpparams_tests.linkLibrary(facilio);
|
httpparams_tests.root_module.addImport("zap", zap_module);
|
||||||
httpparams_tests.addModule("zap", zap_module);
|
|
||||||
const run_httpparams_tests = b.addRunArtifact(httpparams_tests);
|
const run_httpparams_tests = b.addRunArtifact(httpparams_tests);
|
||||||
// TODO: for some reason, tests aren't run more than once unless
|
// TODO: for some reason, tests aren't run more than once unless
|
||||||
// dependencies have changed.
|
// dependencies have changed.
|
||||||
|
@ -164,8 +160,7 @@ pub fn build(b: *std.build.Builder) !void {
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
|
|
||||||
sendfile_tests.linkLibrary(facilio);
|
sendfile_tests.root_module.addImport("zap", zap_module);
|
||||||
sendfile_tests.addModule("zap", zap_module);
|
|
||||||
const run_sendfile_tests = b.addRunArtifact(sendfile_tests);
|
const run_sendfile_tests = b.addRunArtifact(sendfile_tests);
|
||||||
const install_sendfile_tests = b.addInstallArtifact(sendfile_tests, .{});
|
const install_sendfile_tests = b.addInstallArtifact(sendfile_tests, .{});
|
||||||
|
|
||||||
|
@ -198,7 +193,7 @@ pub fn build(b: *std.build.Builder) !void {
|
||||||
//
|
//
|
||||||
// pkghash
|
// pkghash
|
||||||
//
|
//
|
||||||
var pkghash_exe = b.addExecutable(.{
|
const pkghash_exe = b.addExecutable(.{
|
||||||
.name = "pkghash",
|
.name = "pkghash",
|
||||||
.root_source_file = .{ .path = "./tools/pkghash.zig" },
|
.root_source_file = .{ .path = "./tools/pkghash.zig" },
|
||||||
.target = target,
|
.target = target,
|
||||||
|
@ -212,7 +207,7 @@ pub fn build(b: *std.build.Builder) !void {
|
||||||
//
|
//
|
||||||
// announceybot
|
// announceybot
|
||||||
//
|
//
|
||||||
var announceybot_exe = b.addExecutable(.{
|
const announceybot_exe = b.addExecutable(.{
|
||||||
.name = "announceybot",
|
.name = "announceybot",
|
||||||
.root_source_file = .{ .path = "./tools/announceybot.zig" },
|
.root_source_file = .{ .path = "./tools/announceybot.zig" },
|
||||||
.target = target,
|
.target = target,
|
||||||
|
|
|
@ -1 +1,15 @@
|
||||||
.{ .name = "zap", .version = "0.5.0" }
|
.{
|
||||||
|
.name = "zap",
|
||||||
|
.version = "0.5.0",
|
||||||
|
.paths = .{
|
||||||
|
"doc/",
|
||||||
|
"examples/",
|
||||||
|
"facil.io/",
|
||||||
|
"src/",
|
||||||
|
"tools/",
|
||||||
|
"README.md",
|
||||||
|
"build.zig",
|
||||||
|
"build.zig.zon",
|
||||||
|
"targets.txt",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
|
@ -2,11 +2,11 @@ const std = @import("std");
|
||||||
|
|
||||||
pub fn build_facilio(
|
pub fn build_facilio(
|
||||||
comptime subdir: []const u8,
|
comptime subdir: []const u8,
|
||||||
b: *std.build.Builder,
|
b: *std.Build,
|
||||||
target: std.zig.CrossTarget,
|
target: std.Build.ResolvedTarget,
|
||||||
optimize: std.builtin.OptimizeMode,
|
optimize: std.builtin.OptimizeMode,
|
||||||
use_openssl: bool,
|
use_openssl: bool,
|
||||||
) !*std.build.CompileStep {
|
) !*std.Build.Step.Compile {
|
||||||
const lib = b.addStaticLibrary(.{
|
const lib = b.addStaticLibrary(.{
|
||||||
.name = "facil.io",
|
.name = "facil.io",
|
||||||
.target = target,
|
.target = target,
|
||||||
|
@ -15,7 +15,7 @@ pub fn build_facilio(
|
||||||
|
|
||||||
// Generate flags
|
// Generate flags
|
||||||
var flags = std.ArrayList([]const u8).init(std.heap.page_allocator);
|
var flags = std.ArrayList([]const u8).init(std.heap.page_allocator);
|
||||||
if (lib.optimize != .Debug) try flags.append("-Os");
|
// if (lib.optimize != .Debug) try flags.append("-Os"); // TODO
|
||||||
try flags.append("-Wno-return-type-c-linkage");
|
try flags.append("-Wno-return-type-c-linkage");
|
||||||
try flags.append("-fno-sanitize=undefined");
|
try flags.append("-fno-sanitize=undefined");
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ pub fn build_facilio(
|
||||||
//
|
//
|
||||||
|
|
||||||
try flags.append("-DFIO_HTTP_EXACT_LOGGING");
|
try flags.append("-DFIO_HTTP_EXACT_LOGGING");
|
||||||
if (target.getAbi() == .musl)
|
if (target.result.abi == .musl)
|
||||||
try flags.append("-D_LARGEFILE64_SOURCE");
|
try flags.append("-D_LARGEFILE64_SOURCE");
|
||||||
if (use_openssl)
|
if (use_openssl)
|
||||||
try flags.append("-DHAVE_OPENSSL -DFIO_TLS_FOUND");
|
try flags.append("-DHAVE_OPENSSL -DFIO_TLS_FOUND");
|
||||||
|
@ -42,7 +42,8 @@ pub fn build_facilio(
|
||||||
lib.addIncludePath(.{ .path = subdir ++ "/lib/facil/tls" });
|
lib.addIncludePath(.{ .path = subdir ++ "/lib/facil/tls" });
|
||||||
|
|
||||||
// C source files
|
// C source files
|
||||||
lib.addCSourceFiles(&.{
|
lib.addCSourceFiles(.{
|
||||||
|
.files = &.{
|
||||||
subdir ++ "/lib/facil/fio.c",
|
subdir ++ "/lib/facil/fio.c",
|
||||||
subdir ++ "/lib/facil/fio_zig.c",
|
subdir ++ "/lib/facil/fio_zig.c",
|
||||||
subdir ++ "/lib/facil/http/http.c",
|
subdir ++ "/lib/facil/http/http.c",
|
||||||
|
@ -59,13 +60,18 @@ pub fn build_facilio(
|
||||||
subdir ++ "/lib/facil/fiobj/fiobject.c",
|
subdir ++ "/lib/facil/fiobj/fiobject.c",
|
||||||
subdir ++ "/lib/facil/fiobj/fiobj_mustache.c",
|
subdir ++ "/lib/facil/fiobj/fiobj_mustache.c",
|
||||||
subdir ++ "/lib/facil/cli/fio_cli.c",
|
subdir ++ "/lib/facil/cli/fio_cli.c",
|
||||||
}, flags.items);
|
},
|
||||||
|
.flags = flags.items,
|
||||||
|
});
|
||||||
|
|
||||||
if (use_openssl) {
|
if (use_openssl) {
|
||||||
lib.addCSourceFiles(&.{
|
lib.addCSourceFiles(.{
|
||||||
|
.files = &.{
|
||||||
subdir ++ "/lib/facil/tls/fio_tls_openssl.c",
|
subdir ++ "/lib/facil/tls/fio_tls_openssl.c",
|
||||||
subdir ++ "/lib/facil/tls/fio_tls_missing.c",
|
subdir ++ "/lib/facil/tls/fio_tls_missing.c",
|
||||||
}, flags.items);
|
},
|
||||||
|
.flags = flags.items,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// link against libc
|
// link against libc
|
||||||
|
|
Loading…
Add table
Reference in a new issue