diff --git a/src/MTXClient.h b/src/MTXClient.h index 7b5dde7..9e2882b 100644 --- a/src/MTXClient.h +++ b/src/MTXClient.h @@ -44,6 +44,13 @@ typedef void (^mtx_client_login_block_t)(MTXClient *_Nullable client, */ typedef void (^mtx_client_response_block_t)(id _Nullable exception); +/** + * @brief A block called when an exception occurred during sync. + * + * @param exception The exception which occurred during sync + */ +typedef void (^mtx_sync_exception_handler_block_t)(id exception); + /** * @brief A block called when the room list was fetched. * @@ -92,6 +99,19 @@ typedef void (^mtx_client_room_join_block_t)(OFString *_Nullable roomID, */ @property (readonly, nonatomic) id storage; +/** + * @brief The timeout for sync requests. + * + * Defaults to 5 minutes. + */ +@property (nonatomic) of_time_interval_t syncTimeout; + +/** + * @brief A block to handle exceptions that occurred during sync. + */ +@property (copy, nonatomic) + mtx_sync_exception_handler_block_t syncExceptionHandler; + /** * @brief Creates a new client with the specified access token on the specified * homeserver. @@ -143,12 +163,17 @@ typedef void (^mtx_client_room_join_block_t)(OFString *_Nullable roomID, OF_DESIGNATED_INITIALIZER; /** - * @brief Performs a sync. - * - * @param block A block to call when a sync was performed + * @brief Starts the sync loop. */ -- (void)syncWithTimeout: (of_time_interval_t)timeout - block: (mtx_client_response_block_t)block; +- (void)startSyncLoop; + +/** + * @brief Stops the sync loop. + * + * The currently waiting sync is not aborted, but after it returns, no new sync + * will be started. + */ +- (void)stopSyncLoop; /** * @brief Logs out the device and invalidates the access token. diff --git a/src/MTXClient.m b/src/MTXClient.m index 4f401d2..59cee99 100644 --- a/src/MTXClient.m +++ b/src/MTXClient.m @@ -48,6 +48,10 @@ validateHomeserver(OFURL *homeserver) } @implementation MTXClient +{ + bool _syncing; +} + + (instancetype)clientWithUserID: (OFString *)userID deviceID: (OFString *)deviceID accessToken: (OFString *)accessToken @@ -158,6 +162,7 @@ validateHomeserver(OFURL *homeserver) _accessToken = [accessToken copy]; _homeserver = [homeserver copy]; _storage = [storage retain]; + _syncTimeout = 300; } @catch (id e) { [self release]; @throw e; @@ -196,13 +201,17 @@ validateHomeserver(OFURL *homeserver) homeserver: _homeserver]; } -- (void)syncWithTimeout: (of_time_interval_t)timeout - block: (mtx_client_response_block_t)block +- (void)startSyncLoop { + if (_syncing) + return; + + _syncing = true; + void *pool = objc_autoreleasePoolPush(); MTXRequest *request = [self requestWithPath: @"/_matrix/client/r0/sync"]; - unsigned long long timeoutMs = timeout * 1000; + unsigned long long timeoutMs = _syncTimeout * 1000; OFMutableDictionary *query = [OFMutableDictionary dictionaryWithObject: @(timeoutMs).stringValue forKey: @"timeout"]; @@ -211,21 +220,25 @@ validateHomeserver(OFURL *homeserver) [request performWithBlock: ^ (mtx_response_t response, int statusCode, id exception) { if (exception != nil) { - block(exception); + if (_syncExceptionHandler != NULL) + _syncExceptionHandler(exception); return; } if (statusCode != 200) { - block([MTXSyncFailedException - exceptionWithStatusCode: statusCode - response: response - client: self]); + if (_syncExceptionHandler != NULL) + _syncExceptionHandler([MTXSyncFailedException + exceptionWithStatusCode: statusCode + response: response + client: self]); return; } OFString *nextBatch = response[@"next_batch"]; if (![nextBatch isKindOfClass: OFString.class]) { - block([OFInvalidServerReplyException exception]); + if (_syncExceptionHandler != NULL) + _syncExceptionHandler( + [OFInvalidServerReplyException exception]); return; } @@ -245,16 +258,23 @@ validateHomeserver(OFURL *homeserver) return true; }]; } @catch (id e) { - block(e); + if (_syncExceptionHandler != NULL) + _syncExceptionHandler(e); return; } - block(nil); + if (_syncing) + [self startSyncLoop]; }]; objc_autoreleasePoolPop(pool); } +- (void)stopSyncLoop +{ + _syncing = false; +} + - (void)logOutWithBlock: (mtx_client_response_block_t)block { void *pool = objc_autoreleasePoolPush(); diff --git a/tests/tests.m b/tests/tests.m index 7ccd6dd..bdba02d 100644 --- a/tests/tests.m +++ b/tests/tests.m @@ -63,21 +63,7 @@ OF_APPLICATION_DELEGATE(Tests) _client = [client retain]; of_log(@"Logged in client: %@", _client); - [self sync]; - }]; -} - -- (void)sync -{ - [_client syncWithTimeout: 5 - block: ^ (id exception) { - if (exception != nil) { - of_log(@"Failed to sync: %@", exception); - [OFApplication terminateWithStatus: 1]; - } - - of_log(@"Synced"); - + [_client startSyncLoop]; [self fetchRoomList]; }]; } @@ -110,21 +96,6 @@ OF_APPLICATION_DELEGATE(Tests) _roomID = [roomID copy]; of_log(@"Joined room %@", _roomID); - [self sync2]; - }]; -} - -- (void)sync2 -{ - [_client syncWithTimeout: 5 - block: ^ (id exception) { - if (exception != nil) { - of_log(@"Failed to sync: %@", exception); - [OFApplication terminateWithStatus: 1]; - } - - of_log(@"Synced"); - [self sendMessage]; }]; } @@ -142,7 +113,11 @@ OF_APPLICATION_DELEGATE(Tests) of_log(@"Message sent to %@", _roomID); - [self leaveRoom]; + of_log( + @"Waiting 5 seconds before leaving room and logging out"); + + [self performSelector: @selector(leaveRoom) + afterDelay: 5]; }]; }