mirror of
https://github.com/zigzap/zap.git
synced 2025-10-21 07:34:08 +00:00
Fix tiny typos
This commit is contained in:
parent
a231371c3a
commit
ada2bd1837
23 changed files with 559 additions and 534 deletions
19
README.md
19
README.md
|
@ -1,5 +1,3 @@
|
||||||
|
|
||||||
|
|
||||||
# ⚡zap⚡ - blazingly fast backends in zig
|
# ⚡zap⚡ - blazingly fast backends in zig
|
||||||
|
|
||||||
 [](https://discord.gg/jQAAN6Ubyj)
|
 [](https://discord.gg/jQAAN6Ubyj)
|
||||||
|
@ -135,7 +133,7 @@ simplistic testing scenario.
|
||||||
|
|
||||||
|
|
||||||
So, being somewhere in the ballpark of basic GO performance, zig zap seems to be
|
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
|
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.
|
both alternatives: a) staying with Python, and b) creating a GO + Zig hybrid.
|
||||||
|
@ -211,7 +209,7 @@ $ git init ## (optional)
|
||||||
**Note**: Nix/NixOS users are lucky; you can use the existing `flake.nix` and run
|
**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
|
`nix develop` to get a development shell providing zig and all
|
||||||
dependencies to build and run the GO, python, and rust examples for the
|
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.
|
`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:
|
||||||
|
@ -364,16 +362,3 @@ pub fn main() !void {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,23 +9,23 @@ since I used to write my REST APIs in python before creating zig zap.
|
||||||
|
|
||||||
You can check out the scripts I used for the tests in [./wrk](wrk/).
|
You can check out the scripts I used for the tests in [./wrk](wrk/).
|
||||||
|
|
||||||
## Why
|
## Why
|
||||||
|
|
||||||
I aimed to enhance the performance of my Python + Flask backends by replacing
|
I aimed to enhance the performance of my Python + Flask backends by replacing
|
||||||
them with a Zig version. To evaluate the success of this transition, I compared
|
them with a Zig version. To evaluate the success of this transition, I compared
|
||||||
the performance of a static HTTP server implemented in Python and its Zig
|
the performance of a static HTTP server implemented in Python and its Zig
|
||||||
counterpart, which showed significant improvements.
|
counterpart, which showed significant improvements.
|
||||||
|
|
||||||
To further assess the Zig server's performance, I compared it with a Go
|
To further assess the Zig server's performance, I compared it with a Go
|
||||||
implementation, to compare against a widely used industry-standard. I expected
|
implementation, to compare against a widely used industry-standard. I expected
|
||||||
similar performance levels but was pleasantly surprised when Zap outperformed Go
|
similar performance levels but was pleasantly surprised when Zap outperformed Go
|
||||||
by approximately 30% on my test machine.
|
by approximately 30% on my test machine.
|
||||||
|
|
||||||
Intrigued by Rust's reputed performance capabilities, I also experimented with a
|
Intrigued by Rust's reputed performance capabilities, I also experimented with a
|
||||||
Rust version. The results of this experiment are discussed in the
|
Rust version. The results of this experiment are discussed in the
|
||||||
[Flaws](#flaws) section below.
|
[Flaws](#flaws) section below.
|
||||||
|
|
||||||
## What
|
## What
|
||||||
|
|
||||||
So, what are the benchmarks testing?
|
So, what are the benchmarks testing?
|
||||||
|
|
||||||
|
@ -114,21 +114,21 @@ different computers. It's interesting to see the variation in relative numbers.
|
||||||
|
|
||||||
```
|
```
|
||||||
➜ neofetch --stdout
|
➜ neofetch --stdout
|
||||||
rs@ryzen
|
rs@ryzen
|
||||||
--------
|
--------
|
||||||
OS: NixOS 23.05.997.ddf4688dc7a (Stoat) x86_64
|
OS: NixOS 23.05.997.ddf4688dc7a (Stoat) x86_64
|
||||||
Host: Micro-Star International Co., Ltd. B550-A PRO (MS-7C56)
|
Host: Micro-Star International Co., Ltd. B550-A PRO (MS-7C56)
|
||||||
Kernel: 6.3.7
|
Kernel: 6.3.7
|
||||||
Uptime: 15 days, 11 hours, 13 mins
|
Uptime: 15 days, 11 hours, 13 mins
|
||||||
Packages: 2094 (nix-system), 1356 (nix-user), 7 (flatpak)
|
Packages: 2094 (nix-system), 1356 (nix-user), 7 (flatpak)
|
||||||
Shell: bash 5.2.15
|
Shell: bash 5.2.15
|
||||||
Resolution: 3840x2160
|
Resolution: 3840x2160
|
||||||
DE: none+i3
|
DE: none+i3
|
||||||
WM: i3
|
WM: i3
|
||||||
Terminal: tmux
|
Terminal: tmux
|
||||||
CPU: AMD Ryzen 5 5600X (12) @ 3.700GHz
|
CPU: AMD Ryzen 5 5600X (12) @ 3.700GHz
|
||||||
GPU: AMD ATI Radeon RX 6700/6700 XT/6750 XT / 6800M/6850M XT
|
GPU: AMD ATI Radeon RX 6700/6700 XT/6750 XT / 6800M/6850M XT
|
||||||
Memory: 4981MiB / 32028MiB
|
Memory: 4981MiB / 32028MiB
|
||||||
|
|
||||||
|
|
||||||
➜ lscpu
|
➜ lscpu
|
||||||
|
@ -151,25 +151,25 @@ Vendor ID: AuthenticAMD
|
||||||
CPU max MHz: 4650.2920
|
CPU max MHz: 4650.2920
|
||||||
CPU min MHz: 2200.0000
|
CPU min MHz: 2200.0000
|
||||||
BogoMIPS: 7399.43
|
BogoMIPS: 7399.43
|
||||||
Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt
|
Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt
|
||||||
pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid aperfmperf rapl pni pclmulqdq monitor ssse3 fma cx16
|
pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid aperfmperf rapl pni pclmulqdq monitor ssse3 fma cx16
|
||||||
sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefet
|
sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefet
|
||||||
ch osvw ibs skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpb cat_l3 cdp_l3 hw_pstate ssbd mba ibrs ib
|
ch osvw ibs skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpb cat_l3 cdp_l3 hw_pstate ssbd mba ibrs ib
|
||||||
pb stibp vmmcall fsgsbase bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xget
|
pb stibp vmmcall fsgsbase bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xget
|
||||||
bv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local clzero irperf xsaveerptr rdpru wbnoinvd arat npt lbrv svm_lock nrip
|
bv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local clzero irperf xsaveerptr rdpru wbnoinvd arat npt lbrv svm_lock nrip
|
||||||
_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif v_spec_ctrl umip pku ospk
|
_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif v_spec_ctrl umip pku ospk
|
||||||
e vaes vpclmulqdq rdpid overflow_recov succor smca fsrm
|
e vaes vpclmulqdq rdpid overflow_recov succor smca fsrm
|
||||||
Virtualization features:
|
Virtualization features:
|
||||||
Virtualization: AMD-V
|
Virtualization: AMD-V
|
||||||
Caches (sum of all):
|
Caches (sum of all):
|
||||||
L1d: 192 KiB (6 instances)
|
L1d: 192 KiB (6 instances)
|
||||||
L1i: 192 KiB (6 instances)
|
L1i: 192 KiB (6 instances)
|
||||||
L2: 3 MiB (6 instances)
|
L2: 3 MiB (6 instances)
|
||||||
L3: 32 MiB (1 instance)
|
L3: 32 MiB (1 instance)
|
||||||
NUMA:
|
NUMA:
|
||||||
NUMA node(s): 1
|
NUMA node(s): 1
|
||||||
NUMA node0 CPU(s): 0-11
|
NUMA node0 CPU(s): 0-11
|
||||||
Vulnerabilities:
|
Vulnerabilities:
|
||||||
Itlb multihit: Not affected
|
Itlb multihit: Not affected
|
||||||
L1tf: Not affected
|
L1tf: Not affected
|
||||||
Mds: Not affected
|
Mds: Not affected
|
||||||
|
@ -185,7 +185,7 @@ Vulnerabilities:
|
||||||
|
|
||||||
### Workstation at work
|
### Workstation at work
|
||||||
|
|
||||||
A beast. Many cores (which we don't use).
|
A beast. Many cores (which we don't use).
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
@ -193,19 +193,19 @@ A beast. Many cores (which we don't use).
|
||||||
|
|
||||||
```
|
```
|
||||||
[rene@nixos:~]$ neofetch --stdout
|
[rene@nixos:~]$ neofetch --stdout
|
||||||
rene@nixos
|
rene@nixos
|
||||||
----------
|
----------
|
||||||
OS: NixOS 23.05.2947.475d5ae2c4cb (Stoat) x86_64
|
OS: NixOS 23.05.2947.475d5ae2c4cb (Stoat) x86_64
|
||||||
Host: LENOVO 1038
|
Host: LENOVO 1038
|
||||||
Kernel: 6.1.46
|
Kernel: 6.1.46
|
||||||
Uptime: 26 mins
|
Uptime: 26 mins
|
||||||
Packages: 5804 (nix-system), 566 (nix-user)
|
Packages: 5804 (nix-system), 566 (nix-user)
|
||||||
Shell: bash 5.2.15
|
Shell: bash 5.2.15
|
||||||
Terminal: /dev/pts/2
|
Terminal: /dev/pts/2
|
||||||
CPU: Intel Xeon Gold 5218 (64) @ 3.900GHz
|
CPU: Intel Xeon Gold 5218 (64) @ 3.900GHz
|
||||||
GPU: NVIDIA Quadro P620
|
GPU: NVIDIA Quadro P620
|
||||||
GPU: NVIDIA Tesla M40
|
GPU: NVIDIA Tesla M40
|
||||||
Memory: 1610MiB / 95247MiB
|
Memory: 1610MiB / 95247MiB
|
||||||
|
|
||||||
|
|
||||||
[rene@nixos:~]$ lscpu
|
[rene@nixos:~]$ lscpu
|
||||||
|
@ -233,18 +233,18 @@ Vendor ID: GenuineIntel
|
||||||
ority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm mpx rdt_a avx512f avx512dq rdseed adx smap clflushopt clwb intel_pt avx512cd avx512bw avx512vl xsaveopt xs
|
ority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm mpx rdt_a avx512f avx512dq rdseed adx smap clflushopt clwb intel_pt avx512cd avx512bw avx512vl xsaveopt xs
|
||||||
avec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local dtherm ida arat pln pts hwp hwp_act_window hwp_epp hwp_pkg_req pku ospke avx512_vnni md_clear flush_l1d arch_capabi
|
avec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local dtherm ida arat pln pts hwp hwp_act_window hwp_epp hwp_pkg_req pku ospke avx512_vnni md_clear flush_l1d arch_capabi
|
||||||
lities
|
lities
|
||||||
Virtualization features:
|
Virtualization features:
|
||||||
Virtualization: VT-x
|
Virtualization: VT-x
|
||||||
Caches (sum of all):
|
Caches (sum of all):
|
||||||
L1d: 1 MiB (32 instances)
|
L1d: 1 MiB (32 instances)
|
||||||
L1i: 1 MiB (32 instances)
|
L1i: 1 MiB (32 instances)
|
||||||
L2: 32 MiB (32 instances)
|
L2: 32 MiB (32 instances)
|
||||||
L3: 44 MiB (2 instances)
|
L3: 44 MiB (2 instances)
|
||||||
NUMA:
|
NUMA:
|
||||||
NUMA node(s): 2
|
NUMA node(s): 2
|
||||||
NUMA node0 CPU(s): 0-15,32-47
|
NUMA node0 CPU(s): 0-15,32-47
|
||||||
NUMA node1 CPU(s): 16-31,48-63
|
NUMA node1 CPU(s): 16-31,48-63
|
||||||
Vulnerabilities:
|
Vulnerabilities:
|
||||||
Gather data sampling: Mitigation; Microcode
|
Gather data sampling: Mitigation; Microcode
|
||||||
Itlb multihit: KVM: Mitigation: VMX disabled
|
Itlb multihit: KVM: Mitigation: VMX disabled
|
||||||
L1tf: Not affected
|
L1tf: Not affected
|
||||||
|
@ -329,4 +329,3 @@ Vulnerability Spectre v2: Mitigation; Enhanced IBRS, IBPB conditional,
|
||||||
Vulnerability Srbds: Mitigation; Microcode
|
Vulnerability Srbds: Mitigation; Microcode
|
||||||
Vulnerability Tsx async abort: Not affected
|
Vulnerability Tsx async abort: Not affected
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ The `zap.BasicAuth` Authenticator accepts 2 comptime values:
|
||||||
|
|
||||||
- `Lookup`: either a map to look up passwords for users or a set to lookup
|
- `Lookup`: either a map to look up passwords for users or a set to lookup
|
||||||
base64 encoded tokens (user:pass -> base64-encode = token)
|
base64 encoded tokens (user:pass -> base64-encode = token)
|
||||||
- `kind` :
|
- `kind` :
|
||||||
- `UserPass` : decode the authentication header, split into user and
|
- `UserPass` : decode the authentication header, split into user and
|
||||||
password, then lookup the password in the provided map and compare it.
|
password, then lookup the password in the provided map and compare it.
|
||||||
- `Token68` : don't bother decoding, the 'lookup' set is filled with
|
- `Token68` : don't bother decoding, the 'lookup' set is filled with
|
||||||
|
@ -122,7 +122,7 @@ var map = Map.init(allocator);
|
||||||
defer map.deinit();
|
defer map.deinit();
|
||||||
|
|
||||||
// create user / pass entry
|
// create user / pass entry
|
||||||
const user = "Alladdin";
|
const user = "Aladdin";
|
||||||
const pass = "opensesame";
|
const pass = "opensesame";
|
||||||
try map.put(user, pass);
|
try map.put(user, pass);
|
||||||
|
|
||||||
|
@ -253,7 +253,7 @@ pub fn main() !void {
|
||||||
listener.listen() catch {};
|
listener.listen() catch {};
|
||||||
std.debug.print(
|
std.debug.print(
|
||||||
\\ Run the following:
|
\\ Run the following:
|
||||||
\\
|
\\
|
||||||
\\ curl http://localhost:3000/test -i -H "Authorization: Bearer ABCDEFG" -v
|
\\ curl http://localhost:3000/test -i -H "Authorization: Bearer ABCDEFG" -v
|
||||||
\\ curl http://localhost:3000/test -i -H "Authorization: Bearer invalid" -v
|
\\ curl http://localhost:3000/test -i -H "Authorization: Bearer invalid" -v
|
||||||
\\
|
\\
|
||||||
|
@ -268,5 +268,3 @@ pub fn main() !void {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
Recently, GitHub started hosting release archives on a dedicated host
|
Recently, GitHub started hosting release archives on a dedicated host
|
||||||
codeload.github.com. This is when the problems started. Back then, zig's package
|
codeload.github.com. This is when the problems started. Back then, zig's package
|
||||||
manager was not expecting to be re-directed to a different URL. On top of that,
|
manager was not expecting to be re-directed to a different URL. On top of that,
|
||||||
GitHub changed the redirected-to URLs so they wouldn't end in `.tar.gz` anymore.
|
GitHub changed the redirected-to URLs so they wouldn't end in `.tar.gz` anymore.
|
||||||
|
|
||||||
Above issues were fixed but after some progress on `zig.http` related standard
|
Above issues were fixed but after some progress on `zig.http` related standard
|
||||||
library stuff, a similar error started impacting the package manager: parsing
|
library stuff, a similar error started impacting the package manager: parsing
|
||||||
|
@ -51,7 +51,7 @@ $ wget https://github.com/zigzap/facil.io/archive/refs/tags/zap-0.0.8.tar.gz
|
||||||
$ # get zap itself
|
$ # get zap itself
|
||||||
$ wget https://github.com/zigzap/zap/archive/refs/tags/release-0.0.20-localhost.tar.gz
|
$ wget https://github.com/zigzap/zap/archive/refs/tags/release-0.0.20-localhost.tar.gz
|
||||||
$ # start a http server on port 8000
|
$ # start a http server on port 8000
|
||||||
$ python -m http.server
|
$ python -m http.server
|
||||||
```
|
```
|
||||||
|
|
||||||
... and use the following in your build.zig.zon:
|
... and use the following in your build.zig.zon:
|
||||||
|
@ -85,7 +85,7 @@ hashes, as well as a `MY_TAG.tar.gz`.
|
||||||
You can then host this via python HTTP server and proceed as if you had
|
You can then host this via python HTTP server and proceed as if you had
|
||||||
downloaded it from github.
|
downloaded it from github.
|
||||||
|
|
||||||
If all goes well, your dependend code should be able to use your freshly-built
|
If all goes well, your dependent code should be able to use your freshly-built
|
||||||
zap release, depending on it via localhost URL in its `build.zig.zon`.
|
zap release, depending on it via localhost URL in its `build.zig.zon`.
|
||||||
|
|
||||||
If not, fix bugs, rinse, and repeat.
|
If not, fix bugs, rinse, and repeat.
|
||||||
|
@ -97,5 +97,3 @@ with the non-localhost version from the master branch. Commit it, make sure your
|
||||||
worktree is clean, and perform above steps again. This time, using a tag that
|
worktree is clean, and perform above steps again. This time, using a tag that
|
||||||
doesn't contain `localhost`. You can then push to your fork and create a release
|
doesn't contain `localhost`. You can then push to your fork and create a release
|
||||||
for the future when zig's bug is fixed.
|
for the future when zig's bug is fixed.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ the `.hash` value in `build.zig.zon`.
|
||||||
|
|
||||||
## Using an arbitrary (last) commit
|
## Using an arbitrary (last) commit
|
||||||
|
|
||||||
Use the same workflow as above for tags, excpept for the URL, use this schema:
|
Use the same workflow as above for tags, except for the URL, use this schema:
|
||||||
|
|
||||||
```zig
|
```zig
|
||||||
.url = "https://github.com/zigzap/zap/archive/[COMMIT-HASH].tar.gz",
|
.url = "https://github.com/zigzap/zap/archive/[COMMIT-HASH].tar.gz",
|
||||||
|
@ -36,5 +36,3 @@ Use the same workflow as above for tags, excpept for the URL, use this schema:
|
||||||
|
|
||||||
Replace `[COMMIT-HASH]` with the full commit hash as provided, e.g. by `git
|
Replace `[COMMIT-HASH]` with the full commit hash as provided, e.g. by `git
|
||||||
log`.
|
log`.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ Here is a complete `build.zig.zon` example:
|
||||||
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", .{
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
|
|
|
@ -13,7 +13,7 @@ that points you directly to where the exception happened, plus a stack-trace.
|
||||||
Wouldn't that be handy? Wouldn't that be a good idea to also make ZAP behave
|
Wouldn't that be handy? Wouldn't that be a good idea to also make ZAP behave
|
||||||
that way?
|
that way?
|
||||||
|
|
||||||
My argument is: NO. Not unconditionally like this.
|
My argument is: NO. Not unconditionally like this.
|
||||||
|
|
||||||
Let me elaborate: First, ZAP the library cannot know what YOU want to do in case
|
Let me elaborate: First, ZAP the library cannot know what YOU want to do in case
|
||||||
of an error. If some `on_request()` returns an error, ZAP would only be able to
|
of an error. If some `on_request()` returns an error, ZAP would only be able to
|
||||||
|
@ -64,7 +64,7 @@ fn on_request_with_errors(r: zap.SimpleHttpRequest) !void {
|
||||||
```
|
```
|
||||||
|
|
||||||
```zig
|
```zig
|
||||||
// THIS IS WHAT YOU PASS TO THE LISTENER / ENDPONT / ...
|
// THIS IS WHAT YOU PASS TO THE LISTENER / ENDPOINT / ...
|
||||||
fn on_request(r: zap.SimpleHttpRequest) void {
|
fn on_request(r: zap.SimpleHttpRequest) void {
|
||||||
on_request_with_errors(r) catch |err| {
|
on_request_with_errors(r) catch |err| {
|
||||||
// log the error or use:
|
// log the error or use:
|
||||||
|
@ -84,5 +84,3 @@ To better support the use-case of flask-like error returning, we will "soon":
|
||||||
|
|
||||||
- only in debug builds would it return the stack traces and in release builds it
|
- only in debug builds would it return the stack traces and in release builds it
|
||||||
would return more generic 50x responses.
|
would return more generic 50x responses.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,6 @@ const UserMiddleWare = struct {
|
||||||
|
|
||||||
## 🤯
|
## 🤯
|
||||||
|
|
||||||
The comments in the code say it all.
|
The comments in the code say it all.
|
||||||
|
|
||||||
**Isn't ZIG AMAZING?**
|
**Isn't ZIG AMAZING?**
|
||||||
|
|
|
@ -92,16 +92,14 @@ pub fn main() !void {
|
||||||
Handler.alloc = allocator;
|
Handler.alloc = allocator;
|
||||||
|
|
||||||
// setup listener
|
// setup listener
|
||||||
var listener = zap.SimpleHttpListener.init(
|
var listener = zap.SimpleHttpListener.init(.{
|
||||||
.{
|
.port = 3000,
|
||||||
.port = 3000,
|
.on_request = Handler.on_request,
|
||||||
.on_request = Handler.on_request,
|
.log = true,
|
||||||
.log = true,
|
.max_clients = 10,
|
||||||
.max_clients = 10,
|
.max_body_size = 10 * 1024 * 1024,
|
||||||
.max_body_size = 10 * 1024 * 1024,
|
.public_folder = ".",
|
||||||
.public_folder = ".",
|
});
|
||||||
},
|
|
||||||
);
|
|
||||||
zap.enableDebugLog();
|
zap.enableDebugLog();
|
||||||
try listener.listen();
|
try listener.listen();
|
||||||
std.log.info("\n\nURL is http://localhost:3000\n", .{});
|
std.log.info("\n\nURL is http://localhost:3000\n", .{});
|
||||||
|
|
|
@ -98,15 +98,13 @@ pub fn main() !void {
|
||||||
Handler.alloc = allocator;
|
Handler.alloc = allocator;
|
||||||
|
|
||||||
// setup listener
|
// setup listener
|
||||||
var listener = zap.SimpleHttpListener.init(
|
var listener = zap.SimpleHttpListener.init(.{
|
||||||
.{
|
.port = 3000,
|
||||||
.port = 3000,
|
.on_request = Handler.on_request,
|
||||||
.on_request = Handler.on_request,
|
.log = false,
|
||||||
.log = false,
|
.max_clients = 10,
|
||||||
.max_clients = 10,
|
.max_body_size = 1 * 1024,
|
||||||
.max_body_size = 1 * 1024,
|
});
|
||||||
},
|
|
||||||
);
|
|
||||||
zap.enableDebugLog();
|
zap.enableDebugLog();
|
||||||
try listener.listen();
|
try listener.listen();
|
||||||
std.log.info("\n\nTerminate with CTRL+C", .{});
|
std.log.info("\n\nTerminate with CTRL+C", .{});
|
||||||
|
|
|
@ -92,7 +92,6 @@ fn postUser(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void {
|
||||||
}
|
}
|
||||||
} else |err| {
|
} else |err| {
|
||||||
std.debug.print("ADDING error: {}\n", .{err});
|
std.debug.print("ADDING error: {}\n", .{err});
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,59 @@
|
||||||
<html lang='en'>
|
<html lang='en'>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset='utf-8'>
|
<meta charset='utf-8'>
|
||||||
<meta name='viewport' content='width=device-width'>
|
<meta name='viewport' content='width=device-width'>
|
||||||
<title>ZAP Demo</title>
|
<title>ZAP Demo</title>
|
||||||
<style>
|
<style>
|
||||||
body {background-color: #0d1117; }
|
body {
|
||||||
h1 {color: #cdb4db; text-align: center;}
|
background-color: #0d1117;
|
||||||
h2 {color: #ffafcc; text-align: center;}
|
}
|
||||||
h3 {color: #ffc8dd; text-align: center; text-decoration: underline;}
|
|
||||||
.brighter {color: #bde0fe;}
|
h1 {
|
||||||
p {color: #ffc927; padding-left: 50px; margin-right: 50px;}
|
color: #cdb4db;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
color: #ffafcc;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
color: #ffc8dd;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brighter {
|
||||||
|
color: #bde0fe;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: #ffc927;
|
||||||
|
padding-left: 50px;
|
||||||
|
margin-right: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
color: #B0B0B0;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #ffc927;
|
||||||
|
padding-left: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
color: #B06060;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
label {color: #B0B0B0;}
|
|
||||||
a {color: #ffc927; padding-left:15px;}
|
|
||||||
input {color: #B06060; margin-bottom: 20px; font-weight: bold; }
|
|
||||||
textarea {
|
textarea {
|
||||||
background-color:#181818;
|
background-color: #181818;
|
||||||
color: #cdb4db;
|
color: #cdb4db;
|
||||||
font-family:Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New, monospace;
|
font-family: Consolas, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
border: 2px solid #cdb4db;
|
border: 2px solid #cdb4db;
|
||||||
|
@ -26,6 +62,7 @@
|
||||||
width: 80%;
|
width: 80%;
|
||||||
height: 18rem;
|
height: 18rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
form {
|
form {
|
||||||
border: 2px solid #cdb4db;
|
border: 2px solid #cdb4db;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
|
@ -36,6 +73,7 @@
|
||||||
text-align: center;
|
text-align: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tdform {
|
.tdform {
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: none;
|
border-radius: none;
|
||||||
|
@ -46,6 +84,7 @@
|
||||||
text-align: center;
|
text-align: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
background-color: #ffafcc;
|
background-color: #ffafcc;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
|
@ -55,37 +94,42 @@
|
||||||
padding-top: 5px;
|
padding-top: 5px;
|
||||||
padding-bottom: 5px;
|
padding-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.updatebutton {
|
.updatebutton {
|
||||||
background-color: #B0B0B0;
|
background-color: #B0B0B0;
|
||||||
color: #181818;
|
color: #181818;
|
||||||
}
|
}
|
||||||
|
|
||||||
.delbutton {
|
.delbutton {
|
||||||
background-color: #B06060;
|
background-color: #B06060;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.center {
|
.center {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
background-color:#181818;
|
background-color: #181818;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
th {
|
th {
|
||||||
color: #B06060;
|
color: #B06060;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
td {
|
td {
|
||||||
color: #B0B0B0;
|
color: #B0B0B0;
|
||||||
}
|
}
|
||||||
tr {
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="center">
|
<div class="center">
|
||||||
<form >
|
<form>
|
||||||
<div>
|
<div>
|
||||||
<label>First name:</label><br>
|
<label>First name:</label><br>
|
||||||
<input id="first_name"></input>
|
<input id="first_name"></input>
|
||||||
|
@ -94,7 +138,7 @@
|
||||||
<label>Last name:</label><br>
|
<label>Last name:</label><br>
|
||||||
<input id="last_name"></input>
|
<input id="last_name"></input>
|
||||||
</div>
|
</div>
|
||||||
<div >
|
<div>
|
||||||
<button type="button" onclick="onNewUser();">Add new user!</button>
|
<button type="button" onclick="onNewUser();">Add new user!</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -113,149 +157,150 @@
|
||||||
<textarea id="log" style="display:none"></textarea>
|
<textarea id="log" style="display:none"></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
var eL = document.getElementById("log");
|
var eL = document.getElementById("log");
|
||||||
var eLt = document.getElementById("logtoggler");
|
var eLt = document.getElementById("logtoggler");
|
||||||
|
|
||||||
var showLog = false;
|
var showLog = false;
|
||||||
|
|
||||||
function toggleLog() {
|
function toggleLog() {
|
||||||
if(showLog) {
|
if (showLog) {
|
||||||
eL.style.display = "none";
|
eL.style.display = "none";
|
||||||
eLt.textContent = "(show)";
|
eLt.textContent = "(show)";
|
||||||
} else {
|
} else {
|
||||||
eL.style.display = "block";
|
eL.style.display = "block";
|
||||||
eLt.textContent = "(hide)";
|
eLt.textContent = "(hide)";
|
||||||
}
|
|
||||||
showLog = !showLog;
|
|
||||||
}
|
|
||||||
function log(s) {
|
|
||||||
eL.value += s.toString();
|
|
||||||
eL.value += "\n"
|
|
||||||
eL.scrollTop = eL.scrollHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendJSON(data, slug, method="POST") {
|
|
||||||
json = JSON.stringify(data);
|
|
||||||
log("SENDING: " + json);
|
|
||||||
const response = fetch(slug, {
|
|
||||||
method: method,
|
|
||||||
body: json,
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json; charset=UTF-8"
|
|
||||||
}
|
}
|
||||||
});
|
showLog = !showLog;
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
function onNewUser() {
|
|
||||||
var first_name = document.getElementById("first_name").value;
|
|
||||||
var last_name = document.getElementById("last_name").value;
|
|
||||||
data = {
|
|
||||||
first_name: first_name,
|
|
||||||
last_name: last_name,
|
|
||||||
}
|
}
|
||||||
sendJSON(data, "/users", "POST")
|
function log(s) {
|
||||||
.then((response) => response.json())
|
eL.value += s.toString();
|
||||||
.then((data) => {
|
eL.value += "\n"
|
||||||
log("SUCESS: " + JSON.stringify(data));
|
eL.scrollTop = eL.scrollHeight;
|
||||||
getUserList();
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
log("Error posting data");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteUser(id) {
|
|
||||||
fetch("/users/" + id, { method: "DELETE", } )
|
|
||||||
.then((response) => response.json())
|
|
||||||
.then((data) => {
|
|
||||||
log("SUCESS: " + JSON.stringify(data));
|
|
||||||
getUserList();
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
log("Error deleting data");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeUser(id) {
|
|
||||||
const firstname = document.getElementById("first_" + id).value;
|
|
||||||
const lastname = document.getElementById("last_" + id).value;
|
|
||||||
data = {
|
|
||||||
first_name: firstname,
|
|
||||||
last_name: lastname,
|
|
||||||
}
|
}
|
||||||
sendJSON(data, "/users/" + id, "PATCH")
|
|
||||||
.then((response) => response.json())
|
|
||||||
.then((data) => {
|
|
||||||
log("SUCESS: " + JSON.stringify(data));
|
|
||||||
getUserList();
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
log("Error updating data");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function addHeaderCell(tr, text) {
|
function sendJSON(data, slug, method = "POST") {
|
||||||
var th = document.createElement('TH');
|
json = JSON.stringify(data);
|
||||||
th.innerHTML = text;
|
log("SENDING: " + json);
|
||||||
tr.appendChild(th);
|
const response = fetch(slug, {
|
||||||
}
|
method: method,
|
||||||
|
body: json,
|
||||||
function showTable(users) {
|
headers: {
|
||||||
var t = document.getElementById("usertable");
|
"Content-Type": "application/json; charset=UTF-8"
|
||||||
var new_t = document.createElement("TABLE");
|
}
|
||||||
var header = new_t.createTHead();
|
});
|
||||||
var tr = header.insertRow();
|
return response;
|
||||||
// insertCell creates TD, we want TH
|
}
|
||||||
addHeaderCell(tr, 'id');
|
|
||||||
addHeaderCell(tr, 'first name');
|
function onNewUser() {
|
||||||
addHeaderCell(tr, 'last name');
|
var first_name = document.getElementById("first_name").value;
|
||||||
addHeaderCell(tr, '');
|
var last_name = document.getElementById("last_name").value;
|
||||||
addHeaderCell(tr, '');
|
data = {
|
||||||
|
first_name: first_name,
|
||||||
console.log("showTable()");
|
last_name: last_name,
|
||||||
console.log(users);
|
}
|
||||||
// add the data rows
|
sendJSON(data, "/users", "POST")
|
||||||
for(var i=0; i<users.length; i++) {
|
.then((response) => response.json())
|
||||||
var row = new_t.insertRow();
|
.then((data) => {
|
||||||
var c1 = row.insertCell();
|
log("SUCCESS: " + JSON.stringify(data));
|
||||||
c1.innerHTML = users[i].id;
|
getUserList();
|
||||||
var c2 = row.insertCell();
|
})
|
||||||
c2.innerHTML = '<input id="first_' + users[i].id + '" value="' + users[i].first_name + '"></input>';
|
.catch((error) => {
|
||||||
var c3 = row.insertCell();
|
log("Error posting data");
|
||||||
c3.innerHTML = '<input id="last_' + users[i].id + '" value="' + users[i].last_name + '"></input>';
|
});
|
||||||
var c4 = row.insertCell();
|
}
|
||||||
c4.innerHTML = ''
|
|
||||||
+ '<form class="tdform"><button class="updatebutton" type="button" onclick="changeUser(' + users[i].id + ');">change</button></form>'
|
function deleteUser(id) {
|
||||||
;
|
fetch("/users/" + id, { method: "DELETE", })
|
||||||
var c5 = row.insertCell();
|
.then((response) => response.json())
|
||||||
c5.innerHTML = ''
|
.then((data) => {
|
||||||
+ '<form class="tdform"><button class="delbutton" type="button" onclick="deleteUser(' + users[i].id + ');">del</button></form>'
|
log("SUCCESS: " + JSON.stringify(data));
|
||||||
;
|
getUserList();
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
log("Error deleting data");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeUser(id) {
|
||||||
|
const firstname = document.getElementById("first_" + id).value;
|
||||||
|
const lastname = document.getElementById("last_" + id).value;
|
||||||
|
data = {
|
||||||
|
first_name: firstname,
|
||||||
|
last_name: lastname,
|
||||||
|
}
|
||||||
|
sendJSON(data, "/users/" + id, "PATCH")
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
log("SUCCESS: " + JSON.stringify(data));
|
||||||
|
getUserList();
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
log("Error updating data");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function addHeaderCell(tr, text) {
|
||||||
|
var th = document.createElement('TH');
|
||||||
|
th.innerHTML = text;
|
||||||
|
tr.appendChild(th);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showTable(users) {
|
||||||
|
var t = document.getElementById("usertable");
|
||||||
|
var new_t = document.createElement("TABLE");
|
||||||
|
var header = new_t.createTHead();
|
||||||
|
var tr = header.insertRow();
|
||||||
|
// insertCell creates TD, we want TH
|
||||||
|
addHeaderCell(tr, 'id');
|
||||||
|
addHeaderCell(tr, 'first name');
|
||||||
|
addHeaderCell(tr, 'last name');
|
||||||
|
addHeaderCell(tr, '');
|
||||||
|
addHeaderCell(tr, '');
|
||||||
|
|
||||||
|
console.log("showTable()");
|
||||||
|
console.log(users);
|
||||||
|
// add the data rows
|
||||||
|
for (var i = 0; i < users.length; i++) {
|
||||||
|
var row = new_t.insertRow();
|
||||||
|
var c1 = row.insertCell();
|
||||||
|
c1.innerHTML = users[i].id;
|
||||||
|
var c2 = row.insertCell();
|
||||||
|
c2.innerHTML = '<input id="first_' + users[i].id + '" value="' + users[i].first_name + '"></input>';
|
||||||
|
var c3 = row.insertCell();
|
||||||
|
c3.innerHTML = '<input id="last_' + users[i].id + '" value="' + users[i].last_name + '"></input>';
|
||||||
|
var c4 = row.insertCell();
|
||||||
|
c4.innerHTML = ''
|
||||||
|
+ '<form class="tdform"><button class="updatebutton" type="button" onclick="changeUser(' + users[i].id + ');">change</button></form>'
|
||||||
|
;
|
||||||
|
var c5 = row.insertCell();
|
||||||
|
c5.innerHTML = ''
|
||||||
|
+ '<form class="tdform"><button class="delbutton" type="button" onclick="deleteUser(' + users[i].id + ');">del</button></form>'
|
||||||
|
;
|
||||||
|
}
|
||||||
|
console.log("before replace");
|
||||||
|
t.innerHTML = new_t.innerHTML;
|
||||||
|
console.log("after replace");
|
||||||
}
|
}
|
||||||
console.log("before replace");
|
|
||||||
t.innerHTML = new_t.innerHTML;
|
|
||||||
console.log("after replace");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function getUserList() {
|
function getUserList() {
|
||||||
fetch("/users", { method: "GET", } )
|
fetch("/users", { method: "GET", })
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
log("SUCESS: " + JSON.stringify(data));
|
log("SUCCESS: " + JSON.stringify(data));
|
||||||
showTable(data);
|
showTable(data);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
log("Error fetching data");
|
log("Error fetching data");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
getUserList();
|
getUserList();
|
||||||
}
|
}
|
||||||
init();
|
init();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -58,7 +58,7 @@ pub fn main() !void {
|
||||||
listener.listen() catch {};
|
listener.listen() catch {};
|
||||||
std.debug.print(
|
std.debug.print(
|
||||||
\\ Run the following:
|
\\ Run the following:
|
||||||
\\
|
\\
|
||||||
\\ curl http://localhost:3000/test -i -H "Authorization: Bearer ABCDEFG" -v
|
\\ curl http://localhost:3000/test -i -H "Authorization: Bearer ABCDEFG" -v
|
||||||
\\ curl http://localhost:3000/test -i -H "Authorization: Bearer invalid" -v
|
\\ curl http://localhost:3000/test -i -H "Authorization: Bearer invalid" -v
|
||||||
\\
|
\\
|
||||||
|
|
|
@ -52,7 +52,7 @@ pub fn main() !void {
|
||||||
|
|
||||||
std.debug.print(
|
std.debug.print(
|
||||||
\\ Listening on 0.0.0.0:3000
|
\\ Listening on 0.0.0.0:3000
|
||||||
\\
|
\\
|
||||||
\\ Check out:
|
\\ Check out:
|
||||||
\\ http://localhost:3000/user/1 # -- first user
|
\\ http://localhost:3000/user/1 # -- first user
|
||||||
\\ http://localhost:3000/user/2 # -- second user
|
\\ http://localhost:3000/user/2 # -- second user
|
||||||
|
|
|
@ -98,15 +98,13 @@ pub fn main() !void {
|
||||||
Handler.alloc = allocator;
|
Handler.alloc = allocator;
|
||||||
|
|
||||||
// setup listener
|
// setup listener
|
||||||
var listener = zap.SimpleHttpListener.init(
|
var listener = zap.SimpleHttpListener.init(.{
|
||||||
.{
|
.port = 3000,
|
||||||
.port = 3000,
|
.on_request = Handler.on_request,
|
||||||
.on_request = Handler.on_request,
|
.log = false,
|
||||||
.log = false,
|
.max_clients = 10,
|
||||||
.max_clients = 10,
|
.max_body_size = 1 * 1024,
|
||||||
.max_body_size = 1 * 1024,
|
});
|
||||||
},
|
|
||||||
);
|
|
||||||
zap.enableDebugLog();
|
zap.enableDebugLog();
|
||||||
try listener.listen();
|
try listener.listen();
|
||||||
std.log.info("\n\nTerminate with CTRL+C or by sending query param terminate=true\n", .{});
|
std.log.info("\n\nTerminate with CTRL+C or by sending query param terminate=true\n", .{});
|
||||||
|
|
|
@ -191,7 +191,6 @@ const HtmlEndpoint = struct {
|
||||||
|
|
||||||
r.setContentType(.TEXT) catch unreachable;
|
r.setContentType(.TEXT) catch unreachable;
|
||||||
r.sendBody(message) catch unreachable;
|
r.sendBody(message) catch unreachable;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -27,15 +27,13 @@ pub fn on_request(r: zap.SimpleRequest) void {
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
// setup listener
|
// setup listener
|
||||||
var listener = zap.SimpleHttpListener.init(
|
var listener = zap.SimpleHttpListener.init(.{
|
||||||
.{
|
.port = 3000,
|
||||||
.port = 3000,
|
.on_request = on_request,
|
||||||
.on_request = on_request,
|
.log = true,
|
||||||
.log = true,
|
.max_clients = 10,
|
||||||
.max_clients = 10,
|
.max_body_size = 1 * 1024, // careful here
|
||||||
.max_body_size = 1 * 1024, // careful here
|
});
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
zap.enableDebugLog();
|
zap.enableDebugLog();
|
||||||
try listener.listen();
|
try listener.listen();
|
||||||
|
|
|
@ -1,90 +1,94 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
|
||||||
<style>
|
|
||||||
/* Bordered form */
|
|
||||||
form {
|
|
||||||
border: 3px solid #f1f1f1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Full-width inputs */
|
<head>
|
||||||
input[type=text], input[type=password] {
|
<style>
|
||||||
width: 100%;
|
/* Bordered form */
|
||||||
padding: 12px 20px;
|
form {
|
||||||
margin: 8px 0;
|
border: 3px solid #f1f1f1;
|
||||||
display: inline-block;
|
}
|
||||||
border: 1px solid #ccc;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set a style for all buttons */
|
/* Full-width inputs */
|
||||||
button {
|
input[type=text],
|
||||||
background-color: #04AA6D;
|
input[type=password] {
|
||||||
color: white;
|
width: 100%;
|
||||||
padding: 14px 20px;
|
padding: 12px 20px;
|
||||||
margin: 8px 0;
|
margin: 8px 0;
|
||||||
border: none;
|
display: inline-block;
|
||||||
cursor: pointer;
|
border: 1px solid #ccc;
|
||||||
width: 100%;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add a hover effect for buttons */
|
/* Set a style for all buttons */
|
||||||
button:hover {
|
button {
|
||||||
opacity: 0.8;
|
background-color: #04AA6D;
|
||||||
}
|
color: white;
|
||||||
|
padding: 14px 20px;
|
||||||
|
margin: 8px 0;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
/* Extra style for the cancel button (red) */
|
/* Add a hover effect for buttons */
|
||||||
.cancelbtn {
|
button:hover {
|
||||||
width: auto;
|
opacity: 0.8;
|
||||||
padding: 10px 18px;
|
}
|
||||||
background-color: #f44336;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Center the avatar image inside this container */
|
/* Extra style for the cancel button (red) */
|
||||||
.imgcontainer {
|
.cancelbtn {
|
||||||
text-align: center;
|
width: auto;
|
||||||
margin: 24px 0 12px 0;
|
padding: 10px 18px;
|
||||||
}
|
background-color: #f44336;
|
||||||
|
}
|
||||||
|
|
||||||
/* Avatar image */
|
/* Center the avatar image inside this container */
|
||||||
img.avatar {
|
.imgcontainer {
|
||||||
width: 40%;
|
text-align: center;
|
||||||
border-radius: 50%;
|
margin: 24px 0 12px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add padding to containers */
|
/* Avatar image */
|
||||||
.container {
|
img.avatar {
|
||||||
padding: 16px;
|
width: 40%;
|
||||||
}
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add padding to containers */
|
||||||
|
.container {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Change styles for span and cancel button on extra small screens */
|
/* Change styles for span and cancel button on extra small screens */
|
||||||
@media screen and (max-width: 300px) {
|
@media screen and (max-width: 300px) {
|
||||||
span.psw {
|
span.psw {
|
||||||
display: block;
|
display: block;
|
||||||
float: none;
|
float: none;
|
||||||
}
|
}
|
||||||
.cancelbtn {
|
|
||||||
width: 100%;
|
.cancelbtn {
|
||||||
}
|
width: 100%;
|
||||||
}
|
}
|
||||||
</style>
|
}
|
||||||
</head>
|
</style>
|
||||||
<body>
|
</head>
|
||||||
<form action="normal_page" method="post"> <!-- we post directly to the page we want to display if login is successful-->
|
|
||||||
<div class="imgcontainer">
|
<body>
|
||||||
<img src="/login/Ziggy_the_Ziguana.svg.png" alt="Avatar" class="avatar">
|
<form action="normal_page" method="post"> <!-- we post directly to the page we want to display if login is successful-->
|
||||||
</div>
|
<div class="imgcontainer">
|
||||||
|
<img src="/login/Ziggy_the_Ziguana.svg.png" alt="Avatar" class="avatar">
|
||||||
<div class="container">
|
</div>
|
||||||
<label for="username"><b>Username</b></label>
|
|
||||||
<input type="text" placeholder="Enter Username" name="username" required>
|
<div class="container">
|
||||||
|
<label for="username"><b>Username</b></label>
|
||||||
<label for="password"><b>Password</b></label>
|
<input type="text" placeholder="Enter Username" name="username" required>
|
||||||
<input type="password" placeholder="Enter Password" name="password" required>
|
|
||||||
|
<label for="password"><b>Password</b></label>
|
||||||
<button type="submit">Login</button>
|
<input type="password" placeholder="Enter Password" name="password" required>
|
||||||
</div>
|
|
||||||
</form>
|
<button type="submit">Login</button>
|
||||||
</body>
|
</div>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
|
@ -1,183 +1,192 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
|
||||||
<script src="showdown.min.js"></script>
|
|
||||||
|
|
||||||
<title>ZAP-Chat</title>
|
<head>
|
||||||
<style>
|
<meta charset="UTF-8">
|
||||||
* {
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||||
box-sizing: border-box;
|
<script src="showdown.min.js"></script>
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
<title>ZAP-Chat</title>
|
||||||
font-family: 'Arial', sans-serif;
|
<style>
|
||||||
background-color: #f0f0f0;
|
* {
|
||||||
margin: 0;
|
box-sizing: border-box;
|
||||||
padding: 0;
|
|
||||||
padding-bottom: 80px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
max-width: 960px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
header {
|
|
||||||
background-color: #cd0f0d;
|
|
||||||
color: white;
|
|
||||||
text-align: center;
|
|
||||||
padding: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
header h1 {
|
|
||||||
font-size: 2rem;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-between;
|
|
||||||
background-color: white;
|
|
||||||
border-radius: 10px;
|
|
||||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
||||||
padding: 2rem;
|
|
||||||
/* height: 500px; */
|
|
||||||
height: calc(100vh - 260px);
|
|
||||||
margin-top: 2rem;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message {
|
|
||||||
max-width: 80%;
|
|
||||||
padding: 0.5rem;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
border-radius: 10px;
|
|
||||||
/* font-size: 1.2rem; */
|
|
||||||
}
|
|
||||||
|
|
||||||
.bot {
|
|
||||||
align-self: flex-start;
|
|
||||||
background-color: #e0e0e0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user {
|
|
||||||
align-self: flex-end;
|
|
||||||
background-color: #cd0f0d;;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.busy-indicator {
|
|
||||||
display: inline-block;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
border: 3px solid rgba(255, 255, 255, 0.3);
|
|
||||||
border-radius: 50%;
|
|
||||||
border-top-color: #ffffff;
|
|
||||||
animation: spin 1s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes spin {
|
|
||||||
0% {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
}
|
||||||
100% {
|
|
||||||
transform: rotate(360deg);
|
body {
|
||||||
|
font-family: 'Arial', sans-serif;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
padding-bottom: 80px;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.input-container {
|
.container {
|
||||||
display: flex;
|
max-width: 960px;
|
||||||
justify-content: space-between;
|
margin: 0 auto;
|
||||||
position: fixed;
|
}
|
||||||
bottom: 0px;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
background-color: #f0f0f0;
|
|
||||||
padding-left: 1rem;
|
|
||||||
padding-right: 1rem;
|
|
||||||
padding-bottom: 0.8rem;
|
|
||||||
padding-top: 1rem;
|
|
||||||
max-width: 960px;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
/* box-shadow: 0 -2px 4px rgba(0, 0, 0, 0.1); */
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-container input {
|
header {
|
||||||
flex-grow: 1;
|
background-color: #cd0f0d;
|
||||||
padding: 1rem;
|
color: white;
|
||||||
border-radius: 10px;
|
text-align: center;
|
||||||
border: 2px solid #cd0f0d;
|
padding: 1.5rem;
|
||||||
outline: none;
|
}
|
||||||
/* font-size: 1.2rem; */
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-container button {
|
header h1 {
|
||||||
background-color: #cd0f0d;;
|
font-size: 2rem;
|
||||||
color: white;
|
margin: 0;
|
||||||
border: none;
|
}
|
||||||
border-radius: 10px;
|
|
||||||
padding: 1rem 2rem;
|
|
||||||
cursor: pointer;
|
|
||||||
margin-left: 1rem;
|
|
||||||
outline: none;
|
|
||||||
transition: 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-container button:hover {
|
.chat-container {
|
||||||
background-color: #A20000;
|
display: flex;
|
||||||
}
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||||
|
padding: 2rem;
|
||||||
|
/* height: 500px; */
|
||||||
|
height: calc(100vh - 260px);
|
||||||
|
margin-top: 2rem;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.status-bar {
|
.message {
|
||||||
background-color: #8B0000;
|
max-width: 80%;
|
||||||
color: white;
|
padding: 0.5rem;
|
||||||
text-align: center;
|
margin-bottom: 1rem;
|
||||||
padding: 0.5rem;
|
border-radius: 10px;
|
||||||
font-size: 0.9rem;
|
/* font-size: 1.2rem; */
|
||||||
position: fixed;
|
}
|
||||||
/* bottom: 60px; */
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
max-width: 960px;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
/* border-top-left-radius: 10px; */
|
|
||||||
/* border-top-right-radius: 10px; */
|
|
||||||
border-bottom-left-radius: 10px;
|
|
||||||
border-bottom-right-radius: 10px;
|
|
||||||
box-shadow: 0 -2px 4px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-online {
|
.bot {
|
||||||
/* Green, MediumSeaGreen */
|
align-self: flex-start;
|
||||||
background-color: #3CB371;
|
background-color: #e0e0e0;
|
||||||
}
|
}
|
||||||
.status-busy {
|
|
||||||
/* Blue, DodgerBlue */
|
|
||||||
background-color: #1E90FF;
|
|
||||||
}
|
|
||||||
.status-thinking {
|
|
||||||
/* Light Gray, LightSlateGray */
|
|
||||||
background-color: #778899;
|
|
||||||
}
|
|
||||||
.status-offline {
|
|
||||||
/* Red, Tomato */
|
|
||||||
background-color: #FF6347;
|
|
||||||
}
|
|
||||||
.status-warning {
|
|
||||||
/* Yellow, Goldenrod */
|
|
||||||
background-color: #DAA520;
|
|
||||||
}
|
|
||||||
.status-error {
|
|
||||||
/* Dark-Red, Firebrick */
|
|
||||||
background-color: #B22222;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
.user {
|
||||||
|
align-self: flex-end;
|
||||||
|
background-color: #cd0f0d;
|
||||||
|
;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.busy-indicator {
|
||||||
|
display: inline-block;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border: 3px solid rgba(255, 255, 255, 0.3);
|
||||||
|
border-radius: 50%;
|
||||||
|
border-top-color: #ffffff;
|
||||||
|
animation: spin 1s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
padding-left: 1rem;
|
||||||
|
padding-right: 1rem;
|
||||||
|
padding-bottom: 0.8rem;
|
||||||
|
padding-top: 1rem;
|
||||||
|
max-width: 960px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
/* box-shadow: 0 -2px 4px rgba(0, 0, 0, 0.1); */
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-container input {
|
||||||
|
flex-grow: 1;
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 2px solid #cd0f0d;
|
||||||
|
outline: none;
|
||||||
|
/* font-size: 1.2rem; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-container button {
|
||||||
|
background-color: #cd0f0d;
|
||||||
|
;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 1rem 2rem;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-left: 1rem;
|
||||||
|
outline: none;
|
||||||
|
transition: 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-container button:hover {
|
||||||
|
background-color: #A20000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-bar {
|
||||||
|
background-color: #8B0000;
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0.5rem;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
position: fixed;
|
||||||
|
/* bottom: 60px; */
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
max-width: 960px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
/* border-top-left-radius: 10px; */
|
||||||
|
/* border-top-right-radius: 10px; */
|
||||||
|
border-bottom-left-radius: 10px;
|
||||||
|
border-bottom-right-radius: 10px;
|
||||||
|
box-shadow: 0 -2px 4px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-online {
|
||||||
|
/* Green, MediumSeaGreen */
|
||||||
|
background-color: #3CB371;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-busy {
|
||||||
|
/* Blue, DodgerBlue */
|
||||||
|
background-color: #1E90FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-thinking {
|
||||||
|
/* Light Gray, LightSlateGray */
|
||||||
|
background-color: #778899;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-offline {
|
||||||
|
/* Red, Tomato */
|
||||||
|
background-color: #FF6347;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-warning {
|
||||||
|
/* Yellow, Goldenrod */
|
||||||
|
background-color: #DAA520;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-error {
|
||||||
|
/* Dark-Red, Firebrick */
|
||||||
|
background-color: #B22222;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<header>
|
<header>
|
||||||
|
@ -207,4 +216,5 @@
|
||||||
document.head.appendChild(scriptTag);
|
document.head.appendChild(scriptTag);
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -21,31 +21,31 @@ Here's what works:
|
||||||
- **Super easy build process**: zap's `build.zig` fetches facilio's git sub-module, applies a patch to its logging for microsecond precision, and then builds and optionally runs everything.
|
- **Super easy build process**: zap's `build.zig` fetches facilio's git sub-module, applies a patch to its logging for microsecond precision, and then builds and optionally runs everything.
|
||||||
- _tested on Linux and macOS (arm, M1)_
|
- _tested on Linux and macOS (arm, M1)_
|
||||||
- **[hello](https://github.com/renerocksai/zap/blob/master/examples/hello/hello.zig)**: welcomes you with some static HTML
|
- **[hello](https://github.com/renerocksai/zap/blob/master/examples/hello/hello.zig)**: welcomes you with some static HTML
|
||||||
- **[routes](https://github.com/renerocksai/zap/blob/master/examples/routes/routes.zig)**: a super easy example dispatching on the HTTP path
|
- **[routes](https://github.com/renerocksai/zap/blob/master/examples/routes/routes.zig)**: a super easy example dispatching on the HTTP path
|
||||||
- **[serve](https://github.com/renerocksai/zap/blob/master/examples/serve/serve.zig)**: the traditional static web server with optional dynamic request handling
|
- **[serve](https://github.com/renerocksai/zap/blob/master/examples/serve/serve.zig)**: the traditional static web server with optional dynamic request handling
|
||||||
- **[hello_json](https://github.com/renerocksai/zap/blob/master/examples/hello_json/hello_json.zig)**: serves you json dependent on HTTP path
|
- **[hello_json](https://github.com/renerocksai/zap/blob/master/examples/hello_json/hello_json.zig)**: serves you json dependent on HTTP path
|
||||||
- **[endpoint](https://github.com/renerocksai/zap/blob/master/examples/endpoint/)**: a simple JSON REST API example featuring a `/users` endpoint for PUTting/DELETE-ing/GET-ting/POST-ing and listing users, together with a static HTML and JavaScript frontend to play with.
|
- **[endpoint](https://github.com/renerocksai/zap/blob/master/examples/endpoint/)**: a simple JSON REST API example featuring a `/users` endpoint for PUTting/DELETE-ing/GET-ting/POST-ing and listing users, together with a static HTML and JavaScript frontend to play with.
|
||||||
|
|
||||||
If you want to take it for a quick spin:
|
If you want to take it for a quick spin:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ git clone https://github.com/renerocksai/zap.git
|
$ git clone https://github.com/renerocksai/zap.git
|
||||||
$ cd zap
|
$ cd zap
|
||||||
$ zig build run-hello
|
$ zig build run-hello
|
||||||
$ # open http://localhost:3000 in your browser
|
$ # open http://localhost:3000 in your browser
|
||||||
```
|
```
|
||||||
|
|
||||||
See [the README](https://github.com/renerocksai/zap) for how easy it is to get started, how to run the examples, and how to use zap in your own projects.
|
See [the README](https://github.com/renerocksai/zap) for how easy it is to get started, how to run the examples, and how to use zap in your own projects.
|
||||||
|
|
||||||
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. Now that the endpoint example works, ZAP has actually become pretty usable to me.
|
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. Now that the endpoint example works, ZAP has actually become pretty usable to me.
|
||||||
|
|
||||||
**Side-note:** It never ceases to amaze me how productive I can be in zig, eventhough I am still considering myself to be a newbie. Sometimes, it's almost like writing python but with all the nice speed and guarantees that zig gives you. Also, the C integration abilities of zig are just phenomenal! I am super excited about zig's future!
|
**Side-note:** It never ceases to amaze me how productive I can be in zig, even though I am still considering myself to be a newbie. Sometimes, it's almost like writing python but with all the nice speed and guarantees that zig gives you. Also, the C integration abilities of zig are just phenomenal! I am super excited about zig's future!
|
||||||
|
|
||||||
Now, on to the guiding principles of Zap.
|
Now, on to the guiding principles of Zap.
|
||||||
|
|
||||||
## robust
|
## robust
|
||||||
|
|
||||||
A common recommendation for doing web stuff in zig is to write the actual HTTP server in Go, and use zig for the real work. While there is a selection of notable and cool HTTP server implementations written in zig out there, at the time of writing, most of them seem to a) depend on zig's async facilities which are unsupported until ca. April 2023 when async will return to the self-hosted compiler, and b) have not matured to a point where **I** feel safe using them in production. These are just my opionions and they could be totally wrong though.
|
A common recommendation for doing web stuff in zig is to write the actual HTTP server in Go, and use zig for the real work. While there is a selection of notable and cool HTTP server implementations written in zig out there, at the time of writing, most of them seem to a) depend on zig's async facilities which are unsupported until ca. April 2023 when async will return to the self-hosted compiler, and b) have not matured to a point where **I** feel safe using them in production. These are just my opinions and they could be totally wrong though.
|
||||||
|
|
||||||
However, when I conduct my next online research experiment with thousands of concurrent clients, I cannot afford to run into potential maturity-problems of the HTTP server. These projects typically feature a you-get-one-shot process with little room for errors or re-tries.
|
However, when I conduct my next online research experiment with thousands of concurrent clients, I cannot afford to run into potential maturity-problems of the HTTP server. These projects typically feature a you-get-one-shot process with little room for errors or re-tries.
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ So, being somewhere in the ballpark of basic GO performance, zig zap seems to be
|
||||||
|
|
||||||
See more details in [blazingly-fast.md](https://github.com/renerocksai/zap/blob/master/blazingly-fast.md).
|
See more details in [blazingly-fast.md](https://github.com/renerocksai/zap/blob/master/blazingly-fast.md).
|
||||||
|
|
||||||
## minimal
|
## minimal
|
||||||
|
|
||||||
Zap is minimal by necessity. I only (have time to) add what I need - for serving REST APIs and HTML. The primary use-case are frontends that I wrote that communicate with my APIs. Hence, the focus is more on getting stuff done rather than conforming to every standard there is. Even though facilio is able to support TLS, I don't care about that - at least for now. Also, if you present `404 - File not found` as human-readable HTML to the user, nobody forces you to also set the status code to 404, so it can be OK to spare those nanoseconds. Gotta go fast!
|
Zap is minimal by necessity. I only (have time to) add what I need - for serving REST APIs and HTML. The primary use-case are frontends that I wrote that communicate with my APIs. Hence, the focus is more on getting stuff done rather than conforming to every standard there is. Even though facilio is able to support TLS, I don't care about that - at least for now. Also, if you present `404 - File not found` as human-readable HTML to the user, nobody forces you to also set the status code to 404, so it can be OK to spare those nanoseconds. Gotta go fast!
|
||||||
|
|
||||||
|
@ -91,10 +91,10 @@ I am super excited about both zig and zap's future. I am still impressed by how
|
||||||
|
|
||||||
Provided that the incorporated C code is well-written and -tested, WYSIWYG even holds mostly true for combined Zig and C projects.
|
Provided that the incorporated C code is well-written and -tested, WYSIWYG even holds mostly true for combined Zig and C projects.
|
||||||
|
|
||||||
You can truly build on the soulders of giants here. Mind you, it took me less than a week to arrive at the current state of zap where I am confident that I can already use it to write the one or other REST API with it and, after stress-testing, just move it into production - from merely researching Zig and C web frameworks a few days ago.
|
You can truly build on the shoulders of giants here. Mind you, it took me less than a week to arrive at the current state of zap where I am confident that I can already use it to write the one or other REST API with it and, after stress-testing, just move it into production - from merely researching Zig and C web frameworks a few days ago.
|
||||||
|
|
||||||
Oh, and have I mentioned Zig's built-in build system and testing framework? Those are both super amazing and super convenient. `zig build` is so much more useful than `make` (which I quite like to be honest). And `zig test` is just amazing, too. Zig's physical code layout: which file is located where and how can it be built, imported, tested - it all makes so much sense. Such a coherent, pleasant experience.
|
Oh, and have I mentioned Zig's built-in build system and testing framework? Those are both super amazing and super convenient. `zig build` is so much more useful than `make` (which I quite like to be honest). And `zig test` is just amazing, too. Zig's physical code layout: which file is located where and how can it be built, imported, tested - it all makes so much sense. Such a coherent, pleasant experience.
|
||||||
|
|
||||||
Looking forward, I am also tempted to try adding some log-and-replay facilities as a kind of backup for when things go wrong. I wouldn't be confident to attemt such things in C because I'd view them as being too much work; too much could go wrong. But with Zig, I am rather excited about the possibilities that open up and eager to try such things.
|
Looking forward, I am also tempted to try adding some log-and-replay facilities as a kind of backup for when things go wrong. I wouldn't be confident to attempt such things in C because I'd view them as being too much work; too much could go wrong. But with Zig, I am rather excited about the possibilities that open up and eager to try such things.
|
||||||
|
|
||||||
For great justice!
|
For great justice!
|
||||||
|
|
|
@ -156,7 +156,7 @@ pub fn BasicAuth(comptime Lookup: type, comptime kind: BasicAuthStrategy) type {
|
||||||
} else |err| {
|
} else |err| {
|
||||||
// can't calc slice size --> fallthrough to return false
|
// can't calc slice size --> fallthrough to return false
|
||||||
zap.debug(
|
zap.debug(
|
||||||
"ERROR: UserPassAuth: cannot calc slize size for encoded `{s}`: {any} \n",
|
"ERROR: UserPassAuth: cannot calc slice size for encoded `{s}`: {any} \n",
|
||||||
.{ encoded, err },
|
.{ encoded, err },
|
||||||
);
|
);
|
||||||
return .AuthFailed;
|
return .AuthFailed;
|
||||||
|
|
|
@ -80,7 +80,7 @@ pub fn Handler(comptime ContextType: anytype) type {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A convenience handler for artibrary zap.SimpleEndpoint
|
/// A convenience handler for arbitrary zap.SimpleEndpoint
|
||||||
pub fn EndpointHandler(comptime HandlerType: anytype, comptime ContextType: anytype) type {
|
pub fn EndpointHandler(comptime HandlerType: anytype, comptime ContextType: anytype) type {
|
||||||
return struct {
|
return struct {
|
||||||
handler: HandlerType,
|
handler: HandlerType,
|
||||||
|
|
|
@ -74,7 +74,7 @@ test "BasicAuth UserPass" {
|
||||||
defer map.deinit();
|
defer map.deinit();
|
||||||
|
|
||||||
// create user / pass entry
|
// create user / pass entry
|
||||||
const user = "Alladdin";
|
const user = "Aladdin";
|
||||||
const pass = "opensesame";
|
const pass = "opensesame";
|
||||||
try map.put(user, pass);
|
try map.put(user, pass);
|
||||||
|
|
||||||
|
@ -521,7 +521,7 @@ test "BasicAuth UserPass authenticateRequest" {
|
||||||
defer map.deinit();
|
defer map.deinit();
|
||||||
|
|
||||||
// create user / pass entry
|
// create user / pass entry
|
||||||
const user = "Alladdin";
|
const user = "Aladdin";
|
||||||
const pass = "opensesame";
|
const pass = "opensesame";
|
||||||
try map.put(user, pass);
|
try map.put(user, pass);
|
||||||
|
|
||||||
|
@ -587,7 +587,7 @@ test "BasicAuth UserPass authenticateRequest test-unauthorized" {
|
||||||
defer map.deinit();
|
defer map.deinit();
|
||||||
|
|
||||||
// create user / pass entry
|
// create user / pass entry
|
||||||
const user = "Alladdin";
|
const user = "Aladdin";
|
||||||
const pass = "opensesame";
|
const pass = "opensesame";
|
||||||
try map.put(user, pass);
|
try map.put(user, pass);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue