130 lines
4.7 KiB
Zig
130 lines
4.7 KiB
Zig
//! Configuration for the Libertaria Capsule Node.
|
|
|
|
const std = @import("std");
|
|
|
|
pub const NodeConfig = struct {
|
|
/// Data directory for persistent state (DB, keys, etc.)
|
|
data_dir: []const u8,
|
|
|
|
/// UTCP bind port (default: 8710)
|
|
port: u16 = 8710,
|
|
|
|
/// Control Socket Path (Unix Domain Socket)
|
|
control_socket_path: []const u8 = "",
|
|
|
|
/// Identity Key Path (Ed25519 private key)
|
|
identity_key_path: []const u8 = "",
|
|
|
|
/// Bootstrap peers (multiaddrs)
|
|
bootstrap_peers: [][]const u8 = &.{},
|
|
|
|
/// Logging level
|
|
log_level: std.log.Level = .info,
|
|
|
|
/// Enable Gateway Service (Layer 1 Coordination)
|
|
gateway_enabled: bool = false,
|
|
|
|
/// Enable Relay Service (Layer 2 Forwarding)
|
|
relay_enabled: bool = false,
|
|
|
|
/// Enable Bridge Service (Layer 3 Protocol Translation)
|
|
bridge_enabled: bool = false,
|
|
|
|
/// QVL minimum trust score for relay selection
|
|
relay_trust_threshold: f64 = 0.5,
|
|
|
|
/// Free allocated memory (strings, slices)
|
|
pub fn deinit(self: *NodeConfig, allocator: std.mem.Allocator) void {
|
|
allocator.free(self.data_dir);
|
|
allocator.free(self.control_socket_path);
|
|
allocator.free(self.identity_key_path);
|
|
for (self.bootstrap_peers) |peer| {
|
|
allocator.free(peer);
|
|
}
|
|
allocator.free(self.bootstrap_peers);
|
|
}
|
|
|
|
pub fn default(allocator: std.mem.Allocator) !NodeConfig {
|
|
// Default data dir: ~/.libertaria (or "data" for MVP)
|
|
return NodeConfig{
|
|
.data_dir = try allocator.dupe(u8, "data"),
|
|
.control_socket_path = try allocator.dupe(u8, "data/capsule.sock"),
|
|
.identity_key_path = try allocator.dupe(u8, "data/identity.key"),
|
|
.port = 8710,
|
|
.gateway_enabled = false,
|
|
.relay_enabled = false,
|
|
.bridge_enabled = false,
|
|
.relay_trust_threshold = 0.5,
|
|
};
|
|
}
|
|
|
|
/// Load configuration from a JSON file
|
|
pub fn loadFromJsonFile(allocator: std.mem.Allocator, path: []const u8) !NodeConfig {
|
|
const file = std.fs.cwd().openFile(path, .{}) catch |err| {
|
|
if (err == error.FileNotFound) {
|
|
// If config missing, create default
|
|
std.log.info("Config file not found at {s}, creating default...", .{path});
|
|
const cfg = try NodeConfig.default(allocator);
|
|
try cfg.saveToJsonFile(path);
|
|
return cfg;
|
|
}
|
|
return err;
|
|
};
|
|
defer file.close();
|
|
|
|
const max_size = 1024 * 1024; // 1MB config limit
|
|
const content = try file.readToEndAlloc(allocator, max_size);
|
|
defer allocator.free(content);
|
|
|
|
// Parse JSON
|
|
const parsed = try std.json.parseFromSlice(NodeConfig, allocator, content, .{
|
|
.allocate = .alloc_always,
|
|
});
|
|
defer parsed.deinit();
|
|
|
|
// Deep copy strings because parsed.value shares memory with arena/content in some modes,
|
|
// but here we used alloc_always so fields are allocated.
|
|
// However, std.json.parseFromSlice returns a Parsed(T) which manages the memory.
|
|
// We need to detach or copy the data to return a standalone NodeConfig.
|
|
// For simplicity and safety: manually duplicate into new struct.
|
|
|
|
const cfg = parsed.value;
|
|
const data_dir = try allocator.dupe(u8, cfg.data_dir);
|
|
const control_socket_path = if (cfg.control_socket_path.len > 0)
|
|
try allocator.dupe(u8, cfg.control_socket_path)
|
|
else
|
|
try std.fmt.allocPrint(allocator, "{s}/capsule.sock", .{data_dir});
|
|
|
|
const identity_key_path = if (cfg.identity_key_path.len > 0)
|
|
try allocator.dupe(u8, cfg.identity_key_path)
|
|
else
|
|
try std.fmt.allocPrint(allocator, "{s}/identity.key", .{data_dir});
|
|
|
|
var peers = std.array_list.Managed([]const u8).init(allocator);
|
|
for (cfg.bootstrap_peers) |peer| {
|
|
try peers.append(try allocator.dupe(u8, peer));
|
|
}
|
|
|
|
return NodeConfig{
|
|
.data_dir = data_dir,
|
|
.control_socket_path = control_socket_path,
|
|
.identity_key_path = identity_key_path,
|
|
.port = cfg.port,
|
|
.bootstrap_peers = try peers.toOwnedSlice(),
|
|
.log_level = cfg.log_level,
|
|
.gateway_enabled = cfg.gateway_enabled,
|
|
};
|
|
}
|
|
|
|
/// Save configuration to a JSON file
|
|
pub fn saveToJsonFile(self: *const NodeConfig, path: []const u8) !void {
|
|
const file = try std.fs.cwd().createFile(path, .{});
|
|
defer file.close();
|
|
|
|
var buf = std.array_list.Managed(u8).init(std.heap.page_allocator);
|
|
defer buf.deinit();
|
|
try buf.writer().print("{f}", .{std.json.fmt(self, .{ .whitespace = .indent_4 })});
|
|
try file.writeAll(buf.items);
|
|
}
|
|
};
|