diff --git a/NextcloudTalk/NCCallController.m b/NextcloudTalk/NCCallController.m index dbf8c8a30..017f12f7a 100644 --- a/NextcloudTalk/NCCallController.m +++ b/NextcloudTalk/NCCallController.m @@ -97,6 +97,9 @@ - (instancetype)initWithDelegate:(id)delegate inRoom:( _signalingController.observer = self; _account = [[NCDatabaseManager sharedInstance] activeAccount]; + + // NCCallController is only initialized after joining the room. At that point we ensured that there's + // an external signaling controller set, in case we are using external signaling. _externalSignalingController = [[NCSettingsController sharedInstance] externalSignalingControllerForAccountId:_account.accountId]; _externalSignalingController.delegate = self; diff --git a/NextcloudTalk/NCConnectionController.m b/NextcloudTalk/NCConnectionController.m index e969deb3b..49ebf1ba6 100644 --- a/NextcloudTalk/NCConnectionController.m +++ b/NextcloudTalk/NCConnectionController.m @@ -111,14 +111,12 @@ - (void)checkAppState } [self setAppState:kAppStateMissingSignalingConfiguration]; - [[NCSettingsController sharedInstance] getSignalingConfigurationForAccountId:activeAccount.accountId withCompletionBlock:^(NSError *error) { + [[NCSettingsController sharedInstance] updateSignalingConfigurationForAccountId:activeAccount.accountId withCompletionBlock:^(NSError *error) { if (error) { [self notifyAppState]; return; } - // SetSignalingConfiguration should be called just once - [[NCSettingsController sharedInstance] setSignalingConfigurationForAccountId:activeAccount.accountId]; [self checkAppState]; }]; }]; diff --git a/NextcloudTalk/NCRoomsManagerExtensions.swift b/NextcloudTalk/NCRoomsManagerExtensions.swift index 47f790cdd..670140c12 100644 --- a/NextcloudTalk/NCRoomsManagerExtensions.swift +++ b/NextcloudTalk/NCRoomsManagerExtensions.swift @@ -13,6 +13,8 @@ import Foundation // MARK: - Join/Leave room public func joinRoom(_ token: String, forCall call: Bool) { + NCUtils.log("Joining room \(token) for call \(call)") + // Clean up joining room flag and attempts self.joiningRoomToken = nil self.joiningSessionId = nil @@ -150,19 +152,18 @@ import Foundation NCUtils.log("Joined room \(token) in NC successfully") - guard let extSignalingController = NCSettingsController.sharedInstance().externalSignalingController(forAccountId: activeAccount.accountId) - else { - // Joined room in NC successfully and no external signaling server configured. - completionBlock(sessionId, room, nil, 0, nil) - return - } - - NCUtils.log("Trying to join room \(token) in external signaling server...") - // Remember the latest sessionId we're using to join a room, to be able to check when joining the external signaling server self.joiningSessionId = sessionId - self.getSignalingSettingsHelper(for: activeAccount, forRoom: token) { signalingSettings in + self.getExternalSignalingHelper(for: activeAccount, forRoom: token, forCall: call) { extSignalingController, signalingSettings in + guard let extSignalingController else { + // Joined room in NC successfully and no external signaling server configured. + completionBlock(sessionId, room, nil, 0, nil) + return + } + + NCUtils.log("Trying to join room \(token) in external signaling server...") + let federation = signalingSettings?.getFederationJoinDictionary() extSignalingController.joinRoom(token, withSessionId: sessionId, withFederation: federation) { error in @@ -192,18 +193,30 @@ import Foundation }) } - private func getSignalingSettingsHelper(for account: TalkAccount, forRoom token: String, withCompletion completion: @escaping (SignalingSettings?) -> Void) { - // Currently we only need the signaling settings in case the room supports federation-v2 - if let room = NCDatabaseManager.sharedInstance().room(withToken: token, forAccountId: account.accountId), room.supportsFederatedCalling { - NCAPIController.sharedInstance().getSignalingSettings(for: account, forRoom: token) { signalingSettings, _ in - completion(signalingSettings) + private func getExternalSignalingHelper(for account: TalkAccount, forRoom token: String, forCall call: Bool, withCompletion completion: @escaping (NCExternalSignalingController?, SignalingSettings?) -> Void) { + // Currently there are 2 cases where we need to fetch the signaling settings in all cases, a federated room or joining for calling + let room = NCDatabaseManager.sharedInstance().room(withToken: token, forAccountId: account.accountId) + + guard call || room?.supportsFederatedCalling ?? false else { + completion(nil, nil) + return + } + + NCAPIController.sharedInstance().getSignalingSettings(for: account, forRoom: token) { signalingSettings, _ in + guard let signalingSettings else { + completion(nil, nil) + return + } + + NCSettingsController.sharedInstance().ensureSignalingConfiguration(forAccountId: account.accountId, with: signalingSettings) { extSignalingController in + completion(extSignalingController, signalingSettings) } - } else { - completion(nil) } } public func rejoinRoom(_ token: String, completionBlock: @escaping (_ sessionId: String?, _ room: NCRoom?, _ error: Error?, _ statusCode: Int, _ statusReason: String?) -> Void) { + NCUtils.log("Rejoining room \(token)") + guard let roomController = self.activeRooms[token] as? NCRoomController else { return } let activeAccount = NCDatabaseManager.sharedInstance().activeAccount() @@ -214,14 +227,14 @@ import Foundation roomController.userSessionId = sessionId roomController.inChat = true - guard let extSignalingController = NCSettingsController.sharedInstance().externalSignalingController(forAccountId: activeAccount.accountId) - else { - // Joined room in NC successfully and no external signaling server configured. - completionBlock(sessionId, room, nil, 0, nil) - return - } + // Re-joining is currently only happening for calls, so always fetch the signaling settings + self.getExternalSignalingHelper(for: activeAccount, forRoom: token, forCall: true) { extSignalingController, signalingSettings in + guard let extSignalingController else { + // Joined room in NC successfully and no external signaling server configured. + completionBlock(sessionId, room, nil, 0, nil) + return + } - self.getSignalingSettingsHelper(for: activeAccount, forRoom: token) { signalingSettings in let federation = signalingSettings?.getFederationJoinDictionary() extSignalingController.joinRoom(token, withSessionId: sessionId, withFederation: federation) { error in @@ -247,6 +260,8 @@ import Foundation public func leaveRoom(_ token: String) { // Check if leaving the room we are joining if self.isJoiningRoom(withToken: token) { + NCUtils.log("Leaving room \(token), but still joining -> cancel") + self.joiningRoomToken = nil self.joiningSessionId = nil self.joinRoomTask?.cancel() diff --git a/NextcloudTalk/NCSettingsController.h b/NextcloudTalk/NCSettingsController.h index 49d37fd7d..224db0ab5 100644 --- a/NextcloudTalk/NCSettingsController.h +++ b/NextcloudTalk/NCSettingsController.h @@ -29,19 +29,22 @@ extern NSString * const kUserProfileScopePublished; extern NSString * const NCSettingsControllerDidChangeActiveAccountNotification; +@class NCExternalSignalingController; +@class SignalingSettings; + typedef void (^UpdatedProfileCompletionBlock)(NSError *error); typedef void (^LogoutCompletionBlock)(NSError *error); typedef void (^GetCapabilitiesCompletionBlock)(NSError *error); -typedef void (^GetSignalingConfigCompletionBlock)(NSError *error); +typedef void (^UpdateSignalingConfigCompletionBlock)(NSError *error); typedef void (^SubscribeForPushNotificationsCompletionBlock)(BOOL success); +typedef void (^SetSignalingConfigCompletionBlock)(NCExternalSignalingController * _Nullable signalingServer); +typedef void (^EnsureSignalingConfigCompletionBlock)(NCExternalSignalingController * _Nullable signalingServer); typedef NS_ENUM(NSInteger, NCPreferredFileSorting) { NCAlphabeticalSorting = 1, NCModificationDateSorting }; -@class NCExternalSignalingController; - @interface NCSettingsController : NSObject @property (nonatomic, copy) ARDSettingsModel *videoSettingsModel; @@ -56,9 +59,10 @@ typedef NS_ENUM(NSInteger, NCPreferredFileSorting) { - (void)getUserProfileForAccountId:(NSString *)accountId withCompletionBlock:(UpdatedProfileCompletionBlock)block; - (void)logoutAccountWithAccountId:(NSString *)accountId withCompletionBlock:(LogoutCompletionBlock)block; - (void)getCapabilitiesForAccountId:(NSString *)accountId withCompletionBlock:(GetCapabilitiesCompletionBlock)block; -- (void)getSignalingConfigurationForAccountId:(NSString *)accountId withCompletionBlock:(GetSignalingConfigCompletionBlock)block; -- (void)setSignalingConfigurationForAccountId:(NSString *)accountId; -- (NCExternalSignalingController *)externalSignalingControllerForAccountId:(NSString *)accountId; +- (void)updateSignalingConfigurationForAccountId:(NSString * _Nonnull)accountId withCompletionBlock:(UpdateSignalingConfigCompletionBlock _Nonnull)block; +- (void)setSignalingConfigurationForAccountId:(NSString * _Nonnull)accountId withSettings:(SignalingSettings * _Nonnull)settings withCompletionBlock:(SetSignalingConfigCompletionBlock _Nonnull)block; +- (void)ensureSignalingConfigurationForAccountId:(NSString * _Nonnull)accountId withSettings:(SignalingSettings * _Nonnull)settings withCompletionBlock:(EnsureSignalingConfigCompletionBlock _Nonnull)block; +- (NCExternalSignalingController * _Nullable)externalSignalingControllerForAccountId:(NSString * _Nonnull)accountId; - (void)connectDisconnectedExternalSignalingControllers; - (void)disconnectAllExternalSignalingControllers; - (void)subscribeForPushNotificationsForAccountId:(NSString *)accountId withCompletionBlock:(SubscribeForPushNotificationsCompletionBlock)block; diff --git a/NextcloudTalk/NCSettingsController.m b/NextcloudTalk/NCSettingsController.m index 34858e192..f30d74b5d 100644 --- a/NextcloudTalk/NCSettingsController.m +++ b/NextcloudTalk/NCSettingsController.m @@ -88,7 +88,7 @@ - (id)init _videoSettingsModel = [[ARDSettingsModel alloc] init]; _signalingConfigurations = [NSMutableDictionary new]; _externalSignalingControllers = [NSMutableDictionary new]; - + [self configureDatabase]; [self checkStoredDataInKechain]; @@ -281,16 +281,12 @@ - (void)talkConfigurationHasChanged:(NSNotification *)notification return; } - [[NCSettingsController sharedInstance] getSignalingConfigurationForAccountId:accountId withCompletionBlock:^(NSError *error) { - if (error) { - return; - } - - BGTaskHelper *bgTask = [BGTaskHelper startBackgroundTaskWithName:@"NCUpdateSignalingConfiguration" expirationHandler:nil]; + BGTaskHelper *bgTask = [BGTaskHelper startBackgroundTaskWithName:@"NCUpdateSignalingConfiguration" expirationHandler:nil]; - // SetSignalingConfiguration should be called just once - [[NCSettingsController sharedInstance] setSignalingConfigurationForAccountId:accountId]; - [[NCDatabaseManager sharedInstance] updateTalkConfigurationHashForAccountId:accountId withHash:configurationHash]; + [[NCSettingsController sharedInstance] updateSignalingConfigurationForAccountId:accountId withCompletionBlock:^(NSError *error) { + if (!error) { + [[NCDatabaseManager sharedInstance] updateTalkConfigurationHashForAccountId:accountId withHash:configurationHash]; + } [bgTask stopBackgroundTask]; }]; @@ -461,7 +457,7 @@ - (void)switchToAnyInactiveAccount #pragma mark - Signaling Configuration -- (void)getSignalingConfigurationForAccountId:(NSString *)accountId withCompletionBlock:(GetSignalingConfigCompletionBlock)block +- (void)updateSignalingConfigurationForAccountId:(NSString *)accountId withCompletionBlock:(UpdateSignalingConfigCompletionBlock)block { TalkAccount *account = [[NCDatabaseManager sharedInstance] talkAccountForAccountId:accountId]; @@ -477,11 +473,11 @@ - (void)getSignalingConfigurationForAccountId:(NSString *)accountId withCompleti [[NCAPIController sharedInstance] getSignalingSettingsFor:account forRoom:nil completionBlock:^(SignalingSettings * _Nullable settings, NSError * _Nullable error) { if (!error) { if (settings && account && account.accountId) { - [self->_signalingConfigurations setObject:settings forKey:account.accountId]; - - if (block) { - block(nil); - } + [self setSignalingConfigurationForAccountId:account.accountId withSettings:settings withCompletionBlock:^(NCExternalSignalingController * _Nullable signalingServer) { + if (block) { + block(nil); + } + }]; } else { NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:0 userInfo:nil]; @@ -497,9 +493,9 @@ - (void)getSignalingConfigurationForAccountId:(NSString *)accountId withCompleti } // SetSignalingConfiguration should be called just once -- (void)setSignalingConfigurationForAccountId:(NSString *)accountId +- (void)setSignalingConfigurationForAccountId:(NSString *)accountId withSettings:(SignalingSettings * _Nonnull)signalingSettings withCompletionBlock:(SetSignalingConfigCompletionBlock)block { - SignalingSettings *signalingSettings = [_signalingConfigurations objectForKey:accountId]; + [self->_signalingConfigurations setObject:signalingSettings forKey:accountId]; if (signalingSettings.server && signalingSettings.server.length > 0 && signalingSettings.ticket && signalingSettings.ticket.length > 0) { BGTaskHelper *bgTask = [BGTaskHelper startBackgroundTaskWithName:@"NCSetSignalingConfiguration" expirationHandler:nil]; @@ -515,8 +511,18 @@ - (void)setSignalingConfigurationForAccountId:(NSString *)accountId extSignalingController = [[NCExternalSignalingController alloc] initWithAccount:account server:signalingSettings.server andTicket:signalingSettings.ticket]; [self->_externalSignalingControllers setObject:extSignalingController forKey:accountId]; + if (block) { + block(extSignalingController); + } + [bgTask stopBackgroundTask]; }); + + return; + } + + if (block) { + block(nil); } }