const std = @import("std"); const Config = @import("Config.zig"); const Cache = @import("cache/Cache.zig"); const MetNo = @import("weather/MetNo.zig"); const Server = @import("http/Server.zig"); const RateLimiter = @import("http/RateLimiter.zig"); const GeoIp = @import("location/GeoIp.zig"); const GeoCache = @import("location/GeoCache.zig"); const Airports = @import("location/Airports.zig"); const Resolver = @import("location/resolver.zig").Resolver; const GeoLite2 = @import("location/GeoLite2.zig"); const version = @import("build_options").version; pub fn main() !u8 { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); const allocator = gpa.allocator(); const cfg = try Config.load(allocator); defer cfg.deinit(allocator); std.log.info("wttr version {s} starting on {s}:{d}", .{ version, cfg.listen_host, cfg.listen_port }); std.log.info("Cache size: {d}", .{cfg.cache_size}); std.log.info("Cache dir: {s}", .{cfg.cache_dir}); std.log.info("GeoLite2 path: {s}", .{cfg.geolite_path}); if (cfg.geocache_file) |f| { std.log.info("Geocache file: {s}", .{f}); } else { std.log.info("Geocache: in-memory only", .{}); } var metno = MetNo.init(allocator, null) catch |err| { if (err == MetNo.MissingIdentificationError) return 1; return err; }; defer metno.deinit(); // Ensure GeoLite2 database exists try GeoLite2.ensureDatabase(allocator, cfg.geolite_path); // Initialize GeoIP database with optional IP2Location fallback var geoip = GeoIp.init( allocator, cfg.geolite_path, cfg.ip2location_api_key, if (cfg.ip2location_api_key != null) cfg.ip2location_cache_file else null, ) catch |err| { std.log.err("Failed to load GeoIP database from {s}: {}", .{ cfg.geolite_path, err }); return err; }; defer geoip.deinit(); // Initialize geocoding cache var geocache = try GeoCache.init(allocator, cfg.geocache_file); defer geocache.deinit(); // Initialize airports database var airports_db = try Airports.init(allocator); defer airports_db.deinit(); // Initialize location resolver var resolver = Resolver.init(allocator, &geoip, &geocache, &airports_db); const cache = try Cache.init(allocator, .{ .max_entries = cfg.cache_size, .cache_dir = cfg.cache_dir, }); defer cache.deinit(); var rate_limiter = try RateLimiter.init(allocator, .{ .capacity = 300, .refill_rate = 5, .refill_interval_ms = 200, }); defer rate_limiter.deinit(); var server = try Server.init(allocator, cfg.listen_host, cfg.listen_port, .{ .provider = metno.provider(cache), .resolver = &resolver, .geoip = &geoip, }, &rate_limiter); try server.listen(); return 0; } test { std.testing.refAllDecls(@This()); _ = @import("Config.zig"); _ = @import("cache/Lru.zig"); _ = @import("weather/Mock.zig"); _ = @import("http/RateLimiter.zig"); _ = @import("http/query.zig"); _ = @import("http/help.zig"); _ = @import("render/line.zig"); _ = @import("render/json.zig"); _ = @import("render/v2.zig"); _ = @import("render/custom.zig"); _ = @import("location/GeoIp.zig"); _ = @import("location/GeoCache.zig"); _ = @import("location/Airports.zig"); _ = @import("location/resolver.zig"); }