diff --git a/NextcloudTalk/NCConnectionController.m b/NextcloudTalk/NCConnectionController.m index 49ebf1ba6..f9d03ce6a 100644 --- a/NextcloudTalk/NCConnectionController.m +++ b/NextcloudTalk/NCConnectionController.m @@ -111,7 +111,7 @@ - (void)checkAppState } [self setAppState:kAppStateMissingSignalingConfiguration]; - [[NCSettingsController sharedInstance] updateSignalingConfigurationForAccountId:activeAccount.accountId withCompletionBlock:^(NSError *error) { + [[NCSettingsController sharedInstance] updateSignalingConfigurationForAccountId:activeAccount.accountId withCompletionBlock:^(NCExternalSignalingController * _Nullable signalingServer, NSError *error) { if (error) { [self notifyAppState]; return; diff --git a/NextcloudTalk/NCExternalSignalingController.m b/NextcloudTalk/NCExternalSignalingController.m index c77f64940..ba7656759 100644 --- a/NextcloudTalk/NCExternalSignalingController.m +++ b/NextcloudTalk/NCExternalSignalingController.m @@ -370,7 +370,7 @@ - (void)helloResponseReceived:(NSDictionary *)messageDict sessionChanged = NO; [self.delegate externalSignalingControllerWillRejoinCall:self]; - [[NCRoomsManager sharedInstance] rejoinRoom:_currentRoom completionBlock:^(NSString * _Nullable sessionId, NCRoom * _Nullable room, NSError * _Nullable error, NSInteger statusCode, NSString * _Nullable statusReason) { + [[NCRoomsManager sharedInstance] rejoinRoomForCall:_currentRoom completionBlock:^(NSString * _Nullable sessionId, NCRoom * _Nullable room, NSError * _Nullable error, NSInteger statusCode, NSString * _Nullable statusReason) { [self.delegate externalSignalingControllerShouldRejoinCall:self]; }]; } diff --git a/NextcloudTalk/NCRoomsManagerExtensions.swift b/NextcloudTalk/NCRoomsManagerExtensions.swift index 670140c12..04e17c469 100644 --- a/NextcloudTalk/NCRoomsManagerExtensions.swift +++ b/NextcloudTalk/NCRoomsManagerExtensions.swift @@ -7,6 +7,7 @@ import Foundation @objc extension NCRoomsManager { + public static let statusCodeFailedToJoinExternal = 997 public static let statusCodeShouldIgnoreAttemptButJoinedSuccessfully = 998 public static let statusCodeIgnoreJoinAttempt = 999 @@ -35,6 +36,8 @@ import Foundation userInfo["token"] = token if let roomController = self.activeRooms[token] as? NCRoomController { + NCUtils.log("JoinRoomHelper: Found active room controller") + if call { roomController.inCall = true } else { @@ -155,7 +158,13 @@ import Foundation // 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.getExternalSignalingHelper(for: activeAccount, forRoom: token, forCall: call) { extSignalingController, signalingSettings in + self.getExternalSignalingHelper(for: activeAccount, forRoom: token) { extSignalingController, signalingSettings, error in + guard error == nil else { + // There was an error to ensure we have the correct signaling settings for joining a federated conversation + completionBlock(nil, nil, nil, NCRoomsManager.statusCodeFailedToJoinExternal, nil) + return + } + guard let extSignalingController else { // Joined room in NC successfully and no external signaling server configured. completionBlock(sessionId, room, nil, 0, nil) @@ -193,28 +202,34 @@ import Foundation }) } - 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 + private func getExternalSignalingHelper(for account: TalkAccount, forRoom token: String, withCompletion completion: @escaping (NCExternalSignalingController?, SignalingSettings?, Error?) -> Void) { let room = NCDatabaseManager.sharedInstance().room(withToken: token, forAccountId: account.accountId) - guard call || room?.supportsFederatedCalling ?? false else { - completion(nil, nil) + guard room?.supportsFederatedCalling ?? false else { + // No federated room -> just ensure that we have a signaling configuration and a potential external signaling controller + NCSettingsController.sharedInstance().ensureSignalingConfiguration(forAccountId: account.accountId, with: nil) { extSignalingController in + completion(extSignalingController, nil, nil) + } + return } + // This is a federated conversation (with federated calling supported), so we require signaling settings for joining + // the external signaling controller NCAPIController.sharedInstance().getSignalingSettings(for: account, forRoom: token) { signalingSettings, _ in guard let signalingSettings else { - completion(nil, nil) + // We need to fail if we are unable to get signaling settings for a federation conversation + completion(nil, nil, NSError(domain: NSCocoaErrorDomain, code: 0)) return } NCSettingsController.sharedInstance().ensureSignalingConfiguration(forAccountId: account.accountId, with: signalingSettings) { extSignalingController in - completion(extSignalingController, signalingSettings) + completion(extSignalingController, signalingSettings, nil) } } } - public func rejoinRoom(_ token: String, completionBlock: @escaping (_ sessionId: String?, _ room: NCRoom?, _ error: Error?, _ statusCode: Int, _ statusReason: String?) -> Void) { + public func rejoinRoomForCall(_ 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 } @@ -225,10 +240,15 @@ import Foundation self.joinRoomTask = NCAPIController.sharedInstance().joinRoom(token, for: activeAccount, withCompletionBlock: { sessionId, room, error, statusCode, statusReason in if error == nil { roomController.userSessionId = sessionId - roomController.inChat = true + roomController.inCall = true + + self.getExternalSignalingHelper(for: activeAccount, forRoom: token) { extSignalingController, signalingSettings, error in + guard error == nil else { + // There was an error to ensure we have the correct signaling settings for joining a federated conversation + completionBlock(nil, nil, nil, NCRoomsManager.statusCodeFailedToJoinExternal, 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) diff --git a/NextcloudTalk/NCSettingsController.h b/NextcloudTalk/NCSettingsController.h index 224db0ab5..36e49f9da 100644 --- a/NextcloudTalk/NCSettingsController.h +++ b/NextcloudTalk/NCSettingsController.h @@ -35,9 +35,8 @@ extern NSString * const NCSettingsControllerDidChangeActiveAccountNotification; typedef void (^UpdatedProfileCompletionBlock)(NSError *error); typedef void (^LogoutCompletionBlock)(NSError *error); typedef void (^GetCapabilitiesCompletionBlock)(NSError *error); -typedef void (^UpdateSignalingConfigCompletionBlock)(NSError *error); +typedef void (^UpdateSignalingConfigCompletionBlock)(NCExternalSignalingController * _Nullable signalingServer, NSError * _Nullable error); typedef void (^SubscribeForPushNotificationsCompletionBlock)(BOOL success); -typedef void (^SetSignalingConfigCompletionBlock)(NCExternalSignalingController * _Nullable signalingServer); typedef void (^EnsureSignalingConfigCompletionBlock)(NCExternalSignalingController * _Nullable signalingServer); typedef NS_ENUM(NSInteger, NCPreferredFileSorting) { @@ -60,8 +59,8 @@ typedef NS_ENUM(NSInteger, NCPreferredFileSorting) { - (void)logoutAccountWithAccountId:(NSString *)accountId withCompletionBlock:(LogoutCompletionBlock)block; - (void)getCapabilitiesForAccountId:(NSString *)accountId withCompletionBlock:(GetCapabilitiesCompletionBlock)block; - (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)setSignalingConfigurationForAccountId:(NSString * _Nonnull)accountId withSettings:(SignalingSettings * _Nonnull)settings; +- (void)ensureSignalingConfigurationForAccountId:(NSString * _Nonnull)accountId withSettings:(SignalingSettings * _Nullable)settings withCompletionBlock:(EnsureSignalingConfigCompletionBlock _Nonnull)block; - (NCExternalSignalingController * _Nullable)externalSignalingControllerForAccountId:(NSString * _Nonnull)accountId; - (void)connectDisconnectedExternalSignalingControllers; - (void)disconnectAllExternalSignalingControllers; diff --git a/NextcloudTalk/NCSettingsController.m b/NextcloudTalk/NCSettingsController.m index f30d74b5d..dc782ab88 100644 --- a/NextcloudTalk/NCSettingsController.m +++ b/NextcloudTalk/NCSettingsController.m @@ -283,7 +283,7 @@ - (void)talkConfigurationHasChanged:(NSNotification *)notification BGTaskHelper *bgTask = [BGTaskHelper startBackgroundTaskWithName:@"NCUpdateSignalingConfiguration" expirationHandler:nil]; - [[NCSettingsController sharedInstance] updateSignalingConfigurationForAccountId:accountId withCompletionBlock:^(NSError *error) { + [[NCSettingsController sharedInstance] updateSignalingConfigurationForAccountId:accountId withCompletionBlock:^(NCExternalSignalingController * _Nullable signalingServer, NSError *error) { if (!error) { [[NCDatabaseManager sharedInstance] updateTalkConfigurationHashForAccountId:accountId withHash:configurationHash]; } @@ -464,7 +464,7 @@ - (void)updateSignalingConfigurationForAccountId:(NSString *)accountId withCompl if (!account) { if (block) { NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:0 userInfo:nil]; - block(error); + block(nil, error); } return; @@ -473,56 +473,71 @@ - (void)updateSignalingConfigurationForAccountId:(NSString *)accountId withCompl [[NCAPIController sharedInstance] getSignalingSettingsFor:account forRoom:nil completionBlock:^(SignalingSettings * _Nullable settings, NSError * _Nullable error) { if (!error) { if (settings && account && account.accountId) { - [self setSignalingConfigurationForAccountId:account.accountId withSettings:settings withCompletionBlock:^(NCExternalSignalingController * _Nullable signalingServer) { - if (block) { - block(nil); - } - }]; + NCExternalSignalingController *extSignalingController = [self setSignalingConfigurationForAccountId:account.accountId withSettings:settings]; + + if (block) { + block(extSignalingController, nil); + } } else { NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:0 userInfo:nil]; if (block) { - block(error); + block(nil, error); } } } else { NSLog(@"Error while getting signaling configuration"); - if (block) block(error); + if (block) { + block(nil, error); + } } }]; } // SetSignalingConfiguration should be called just once -- (void)setSignalingConfigurationForAccountId:(NSString *)accountId withSettings:(SignalingSettings * _Nonnull)signalingSettings withCompletionBlock:(SetSignalingConfigCompletionBlock)block +- (NCExternalSignalingController * _Nullable)setSignalingConfigurationForAccountId:(NSString *)accountId withSettings:(SignalingSettings * _Nonnull)signalingSettings { [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]; + NCExternalSignalingController *extSignalingController = [self->_externalSignalingControllers objectForKey:accountId]; - dispatch_async(dispatch_get_main_queue(), ^{ - NCExternalSignalingController *extSignalingController = [self->_externalSignalingControllers objectForKey:accountId]; - - if (extSignalingController) { - [extSignalingController disconnect]; - } - - TalkAccount *account = [[NCDatabaseManager sharedInstance] talkAccountForAccountId:accountId]; - extSignalingController = [[NCExternalSignalingController alloc] initWithAccount:account server:signalingSettings.server andTicket:signalingSettings.ticket]; - [self->_externalSignalingControllers setObject:extSignalingController forKey:accountId]; + if (extSignalingController) { + [extSignalingController disconnect]; + } - if (block) { - block(extSignalingController); - } + TalkAccount *account = [[NCDatabaseManager sharedInstance] talkAccountForAccountId:accountId]; + extSignalingController = [[NCExternalSignalingController alloc] initWithAccount:account server:signalingSettings.server andTicket:signalingSettings.ticket]; + [self->_externalSignalingControllers setObject:extSignalingController forKey:accountId]; - [bgTask stopBackgroundTask]; - }); + [bgTask stopBackgroundTask]; - return; + return extSignalingController; } - if (block) { - block(nil); + return nil; +} + +- (void)ensureSignalingConfigurationForAccountId:(NSString *)accountId withSettings:(SignalingSettings *)settings withCompletionBlock:(EnsureSignalingConfigCompletionBlock)block +{ + SignalingSettings *currentSignalingSettings = [_signalingConfigurations objectForKey:accountId]; + + if (currentSignalingSettings) { + block([self->_externalSignalingControllers objectForKey:accountId]); + } else { + [NCUtils log:@"Ensure signaling configuration -> Setting configuration"]; + + if (settings) { + // In case settings are provided, we use these provided settings + NCExternalSignalingController *extSignalingController = [self setSignalingConfigurationForAccountId:accountId withSettings:settings]; + block(extSignalingController); + } else { + // There were no settings provided for that call, we have to update the settings + [self updateSignalingConfigurationForAccountId:accountId withCompletionBlock:^(NCExternalSignalingController * _Nullable signalingServer, NSError *error) { + block(signalingServer); + }]; + } } }