Xbase++ Requires Chilkat v11.5.0+
Xbase++
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 Xbase++ Downloads
LOCAL nSuccess
LOCAL oCurl
LOCAL oState
LOCAL oFiles
LOCAL cStatePath
LOCAL oPage
LOCAL oSeenPath
LOCAL cEventId
LOCAL cNextPosition
LOCAL nBatch
LOCAL i
LOCAL nCount
LOCAL nMore
LOCAL oAuthorizedCommand1
LOCAL nHeaderReplacement1
nSuccess := 0
// Requires Chilkat 11.5.0 or later and a previously unlocked Chilkat bundle.
// See Global Unlock Sample.
// Guide: Box API Guide.
nSuccess := 0
// 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.
oCurl := CreateObject("Chilkat.HttpCurl")
oCurl:SetVar("access_token", "BOX_ACCESS_TOKEN")
oState := CreateObject("Chilkat.JsonObject")
oFiles := CreateObject("Chilkat.FileAccess")
cStatePath := "qa_data/box_events_state.json"
IF (oFiles:FileExists(cStatePath) == 1)
nSuccess := oState:LoadFile(cStatePath)
IF (nSuccess != 1)
? oState:LastErrorText
oCurl:destroy()
oState:destroy()
oFiles:destroy()
RETURN
ENDIF
IF (oState:HasMember("position") != 1)
? "Invalid checkpoint: position missing."
oCurl:destroy()
oState:destroy()
oFiles:destroy()
RETURN
ENDIF
ELSE
// "now" starts a new subscription. It deliberately skips historical events.
oState:UpdateString("position", "now")
ENDIF
oCurl:SetVar("position", oState:StringOf("position"))
oPage := CreateObject("Chilkat.JsonObject")
oSeenPath := CreateObject("Chilkat.StringBuilder")
nBatch := 0
nMore := 1
DO WHILE (nMore == 1) .AND. (nBatch < 20)
oCurl:ClearTargetOutput("*")
oAuthorizedCommand1 := CreateObject("Chilkat.StringBuilder")
oAuthorizedCommand1:SetString('curl -X GET "https://api.box.com/2.0/events?stream_type=all&stream_position={{position}}&limit=100" -H "Authorization: Bearer {{access_token}}"')
nHeaderReplacement1 := oAuthorizedCommand1:Replace("{{access_token}}", oCurl:GetVar("access_token"))
nSuccess := oCurl:DoYourThing(oAuthorizedCommand1:GetAsString())
IF ((nSuccess != 1) .OR. (oCurl:StatusCode != 200))
? "Box request failed. HTTP status: " + Str(oCurl:StatusCode)
? "Failure reason: " + Str(oCurl:FailReason)
? oCurl:ResponseBodyStr
oCurl:destroy()
oState:destroy()
oFiles:destroy()
oPage:destroy()
oSeenPath:destroy()
oAuthorizedCommand1:destroy()
RETURN
ENDIF
nSuccess := oCurl:GetResponseJson(oPage)
IF (nSuccess != 1)
? oCurl:LastErrorText
oCurl:destroy()
oState:destroy()
oFiles:destroy()
oPage:destroy()
oSeenPath:destroy()
oAuthorizedCommand1:destroy()
RETURN
ENDIF
nCount := oPage:SizeOfArray("entries")
i := 0
DO WHILE i < nCount
oPage:I := i
cEventId := oPage:StringOf("entries[i].event_id")
IF (cEventId == "")
? "Event without an event_id; checkpoint not advanced."
oCurl:destroy()
oState:destroy()
oFiles:destroy()
oPage:destroy()
oSeenPath:destroy()
oAuthorizedCommand1:destroy()
RETURN
ENDIF
oSeenPath:Clear()
oSeenPath:Append("seen.")
oSeenPath:Append(cEventId)
IF (oState:HasMember(oSeenPath:GetAsString()) == 0)
// Replace this logging with your idempotent business operation.
// Record success only after that operation succeeds.
? cEventId + " " + oPage:StringOf("entries[i].event_type") + " " + oPage:StringOf("entries[i].source.id")
oState:UpdateBool(oSeenPath:GetAsString(), 1)
ENDIF
i := i + 1
ENDDO
cNextPosition := oPage:StringOf("next_stream_position")
IF (cNextPosition == "")
? "Missing next_stream_position; checkpoint not advanced."
oCurl:destroy()
oState:destroy()
oFiles:destroy()
oPage:destroy()
oSeenPath:destroy()
oAuthorizedCommand1:destroy()
RETURN
ENDIF
nMore := (nCount > 0) .AND. (cNextPosition != oCurl:GetVar("position"))
oState:UpdateString("position", cNextPosition)
nSuccess := oState:WriteFile(cStatePath)
IF (nSuccess != 1)
? oState:LastErrorText
oCurl:destroy()
oState:destroy()
oFiles:destroy()
oPage:destroy()
oSeenPath:destroy()
oAuthorizedCommand1:destroy()
RETURN
ENDIF
oCurl:SetVar("position", cNextPosition)
nBatch := nBatch + 1
ENDDO
? "Checkpoint saved. Run again later to continue polling."
oCurl:destroy()
oState:destroy()
oFiles:destroy()
oPage:destroy()
oSeenPath:destroy()
oAuthorizedCommand1:destroy()