Selaa lähdekoodia

implement DB migration from local to shared container

cyberta 5 vuotta sitten
vanhempi
commit
f581fd6b54

+ 4 - 0
deltachat-ios.xcodeproj/project.pbxproj

@@ -91,6 +91,7 @@
 		3095A351237DD1F700AB07F7 /* MediaPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3095A350237DD1F700AB07F7 /* MediaPicker.swift */; };
 		30A4D9AE2332672700544344 /* QrInviteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A4D9AD2332672600544344 /* QrInviteViewController.swift */; };
 		30C0D49D237C4908008E2A0E /* CertificateCheckController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30C0D49C237C4908008E2A0E /* CertificateCheckController.swift */; };
+		30ECA5472436026F006F2E7A /* DatabaseHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30ECA5462436026F006F2E7A /* DatabaseHelper.swift */; };
 		30F9B9EC235F2116006E7ACF /* MessageCounter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30F9B9EB235F2116006E7ACF /* MessageCounter.swift */; };
 		6795F63A82E94FF7CD2CEC0F /* Pods_deltachat_iosTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2F7009234DB9408201A6CDCB /* Pods_deltachat_iosTests.framework */; };
 		7070FB9B2101ECBB000DC258 /* NewGroupController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7070FB9A2101ECBB000DC258 /* NewGroupController.swift */; };
@@ -317,6 +318,7 @@
 		30A4D9AD2332672600544344 /* QrInviteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QrInviteViewController.swift; sourceTree = "<group>"; };
 		30AC265E237F1807002A943F /* AvatarHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarHelper.swift; sourceTree = "<group>"; };
 		30C0D49C237C4908008E2A0E /* CertificateCheckController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CertificateCheckController.swift; sourceTree = "<group>"; };
+		30ECA5462436026F006F2E7A /* DatabaseHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseHelper.swift; sourceTree = "<group>"; };
 		30F9B9EB235F2116006E7ACF /* MessageCounter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageCounter.swift; sourceTree = "<group>"; };
 		6241BE1534A653E79AD5D01D /* Pods_deltachat_ios.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_deltachat_ios.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		7070FB9A2101ECBB000DC258 /* NewGroupController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewGroupController.swift; sourceTree = "<group>"; };
@@ -794,6 +796,7 @@
 				AE1988A423EB2FBA00B4CD5F /* Errors.swift */,
 				AEFBE23023FF09B20045327A /* TypeAlias.swift */,
 				307D822D241669C7006D2490 /* LocationManager.swift */,
+				30ECA5462436026F006F2E7A /* DatabaseHelper.swift */,
 			);
 			path = Helper;
 			sourceTree = "<group>";
@@ -1158,6 +1161,7 @@
 				3040F45E234DFBC000FA34D5 /* Audio.swift in Sources */,
 				305961FE2346125100C80F33 /* InsetLabel.swift in Sources */,
 				3095A351237DD1F700AB07F7 /* MediaPicker.swift in Sources */,
+				30ECA5472436026F006F2E7A /* DatabaseHelper.swift in Sources */,
 				B21005DB23383664004C70C5 /* SettingsClassicViewController.swift in Sources */,
 				305961F62346125100C80F33 /* MessageContentCell.swift in Sources */,
 				305961E42346125100C80F33 /* MessageKitDateFormatter.swift in Sources */,

+ 5 - 9
deltachat-ios/AppDelegate.swift

@@ -125,16 +125,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         NotificationCenter.default.removeObserver(self, name: .reachabilityChanged, object: reachability)
     }
 
