1
0
mirror of https://github.com/immich-app/immich.git synced 2025-08-10 23:22:22 +02:00

feature(mobile): hash assets & sync via checksum (#2592)

* compare different sha1 implementations

* remove openssl sha1

* sync via checksum

* hash assets in batches

* hash in background, show spinner in tab

* undo tmp changes

* migrate by clearing assets

* ignore duplicate assets

* error handling

* trigger sync/merge after download and update view

* review feedback improvements

* hash in background isolate on iOS

* rework linking assets with existing from DB

* fine-grained errors on unique index violation

* hash lenth validation

* revert compute in background on iOS

* ignore duplicate assets on device

* fix bug with batching based on accumulated size

---------

Co-authored-by: Fynn Petersen-Frey <zoodyy@users.noreply.github.com>
This commit is contained in:
Fynn Petersen-Frey
2023-06-10 20:13:59 +02:00
committed by GitHub
parent 053a0482b4
commit 73075c64d1
28 changed files with 2315 additions and 507 deletions

View File

@@ -84,6 +84,7 @@ flutter {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
implementation "androidx.work:work-runtime-ktx:$work_version"
implementation "androidx.concurrent:concurrent-futures:$concurrent_version"
implementation "com.google.guava:guava:$guava_version"

View File

@@ -1,10 +1,15 @@
package app.alextran.immich
import android.content.Context
import android.util.Log
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import java.security.MessageDigest
import java.io.File
import java.io.FileInputStream
import kotlinx.coroutines.*
/**
* Android plugin for Dart `BackgroundService`
@@ -16,6 +21,7 @@ class BackgroundServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
private var methodChannel: MethodChannel? = null
private var context: Context? = null
private val sha1: MessageDigest = MessageDigest.getInstance("SHA-1")
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
onAttachedToEngine(binding.applicationContext, binding.binaryMessenger)
@@ -70,9 +76,40 @@ class BackgroundServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
"isIgnoringBatteryOptimizations" -> {
result.success(BackupWorker.isIgnoringBatteryOptimizations(ctx))
}
"digestFiles" -> {
val args = call.arguments<ArrayList<String>>()!!
GlobalScope.launch(Dispatchers.IO) {
val buf = ByteArray(BUFSIZE)
val digest: MessageDigest = MessageDigest.getInstance("SHA-1")
val hashes = arrayOfNulls<ByteArray>(args.size)
for (i in args.indices) {
val path = args[i]
var len = 0
try {
val file = FileInputStream(path)
try {
while (true) {
len = file.read(buf)
if (len != BUFSIZE) break
digest.update(buf)
}
} finally {
file.close()
}
digest.update(buf, 0, len)
hashes[i] = digest.digest()
} catch (e: Exception) {
// skip this file
Log.w(TAG, "Failed to hash file ${args[i]}: $e")
}
}
result.success(hashes.asList())
}
}
else -> result.notImplemented()
}
}
}
private const val TAG = "BackgroundServicePlugin"
private const val TAG = "BackgroundServicePlugin"
private const val BUFSIZE = 2*1024*1024;