Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Get sent or received transfers by transfer direction #33

Merged
merged 13 commits into from
Oct 15, 2024
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 @@ -17,7 +17,7 @@
*/
package com.infomaniak.multiplatform_swisstransfer.common.interfaces.transfers

interface Container<F : List<File>> {
interface Container {
val uuid: String
val duration: Long
val createdDateTimestamp: Long
Expand All @@ -33,5 +33,5 @@ interface Container<F : List<File>> {
val source: String
// @SerialName("WSUser") // TODO: What's this ?
// val wsUser: JsonElement?
val files: F
val files: List<File>
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
*/
package com.infomaniak.multiplatform_swisstransfer.common.interfaces.transfers

interface Transfer<ContainerType> {
import com.infomaniak.multiplatform_swisstransfer.common.models.TransferDirection

interface Transfer {
val linkUuid: String
val containerUuid: String
val downloadCounterCredit: Int
Expand All @@ -26,5 +28,7 @@ interface Transfer<ContainerType> {
val hasBeenDownloadedOneTime: Boolean
val isMailSent: Boolean
val downloadHost: String
val container: ContainerType
val container: Container?

fun transferDirection(): TransferDirection? = null
tevincent marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Infomaniak SwissTransfer - Multiplatform
* Copyright (C) 2024 Infomaniak Network SA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.infomaniak.multiplatform_swisstransfer.common.models

enum class TransferDirection {
SENT, RECEIVED
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package com.infomaniak.multiplatform_swisstransfer.managers

import com.infomaniak.multiplatform_swisstransfer.common.exceptions.UnknownException
import com.infomaniak.multiplatform_swisstransfer.common.interfaces.transfers.Transfer
import com.infomaniak.multiplatform_swisstransfer.common.models.TransferDirection
import com.infomaniak.multiplatform_swisstransfer.database.cache.setting.TransferController
import com.infomaniak.multiplatform_swisstransfer.network.ApiClientProvider
import com.infomaniak.multiplatform_swisstransfer.network.exceptions.ApiException
Expand All @@ -28,6 +29,7 @@ import com.infomaniak.multiplatform_swisstransfer.network.models.transfer.Transf
import com.infomaniak.multiplatform_swisstransfer.network.repositories.TransferRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.withContext
import kotlin.coroutines.cancellation.CancellationException
Expand All @@ -51,11 +53,17 @@ class TransferManager internal constructor(
) {

/**
* The `Flow` of [transfers] is used to receive updates for new transfers added in database.
* @see addTransferByLinkUuid
* Retrieves a flow of transfers based on the specified transfer direction.
*
* @see addTransferByUrl
* @see addTransferByLinkUuid
*
* @param transferDirection The direction of the transfers to retrieve (e.g., [TransferDirection.SENT] or [TransferDirection.RECEIVED]).
* @return A `Flow` that emits a list of transfers matching the specified direction.
*/
val transfers get() = transferController.getTransfersFlow().flowOn(Dispatchers.IO)
fun getTransfers(transferDirection: TransferDirection): Flow<List<Transfer>> {
return transferController.getTransfersFlow(transferDirection).flowOn(Dispatchers.IO)
}

/**
* Retrieves a transfer using the provided link UUID and saves it to the database.
Expand All @@ -64,7 +72,7 @@ class TransferManager internal constructor(
* a `linkUuid` is returned, which must be passed to this function to retrieve the corresponding transfer.
* After retrieving the transfer, it is saved to the database.
*
* @see transfers
* @see getTransfers
*
* @param linkUuid The UUID corresponding to the uploaded transfer link.
* @throws CancellationException If the operation is cancelled.
Expand All @@ -81,7 +89,7 @@ class TransferManager internal constructor(
UnknownException::class,
)
suspend fun addTransferByLinkUuid(linkUuid: String) = withContext(Dispatchers.IO) {
addTransfer(transferRepository.getTransferByLinkUuid(linkUuid).data)
addTransfer(transferRepository.getTransferByLinkUuid(linkUuid).data, TransferDirection.SENT)
}

/**
Expand All @@ -91,7 +99,7 @@ class TransferManager internal constructor(
* the corresponding transfer, and after the transfer is successfully retrieved, it is saved to
* the database.
*
* @see transfers
* @see getTransfers
*
* @param url The URL associated with the transfer to retrieve.
* @throws CancellationException If the operation is cancelled.
Expand All @@ -108,12 +116,12 @@ class TransferManager internal constructor(
UnknownException::class,
)
suspend fun addTransferByUrl(url: String) = withContext(Dispatchers.IO) {
addTransfer(transferRepository.getTransferByUrl(url).data)
addTransfer(transferRepository.getTransferByUrl(url).data, TransferDirection.RECEIVED)
}

private suspend fun addTransfer(transferApi: TransferApi?) {
private suspend fun addTransfer(transferApi: TransferApi?, transferDirection: TransferDirection) {
runCatching {
transferController.upsert(transferApi as Transfer<*>)
transferController.upsert(transferApi as Transfer, transferDirection)
}.onFailure {
throw UnknownException(it)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ import com.infomaniak.multiplatform_swisstransfer.database.models.upload.Upload
import io.realm.kotlin.Realm
import io.realm.kotlin.RealmConfiguration

class RealmProvider {
class RealmProvider(private val loadDataInMemory: Boolean = false) {

val realmAppSettings by lazy { Realm.open(realmAppSettingsConfiguration) }
val realmUploads by lazy { Realm.open(realmUploadConfiguration) }
var realmTransfers: Realm? = null
private set

fun openRealmTransfers(userId: Int, inMemory: Boolean = false) {
realmTransfers = Realm.open(realmTransfersConfiguration(userId, inMemory))
fun openRealmTransfers(userId: Int) {
realmTransfers = Realm.open(realmTransfersConfiguration(userId))
}

fun closeRealmAppSettings() {
Expand All @@ -57,18 +57,24 @@ class RealmProvider {
private val realmAppSettingsConfiguration = RealmConfiguration
.Builder(schema = setOf(AppSettingsDB::class))
.name("AppSettings")
.loadDataInMemoryIfNeeded()
.build()

private val realmUploadConfiguration = RealmConfiguration
.Builder(schema = setOf(Upload::class))
.name("Uploads")
.loadDataInMemoryIfNeeded()
.build()

private fun realmTransfersConfiguration(userId: Int, inMemory: Boolean) = RealmConfiguration
private fun realmTransfersConfiguration(userId: Int) = RealmConfiguration
.Builder(schema = setOf(TransferDB::class, ContainerDB::class, FileDB::class))
.name(transferRealmName(userId))
.apply { if (inMemory) inMemory() }
.loadDataInMemoryIfNeeded()
.build()

private fun transferRealmName(userId: Int) = "Transfers-$userId"

private fun RealmConfiguration.Builder.loadDataInMemoryIfNeeded(): RealmConfiguration.Builder {
return apply { if (loadDataInMemory) inMemory() }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@
package com.infomaniak.multiplatform_swisstransfer.database.cache.setting

import com.infomaniak.multiplatform_swisstransfer.common.interfaces.transfers.Transfer
import com.infomaniak.multiplatform_swisstransfer.common.models.TransferDirection
import com.infomaniak.multiplatform_swisstransfer.database.RealmProvider
import com.infomaniak.multiplatform_swisstransfer.database.models.transfers.TransferDB
import io.realm.kotlin.UpdatePolicy
import io.realm.kotlin.ext.query
import io.realm.kotlin.query.RealmResults
import io.realm.kotlin.query.Sort
import io.realm.kotlin.query.TRUE_PREDICATE
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow
Expand All @@ -37,22 +39,28 @@ class TransferController(private val realmProvider: RealmProvider) {

//region Get data
@Throws(IllegalArgumentException::class, CancellationException::class)
fun getTransfers(): RealmResults<TransferDB>? {
return realm?.query<TransferDB>()?.sort(TransferDB::createdDateTimestamp.name, Sort.DESCENDING)?.find()
internal fun getTransfers(transferDirection: TransferDirection? = null): RealmResults<TransferDB>? {
val sentFilterQuery = when (transferDirection) {
null -> TRUE_PREDICATE
else -> "${TransferDB.transferDirectionPropertyName} == '${transferDirection}'"
}
return realm?.query<TransferDB>(sentFilterQuery)?.sort(TransferDB::createdDateTimestamp.name, Sort.DESCENDING)?.find()
}

@Throws(IllegalArgumentException::class, CancellationException::class)
fun getTransfersFlow(): Flow<List<TransferDB>> = getTransfers()?.asFlow()?.mapLatest { it.list } ?: emptyFlow()
fun getTransfersFlow(transferDirection: TransferDirection): Flow<List<Transfer>> {
return getTransfers(transferDirection)?.asFlow()?.mapLatest { it.list } ?: emptyFlow()
}

fun getTransfer(linkUuid: String): TransferDB? {
fun getTransfer(linkUuid: String): Transfer? {
return realm?.query<TransferDB>("${TransferDB::linkUuid.name} == '$linkUuid'")?.first()?.find()
}
//endregion

//region Upsert data
suspend fun upsert(transfer: Transfer<*>) {
suspend fun upsert(transfer: Transfer, transferDirection: TransferDirection) {
realm?.write {
this.copyToRealm(TransferDB(transfer), UpdatePolicy.ALL)
this.copyToRealm(TransferDB(transfer, transferDirection), UpdatePolicy.ALL)
}
}
//endregion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@
package com.infomaniak.multiplatform_swisstransfer.database.models.transfers

import com.infomaniak.multiplatform_swisstransfer.common.interfaces.transfers.Container
import com.infomaniak.multiplatform_swisstransfer.common.interfaces.transfers.File
import io.realm.kotlin.ext.realmListOf
import io.realm.kotlin.types.RealmList
import io.realm.kotlin.types.RealmObject
import io.realm.kotlin.types.annotations.PrimaryKey

class ContainerDB() : Container<RealmList<FileDB>>, RealmObject {
class ContainerDB() : Container, RealmObject {
@PrimaryKey
override var uuid: String = ""
override var duration: Long = 0L
Expand All @@ -43,7 +42,7 @@ class ContainerDB() : Container<RealmList<FileDB>>, RealmObject {
// val wsUser: JsonElement?
override var files: RealmList<FileDB> = realmListOf()

constructor(container: Container<List<File>>) : this() {
constructor(container: Container) : this() {
this.uuid = container.uuid
this.duration = container.duration
this.createdDateTimestamp = container.createdDateTimestamp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,12 @@
*/
package com.infomaniak.multiplatform_swisstransfer.database.models.transfers

import com.infomaniak.multiplatform_swisstransfer.common.interfaces.transfers.Container
import com.infomaniak.multiplatform_swisstransfer.common.interfaces.transfers.File
import com.infomaniak.multiplatform_swisstransfer.common.interfaces.transfers.Transfer
import com.infomaniak.multiplatform_swisstransfer.common.models.TransferDirection
import io.realm.kotlin.types.RealmObject
import io.realm.kotlin.types.annotations.PrimaryKey

class TransferDB() : Transfer<ContainerDB?>, RealmObject {
class TransferDB() : Transfer, RealmObject {
@PrimaryKey
override var linkUuid: String = ""
override var containerUuid: String = ""
Expand All @@ -35,8 +34,9 @@ class TransferDB() : Transfer<ContainerDB?>, RealmObject {
override var downloadHost: String = ""
override var container: ContainerDB? = null

@Suppress("UNCHECKED_CAST")
constructor(transfer: Transfer<*>) : this() {
private var transferDirectionValue: String = ""

constructor(transfer: Transfer, transferDirection: TransferDirection) : this() {
this.linkUuid = transfer.linkUuid
this.containerUuid = transfer.containerUuid
this.downloadCounterCredit = transfer.downloadCounterCredit
Expand All @@ -45,6 +45,14 @@ class TransferDB() : Transfer<ContainerDB?>, RealmObject {
this.hasBeenDownloadedOneTime = transfer.hasBeenDownloadedOneTime
this.isMailSent = transfer.isMailSent
this.downloadHost = transfer.downloadHost
this.container = ContainerDB(transfer.container as Container<List<File>>)
this.container = transfer.container?.let(::ContainerDB)

this.transferDirectionValue = transferDirection.name
}

override fun transferDirection(): TransferDirection = TransferDirection.valueOf(transferDirectionValue)

internal companion object {
val transferDirectionPropertyName = TransferDB::transferDirectionValue.name
}
}
Loading
Loading