From 932f22b1483033d20737ad9e345b20f9cb461afa Mon Sep 17 00:00:00 2001 From: Nic-dorman Date: Tue, 5 May 2026 10:58:11 +0100 Subject: [PATCH] feat(antd-zig): expose new HealthStatus diagnostic fields Mirrors antd-go v0.5.0 / antd-py: HealthStatus now carries version, evm_network, uptime_seconds, build_commit, payment_token_address, and payment_vault_address. All have struct-level default values ("" / 0) so existing two-field constructions keep compiling and pre-0.4.0 daemon responses parse cleanly. parseHealthStatus duplicates each new string field via dupeString (yielding allocator-owned 0-length slices when missing) and reads uptime_seconds via jsonInt. HealthStatus.deinit frees each duped string; freeing the static "" defaults from manual construction is a no-op on the standard zig allocators. antd-zig is REST-only (no gRPC client). No proto regen step needed. src/tests.zig: existing parseHealthStatus tests assert the empty- defaults path; new test exercises the 0.4.0 shape with all 6 fields. zig test src/tests.zig --test-filter HealthStatus: 4 pass. Part of #37. Co-Authored-By: Claude Opus 4.7 (1M context) --- antd-zig/src/json_helpers.zig | 37 ++++++++++++++++++++++++++++++++++- antd-zig/src/models.zig | 16 +++++++++++++++ antd-zig/src/tests.zig | 21 ++++++++++++++++++++ 3 files changed, 73 insertions(+), 1 deletion(-) diff --git a/antd-zig/src/json_helpers.zig b/antd-zig/src/json_helpers.zig index 9a2668a..1f91292 100644 --- a/antd-zig/src/json_helpers.zig +++ b/antd-zig/src/json_helpers.zig @@ -39,8 +39,43 @@ pub fn parseHealthStatus(allocator: Allocator, body: []const u8) !models.HealthS const network = dupeString(allocator, obj.get("network") orelse .null) catch return error.JsonError; + errdefer allocator.free(network); - return .{ .ok = ok, .network = network }; + const version = dupeString(allocator, obj.get("version") orelse .null) catch + return error.JsonError; + errdefer allocator.free(version); + + const evm_network = dupeString(allocator, obj.get("evm_network") orelse .null) catch + return error.JsonError; + errdefer allocator.free(evm_network); + + const uptime_seconds: u64 = blk: { + const v = obj.get("uptime_seconds") orelse break :blk 0; + const n = jsonInt(v); + break :blk if (n < 0) 0 else @intCast(n); + }; + + const build_commit = dupeString(allocator, obj.get("build_commit") orelse .null) catch + return error.JsonError; + errdefer allocator.free(build_commit); + + const payment_token_address = dupeString(allocator, obj.get("payment_token_address") orelse .null) catch + return error.JsonError; + errdefer allocator.free(payment_token_address); + + const payment_vault_address = dupeString(allocator, obj.get("payment_vault_address") orelse .null) catch + return error.JsonError; + + return .{ + .ok = ok, + .network = network, + .version = version, + .evm_network = evm_network, + .uptime_seconds = uptime_seconds, + .build_commit = build_commit, + .payment_token_address = payment_token_address, + .payment_vault_address = payment_vault_address, + }; } /// Parse a PutResult from a JSON response body. The address_key parameter diff --git a/antd-zig/src/models.zig b/antd-zig/src/models.zig index 0d129ce..c72fa75 100644 --- a/antd-zig/src/models.zig +++ b/antd-zig/src/models.zig @@ -2,12 +2,28 @@ const std = @import("std"); const Allocator = std.mem.Allocator; /// Result of a health check against the antd daemon. +/// +/// The diagnostic fields (version, evm_network, uptime_seconds, build_commit, +/// payment_token_address, payment_vault_address) were added in antd 0.4.0. +/// They default to empty / 0 so the struct stays usable when talking to a +/// pre-0.4.0 daemon that doesn't report them. pub const HealthStatus = struct { ok: bool, network: []const u8, + version: []const u8 = "", + evm_network: []const u8 = "", + uptime_seconds: u64 = 0, + build_commit: []const u8 = "", + payment_token_address: []const u8 = "", + payment_vault_address: []const u8 = "", pub fn deinit(self: HealthStatus, allocator: Allocator) void { allocator.free(self.network); + allocator.free(self.version); + allocator.free(self.evm_network); + allocator.free(self.build_commit); + allocator.free(self.payment_token_address); + allocator.free(self.payment_vault_address); } }; diff --git a/antd-zig/src/tests.zig b/antd-zig/src/tests.zig index ed2bf02..5f9b54a 100644 --- a/antd-zig/src/tests.zig +++ b/antd-zig/src/tests.zig @@ -53,6 +53,27 @@ test "parseHealthStatus parses ok status" { try testing.expect(result.ok); try testing.expectEqualStrings("local", result.network); + // Pre-0.4.0 daemon shape: diagnostic fields default to empty / 0. + try testing.expectEqualStrings("", result.version); + try testing.expectEqualStrings("", result.evm_network); + try testing.expect(result.uptime_seconds == 0); +} + +test "parseHealthStatus parses 0.4.0 diagnostic fields" { + const body = + \\{"status":"ok","network":"local","version":"0.4.0","evm_network":"local","uptime_seconds":42,"build_commit":"abcdef123456","payment_token_address":"0xtoken","payment_vault_address":"0xvault"} + ; + const result = try json_helpers.parseHealthStatus(testing.allocator, body); + defer result.deinit(testing.allocator); + + try testing.expect(result.ok); + try testing.expectEqualStrings("local", result.network); + try testing.expectEqualStrings("0.4.0", result.version); + try testing.expectEqualStrings("local", result.evm_network); + try testing.expect(result.uptime_seconds == 42); + try testing.expectEqualStrings("abcdef123456", result.build_commit); + try testing.expectEqualStrings("0xtoken", result.payment_token_address); + try testing.expectEqualStrings("0xvault", result.payment_vault_address); } test "parseHealthStatus parses non-ok status" {