Init
This commit is contained in:
commit
e70a04ac16
19 changed files with 576 additions and 0 deletions
22
.gitignore
vendored
Normal file
22
.gitignore
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# This file is for zig-specific build artifacts.
|
||||||
|
# If you have OS-specific or editor-specific files to ignore,
|
||||||
|
# such as *.swp or .DS_Store, put those in your global
|
||||||
|
# ~/.gitignore and put this in your ~/.gitconfig:
|
||||||
|
#
|
||||||
|
# [core]
|
||||||
|
# excludesfile = ~/.gitignore
|
||||||
|
#
|
||||||
|
# Cheers!
|
||||||
|
# -andrewrk
|
||||||
|
|
||||||
|
.zig-cache/
|
||||||
|
zig-out/
|
||||||
|
/release/
|
||||||
|
/debug/
|
||||||
|
/build/
|
||||||
|
/build-*/
|
||||||
|
/docgen_tmp/
|
||||||
|
|
||||||
|
# Although this was renamed to .zig-cache, let's leave it here for a few
|
||||||
|
# releases to make it less annoying to work with multiple branches.
|
||||||
|
zig-cache/
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025 Dominic Grimm
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
35
build.zig
Normal file
35
build.zig
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn build(b: *std.Build) void {
|
||||||
|
const target = b.standardTargetOptions(.{});
|
||||||
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
|
const zap_dep = b.dependency("zap", .{});
|
||||||
|
|
||||||
|
const lib_mod = b.addModule("craftflut", .{
|
||||||
|
.root_source_file = b.path("src/root.zig"),
|
||||||
|
});
|
||||||
|
lib_mod.addImport("zap", zap_dep.module("zap"));
|
||||||
|
|
||||||
|
const exe_mod = b.createModule(.{
|
||||||
|
.root_source_file = b.path("src/main.zig"),
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
exe_mod.addImport("craftflut", lib_mod);
|
||||||
|
|
||||||
|
const exe = b.addExecutable(.{
|
||||||
|
.name = "craftflut",
|
||||||
|
.root_module = exe_mod,
|
||||||
|
});
|
||||||
|
b.installArtifact(exe);
|
||||||
|
|
||||||
|
const run_cmd = b.addRunArtifact(exe);
|
||||||
|
run_cmd.step.dependOn(b.getInstallStep());
|
||||||
|
if (b.args) |args| {
|
||||||
|
run_cmd.addArgs(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const run_step = b.step("run", "Run the app");
|
||||||
|
run_step.dependOn(&run_cmd.step);
|
||||||
|
}
|
19
build.zig.zon
Normal file
19
build.zig.zon
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
.{
|
||||||
|
.name = .craftflut,
|
||||||
|
.version = "0.0.0",
|
||||||
|
.fingerprint = 0xc80c703678f7ec11,
|
||||||
|
.minimum_zig_version = "0.14.0",
|
||||||
|
|
||||||
|
.dependencies = .{
|
||||||
|
.zap = .{
|
||||||
|
.url = "git+https://github.com/zigzap/zap.git#ec7cac6f6ab8e1892fe6fc499fd37cd93f7b2256",
|
||||||
|
.hash = "zap-0.9.1-GoeB85JTJAADY1vAnA4lTuU66t6JJiuhGos5ex6CpifA",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.paths = .{
|
||||||
|
"build.zig",
|
||||||
|
"build.zig.zon",
|
||||||
|
"src",
|
||||||
|
"LICENSE",
|
||||||
|
},
|
||||||
|
}
|
0
src/dispatchers/BlockUpdate.zig
Normal file
0
src/dispatchers/BlockUpdate.zig
Normal file
0
src/dispatchers/root.zig
Normal file
0
src/dispatchers/root.zig
Normal file
24
src/main.zig
Normal file
24
src/main.zig
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
|
const craftflut = @import("craftflut");
|
||||||
|
|
||||||
|
pub const std_options: std.Options = .{
|
||||||
|
.log_level = if (builtin.mode == .Debug) .debug else .info,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
var gpa = std.heap.GeneralPurposeAllocator(.{
|
||||||
|
.thread_safe = true,
|
||||||
|
}){};
|
||||||
|
defer _ = gpa.deinit();
|
||||||
|
const allocator = gpa.allocator();
|
||||||
|
|
||||||
|
{
|
||||||
|
const config = craftflut.Config{
|
||||||
|
.web_port = 3000,
|
||||||
|
.web_threads = 16,
|
||||||
|
};
|
||||||
|
try craftflut.start(allocator, &config);
|
||||||
|
}
|
||||||
|
}
|
152
src/mpsc.zig
Normal file
152
src/mpsc.zig
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn Slot(comptime T: type) type {
|
||||||
|
return struct {
|
||||||
|
value: T,
|
||||||
|
version: std.atomic.Value(usize),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn RingBuffer(comptime T: type) type {
|
||||||
|
return struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
capacity: usize,
|
||||||
|
buffer: []Slot(T),
|
||||||
|
head: std.atomic.Value(usize) = std.atomic.Value(usize).init(0),
|
||||||
|
tail: usize = 0,
|
||||||
|
|
||||||
|
pub fn init(buffer: []Slot(T)) Self {
|
||||||
|
// var buffer: [capacity]Slot(T) = undefined;
|
||||||
|
// {
|
||||||
|
// @setEvalBranchQuota(capacity * 4);
|
||||||
|
// for (0..capacity) |i| {
|
||||||
|
// buffer[i].version = std.atomic.Value(usize).init(i);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
for (buffer, 0..) |*slot, i| {
|
||||||
|
slot.version = std.atomic.Value(usize).init(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.capacity = buffer.len,
|
||||||
|
.buffer = buffer,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enqueue(self: *Self, value: T) error{Overflow}!void {
|
||||||
|
while (true) {
|
||||||
|
const head = self.head.load(.acquire);
|
||||||
|
const index = head % self.capacity;
|
||||||
|
const slot = &self.buffer[index];
|
||||||
|
|
||||||
|
const expected_version = head;
|
||||||
|
if (slot.version.load(.acquire) != expected_version) {
|
||||||
|
return error.Overflow;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.head.cmpxchgStrong(
|
||||||
|
head,
|
||||||
|
head + 1,
|
||||||
|
.seq_cst,
|
||||||
|
.seq_cst,
|
||||||
|
)) |_| {
|
||||||
|
std.atomic.spinLoopHint();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
slot.value = value;
|
||||||
|
slot.version.store(expected_version + 1, .release);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dequeue(self: *Self) error{Underflow}!T {
|
||||||
|
const tail = self.tail;
|
||||||
|
const index = tail % self.capacity;
|
||||||
|
const slot = &self.buffer[index];
|
||||||
|
|
||||||
|
const expected_version = tail + 1;
|
||||||
|
if (slot.version.load(.acquire) != expected_version) {
|
||||||
|
return error.Underflow;
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = slot.value;
|
||||||
|
slot.version.store(tail +% self.capacity, .release);
|
||||||
|
self.tail +%= 1;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub fn RingBuffer(comptime T: type) type {
|
||||||
|
// return struct {
|
||||||
|
// const Self = @This();
|
||||||
|
|
||||||
|
// capacity: usize,
|
||||||
|
// buffer: []Slot(T),
|
||||||
|
// head: std.atomic.Value(usize) = std.atomic.Value(usize).init(0),
|
||||||
|
// tail: usize = 0,
|
||||||
|
|
||||||
|
// pub fn init(buffer: []Slot(T)) Self {
|
||||||
|
// // var buffer: [capacity]Slot(T) = undefined;
|
||||||
|
// // {
|
||||||
|
// // @setEvalBranchQuota(capacity * 4);
|
||||||
|
// // for (0..capacity) |i| {
|
||||||
|
// // buffer[i].version = std.atomic.Value(usize).init(i);
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
// for (buffer, 0..) |*slot, i| {
|
||||||
|
// slot.value = std.atomic.Value(usize).init(i);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return .{
|
||||||
|
// .capacity = buffer.len,
|
||||||
|
// .buffer = buffer,
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn enqueue(self: *Self, value: T) error{Overflow}!void {
|
||||||
|
// while (true) {
|
||||||
|
// const head = self.head.load(.acquire);
|
||||||
|
// const index = head % self.capacity;
|
||||||
|
// const slot = &self.buffer[index];
|
||||||
|
|
||||||
|
// const expected_version = head;
|
||||||
|
// if (slot.version.load(.acquire) != expected_version) {
|
||||||
|
// return error.Overflow;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (self.head.cmpxchgStrong(
|
||||||
|
// head,
|
||||||
|
// head + 1,
|
||||||
|
// .seq_cst,
|
||||||
|
// .seq_cst,
|
||||||
|
// )) |_| {
|
||||||
|
// std.atomic.spinLoopHint();
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// slot.value = value;
|
||||||
|
// slot.version.store(expected_version + 1, .release);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn dequeue(self: *Self) error{Underflow}!T {
|
||||||
|
// const tail = self.tail;
|
||||||
|
// const index = tail % self.capacity;
|
||||||
|
// const slot = &self.buffer[index];
|
||||||
|
|
||||||
|
// const expected_version = tail + 1;
|
||||||
|
// if (slot.version.load(.acquire) != expected_version) {
|
||||||
|
// return error.Underflow;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const value = slot.value;
|
||||||
|
// slot.version.store(tail +% self.capacity, .release);
|
||||||
|
// self.tail +%= 1;
|
||||||
|
// return value;
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// }
|
10
src/msg_queue/messages.zig
Normal file
10
src/msg_queue/messages.zig
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
pub const BlockUpdate = struct {
|
||||||
|
pub const material_len_max = 32;
|
||||||
|
|
||||||
|
dimension: u8,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
z: i32,
|
||||||
|
material: [material_len_max]u8 = undefined,
|
||||||
|
material_len: usize = 0,
|
||||||
|
};
|
35
src/msg_queue/queue.zig
Normal file
35
src/msg_queue/queue.zig
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const mpsc = @import("../mpsc.zig");
|
||||||
|
|
||||||
|
pub fn Queue(comptime T: type) type {
|
||||||
|
return struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
ring_buffer: mpsc.RingBuffer(T),
|
||||||
|
|
||||||
|
pub fn init(buffer: []mpsc.Slot(T)) Self {
|
||||||
|
return .{
|
||||||
|
.ring_buffer = mpsc.RingBuffer(T).init(buffer),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn blockingEnqueue(self: *Self, value: T) void {
|
||||||
|
while (true) {
|
||||||
|
self.ring_buffer.enqueue(value) catch |err| switch (err) {
|
||||||
|
error.Overflow => {
|
||||||
|
std.atomic.spinLoopHint();
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dequeue(self: *Self) ?T {
|
||||||
|
return self.ring_buffer.dequeue() catch |err| switch (err) {
|
||||||
|
error.Underflow => return null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
78
src/msg_queue/root.zig
Normal file
78
src/msg_queue/root.zig
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const mpsc = @import("../mpsc.zig");
|
||||||
|
const queue = @import("queue.zig");
|
||||||
|
|
||||||
|
pub const messages = @import("messages.zig");
|
||||||
|
|
||||||
|
pub fn MsgQueueUnmanaged(comptime T: type) type {
|
||||||
|
return struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
queue: queue.Queue(T),
|
||||||
|
// consumer_mutex: std.Thread.Mutex = std.Thread.Mutex{},
|
||||||
|
cond: std.Thread.Condition = std.Thread.Condition{},
|
||||||
|
|
||||||
|
pub fn init(buffer: []mpsc.Slot(T)) Self {
|
||||||
|
return .{
|
||||||
|
.queue = queue.Queue(T).init(buffer),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enqueue(self: *Self, value: T) void {
|
||||||
|
self.queue.blockingEnqueue(value);
|
||||||
|
std.log.info("enqueue: SENDING signal", .{});
|
||||||
|
self.cond.signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dequeue(self: *Self) T {
|
||||||
|
var m = std.Thread.Mutex{};
|
||||||
|
m.lock();
|
||||||
|
defer m.unlock();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (self.queue.dequeue()) |val| return val;
|
||||||
|
std.log.info("dequeue: STARTING consumer condition wait", .{});
|
||||||
|
self.cond.wait(&m);
|
||||||
|
std.log.info("dequeue: RECEIVED signal", .{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn MsgQueueManaged(comptime T: type) type {
|
||||||
|
return struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
buffer: []mpsc.Slot(T),
|
||||||
|
msg_queue: MsgQueueUnmanaged(T),
|
||||||
|
|
||||||
|
pub fn init(allocator: std.mem.Allocator, capacity: usize) !Self {
|
||||||
|
const buffer = try allocator.alloc(mpsc.Slot(T), capacity);
|
||||||
|
errdefer allocator.free(buffer);
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.allocator = allocator,
|
||||||
|
.buffer = buffer,
|
||||||
|
.msg_queue = MsgQueueUnmanaged(T).init(buffer),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Self) void {
|
||||||
|
self.allocator.free(self.buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unmanaged(self: *Self) *MsgQueueUnmanaged(T) {
|
||||||
|
return &self.msg_queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enqueue(self: *Self, value: T) void {
|
||||||
|
self.msg_queue.enqueue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dequeue(self: *Self) T {
|
||||||
|
return self.msg_queue.dequeue();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
28
src/root.zig
Normal file
28
src/root.zig
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const msg_queue = @import("msg_queue/root.zig");
|
||||||
|
const dispatchers = @import("dispatchers/root.zig");
|
||||||
|
const web = @import("web/root.zig");
|
||||||
|
|
||||||
|
pub const Config = struct {
|
||||||
|
web_port: u16,
|
||||||
|
web_threads: i16,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn receiver(queue: *msg_queue.MsgQueueUnmanaged(msg_queue.messages.BlockUpdate)) void {
|
||||||
|
while (true) {
|
||||||
|
const packet = queue.dequeue();
|
||||||
|
std.log.info("packet: {}", .{packet});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start(allocator: std.mem.Allocator, config: *const Config) !void {
|
||||||
|
// var update_queue = UpdateQueue.init();
|
||||||
|
const capacity: usize = 1024;
|
||||||
|
var queue = try msg_queue.MsgQueueManaged(msg_queue.messages.BlockUpdate).init(allocator, capacity);
|
||||||
|
defer queue.deinit();
|
||||||
|
|
||||||
|
_ = try std.Thread.spawn(.{}, receiver, .{queue.unmanaged()});
|
||||||
|
|
||||||
|
try web.start(allocator, config.web_threads, config.web_port, queue.unmanaged());
|
||||||
|
}
|
89
src/web/endpoints/Block.zig
Normal file
89
src/web/endpoints/Block.zig
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const zap = @import("zap");
|
||||||
|
|
||||||
|
const models = @import("../models/root.zig");
|
||||||
|
const stores = @import("../stores/root.zig");
|
||||||
|
const msg_queue = @import("../../msg_queue/root.zig");
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
pub const default_path = "block";
|
||||||
|
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
block_update_queue: *const stores.BlockUpdateQueue,
|
||||||
|
|
||||||
|
path: []const u8,
|
||||||
|
error_strategy: zap.Endpoint.ErrorStrategy = .log_to_console,
|
||||||
|
|
||||||
|
pub fn init(allocator: std.mem.Allocator, block_update_queue: *const stores.BlockUpdateQueue, path: []const u8) Self {
|
||||||
|
return .{
|
||||||
|
.allocator = allocator,
|
||||||
|
.block_update_queue = block_update_queue,
|
||||||
|
.path = path,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(_: *Self, r: zap.Request) !void {
|
||||||
|
r.setStatus(.method_not_allowed);
|
||||||
|
r.markAsFinished(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn post(_: *Self, r: zap.Request) !void {
|
||||||
|
r.setStatus(.method_not_allowed);
|
||||||
|
r.markAsFinished(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn put(self: *Self, r: zap.Request) !void {
|
||||||
|
blk: {
|
||||||
|
if (r.body) |body| {
|
||||||
|
const maybe_block: ?std.json.Parsed(models.Block) = std.json.parseFromSlice(models.Block, self.allocator, body, .{}) catch null;
|
||||||
|
if (maybe_block) |parsed| {
|
||||||
|
defer parsed.deinit();
|
||||||
|
const block = parsed.value;
|
||||||
|
if (block.material.len > msg_queue.messages.BlockUpdate.material_len_max or !models.Block.materialIsValid(block.material)) {
|
||||||
|
break :blk;
|
||||||
|
}
|
||||||
|
std.log.info("block: {}", .{block});
|
||||||
|
|
||||||
|
var msg = msg_queue.messages.BlockUpdate{
|
||||||
|
.dimension = block.dimension,
|
||||||
|
.x = block.x,
|
||||||
|
.y = block.y,
|
||||||
|
.z = block.z,
|
||||||
|
};
|
||||||
|
std.mem.copyForwards(u8, &msg.material, block.material);
|
||||||
|
msg.material_len = block.material.len;
|
||||||
|
self.block_update_queue.queue.enqueue(msg);
|
||||||
|
|
||||||
|
r.setStatus(.created);
|
||||||
|
r.markAsFinished(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r.setStatus(.bad_request);
|
||||||
|
r.markAsFinished(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete(_: *Self, r: zap.Request) !void {
|
||||||
|
r.setStatus(.method_not_allowed);
|
||||||
|
r.markAsFinished(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn patch(_: *Self, r: zap.Request) !void {
|
||||||
|
r.setStatus(.method_not_allowed);
|
||||||
|
r.markAsFinished(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn options(_: *Self, r: zap.Request) !void {
|
||||||
|
try r.setHeader("Access-Control-Allow-Origin", "*");
|
||||||
|
try r.setHeader("Access-Control-Allow-Methods", "PUT, OPTIONS, HEAD");
|
||||||
|
r.setStatus(zap.http.StatusCode.no_content);
|
||||||
|
r.markAsFinished(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn head(_: *Self, r: zap.Request) !void {
|
||||||
|
r.setStatus(zap.http.StatusCode.no_content);
|
||||||
|
r.markAsFinished(true);
|
||||||
|
}
|
1
src/web/endpoints/root.zig
Normal file
1
src/web/endpoints/root.zig
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub const Block = @import("Block.zig");
|
16
src/web/models/Block.zig
Normal file
16
src/web/models/Block.zig
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
dimension: u8,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
z: i32,
|
||||||
|
material: []const u8,
|
||||||
|
|
||||||
|
pub fn materialIsValid(material: []const u8) bool {
|
||||||
|
for (material) |ch| {
|
||||||
|
if (!std.ascii.isAlphabetic(ch))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
1
src/web/models/root.zig
Normal file
1
src/web/models/root.zig
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub const Block = @import("Block.zig");
|
41
src/web/root.zig
Normal file
41
src/web/root.zig
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const zap = @import("zap");
|
||||||
|
|
||||||
|
const msg_queue = @import("../msg_queue/root.zig");
|
||||||
|
|
||||||
|
const models = @import("models/root.zig");
|
||||||
|
const endpoints = @import("endpoints/root.zig");
|
||||||
|
const stores = @import("stores/root.zig");
|
||||||
|
|
||||||
|
fn onRequest(r: zap.Request) !void {
|
||||||
|
_ = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start(allocator: std.mem.Allocator, threads: i16, port: u16, queue: *msg_queue.MsgQueueUnmanaged(msg_queue.messages.BlockUpdate)) !void {
|
||||||
|
var listener = zap.Endpoint.Listener.init(allocator, .{
|
||||||
|
.port = port,
|
||||||
|
.on_request = onRequest,
|
||||||
|
.log = true,
|
||||||
|
});
|
||||||
|
defer listener.deinit();
|
||||||
|
|
||||||
|
const block_update_queue_store = stores.BlockUpdateQueue{
|
||||||
|
.queue = queue,
|
||||||
|
};
|
||||||
|
|
||||||
|
var block_endpoint = endpoints.Block.init(
|
||||||
|
allocator,
|
||||||
|
&block_update_queue_store,
|
||||||
|
std.fmt.comptimePrint("/api/{s}", .{endpoints.Block.default_path}),
|
||||||
|
);
|
||||||
|
|
||||||
|
try listener.register(&block_endpoint);
|
||||||
|
|
||||||
|
try listener.listen();
|
||||||
|
std.log.info("Listening on 0.0.0.0:{d}", .{port});
|
||||||
|
|
||||||
|
zap.start(.{
|
||||||
|
.threads = threads,
|
||||||
|
.workers = 1,
|
||||||
|
});
|
||||||
|
}
|
3
src/web/stores/BlockUpdateQueue.zig
Normal file
3
src/web/stores/BlockUpdateQueue.zig
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
const msg_queue = @import("../../msg_queue/root.zig");
|
||||||
|
|
||||||
|
queue: *msg_queue.MsgQueueUnmanaged(msg_queue.messages.BlockUpdate),
|
1
src/web/stores/root.zig
Normal file
1
src/web/stores/root.zig
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub const BlockUpdateQueue = @import("BlockUpdateQueue.zig");
|
Loading…
Add table
Add a link
Reference in a new issue