1
0
mirror of https://github.com/danog/Telegram.git synced 2024-12-02 09:27:55 +01:00
Telegram/Telegraph/TGGenericPeerPlaylistSignals.m
2016-02-25 01:03:51 +01:00

314 lines
12 KiB
Objective-C

#import "TGGenericPeerPlaylistSignals.h"
#import "ActionStage.h"
#import "TGMusicPlayerPlaylist.h"
#import "TGSharedMediaCacheSignals.h"
#import "TGMessage.h"
#import "TGDatabase.h"
#import "TGMessageViewedContentProperty.h"
#import "TGTelegraph.h"
#import "TGPeerIdAdapter.h"
@interface TGGenericPeerPlaylistHelper : NSObject <ASWatcher>
{
int64_t _peerId;
bool _important;
int32_t _atMessageId;
void (^_updated)(TGMusicPlayerPlaylist *);
id<SDisposable> _cachedMediaDisposable;
NSMutableArray *_currentMessages;
NSMutableDictionary *_currentItemKeyAliases;
bool _voice;
}
@property (nonatomic, strong) ASHandle *actionHandle;
@end
@implementation TGGenericPeerPlaylistHelper
- (NSArray *)sortedMessages:(NSArray *)array
{
return [array sortedArrayUsingComparator:^NSComparisonResult(TGMessage *message1, TGMessage *message2)
{
NSTimeInterval date1 = message1.date;
NSTimeInterval date2 = message2.date;
if (ABS(date1 - date2) < DBL_EPSILON)
{
if (message1.mid > message2.mid)
return NSOrderedDescending;
else
return NSOrderedAscending;
}
return date1 > date2 ? NSOrderedDescending : NSOrderedAscending;
}];
}
- (NSArray *)itemListFromMessages:(NSArray *)messages
{
NSMutableArray *items = [[NSMutableArray alloc] init];
for (TGMessage *message in messages)
{
TGUser *author = nil;
if (!TGPeerIdIsChannel(message.fromUid)) {
author = [TGDatabaseInstance() loadUser:(int32_t)message.fromUid];
}
TGMusicPlayerItem *item = [TGMusicPlayerItem itemWithMessage:message author:author];
if (item != nil)
[items addObject:item];
}
return items;
}
- (instancetype)initWithPeerId:(int64_t)peerId important:(bool)important atMessageId:(int32_t)atMessageId voice:(bool)voice updated:(void (^)(TGMusicPlayerPlaylist *))updated
{
self = [super init];
if (self != nil)
{
_peerId = peerId;
_important = important;
_atMessageId = atMessageId;
_updated = [updated copy];
_voice = voice;
_currentMessages = [[NSMutableArray alloc] init];
_currentItemKeyAliases = [[NSMutableDictionary alloc] init];
_actionHandle = [[ASHandle alloc] initWithDelegate:self];
__weak TGGenericPeerPlaylistHelper *weakSelf = self;
SSignal *initialSignal = [[TGDatabaseInstance() modify:^id{
TGMessage *message = [TGDatabaseInstance() loadMessageWithMid:atMessageId peerId:peerId];
if (message != nil) {
return [SSignal single:@[message]];
} else {
return [SSignal complete];
}
}] switchToLatest];
_cachedMediaDisposable = [[initialSignal then:[[TGSharedMediaCacheSignals cachedMediaForPeerId:peerId itemType:voice ? TGSharedMediaCacheItemTypeVoiceNote : TGSharedMediaCacheItemTypeAudio important:_important] filter:^bool (id next)
{
if ([next respondsToSelector:@selector(objectAtIndex:)])
{
for (TGMessage *message in next)
{
if (message.mid == atMessageId)
return true;
}
}
return false;
}]] startWithNext:^(NSArray *messages)
{
[ActionStageInstance() dispatchOnStageQueue:^
{
__strong TGGenericPeerPlaylistHelper *strongSelf = weakSelf;
if (strongSelf != nil)
{
[strongSelf replaceMessages:messages];
}
}];
} completed:^
{
[ActionStageInstance() watchForPaths:@[
[NSString stringWithFormat:@"/tg/conversation/(%lld)/messages", _peerId],
[NSString stringWithFormat:@"/tg/conversation/(%lld)/messagesChanged", _peerId],
[NSString stringWithFormat:@"/tg/conversation/(%lld)/messagesDeleted", _peerId]
] watcher:self];
}];
}
return self;
}
- (void)dealloc
{
[_cachedMediaDisposable dispose];
[_actionHandle reset];
[ActionStageInstance() removeWatcher:self];
}
+ (void)markItemAsViewed:(TGMusicPlayerItem *)item {
[TGDatabaseInstance() dispatchOnDatabaseThread:^{
if ([item.key respondsToSelector:@selector(intValue)]) {
TGMessage *message = [TGDatabaseInstance() loadMessageWithMid:[(NSNumber *)item.key intValue] peerId:item.peerId];
if (message != nil && !message.outgoing) {
if (TGPeerIdIsSecretChat(message.cid)) {
int32_t flags = [TGDatabaseInstance() secretMessageFlags:message.mid];
if ((flags & TGSecretMessageFlagViewed) == 0) {
[TGDatabaseInstance() messageCountdownLocalTime:message.mid enqueueIfNotQueued:true initiatedCountdown:NULL];
[ActionStageInstance() requestActor:@"/tg/service/synchronizeserviceactions/(settings)" options:nil watcher:TGTelegraphInstance];
}
} else {
if (message.contentProperties[@"contentsRead"] == nil) {
NSMutableDictionary *contentProperties = [[NSMutableDictionary alloc] initWithDictionary:message.contentProperties];
contentProperties[@"contentsRead"] = [[TGMessageViewedContentProperty alloc] init];
message.contentProperties = contentProperties;
TGDatabaseAction action = { .type = TGDatabaseActionReadMessageContents, .subject = message.mid, .arg0 = 0, .arg1 = 0};
[TGDatabaseInstance() storeQueuedActions:[NSArray arrayWithObject:[[NSValue alloc] initWithBytes:&action objCType:@encode(TGDatabaseAction)]]];
[ActionStageInstance() requestActor:@"/tg/service/synchronizeactionqueue/(global)" options:nil watcher:TGTelegraphInstance];
[TGDatabaseInstance() updateMessage:message.mid peerId:message.cid withMessage:message];
[ActionStageInstance() dispatchResource:[NSString stringWithFormat:@"/tg/conversation/*/readmessageContents"] resource:@{@"messageIds": @[@(message.mid)]}];
}
}
}
}
} synchronous:false];
}
- (void)replaceMessages:(NSArray *)messages
{
[_currentItemKeyAliases removeAllObjects];
[_currentMessages removeAllObjects];
[_currentMessages addObjectsFromArray:[self sortedMessages:messages]];
if (_updated)
{
_updated([[TGMusicPlayerPlaylist alloc] initWithVoice:_voice items:[self itemListFromMessages:_currentMessages] itemKeyAliases:[[NSDictionary alloc] initWithDictionary:_currentItemKeyAliases] markItemAsViewed:^(TGMusicPlayerItem *item) {
[TGGenericPeerPlaylistHelper markItemAsViewed:item];
}]);
}
}
- (void)addMessages:(NSArray *)messages
{
NSMutableSet *currentMessageIds = [[NSMutableSet alloc] init];
for (TGMessage *message in _currentMessages)
{
[currentMessageIds addObject:@(message.mid)];
}
bool added = false;
for (TGMessage *message in messages)
{
if (![currentMessageIds containsObject:@(message.mid)])
{
[currentMessageIds addObject:@(message.mid)];
if ([TGMusicPlayerItem itemWithMessage:message author:nil] != nil)
{
[_currentMessages addObject:message];
added = true;
}
}
}
if (added)
{
NSArray *sortedMessages = [self sortedMessages:_currentMessages];
[_currentMessages removeAllObjects];
[_currentMessages addObjectsFromArray:sortedMessages];
if (_updated)
{
_updated([[TGMusicPlayerPlaylist alloc] initWithVoice:_voice items:[self itemListFromMessages:_currentMessages] itemKeyAliases:[[NSDictionary alloc] initWithDictionary:_currentItemKeyAliases] markItemAsViewed:^(TGMusicPlayerItem *item) {
[TGGenericPeerPlaylistHelper markItemAsViewed:item];
}]);
}
}
}
- (void)deleteMessagesWithIds:(NSArray *)messageIds
{
NSMutableSet *idsSet = [[NSMutableSet alloc] init];
for (NSNumber *nMessageId in messageIds)
{
[idsSet addObject:nMessageId];
}
for (NSInteger i = 0; i < (NSInteger)_currentMessages.count; i++)
{
if ([idsSet containsObject:@(((TGMessage *)_currentMessages[i]).mid)])
{
[_currentMessages removeObjectAtIndex:i];
i--;
}
}
if (_updated)
{
_updated([[TGMusicPlayerPlaylist alloc] initWithVoice:_voice items:[self itemListFromMessages:_currentMessages] itemKeyAliases:[[NSDictionary alloc] initWithDictionary:_currentItemKeyAliases] markItemAsViewed:^(TGMusicPlayerItem *item) {
[TGGenericPeerPlaylistHelper markItemAsViewed:item];
}]);
}
}
- (void)remapMessages:(NSDictionary *)messages
{
for (NSInteger i = 0; i < (NSInteger)_currentMessages.count; i++)
{
TGMessage *updatedMessage = messages[@(((TGMessage *)_currentMessages[i]).mid)];
if (updatedMessage != nil)
{
_currentItemKeyAliases[@(((TGMessage *)_currentMessages[i]).mid)] = @(updatedMessage.mid);
[_currentMessages replaceObjectAtIndex:i withObject:updatedMessage];
}
}
NSArray *sortedMessages = [self sortedMessages:_currentMessages];
[_currentMessages removeAllObjects];
[_currentMessages addObjectsFromArray:sortedMessages];
if (_updated)
{
_updated([[TGMusicPlayerPlaylist alloc] initWithVoice:_voice items:[self itemListFromMessages:_currentMessages] itemKeyAliases:[[NSDictionary alloc] initWithDictionary:_currentItemKeyAliases] markItemAsViewed:^(TGMusicPlayerItem *item) {
[TGGenericPeerPlaylistHelper markItemAsViewed:item];
}]);
}
}
- (void)actionStageResourceDispatched:(NSString *)path resource:(id)resource arguments:(id)__unused arguments
{
if ([path isEqualToString:[[NSString alloc] initWithFormat:@"/tg/conversation/(%lld)/messages", _peerId]])
{
NSArray *messages = [((SGraphObjectNode *)resource).object copy];
[self addMessages:messages];
}
else if ([path isEqualToString:[[NSString alloc] initWithFormat:@"/tg/conversation/(%lld)/messagesChanged", _peerId]])
{
NSArray *midMessagePairs = ((SGraphObjectNode *)resource).object;
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
for (NSUInteger i = 0; i < midMessagePairs.count; i += 2)
{
dict[midMessagePairs[0]] = midMessagePairs[1];
}
[self remapMessages:dict];
}
else if ([path isEqualToString:[[NSString alloc] initWithFormat:@"/tg/conversation/(%lld)/messagesDeleted", _peerId]])
{
[self deleteMessagesWithIds:((SGraphObjectNode *)resource).object];
}
}
@end
@implementation TGGenericPeerPlaylistSignals
+ (SSignal *)playlistForPeerId:(int64_t)peerId important:(bool)important atMessageId:(int32_t)messageId voice:(bool)voice
{
return [[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber)
{
TGGenericPeerPlaylistHelper *helper = [[TGGenericPeerPlaylistHelper alloc] initWithPeerId:peerId important:important atMessageId:messageId voice:voice updated:^(TGMusicPlayerPlaylist *playlist)
{
[subscriber putNext:playlist];
}];
return [[SBlockDisposable alloc] initWithBlock:^
{
[helper description]; //keep reference
}];
}];
}
@end