diff --git a/native/ios/Comm/TemporaryMessageStorage/TemporaryMessageStorage.mm b/native/ios/Comm/TemporaryMessageStorage/TemporaryMessageStorage.mm index 61e67960d..2133dd2cd 100644 --- a/native/ios/Comm/TemporaryMessageStorage/TemporaryMessageStorage.mm +++ b/native/ios/Comm/TemporaryMessageStorage/TemporaryMessageStorage.mm @@ -1,75 +1,130 @@ #import "TemporaryMessageStorage.h" #import "EncryptedFileUtils.h" #import "Logger.h" #import "NonBlockingLock.h" #import @interface TemporaryMessageStorage () - (NSString *)_createNewStorage; - (NSString *)_getLockName:(NSString *)fileName; - (NSString *)_getPath:(NSString *)fileName; @end @implementation TemporaryMessageStorage - (instancetype)init { self = [self initAtDirectory:@"TemporaryMessageStorage"]; return self; } - (instancetype)initAtDirectory:(NSString *)directoryName { self = [super init]; if (!self) { return self; } NSURL *groupURL = [NSFileManager.defaultManager containerURLForSecurityApplicationGroupIdentifier:@"group.app.comm"]; NSURL *directoryURL = [groupURL URLByAppendingPathComponent:directoryName]; NSString *directoryPath = directoryURL.path; NSError *err = nil; if (![NSFileManager.defaultManager fileExistsAtPath:directoryPath]) { [NSFileManager.defaultManager createDirectoryAtPath:directoryPath withIntermediateDirectories:NO attributes:nil error:&err]; } if (err) { comm::Logger::log( "Failed to create directory at path: " + std::string([directoryPath UTF8String]) + ". Details: " + std::string([err.localizedDescription UTF8String])); } _directoryURL = directoryURL; _directoryPath = directoryPath; return self; } +- (void)writeMessage:(NSString *)message { + NSArray *storageContent = + [NSFileManager.defaultManager contentsOfDirectoryAtPath:self.directoryPath + error:nil]; + if (!storageContent) { + comm::Logger::log("Storage not existing yet. Skipping notification"); + return; + } + + NSString *currentFileName = nil; + if (storageContent.count) { + currentFileName = + [storageContent sortedArrayUsingSelector:@selector(compare:)] + .lastObject; + } else if (!(currentFileName = [self _createNewStorage])) { + comm::Logger::log( + "Failed to create new storage file. Details: " + + std::string(strerror(errno))); + } + + NSString *currentFilePath = [self _getPath:currentFileName]; + NSString *lockName = [self _getLockName:currentFileName]; + NonBlockingLock *lock = [[NonBlockingLock alloc] initWithName:lockName]; + + NSError *lockError = nil; + NSError *writeError = nil; + + @try { + if (![lock tryAcquireLock:&lockError]) { + NSString *randomPath = + [self.directoryURL + URLByAppendingPathComponent:[NSUUID UUID].UUIDString] + .path; + [EncryptedFileUtils writeData:message toFileAtPath:randomPath error:nil]; + comm::Logger::log( + "Failed to acquire lock. Details: " + + std::string([lockError.localizedDescription UTF8String]) + + " Persisting notification at path: " + + std::string([randomPath UTF8String])); + return; + } + [EncryptedFileUtils appendData:message + toFileAtPath:currentFilePath + error:&writeError]; + } @finally { + [lock releaseLock:&lockError]; + } + + if (writeError) { + comm::Logger::log( + "Failed to append message to storage. Details: " + + std::string([writeError.localizedDescription UTF8String])); + } +} + - (NSString *)_createNewStorage { int64_t timestamp = (int64_t)[NSDate date].timeIntervalSince1970; NSString *newStorageName = [NSString stringWithFormat:@"msg_%lld", timestamp]; NSString *newStoragePath = [self.directoryURL URLByAppendingPathComponent:newStorageName].path; const char *newStoragePathCstr = [newStoragePath cStringUsingEncoding:NSUTF8StringEncoding]; FILE *newStorage = fopen(newStoragePathCstr, "a"); if (!newStorage) { return nil; } fclose(newStorage); return newStorageName; } - (NSString *)_getLockName:(NSString *)fileName { return [NSString stringWithFormat:@"group.app.comm/%@", fileName]; } - (NSString *)_getPath:(NSString *)fileName { if (!fileName) { return nil; } return [self.directoryURL URLByAppendingPathComponent:fileName].path; } @end