Migrate preferencesDataStoreFile to a file using a hash, to fix a crash if the userId is too long.

This commit is contained in:
Benoit Marty
2024-01-16 14:02:40 +01:00
committed by Benoit Marty
parent a9776f9fcb
commit 9f4164a287
2 changed files with 24 additions and 1 deletions

View File

@@ -34,6 +34,7 @@ anvil {
dependencies {
implementation(libs.dagger)
implementation(projects.libraries.architecture)
implementation(projects.libraries.androidutils)
implementation(projects.libraries.core)
implementation(projects.libraries.matrix.api)
implementation(projects.libraries.pushstore.api)

View File

@@ -23,12 +23,15 @@ import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import androidx.datastore.preferences.preferencesDataStoreFile
import io.element.android.libraries.androidutils.hash.hash
import io.element.android.libraries.core.bool.orTrue
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.pushstore.api.UserPushStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import timber.log.Timber
/**
* Store data related to push about a user.
@@ -37,7 +40,24 @@ class UserPushStoreDataStore(
private val context: Context,
userId: SessionId,
) : UserPushStore {
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "push_store_$userId")
// Hash the sessionId to get ride of exotic chars and take only the first 16 chars.
// The risk of collision is not high.
private val preferenceName = "push_store_${userId.value.hash().take(16)}"
init {
// Migrate legacy data. Previous file can be too long if the userId is too long. The userId can be up to 255 chars.
// Example of long file path, with `averylonguserid` replacing a very longer name
// /data/user/0/io.element.android.x.debug/files/datastore/push_store_@averylonguserid:example.org.preferences_pb
val legacyFile = context.preferencesDataStoreFile("push_store_$userId")
if (legacyFile.exists()) {
Timber.d("Migrating legacy push data store for $userId")
if (!legacyFile.renameTo(context.preferencesDataStoreFile(preferenceName))) {
Timber.w("Failed to migrate legacy push data store for $userId")
}
}
}
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = preferenceName)
private val pushProviderName = stringPreferencesKey("pushProviderName")
private val currentPushKey = stringPreferencesKey("currentPushKey")
private val notificationEnabled = booleanPreferencesKey("notificationEnabled")
@@ -81,4 +101,6 @@ class UserPushStoreDataStore(
it.clear()
}
}
}
}