const std = @import("std"); const Config = @import("../config.zig").Config; const ws = @import("../net/ws.zig"); const crypto = @import("../utils/crypto.zig"); const errors = @import("../errors.zig"); const logging = @import("../utils/logging.zig"); const UserContext = struct { name: []const u8, admin: bool, allocator: std.mem.Allocator, pub fn deinit(self: *UserContext) void { self.allocator.free(self.name); } }; fn authenticateUser(allocator: std.mem.Allocator, config: Config) !UserContext { // Validate API key by making a simple API call to the server const ws_url = try std.fmt.allocPrint(allocator, "ws://{s}:9101/ws", .{config.worker_host}); defer allocator.free(ws_url); // Try to connect with the API key to validate it var client = ws.Client.connect(allocator, ws_url, config.api_key) catch |err| { switch (err) { error.ConnectionRefused => return error.ConnectionFailed, error.NetworkUnreachable => return error.ServerUnreachable, error.InvalidURL => return error.ConfigInvalid, else => return error.AuthenticationFailed, } }; defer client.close(); // For now, create a user context after successful authentication // In a real implementation, this would get user info from the server const user_name = try allocator.dupe(u8, "authenticated_user"); return UserContext{ .name = user_name, .admin = false, .allocator = allocator, }; } pub fn run(allocator: std.mem.Allocator, args: []const []const u8) !void { _ = args; // Load configuration with proper error handling const config = Config.load(allocator) catch |err| { switch (err) { error.FileNotFound => return error.ConfigNotFound, else => return err, } }; defer { var mut_config = config; mut_config.deinit(allocator); } // Check if API key is configured if (config.api_key.len == 0) { return error.APIKeyMissing; } // Authenticate with server to get user context var user_context = try authenticateUser(allocator, config); defer user_context.deinit(); // Use plain password for WebSocket authentication, compute hash for binary protocol const api_key_plain = config.api_key; // Plain password from config const api_key_hash = try crypto.hashString(allocator, api_key_plain); defer allocator.free(api_key_hash); // Connect to WebSocket and request status const ws_url = std.fmt.allocPrint(allocator, "ws://{s}:9101/ws", .{config.worker_host}) catch |err| { return err; }; defer allocator.free(ws_url); var client = ws.Client.connect(allocator, ws_url, api_key_plain) catch |err| { switch (err) { error.ConnectionRefused => return error.ConnectionFailed, error.NetworkUnreachable => return error.ServerUnreachable, error.InvalidURL => return error.ConfigInvalid, else => return err, } }; defer client.close(); client.sendStatusRequest(api_key_hash) catch { return error.RequestFailed; }; // Receive and display user-filtered response try client.receiveAndHandleStatusResponse(allocator, user_context); }