|
|
|
@ -30,6 +30,7 @@ import org.isoron.uhabits.core.tasks.*
|
|
|
|
|
import org.isoron.uhabits.tasks.*
|
|
|
|
|
import org.isoron.uhabits.utils.*
|
|
|
|
|
import java.io.*
|
|
|
|
|
import java.lang.RuntimeException
|
|
|
|
|
import javax.inject.*
|
|
|
|
|
|
|
|
|
|
@AppScope
|
|
|
|
@ -43,7 +44,7 @@ class SyncManager @Inject constructor(
|
|
|
|
|
|
|
|
|
|
private val server = RemoteSyncServer()
|
|
|
|
|
private val tmpFile = File.createTempFile("import", "", context.externalCacheDir)
|
|
|
|
|
private var currVersion = 0L
|
|
|
|
|
private var currVersion = 1L
|
|
|
|
|
private var dirty = true
|
|
|
|
|
|
|
|
|
|
private lateinit var encryptionKey: EncryptionKey
|
|
|
|
@ -72,35 +73,53 @@ class SyncManager @Inject constructor(
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private suspend fun push() {
|
|
|
|
|
if (!dirty) {
|
|
|
|
|
Log.i("SyncManager", "Database not dirty. Skipping upload.")
|
|
|
|
|
return
|
|
|
|
|
private suspend fun push(depth: Int = 0) {
|
|
|
|
|
if(depth >= 5) {
|
|
|
|
|
throw RuntimeException()
|
|
|
|
|
}
|
|
|
|
|
Log.i("SyncManager", "Encrypting database...")
|
|
|
|
|
if (dirty) {
|
|
|
|
|
Log.i("SyncManager", "Encrypting local database...")
|
|
|
|
|
val db = DatabaseUtils.getDatabaseFile(context)
|
|
|
|
|
val encryptedDB = db.encryptToString(encryptionKey)
|
|
|
|
|
Log.i("SyncManager", "Uploading database (version ${currVersion}, ${encryptedDB.length / 1024} KB)")
|
|
|
|
|
val size = encryptedDB.length / 1024
|
|
|
|
|
Log.i("SyncManager", "Pushing local database (version $currVersion, $size KB)")
|
|
|
|
|
try {
|
|
|
|
|
server.put(preferences.syncKey, SyncData(currVersion, encryptedDB))
|
|
|
|
|
dirty = false
|
|
|
|
|
} catch (e: EditConflictException) {
|
|
|
|
|
Log.i("SyncManager", "Sync conflict detected while pushing.")
|
|
|
|
|
setCurrentVersion(0)
|
|
|
|
|
pull()
|
|
|
|
|
push(depth = depth + 1)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
Log.i("SyncManager", "Local database not modified. Skipping push.")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private suspend fun pull() {
|
|
|
|
|
Log.i("SyncManager", "Fetching database from server...")
|
|
|
|
|
val data = server.getData(preferences.syncKey)
|
|
|
|
|
Log.i("SyncManager", "Fetched database (version ${data.version}, ${data.content.length / 1024} KB)")
|
|
|
|
|
if (data.version == 0L) {
|
|
|
|
|
Log.i("SyncManager", "Initial upload detected. Marking db as dirty.")
|
|
|
|
|
dirty = true
|
|
|
|
|
}
|
|
|
|
|
if (data.version <= currVersion) {
|
|
|
|
|
Log.i("SyncManager", "Local version is up-to-date. Skipping merge.")
|
|
|
|
|
Log.i("SyncManager", "Querying remote database version...")
|
|
|
|
|
val remoteVersion = server.getDataVersion(syncKey)
|
|
|
|
|
Log.i("SyncManager", "Remote database has version $remoteVersion")
|
|
|
|
|
|
|
|
|
|
if (remoteVersion <= currVersion) {
|
|
|
|
|
Log.i("SyncManager", "Local database is up-to-date. Skipping merge.")
|
|
|
|
|
} else {
|
|
|
|
|
Log.i("SyncManager", "Decrypting and merging with local changes...")
|
|
|
|
|
Log.i("SyncManager", "Pulling remote database...")
|
|
|
|
|
val data = server.getData(syncKey)
|
|
|
|
|
val size = data.content.length / 1024
|
|
|
|
|
Log.i("SyncManager", "Pulled remote database (version ${data.version}, $size KB)")
|
|
|
|
|
Log.i("SyncManager", "Decrypting remote database and merging with local changes...")
|
|
|
|
|
data.content.decryptToFile(encryptionKey, tmpFile)
|
|
|
|
|
taskRunner.execute(importDataTaskFactory.create(tmpFile) { tmpFile.delete() })
|
|
|
|
|
dirty = true
|
|
|
|
|
setCurrentVersion(data.version + 1)
|
|
|
|
|
}
|
|
|
|
|
currVersion = data.version + 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun setCurrentVersion(v: Long) {
|
|
|
|
|
currVersion = v
|
|
|
|
|
Log.i("SyncManager", "Setting local database version to $currVersion")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
suspend fun onResume() {
|
|
|
|
@ -118,6 +137,9 @@ class SyncManager @Inject constructor(
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onCommandExecuted(command: Command?, refreshKey: Long?) {
|
|
|
|
|
if (!dirty) {
|
|
|
|
|
setCurrentVersion(currVersion + 1)
|
|
|
|
|
}
|
|
|
|
|
dirty = true
|
|
|
|
|
}
|
|
|
|
|
}
|