94 lines
3.0 KiB
Zig
94 lines
3.0 KiB
Zig
//! Entry point for the zocket daemon.
|
|
//!
|
|
//! Handles allocator selection (debug-checked vs. release), CLI argument
|
|
//! parsing, and configuration path resolution before handing off to `run`.
|
|
|
|
const zocket = @import("zocket");
|
|
|
|
const std = @import("std");
|
|
const builtin = @import("builtin");
|
|
const options = @import("build_options");
|
|
|
|
|
|
const args = zocket.deps.args;
|
|
|
|
/// Resolves the config path, then delegates to `run`.
|
|
///
|
|
/// Allocator strategy:
|
|
/// - Debug builds use `DebugAllocator`, which tracks every allocation and
|
|
/// panics/exits on leaks or double-frees.
|
|
/// - Release builds use `smp_allocator`.
|
|
pub fn main(init: std.process.Init) !void
|
|
{
|
|
const debug = builtin.mode == .Debug;
|
|
const io = init.io;
|
|
|
|
var gpa: std.heap.DebugAllocator(.{}) = .init;
|
|
defer if (gpa.deinit() == .leak) std.process.exit(1);
|
|
|
|
const allocator = if (debug) gpa.allocator() else std.heap.smp_allocator;
|
|
|
|
var tmp_arena: ?std.heap.ArenaAllocator = .init(allocator);
|
|
errdefer _ = zocket.memory.deinitIfExists(&tmp_arena);
|
|
|
|
const tmp_allocator = tmp_arena.?.allocator();
|
|
|
|
var parser = try args.ArgumentParser.init(tmp_allocator, .{
|
|
.name = "zocket",
|
|
.version = options.version,
|
|
.description = "A lightweight Zig WebSocket server and mesh routing daemon.",
|
|
});
|
|
|
|
try parser.addOption("path", .{
|
|
.short = 'p',
|
|
.help = "Configuration-File Path (*.toml)",
|
|
});
|
|
|
|
var result = try parser.parseProcess(init);
|
|
|
|
const path = if (debug) path:
|
|
{
|
|
const tmp_path = result.getString("path") orelse "config/config.toml";
|
|
break :path try allocator.dupe(u8, tmp_path);
|
|
}
|
|
else path:
|
|
{
|
|
const tmp_path = result.getString("path") orelse blk: {
|
|
const exe = try std.process.executableDirPathAlloc(io, tmp_allocator);
|
|
break :blk try std.Io.Dir.path.join(tmp_allocator, &.{ exe, "config/config.toml" });
|
|
};
|
|
break :path try allocator.dupe(u8, tmp_path);
|
|
};
|
|
|
|
_ = zocket.memory.deinitIfExists(&tmp_arena);
|
|
|
|
try run(io, allocator, path);
|
|
}
|
|
|
|
/// Loads and parses the configuration file at `path`, then hands off to
|
|
/// the rest of the application.
|
|
///
|
|
/// Owns `path` and frees it once it's no longer needed; Callers must not free `path` themselves!
|
|
///
|
|
/// On parse failure, logs a human-readable reason and terminates the
|
|
/// process immediately via `std.process.exit`.
|
|
fn run(io: std.Io, allocator: std.mem.Allocator, path: []const u8) !void
|
|
{
|
|
const parsed = zocket.config.parse(io, allocator, path) catch |err|
|
|
{
|
|
const msg: []const u8 = switch (err) {
|
|
error.FileNotFound => "File not found",
|
|
error.AccessDenied => "Permission denied reading",
|
|
else => "Unexpected error opening",
|
|
};
|
|
std.log.err("{s}: '{s}' ({any})", .{ msg, path, err });
|
|
std.process.exit(1);
|
|
};
|
|
defer parsed.deinit();
|
|
allocator.free(path);
|
|
|
|
const configuration = parsed.value;
|
|
|
|
std.debug.print("{any}", .{configuration});
|
|
}
|