@@ -160,15 +160,16 @@ fileprivate class IP2Country: IP2CountryCacheType {
160160 /// We found a separator so create a string from the bytes we just passed
161161 let length : Int = ( i - ( lastIndex - contentData. startIndex) )
162162
163- if length > 0 {
164- let dataChunk : Data = Data (
165- bytes: baseAddress. advanced ( by: lastIndex - contentData. startIndex) ,
166- count: length
167- )
168-
169- if let stringValue: String = String ( data: dataChunk, encoding: . utf8) {
170- result. append ( stringValue)
171- }
163+ let dataChunk : Data = Data (
164+ bytes: baseAddress. advanced ( by: lastIndex - contentData. startIndex) ,
165+ count: length
166+ )
167+
168+ if let stringValue: String = String ( data: dataChunk, encoding: . utf8) {
169+ result. append ( stringValue)
170+ }
171+ else {
172+ result. append ( " " ) /// Need to insert empty entries as well to ensure the indexes are correct
172173 }
173174
174175 /// Move past the separator
@@ -214,87 +215,43 @@ fileprivate class IP2Country: IP2CountryCacheType {
214215
215216 init ( using dependencies: Dependencies ) {
216217 /// Ensure the lookup tables get loaded in the background
217- DispatchQueue . global ( qos : . utility) . async { [ weak self] in
218+ Task . detached ( priority : . utility) { [ weak self] in
218219 _ = self ? . cache
219-
220- /// Then register for path change callbacks which will be used to update the country name cache
221- self ? . registerNetworkObservables ( using: dependencies)
220+ self ? . _cacheLoaded. send ( true )
221+ Log . info ( . ip2Country, " IP2Country cache loaded. " )
222222 }
223223 }
224224
225225 // MARK: - Functions
226226
227- private func registerNetworkObservables( using dependencies: Dependencies ) {
228- /// Register for path change callbacks which will be used to update the country name cache
229- dependencies [ cache: . libSessionNetwork] . paths
230- . subscribe ( on: DispatchQueue . global ( qos: . utility) , using: dependencies)
231- . receive ( on: DispatchQueue . global ( qos: . utility) , using: dependencies)
232- . sink (
233- receiveCompletion: { [ weak self] _ in
234- /// If the stream completes it means the network cache was reset in which case we want to
235- /// re-register for updates in the next run loop (as the new cache should be created by then)
236- DispatchQueue . global ( qos: . background) . async {
237- self ? . registerNetworkObservables ( using: dependencies)
238- }
239- } ,
240- receiveValue: { [ weak self] paths in
241- dependencies. mutate ( cache: . ip2Country) { _ in
242- self ? . populateCacheIfNeeded ( paths: paths)
243- }
244- }
245- )
246- . store ( in: & disposables)
247- }
248-
249- private func populateCacheIfNeeded( paths: [ [ LibSession . Snode ] ] ) {
250- guard !paths. isEmpty else { return }
251-
252- paths. forEach { path in
253- path. forEach { snode in
254- self . cacheCountry ( for: snode. ip, inCache: & countryNamesCache)
255- }
256- }
257-
258- self . _cacheLoaded. send ( true )
259- Log . info ( . ip2Country, " Update onion request path countries. " )
260- }
261-
262- private func cacheCountry( for ip: String , inCache nameCache: inout [ String : String ] ) {
263- let currentLocale : String = self . currentLocale // Store local copy for efficiency
264-
265- guard nameCache [ " \( ip) - \( currentLocale) " ] == nil else { return }
266-
267- /// Code block checks if IP passed is unknown, not supported or blocked
268- guard
269- let ipAsInt: Int64 = IPv4 . toInt ( ip) ,
270- let countryBlockGeonameIdIndex: Int = cache. countryBlocksIPInt. firstIndex ( where: { $0 > ipAsInt } ) . map ( { $0 - 1 } )
271- else { return }
272-
273- /// Get local index for the current locale
274- /// When index is not found it should fallback to english
275- var validLocaleStartIndex : Int ? {
276- cache. countryLocationsLocaleCode. firstIndex ( of: currentLocale)
277- ?? cache. countryLocationsLocaleCode. firstIndex ( of: " en " )
278- }
279-
280- guard
281- let localeStartIndex: Int = validLocaleStartIndex,
282- let countryNameIndex: Int = Array ( cache. countryLocationsGeonameId [ localeStartIndex... ] ) . firstIndex ( where: { geonameId in
283- geonameId == cache. countryBlocksGeonameId [ countryBlockGeonameIdIndex]
284- } ) ,
285- ( localeStartIndex + countryNameIndex) < cache. countryLocationsCountryName. count
286- else { return }
287-
288- let result : String = cache. countryLocationsCountryName [ localeStartIndex + countryNameIndex]
289- nameCache [ " \( ip) - \( currentLocale) " ] = result
290- }
291-
292- // MARK: - Functions
293-
294227 public func country( for ip: String ) -> String {
295228 guard _cacheLoaded. value else { return " resolving " . localized ( ) }
296229
297- return ( countryNamesCache [ " \( ip) - \( currentLocale) " ] ?? " onionRoutingPathUnknownCountry " . localized ( ) )
230+ /// Get local index for the current locale (when index is not found it should fallback to english)
231+ let validLocaleStartIndex : Int ? = (
232+ cache. countryLocationsLocaleCode. firstIndex ( of: currentLocale) ??
233+ cache. countryLocationsLocaleCode. firstIndex ( of: " en " )
234+ )
235+ let key : String = " \( ip) - \( currentLocale) "
236+
237+ switch countryNamesCache [ key] {
238+ case . some( let value) : return value
239+ case . none:
240+ guard
241+ let ipAsInt: Int64 = IPv4 . toInt ( ip) ,
242+ let countryBlockGeonameIdIndex: Int = cache. countryBlocksIPInt. firstIndex ( where: { $0 > ipAsInt } ) . map ( { $0 - 1 } ) ,
243+ let localeStartIndex: Int = validLocaleStartIndex,
244+ let countryNameIndex: Int = Array ( cache. countryLocationsGeonameId [ localeStartIndex... ] ) . firstIndex ( where: { geonameId in
245+ geonameId == cache. countryBlocksGeonameId [ countryBlockGeonameIdIndex]
246+ } ) ,
247+ ( localeStartIndex + countryNameIndex) < cache. countryLocationsCountryName. count
248+ else { return " onionRoutingPathUnknownCountry " . localized ( ) }
249+
250+ let result : String = cache. countryLocationsCountryName [ localeStartIndex + countryNameIndex]
251+ countryNamesCache [ key] = result
252+
253+ return result
254+ }
298255 }
299256}
300257
0 commit comments