damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

ImageCacheMigrations.swift (3694B)


      1 //
      2 //  ImageCacheMigrations.swift
      3 //  damus
      4 //
      5 //  Created by Daniel D’Aquino on 2025-04-26.
      6 //
      7 
      8 import Foundation
      9 import Kingfisher
     10 
     11 struct ImageCacheMigrations {
     12     static func migrateKingfisherCacheIfNeeded() {
     13         let fileManager = FileManager.default
     14         let defaults = UserDefaults.standard
     15         let migration1Key = "KingfisherCacheMigrated"   // Never ever changes
     16         let migration2Key = "KingfisherCacheMigratedV2" // Never ever changes
     17         
     18         let migration1Done = defaults.bool(forKey: migration1Key)
     19         let migration2Done = defaults.bool(forKey: migration2Key)
     20 
     21         guard !migration1Done || !migration2Done else {
     22             // All migrations are already done. Skip.
     23             return
     24         }
     25 
     26         let oldCachePath = migration1Done ? migration1KingfisherCachePath() : migration0KingfisherCachePath()
     27 
     28         // New shared cache location
     29         let newCachePath = kingfisherCachePath().path
     30 
     31         if fileManager.fileExists(atPath: oldCachePath) {
     32             do {
     33                 // Move the old cache to the new location
     34                 try fileManager.moveItem(atPath: oldCachePath, toPath: newCachePath)
     35                 Log.info("Successfully migrated Kingfisher cache to %s", for: .storage, newCachePath)
     36             } catch {
     37                 do {
     38                     // Cache data is not essential, fallback to deleting the cache and starting all over
     39                     // It's better than leaving significant garbage data stuck indefinitely on the user's phone
     40                     try fileManager.removeItem(atPath: newCachePath)
     41                     try fileManager.removeItem(atPath: oldCachePath)
     42                 }
     43                 catch {
     44                     Log.error("Failed to migrate cache: %s", for: .storage, error.localizedDescription)
     45                     return  // Do not mark them as complete, we can try again next time the user reloads the app
     46                 }
     47             }
     48         }
     49         
     50         // Mark migrations as complete
     51         defaults.set(true, forKey: migration1Key)
     52         defaults.set(true, forKey: migration2Key)
     53     }
     54     
     55     static private func migration0KingfisherCachePath() -> String {
     56         // Implementation note: These are old, so they should not be changed
     57         let defaultCache = ImageCache.default
     58         return defaultCache.diskStorage.directoryURL.path
     59     }
     60     
     61     static private func migration1KingfisherCachePath() -> String {
     62         // Implementation note: These are old, so they are hard-coded on purpose, because we can't change these values from the past.
     63         let groupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.damus")!
     64         return groupURL.appendingPathComponent("ImageCache").path
     65     }
     66     
     67     /// The latest path for kingfisher to store cached images on.
     68     ///
     69     /// Documentation references:
     70     /// - https://developer.apple.com/documentation/foundation/filemanager/containerurl(forsecurityapplicationgroupidentifier:)#:~:text=The%20system%20creates%20only%20the%20Library/Caches%20subdirectory%20automatically
     71     /// - https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html#:~:text=Put%20data%20cache,files%20as%20needed.
     72     static func kingfisherCachePath() -> URL {
     73         let groupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: Constants.DAMUS_APP_GROUP_IDENTIFIER)!
     74         return groupURL
     75             .appendingPathComponent("Library")
     76             .appendingPathComponent("Caches")
     77             .appendingPathComponent(Constants.IMAGE_CACHE_DIRNAME)
     78     }
     79 }