//! Configuration management - loads from .env file and environment variables. //! Environment variables take precedence over .env file values. const std = @import("std"); const Config = @This(); allocator: std.mem.Allocator, cognito_username: ?[]const u8, cognito_password: ?[]const u8, home_assistant_url: ?[]const u8, home_assistant_token: ?[]const u8, is_lambda: bool, pub fn init(allocator: std.mem.Allocator) !Config { var self = Config{ .allocator = allocator, .cognito_username = null, .cognito_password = null, .home_assistant_url = null, .home_assistant_token = null, .is_lambda = false, }; // Load .env file first (if present) try self.loadEnvFile(); // Environment variables override .env var env_map = try std.process.getEnvMap(allocator); defer env_map.deinit(); if (env_map.get("COGNITO_USERNAME")) |v| { if (self.cognito_username) |old| allocator.free(old); self.cognito_username = try allocator.dupe(u8, v); } if (env_map.get("COGNITO_PASSWORD")) |v| { if (self.cognito_password) |old| allocator.free(old); self.cognito_password = try allocator.dupe(u8, v); } if (env_map.get("HOME_ASSISTANT_URL")) |v| { if (self.home_assistant_url) |old| allocator.free(old); self.home_assistant_url = try allocator.dupe(u8, v); } if (env_map.get("HOME_ASSISTANT_TOKEN")) |v| { if (self.home_assistant_token) |old| allocator.free(old); self.home_assistant_token = try allocator.dupe(u8, v); } // Detect Lambda environment self.is_lambda = env_map.get("AWS_LAMBDA_RUNTIME_API") != null; return self; } pub fn deinit(self: *Config) void { if (self.cognito_username) |v| self.allocator.free(v); if (self.cognito_password) |v| self.allocator.free(v); if (self.home_assistant_url) |v| self.allocator.free(v); if (self.home_assistant_token) |v| self.allocator.free(v); self.cognito_username = null; self.cognito_password = null; self.home_assistant_url = null; self.home_assistant_token = null; } fn loadEnvFile(self: *Config) !void { const file = std.fs.cwd().openFile(".env", .{}) catch return; defer file.close(); const content = try file.readToEndAlloc(self.allocator, 1024 * 1024); defer self.allocator.free(content); var lines = std.mem.tokenizeScalar(u8, content, '\n'); while (lines.next()) |line| { const trimmed = std.mem.trim(u8, line, " \t\r"); if (trimmed.len == 0 or trimmed[0] == '#') continue; if (std.mem.indexOf(u8, trimmed, "=")) |eq_idx| { const key = trimmed[0..eq_idx]; const val = trimmed[eq_idx + 1 ..]; if (std.mem.eql(u8, key, "COGNITO_USERNAME")) { self.cognito_username = try self.allocator.dupe(u8, val); } else if (std.mem.eql(u8, key, "COGNITO_PASSWORD")) { self.cognito_password = try self.allocator.dupe(u8, val); } else if (std.mem.eql(u8, key, "HOME_ASSISTANT_URL")) { self.home_assistant_url = try self.allocator.dupe(u8, val); } else if (std.mem.eql(u8, key, "HOME_ASSISTANT_TOKEN")) { self.home_assistant_token = try self.allocator.dupe(u8, val); } } } }