| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- /*
- * Copyright 2017 Google
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #import "FirebaseDatabase/Sources/Realtime/FConnection.h"
- #import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
- #import "FirebaseDatabase/Sources/Constants/FConstants.h"
- typedef enum {
- REALTIME_STATE_CONNECTING = 0,
- REALTIME_STATE_CONNECTED = 1,
- REALTIME_STATE_DISCONNECTED = 2,
- } FConnectionState;
- @interface FConnection () {
- FConnectionState state;
- }
- @property(nonatomic, strong) FWebSocketConnection *conn;
- @property(nonatomic, strong) FRepoInfo *repoInfo;
- @end
- #pragma mark -
- #pragma mark FConnection implementation
- @implementation FConnection
- @synthesize delegate;
- @synthesize conn;
- @synthesize repoInfo;
- #pragma mark -
- #pragma mark Initializers
- - (instancetype)initWith:(FRepoInfo *)aRepoInfo
- andDispatchQueue:(dispatch_queue_t)queue
- googleAppID:(NSString *)googleAppID
- lastSessionID:(NSString *)lastSessionID
- appCheckToken:(NSString *)appCheckToken {
- self = [super init];
- if (self) {
- state = REALTIME_STATE_CONNECTING;
- self.repoInfo = aRepoInfo;
- self.conn = [[FWebSocketConnection alloc] initWith:self.repoInfo
- andQueue:queue
- googleAppID:googleAppID
- lastSessionID:lastSessionID
- appCheckToken:appCheckToken];
- self.conn.delegate = self;
- }
- return self;
- }
- #pragma mark -
- #pragma mark Public method implementation
- - (void)open {
- FFLog(@"I-RDB082001", @"Calling open in FConnection");
- [self.conn open];
- }
- - (void)closeWithReason:(FDisconnectReason)reason {
- if (state != REALTIME_STATE_DISCONNECTED) {
- FFLog(@"I-RDB082002", @"Closing realtime connection.");
- state = REALTIME_STATE_DISCONNECTED;
- if (self.conn) {
- FFLog(@"I-RDB082003", @"Calling close again.");
- [self.conn close];
- self.conn = nil;
- }
- [self.delegate onDisconnect:self withReason:reason];
- }
- }
- - (void)close {
- [self closeWithReason:DISCONNECT_REASON_OTHER];
- }
- - (void)sendRequest:(NSDictionary *)dataMsg sensitive:(BOOL)sensitive {
- // since this came from the persistent connection, wrap it in a data message
- // envelope
- NSDictionary *msg = @{
- kFWPRequestType : kFWPRequestTypeData,
- kFWPRequestDataPayload : dataMsg
- };
- [self sendData:msg sensitive:sensitive];
- }
- #pragma mark -
- #pragma mark Helpers
- - (void)sendData:(NSDictionary *)data sensitive:(BOOL)sensitive {
- if (state != REALTIME_STATE_CONNECTED) {
- @throw [[NSException alloc]
- initWithName:@"InvalidConnectionState"
- reason:@"Tried to send data on an unconnected FConnection"
- userInfo:nil];
- } else {
- if (sensitive) {
- FFLog(@"I-RDB082004", @"Sending data (contents hidden)");
- } else {
- FFLog(@"I-RDB082005", @"Sending: %@", data);
- }
- [self.conn send:data];
- }
- }
- #pragma mark -
- #pragma mark FWebSocketConnectinDelegate implementation
- // Corresponds to onConnectionLost in JS
- - (void)onDisconnect:(FWebSocketConnection *)fwebSocket
- wasEverConnected:(BOOL)everConnected {
- self.conn = nil;
- if (!everConnected && state == REALTIME_STATE_CONNECTING) {
- FFLog(@"I-RDB082006", @"Realtime connection failed.");
- // Since we failed to connect at all, clear any cached entry for this
- // namespace in case the machine went away
- [self.repoInfo clearInternalHostCache];
- } else if (state == REALTIME_STATE_CONNECTED) {
- FFLog(@"I-RDB082007", @"Realtime connection lost.");
- }
- [self close];
- }
- // Corresponds to onMessageReceived in JS
- - (void)onMessage:(FWebSocketConnection *)fwebSocket
- withMessage:(NSDictionary *)message {
- NSString *rawMessageType =
- [message objectForKey:kFWPAsyncServerEnvelopeType];
- if (rawMessageType != nil) {
- if ([rawMessageType isEqualToString:kFWPAsyncServerDataMessage]) {
- [self onDataMessage:[message
- objectForKey:kFWPAsyncServerEnvelopeData]];
- } else if ([rawMessageType
- isEqualToString:kFWPAsyncServerControlMessage]) {
- [self onControl:[message objectForKey:kFWPAsyncServerEnvelopeData]];
- } else {
- FFLog(@"I-RDB082008", @"Unrecognized server packet type: %@",
- rawMessageType);
- }
- } else {
- FFLog(@"I-RDB082009", @"Unrecognized raw server packet received: %@",
- message);
- }
- }
- - (void)onDataMessage:(NSDictionary *)message {
- // we don't do anything with data messages, just kick them up a level
- FFLog(@"I-RDB082010", @"Got data message: %@", message);
- [self.delegate onDataMessage:self withMessage:message];
- }
- - (void)onControl:(NSDictionary *)message {
- FFLog(@"I-RDB082011", @"Got control message: %@", message);
- NSString *type = [message objectForKey:kFWPAsyncServerControlMessageType];
- if ([type isEqualToString:kFWPAsyncServerControlMessageShutdown]) {
- NSString *reason =
- [message objectForKey:kFWPAsyncServerControlMessageData];
- [self onConnectionShutdownWithReason:reason];
- } else if ([type isEqualToString:kFWPAsyncServerControlMessageReset]) {
- NSString *host =
- [message objectForKey:kFWPAsyncServerControlMessageData];
- [self onReset:host];
- } else if ([type isEqualToString:kFWPAsyncServerHello]) {
- NSDictionary *handshakeData =
- [message objectForKey:kFWPAsyncServerControlMessageData];
- [self onHandshake:handshakeData];
- } else {
- FFLog(@"I-RDB082012",
- @"Unknown control message returned from server: %@", message);
- }
- }
- - (void)onConnectionShutdownWithReason:(NSString *)reason {
- FFLog(@"I-RDB082013",
- @"Connection shutdown command received. Shutting down...");
- [self.delegate onKill:self withReason:reason];
- [self close];
- }
- - (void)onHandshake:(NSDictionary *)handshake {
- NSNumber *timestamp =
- [handshake objectForKey:kFWPAsyncServerHelloTimestamp];
- // NSString* version = [handshake
- // objectForKey:kFWPAsyncServerHelloVersion];
- NSString *host = [handshake objectForKey:kFWPAsyncServerHelloConnectedHost];
- NSString *sessionID = [handshake objectForKey:kFWPAsyncServerHelloSession];
- self.repoInfo.internalHost = host;
- if (state == REALTIME_STATE_CONNECTING) {
- [self.conn start];
- [self onConnection:self.conn readyAtTime:timestamp sessionID:sessionID];
- }
- }
- - (void)onConnection:(FWebSocketConnection *)conn
- readyAtTime:(NSNumber *)timestamp
- sessionID:(NSString *)sessionID {
- FFLog(@"I-RDB082014", @"Realtime connection established");
- state = REALTIME_STATE_CONNECTED;
- [self.delegate onReady:self atTime:timestamp sessionID:sessionID];
- }
- - (void)onReset:(NSString *)host {
- FFLog(
- @"I-RDB082015",
- @"Got a reset; killing connection to: %@; Updating internalHost to: %@",
- repoInfo.internalHost, host);
- self.repoInfo.internalHost = host;
- // Explicitly close the connection with SERVER_RESET so calling code knows
- // to reconnect immediately.
- [self closeWithReason:DISCONNECT_REASON_SERVER_RESET];
- }
- @end
|