diff --git a/src/error.zig b/src/error.zig index 1290900..2ad8c58 100644 --- a/src/error.zig +++ b/src/error.zig @@ -12,7 +12,7 @@ pub const ErrorInfo = struct { }; pub fn getLastError() ErrorInfo { - const status: c_uint = 0; + var status: c_uint = 0; const desc = nats_c.nats_GetLastError(&status); return .{ @@ -21,8 +21,8 @@ pub fn getLastError() ErrorInfo { }; } -pub fn getLastErrorStack(buffer: []u8) Error!void { - const status = Status.fromInt(nats_c.getLastErrorStack(buffer.ptr, buffer.len)); +pub fn getLastErrorStack(buffer: *[]u8) Error!void { + const status = Status.fromInt(nats_c.nats_GetLastErrorStack(buffer.ptr, buffer.len)); return status.raise(); } diff --git a/src/nats.zig b/src/nats.zig index bf494c9..aefd67d 100644 --- a/src/nats.zig +++ b/src/nats.zig @@ -35,6 +35,9 @@ pub const Message = msg_.Message; pub const Statistics = sta_.Statistics; pub const StatsCounts = sta_.StatsCounts; +pub const ErrorInfo = err_.ErrorInfo; +pub const getLastError = err_.getLastError; +pub const getLastErrorStack = err_.getLastErrorStack; pub const Status = err_.Status; pub const Error = err_.Error; @@ -59,7 +62,7 @@ pub fn now() i64 { return nats_c.nats_Now(); } -pub fn nowInNanoSeconds() i64 { +pub fn nowInNanoseconds() i64 { return nats_c.nats_NowInNanoSeconds(); } @@ -76,6 +79,8 @@ pub fn releaseThreadMemory() void { return nats_c.nats_ReleaseThreadMemory(); } +pub const default_spin_count: i64 = -1; + pub fn init(lock_spin_count: i64) Error!void { const status = Status.fromInt(nats_c.nats_Open(lock_spin_count)); return status.raise(); @@ -85,37 +90,41 @@ pub fn deinit() void { return nats_c.nats_Close(); } -// the result of this requires manual deallocation unless it is used to provide the -// signature out-parameter in the natsSignatureHandler callback. Calling it outside of -// that context seems unlikely, but we should probably provide a deinit function so the -// user doesn't have to dig around for libc free to deallocate it. -pub fn sign(encoded_seed: [:0]const u8, input: [:0]const u8) Error![]const u8 { - var result: [*]u8 = undefined; - var length: c_int = 0; - const status = Status.fromInt(nats_c.nats_Sign(encoded_seed.ptr, &input, &length)); - - return status.toError() orelse result[0..@intCast(length)]; -} - pub fn deinitWait(timeout: i64) Error!void { const status = Status.fromInt(nats_c.nats_CloseAndWait(timeout)); return status.raise(); } -// This appears to be a jetstream API, but these two endpoints are trivial, so, whoops. -// I have no clue what this does, since there's basically no -pub const Inbox = opaque { - pub fn create() Error!*Inbox { - var self: *Inbox = undefined; - const status = Status.fromInt(nats_c.natsInbox_Create(@ptrCast(&self))); +// the result of this requires manual deallocation unless it is used to provide the +// signature out-parameter in the natsSignatureHandler callback. Calling it outside of +// that context seems unlikely, but we should probably provide a deinit function so the +// user doesn't have to dig around for libc free to deallocate it. +pub fn sign(encoded_seed: [:0]const u8, input: [:0]const u8) Error![]const u8 { + var result: [*c]u8 = undefined; + var length: c_int = 0; + const status = Status.fromInt(nats_c.nats_Sign( + encoded_seed.ptr, + input.ptr, + &result, + &length, + )); - return status.toError() orelse self; - } + return status.toError() orelse result[0..@intCast(length)]; +} - pub fn destroy(self: *Inbox) void { - nats_c.natsInbox_Destroy(@ptrCast(self)); - } -}; +// Note: an "Inbox" is actually just a string. This API creates a random (unique) +// string suitable for passing as the `reply` field to Message.create or +// Connection.publishRequest. +pub fn createInbox() Error![:0]u8 { + var self: [*c]u8 = undefined; + const status = Status.fromInt(nats_c.natsInbox_Create(@ptrCast(&self))); + + return status.toError() orelse std.mem.sliceTo(self, 0); +} + +pub fn destroyInbox(inbox: [:0]const u8) void { + nats_c.natsInbox_Destroy(@constCast(@ptrCast(inbox.ptr))); +} // I think this is also a jetstream API. This function sure does not seem at all useful // by itself. diff --git a/tests/main.zig b/tests/main.zig index 3cf1919..bdcd393 100644 --- a/tests/main.zig +++ b/tests/main.zig @@ -1,5 +1,4 @@ -const std = @import("std"); - test { + _ = @import("./nats.zig"); _ = @import("./message.zig"); } diff --git a/tests/nats.zig b/tests/nats.zig new file mode 100644 index 0000000..2455116 --- /dev/null +++ b/tests/nats.zig @@ -0,0 +1,96 @@ +const std = @import("std"); + +const nats = @import("nats"); + +test "version" { + const version = nats.getVersion(); + const vernum = nats.getVersionNumber(); + + try std.testing.expectEqualStrings("3.6.1", version); + try std.testing.expectEqual(@as(u32, 0x03_06_01), vernum); + try std.testing.expect(nats.checkCompatibility()); +} + +test "time" { + const now = nats.now(); + const nownano = nats.nowInNanoseconds(); + + nats.sleep(1); + + const later = nats.now(); + const laternano = nats.nowInNanoseconds(); + + try std.testing.expect(later >= now); + try std.testing.expect(laternano >= nownano); +} + +test "init" { + { + try nats.init(nats.default_spin_count); + defer nats.deinit(); + } + + { + // a completely random number + try nats.init(900_142_069); + nats.deinit(); + } + + { + try nats.init(0); + try nats.deinitWait(1000); + } +} + +test "misc" { + { + try nats.init(nats.default_spin_count); + defer nats.deinit(); + + try nats.setMessageDeliveryPoolSize(500); + } + + { + try nats.init(nats.default_spin_count); + defer nats.deinit(); + + // just test that the function is wrapped properly + nats.releaseThreadMemory(); + } + + blk: { + try nats.init(nats.default_spin_count); + defer nats.deinit(); + + // this is a mess of a test that is designed to fail because actually we're + // testing out the error reporting functions instead of signing. Nice bait + // and switch. + const signed = nats.sign("12345678", "12345678") catch { + const err = nats.getLastError(); + std.debug.print("signing failed: {s}\n", .{err.desc}); + + var stackmem = [_]u8{0} ** 512; + var stackbuf: []u8 = &stackmem; + + nats.getLastErrorStack(&stackbuf) catch { + std.debug.print("Actually, the error stack was too big\n", .{}); + break :blk; + }; + + std.debug.print("stack: {s}\n", .{stackbuf}); + break :blk; + }; + + std.heap.raw_c_allocator.free(signed); + } +} + +test "inbox" { + try nats.init(nats.default_spin_count); + defer nats.deinit(); + + const inbox = try nats.createInbox(); + defer nats.destroyInbox(inbox); + + std.debug.print("inbox: {s}\n", .{inbox}); +}