Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import com.simprints.infra.config.store.local.migrations.ProjectConfigFingerprin
import com.simprints.infra.config.store.local.migrations.ProjectConfigLedsModeMigration
import com.simprints.infra.config.store.local.migrations.ProjectConfigMatchingModalitiesMigration
import com.simprints.infra.config.store.local.migrations.ProjectConfigQualityThresholdMigration
import com.simprints.infra.config.store.local.migrations.ProjectConfigSampleUploadMigration
import com.simprints.infra.config.store.local.migrations.ProjectConfigSharedPrefsMigration
import com.simprints.infra.config.store.local.migrations.ProjectRealmMigration
import com.simprints.infra.config.store.local.models.ProtoDeviceConfiguration
Expand Down Expand Up @@ -76,6 +77,7 @@ object DataStoreModule {
projectConfigLedsModeMigration: ProjectConfigLedsModeMigration,
projectConfigMatchingModalitiesMigration: ProjectConfigMatchingModalitiesMigration,
projectConfigFaceEmptyVersionMigration: ProjectConfigFaceEmptyVersionMigration,
projectConfigSampleUploadMigration: ProjectConfigSampleUploadMigration,
): DataStore<ProtoProjectConfiguration> = DataStoreFactory.create(
serializer = ProjectConfigurationSerializer,
produceFile = { appContext.dataStoreFile(PROJECT_CONFIG_DATA_STORE_FILE_NAME) },
Expand All @@ -88,6 +90,7 @@ object DataStoreModule {
projectConfigLedsModeMigration,
projectConfigMatchingModalitiesMigration,
projectConfigFaceEmptyVersionMigration,
projectConfigSampleUploadMigration,
),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import com.simprints.infra.config.store.models.GeneralConfiguration
import com.simprints.infra.config.store.models.IdentificationConfiguration
import com.simprints.infra.config.store.models.Project
import com.simprints.infra.config.store.models.ProjectConfiguration
import com.simprints.infra.config.store.models.SampleSynchronizationConfiguration
import com.simprints.infra.config.store.models.SettingsPasswordConfig
import com.simprints.infra.config.store.models.SynchronizationConfiguration
import com.simprints.infra.config.store.models.TokenKeyType
Expand All @@ -37,7 +38,7 @@ internal class ConfigLocalDataSourceImpl @Inject constructor(
private val projectDataStore: DataStore<ProtoProject>,
private val configDataStore: DataStore<ProtoProjectConfiguration>,
private val deviceConfigDataStore: DataStore<ProtoDeviceConfiguration>,
private val tokenizationProcessor: TokenizationProcessor
private val tokenizationProcessor: TokenizationProcessor,
) : ConfigLocalDataSource {
override suspend fun saveProject(project: Project) {
projectDataStore.updateData { project.toProto() }
Expand Down Expand Up @@ -73,21 +74,20 @@ internal class ConfigLocalDataSourceImpl @Inject constructor(

override suspend fun getProjectConfiguration(): ProjectConfiguration = configDataStore.data.first().toDomain()

override fun watchProjectConfiguration(): Flow<ProjectConfiguration> =
configDataStore.data.map(ProtoProjectConfiguration::toDomain)
override fun watchProjectConfiguration(): Flow<ProjectConfiguration> = configDataStore.data.map(ProtoProjectConfiguration::toDomain)

override suspend fun clearProjectConfiguration() {
configDataStore.updateData { it.toBuilder().clear().build() }
}

override suspend fun getDeviceConfiguration(): DeviceConfiguration {
val config = deviceConfigDataStore.data.first().toDomain()
val tokenizedModules = config.selectedModules.map {moduleId ->
when(moduleId) {
val tokenizedModules = config.selectedModules.map { moduleId ->
when (moduleId) {
is TokenizableString.Raw -> tokenizationProcessor.encrypt(
decrypted = moduleId,
tokenKeyType = TokenKeyType.ModuleId,
project = getProject()
project = getProject(),
)
is TokenizableString.Tokenized -> moduleId
}
Expand Down Expand Up @@ -229,6 +229,9 @@ internal class ConfigLocalDataSourceImpl @Inject constructor(
moduleOptions = listOf(),
maxAge = DEFAULT_DOWN_SYNC_MAX_AGE,
),
samples = SampleSynchronizationConfiguration(
signedUrlBatchSize = 1,
),
),
custom = null,
).toProto()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.simprints.infra.config.store.local.migrations

import androidx.datastore.core.DataMigration
import com.simprints.infra.config.store.local.models.ProtoProjectConfiguration
import com.simprints.infra.config.store.local.models.ProtoSampleSynchronizationConfiguration
import com.simprints.infra.logging.LoggingConstants.CrashReportTag.MIGRATION
import com.simprints.infra.logging.Simber
import javax.inject.Inject

/**
* Can be removed once all the devices have been updated to 2025.3.0
*/
class ProjectConfigSampleUploadMigration @Inject constructor() : DataMigration<ProtoProjectConfiguration> {
override suspend fun cleanUp() {
Simber.i("Migration of project configuration sample upload is done", tag = MIGRATION)
}

override suspend fun shouldMigrate(currentData: ProtoProjectConfiguration) = with(currentData) {
val hasNoSamplesSyncObject = !synchronization.hasSamples()
val eventSyncBatchSizeIsEmpty = synchronization.up.simprints.batchSizes
.let { it.eventUpSyncs == 0 || it.eventDownSyncs == 0 }

hasNoSamplesSyncObject || eventSyncBatchSizeIsEmpty
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just a general comment

Don't you find such conditions difficult to read? While it is a relatively short notation, wouldn't it be better to write such conditions in more human-friendly format?

with (currentData) {
    val hasNoSamples = !synchronization.hasSamples()
    val batchSizeIsEmpty = synchronization.up.simprints.batchSizes
                  .let { it.eventUpSyncs == 0 || it.eventDownSyncs == 0 }
    return@with hasNoSamples || batchSizeIsEmpty
}


override suspend fun migrate(currentData: ProtoProjectConfiguration): ProtoProjectConfiguration {
Simber.i("Start migration of project configuration sample upload", tag = MIGRATION)

val currentSyncConfig = currentData.synchronization
val currentBatchSizes = currentSyncConfig.up.simprints.batchSizes
val upBatchSizes = currentBatchSizes
.toBuilder()
.setEventUpSyncs(currentBatchSizes.upSyncs)
.setEventDownSyncs(currentBatchSizes.downSyncs)
.setSampleUpSyncs(DEFAULT_BATCH_SIZE)
.build()
val upSyncSimprintsConfig = currentSyncConfig.up.simprints
.toBuilder()
.setBatchSizes(upBatchSizes)
.build()
val upSyncConfig = currentSyncConfig.up
.toBuilder()
.setSimprints(upSyncSimprintsConfig)
.build()
val samplesConfig = ProtoSampleSynchronizationConfiguration.newBuilder().setSignedUrlBatchSize(DEFAULT_BATCH_SIZE).build()

return currentData
.toBuilder()
.setSynchronization(
currentSyncConfig
.toBuilder()
.setUp(upSyncConfig)
.setSamples(samplesConfig)
.build(),
).build()
}

companion object {
private const val DEFAULT_BATCH_SIZE = 1
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.simprints.infra.config.store.models.FingerprintConfiguration
import com.simprints.infra.config.store.models.GeneralConfiguration
import com.simprints.infra.config.store.models.IdentificationConfiguration
import com.simprints.infra.config.store.models.ProjectConfiguration
import com.simprints.infra.config.store.models.SampleSynchronizationConfiguration
import com.simprints.infra.config.store.models.SettingsPasswordConfig
import com.simprints.infra.config.store.models.SynchronizationConfiguration
import com.simprints.infra.config.store.models.UpSynchronizationConfiguration
Expand Down Expand Up @@ -226,9 +227,10 @@ internal data class OldProjectConfig(
)
},
batchSizes = UpSynchronizationConfiguration.UpSyncBatchSizes(
sessions = 1,
upSyncs = 1,
downSyncs = 1,
sessions = DEFAULT_BATCH_SIZE,
eventUpSyncs = DEFAULT_BATCH_SIZE,
eventDownSyncs = DEFAULT_BATCH_SIZE,
sampleUpSyncs = DEFAULT_BATCH_SIZE,
),
imagesRequireUnmeteredConnection = false,
),
Expand All @@ -254,6 +256,9 @@ internal data class OldProjectConfig(
moduleOptions = moduleIdOptions.split("|").map(String::asTokenizableRaw),
maxAge = DownSynchronizationConfiguration.DEFAULT_DOWN_SYNC_MAX_AGE,
),
samples = SampleSynchronizationConfiguration(
signedUrlBatchSize = DEFAULT_BATCH_SIZE,
),
)

private fun parseDecisionPolicy(decisionPolicy: String): DecisionPolicy = with(JSONObject(decisionPolicy)) {
Expand All @@ -267,5 +272,6 @@ internal data class OldProjectConfig(
companion object {
private const val DEFAULT_FACE_FRAMES_TO_CAPTURE = 2
private const val DEFAULT_FACE_SDK_VERSION = "1.23"
private const val DEFAULT_BATCH_SIZE = 1
}
}
Original file line number Diff line number Diff line change
@@ -1,30 +1,33 @@
package com.simprints.infra.config.store.local.models

import com.simprints.infra.config.store.exceptions.InvalidProtobufEnumException
import com.simprints.infra.config.store.local.models.ProtoSynchronizationConfiguration.Frequency
import com.simprints.infra.config.store.models.SynchronizationConfiguration

internal fun SynchronizationConfiguration.toProto(): ProtoSynchronizationConfiguration = ProtoSynchronizationConfiguration
.newBuilder()
.setFrequency(frequency.toProto())
.setDown(down.toProto())
.setUp(up.toProto())
.setSamples(samples.toProto())
.build()

internal fun SynchronizationConfiguration.Frequency.toProto(): ProtoSynchronizationConfiguration.Frequency = when (this) {
SynchronizationConfiguration.Frequency.ONLY_PERIODICALLY_UP_SYNC -> ProtoSynchronizationConfiguration.Frequency.ONLY_PERIODICALLY_UP_SYNC
SynchronizationConfiguration.Frequency.PERIODICALLY -> ProtoSynchronizationConfiguration.Frequency.PERIODICALLY
SynchronizationConfiguration.Frequency.PERIODICALLY_AND_ON_SESSION_START -> ProtoSynchronizationConfiguration.Frequency.PERIODICALLY_AND_ON_SESSION_START
internal fun SynchronizationConfiguration.Frequency.toProto(): Frequency = when (this) {
SynchronizationConfiguration.Frequency.ONLY_PERIODICALLY_UP_SYNC -> Frequency.ONLY_PERIODICALLY_UP_SYNC
SynchronizationConfiguration.Frequency.PERIODICALLY -> Frequency.PERIODICALLY
SynchronizationConfiguration.Frequency.PERIODICALLY_AND_ON_SESSION_START -> Frequency.PERIODICALLY_AND_ON_SESSION_START
}

internal fun ProtoSynchronizationConfiguration.toDomain(): SynchronizationConfiguration = SynchronizationConfiguration(
frequency.toDomain(),
up.toDomain(),
down.toDomain(),
frequency = frequency.toDomain(),
up = up.toDomain(),
down = down.toDomain(),
samples = samples.toDomain(),
)

internal fun ProtoSynchronizationConfiguration.Frequency.toDomain(): SynchronizationConfiguration.Frequency = when (this) {
ProtoSynchronizationConfiguration.Frequency.ONLY_PERIODICALLY_UP_SYNC -> SynchronizationConfiguration.Frequency.ONLY_PERIODICALLY_UP_SYNC
ProtoSynchronizationConfiguration.Frequency.PERIODICALLY -> SynchronizationConfiguration.Frequency.PERIODICALLY
ProtoSynchronizationConfiguration.Frequency.PERIODICALLY_AND_ON_SESSION_START -> SynchronizationConfiguration.Frequency.PERIODICALLY_AND_ON_SESSION_START
ProtoSynchronizationConfiguration.Frequency.UNRECOGNIZED -> throw InvalidProtobufEnumException("invalid Frequency $name")
internal fun Frequency.toDomain(): SynchronizationConfiguration.Frequency = when (this) {
Frequency.ONLY_PERIODICALLY_UP_SYNC -> SynchronizationConfiguration.Frequency.ONLY_PERIODICALLY_UP_SYNC
Frequency.PERIODICALLY -> SynchronizationConfiguration.Frequency.PERIODICALLY
Frequency.PERIODICALLY_AND_ON_SESSION_START -> SynchronizationConfiguration.Frequency.PERIODICALLY_AND_ON_SESSION_START
Frequency.UNRECOGNIZED -> throw InvalidProtobufEnumException("invalid Frequency $name")
}
Original file line number Diff line number Diff line change
@@ -1,66 +1,78 @@
package com.simprints.infra.config.store.local.models

import com.simprints.infra.config.store.exceptions.InvalidProtobufEnumException
import com.simprints.infra.config.store.models.SampleSynchronizationConfiguration
import com.simprints.infra.config.store.models.UpSynchronizationConfiguration
import com.simprints.infra.config.store.models.UpSynchronizationConfiguration.UpSynchronizationKind

internal fun UpSynchronizationConfiguration.toProto(): ProtoUpSynchronizationConfiguration = ProtoUpSynchronizationConfiguration
.newBuilder()
.setSimprints(simprints.toProto())
.setCoSync(coSync.toProto())
.build()

internal fun UpSynchronizationConfiguration.SimprintsUpSynchronizationConfiguration.toProto(): ProtoUpSynchronizationConfiguration.SimprintsUpSynchronizationConfiguration =
internal fun UpSynchronizationConfiguration.SimprintsUpSynchronizationConfiguration.toProto() =
ProtoUpSynchronizationConfiguration.SimprintsUpSynchronizationConfiguration
.newBuilder()
.setKind(kind.toProto())
.setBatchSizes(batchSizes.toProto())
.setImagesRequireUnmeteredConnection(imagesRequireUnmeteredConnection)
.build()

internal fun UpSynchronizationConfiguration.CoSyncUpSynchronizationConfiguration.toProto(): ProtoUpSynchronizationConfiguration.CoSyncUpSynchronizationConfiguration =
internal fun UpSynchronizationConfiguration.CoSyncUpSynchronizationConfiguration.toProto() =
ProtoUpSynchronizationConfiguration.CoSyncUpSynchronizationConfiguration
.newBuilder()
.setKind(kind.toProto())
.build()

internal fun UpSynchronizationConfiguration.UpSynchronizationKind.toProto(): ProtoUpSynchronizationConfiguration.UpSynchronizationKind =
when (this) {
UpSynchronizationConfiguration.UpSynchronizationKind.NONE -> ProtoUpSynchronizationConfiguration.UpSynchronizationKind.NONE
UpSynchronizationConfiguration.UpSynchronizationKind.ONLY_ANALYTICS -> ProtoUpSynchronizationConfiguration.UpSynchronizationKind.ONLY_ANALYTICS
UpSynchronizationConfiguration.UpSynchronizationKind.ONLY_BIOMETRICS -> ProtoUpSynchronizationConfiguration.UpSynchronizationKind.ONLY_BIOMETRICS
UpSynchronizationConfiguration.UpSynchronizationKind.ALL -> ProtoUpSynchronizationConfiguration.UpSynchronizationKind.ALL
}
internal fun UpSynchronizationKind.toProto(): ProtoUpSynchronizationConfiguration.UpSynchronizationKind = when (this) {
UpSynchronizationKind.NONE -> ProtoUpSynchronizationConfiguration.UpSynchronizationKind.NONE
UpSynchronizationKind.ONLY_ANALYTICS -> ProtoUpSynchronizationConfiguration.UpSynchronizationKind.ONLY_ANALYTICS
UpSynchronizationKind.ONLY_BIOMETRICS -> ProtoUpSynchronizationConfiguration.UpSynchronizationKind.ONLY_BIOMETRICS
UpSynchronizationKind.ALL -> ProtoUpSynchronizationConfiguration.UpSynchronizationKind.ALL
}

internal fun UpSynchronizationConfiguration.UpSyncBatchSizes.toProto(): ProtoUpSyncBatchSizes = ProtoUpSyncBatchSizes
internal fun UpSynchronizationConfiguration.UpSyncBatchSizes.toProto() = ProtoUpSyncBatchSizes
.newBuilder()
.setSessions(sessions)
.setUpSyncs(upSyncs)
.setDownSyncs(downSyncs)
.setEventUpSyncs(eventUpSyncs)
.setEventDownSyncs(eventDownSyncs)
.setSampleUpSyncs(sampleUpSyncs)
.build()

internal fun ProtoUpSynchronizationConfiguration.toDomain(): UpSynchronizationConfiguration =
UpSynchronizationConfiguration(simprints.toDomain(), coSync.toDomain())
internal fun SampleSynchronizationConfiguration.toProto() = ProtoSampleSynchronizationConfiguration
.newBuilder()
.setSignedUrlBatchSize(signedUrlBatchSize)
.build()

internal fun ProtoUpSynchronizationConfiguration.toDomain() = UpSynchronizationConfiguration(
simprints.toDomain(),
coSync.toDomain(),
)

internal fun ProtoUpSynchronizationConfiguration.SimprintsUpSynchronizationConfiguration.toDomain(): UpSynchronizationConfiguration.SimprintsUpSynchronizationConfiguration =
internal fun ProtoUpSynchronizationConfiguration.SimprintsUpSynchronizationConfiguration.toDomain() =
UpSynchronizationConfiguration.SimprintsUpSynchronizationConfiguration(
kind.toDomain(),
batchSizes.toDomain(),
imagesRequireUnmeteredConnection,
)

internal fun ProtoUpSynchronizationConfiguration.CoSyncUpSynchronizationConfiguration.toDomain(): UpSynchronizationConfiguration.CoSyncUpSynchronizationConfiguration =
internal fun ProtoUpSynchronizationConfiguration.CoSyncUpSynchronizationConfiguration.toDomain() =
UpSynchronizationConfiguration.CoSyncUpSynchronizationConfiguration(kind.toDomain())

internal fun ProtoUpSynchronizationConfiguration.UpSynchronizationKind.toDomain(): UpSynchronizationConfiguration.UpSynchronizationKind =
when (this) {
ProtoUpSynchronizationConfiguration.UpSynchronizationKind.NONE -> UpSynchronizationConfiguration.UpSynchronizationKind.NONE
ProtoUpSynchronizationConfiguration.UpSynchronizationKind.ONLY_ANALYTICS -> UpSynchronizationConfiguration.UpSynchronizationKind.ONLY_ANALYTICS
ProtoUpSynchronizationConfiguration.UpSynchronizationKind.ONLY_BIOMETRICS -> UpSynchronizationConfiguration.UpSynchronizationKind.ONLY_BIOMETRICS
ProtoUpSynchronizationConfiguration.UpSynchronizationKind.ALL -> UpSynchronizationConfiguration.UpSynchronizationKind.ALL
ProtoUpSynchronizationConfiguration.UpSynchronizationKind.UNRECOGNIZED -> throw InvalidProtobufEnumException(
"invalid UpSynchronizationKind $name",
)
}
internal fun ProtoUpSynchronizationConfiguration.UpSynchronizationKind.toDomain() = when (this) {
ProtoUpSynchronizationConfiguration.UpSynchronizationKind.NONE -> UpSynchronizationKind.NONE
ProtoUpSynchronizationConfiguration.UpSynchronizationKind.ONLY_ANALYTICS -> UpSynchronizationKind.ONLY_ANALYTICS
ProtoUpSynchronizationConfiguration.UpSynchronizationKind.ONLY_BIOMETRICS -> UpSynchronizationKind.ONLY_BIOMETRICS
ProtoUpSynchronizationConfiguration.UpSynchronizationKind.ALL -> UpSynchronizationKind.ALL
ProtoUpSynchronizationConfiguration.UpSynchronizationKind.UNRECOGNIZED -> throw InvalidProtobufEnumException(
"invalid UpSynchronizationKind $name",
)
}

internal fun ProtoUpSyncBatchSizes.toDomain(): UpSynchronizationConfiguration.UpSyncBatchSizes =
UpSynchronizationConfiguration.UpSyncBatchSizes(sessions, upSyncs, downSyncs)
UpSynchronizationConfiguration.UpSyncBatchSizes(sessions, eventUpSyncs, eventDownSyncs, sampleUpSyncs)

internal fun ProtoSampleSynchronizationConfiguration.toDomain() = SampleSynchronizationConfiguration(
signedUrlBatchSize = signedUrlBatchSize,
)
Loading