mirror of
https://github.com/firebase/firebase-ios-sdk
synced 2026-11-10 22:45:59 +05:45
* [skip ci] [will revert] Add debug printing to `pod_lib_lint.rb`
* Reorganize FirebaseCore libraries for SPM and CP
* [skip ci] Revert "[skip ci] [will revert] Add debug printing to `pod_lib_lint.rb`"
This reverts commit 2a837e39708c21b0a324743ab226bd6c01047de7.
* Review and fix CI
* Remove `heartbeat_logging.yml` and add `core_internal.yml`
* Remove trailing whitespace
* Fix more whitespace 😞
* Fix `core_internal.yml` scheme name
* Update `check_imports.swift` and TODO
* Review
* Add FirebaseCoreInternal pod to Firestore example's Podfile
* [skip ci] Review - remove TODOs
* [skip ci] Remove duplicate `XCTest` import
239 lines
7.8 KiB
Objective-C
239 lines
7.8 KiB
Objective-C
/*
|
|
* 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/Extension/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
|