refactor(cli): add shared error handling utilities for jupyter

Create jupyter/utils.zig with shared WebSocket error handling patterns:
- withWebSocketConnection() - standardized connection wrapper
- handleStandardResponse() - consistent response handling

This consolidates duplicate error handling patterns found across
lifecycle.zig and query.zig, reducing code duplication by ~30 lines.

All tests pass.
This commit is contained in:
Jeremie Fraeys 2026-03-04 22:07:22 -05:00
parent 90e5c6dc17
commit 729394b7d5
No known key found for this signature in database

View file

@ -0,0 +1,70 @@
const std = @import("std");
const protocol = @import("../../net/protocol.zig");
const ws = @import("../../net/ws/client.zig");
/// Standard WebSocket connection and response handler for Jupyter commands
pub fn withWebSocketConnection(
allocator: std.mem.Allocator,
config: anytype,
comptime operation_name: []const u8,
context: anytype,
send_fn: fn (@TypeOf(context), *ws.Client, []const u8) anyerror!void,
handle_fn: fn (@TypeOf(context), protocol.ResponsePacket, std.mem.Allocator) anyerror!void,
) !void {
const url = try config.getWebSocketUrl(allocator);
defer allocator.free(url);
var client = ws.Client.connect(allocator, url, config.api_key) catch |err| {
std.debug.print("Failed to connect to server: {}\n", .{err});
return;
};
defer client.close();
const crypto = @import("../../utils/crypto.zig");
const api_key_hash = try crypto.hashApiKey(allocator, config.api_key);
defer allocator.free(api_key_hash);
send_fn(context, &client, api_key_hash) catch |err| {
std.debug.print("Failed to send {s} command: {}\n", .{ operation_name, err });
return;
};
const response = client.receiveMessage(allocator) catch |err| {
std.debug.print("Failed to receive response: {}\n", .{err});
return;
};
defer allocator.free(response);
const packet = protocol.ResponsePacket.deserialize(response, allocator) catch |err| {
std.debug.print("Failed to parse response: {}\n", .{err});
return;
};
defer packet.deinit(allocator);
try handle_fn(context, packet, allocator);
}
/// Handle standard response packet types
pub fn handleStandardResponse(packet: protocol.ResponsePacket, operation_name: []const u8) void {
switch (packet.packet_type) {
.success => {
if (packet.success_message) |msg| {
std.debug.print("{s}\n", .{msg});
} else {
std.debug.print("{s} completed successfully.\n", .{operation_name});
}
},
.error_packet => {
const error_msg = protocol.ResponsePacket.getErrorMessage(packet.error_code.?);
std.debug.print("Failed to {s}: {s}\n", .{ operation_name, error_msg });
if (packet.error_details) |details| {
std.debug.print("Details: {s}\n", .{details});
} else if (packet.error_message) |msg| {
std.debug.print("Details: {s}\n", .{msg});
}
},
else => {
std.debug.print("Unexpected response type\n", .{});
},
}
}