Sample code for 30+ languages & platforms
C Requires Chilkat v11.5.0+

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 C Downloads

C
#include <C_CkHttpCurl.h>
#include <C_CkJsonObject.h>
#include <C_CkFileAccess.h>
#include <C_CkStringBuilder.h>

void ChilkatSample(void)
    {
    BOOL success;
    HCkHttpCurl curl;
    HCkJsonObject state;
    HCkFileAccess files;
    const char *statePath;
    HCkJsonObject page;
    HCkStringBuilder seenPath;
    const char *eventId;
    const char *nextPosition;
    int batch;
    int i;
    int count;
    BOOL more;
    HCkStringBuilder authorizedCommand1;
    int headerReplacement1;

    success = 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.
    curl = CkHttpCurl_Create();
    CkHttpCurl_SetVar(curl,"access_token","BOX_ACCESS_TOKEN");

    state = CkJsonObject_Create();
    files = CkFileAccess_Create();
    statePath = "qa_data/box_events_state.json";
    if (CkFileAccess_FileExists(files,statePath) == TRUE) {
        success = CkJsonObject_LoadFile(state,statePath);
        if (success != TRUE) {
            printf("%s\n",CkJsonObject_lastErrorText(state));
            CkHttpCurl_Dispose(curl);
            CkJsonObject_Dispose(state);
            CkFileAccess_Dispose(files);
            return;
        }

        if (CkJsonObject_HasMember(state,"position") != TRUE) {
            printf("Invalid checkpoint: position missing.\n");
            CkHttpCurl_Dispose(curl);
            CkJsonObject_Dispose(state);
            CkFileAccess_Dispose(files);
            return;
        }

    }
    else {
        //  "now" starts a new subscription. It deliberately skips historical events.
        CkJsonObject_UpdateString(state,"position","now");
    }

    CkHttpCurl_SetVar(curl,"position",CkJsonObject_stringOf(state,"position"));
    page = CkJsonObject_Create();
    seenPath = CkStringBuilder_Create();

    batch = 0;

    more = TRUE;
    while ((more == TRUE) && (batch < 20)) {
        CkHttpCurl_ClearTargetOutput(curl,"*");
        authorizedCommand1 = CkStringBuilder_Create();
        CkStringBuilder_SetString(authorizedCommand1,"curl -X GET \"https://api.box.com/2.0/events?stream_type=all&stream_position={{position}}&limit=100\" -H \"Authorization: Bearer {{access_token}}\"");
        headerReplacement1 = CkStringBuilder_Replace(authorizedCommand1,"{{access_token}}",CkHttpCurl_getVar(curl,"access_token"));
        success = CkHttpCurl_DoYourThing(curl,CkStringBuilder_getAsString(authorizedCommand1));
        if ((success != TRUE) || (CkHttpCurl_getStatusCode(curl) != 200)) {
            printf("Box request failed. HTTP status: %d\n",CkHttpCurl_getStatusCode(curl));
            printf("Failure reason: %d\n",CkHttpCurl_getFailReason(curl));
            printf("%s\n",CkHttpCurl_responseBodyStr(curl));
            CkHttpCurl_Dispose(curl);
            CkJsonObject_Dispose(state);
            CkFileAccess_Dispose(files);
            CkJsonObject_Dispose(page);
            CkStringBuilder_Dispose(seenPath);
            CkStringBuilder_Dispose(authorizedCommand1);
            return;
        }

        success = CkHttpCurl_GetResponseJson(curl,page);
        if (success != TRUE) {
            printf("%s\n",CkHttpCurl_lastErrorText(curl));
            CkHttpCurl_Dispose(curl);
            CkJsonObject_Dispose(state);
            CkFileAccess_Dispose(files);
            CkJsonObject_Dispose(page);
            CkStringBuilder_Dispose(seenPath);
            CkStringBuilder_Dispose(authorizedCommand1);
            return;
        }

        count = CkJsonObject_SizeOfArray(page,"entries");
        i = 0;
        while (i < count) {
            CkJsonObject_putI(page,i);
            eventId = CkJsonObject_stringOf(page,"entries[i].event_id");
            if (eventId == "") {
                printf("Event without an event_id; checkpoint not advanced.\n");
                CkHttpCurl_Dispose(curl);
                CkJsonObject_Dispose(state);
                CkFileAccess_Dispose(files);
                CkJsonObject_Dispose(page);
                CkStringBuilder_Dispose(seenPath);
                CkStringBuilder_Dispose(authorizedCommand1);
                return;
            }

            CkStringBuilder_Clear(seenPath);
            CkStringBuilder_Append(seenPath,"seen.");
            CkStringBuilder_Append(seenPath,eventId);
            if (CkJsonObject_HasMember(state,CkStringBuilder_getAsString(seenPath)) == FALSE) {
                //  Replace this logging with your idempotent business operation.
                //  Record success only after that operation succeeds.
                printf("%s %s %s\n",eventId,CkJsonObject_stringOf(page,"entries[i].event_type"),CkJsonObject_stringOf(page,"entries[i].source.id"));
                CkJsonObject_UpdateBool(state,CkStringBuilder_getAsString(seenPath),TRUE);
            }

            i = i + 1;
        }

        nextPosition = CkJsonObject_stringOf(page,"next_stream_position");
        if (nextPosition == "") {
            printf("Missing next_stream_position; checkpoint not advanced.\n");
            CkHttpCurl_Dispose(curl);
            CkJsonObject_Dispose(state);
            CkFileAccess_Dispose(files);
            CkJsonObject_Dispose(page);
            CkStringBuilder_Dispose(seenPath);
            CkStringBuilder_Dispose(authorizedCommand1);
            return;
        }

        more = (count > 0) && (nextPosition != CkHttpCurl_getVar(curl,"position"));
        CkJsonObject_UpdateString(state,"position",nextPosition);
        success = CkJsonObject_WriteFile(state,statePath);
        if (success != TRUE) {
            printf("%s\n",CkJsonObject_lastErrorText(state));
            CkHttpCurl_Dispose(curl);
            CkJsonObject_Dispose(state);
            CkFileAccess_Dispose(files);
            CkJsonObject_Dispose(page);
            CkStringBuilder_Dispose(seenPath);
            CkStringBuilder_Dispose(authorizedCommand1);
            return;
        }

        CkHttpCurl_SetVar(curl,"position",nextPosition);
        batch = batch + 1;
    }

    printf("Checkpoint saved. Run again later to continue polling.\n");


    CkHttpCurl_Dispose(curl);
    CkJsonObject_Dispose(state);
    CkFileAccess_Dispose(files);
    CkJsonObject_Dispose(page);
    CkStringBuilder_Dispose(seenPath);
    CkStringBuilder_Dispose(authorizedCommand1);

    }