1
0
mirror of https://github.com/danog/Telegram.git synced 2024-12-04 02:17:51 +01:00
Telegram/Watch/Extension/TGBridgeUserCache.m
2016-02-25 01:03:51 +01:00

172 lines
4.3 KiB
Objective-C

#import "TGBridgeUserCache.h"
#import "TGFileCache.h"
#import <libkern/OSAtomic.h>
#import "TGBridgeUser.h"
#import "TGBridgeBotInfo.h"
@interface TGBridgeUserCache ()
{
NSMutableDictionary *_userByUid;
OSSpinLock _userByUidLock;
NSMutableDictionary *_botInfoByUid;
OSSpinLock _botInfoByUidLock;
TGFileCache *_fileCache;
}
@end
@implementation TGBridgeUserCache
- (instancetype)init
{
self = [super init];
if (self != nil)
{
_userByUid = [[NSMutableDictionary alloc] init];
_botInfoByUid = [[NSMutableDictionary alloc] init];
_fileCache = [[TGFileCache alloc] initWithName:@"users" useMemoryCache:false];
}
return self;
}
- (TGBridgeUser *)userWithId:(int32_t)userId
{
__block TGBridgeUser *user = nil;
OSSpinLockLock(&_userByUidLock);
user = _userByUid[@(userId)];
OSSpinLockUnlock(&_userByUidLock);
return user;
}
- (NSDictionary *)usersWithIndexSet:(NSIndexSet *)indexSet
{
NSMutableDictionary *users = [[NSMutableDictionary alloc] init];
NSMutableIndexSet *neededUsers = [indexSet mutableCopy];
NSMutableIndexSet *foundUsers = [[NSMutableIndexSet alloc] init];
OSSpinLockLock(&_userByUidLock);
[neededUsers enumerateIndexesUsingBlock:^(NSUInteger index, BOOL * _Nonnull stop)
{
TGBridgeUser *user = _userByUid[@(index)];
if (user != nil)
{
users[@(index)] = user;
[foundUsers addIndex:index];
}
}];
OSSpinLockUnlock(&_userByUidLock);
[neededUsers removeIndexes:foundUsers];
return users;
}
- (void)storeUser:(TGBridgeUser *)user
{
if (user == nil)
return;
[self storeUsers:@[ user ]];
}
- (void)storeUsers:(NSArray *)users
{
OSSpinLockLock(&_userByUidLock);
for (id peer in users)
{
if ([peer isKindOfClass:[TGBridgeUser class]])
_userByUid[@(((TGBridgeUser *)peer).identifier)] = peer;
}
OSSpinLockUnlock(&_userByUidLock);
}
- (NSArray *)applyUserChanges:(NSArray *)userChanges
{
NSMutableArray *missedUserIds = [[NSMutableArray alloc] init];
NSMutableArray *updatedUsers = [[NSMutableArray alloc] init];
for (TGBridgeUserChange *change in userChanges)
{
TGBridgeUser *user = [self userWithId:change.userIdentifier];
if (user != nil)
{
TGBridgeUser *updatedUser = [user userByApplyingChange:change];
[updatedUsers addObject:updatedUser];
}
else
{
[missedUserIds addObject:@(change.userIdentifier)];
}
}
[self storeUsers:updatedUsers];
if (missedUserIds.count == 0)
return nil;
return missedUserIds;
}
- (TGBridgeBotInfo *)botInfoForUserId:(int32_t)userId
{
__block TGBridgeBotInfo *botInfo = nil;
OSSpinLockLock(&_botInfoByUidLock);
botInfo = _botInfoByUid[@(userId)];
OSSpinLockUnlock(&_botInfoByUidLock);
if (botInfo == nil)
{
[_fileCache fetchDataForKey:[NSString stringWithFormat:@"botInfo-%d", userId] synchronous:true unserializeBlock:^id(NSData *data)
{
id object = [NSKeyedUnarchiver unarchiveObjectWithData:data];
if ([object isKindOfClass:[TGBridgeBotInfo class]])
return object;
return nil;
} completion:^(TGBridgeBotInfo *result)
{
if (result != nil)
{
botInfo = result;
OSSpinLockLock(&_botInfoByUidLock);
_botInfoByUid[@(userId)] = botInfo;
OSSpinLockUnlock(&_botInfoByUidLock);
}
}];
}
return botInfo;
}
- (void)storeBotInfo:(TGBridgeBotInfo *)botInfo forUserId:(int32_t)userId
{
OSSpinLockLock(&_botInfoByUidLock);
_botInfoByUid[@(userId)] = botInfo;
[_fileCache cacheData:botInfo key:[NSString stringWithFormat:@"botInfo-%d", userId] synchronous:true serializeBlock:^NSData *(NSObject<NSCoding> *object)
{
return [NSKeyedArchiver archivedDataWithRootObject:object];
} completion:nil];
OSSpinLockUnlock(&_botInfoByUidLock);
}
+ (instancetype)instance
{
static dispatch_once_t onceToken;
static TGBridgeUserCache *userCache;
dispatch_once(&onceToken, ^
{
userCache = [[TGBridgeUserCache alloc] init];
});
return userCache;
}
@end