mirror of https://github.com/oxen-io/session-ios
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			71 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Swift
		
	
		
		
			
		
	
	
			71 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Swift
		
	
| 
											5 years ago
										 | 
 | ||
|  | final class IP2Country { | ||
| 
											5 years ago
										 |     var countryNamesCache: [String:String] = [:] | ||
| 
											5 years ago
										 | 
 | ||
| 
											5 years ago
										 |     private lazy var ipv4Table = try! CSV(name: "GeoLite2-Country-Blocks-IPv4", extension: "csv", bundle: .main, delimiter: ",", encoding: .utf8, loadColumns: true)! | ||
|  |     private lazy var countryNamesTable = try! CSV(name: "GeoLite2-Country-Locations-English", extension: "csv", bundle: .main, delimiter: ",", encoding: .utf8, loadColumns: true)! | ||
| 
											5 years ago
										 | 
 | ||
|  |     private static let workQueue = DispatchQueue(label: "IP2Country.workQueue", qos: .utility) // It's important that this is a serial queue | ||
| 
											5 years ago
										 | 
 | ||
| 
											5 years ago
										 |     static var isInitialized = false | ||
|  | 
 | ||
| 
											5 years ago
										 |     // MARK: Lifecycle | ||
|  |     static let shared = IP2Country() | ||
|  | 
 | ||
|  |     private init() { | ||
| 
											5 years ago
										 |         NotificationCenter.default.addObserver(self, selector: #selector(populateCacheIfNeededAsync), name: .pathsBuilt, object: nil) | ||
| 
											5 years ago
										 |     } | ||
|  | 
 | ||
|  |     deinit { | ||
|  |         NotificationCenter.default.removeObserver(self) | ||
|  |     } | ||
|  | 
 | ||
|  |     // MARK: Implementation | ||
| 
											5 years ago
										 |     private func cacheCountry(for ip: String) -> String { | ||
| 
											5 years ago
										 |         var truncatedIP = ip | ||
|  |         func getCountryInternal() -> String { | ||
| 
											5 years ago
										 |             if let country = countryNamesCache[ip] { return country } | ||
|  |             if let ipv4TableIndex = ipv4Table.namedColumns["network"]!.firstIndex(where: { $0.starts(with: truncatedIP) }) { | ||
|  |                 let countryID = ipv4Table.namedColumns["registered_country_geoname_id"]![ipv4TableIndex] | ||
|  |                 if let countryNamesTableIndex = countryNamesTable.namedColumns["geoname_id"]!.firstIndex(of: countryID) { | ||
|  |                     let country = countryNamesTable.namedColumns["country_name"]![countryNamesTableIndex] | ||
|  |                     countryNamesCache[ip] = country | ||
|  |                     return country | ||
|  |                 } | ||
|  |             } | ||
|  |             if truncatedIP.contains(".") && !truncatedIP.hasSuffix(".") { // The fuzziest we want to go is xxx.x | ||
|  |                 truncatedIP.removeLast() | ||
|  |                 if truncatedIP.hasSuffix(".") { truncatedIP.removeLast() } | ||
|  |                 return getCountryInternal() | ||
|  |             } else { | ||
|  |                 return "Unknown Country" | ||
|  |             } | ||
| 
											5 years ago
										 |         } | ||
|  |         return getCountryInternal() | ||
|  |     } | ||
|  | 
 | ||
| 
											5 years ago
										 |     @objc func populateCacheIfNeededAsync() { | ||
| 
											5 years ago
										 |         IP2Country.workQueue.async { | ||
| 
											5 years ago
										 |             let _ = self.populateCacheIfNeeded() | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     func populateCacheIfNeeded() -> Bool { | ||
| 
											5 years ago
										 |         if OnionRequestAPI.paths.isEmpty { | ||
| 
											5 years ago
										 |             OnionRequestAPI.paths = Storage.getOnionRequestPaths() | ||
| 
											5 years ago
										 |         } | ||
| 
											5 years ago
										 |         let paths = OnionRequestAPI.paths | ||
| 
											5 years ago
										 |         guard !paths.isEmpty else { return false } | ||
| 
											5 years ago
										 |         let pathToDisplay = paths.first! | ||
| 
											5 years ago
										 |         pathToDisplay.forEach { snode in | ||
|  |             let _ = self.cacheCountry(for: snode.ip) // Preload if needed | ||
|  |         } | ||
|  |         DispatchQueue.main.async { | ||
|  |             IP2Country.isInitialized = true | ||
|  |             NotificationCenter.default.post(name: .onionRequestPathCountriesLoaded, object: nil) | ||
|  |         } | ||
|  |         print("[Loki] Finished preloading onion request path countries.") | ||
|  |         return true | ||
| 
											5 years ago
										 |     } | ||
|  | } |