diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 602b4bd487..47dd4386c6 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -8568,7 +8568,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; COMPILE_LIB_SESSION = ""; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 678; + CURRENT_PROJECT_VERSION = 680; ENABLE_BITCODE = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -8649,7 +8649,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Distribution"; COMPILE_LIB_SESSION = ""; - CURRENT_PROJECT_VERSION = 678; + CURRENT_PROJECT_VERSION = 680; ENABLE_BITCODE = NO; ENABLE_MODULE_VERIFIER = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -9349,7 +9349,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; COMPILE_LIB_SESSION = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 678; + CURRENT_PROJECT_VERSION = 680; ENABLE_BITCODE = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -9938,7 +9938,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Distribution"; COMPILE_LIB_SESSION = YES; - CURRENT_PROJECT_VERSION = 678; + CURRENT_PROJECT_VERSION = 680; ENABLE_BITCODE = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; diff --git a/Session/Meta/Translations/InfoPlist.xcstrings b/Session/Meta/Translations/InfoPlist.xcstrings index 3d97c3284c..46511db12c 100644 --- a/Session/Meta/Translations/InfoPlist.xcstrings +++ b/Session/Meta/Translations/InfoPlist.xcstrings @@ -1558,6 +1558,12 @@ "value" : "Session necesita acceso a la red local para realizar llamadas de voz y video." } }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Session tarvitsee pääsyn paikalliseen verkkoon soittaakseen ääni- ja videopuheluja." + } + }, "fr" : { "stringUnit" : { "state" : "translated", diff --git a/Session/Utilities/IP2Country.swift b/Session/Utilities/IP2Country.swift index 0ad1087195..9acfa9d62f 100644 --- a/Session/Utilities/IP2Country.swift +++ b/Session/Utilities/IP2Country.swift @@ -160,15 +160,16 @@ fileprivate class IP2Country: IP2CountryCacheType { /// We found a separator so create a string from the bytes we just passed let length: Int = (i - (lastIndex - contentData.startIndex)) - if length > 0 { - let dataChunk: Data = Data( - bytes: baseAddress.advanced(by: lastIndex - contentData.startIndex), - count: length - ) - - if let stringValue: String = String(data: dataChunk, encoding: .utf8) { - result.append(stringValue) - } + let dataChunk: Data = Data( + bytes: baseAddress.advanced(by: lastIndex - contentData.startIndex), + count: length + ) + + if let stringValue: String = String(data: dataChunk, encoding: .utf8) { + result.append(stringValue) + } + else { + result.append("") /// Need to insert empty entries as well to ensure the indexes are correct } /// Move past the separator @@ -214,87 +215,43 @@ fileprivate class IP2Country: IP2CountryCacheType { init(using dependencies: Dependencies) { /// Ensure the lookup tables get loaded in the background - DispatchQueue.global(qos: .utility).async { [weak self] in + Task.detached(priority: .utility) { [weak self] in _ = self?.cache - - /// Then register for path change callbacks which will be used to update the country name cache - self?.registerNetworkObservables(using: dependencies) + self?._cacheLoaded.send(true) + Log.info(.ip2Country, "IP2Country cache loaded.") } } // MARK: - Functions - private func registerNetworkObservables(using dependencies: Dependencies) { - /// Register for path change callbacks which will be used to update the country name cache - dependencies[cache: .libSessionNetwork].paths - .subscribe(on: DispatchQueue.global(qos: .utility), using: dependencies) - .receive(on: DispatchQueue.global(qos: .utility), using: dependencies) - .sink( - receiveCompletion: { [weak self] _ in - /// If the stream completes it means the network cache was reset in which case we want to - /// re-register for updates in the next run loop (as the new cache should be created by then) - DispatchQueue.global(qos: .background).async { - self?.registerNetworkObservables(using: dependencies) - } - }, - receiveValue: { [weak self] paths in - dependencies.mutate(cache: .ip2Country) { _ in - self?.populateCacheIfNeeded(paths: paths) - } - } - ) - .store(in: &disposables) - } - - private func populateCacheIfNeeded(paths: [[LibSession.Snode]]) { - guard !paths.isEmpty else { return } - - paths.forEach { path in - path.forEach { snode in - self.cacheCountry(for: snode.ip, inCache: &countryNamesCache) - } - } - - self._cacheLoaded.send(true) - Log.info(.ip2Country, "Update onion request path countries.") - } - - private func cacheCountry(for ip: String, inCache nameCache: inout [String: String]) { - let currentLocale: String = self.currentLocale // Store local copy for efficiency - - guard nameCache["\(ip)-\(currentLocale)"] == nil else { return } - - /// Code block checks if IP passed is unknown, not supported or blocked - guard - let ipAsInt: Int64 = IPv4.toInt(ip), - let countryBlockGeonameIdIndex: Int = cache.countryBlocksIPInt.firstIndex(where: { $0 > ipAsInt }).map({ $0 - 1 }) - else { return } - - /// Get local index for the current locale - /// When index is not found it should fallback to english - var validLocaleStartIndex: Int? { - cache.countryLocationsLocaleCode.firstIndex(of: currentLocale) - ?? cache.countryLocationsLocaleCode.firstIndex(of: "en") - } - - guard - let localeStartIndex: Int = validLocaleStartIndex, - let countryNameIndex: Int = Array(cache.countryLocationsGeonameId[localeStartIndex...]).firstIndex(where: { geonameId in - geonameId == cache.countryBlocksGeonameId[countryBlockGeonameIdIndex] - }), - (localeStartIndex + countryNameIndex) < cache.countryLocationsCountryName.count - else { return } - - let result: String = cache.countryLocationsCountryName[localeStartIndex + countryNameIndex] - nameCache["\(ip)-\(currentLocale)"] = result - } - - // MARK: - Functions - public func country(for ip: String) -> String { guard _cacheLoaded.value else { return "resolving".localized() } - return (countryNamesCache["\(ip)-\(currentLocale)"] ?? "onionRoutingPathUnknownCountry".localized()) + /// Get local index for the current locale (when index is not found it should fallback to english) + let validLocaleStartIndex: Int? = ( + cache.countryLocationsLocaleCode.firstIndex(of: currentLocale) ?? + cache.countryLocationsLocaleCode.firstIndex(of: "en") + ) + let key: String = "\(ip)-\(currentLocale)" + + switch countryNamesCache[key] { + case .some(let value): return value + case .none: + guard + let ipAsInt: Int64 = IPv4.toInt(ip), + let countryBlockGeonameIdIndex: Int = cache.countryBlocksIPInt.firstIndex(where: { $0 > ipAsInt }).map({ $0 - 1 }), + let localeStartIndex: Int = validLocaleStartIndex, + let countryNameIndex: Int = Array(cache.countryLocationsGeonameId[localeStartIndex...]).firstIndex(where: { geonameId in + geonameId == cache.countryBlocksGeonameId[countryBlockGeonameIdIndex] + }), + (localeStartIndex + countryNameIndex) < cache.countryLocationsCountryName.count + else { return "onionRoutingPathUnknownCountry".localized() } + + let result: String = cache.countryLocationsCountryName[localeStartIndex + countryNameIndex] + countryNamesCache[key] = result + + return result + } } } diff --git a/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift b/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift index 44a97f04cb..5508a2e9a2 100644 --- a/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift +++ b/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift @@ -1052,7 +1052,8 @@ public extension SessionThreadViewModel { return SQL(""" (IFNULL(\(thread[.pinnedPriority]), 0) > 0) DESC, - IFNULL(\(interaction[.timestampMs]), (\(thread[.creationDateTimestamp]) * 1000)) DESC + IFNULL(\(interaction[.timestampMs]), (\(thread[.creationDateTimestamp]) * 1000)) DESC, + \(thread[.id]) DESC """) }() @@ -1060,7 +1061,10 @@ public extension SessionThreadViewModel { let thread: TypedTableAlias = TypedTableAlias() let interaction: TypedTableAlias = TypedTableAlias() - return SQL("IFNULL(\(interaction[.timestampMs]), (\(thread[.creationDateTimestamp]) * 1000)) DESC") + return SQL(""" + IFNULL(\(interaction[.timestampMs]), (\(thread[.creationDateTimestamp]) * 1000)) DESC, + \(thread[.id]) DESC + """) }() }