Swift
Swift
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 Swift Downloads
func chilkatTest() {
var success: Bool = 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.
let fac = CkoFileAccess()!
var accessToken: String? = fac.readEntireTextFile(path: "qa_data/tokens/firebaseToken.txt", charset: "utf-8")
if fac.lastMethodSuccess == false {
print("\(fac.lastErrorText!)")
return
}
let rest = CkoRest()!
// 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 = rest.connect(hostname: "chilkat.firebaseio.com", port: 443, tls: true, autoReconnect: true)
if success == false {
print("\(rest.lastErrorText!)")
return
}
let authGoogle = CkoAuthGoogle()!
authGoogle.accessToken = accessToken
rest.setAuthGoogle(authProvider: authGoogle)
rest.addHeader(name: "Accept", value: "text/event-stream")
rest.addHeader(name: "Cache-Control", value: "no-cache")
var responseBody: String? = rest.fullRequestNoBody(httpVerb: "GET", uriPath: "/.json")
// A 307 redirect response is expected.
if rest.responseStatusCode.intValue != 307 {
print("Unexpected response code: \(rest.responseStatusCode.intValue)")
print("\(responseBody!)")
print("Failed.")
return
}
// Get the redirect URL
var urlStr: String? = rest.lastRedirectUrl
let url = CkoUrl()!
url.parse(url: urlStr)
print("redirect URL domain: \(url.host!)")
print("redirect URL path: \(url.path!)")
print("redirect URL query params: \(url.query!)")
print("redirect URL path with query params: \(url.pathWithQueryParams!)")
// Our text/event-stream will be obtained from the redirect URL...
let rest2 = CkoRest()!
success = rest2.connect(hostname: url.host, port: 443, tls: true, autoReconnect: true)
if success != true {
print("\(rest2.lastErrorText!)")
return
}
rest2.addHeader(name: "Accept", value: "text/event-stream")
rest2.addHeader(name: "Cache-Control", value: "no-cache")
// Add the redirect query params to the request
rest2.addQueryParams(queryString: url.query)
// In our case, we don't actually need the auth query param,
// so remove it.
rest2.removeQueryParam(name: "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(httpVerb: "GET", uriPath: url.path)
if success != true {
print("\(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.
var responseStatusCode: Int = rest2.readResponseHeader().intValue
if responseStatusCode < 0 {
print("\(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 {
print("Response Code: \(responseStatusCode)")
print("Response Status Text: \(rest2.responseStatusText!)")
print("Response Header: \(rest2.responseHeader!)")
responseBody = rest2.readRespBodyString()
if rest2.lastMethodSuccess == true {
print("Error Response Body: \(responseBody!)")
}
print("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.
let jsonDb = CkoJsonObject()!
// 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..
let eventStream = CkoStream()!
// This sse object will be used as a helper to parse the server-sent event stream.
let sse = CkoServerSentEvent()!
var task: CkoTask? = rest2.readRespBodyStreamAsync(stream: eventStream, autoSetStreamCharset: true)
task!.run()
// For this example, we'll just read a few events, and then cancel the
// async task.
var count: Int = 0
while (count < 3) && (task!.finished == 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.
var eventStr: String? = eventStream.read(untilMatch: "\r\n\r\n")
if eventStream.lastMethodSuccess != true {
print("\(eventStream.lastErrorText!)")
// Force the loop to exit by setting the count to a high number.
count = 99999
}
else {
print("Event: [\(eventStr!)]")
// We have an event. Let's update our local copy of the JSON database.
success = sse.loadEvent(eventText: eventStr)
if success != true {
print("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(name: sse.eventName, data: sse.data)
if success != true {
print("Failed to apply event: \(sse.eventName!): \(sse.data!)")
}
else {
print("Successfully applied event: \(sse.eventName!): \(sse.data!)")
}
}
}
count = count + 1
}
// Make sure the background task is cancelled if still running.
task!.cancel()
task = nil
// Examine the JSON database after applying events..
jsonDb.emitCompact = false
print("----")
print("\(jsonDb.emit()!)")
}