Objective-C Requires Chilkat v11.5.0+
Objective-C
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 Objective-C Downloads
#import <CkoHttpCurl.h>
#import <CkoJsonObject.h>
#import <CkoFileAccess.h>
#import <NSString.h>
#import <CkoStringBuilder.h>
BOOL success = NO;
// Requires Chilkat 11.5.0 or later and a previously unlocked Chilkat bundle.
// See Global Unlock Sample.
// Guide: Box API Guide.
success = NO;
// 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.
CkoHttpCurl *curl = [[CkoHttpCurl alloc] init];
[curl SetVar: @"access_token" varValue: @"BOX_ACCESS_TOKEN"];
CkoJsonObject *state = [[CkoJsonObject alloc] init];
CkoFileAccess *files = [[CkoFileAccess alloc] init];
NSString *statePath = @"qa_data/box_events_state.json";
if ([files FileExists: statePath] == YES) {
success = [state LoadFile: statePath];
if (success != YES) {
NSLog(@"%@",state.LastErrorText);
return;
}
if ([state HasMember: @"position"] != YES) {
NSLog(@"%@",@"Invalid checkpoint: position missing.");
return;
}
}
else {
// "now" starts a new subscription. It deliberately skips historical events.
[state UpdateString: @"position" value: @"now"];
}
[curl SetVar: @"position" varValue: [state StringOf: @"position"]];
CkoJsonObject *page = [[CkoJsonObject alloc] init];
CkoStringBuilder *seenPath = [[CkoStringBuilder alloc] init];
NSString *eventId = 0;
NSString *nextPosition = 0;
int batch = 0;
int i;
int count;
BOOL more = YES;
while ((more == YES) && (batch < 20)) {
[curl ClearTargetOutput: @"*"];
CkoStringBuilder *authorizedCommand1 = [[CkoStringBuilder alloc] init];
[authorizedCommand1 SetString: @"curl -X GET \"https://api.box.com/2.0/events?stream_type=all&stream_position={{position}}&limit=100\" -H \"Authorization: Bearer {{access_token}}\""];
int headerReplacement1 = [[authorizedCommand1 Replace: @"{{access_token}}" replacement: [curl GetVar: @"access_token"]] intValue];
success = [curl DoYourThing: [authorizedCommand1 GetAsString]];
if ((success != YES) || ([curl.StatusCode intValue] != 200)) {
NSLog(@"%@%d",@"Box request failed. HTTP status: ",[curl.StatusCode intValue]);
NSLog(@"%@%d",@"Failure reason: ",[curl.FailReason intValue]);
NSLog(@"%@",curl.ResponseBodyStr);
return;
}
success = [curl GetResponseJson: page];
if (success != YES) {
NSLog(@"%@",curl.LastErrorText);
return;
}
count = [[page SizeOfArray: @"entries"] intValue];
i = 0;
while (i < count) {
page.I = [NSNumber numberWithInt: i];
eventId = [page StringOf: @"entries[i].event_id"];
if (eventId == @"") {
NSLog(@"%@",@"Event without an event_id; checkpoint not advanced.");
return;
}
[seenPath Clear];
[seenPath Append: @"seen."];
[seenPath Append: eventId];
if ([state HasMember: [seenPath GetAsString]] == NO) {
// Replace this logging with your idempotent business operation.
// Record success only after that operation succeeds.
NSLog(@"%@%@%@%@%@",eventId,@" ",[page StringOf: @"entries[i].event_type"],@" ",[page StringOf: @"entries[i].source.id"]);
[state UpdateBool: [seenPath GetAsString] value: YES];
}
i = i + 1;
}
nextPosition = [page StringOf: @"next_stream_position"];
if (nextPosition == @"") {
NSLog(@"%@",@"Missing next_stream_position; checkpoint not advanced.");
return;
}
more = (count > 0) && (nextPosition != [curl GetVar: @"position"]);
[state UpdateString: @"position" value: nextPosition];
success = [state WriteFile: statePath];
if (success != YES) {
NSLog(@"%@",state.LastErrorText);
return;
}
[curl SetVar: @"position" varValue: nextPosition];
batch = batch + 1;
}
NSLog(@"%@",@"Checkpoint saved. Run again later to continue polling.");