Add Rust interface for Kotlin vault merge logic (#1404)

This commit is contained in:
Leendert de Borst
2026-01-10 22:25:41 +01:00
parent d1560347f0
commit 689ab017cf
5 changed files with 38 additions and 11 deletions

View File

@@ -73,7 +73,7 @@ class VaultStore(
private val query = VaultQuery(databaseComponent)
internal val metadata = VaultMetadataManager(storageProvider)
private val auth = VaultAuth(storageProvider) { cache.clearCache() }
private val sync = VaultSync(databaseComponent, metadata, crypto)
private val sync = VaultSync(databaseComponent, metadata, crypto, storageProvider)
private val mutate = VaultMutate(databaseComponent, query, metadata)
private val cache = VaultCache(crypto, databaseComponent, keystoreProvider, storageProvider)
private val passkey = VaultPasskey(databaseComponent, query)

View File

@@ -3,7 +3,9 @@ package net.aliasvault.app.vaultstore
import android.util.Log
import net.aliasvault.app.exceptions.SerializationException
import net.aliasvault.app.exceptions.VaultOperationException
import net.aliasvault.app.rustcore.VaultMergeService
import net.aliasvault.app.utils.AppInfo
import net.aliasvault.app.vaultstore.storageprovider.StorageProvider
import net.aliasvault.app.vaultstore.utils.VersionComparison
import org.json.JSONObject
@@ -14,6 +16,7 @@ class VaultSync(
private val database: VaultDatabase,
private val metadata: VaultMetadataManager,
private val crypto: VaultCrypto,
private val storageProvider: StorageProvider,
) {
companion object {
private const val TAG = "VaultSync"
@@ -261,7 +264,7 @@ class VaultSync(
/**
* Perform merge sync (both local and server have changes).
*/
@Suppress("UnusedParameter") // serverRevision will be used when Rust merge is implemented
@Suppress("UnusedParameter") // serverRevision will be used for conflict resolution metadata in the future
private suspend fun performMergeSync(
webApiService: net.aliasvault.app.webapi.WebApiService,
mutate: VaultMutate,
@@ -285,8 +288,6 @@ class VaultSync(
}
// Perform LWW merge using Rust core library
// TODO: Call actual Rust merge function via Kotlin bindings
// For now, we preserve local changes (same as before)
val mergedVault = performLWWMerge(localVault, serverVault.vault.blob)
// Store merged vault with race detection
@@ -352,15 +353,27 @@ class VaultSync(
}
/**
* Perform Last-Write-Wins merge between local and server vaults.
* TODO: Integrate with Rust core library for actual merge logic.
* Perform Last-Write-Wins merge between local and server vaults using Rust core library.
*
* @param localVault Base64-encoded encrypted local vault
* @param serverVault Base64-encoded encrypted server vault
* @return Base64-encoded encrypted merged vault
*/
@Suppress("UnusedParameter") // serverVault will be used when Rust merge is implemented
private fun performLWWMerge(localVault: String, serverVault: String): String {
// TODO: Call Rust core's merge function via Kotlin bindings
// For now, preserve local changes (temporary behavior)
Log.w(TAG, "LWW merge not yet implemented - preserving local changes")
return localVault
val encryptionKey = crypto.encryptionKey
?: throw VaultOperationException("Encryption key not available for merge")
return try {
VaultMergeService.mergeVaults(
localVaultBase64 = localVault,
serverVaultBase64 = serverVault,
encryptionKey = encryptionKey,
tempDir = storageProvider.getCacheDir(),
)
} catch (e: VaultMergeService.VaultMergeException) {
Log.e(TAG, "Rust merge failed: ${e.message}", e)
throw VaultOperationException("Vault merge failed: ${e.message}", e)
}
}
/**

View File

@@ -199,4 +199,8 @@ class AndroidStorageProvider(private val context: Context) : StorageProvider {
}
// endregion
override fun getCacheDir(): File {
return context.cacheDir
}
}

View File

@@ -168,4 +168,10 @@ interface StorageProvider {
fun clearSyncState()
// endregion
/**
* Get the cache directory for temporary files.
* @return The cache directory
*/
fun getCacheDir(): File
}

View File

@@ -137,4 +137,8 @@ class TestStorageProvider : StorageProvider {
}
// endregion
override fun getCacheDir(): File {
return File(System.getProperty("java.io.tmpdir") ?: "/tmp")
}
}