Chilkat HOME .NET Core C# Android™ AutoIt C C# C++ Chilkat2-Python CkPython Classic ASP DataFlex Delphi ActiveX Delphi DLL Go Java Lianja Mono C# Node.js Objective-C PHP ActiveX PHP Extension Perl PowerBuilder PowerShell PureBasic Ruby SQL Server Swift 2 Swift 3,4,5... Tcl Unicode C Unicode C++ VB.NET VBScript Visual Basic 6.0 Visual FoxPro Xojo Plugin
(Objective-C) Firebase Receive Server-Sent Events (text/event-stream)Demonstrates how to start receiving server-sent events and update your JSON database with each event.
#import <CkoFileAccess.h> #import <NSString.h> #import <CkoRest.h> #import <CkoAuthGoogle.h> #import <CkoUrl.h> #import <CkoJsonObject.h> #import <CkoStream.h> #import <CkoServerSentEvent.h> #import <CkoTask.h> // 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. CkoFileAccess *fac = [[CkoFileAccess alloc] init]; NSString *accessToken = [fac ReadEntireTextFile: @"qa_data/tokens/firebaseToken.txt" charset: @"utf-8"]; if (fac.LastMethodSuccess != YES) { NSLog(@"%@",fac.LastErrorText); return; } CkoRest *rest = [[CkoRest alloc] init]; // 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. BOOL success = [rest Connect: @"chilkat.firebaseio.com" port: [NSNumber numberWithInt: 443] tls: YES autoReconnect: YES]; if (success != YES) { NSLog(@"%@",rest.LastErrorText); return; } CkoAuthGoogle *authGoogle = [[CkoAuthGoogle alloc] init]; authGoogle.AccessToken = accessToken; [rest SetAuthGoogle: authGoogle]; [rest AddHeader: @"Accept" value: @"text/event-stream"]; [rest AddHeader: @"Cache-Control" value: @"no-cache"]; NSString *responseBody = [rest FullRequestNoBody: @"GET" uriPath: @"/.json"]; // A 307 redirect response is expected. if ([rest.ResponseStatusCode intValue] != 307) { NSLog(@"%@%d",@"Unexpected response code: ",[rest.ResponseStatusCode intValue]); NSLog(@"%@",responseBody); NSLog(@"%@",@"Failed."); return; } // Get the redirect URL CkoUrl *url = [rest RedirectUrl]; if (rest.LastMethodSuccess != YES) { NSLog(@"%@",rest.LastErrorText); return; } NSLog(@"%@%@",@"redirect URL domain: ",url.Host); NSLog(@"%@%@",@"redirect URL path: ",url.Path); NSLog(@"%@%@",@"redirect URL query params: ",url.Query); NSLog(@"%@%@",@"redirect URL path with query params: ",url.PathWithQueryParams); // Our text/event-stream will be obtained from the redirect URL... CkoRest *rest2 = [[CkoRest alloc] init]; success = [rest2 Connect: url.Host port: [NSNumber numberWithInt: 443] tls: YES autoReconnect: YES]; if (success != YES) { NSLog(@"%@",rest2.LastErrorText); return; } [rest2 AddHeader: @"Accept" value: @"text/event-stream"]; [rest2 AddHeader: @"Cache-Control" value: @"no-cache"]; // Add the redirect query params to the request [rest2 AddQueryParams: url.Query]; // In our case, we don't actually need the auth query param, // so remove it. [rest2 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.) success = [rest2 SendReqNoBody: @"GET" uriPath: url.Path]; if (success != YES) { NSLog(@"%@",rest2.LastErrorText); 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. int responseStatusCode = [[rest2 ReadResponseHeader] intValue]; if (responseStatusCode < 0) { NSLog(@"%@",rest2.LastErrorText); 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) { NSLog(@"%@%d",@"Response Code: ",responseStatusCode); NSLog(@"%@%@",@"Response Status Text: ",rest2.ResponseStatusText); NSLog(@"%@%@",@"Response Header: ",rest2.ResponseHeader); responseBody = [rest2 ReadRespBodyString]; if (rest2.LastMethodSuccess == YES) { NSLog(@"%@%@",@"Error Response Body: ",responseBody); } NSLog(@"%@",@"Failed."); 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. CkoJsonObject *jsonDb = [[CkoJsonObject alloc] init]; // Make sure to set the JSON path delimiter to "/". The default is "." and this // is not compatible with Firebase paths. jsonDb.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.. CkoStream *eventStream = [[CkoStream alloc] init]; // This sse object will be used as a helper to parse the server-sent event stream. CkoServerSentEvent *sse = [[CkoServerSentEvent alloc] init]; CkoTask *task = [rest2 ReadRespBodyStreamAsync: eventStream autoSetStreamCharset: YES]; [task Run]; // For this example, we'll just read a few events, and then cancel the // async task. int count = 0; while ((count < 3) && (task.Finished == NO)) { // 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. NSString *eventStr = [eventStream ReadUntilMatch: @"\r\n\r\n"]; if (eventStream.LastMethodSuccess != YES) { NSLog(@"%@",eventStream.LastErrorText); // Force the loop to exit by setting the count to a high number. count = 99999; } else { NSLog(@"%@%@%@",@"Event: [",eventStr,@"]"); // We have an event. Let's update our local copy of the JSON database. success = [sse LoadEvent: eventStr]; if (success != YES) { NSLog(@"%@%@",@"Failed to load sse event: ",eventStr); } else { // Now we can easily access the event name and data, and apply it to our JSON database: success = [jsonDb FirebaseApplyEvent: sse.EventName data: sse.Data]; if (success != YES) { NSLog(@"%@%@%@%@",@"Failed to apply event: ",sse.EventName,@": ",sse.Data); } else { NSLog(@"%@%@%@%@",@"Successfully applied event: ",sse.EventName,@": ",sse.Data); } } } count = count + 1; } // Make sure the background task is cancelled if still running. [task Cancel]; // Examine the JSON database after applying events.. jsonDb.EmitCompact = NO; NSLog(@"%@",@"----"); NSLog(@"%@",[jsonDb Emit]); |
© 2000-2024 Chilkat Software, Inc. All Rights Reserved.