Fixed a few bugs

• Updated to the latest libSession
• Fixed some warnings
• Fixed a compilation issue on non-debug builds
• Fixed an issue with the dev settings data importer when ignoring hidden files from old exports (wouldn't move the inputStream forward correctly resulting in a crash)
• Fixed an issue where the swarm poller wasn't included synchronously processed messages in it's publisher output
pull/894/head
Morgan Pretty 2 months ago
parent 811528bfd5
commit d91af1b5b6

@ -1 +1 @@
Subproject commit 4651fe174e79f10a58d07f748fcabfd145ccb0bd Subproject commit 1ce161d98ada8f154cb8fd0e14458d65d85bc944

@ -386,7 +386,7 @@ final class ConversationVC: BaseVC, LibSessionRespondingViewController, Conversa
private lazy var legacyGroupsFooterButton: SessionButton = { private lazy var legacyGroupsFooterButton: SessionButton = {
let result: SessionButton = SessionButton(style: .bordered, size: .large) let result: SessionButton = SessionButton(style: .bordered, size: .large)
result.translatesAutoresizingMaskIntoConstraints = false result.translatesAutoresizingMaskIntoConstraints = false
result.setTitle("Recreate Group", for: .normal) result.setTitle("recreateGroup".localized(), for: .normal)
result.addTarget(self, action: #selector(recreateLegacyGroupTapped), for: .touchUpInside) result.addTarget(self, action: #selector(recreateLegacyGroupTapped), for: .touchUpInside)
result.accessibilityIdentifier = "Legacy Groups Recreate Button" result.accessibilityIdentifier = "Legacy Groups Recreate Button"
@ -823,7 +823,7 @@ final class ConversationVC: BaseVC, LibSessionRespondingViewController, Conversa
let messageRequestsViewWasVisible: Bool = (self.messageRequestFooterView.isHidden == false) let messageRequestsViewWasVisible: Bool = (self.messageRequestFooterView.isHidden == false)
UIView.animate(withDuration: 0.3) { [weak self, dependencies = viewModel.dependencies] in UIView.animate(withDuration: 0.3) { [weak self] in
self?.messageRequestFooterView.update( self?.messageRequestFooterView.update(
threadVariant: updatedThreadData.threadVariant, threadVariant: updatedThreadData.threadVariant,
canWrite: (updatedThreadData.threadCanWrite == true), canWrite: (updatedThreadData.threadCanWrite == true),
@ -1585,16 +1585,14 @@ final class ConversationVC: BaseVC, LibSessionRespondingViewController, Conversa
return return
} }
let profileDispalyName: String = Profile.displayName(
id: outdatedMemberId,
threadVariant: self.viewModel.threadData.threadVariant,
using: viewModel.dependencies
)
self.outdatedClientBanner.update( self.outdatedClientBanner.update(
message: "disappearingMessagesLegacy" message: "disappearingMessagesLegacy"
.put( .put(key: "name", value: profileDispalyName)
key: "name",
value: Profile.displayName(
id: outdatedMemberId,
threadVariant: self.viewModel.threadData.threadVariant,
using: viewModel.dependencies
)
)
.localizedFormatted(baseFont: self.outdatedClientBanner.font), .localizedFormatted(baseFont: self.outdatedClientBanner.font),
onTap: { [weak self] in self?.removeOutdatedClientBanner() } onTap: { [weak self] in self?.removeOutdatedClientBanner() }
) )

@ -76,7 +76,7 @@ public class ConversationViewModel: OWSAudioPlayerDelegate, NavigatableStateHold
} }
// FIXME: Strings should be updated in Crowdin to include the {icon} // FIXME: Strings should be updated in Crowdin to include the {icon}
return localizationKey return LocalizationHelper(template: localizationKey)
.put(key: "date", value: Features.legacyGroupDepricationDate.formattedForBanner) .put(key: "date", value: Features.legacyGroupDepricationDate.formattedForBanner)
.localizedFormatted(baseFont: legacyGroupsBannerFont) .localizedFormatted(baseFont: legacyGroupsBannerFont)
.appending(string: " ") // Designs have a space before the icon .appending(string: " ") // Designs have a space before the icon

@ -58,12 +58,12 @@ public extension LibSession {
var count: Int { var count: Int {
switch self { switch self {
case .userProfile(let conf): return 1 case .userProfile: return 1
case .contacts(let conf): return contacts_size(conf) case .contacts(let conf): return contacts_size(conf)
case .convoInfoVolatile(let conf): return convo_info_volatile_size(conf) case .convoInfoVolatile(let conf): return convo_info_volatile_size(conf)
case .userGroups(let conf): return user_groups_size(conf) case .userGroups(let conf): return user_groups_size(conf)
case .groupInfo(let conf): return 1 case .groupInfo: return 1
case .groupMembers(let conf): return groups_members_size(conf) case .groupMembers(let conf): return groups_members_size(conf)
case .groupKeys(let conf, _, _): return groups_keys_size(conf) case .groupKeys(let conf, _, _): return groups_keys_size(conf)
} }

@ -150,7 +150,7 @@ public class SwarmPoller: SwarmPollerType & PollerType {
.compactMap { $0.value.data?.messages.map { $0.info.hash } } .compactMap { $0.value.data?.messages.map { $0.info.hash } }
.reduce([], +) .reduce([], +)
var messageCount: Int = 0 var messageCount: Int = 0
var processedMessages: [ProcessedMessage] = [] var finalProcessedMessages: [ProcessedMessage] = []
var hadValidHashUpdate: Bool = false var hadValidHashUpdate: Bool = false
return dependencies[singleton: .storage].writePublisher { db -> (configMessageJobs: [Job], standardMessageJobs: [Job], pollResult: PollResult) in return dependencies[singleton: .storage].writePublisher { db -> (configMessageJobs: [Job], standardMessageJobs: [Job], pollResult: PollResult) in
@ -258,6 +258,9 @@ public class SwarmPoller: SwarmPollerType & PollerType {
} }
} }
/// Make sure to add any synchronously processed messages to the `finalProcessedMessages`
/// as otherwise they wouldn't be emitted by the `receivedPollResponseSubject`
finalProcessedMessages += processedMessages
return nil return nil
} }
.flatMap { $0 } .flatMap { $0 }
@ -266,8 +269,8 @@ public class SwarmPoller: SwarmPollerType & PollerType {
// to create message receive jobs or mess with cached hashes) // to create message receive jobs or mess with cached hashes)
guard shouldStoreMessages else { guard shouldStoreMessages else {
messageCount += allProcessedMessages.count messageCount += allProcessedMessages.count
processedMessages += allProcessedMessages finalProcessedMessages += allProcessedMessages
return ([], [], (processedMessages, rawMessageCount, messageCount, hadValidHashUpdate)) return ([], [], (finalProcessedMessages, rawMessageCount, messageCount, hadValidHashUpdate))
} }
// Add a job to process the config messages first // Add a job to process the config messages first
@ -276,7 +279,7 @@ public class SwarmPoller: SwarmPollerType & PollerType {
.grouped { $0.threadId } .grouped { $0.threadId }
.compactMap { threadId, threadMessages in .compactMap { threadId, threadMessages in
messageCount += threadMessages.count messageCount += threadMessages.count
processedMessages += threadMessages finalProcessedMessages += threadMessages
let job: Job? = Job( let job: Job? = Job(
variant: .configMessageReceive, variant: .configMessageReceive,
@ -306,7 +309,7 @@ public class SwarmPoller: SwarmPollerType & PollerType {
.grouped { $0.threadId } .grouped { $0.threadId }
.compactMap { threadId, threadMessages in .compactMap { threadId, threadMessages in
messageCount += threadMessages.count messageCount += threadMessages.count
processedMessages += threadMessages finalProcessedMessages += threadMessages
let job: Job? = Job( let job: Job? = Job(
variant: .messageReceive, variant: .messageReceive,
@ -360,7 +363,7 @@ public class SwarmPoller: SwarmPollerType & PollerType {
otherKnownValidHashes: otherKnownHashes otherKnownValidHashes: otherKnownHashes
) )
return (configMessageJobs, standardMessageJobs, (processedMessages, rawMessageCount, messageCount, hadValidHashUpdate)) return (configMessageJobs, standardMessageJobs, (finalProcessedMessages, rawMessageCount, messageCount, hadValidHashUpdate))
} }
} }
.flatMap { [dependencies] (configMessageJobs: [Job], standardMessageJobs: [Job], pollResult: PollResult) -> AnyPublisher<PollResult, Error> in .flatMap { [dependencies] (configMessageJobs: [Job], standardMessageJobs: [Job], pollResult: PollResult) -> AnyPublisher<PollResult, Error> in

@ -717,7 +717,7 @@ open class Storage {
semaphoreResult = semaphore.wait(timeout: .now() + .seconds(Storage.transactionDeadlockTimeoutSeconds)) semaphoreResult = semaphore.wait(timeout: .now() + .seconds(Storage.transactionDeadlockTimeoutSeconds))
} }
#else #else
semaphoreResult = semaphore?.wait(timeout: .now() + .seconds(Storage.transactionDeadlockTimeoutSeconds)) semaphoreResult = semaphore.wait(timeout: .now() + .seconds(Storage.transactionDeadlockTimeoutSeconds))
#endif #endif
/// If the query timed out then we should interrupt the query (don't want the query thread to remain blocked when we've /// If the query timed out then we should interrupt the query (don't want the query thread to remain blocked when we've

@ -284,32 +284,36 @@ public class DirectoryArchiver {
encryptedFileSize encryptedFileSize
) )
// If the file is a hidden file (shouldn't be possible anymore but old backups had this
// issue) then just skip the file - any hidden files are from Apple and seem to fail to
// decrypt causing the entire import to fail
guard !URL(fileURLWithPath: relativePath).lastPathComponent.starts(with: ".") else {
Log.warn(.cat, "Skipping hidden file to avoid breaking the import: \(relativePath)")
skippedFilePaths.append(fullPath)
// Update the progress
fileAmountProcessed += fileSize
progressChanged?(
(filePaths.count + skippedFilePaths.count + additionalFilePaths.count),
Int(expectedFileCount + expectedAdditionalFileCount),
fileAmountProcessed,
encryptedFileSize
)
continue
}
// Read and decrypt file content // Read and decrypt file content
guard let outputStream: OutputStream = OutputStream(toFileAtPath: fullPath, append: false) else { let outputStream: OutputStream?
Log.error(.cat, "Failed to create output stream") let isHiddenFile: Bool = URL(fileURLWithPath: relativePath).lastPathComponent.starts(with: ".")
throw ArchiveError.unarchiveFailed defer { outputStream?.close() }
switch isHiddenFile {
case true:
// If the file is a hidden file (shouldn't be possible anymore but old backups had this
// issue) then just skip the file - any hidden files are from Apple and seem to fail to
// decrypt causing the entire import to fail
//
// Note: We still need to process the file in order to ensure the inputStream is moved
// the correct amount, otherwise out byte alignment could be off which will result in
// at best a failed import, but more likely a crash due to invalid size data
Log.warn(.cat, "Skipping hidden file to avoid breaking the import: \(relativePath)")
skippedFilePaths.append(fullPath)
outputStream = nil
case false:
// It's a valid file so ensure the OutputStream was opened successfully
outputStream = OutputStream(toFileAtPath: fullPath, append: false)
outputStream?.open()
guard outputStream != nil else {
Log.error(.cat, "Failed to create output stream")
throw ArchiveError.unarchiveFailed
}
} }
outputStream.open()
defer { outputStream.close() }
// Process the file chunk by chunk
var remainingFileSize: Int = Int(fileSize) var remainingFileSize: Int = Int(fileSize)
while remainingFileSize > 0 { while remainingFileSize > 0 {
let (chunk, chunkSizeBytesRead, encryptedSize): ([UInt8], Int, UInt32) = try read( let (chunk, chunkSizeBytesRead, encryptedSize): ([UInt8], Int, UInt32) = try read(
@ -318,7 +322,7 @@ public class DirectoryArchiver {
) )
// Write to the output // Write to the output
outputStream.write(chunk, maxLength: chunk.count) outputStream?.write(chunk, maxLength: chunk.count)
remainingFileSize -= chunk.count remainingFileSize -= chunk.count
// Update the progress // Update the progress
@ -332,9 +336,10 @@ public class DirectoryArchiver {
} }
// Store the file path info and update the progress // Store the file path info and update the progress
switch isExtraFile { switch (isExtraFile, isHiddenFile) {
case false: filePaths.append(fullPath) case (_, true): break
case true: additionalFilePaths.append(fullPath) case (false, false): filePaths.append(fullPath)
case (true, false): additionalFilePaths.append(fullPath)
} }
progressChanged?( progressChanged?(
(filePaths.count + skippedFilePaths.count + additionalFilePaths.count), (filePaths.count + skippedFilePaths.count + additionalFilePaths.count),

@ -165,7 +165,7 @@ class TypeConversionUtilitiesSpec: QuickSpec {
// MARK: ---- returns an empty string when null and not set to return null // MARK: ---- returns an empty string when null and not set to return null
it("returns an empty string when null and not set to return null") { it("returns an empty string when null and not set to return null") {
var test: TestClass = TestClass() let test: TestClass = TestClass()
let result: String? = test.get(\.testString, nullIfEmpty: false) let result: String? = test.get(\.testString, nullIfEmpty: false)
expect(result).to(equal("")) expect(result).to(equal(""))
@ -173,7 +173,7 @@ class TypeConversionUtilitiesSpec: QuickSpec {
// MARK: ---- returns null when specified and empty // MARK: ---- returns null when specified and empty
it("returns null when specified and empty") { it("returns null when specified and empty") {
var test: TestClass = TestClass() let test: TestClass = TestClass()
let result: String? = test.get(\.testString, nullIfEmpty: true) let result: String? = test.get(\.testString, nullIfEmpty: true)
expect(result).to(beNil()) expect(result).to(beNil())
@ -181,7 +181,7 @@ class TypeConversionUtilitiesSpec: QuickSpec {
// MARK: ---- defaults the null if empty flag to false // MARK: ---- defaults the null if empty flag to false
it("defaults the null if empty flag to false") { it("defaults the null if empty flag to false") {
var test: TestClass = TestClass() let test: TestClass = TestClass()
let result: String? = test.get(\.testString) let result: String? = test.get(\.testString)
expect(result).to(equal("")) expect(result).to(equal(""))

Loading…
Cancel
Save