diff --git a/STCore/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/SharedApiUrlCreator.kt b/STCore/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/SharedApiUrlCreator.kt index 8ed45557..03b68efd 100644 --- a/STCore/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/SharedApiUrlCreator.kt +++ b/STCore/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/SharedApiUrlCreator.kt @@ -21,6 +21,7 @@ import com.infomaniak.multiplatform_swisstransfer.common.exceptions.RealmExcepti import com.infomaniak.multiplatform_swisstransfer.database.controllers.TransferController import com.infomaniak.multiplatform_swisstransfer.database.controllers.UploadController import com.infomaniak.multiplatform_swisstransfer.network.utils.SharedApiRoutes +import kotlin.coroutines.cancellation.CancellationException /** * Utility class responsible for creating API URLs for shared routes. @@ -33,14 +34,14 @@ class SharedApiUrlCreator internal constructor( fun shareTransferUrl(transferUUID: String) = SharedApiRoutes.shareTransfer(transferUUID) - @Throws(RealmException::class) - fun downloadFilesUrl(transferUUID: String): String? { + @Throws(RealmException::class, CancellationException::class) + suspend fun downloadFilesUrl(transferUUID: String): String? { val transfer = transferController.getTransfer(transferUUID) ?: return null return SharedApiRoutes.downloadFiles(transfer.downloadHost, transfer.linkUUID) } - @Throws(RealmException::class) - fun downloadFileUrl(transferUUID: String, fileUUID: String?): String? { + @Throws(RealmException::class, CancellationException::class) + suspend fun downloadFileUrl(transferUUID: String, fileUUID: String?): String? { val transfer = transferController.getTransfer(transferUUID) ?: return null return SharedApiRoutes.downloadFile(transfer.downloadHost, transfer.linkUUID, fileUUID) } diff --git a/STCore/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/managers/TransferManager.kt b/STCore/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/managers/TransferManager.kt index 82539e55..96b30a02 100644 --- a/STCore/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/managers/TransferManager.kt +++ b/STCore/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/managers/TransferManager.kt @@ -122,7 +122,7 @@ class TransferManager internal constructor( * * @return A transfer matching the specified transferUUID or null. */ - fun getTransferByUUID(transferUUID: String): TransferUi? { + suspend fun getTransferByUUID(transferUUID: String): TransferUi? { return transferController.getTransfer(transferUUID)?.let(::TransferUi) } diff --git a/STDatabase/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/database/RealmProvider.kt b/STDatabase/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/database/RealmProvider.kt index be5d02b0..4908c757 100644 --- a/STDatabase/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/database/RealmProvider.kt +++ b/STDatabase/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/database/RealmProvider.kt @@ -26,18 +26,37 @@ import com.infomaniak.multiplatform_swisstransfer.database.models.upload.RemoteU import com.infomaniak.multiplatform_swisstransfer.database.models.upload.UploadContainerDB import com.infomaniak.multiplatform_swisstransfer.database.models.upload.UploadFileSessionDB import com.infomaniak.multiplatform_swisstransfer.database.models.upload.UploadSessionDB +import com.infomaniak.multiplatform_swisstransfer.database.utils.RealmUtils.runThrowingRealm import io.realm.kotlin.Realm import io.realm.kotlin.RealmConfiguration +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.emitAll +import kotlinx.coroutines.flow.flow class RealmProvider(private val loadDataInMemory: Boolean = false) { val realmAppSettings by lazy { Realm.open(realmAppSettingsConfiguration) } val realmUploads by lazy { Realm.open(realmUploadDBConfiguration) } - var realmTransfers: Realm? = null - private set + + suspend fun realmTransfers(): Realm = realmTransfersAsync.await() + + private val realmTransfersAsync = CompletableDeferred() fun openRealmTransfers(userId: Int) { - realmTransfers = Realm.open(realmTransfersConfiguration(userId)) + realmTransfersAsync.complete(Realm.open(realmTransfersConfiguration(userId))) + } + + suspend inline fun withRealm(block: (Realm) -> T): T { + runThrowingRealm { + return block(realmTransfers()) + } + } + + fun flowWithRealm(block: suspend (Realm) -> Flow): Flow = flow { + runThrowingRealm { + emitAll(block(realmTransfers())) + } } fun closeRealmAppSettings() { @@ -48,11 +67,11 @@ class RealmProvider(private val loadDataInMemory: Boolean = false) { realmUploads.close() } - fun closeRealmTransfers() { - realmTransfers?.close() + suspend fun closeRealmTransfers() { + realmTransfersAsync.await().close() } - fun closeAllRealms() { + suspend fun closeAllRealms() { closeRealmAppSettings() closeRealmUploads() closeRealmTransfers() diff --git a/STDatabase/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/database/controllers/FileController.kt b/STDatabase/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/database/controllers/FileController.kt index ed578f89..d15e12f9 100644 --- a/STDatabase/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/database/controllers/FileController.kt +++ b/STDatabase/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/database/controllers/FileController.kt @@ -21,7 +21,6 @@ import com.infomaniak.multiplatform_swisstransfer.common.exceptions.RealmExcepti import com.infomaniak.multiplatform_swisstransfer.common.interfaces.transfers.File import com.infomaniak.multiplatform_swisstransfer.database.RealmProvider import com.infomaniak.multiplatform_swisstransfer.database.models.transfers.FileDB -import com.infomaniak.multiplatform_swisstransfer.database.utils.RealmUtils.runThrowingRealm import io.realm.kotlin.ext.query import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow @@ -30,11 +29,9 @@ import kotlinx.coroutines.flow.mapLatest @OptIn(ExperimentalCoroutinesApi::class) class FileController(private val realmProvider: RealmProvider) { - private val realm by lazy { realmProvider.realmTransfers!! } - @Throws(RealmException::class) - fun getFilesFromTransfer(folderUuid: String): Flow> = runThrowingRealm { + fun getFilesFromTransfer(folderUuid: String): Flow> = realmProvider.flowWithRealm { realm -> val query = "${FileDB::folder.name}.uuid == '$folderUuid'" - return realm.query(query).asFlow().mapLatest { it.list } + realm.query(query).asFlow().mapLatest { it.list } } } diff --git a/STDatabase/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/database/controllers/TransferController.kt b/STDatabase/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/database/controllers/TransferController.kt index acd3c2d3..ba443f52 100644 --- a/STDatabase/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/database/controllers/TransferController.kt +++ b/STDatabase/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/database/controllers/TransferController.kt @@ -27,7 +27,6 @@ import com.infomaniak.multiplatform_swisstransfer.common.utils.DateUtils import com.infomaniak.multiplatform_swisstransfer.database.RealmProvider import com.infomaniak.multiplatform_swisstransfer.database.models.transfers.TransferDB import com.infomaniak.multiplatform_swisstransfer.database.utils.FileUtils -import com.infomaniak.multiplatform_swisstransfer.database.utils.RealmUtils.runThrowingRealm import io.realm.kotlin.MutableRealm import io.realm.kotlin.Realm import io.realm.kotlin.UpdatePolicy @@ -43,11 +42,11 @@ import kotlin.coroutines.cancellation.CancellationException @OptIn(ExperimentalCoroutinesApi::class) class TransferController(private val realmProvider: RealmProvider) { - private val realm by lazy { realmProvider.realmTransfers!! } - //region Get data - @Throws(RealmException::class) - internal fun getTransfers(transferDirection: TransferDirection? = null): RealmResults = runThrowingRealm { + @Throws(RealmException::class, CancellationException::class) + internal suspend fun getTransfers( + transferDirection: TransferDirection? = null + ): RealmResults = realmProvider.withRealm { realm -> val directionFilterQuery = when (transferDirection) { null -> TRUE_PREDICATE else -> "${TransferDB.transferDirectionPropertyName} == '${transferDirection}'" @@ -56,22 +55,22 @@ class TransferController(private val realmProvider: RealmProvider) { } @Throws(RealmException::class) - fun getTransfersFlow(transferDirection: TransferDirection): Flow> = runThrowingRealm { - return getTransfers(transferDirection).asFlow().mapLatest { it.list } + fun getTransfersFlow(transferDirection: TransferDirection): Flow> = realmProvider.flowWithRealm { + getTransfers(transferDirection).asFlow().mapLatest { it.list } } @Throws(RealmException::class) - fun getTransferFlow(linkUUID: String): Flow = runThrowingRealm { - return getTransferQuery(realm, linkUUID).asFlow().mapLatest { it.obj } + fun getTransferFlow(linkUUID: String): Flow = realmProvider.flowWithRealm { realm -> + getTransferQuery(realm, linkUUID).asFlow().mapLatest { it.obj } } - @Throws(RealmException::class) - fun getTransfer(linkUUID: String): Transfer? = runThrowingRealm { + @Throws(RealmException::class, CancellationException::class) + suspend fun getTransfer(linkUUID: String): Transfer? = realmProvider.withRealm { realm -> return getTransferQuery(realm, linkUUID).find() } - @Throws(RealmException::class) - fun getNotReadyTransfers(): List = runThrowingRealm { + @Throws(RealmException::class, CancellationException::class) + suspend fun getNotReadyTransfers(): List = realmProvider.withRealm { realm -> val query = "${TransferDB.transferStatusPropertyName} != '${TransferStatus.READY.name}'" return realm.query(query).find() } @@ -79,7 +78,7 @@ class TransferController(private val realmProvider: RealmProvider) { //region Upsert data @Throws(RealmException::class, CancellationException::class, TransferWithoutFilesException::class) - suspend fun upsert(transfer: Transfer, transferDirection: TransferDirection, password: String?) = runThrowingRealm { + suspend fun upsert(transfer: Transfer, transferDirection: TransferDirection, password: String?) = realmProvider.withRealm { realm -> realm.write { val transferDB = TransferDB(transfer, transferDirection, password) transferDB.container?.files?.let { transferFiles -> @@ -94,7 +93,7 @@ class TransferController(private val realmProvider: RealmProvider) { linkUUID: String, uploadSession: UploadSession, transferStatus: TransferStatus, - ) = runThrowingRealm { + ) = realmProvider.withRealm { realm -> val transferDB = TransferDB(linkUUID, uploadSession, transferStatus).apply { container?.files?.let { files -> FileUtils.getFileDBTree(containerUUID, files) @@ -109,7 +108,7 @@ class TransferController(private val realmProvider: RealmProvider) { //region Update data @Throws(RealmException::class, CancellationException::class) - suspend fun deleteTransfer(transferUUID: String) = runThrowingRealm { + suspend fun deleteTransfer(transferUUID: String) = realmProvider.withRealm { realm -> realm.write { val transferToDelete = query("${TransferDB::linkUUID.name} == '$transferUUID'").first() delete(transferToDelete) @@ -117,12 +116,12 @@ class TransferController(private val realmProvider: RealmProvider) { } @Throws(RealmException::class, CancellationException::class) - suspend fun deleteExpiredTransfers() = runThrowingRealm { + suspend fun deleteExpiredTransfers() = realmProvider.withRealm { realm -> realm.write { delete(getExpiredTransfersQuery(realm = this)) } } @Throws(RealmException::class, CancellationException::class) - suspend fun removeData() = runThrowingRealm { + suspend fun removeData() = realmProvider.withRealm { realm -> realm.write { deleteAll() } } //endregion diff --git a/STDatabase/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/database/utils/RealmUtils.kt b/STDatabase/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/database/utils/RealmUtils.kt index 73e40ba0..048b3a3b 100644 --- a/STDatabase/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/database/utils/RealmUtils.kt +++ b/STDatabase/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/database/utils/RealmUtils.kt @@ -18,11 +18,14 @@ package com.infomaniak.multiplatform_swisstransfer.database.utils import com.infomaniak.multiplatform_swisstransfer.common.exceptions.RealmException +import kotlinx.coroutines.CancellationException object RealmUtils { @Throws(RealmException::class) inline fun runThrowingRealm(block: () -> R): R { - return runCatching { block() }.getOrElse { throw RealmException(it) } + return runCatching { block() }.onFailure { + if (it is CancellationException) throw it + }.getOrElse { throw RealmException(it) } } }