Zig Requires Chilkat v11.5.0+
Zig
Box: Poll User Events and Save a Checkpoint
See more Box Examples
Poll the authenticated user event stream in bounded batches. The local JSON checkpoint keeps processed event IDs and the next stream position. This single-process demonstration logs events; a production worker should commit its business action, deduplication record, and cursor transactionally and prune old IDs.
See the Box API guide for setup and the complete workflow.
Chilkat Zig Downloads
const std = @import("std");
const chilkat = @import("chilkat");
pub fn main(init: std.process.Init) !void {
const alloc = init.arena.allocator();
var success: bool = false;
// Requires Chilkat 11.5.0 or later and a previously unlocked Chilkat bundle.
// See Global Unlock Sample.
// Guide: Box API Guide.
success = false;
// Supply an unexpired token obtained with one of the Box authentication examples.
// A token represents a particular user or service account. IDs must be accessible to it.
const curl = try chilkat.HttpCurl.init();
defer curl.deinit();
curl.setVar("access_token", "BOX_ACCESS_TOKEN");
const state = try chilkat.JsonObject.init();
defer state.deinit();
const files = try chilkat.FileAccess.init();
defer files.deinit();
const state_path = "qa_data/box_events_state.json";
if (files.fileExists(state_path)) {
success = if (state.loadFile(state_path)) true else |_| false;
if (!success) {
std.debug.print("{s}\n", .{try state.getLastErrorText(alloc)});
return;
}
if (!state.hasMember("position")) {
std.debug.print("Invalid checkpoint: position missing.\n", .{});
return;
}
} else {
// "now" starts a new subscription. It deliberately skips historical events.
state.updateString("position", "now") catch {};
}
curl.setVar("position", try state.stringOf(alloc, "position"));
const page = try chilkat.JsonObject.init();
defer page.deinit();
const seen_path = try chilkat.StringBuilder.init();
defer seen_path.deinit();
var event_id: [:0]const u8 = "";
var next_position: [:0]const u8 = "";
var batch: i32 = 0;
var i: i32 = 0;
var count: i32 = 0;
var more: bool = true;
while ((more) and (batch < 20)) {
curl.clearTargetOutput("*");
const authorized_command1 = try chilkat.StringBuilder.init();
defer authorized_command1.deinit();
authorized_command1.setString("curl -X GET \"https://api.box.com/2.0/events?stream_type=all&stream_position={{position}}&limit=100\" -H \"Authorization: Bearer {{access_token}}\"") catch {};
_ = authorized_command1.replace("{{access_token}}", try curl.getVar(alloc, "access_token"));
success = if (curl.doYourThing(try authorized_command1.getAsString(alloc))) true else |_| false;
if ((!success) or (curl.getStatusCode() != 200)) {
std.debug.print("Box request failed. HTTP status: {d}\n", .{curl.getStatusCode()});
std.debug.print("Failure reason: {d}\n", .{curl.getFailReason()});
std.debug.print("{s}\n", .{try curl.getResponseBodyStr(alloc)});
return;
}
curl.getResponseJson(page) catch {
std.debug.print("{s}\n", .{try curl.getLastErrorText(alloc)});
return;
};
count = page.sizeOfArray("entries");
i = 0;
while (i < count) {
page.setI(i);
event_id = try page.stringOf(alloc, "entries[i].event_id");
if (std.mem.eql(u8, event_id, "")) {
std.debug.print("Event without an event_id; checkpoint not advanced.\n", .{});
return;
}
seen_path.clear();
seen_path.append("seen.") catch {};
seen_path.append(event_id) catch {};
if (!state.hasMember(try seen_path.getAsString(alloc))) {
// Replace this logging with your idempotent business operation.
// Record success only after that operation succeeds.
std.debug.print("{s} {s} {s}\n", .{ event_id, try page.stringOf(alloc, "entries[i].event_type"), try page.stringOf(alloc, "entries[i].source.id") });
state.updateBool(try seen_path.getAsString(alloc), true) catch {};
}
i = i + 1;
}
next_position = try page.stringOf(alloc, "next_stream_position");
if (std.mem.eql(u8, next_position, "")) {
std.debug.print("Missing next_stream_position; checkpoint not advanced.\n", .{});
return;
}
more = (count > 0) and (!std.mem.eql(u8, next_position, try curl.getVar(alloc, "position")));
state.updateString("position", next_position) catch {};
state.writeFile(state_path) catch {
std.debug.print("{s}\n", .{try state.getLastErrorText(alloc)});
return;
};
curl.setVar("position", next_position);
batch = batch + 1;
}
std.debug.print("Checkpoint saved. Run again later to continue polling.\n", .{});
}