const std = @import("std"); pub const Config = struct { listen_host: []const u8, listen_port: u16, cache_size: usize, cache_dir: []const u8, geolite_path: []const u8, geocache_file: ?[]const u8, pub fn load(allocator: std.mem.Allocator) !Config { var env = try std.process.getEnvMap(allocator); defer env.deinit(); return Config{ .listen_host = env.get("WTTR_LISTEN_HOST") orelse try allocator.dupe(u8, "0.0.0.0"), .listen_port = if (env.get("WTTR_LISTEN_PORT")) |p| try std.fmt.parseInt(u16, p, 10) else 8002, .cache_size = if (env.get("WTTR_CACHE_SIZE")) |s| try std.fmt.parseInt(usize, s, 10) else 10_000, .cache_dir = try allocator.dupe(u8, env.get("WTTR_CACHE_DIR") orelse "/tmp/wttr-cache"), .geolite_path = try allocator.dupe(u8, env.get("WTTR_GEOLITE_PATH") orelse "./GeoLite2-City.mmdb"), .geocache_file = if (env.get("WTTR_GEOCACHE_FILE")) |v| try allocator.dupe(u8, v) else null, }; } pub fn deinit(self: Config, allocator: std.mem.Allocator) void { allocator.free(self.listen_host); allocator.free(self.cache_dir); allocator.free(self.geolite_path); if (self.geocache_file) |f| allocator.free(f); } }; test "config loads defaults" { const allocator = std.testing.allocator; const cfg = try Config.load(allocator); defer cfg.deinit(allocator); try std.testing.expectEqualStrings("0.0.0.0", cfg.listen_host); try std.testing.expectEqual(@as(u16, 8002), cfg.listen_port); try std.testing.expectEqual(@as(usize, 10_000), cfg.cache_size); try std.testing.expectEqualStrings("./GeoLite2-City.mmdb", cfg.geolite_path); try std.testing.expect(cfg.geocache_file == null); }