зеркало из https://github.com/nextcloud/talk-ios.git
578 строки
27 KiB
Objective-C
578 строки
27 KiB
Objective-C
/**
|
|
* @copyright Copyright (c) 2020 Ivan Sein <ivan@nextcloud.com>
|
|
*
|
|
* @author Ivan Sein <ivan@nextcloud.com>
|
|
*
|
|
* @license GNU GPL version 3 or any later version
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#import "NCChatController.h"
|
|
|
|
#import "NCAPIController.h"
|
|
#import "NCDatabaseManager.h"
|
|
#import "NCRoomsManager.h"
|
|
#import "NCSettingsController.h"
|
|
|
|
NSString * const NCChatControllerDidReceiveInitialChatHistoryNotification = @"NCChatControllerDidReceiveInitialChatHistoryNotification";
|
|
NSString * const NCChatControllerDidReceiveInitialChatHistoryOfflineNotification = @"NCChatControllerDidReceiveInitialChatHistoryOfflineNotification";
|
|
NSString * const NCChatControllerDidReceiveChatHistoryNotification = @"NCChatControllerDidReceiveChatHistoryNotification";
|
|
NSString * const NCChatControllerDidReceiveChatMessagesNotification = @"NCChatControllerDidReceiveChatMessagesNotification";
|
|
NSString * const NCChatControllerDidSendChatMessageNotification = @"NCChatControllerDidSendChatMessageNotification";
|
|
NSString * const NCChatControllerDidReceiveChatBlockedNotification = @"NCChatControllerDidReceiveChatBlockedNotification";
|
|
NSString * const NCChatControllerDidRemoveTemporaryMessagesNotification = @"NCChatControllerDidRemoveTemporaryMessagesNotification";
|
|
|
|
@interface NCChatController ()
|
|
|
|
@property (nonatomic, assign) BOOL stopChatMessagesPoll;
|
|
@property (nonatomic, strong) TalkAccount *account;
|
|
@property (nonatomic, strong) NSURLSessionTask *getHistoryTask;
|
|
@property (nonatomic, strong) NSURLSessionTask *pullMessagesTask;
|
|
|
|
@end
|
|
|
|
@implementation NCChatBlock
|
|
@end
|
|
|
|
@implementation NCChatController
|
|
|
|
- (instancetype)initForRoom:(NCRoom *)room
|
|
{
|
|
self = [super init];
|
|
if (self) {
|
|
_room = room;
|
|
_account = [[NCDatabaseManager sharedInstance] talkAccountForAccountId:_room.accountId];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
#pragma mark - Database
|
|
|
|
- (NSArray *)chatBlocksForRoom
|
|
{
|
|
RLMResults *managedBlocks = [NCChatBlock objectsWhere:@"internalId = %@", _room.internalId];
|
|
RLMResults *managedSortedBlocks = [managedBlocks sortedResultsUsingKeyPath:@"newestMessageId" ascending:YES];
|
|
// Create an unmanaged copy of the blocks
|
|
NSMutableArray *sortedBlocks = [NSMutableArray new];
|
|
for (NCChatBlock *managedBlock in managedSortedBlocks) {
|
|
NCChatBlock *sortedBlock = [[NCChatBlock alloc] initWithValue:managedBlock];
|
|
[sortedBlocks addObject:sortedBlock];
|
|
}
|
|
|
|
return sortedBlocks;
|
|
}
|
|
|
|
- (NSArray *)getBatchOfMessagesInBlock:(NCChatBlock *)chatBlock fromMessageId:(NSInteger)messageId included:(BOOL)included
|
|
{
|
|
NSInteger fromMessageId = messageId > 0 ? messageId : chatBlock.newestMessageId;
|
|
NSPredicate *query = [NSPredicate predicateWithFormat:@"accountId = %@ AND token = %@ AND messageId >= %ld AND messageId < %ld", _account.accountId, _room.token, (long)chatBlock.oldestMessageId, (long)fromMessageId];
|
|
if (included) {
|
|
query = [NSPredicate predicateWithFormat:@"accountId = %@ AND token = %@ AND messageId >= %ld AND messageId <= %ld", _account.accountId, _room.token, (long)chatBlock.oldestMessageId, (long)fromMessageId];
|
|
}
|
|
RLMResults *managedMessages = [NCChatMessage objectsWithPredicate:query];
|
|
RLMResults *managedSortedMessages = [managedMessages sortedResultsUsingKeyPath:@"messageId" ascending:YES];
|
|
// Create an unmanaged copy of the messages
|
|
NSMutableArray *sortedMessages = [NSMutableArray new];
|
|
NSInteger startingIndex = managedSortedMessages.count - kReceivedChatMessagesLimit;
|
|
startingIndex = (startingIndex < 0) ? 0 : startingIndex;
|
|
for (NSInteger i = startingIndex; i < managedSortedMessages.count; i++) {
|
|
NCChatMessage *sortedMessage = [[NCChatMessage alloc] initWithValue:managedSortedMessages[i]];
|
|
[sortedMessages addObject:sortedMessage];
|
|
}
|
|
|
|
return sortedMessages;
|
|
}
|
|
|
|
- (NSArray *)getNewStoredMessagesInBlock:(NCChatBlock *)chatBlock sinceMessageId:(NSInteger)messageId
|
|
{
|
|
NSPredicate *query = [NSPredicate predicateWithFormat:@"accountId = %@ AND token = %@ AND messageId > %ld AND messageId <= %ld", _account.accountId, _room.token, (long)messageId, (long)chatBlock.newestMessageId];
|
|
RLMResults *managedMessages = [NCChatMessage objectsWithPredicate:query];
|
|
RLMResults *managedSortedMessages = [managedMessages sortedResultsUsingKeyPath:@"messageId" ascending:YES];
|
|
// Create an unmanaged copy of the messages
|
|
NSMutableArray *sortedMessages = [NSMutableArray new];
|
|
for (NCChatMessage *managedMessage in managedSortedMessages) {
|
|
NCChatMessage *sortedMessage = [[NCChatMessage alloc] initWithValue:managedMessage];
|
|
[sortedMessages addObject:sortedMessage];
|
|
}
|
|
|
|
return sortedMessages;
|
|
}
|
|
|
|
- (void)storeMessages:(NSArray *)messages
|
|
{
|
|
RLMRealm *realm = [RLMRealm defaultRealm];
|
|
[realm transactionWithBlock:^{
|
|
NSMutableArray *removedTemporaryMessages = [NSMutableArray new];
|
|
// Add or update messages
|
|
for (NSDictionary *messageDict in messages) {
|
|
NCChatMessage *message = [NCChatMessage messageWithDictionary:messageDict andAccountId:_account.accountId];
|
|
NCChatMessage *parent = [NCChatMessage messageWithDictionary:[messageDict objectForKey:@"parent"] andAccountId:_account.accountId];
|
|
message.parentId = parent.internalId;
|
|
|
|
if (message.referenceId && ![message.referenceId isEqualToString:@""]) {
|
|
NCChatMessage *managedTemporaryMessage = [NCChatMessage objectsWhere:@"referenceId = %@", message.referenceId].firstObject;
|
|
if (managedTemporaryMessage) {
|
|
[realm deleteObject:managedTemporaryMessage];
|
|
// Create a unmanaged copy of message, since 'message' will point to a managed object when added to the DB.
|
|
NCChatMessage *unmanagedMessage = [[NCChatMessage alloc] initWithValue:message];
|
|
[removedTemporaryMessages addObject:unmanagedMessage];
|
|
}
|
|
}
|
|
|
|
NCChatMessage *managedMessage = [NCChatMessage objectsWhere:@"internalId = %@", message.internalId].firstObject;
|
|
if (managedMessage) {
|
|
[NCChatMessage updateChatMessage:managedMessage withChatMessage:message];
|
|
} else if (message) {
|
|
[realm addObject:message];
|
|
}
|
|
|
|
NCChatMessage *managedParentMessage = [NCChatMessage objectsWhere:@"internalId = %@", parent.internalId].firstObject;
|
|
if (managedParentMessage) {
|
|
[NCChatMessage updateChatMessage:managedParentMessage withChatMessage:parent];
|
|
} else if (parent) {
|
|
[realm addObject:parent];
|
|
}
|
|
}
|
|
// Send notification with removed temprary messages
|
|
if (removedTemporaryMessages.count > 0) {
|
|
NSMutableDictionary *userInfo = [NSMutableDictionary new];
|
|
[userInfo setObject:_room.token forKey:@"room"];
|
|
[userInfo setObject:removedTemporaryMessages forKey:@"messages"];
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:NCChatControllerDidRemoveTemporaryMessagesNotification
|
|
object:self
|
|
userInfo:userInfo];
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (void)updateLastChatBlockWithNewestKnown:(NSInteger)newestKnown
|
|
{
|
|
RLMRealm *realm = [RLMRealm defaultRealm];
|
|
[realm transactionWithBlock:^{
|
|
RLMResults *managedBlocks = [NCChatBlock objectsWhere:@"internalId = %@", _room.internalId];
|
|
RLMResults *managedSortedBlocks = [managedBlocks sortedResultsUsingKeyPath:@"newestMessageId" ascending:YES];
|
|
NCChatBlock *lastBlock = managedSortedBlocks.lastObject;
|
|
if (newestKnown > 0) {
|
|
lastBlock.newestMessageId = newestKnown;
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (void)updateChatBlocksWithLastKnown:(NSInteger)lastKnown
|
|
{
|
|
if (lastKnown <= 0) {
|
|
return;
|
|
}
|
|
|
|
RLMRealm *realm = [RLMRealm defaultRealm];
|
|
[realm transactionWithBlock:^{
|
|
RLMResults *managedBlocks = [NCChatBlock objectsWhere:@"internalId = %@", _room.internalId];
|
|
RLMResults *managedSortedBlocks = [managedBlocks sortedResultsUsingKeyPath:@"newestMessageId" ascending:YES];
|
|
NCChatBlock *lastBlock = managedSortedBlocks.lastObject;
|
|
// There is more than one chat block stored
|
|
if (managedSortedBlocks.count > 1) {
|
|
for (NSInteger i = managedSortedBlocks.count - 2; i >= 0; i--) {
|
|
NCChatBlock *block = managedSortedBlocks[i];
|
|
// Merge blocks if the lastKnown message is inside the current block
|
|
if (lastKnown >= block.oldestMessageId && lastKnown <= block.newestMessageId) {
|
|
lastBlock.oldestMessageId = block.oldestMessageId;
|
|
[realm deleteObject:block];
|
|
break;
|
|
// Update lastBlock if the lastKnown message is between the 2 blocks
|
|
} else if (lastKnown > block.newestMessageId) {
|
|
lastBlock.oldestMessageId = lastKnown;
|
|
break;
|
|
// The current block is completely included in the retrieved history
|
|
// This could happen if we vary the message limit when fetching messages
|
|
// Delete included block
|
|
} else if (lastKnown < block.oldestMessageId) {
|
|
[realm deleteObject:block];
|
|
}
|
|
}
|
|
// There is just one chat block stored
|
|
} else {
|
|
lastBlock.oldestMessageId = lastKnown;
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (void)updateChatBlocksWithReceivedMessages:(NSArray *)messages newestKnown:(NSInteger)newestKnown andLastKnown:(NSInteger)lastKnown
|
|
{
|
|
NSArray *sortedMessages = [self sortedMessagesFromMessageArray:messages];
|
|
NCChatMessage *newestMessageReceived = sortedMessages.lastObject;
|
|
NSInteger newestMessageKnown = newestKnown > 0 ? newestKnown : newestMessageReceived.messageId;
|
|
|
|
RLMRealm *realm = [RLMRealm defaultRealm];
|
|
[realm transactionWithBlock:^{
|
|
RLMResults *managedBlocks = [NCChatBlock objectsWhere:@"internalId = %@", _room.internalId];
|
|
RLMResults *managedSortedBlocks = [managedBlocks sortedResultsUsingKeyPath:@"newestMessageId" ascending:YES];
|
|
|
|
// Create new chat block
|
|
NCChatBlock *newBlock = [[NCChatBlock alloc] init];
|
|
newBlock.internalId = _room.internalId;
|
|
newBlock.accountId = _room.accountId;
|
|
newBlock.token = _room.token;
|
|
newBlock.oldestMessageId = lastKnown;
|
|
newBlock.newestMessageId = newestMessageKnown;
|
|
newBlock.hasHistory = YES;
|
|
|
|
// There is at least one chat block stored
|
|
if (managedSortedBlocks.count > 0) {
|
|
for (NSInteger i = managedSortedBlocks.count - 1; i >= 0; i--) {
|
|
NCChatBlock *block = managedSortedBlocks[i];
|
|
// Merge blocks if the lastKnown message is inside the current block
|
|
if (lastKnown >= block.oldestMessageId && lastKnown <= block.newestMessageId) {
|
|
block.newestMessageId = newestMessageKnown;
|
|
break;
|
|
// Add new block if it didn't reach the previous block
|
|
} else if (lastKnown > block.newestMessageId) {
|
|
[realm addObject:newBlock];
|
|
break;
|
|
// The current block is completely included in the retrieved history
|
|
// This could happen if we vary the message limit when fetching messages
|
|
// Delete included block
|
|
} else if (lastKnown < block.oldestMessageId) {
|
|
[realm deleteObject:block];
|
|
}
|
|
}
|
|
// No chat blocks stored yet, add new chat block
|
|
} else {
|
|
[realm addObject:newBlock];
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (void)updateHistoryFlagInFirstBlock
|
|
{
|
|
RLMRealm *realm = [RLMRealm defaultRealm];
|
|
[realm transactionWithBlock:^{
|
|
RLMResults *managedBlocks = [NCChatBlock objectsWhere:@"internalId = %@", _room.internalId];
|
|
RLMResults *managedSortedBlocks = [managedBlocks sortedResultsUsingKeyPath:@"newestMessageId" ascending:YES];
|
|
NCChatBlock *firstChatBlock = managedSortedBlocks.firstObject;
|
|
firstChatBlock.hasHistory = NO;
|
|
}];
|
|
}
|
|
|
|
- (void)setSendingFailedToMessageWithReferenceId:(NSString *)referenceId
|
|
{
|
|
RLMRealm *realm = [RLMRealm defaultRealm];
|
|
[realm transactionWithBlock:^{
|
|
NCChatMessage *managedChatMessage = [NCChatMessage objectsWhere:@"referenceId = %@", referenceId].firstObject;
|
|
managedChatMessage.sendingFailed = YES;
|
|
}];
|
|
}
|
|
|
|
- (NSArray *)sortedMessagesFromMessageArray:(NSArray *)messages
|
|
{
|
|
NSMutableArray *sortedMessages = [[NSMutableArray alloc] initWithCapacity:messages.count];
|
|
for (NSDictionary *messageDict in messages) {
|
|
NCChatMessage *message = [NCChatMessage messageWithDictionary:messageDict];
|
|
[sortedMessages addObject:message];
|
|
}
|
|
// Sort by messageId
|
|
NSSortDescriptor *valueDescriptor = [[NSSortDescriptor alloc] initWithKey:@"messageId" ascending:YES];
|
|
NSArray *descriptors = [NSArray arrayWithObject:valueDescriptor];
|
|
[sortedMessages sortUsingDescriptors:descriptors];
|
|
|
|
return sortedMessages;
|
|
}
|
|
|
|
#pragma mark - Chat
|
|
|
|
- (NSMutableArray *)getTemporaryMessages
|
|
{
|
|
NSPredicate *query = [NSPredicate predicateWithFormat:@"accountId = %@ AND token = %@ AND isTemporary = true", _account.accountId, _room.token];
|
|
RLMResults *managedTemporaryMessages = [NCChatMessage objectsWithPredicate:query];
|
|
RLMResults *managedSortedTemporaryMessages = [managedTemporaryMessages sortedResultsUsingKeyPath:@"timestamp" ascending:YES];
|
|
// Mark temporary messages sent more than 1 min ago as failed-to-send messages
|
|
NSInteger oneMinAgoTimestamp = [[NSDate date] timeIntervalSince1970] - 60;
|
|
for (NCChatMessage *temporaryMessage in managedTemporaryMessages) {
|
|
if (temporaryMessage.timestamp < oneMinAgoTimestamp) {
|
|
RLMRealm *realm = [RLMRealm defaultRealm];
|
|
[realm transactionWithBlock:^{
|
|
temporaryMessage.sendingFailed = YES;
|
|
}];
|
|
}
|
|
}
|
|
// Create an unmanaged copy of the messages
|
|
NSMutableArray *sortedMessages = [NSMutableArray new];
|
|
for (NCChatMessage *managedMessage in managedSortedTemporaryMessages) {
|
|
NCChatMessage *sortedMessage = [[NCChatMessage alloc] initWithValue:managedMessage];
|
|
[sortedMessages addObject:sortedMessage];
|
|
}
|
|
|
|
return sortedMessages;
|
|
}
|
|
|
|
- (void)getInitialChatHistory
|
|
{
|
|
NSMutableDictionary *userInfo = [NSMutableDictionary new];
|
|
[userInfo setObject:_room.token forKey:@"room"];
|
|
|
|
NSInteger lastReadMessageId = 0;
|
|
if ([[NCSettingsController sharedInstance] serverHasTalkCapability:kCapabilityChatReadMarker]) {
|
|
lastReadMessageId = _room.lastReadMessage;
|
|
}
|
|
|
|
NCChatBlock *lastChatBlock = [self chatBlocksForRoom].lastObject;
|
|
if (lastChatBlock.newestMessageId > 0 && lastChatBlock.newestMessageId >= lastReadMessageId) {
|
|
NSArray *storedMessages = [self getBatchOfMessagesInBlock:lastChatBlock fromMessageId:lastChatBlock.newestMessageId included:YES];
|
|
[userInfo setObject:storedMessages forKey:@"messages"];
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:NCChatControllerDidReceiveInitialChatHistoryNotification
|
|
object:self
|
|
userInfo:userInfo];
|
|
} else {
|
|
_pullMessagesTask = [[NCAPIController sharedInstance] receiveChatMessagesOfRoom:_room.token fromLastMessageId:lastReadMessageId history:YES includeLastMessage:YES timeout:NO forAccount:_account withCompletionBlock:^(NSArray *messages, NSInteger lastKnownMessage, NSError *error, NSInteger statusCode) {
|
|
if (_stopChatMessagesPoll) {
|
|
return;
|
|
}
|
|
if (error) {
|
|
if ([self isChatBeingBlocked:statusCode]) {
|
|
[self notifyChatIsBlocked];
|
|
return;
|
|
}
|
|
[userInfo setObject:error forKey:@"error"];
|
|
NSLog(@"Could not get initial chat history. Error: %@", error.description);
|
|
} else {
|
|
// Update chat blocks
|
|
[self updateChatBlocksWithReceivedMessages:messages newestKnown:lastReadMessageId andLastKnown:lastKnownMessage];
|
|
// Store new messages
|
|
if (messages.count > 0) {
|
|
[self storeMessages:messages];
|
|
NCChatBlock *lastChatBlock = [self chatBlocksForRoom].lastObject;
|
|
NSArray *storedMessages = [self getBatchOfMessagesInBlock:lastChatBlock fromMessageId:lastReadMessageId included:YES];
|
|
[userInfo setObject:storedMessages forKey:@"messages"];
|
|
}
|
|
}
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:NCChatControllerDidReceiveInitialChatHistoryNotification
|
|
object:self
|
|
userInfo:userInfo];
|
|
}];
|
|
}
|
|
}
|
|
|
|
- (void)getInitialChatHistoryForOfflineMode
|
|
{
|
|
NSMutableDictionary *userInfo = [NSMutableDictionary new];
|
|
[userInfo setObject:_room.token forKey:@"room"];
|
|
|
|
NCChatBlock *lastChatBlock = [self chatBlocksForRoom].lastObject;
|
|
NSArray *storedMessages = [self getBatchOfMessagesInBlock:lastChatBlock fromMessageId:lastChatBlock.newestMessageId included:YES];
|
|
[userInfo setObject:storedMessages forKey:@"messages"];
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:NCChatControllerDidReceiveInitialChatHistoryOfflineNotification
|
|
object:self
|
|
userInfo:userInfo];
|
|
}
|
|
|
|
- (void)getHistoryBatchFromMessagesId:(NSInteger)messageId
|
|
{
|
|
NSMutableDictionary *userInfo = [NSMutableDictionary new];
|
|
[userInfo setObject:_room.token forKey:@"room"];
|
|
|
|
NCChatBlock *lastChatBlock = [self chatBlocksForRoom].lastObject;
|
|
if (lastChatBlock && lastChatBlock.oldestMessageId < messageId) {
|
|
NSArray *storedMessages = [self getBatchOfMessagesInBlock:lastChatBlock fromMessageId:messageId included:NO];
|
|
[userInfo setObject:storedMessages forKey:@"messages"];
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:NCChatControllerDidReceiveChatHistoryNotification
|
|
object:self
|
|
userInfo:userInfo];
|
|
} else {
|
|
_getHistoryTask = [[NCAPIController sharedInstance] receiveChatMessagesOfRoom:_room.token fromLastMessageId:messageId history:YES includeLastMessage:NO timeout:NO forAccount:_account withCompletionBlock:^(NSArray *messages, NSInteger lastKnownMessage, NSError *error, NSInteger statusCode) {
|
|
if (statusCode == 304) {
|
|
[self updateHistoryFlagInFirstBlock];
|
|
}
|
|
if (error) {
|
|
if ([self isChatBeingBlocked:statusCode]) {
|
|
[self notifyChatIsBlocked];
|
|
return;
|
|
}
|
|
[userInfo setObject:error forKey:@"error"];
|
|
if (statusCode != 304) {
|
|
NSLog(@"Could not get chat history. Error: %@", error.description);
|
|
}
|
|
} else {
|
|
// Update chat blocks
|
|
[self updateChatBlocksWithLastKnown:lastKnownMessage];
|
|
// Store new messages
|
|
if (messages.count > 0) {
|
|
[self storeMessages:messages];
|
|
NCChatBlock *lastChatBlock = [self chatBlocksForRoom].lastObject;
|
|
NSArray *historyBatch = [self getBatchOfMessagesInBlock:lastChatBlock fromMessageId:messageId included:NO];
|
|
[userInfo setObject:historyBatch forKey:@"messages"];
|
|
}
|
|
}
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:NCChatControllerDidReceiveChatHistoryNotification
|
|
object:self
|
|
userInfo:userInfo];
|
|
}];
|
|
}
|
|
}
|
|
|
|
- (void)getHistoryBatchOfflineFromMessagesId:(NSInteger)messageId
|
|
{
|
|
NSMutableDictionary *userInfo = [NSMutableDictionary new];
|
|
[userInfo setObject:_room.token forKey:@"room"];
|
|
|
|
NSArray *chatBlocks = [self chatBlocksForRoom];
|
|
NSMutableArray *historyBatch = [NSMutableArray new];
|
|
if (chatBlocks.count > 0) {
|
|
for (NSInteger i = chatBlocks.count - 1; i >= 0; i--) {
|
|
NCChatBlock *currentBlock = chatBlocks[i];
|
|
BOOL noMoreMessagesToRetrieveInBlock = NO;
|
|
if (currentBlock.oldestMessageId < messageId) {
|
|
NSArray *storedMessages = [self getBatchOfMessagesInBlock:currentBlock fromMessageId:messageId included:NO];
|
|
historyBatch = [[NSMutableArray alloc] initWithArray:storedMessages];
|
|
if (storedMessages.count > 0) {
|
|
break;
|
|
} else {
|
|
// We use this flag in case the rest of the messages in current block
|
|
// are system messages invisible for the user.
|
|
noMoreMessagesToRetrieveInBlock = YES;
|
|
}
|
|
}
|
|
if (i > 0 && (currentBlock.oldestMessageId == messageId || noMoreMessagesToRetrieveInBlock)) {
|
|
NCChatBlock *previousBlock = chatBlocks[i - 1];
|
|
NSArray *storedMessages = [self getBatchOfMessagesInBlock:previousBlock fromMessageId:previousBlock.newestMessageId included:YES];
|
|
historyBatch = [[NSMutableArray alloc] initWithArray:storedMessages];
|
|
[userInfo setObject:@(YES) forKey:@"shouldAddBlockSeparator"];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (historyBatch.count == 0) {
|
|
[userInfo setObject:@(YES) forKey:@"noMoreStoredHistory"];
|
|
}
|
|
|
|
[userInfo setObject:historyBatch forKey:@"messages"];
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:NCChatControllerDidReceiveChatHistoryNotification
|
|
object:self
|
|
userInfo:userInfo];
|
|
}
|
|
|
|
- (void)stopReceivingChatHistory
|
|
{
|
|
[_getHistoryTask cancel];
|
|
}
|
|
|
|
- (void)startReceivingChatMessagesFromMessagesId:(NSInteger)messageId withTimeout:(BOOL)timeout
|
|
{
|
|
_stopChatMessagesPoll = NO;
|
|
[_pullMessagesTask cancel];
|
|
_pullMessagesTask = [[NCAPIController sharedInstance] receiveChatMessagesOfRoom:_room.token fromLastMessageId:messageId history:NO includeLastMessage:NO timeout:timeout forAccount:_account withCompletionBlock:^(NSArray *messages, NSInteger lastKnownMessage, NSError *error, NSInteger statusCode) {
|
|
if (_stopChatMessagesPoll) {
|
|
return;
|
|
}
|
|
NSMutableDictionary *userInfo = [NSMutableDictionary new];
|
|
if (error) {
|
|
if ([self isChatBeingBlocked:statusCode]) {
|
|
[self notifyChatIsBlocked];
|
|
return;
|
|
}
|
|
if (statusCode != 304) {
|
|
[userInfo setObject:error forKey:@"error"];
|
|
NSLog(@"Could not get new chat messages. Error: %@", error.description);
|
|
}
|
|
} else {
|
|
// Update last chat block
|
|
[self updateLastChatBlockWithNewestKnown:lastKnownMessage];
|
|
// Store new messages
|
|
if (messages.count > 0) {
|
|
[self storeMessages:messages];
|
|
NCChatBlock *lastChatBlock = [self chatBlocksForRoom].lastObject;
|
|
NSArray *storedMessages = [self getNewStoredMessagesInBlock:lastChatBlock sinceMessageId:messageId];
|
|
[userInfo setObject:storedMessages forKey:@"messages"];
|
|
}
|
|
}
|
|
[userInfo setObject:_room.token forKey:@"room"];
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:NCChatControllerDidReceiveChatMessagesNotification
|
|
object:self
|
|
userInfo:userInfo];
|
|
if (error.code != -999) {
|
|
NCChatBlock *lastChatBlock = [self chatBlocksForRoom].lastObject;
|
|
[self startReceivingChatMessagesFromMessagesId:lastChatBlock.newestMessageId withTimeout:YES];
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (void)startReceivingNewChatMessages
|
|
{
|
|
NCChatBlock *lastChatBlock = [self chatBlocksForRoom].lastObject;
|
|
[self startReceivingChatMessagesFromMessagesId:lastChatBlock.newestMessageId withTimeout:NO];
|
|
}
|
|
|
|
- (void)stopReceivingNewChatMessages
|
|
{
|
|
_stopChatMessagesPoll = YES;
|
|
[_pullMessagesTask cancel];
|
|
}
|
|
|
|
- (void)sendChatMessage:(NSString *)message replyTo:(NSInteger)replyTo referenceId:(NSString *)referenceId
|
|
{
|
|
NSMutableDictionary *userInfo = [NSMutableDictionary new];
|
|
[userInfo setObject:message forKey:@"message"];
|
|
[[NCAPIController sharedInstance] sendChatMessage:message toRoom:_room.token displayName:nil replyTo:replyTo referenceId:referenceId forAccount:_account withCompletionBlock:^(NSError *error) {
|
|
if (referenceId) {
|
|
[userInfo setObject:referenceId forKey:@"referenceId"];
|
|
}
|
|
if (error) {
|
|
[userInfo setObject:error forKey:@"error"];
|
|
if (referenceId) {
|
|
[self setSendingFailedToMessageWithReferenceId:referenceId];
|
|
}
|
|
NSLog(@"Could not send chat message. Error: %@", error.description);
|
|
}
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:NCChatControllerDidSendChatMessageNotification
|
|
object:self
|
|
userInfo:userInfo];
|
|
}];
|
|
}
|
|
|
|
- (BOOL)isChatBeingBlocked:(NSInteger)statusCode
|
|
{
|
|
if (statusCode == 412) {
|
|
return YES;
|
|
}
|
|
return NO;
|
|
}
|
|
|
|
- (void)notifyChatIsBlocked
|
|
{
|
|
NSMutableDictionary *userInfo = [NSMutableDictionary new];
|
|
[userInfo setObject:_room.token forKey:@"room"];
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:NCChatControllerDidReceiveChatBlockedNotification
|
|
object:self
|
|
userInfo:userInfo];
|
|
}
|
|
|
|
- (void)stopChatController
|
|
{
|
|
[self stopReceivingNewChatMessages];
|
|
[self stopReceivingChatHistory];
|
|
}
|
|
|
|
- (BOOL)hasHistoryFromMessageId:(NSInteger)messageId
|
|
{
|
|
NCChatBlock *firstChatBlock = [self chatBlocksForRoom].firstObject;
|
|
if (firstChatBlock && firstChatBlock.oldestMessageId == messageId) {
|
|
return firstChatBlock.hasHistory;
|
|
}
|
|
return YES;
|
|
}
|
|
|
|
@end
|