Sample code for 30+ languages & platforms
Lianja Requires Chilkat v11.0.0+

Firebase Receive Server-Sent Events (text/event-stream)

See more Firebase Examples

Demonstrates how to start receiving server-sent events and update your JSON database with each event.

Chilkat Lianja Downloads

Lianja
llSuccess = .F.

//  Demonstrates how to begin receiving server-sent events, and to update
//  your JSON database for each event.

//  This example requires the Chilkat API to have been previously unlocked.
//  See Global Unlock Sample for sample code.

//  This example assumes a JWT authentication token, if required, has been previously obtained.
//  See Get Firebase Access Token from JSON Service Account Private Key for sample code.

//  Load the previously obtained Firebase access token into a string.
loFac = createobject("CkFileAccess")
lcAccessToken = loFac.ReadEntireTextFile("qa_data/tokens/firebaseToken.txt","utf-8")
if (loFac.LastMethodSuccess = .F.) then
    ? loFac.LastErrorText
    release loFac
    return
endif

loRest = createobject("CkRest")

//  Make the initial connection (without sending a request yet).
//  Once connected, any number of requests may be sent.  It is not necessary to explicitly
//  call Connect before each request.  
llSuccess = loRest.Connect("chilkat.firebaseio.com",443,.T.,.T.)
if (llSuccess = .F.) then
    ? loRest.LastErrorText
    release loFac
    release loRest
    return
endif

loAuthGoogle = createobject("CkAuthGoogle")
loAuthGoogle.AccessToken = lcAccessToken
loRest.SetAuthGoogle(loAuthGoogle)

loRest.AddHeader("Accept","text/event-stream")
loRest.AddHeader("Cache-Control","no-cache")

lcResponseBody = loRest.FullRequestNoBody("GET","/.json")

//  A 307 redirect response is expected.
if (loRest.ResponseStatusCode <> 307) then
    ? "Unexpected response code: " + str(loRest.ResponseStatusCode)
    ? lcResponseBody
    ? "Failed."
    release loFac
    release loRest
    release loAuthGoogle
    return
endif

//  Get the redirect URL
lcUrlStr = loRest.LastRedirectUrl
loUrl = createobject("CkUrl")
loUrl.ParseUrl(lcUrlStr)

? "redirect URL domain: " + loUrl.Host
? "redirect URL path: " + loUrl.Path
? "redirect URL query params: " + loUrl.Query
? "redirect URL path with query params: " + loUrl.PathWithQueryParams

//  Our text/event-stream will be obtained from the redirect URL...
loRest2 = createobject("CkRest")

llSuccess = loRest2.Connect(loUrl.Host,443,.T.,.T.)
if (llSuccess <> .T.) then
    ? loRest2.LastErrorText
    release loFac
    release loRest
    release loAuthGoogle
    release loUrl
    release loRest2
    return
endif

loRest2.AddHeader("Accept","text/event-stream")
loRest2.AddHeader("Cache-Control","no-cache")

//  Add the redirect query params to the request
loRest2.AddQueryParams(loUrl.Query)

//  In our case, we don't actually need the auth query param,
//  so remove it.
loRest2.RemoveQueryParam("auth")

//  Send the request.  (We are only sending the request here.
//  We are not yet getting the response because the response
//  will be a text/event-stream.)
llSuccess = loRest2.SendReqNoBody("GET",loUrl.Path)
if (llSuccess <> .T.) then
    ? loRest2.LastErrorText
    release loFac
    release loRest
    release loAuthGoogle
    release loUrl
    release loRest2
    return
endif

//  Read the response header.  
//  We want to first get the response header to see if it's a successful
//  response status code.  If not, then the response will not be a text/event-stream
//  and we should read the response body normally.
lnResponseStatusCode = loRest2.ReadResponseHeader()
if (lnResponseStatusCode < 0) then
    ? loRest2.LastErrorText
    release loFac
    release loRest
    release loAuthGoogle
    release loUrl
    release loRest2
    return
endif

//  If successful, a 200 response code is expected.
//  If the reponse code is not 200, then read the response body and fail..
if (lnResponseStatusCode <> 200) then
    ? "Response Code: " + str(lnResponseStatusCode)
    ? "Response Status Text: " + loRest2.ResponseStatusText
    ? "Response Header: " + loRest2.ResponseHeader
    lcResponseBody = loRest2.ReadRespBodyString()
    if (loRest2.LastMethodSuccess = .T.) then
        ? "Error Response Body: " + lcResponseBody
    endif

    ? "Failed."
    release loFac
    release loRest
    release loAuthGoogle
    release loUrl
    release loRest2
    return
endif

//  For this example, our JSON database will be empty at the beginning.
//  The incoming events (put and patch) will be applied to this database.
loJsonDb = createobject("CkJsonObject")

//  Make sure to set the JSON path delimiter to "/".  The default is "." and this
//  is not compatible with Firebase paths.
loJsonDb.DelimiterChar = "/"

//  At this point, we've received the response header.  Now it's time to begin
//  receiving the event stream.  We'll start a background thread to read the 
//  stream.  (Our main application (foreground) thread can cancel it at any time.)  
//  While receiving in the background thread, our foreground thread can read the stream
//  as it desires..
loEventStream = createobject("CkStream")

//  This sse object will be used as a helper to parse the server-sent event stream.
loSse = createobject("CkServerSentEvent")

loTask = loRest2.ReadRespBodyStreamAsync(loEventStream,.T.)
loTask.Run()

//  For this example, we'll just read a few events, and then cancel the
//  async task.
lnCount = 0
do while (lnCount < 3) and (loTask.Finished = .F.)

    //  Get the next event, which is a series of text lines ending with
    //  a blank line. 
    //  Note: This method blocks the calling thread until a message arrives.
    //  a program might instead periodically check the availability of
    //  data via the stream's DataAvailable property, and then do the read.

    //  An alternative to writing a while loop to read the event stream
    //  would be to setup some sort of timer event in your program (using whatever timer functionality
    //  is provided in a programming language/environment), to periodically check the eventStream's
    //  DataAvailable property and consume the incoming event.
    lcEventStr = loEventStream.ReadUntilMatch(Chr(13) + Chr(10) + Chr(13) + Chr(10))
    if (loEventStream.LastMethodSuccess <> .T.) then
        ? loEventStream.LastErrorText
        //  Force the loop to exit by setting the count to a high number.
        lnCount = 99999
    else
        ? "Event: [" + lcEventStr + "]"

        //  We have an event. Let's update our local copy of the JSON database.
        llSuccess = loSse.LoadEvent(lcEventStr)
        if (llSuccess <> .T.) then
            ? "Failed to load sse event: " + lcEventStr
        else
            //  Now we can easily access the event name and data, and apply it to our JSON database:
            llSuccess = loJsonDb.FirebaseApplyEvent(loSse.EventName,loSse.Data)
            if (llSuccess <> .T.) then
                ? "Failed to apply event: " + loSse.EventName + ": " + loSse.Data
            else
                ? "Successfully applied event: " + loSse.EventName + ": " + loSse.Data
            endif

        endif

    endif

    lnCount = lnCount + 1
enddo

//  Make sure the background task is cancelled if still running.
loTask.Cancel()

release loTask

//  Examine the JSON database after applying events..
loJsonDb.EmitCompact = .F.
? "----"
? loJsonDb.Emit()


release loFac
release loRest
release loAuthGoogle
release loUrl
release loRest2
release loJsonDb
release loEventStream
release loSse