wttr/src/main.zig

116 lines
3.8 KiB
Zig

const std = @import("std");
const config = @import("config.zig");
const Cache = @import("cache/Cache.zig");
const MetNo = @import("weather/MetNo.zig");
const types = @import("weather/types.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 geolite_downloader = @import("location/geolite_downloader.zig");
pub const std_options: std.Options = .{
.log_level = .info,
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var stdout_buffer: [4096]u8 = undefined;
var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
const stdout = &stdout_writer.interface;
const cfg = try config.Config.load(allocator);
defer cfg.deinit(allocator);
try stdout.print("wttr starting on {s}:{d}\n", .{ cfg.listen_host, cfg.listen_port });
try stdout.print("Cache size: {d}\n", .{cfg.cache_size});
try stdout.print("Cache dir: {s}\n", .{cfg.cache_dir});
try stdout.print("GeoLite2 path: {s}\n", .{cfg.geolite_path});
if (cfg.geocache_file) |f| {
try stdout.print("Geocache file: {s}\n", .{f});
} else {
try stdout.print("Geocache: in-memory only\n", .{});
}
if (cfg.airports_dat_path) |f| {
try stdout.print("Airports database: {s}\n", .{f});
}
try stdout.flush();
// Ensure GeoLite2 database exists
try geolite_downloader.ensureDatabase(allocator, cfg.geolite_path);
// Initialize GeoIP database
var geoip = GeoIP.init(cfg.geolite_path) catch |err| {
std.log.warn("Failed to load GeoIP database: {}", .{err});
std.log.warn("IP-based location resolution will be unavailable", .{});
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: ?Airports = null;
if (cfg.airports_dat_path) |path| {
airports_db = Airports.initFromFile(allocator, path) catch |err| blk: {
std.log.warn("Failed to load airports database: {}", .{err});
break :blk null;
};
}
if (airports_db) |*db| {
defer db.deinit();
}
// Initialize location resolver
var resolver = Resolver.init(allocator, &geoip, &geocache, if (airports_db) |*db| db else null);
var 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 metno = try MetNo.init(allocator);
defer metno.deinit();
var server = try Server.init(allocator, cfg.listen_host, cfg.listen_port, .{
.cache = &cache,
.provider = metno.provider(),
.resolver = &resolver,
.geoip = &geoip,
}, &rate_limiter);
try server.listen();
}
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");
}