-    func dbfile() -> String {
-        let paths = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true)
-        let documentsPath = paths[0]
-
-        return documentsPath + "/messenger.db"
-    }
-
     func open() {
-        logger.info("open: \(dbfile())")
-        dcContext.openDatabase(dbFile: dbfile())
+        guard let databaseLocation = DatabaseHelper().testMove(toShared: true) else {
+            fatalError("Database could not be opened")
+        }
+        logger.info("open: \(databaseLocation)")
+        dcContext.openDatabase(dbFile: databaseLocation)
     }
 
     func setStockTranslations() {

+ 2 - 1
deltachat-ios/Controller/AccountSetupController.swift

@@ -804,7 +804,7 @@ class AccountSetupController: UITableViewController {
             return
         }
 
-        let dbfile = appDelegate.dbfile()
+        let dbfile = DatabaseHelper().currentDatabaseLocation
         let dburl = URL(fileURLWithPath: dbfile, isDirectory: false)
         let alert = UIAlertController(
             title: String.localized("delete_account_ask"),
@@ -815,6 +815,7 @@ class AccountSetupController: UITableViewController {
             appDelegate.stop()
             appDelegate.close()
             do {
+                //TODO: remove also blobs folder?!
                 try FileManager.default.removeItem(at: dburl)
             } catch {
                 logger.error("failed to delete db: \(error)")

+ 128 - 0
deltachat-ios/Helper/DatabaseHelper.swift

@@ -0,0 +1,128 @@
+import Foundation
+class DatabaseHelper {
+
+    var sharedDbFile: String {
+        guard let fileContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.eu.merlinux.group.chat.delta.ios") else {
+            return ""
+        }
+        let storeURL = fileContainer.appendingPathComponent("messenger.db")
+        return storeURL.path
+    }
+
+    var localDbFile: String {
+        return localDocumentsDir.appendingPathComponent("messenger.db").path
+    }
+
+    var sharedDbBlobsDir: String {
+        guard let fileContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.eu.merlinux.group.chat.delta.ios") else {
+            return ""
+        }
+        return fileContainer.appendingPathComponent("messenger.db-blobs").path
+    }
+
+    var localBlobsDir: String {
+        return localDocumentsDir.appendingPathComponent("messenger.db-blobs").path
+    }
+
+    var localDocumentsDir: URL {
+        let paths = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true)
+        return URL(fileURLWithPath: paths[0], isDirectory: true)
+    }
+
+    var currentDatabaseLocation: String {
+        let filemanager = FileManager.default
+        if filemanager.fileExists(atPath: localDbFile) {
+            return localDbFile
+        }
+        return sharedDbFile
+    }
+
+    func clearSharedDbBlobsDir() {
+      let fileManager = FileManager.default
+      do {
+        if fileManager.fileExists(atPath: sharedDbBlobsDir) {
+            let filePaths =  try fileManager.contentsOfDirectory(atPath: sharedDbBlobsDir)
+            for filePath in filePaths {
+                let completePath = URL(fileURLWithPath: sharedDbBlobsDir).appendingPathComponent(filePath)
+                try fileManager.removeItem(atPath: completePath.path)
+            }
+            try fileManager.removeItem(atPath: sharedDbBlobsDir)
+        }
+      } catch {
+          logger.error("Could not clean shared blobs dir, it might be it didn't exist")
+      }
+    }
+
+    func clearSharedDb() {
+        let filemanager = FileManager.default
+        if filemanager.fileExists(atPath: sharedDbFile) {
+            try? filemanager.removeItem(atPath: sharedDbFile)
+        }
+    }
+
+    func moveBlobsFolder() {
+        let filemanager = FileManager.default
+        if filemanager.fileExists(atPath: localBlobsDir) {
+            do {
+                clearSharedDbBlobsDir()
+                try filemanager.moveItem(at: URL(fileURLWithPath: localBlobsDir), to: URL(fileURLWithPath: sharedDbBlobsDir))
+            } catch let error {
+                logger.error("Could not move db blobs directory to shared space: \(error.localizedDescription)")
+            }
+        }
+    }
+
+    func updateDatabaseLocation() -> String? {
+      let filemanager = FileManager.default
+      if filemanager.fileExists(atPath: localDbFile) {
+          do {
+              clearSharedDb()
+              try filemanager.moveItem(at: URL(fileURLWithPath: localDbFile), to: URL(fileURLWithPath: sharedDbFile))
+              moveBlobsFolder()
+          } catch let error {
+              logger.error("Could not update DB location. Share extension will probably not work. \n\(error.localizedDescription)")
+              return localDbFile
+          }
+      }
+
+      return sharedDbFile
+    }
+
+    func testMove(toShared: Bool) -> String? {
+        if toShared {
+            return updateDatabaseLocation()
+        } else {
+            return reverse()
+        }
+    }
+
+    func reverse() -> String? {
+      let filemanager = FileManager.default
+      if  filemanager.fileExists(atPath: sharedDbFile) {
+          do {
+              if filemanager.fileExists(atPath: localDbFile) {
+                  logger.debug("remove local DB first, in order to move DB from shared to local space")
+                  try? filemanager.removeItem(atPath: localDbFile)
+              }
+              try filemanager.moveItem(at: URL(fileURLWithPath: sharedDbFile), to: URL(fileURLWithPath: localDbFile))
+              let filemanager = FileManager.default
+              if filemanager.fileExists(atPath: sharedDbBlobsDir) {
+                  if filemanager.fileExists(atPath: localBlobsDir) {
+                      try? filemanager.removeItem(atPath: localBlobsDir)
+                  }
+                  do {
+                  try filemanager.moveItem(at: URL(fileURLWithPath: sharedDbBlobsDir), to: URL(fileURLWithPath: localBlobsDir))
+                  } catch let error {
+                      logger.error("Could not move db blobs directory to shared space: \(error.localizedDescription)")
+                  }
+              }
+
+          } catch let error {
+              logger.error("Could not update DB location. Share extension will probably not work. \n\(error.localizedDescription)")
+              return sharedDbFile
+          }
+      }
+      return localDbFile
+    }
+
+}