Unicode C
Unicode C
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 Unicode C Downloads
#include <C_CkFileAccessW.h>
#include <C_CkRestW.h>
#include <C_CkAuthGoogleW.h>
#include <C_CkUrlW.h>
#include <C_CkJsonObjectW.h>
#include <C_CkStreamW.h>
#include <C_CkServerSentEventW.h>
#include <C_CkTaskW.h>
void ChilkatSample(void)
{
BOOL success;
HCkFileAccessW fac;
const wchar_t *accessToken;
HCkRestW rest;
HCkAuthGoogleW authGoogle;
const wchar_t *responseBody;
const wchar_t *urlStr;
HCkUrlW url;
HCkRestW rest2;
int responseStatusCode;
HCkJsonObjectW jsonDb;
HCkStreamW eventStream;
HCkServerSentEventW sse;
HCkTaskW task;
int count;
const wchar_t *eventStr;
success = FALSE;
// 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.
fac = CkFileAccessW_Create();
accessToken = CkFileAccessW_readEntireTextFile(fac,L"qa_data/tokens/firebaseToken.txt",L"utf-8");
if (CkFileAccessW_getLastMethodSuccess(fac) == FALSE) {
wprintf(L"%s\n",CkFileAccessW_lastErrorText(fac));
CkFileAccessW_Dispose(fac);
return;
}
rest = CkRestW_Create();
// 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.
success = CkRestW_Connect(rest,L"chilkat.firebaseio.com",443,TRUE,TRUE);
if (success == FALSE) {
wprintf(L"%s\n",CkRestW_lastErrorText(rest));
CkFileAccessW_Dispose(fac);
CkRestW_Dispose(rest);
return;
}
authGoogle = CkAuthGoogleW_Create();
CkAuthGoogleW_putAccessToken(authGoogle,accessToken);
CkRestW_SetAuthGoogle(rest,authGoogle);
CkRestW_AddHeader(rest,L"Accept",L"text/event-stream");
CkRestW_AddHeader(rest,L"Cache-Control",L"no-cache");
responseBody = CkRestW_fullRequestNoBody(rest,L"GET",L"/.json");
// A 307 redirect response is expected.
if (CkRestW_getResponseStatusCode(rest) != 307) {
wprintf(L"Unexpected response code: %d\n",CkRestW_getResponseStatusCode(rest));
wprintf(L"%s\n",responseBody);
wprintf(L"Failed.\n");
CkFileAccessW_Dispose(fac);
CkRestW_Dispose(rest);
CkAuthGoogleW_Dispose(authGoogle);
return;
}
// Get the redirect URL
urlStr = CkRestW_lastRedirectUrl(rest);
url = CkUrlW_Create();
CkUrlW_ParseUrl(url,urlStr);
wprintf(L"redirect URL domain: %s\n",CkUrlW_host(url));
wprintf(L"redirect URL path: %s\n",CkUrlW_path(url));
wprintf(L"redirect URL query params: %s\n",CkUrlW_query(url));
wprintf(L"redirect URL path with query params: %s\n",CkUrlW_pathWithQueryParams(url));
// Our text/event-stream will be obtained from the redirect URL...
rest2 = CkRestW_Create();
success = CkRestW_Connect(rest2,CkUrlW_host(url),443,TRUE,TRUE);
if (success != TRUE) {
wprintf(L"%s\n",CkRestW_lastErrorText(rest2));
CkFileAccessW_Dispose(fac);
CkRestW_Dispose(rest);
CkAuthGoogleW_Dispose(authGoogle);
CkUrlW_Dispose(url);
CkRestW_Dispose(rest2);
return;
}
CkRestW_AddHeader(rest2,L"Accept",L"text/event-stream");
CkRestW_AddHeader(rest2,L"Cache-Control",L"no-cache");
// Add the redirect query params to the request
CkRestW_AddQueryParams(rest2,CkUrlW_query(url));
// In our case, we don't actually need the auth query param,
// so remove it.
CkRestW_RemoveQueryParam(rest2,L"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.)
success = CkRestW_SendReqNoBody(rest2,L"GET",CkUrlW_path(url));
if (success != TRUE) {
wprintf(L"%s\n",CkRestW_lastErrorText(rest2));
CkFileAccessW_Dispose(fac);
CkRestW_Dispose(rest);
CkAuthGoogleW_Dispose(authGoogle);
CkUrlW_Dispose(url);
CkRestW_Dispose(rest2);
return;
}
// 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.
responseStatusCode = CkRestW_ReadResponseHeader(rest2);
if (responseStatusCode < 0) {
wprintf(L"%s\n",CkRestW_lastErrorText(rest2));
CkFileAccessW_Dispose(fac);
CkRestW_Dispose(rest);
CkAuthGoogleW_Dispose(authGoogle);
CkUrlW_Dispose(url);
CkRestW_Dispose(rest2);
return;
}
// If successful, a 200 response code is expected.
// If the reponse code is not 200, then read the response body and fail..
if (responseStatusCode != 200) {
wprintf(L"Response Code: %d\n",responseStatusCode);
wprintf(L"Response Status Text: %s\n",CkRestW_responseStatusText(rest2));
wprintf(L"Response Header: %s\n",CkRestW_responseHeader(rest2));
responseBody = CkRestW_readRespBodyString(rest2);
if (CkRestW_getLastMethodSuccess(rest2) == TRUE) {
wprintf(L"Error Response Body: %s\n",responseBody);
}
wprintf(L"Failed.\n");
CkFileAccessW_Dispose(fac);
CkRestW_Dispose(rest);
CkAuthGoogleW_Dispose(authGoogle);
CkUrlW_Dispose(url);
CkRestW_Dispose(rest2);
return;
}
// For this example, our JSON database will be empty at the beginning.
// The incoming events (put and patch) will be applied to this database.
jsonDb = CkJsonObjectW_Create();
// Make sure to set the JSON path delimiter to "/". The default is "." and this
// is not compatible with Firebase paths.
CkJsonObjectW_putDelimiterChar(jsonDb,L"/");
// 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..
eventStream = CkStreamW_Create();
// This sse object will be used as a helper to parse the server-sent event stream.
sse = CkServerSentEventW_Create();
task = CkRestW_ReadRespBodyStreamAsync(rest2,eventStream,TRUE);
CkTaskW_Run(task);
// For this example, we'll just read a few events, and then cancel the
// async task.
count = 0;
while ((count < 3) && (CkTaskW_getFinished(task) == FALSE)) {
// 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.
eventStr = CkStreamW_readUntilMatch(eventStream,L"\r\n\r\n");
if (CkStreamW_getLastMethodSuccess(eventStream) != TRUE) {
wprintf(L"%s\n",CkStreamW_lastErrorText(eventStream));
// Force the loop to exit by setting the count to a high number.
count = 99999;
}
else {
wprintf(L"Event: [%s]\n",eventStr);
// We have an event. Let's update our local copy of the JSON database.
success = CkServerSentEventW_LoadEvent(sse,eventStr);
if (success != TRUE) {
wprintf(L"Failed to load sse event: %s\n",eventStr);
}
else {
// Now we can easily access the event name and data, and apply it to our JSON database:
success = CkJsonObjectW_FirebaseApplyEvent(jsonDb,CkServerSentEventW_eventName(sse),CkServerSentEventW_data(sse));
if (success != TRUE) {
wprintf(L"Failed to apply event: %s: %s\n",CkServerSentEventW_eventName(sse),CkServerSentEventW_data(sse));
}
else {
wprintf(L"Successfully applied event: %s: %s\n",CkServerSentEventW_eventName(sse),CkServerSentEventW_data(sse));
}
}
}
count = count + 1;
}
// Make sure the background task is cancelled if still running.
CkTaskW_Cancel(task);
CkTaskW_Dispose(task);
// Examine the JSON database after applying events..
CkJsonObjectW_putEmitCompact(jsonDb,FALSE);
wprintf(L"----\n");
wprintf(L"%s\n",CkJsonObjectW_emit(jsonDb));
CkFileAccessW_Dispose(fac);
CkRestW_Dispose(rest);
CkAuthGoogleW_Dispose(authGoogle);
CkUrlW_Dispose(url);
CkRestW_Dispose(rest2);
CkJsonObjectW_Dispose(jsonDb);
CkStreamW_Dispose(eventStream);
CkServerSentEventW_Dispose(sse);
}