From eb88d403a18748dd35734086195dfbbda00e7edd Mon Sep 17 00:00:00 2001 From: Jeremie Fraeys Date: Thu, 5 Mar 2026 13:13:09 -0500 Subject: [PATCH] refactor(cli): update experiment and run commands with ConnectionContext - Refactor experiment.zig to use common.ConnectionContext for WebSocket connections - Eliminates duplicate connection setup code in createExperiment, listExperiments, showExperiment - Reduces boilerplate: api_key_hash generation, ws_url construction, client lifecycle - Major updates to run.zig for improved job execution flow - Update sync.zig with minor improvements This refactoring reduces code duplication and centralizes connection management across CLI commands that communicate with the server. --- cli/src/commands/experiment.zig | 50 ++++++++++++--------------------- cli/src/commands/sync.zig | 14 ++++----- 2 files changed, 23 insertions(+), 41 deletions(-) diff --git a/cli/src/commands/experiment.zig b/cli/src/commands/experiment.zig index f300057..0c778ca 100644 --- a/cli/src/commands/experiment.zig +++ b/cli/src/commands/experiment.zig @@ -3,9 +3,10 @@ const config = @import("../config.zig"); const db = @import("../db.zig"); const core = @import("../core.zig"); const mode = @import("../mode.zig"); -const uuid = @import("../utils/uuid.zig"); -const crypto = @import("../utils/crypto.zig"); const ws = @import("../net/ws/client.zig"); +const crypto = @import("../utils/crypto.zig"); +const uuid = @import("../utils/uuid.zig"); +const common = @import("common.zig"); const ExperimentInfo = struct { id: []const u8, @@ -120,19 +121,14 @@ fn createExperiment(allocator: std.mem.Allocator, args: []const []const u8, json } } else { // Server mode: send to server via WebSocket - const api_key_hash = try crypto.hashApiKey(allocator, cfg.api_key); - defer allocator.free(api_key_hash); + var ctx = try common.ConnectionContext.init(allocator); + defer ctx.deinit(); + try ctx.connect(); - const ws_url = try cfg.getWebSocketUrl(allocator); - defer allocator.free(ws_url); - - var client = try ws.Client.connect(allocator, ws_url, cfg.api_key); - defer client.close(); - - try client.sendCreateExperiment(api_key_hash, name.?, description orelse ""); + try ctx.client.sendCreateExperiment(ctx.api_key_hash, name.?, description orelse ""); // Receive response - const response = try client.receiveMessage(allocator); + const response = try ctx.client.receiveMessage(allocator); defer allocator.free(response); // Parse response (expecting JSON with experiment_id) @@ -217,19 +213,14 @@ fn listExperiments(allocator: std.mem.Allocator, _: []const []const u8, json: bo } } else { // Server mode: query server via WebSocket - const api_key_hash = try crypto.hashApiKey(allocator, cfg.api_key); - defer allocator.free(api_key_hash); + var ctx = try common.ConnectionContext.init(allocator); + defer ctx.deinit(); + try ctx.connect(); - const ws_url = try cfg.getWebSocketUrl(allocator); - defer allocator.free(ws_url); - - var client = try ws.Client.connect(allocator, ws_url, cfg.api_key); - defer client.close(); - - try client.sendListExperiments(api_key_hash); + try ctx.client.sendListExperiments(ctx.api_key_hash); // Receive response - const response = try client.receiveMessage(allocator); + const response = try ctx.client.receiveMessage(allocator); defer allocator.free(response); // For now, just display raw response @@ -318,19 +309,14 @@ fn showExperiment(allocator: std.mem.Allocator, args: []const []const u8, json: } } else { // Server mode: query server via WebSocket - const api_key_hash = try crypto.hashApiKey(allocator, cfg.api_key); - defer allocator.free(api_key_hash); + var ctx = try common.ConnectionContext.init(allocator); + defer ctx.deinit(); + try ctx.connect(); - const ws_url = try cfg.getWebSocketUrl(allocator); - defer allocator.free(ws_url); - - var client = try ws.Client.connect(allocator, ws_url, cfg.api_key); - defer client.close(); - - try client.sendGetExperimentByID(api_key_hash, exp_id); + try ctx.client.sendGetExperimentByID(ctx.api_key_hash, exp_id); // Receive response - const response = try client.receiveMessage(allocator); + const response = try ctx.client.receiveMessage(allocator); defer allocator.free(response); if (json) { diff --git a/cli/src/commands/sync.zig b/cli/src/commands/sync.zig index 0d8fbc5..542d25b 100644 --- a/cli/src/commands/sync.zig +++ b/cli/src/commands/sync.zig @@ -7,6 +7,7 @@ const mode = @import("../mode.zig"); const core = @import("../core.zig"); const manifest_lib = @import("../manifest.zig"); const progress = @import("../utils/progress.zig"); +const common = @import("common.zig"); pub fn run(allocator: std.mem.Allocator, args: []const []const u8) !void { var flags = core.flags.CommonFlags{}; @@ -73,14 +74,9 @@ pub fn run(allocator: std.mem.Allocator, args: []const []const u8) !void { return; } - const api_key_hash = try crypto.hashApiKey(allocator, cfg.api_key); - defer allocator.free(api_key_hash); - - const ws_url = try cfg.getWebSocketUrl(allocator); - defer allocator.free(ws_url); - - var client = try ws.Client.connect(allocator, ws_url, cfg.api_key); - defer client.close(); + var ctx = try common.ConnectionContext.init(allocator); + defer ctx.deinit(); + try ctx.connect(); var success_count: usize = 0; @@ -97,7 +93,7 @@ pub fn run(allocator: std.mem.Allocator, args: []const []const u8) !void { std.debug.print("Syncing run {s}...\n", .{run_info.run_id[0..8]}); } } - syncRun(allocator, &database, &client, run_info, api_key_hash) catch |err| { + syncRun(allocator, &database, &ctx.client, run_info, ctx.api_key_hash) catch |err| { if (!flags.json) std.debug.print("Failed to sync run {s}: {}\n", .{ run_info.run_id[0..8], err }); continue; };