mirror of
https://github.com/openflocon/Flocon.git
synced 2026-05-05 02:16:33 +00:00
Feature/domain (#95)
* feature: Move analytics * feature: remote dashboard * fix: DI * feature: Dashboard * fix: DI * feature: Move files * feature: Move database * feature: Move files * feature: Move * feature: Move * feature: Move files * feature: Move files * feature: Move * feature: Move images * feature: Move sharedprefe * fix: Merge * feature: Network * fix: Network * feature: Move files * feature: Move * fix: DI * fix: DI * fix: Discussion * fix: Discussion * fix: Delete * fix: Comment * fix: Discussion * fix: Build * fix textfield * fix textfield --------- Co-authored-by: TEYSSANDIER Raphael <rteyssandier@sephora.fr> Co-authored-by: Florent Champigny <florent@bere.al>
This commit is contained in:
parent
d22bd8642f
commit
08698acf25
298 changed files with 2131 additions and 1976 deletions
|
|
@ -1,20 +1,33 @@
|
|||
package com.flocon.data.remote
|
||||
|
||||
import com.flocon.data.remote.analytics.analyticsModule
|
||||
import com.flocon.data.remote.dashboard.dashboardModule
|
||||
import com.flocon.data.remote.database.databaseModule
|
||||
import com.flocon.data.remote.deeplink.deeplinkModule
|
||||
import com.flocon.data.remote.files.filesModule
|
||||
import com.flocon.data.remote.messages.messagesModule
|
||||
import com.flocon.data.remote.network.networkModule
|
||||
import com.flocon.data.remote.sharedpreference.sharedPreferencesModule
|
||||
import com.flocon.data.remote.table.tableModule
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.koin.dsl.module
|
||||
|
||||
val dataRemoteModule = module {
|
||||
includes(
|
||||
analyticsModule,
|
||||
dashboardModule,
|
||||
databaseModule,
|
||||
deeplinkModule,
|
||||
filesModule,
|
||||
messagesModule,
|
||||
networkModule,
|
||||
sharedPreferencesModule,
|
||||
tableModule,
|
||||
tableModule
|
||||
)
|
||||
|
||||
single {
|
||||
Json {
|
||||
ignoreUnknownKeys = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,149 +0,0 @@
|
|||
@file:Suppress("ktlint")
|
||||
package com.flocon.data.remote
|
||||
|
||||
object Protocol {
|
||||
object FromDevice {
|
||||
|
||||
object Analytics {
|
||||
const val Plugin = "Analytics"
|
||||
|
||||
object Method {
|
||||
const val AddItems = "AddItems"
|
||||
}
|
||||
}
|
||||
|
||||
object Dashboard {
|
||||
const val Plugin = "Dashboard"
|
||||
|
||||
object Method {
|
||||
const val Update = "update"
|
||||
}
|
||||
}
|
||||
|
||||
object Database {
|
||||
const val Plugin = "database"
|
||||
|
||||
object Method {
|
||||
const val Query = "query"
|
||||
const val GetDatabases = "getDatabases"
|
||||
}
|
||||
}
|
||||
|
||||
object Deeplink {
|
||||
const val Plugin = "Deeplink"
|
||||
|
||||
object Method {
|
||||
const val GetDeeplinks = "GetDeeplinks"
|
||||
}
|
||||
}
|
||||
|
||||
object Files {
|
||||
const val Plugin = "files"
|
||||
|
||||
object Method {
|
||||
const val ListFiles = "listFiles"
|
||||
}
|
||||
}
|
||||
|
||||
object Images {
|
||||
const val Plugin = "images"
|
||||
|
||||
object Method {
|
||||
const val LogNetworkImage = "logNetworkCall"
|
||||
}
|
||||
}
|
||||
|
||||
object Network {
|
||||
const val Plugin = "network"
|
||||
|
||||
object Method {
|
||||
const val LogNetworkCall = "logNetworkCall"
|
||||
const val LogNetworkCallRequest = "logNetworkCallRequest"
|
||||
const val LogNetworkCallResponse = "logNetworkCallResponse"
|
||||
}
|
||||
}
|
||||
|
||||
object SharedPreferences {
|
||||
const val Plugin = "sharedPreferences"
|
||||
|
||||
object Method {
|
||||
const val GetSharedPreferences = "getSharedPreferences"
|
||||
const val GetSharedPreferenceValue = "getSharedPreferenceValue"
|
||||
}
|
||||
}
|
||||
|
||||
object Table {
|
||||
const val Plugin = "Table"
|
||||
|
||||
object Method {
|
||||
const val AddItems = "AddItems"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object ToDevice {
|
||||
|
||||
object Analytics {
|
||||
const val Plugin = "Analytics"
|
||||
|
||||
object Method {
|
||||
const val ClearItems = "ClearItems"
|
||||
}
|
||||
}
|
||||
|
||||
object Dashboard {
|
||||
const val Plugin = "Dashboard"
|
||||
|
||||
object Method {
|
||||
const val OnClick = "onClick"
|
||||
const val OnTextFieldSubmitted = "onTextFieldSubmitted"
|
||||
const val OnCheckBoxValueChanged = "onCheckBoxValueChanged"
|
||||
}
|
||||
}
|
||||
|
||||
object Database {
|
||||
const val Plugin = "database"
|
||||
|
||||
object Method {
|
||||
const val Query = "query"
|
||||
const val GetDatabases = "getDatabases"
|
||||
}
|
||||
}
|
||||
|
||||
object Files {
|
||||
const val Plugin = "files"
|
||||
|
||||
object Method {
|
||||
const val ListFiles = "listFiles"
|
||||
const val DeleteFile = "deleteFile"
|
||||
const val DeleteFolderContent = "deleteFolderContent"
|
||||
}
|
||||
}
|
||||
|
||||
object Network {
|
||||
const val Plugin = "network"
|
||||
|
||||
object Method {
|
||||
const val SetupMocks = "setupMocks"
|
||||
}
|
||||
}
|
||||
|
||||
object SharedPreferences {
|
||||
const val Plugin = "sharedPreferences"
|
||||
|
||||
object Method {
|
||||
const val GetSharedPreferences = "getSharedPreferences"
|
||||
const val GetSharedPreferenceValue = "getSharedPreferenceValue"
|
||||
const val SetSharedPreferenceValue = "setSharedPreferenceValue"
|
||||
}
|
||||
}
|
||||
|
||||
object Table {
|
||||
const val Plugin = "Table"
|
||||
|
||||
object Method {
|
||||
const val ClearItems = "ClearItems"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +1,22 @@
|
|||
package com.flocon.data.remote.analytics.datasource
|
||||
|
||||
import com.flocon.data.remote.Protocol
|
||||
import com.flocon.data.remote.analytics.mapper.toDomain
|
||||
import com.flocon.data.remote.analytics.model.AnalyticsItemDataModel
|
||||
import com.flocon.data.remote.models.FloconOutgoingMessageDataModel
|
||||
import com.flocon.data.remote.models.toRemote
|
||||
import com.flocon.data.remote.server.Server
|
||||
import io.github.openflocon.data.core.analytics.datasource.AnalyticsRemoteDataSource
|
||||
import io.github.openflocon.domain.Protocol
|
||||
import io.github.openflocon.domain.analytics.models.AnalyticsItemDomainModel
|
||||
import io.github.openflocon.domain.device.models.DeviceIdAndPackageNameDomainModel
|
||||
import io.github.openflocon.domain.messages.models.FloconIncomingMessageDomainModel
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
class AnalyticsRemoteDataSourceImpl(
|
||||
private val server: Server,
|
||||
private val json: Json
|
||||
) : AnalyticsRemoteDataSource {
|
||||
|
||||
override suspend fun clearReceivedItem(deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel, items: List<String>) {
|
||||
server.sendMessageToClient(
|
||||
deviceIdAndPackageName = deviceIdAndPackageName.toRemote(),
|
||||
|
|
@ -21,4 +27,20 @@ class AnalyticsRemoteDataSourceImpl(
|
|||
),
|
||||
)
|
||||
}
|
||||
|
||||
override fun getItems(message: FloconIncomingMessageDomainModel): List<AnalyticsItemDomainModel> {
|
||||
return decodeAddItems(message).takeIf { it.isNotEmpty() }
|
||||
?.let { list -> list.map { toDomain(it) } }
|
||||
?.takeIf { it.isNotEmpty() }
|
||||
.orEmpty()
|
||||
}
|
||||
|
||||
private fun decodeAddItems(message: FloconIncomingMessageDomainModel): List<AnalyticsItemDataModel> = try {
|
||||
json.decodeFromString<List<AnalyticsItemDataModel>>(message.body)
|
||||
} catch (t: Throwable) {
|
||||
t.printStackTrace()
|
||||
emptyList()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
package com.flocon.data.remote.analytics.mapper
|
||||
|
||||
import com.flocon.data.remote.analytics.model.AnalyticsItemDataModel
|
||||
import io.github.openflocon.domain.analytics.models.AnalyticsItemDomainModel
|
||||
import io.github.openflocon.domain.analytics.models.AnalyticsPropertyDomainModel
|
||||
|
||||
internal fun toDomain(dataModel: AnalyticsItemDataModel) = AnalyticsItemDomainModel(
|
||||
analyticsTableId = dataModel.analyticsTableId,
|
||||
itemId = dataModel.id,
|
||||
createdAt = dataModel.createdAt,
|
||||
eventName = dataModel.eventName,
|
||||
properties = dataModel.properties?.map {
|
||||
AnalyticsPropertyDomainModel(
|
||||
name = it.name,
|
||||
value = it.value,
|
||||
)
|
||||
} ?: emptyList(),
|
||||
)
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.flocon.data.remote.analytics.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class AnalyticsItemDataModel(
|
||||
val id: String,
|
||||
val analyticsTableId: String,
|
||||
val eventName: String,
|
||||
val createdAt: Long,
|
||||
val properties: List<AnalyticsPropertyDataModel>? = emptyList(),
|
||||
)
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.flocon.data.remote.analytics.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class AnalyticsPropertyDataModel(
|
||||
val name: String,
|
||||
val value: String,
|
||||
)
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.flocon.data.remote.common
|
||||
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
internal inline fun <reified T> Json.safeDecodeFromString(data: String): T? = try {
|
||||
decodeFromString(data)
|
||||
} catch (e: Throwable) {
|
||||
null
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.flocon.data.remote.dashboard
|
||||
|
||||
import com.flocon.data.remote.dashboard.datasource.ToDeviceDashboardDataSourceImpl
|
||||
import io.github.openflocon.data.core.dashboard.datasource.ToDeviceDashboardDataSource
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.dsl.bind
|
||||
import org.koin.dsl.module
|
||||
|
||||
internal val dashboardModule = module {
|
||||
singleOf(::ToDeviceDashboardDataSourceImpl) bind ToDeviceDashboardDataSource::class
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
package com.flocon.data.remote.dashboard.datasource
|
||||
|
||||
import com.flocon.data.remote.dashboard.mapper.toDomain
|
||||
import com.flocon.data.remote.dashboard.models.DashboardConfigDataModel
|
||||
import com.flocon.data.remote.dashboard.models.ToDeviceCheckBoxValueChangedMessage
|
||||
import com.flocon.data.remote.dashboard.models.ToDeviceSubmittedTextFieldMessage
|
||||
import com.flocon.data.remote.models.FloconOutgoingMessageDataModel
|
||||
import com.flocon.data.remote.models.toRemote
|
||||
import com.flocon.data.remote.server.Server
|
||||
import io.github.openflocon.data.core.dashboard.datasource.ToDeviceDashboardDataSource
|
||||
import io.github.openflocon.domain.Protocol
|
||||
import io.github.openflocon.domain.dashboard.models.DashboardDomainModel
|
||||
import io.github.openflocon.domain.device.models.DeviceIdAndPackageNameDomainModel
|
||||
import io.github.openflocon.domain.messages.models.FloconIncomingMessageDomainModel
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlin.uuid.ExperimentalUuidApi
|
||||
|
||||
class ToDeviceDashboardDataSourceImpl(
|
||||
private val server: Server,
|
||||
private val json: Json
|
||||
) : ToDeviceDashboardDataSource {
|
||||
|
||||
@OptIn(ExperimentalUuidApi::class)
|
||||
override suspend fun sendClickEvent(
|
||||
deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel,
|
||||
buttonId: String,
|
||||
) {
|
||||
server.sendMessageToClient(
|
||||
deviceIdAndPackageName = deviceIdAndPackageName.toRemote(),
|
||||
message = FloconOutgoingMessageDataModel(
|
||||
plugin = Protocol.ToDevice.Dashboard.Plugin,
|
||||
method = Protocol.ToDevice.Dashboard.Method.OnClick,
|
||||
body = buttonId,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalUuidApi::class)
|
||||
override suspend fun submitTextFieldEvent(
|
||||
deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel,
|
||||
textFieldId: String,
|
||||
value: String,
|
||||
) {
|
||||
server.sendMessageToClient(
|
||||
deviceIdAndPackageName = deviceIdAndPackageName.toRemote(),
|
||||
message = FloconOutgoingMessageDataModel(
|
||||
plugin = Protocol.ToDevice.Dashboard.Plugin,
|
||||
method = Protocol.ToDevice.Dashboard.Method.OnTextFieldSubmitted,
|
||||
body = json.encodeToString(
|
||||
ToDeviceSubmittedTextFieldMessage(
|
||||
id = textFieldId,
|
||||
value = value,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalUuidApi::class)
|
||||
override suspend fun sendUpdateCheckBoxEvent(
|
||||
deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel,
|
||||
checkBoxId: String,
|
||||
value: Boolean,
|
||||
) {
|
||||
server.sendMessageToClient(
|
||||
deviceIdAndPackageName = deviceIdAndPackageName.toRemote(),
|
||||
message = FloconOutgoingMessageDataModel(
|
||||
plugin = Protocol.ToDevice.Dashboard.Plugin,
|
||||
method = Protocol.ToDevice.Dashboard.Method.OnCheckBoxValueChanged,
|
||||
body = json.encodeToString(
|
||||
ToDeviceCheckBoxValueChangedMessage(
|
||||
id = checkBoxId,
|
||||
value = value,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
override fun getItem(message: FloconIncomingMessageDomainModel): DashboardDomainModel? {
|
||||
return decode(message)?.let { toDomain(it) }
|
||||
}
|
||||
|
||||
private fun decode(message: FloconIncomingMessageDomainModel): DashboardConfigDataModel? = try {
|
||||
json.decodeFromString<DashboardConfigDataModel>(message.body)
|
||||
} catch (t: Throwable) {
|
||||
t.printStackTrace()
|
||||
null
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
package com.flocon.data.remote.dashboard.mapper
|
||||
|
||||
import com.flocon.data.remote.dashboard.models.ButtonConfigDataModel
|
||||
import com.flocon.data.remote.dashboard.models.CheckBoxConfigDataModel
|
||||
import com.flocon.data.remote.dashboard.models.DashboardConfigDataModel
|
||||
import com.flocon.data.remote.dashboard.models.DashboardElementDataModel
|
||||
import com.flocon.data.remote.dashboard.models.SectionConfigDataModel
|
||||
import com.flocon.data.remote.dashboard.models.TextConfigDataModel
|
||||
import com.flocon.data.remote.dashboard.models.TextFieldConfigDataModel
|
||||
import io.github.openflocon.domain.dashboard.models.DashboardDomainModel
|
||||
import io.github.openflocon.domain.dashboard.models.DashboardElementDomainModel
|
||||
import io.github.openflocon.domain.dashboard.models.DashboardSectionDomainModel
|
||||
|
||||
fun toDomain(model: DashboardConfigDataModel): DashboardDomainModel = DashboardDomainModel(
|
||||
dashboardId = model.dashboardId,
|
||||
sections = model.sections.map {
|
||||
toDomain(it)
|
||||
},
|
||||
)
|
||||
|
||||
fun toDomain(model: SectionConfigDataModel): DashboardSectionDomainModel = DashboardSectionDomainModel(
|
||||
name = model.name,
|
||||
elements = model.elements.mapNotNull { toDomain(it) },
|
||||
)
|
||||
|
||||
fun toDomain(model: DashboardElementDataModel): DashboardElementDomainModel? {
|
||||
model.text?.let {
|
||||
return toDomain(it)
|
||||
}
|
||||
model.button?.let {
|
||||
return toDomain(it)
|
||||
}
|
||||
model.textField?.let {
|
||||
return toDomain(it)
|
||||
}
|
||||
model.checkBox?.let {
|
||||
return toDomain(it)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun toDomain(model: ButtonConfigDataModel): DashboardElementDomainModel.Button = DashboardElementDomainModel.Button(
|
||||
text = model.text,
|
||||
id = model.id,
|
||||
)
|
||||
|
||||
fun toDomain(model: TextConfigDataModel): DashboardElementDomainModel.Text = DashboardElementDomainModel.Text(
|
||||
label = model.label,
|
||||
value = model.value,
|
||||
color = model.color,
|
||||
)
|
||||
|
||||
fun toDomain(model: TextFieldConfigDataModel): DashboardElementDomainModel.TextField = DashboardElementDomainModel.TextField(
|
||||
value = model.value,
|
||||
label = model.label,
|
||||
placeHolder = model.placeHolder,
|
||||
id = model.id,
|
||||
)
|
||||
|
||||
fun toDomain(model: CheckBoxConfigDataModel): DashboardElementDomainModel.CheckBox = DashboardElementDomainModel.CheckBox(
|
||||
value = model.value,
|
||||
label = model.label,
|
||||
id = model.id,
|
||||
)
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
package com.flocon.data.remote.dashboard.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class DashboardConfigDataModel(
|
||||
val dashboardId: String,
|
||||
val sections: List<SectionConfigDataModel>,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class SectionConfigDataModel(
|
||||
val name: String,
|
||||
val elements: List<DashboardElementDataModel>,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class DashboardElementDataModel(
|
||||
val button: ButtonConfigDataModel? = null,
|
||||
val text: TextConfigDataModel? = null,
|
||||
val plainText: PlainTextConfigDataModel? = null,
|
||||
val textField: TextFieldConfigDataModel? = null,
|
||||
val checkBox: CheckBoxConfigDataModel? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ButtonConfigDataModel(
|
||||
val text: String,
|
||||
val id: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class TextFieldConfigDataModel(
|
||||
val label: String,
|
||||
val placeHolder: String? = null,
|
||||
val value: String,
|
||||
val id: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class CheckBoxConfigDataModel(
|
||||
val label: String,
|
||||
val value: Boolean,
|
||||
val id: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class TextConfigDataModel(
|
||||
val label: String,
|
||||
val value: String,
|
||||
val color: Int? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class PlainTextConfigDataModel(
|
||||
val label: String,
|
||||
val value: String,
|
||||
val type: String,
|
||||
)
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.flocon.data.remote.dashboard.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ToDeviceCheckBoxValueChangedMessage(
|
||||
val id: String,
|
||||
val value: Boolean,
|
||||
)
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.flocon.data.remote.dashboard.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ToDeviceSubmittedTextFieldMessage(
|
||||
val id: String,
|
||||
val value: String,
|
||||
)
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.flocon.data.remote.database.datasource
|
||||
|
||||
import com.flocon.data.remote.Protocol
|
||||
import io.github.openflocon.domain.Protocol
|
||||
import com.flocon.data.remote.models.FloconOutgoingMessageDataModel
|
||||
import com.flocon.data.remote.models.toRemote
|
||||
import com.flocon.data.remote.server.Server
|
||||
|
|
|
|||
|
|
@ -1,21 +1,26 @@
|
|||
package com.flocon.data.remote.database.datasource
|
||||
|
||||
import com.flocon.data.remote.Protocol
|
||||
import com.flocon.data.remote.database.mapper.decodeDeviceDatabases
|
||||
import com.flocon.data.remote.database.mapper.decodeReceivedQuery
|
||||
import com.flocon.data.remote.database.models.DatabaseExecuteSqlResponseDataModel
|
||||
import com.flocon.data.remote.database.models.DatabaseOutgoingQueryMessage
|
||||
import com.flocon.data.remote.database.models.ResponseAndRequestIdDataModel
|
||||
import com.flocon.data.remote.database.models.toDeviceDatabasesDomain
|
||||
import com.flocon.data.remote.models.FloconOutgoingMessageDataModel
|
||||
import com.flocon.data.remote.models.toRemote
|
||||
import com.flocon.data.remote.server.Server
|
||||
import com.flocon.data.remote.server.newRequestId
|
||||
import io.github.openflocon.data.core.database.datasource.QueryDatabaseRemoteDataSource
|
||||
import io.github.openflocon.domain.Protocol
|
||||
import io.github.openflocon.domain.common.Either
|
||||
import io.github.openflocon.domain.common.Failure
|
||||
import io.github.openflocon.domain.common.Success
|
||||
import io.github.openflocon.domain.database.models.DatabaseExecuteSqlResponseDomainModel
|
||||
import io.github.openflocon.domain.database.models.DeviceDataBaseDomainModel
|
||||
import io.github.openflocon.domain.database.models.DeviceDataBaseId
|
||||
import io.github.openflocon.domain.database.models.ResponseAndRequestIdDomainModel
|
||||
import io.github.openflocon.domain.device.models.DeviceIdAndPackageNameDomainModel
|
||||
import io.github.openflocon.domain.messages.models.FloconIncomingMessageDomainModel
|
||||
import kotlinx.coroutines.TimeoutCancellationException
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
|
|
@ -27,6 +32,7 @@ import kotlin.uuid.ExperimentalUuidApi
|
|||
|
||||
class QueryDatabaseRemoteDataSourceImpl(
|
||||
private val server: Server,
|
||||
private val json: Json
|
||||
) : QueryDatabaseRemoteDataSource {
|
||||
private val queryResultReceived = MutableStateFlow<Set<ResponseAndRequestIdDomainModel>>(emptySet())
|
||||
|
||||
|
|
@ -77,9 +83,17 @@ class QueryDatabaseRemoteDataSourceImpl(
|
|||
return Failure(e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDeviceDatabases(message: FloconIncomingMessageDomainModel): List<DeviceDataBaseDomainModel> {
|
||||
return toDeviceDatabasesDomain(json.decodeDeviceDatabases(message.body).orEmpty())
|
||||
}
|
||||
|
||||
override fun getReceiveQuery(message: FloconIncomingMessageDomainModel): ResponseAndRequestIdDomainModel? {
|
||||
return json.decodeReceivedQuery(message.body)?.toDomain()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Move
|
||||
// TODO internal
|
||||
fun ResponseAndRequestIdDataModel.toDomain() = ResponseAndRequestIdDomainModel(
|
||||
requestId = requestId,
|
||||
response = response.toDomain(),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
package com.flocon.data.remote.database.mapper
|
||||
|
||||
import com.flocon.data.remote.database.models.DatabaseExecuteSqlResponseDataModel
|
||||
import com.flocon.data.remote.database.models.DeviceDataBaseDataModel
|
||||
import com.flocon.data.remote.database.models.QueryResultReceivedDataModel
|
||||
import com.flocon.data.remote.database.models.ResponseAndRequestIdDataModel
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
@Serializable
|
||||
data class ReceivedQueryWrapper(
|
||||
val type: String,
|
||||
val body: String,
|
||||
)
|
||||
|
||||
internal fun Json.decodeReceivedQuery(body: String): ResponseAndRequestIdDataModel? = try {
|
||||
val result = decodeFromString<QueryResultReceivedDataModel>(body)
|
||||
val queryWrapper = decodeFromString<ReceivedQueryWrapper>(result.result)
|
||||
when (queryWrapper.type) {
|
||||
"Error" -> decodeFromString<DatabaseExecuteSqlResponseDataModel.Error>(queryWrapper.body)
|
||||
"Insert" -> decodeFromString<DatabaseExecuteSqlResponseDataModel.Insert>(queryWrapper.body)
|
||||
"RawSuccess" -> decodeFromString<DatabaseExecuteSqlResponseDataModel.RawSuccess>(queryWrapper.body)
|
||||
"Select" -> decodeFromString<DatabaseExecuteSqlResponseDataModel.Select>(queryWrapper.body)
|
||||
"UpdateDelete" -> decodeFromString<DatabaseExecuteSqlResponseDataModel.UpdateDelete>(queryWrapper.body)
|
||||
|
||||
else -> null
|
||||
}?.let {
|
||||
ResponseAndRequestIdDataModel(
|
||||
requestId = result.requestId,
|
||||
response = it,
|
||||
)
|
||||
}
|
||||
} catch (t: Throwable) {
|
||||
t.printStackTrace()
|
||||
null
|
||||
}
|
||||
|
||||
internal fun Json.decodeDeviceDatabases(body: String): List<DeviceDataBaseDataModel>? = try {
|
||||
decodeFromString<List<DeviceDataBaseDataModel>>(body)
|
||||
} catch (t: Throwable) {
|
||||
t.printStackTrace()
|
||||
null
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.flocon.data.remote.deeplink
|
||||
|
||||
import com.flocon.data.remote.deeplink.datasource.DeeplinkRemoteDataSourceImpl
|
||||
import io.github.openflocon.data.core.deeplink.datasource.DeeplinkRemoteDataSource
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.dsl.bind
|
||||
import org.koin.dsl.module
|
||||
|
||||
internal val deeplinkModule = module {
|
||||
singleOf(::DeeplinkRemoteDataSourceImpl) bind DeeplinkRemoteDataSource::class
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.flocon.data.remote.deeplink.datasource
|
||||
|
||||
import com.flocon.data.remote.common.safeDecodeFromString
|
||||
import com.flocon.data.remote.deeplink.models.DeeplinksReceivedDataModel
|
||||
import com.flocon.data.remote.deeplink.models.toDomain
|
||||
import io.github.openflocon.data.core.deeplink.datasource.DeeplinkRemoteDataSource
|
||||
import io.github.openflocon.domain.deeplink.models.DeeplinkDomainModel
|
||||
import io.github.openflocon.domain.messages.models.FloconIncomingMessageDomainModel
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
internal class DeeplinkRemoteDataSourceImpl(
|
||||
private val json: Json
|
||||
) : DeeplinkRemoteDataSource {
|
||||
|
||||
override fun getItems(message: FloconIncomingMessageDomainModel): List<DeeplinkDomainModel> {
|
||||
return json.safeDecodeFromString<DeeplinksReceivedDataModel>(message.body)
|
||||
?.toDomain()
|
||||
.orEmpty()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.flocon.data.remote.deeplink.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
internal data class DeeplinkReceivedDataModel(
|
||||
val label: String? = null,
|
||||
val link: String,
|
||||
val description: String? = null,
|
||||
)
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.flocon.data.remote.deeplink.models
|
||||
|
||||
import io.github.openflocon.domain.deeplink.models.DeeplinkDomainModel
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
internal data class DeeplinksReceivedDataModel(
|
||||
val deeplinks: List<DeeplinkReceivedDataModel>,
|
||||
)
|
||||
|
||||
internal fun DeeplinksReceivedDataModel.toDomain(): List<DeeplinkDomainModel> = deeplinks.map {
|
||||
DeeplinkDomainModel(
|
||||
label = it.label,
|
||||
link = it.link,
|
||||
description = it.description,
|
||||
)
|
||||
}
|
||||
|
|
@ -1,14 +1,17 @@
|
|||
package com.flocon.data.remote.files.datasource
|
||||
|
||||
import com.flocon.data.remote.Protocol
|
||||
import com.flocon.data.remote.common.safeDecodeFromString
|
||||
import com.flocon.data.remote.files.models.FromDeviceFilesResultDataModel
|
||||
import com.flocon.data.remote.files.models.ToDeviceDeleteFileMessage
|
||||
import com.flocon.data.remote.files.models.ToDeviceDeleteFolderContentMessage
|
||||
import com.flocon.data.remote.files.models.ToDeviceGetFilesMessage
|
||||
import com.flocon.data.remote.files.models.toDomain
|
||||
import com.flocon.data.remote.models.FloconOutgoingMessageDataModel
|
||||
import com.flocon.data.remote.models.toRemote
|
||||
import com.flocon.data.remote.server.Server
|
||||
import com.flocon.data.remote.server.newRequestId
|
||||
import io.github.openflocon.data.core.files.datasource.FilesRemoteDataSource
|
||||
import io.github.openflocon.domain.Protocol
|
||||
import io.github.openflocon.domain.common.Either
|
||||
import io.github.openflocon.domain.common.Failure
|
||||
import io.github.openflocon.domain.common.Success
|
||||
|
|
@ -16,6 +19,7 @@ import io.github.openflocon.domain.device.models.DeviceIdAndPackageNameDomainMod
|
|||
import io.github.openflocon.domain.files.models.FileDomainModel
|
||||
import io.github.openflocon.domain.files.models.FilePathDomainModel
|
||||
import io.github.openflocon.domain.files.models.FromDeviceFilesResultDomainModel
|
||||
import io.github.openflocon.domain.messages.models.FloconIncomingMessageDomainModel
|
||||
import kotlinx.coroutines.TimeoutCancellationException
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
|
|
@ -28,6 +32,7 @@ import kotlin.uuid.ExperimentalUuidApi
|
|||
|
||||
class FilesRemoteDataSourceImpl(
|
||||
private val server: Server,
|
||||
private val json: Json
|
||||
) : FilesRemoteDataSource {
|
||||
private val getFilesResultReceived =
|
||||
MutableStateFlow<Set<FromDeviceFilesResultDomainModel>>(emptySet())
|
||||
|
|
@ -144,6 +149,11 @@ class FilesRemoteDataSourceImpl(
|
|||
return waitForResult(requestId)
|
||||
}
|
||||
|
||||
override fun getItems(message: FloconIncomingMessageDomainModel): FromDeviceFilesResultDomainModel? {
|
||||
return json.safeDecodeFromString<FromDeviceFilesResultDataModel>(message.body)
|
||||
?.toDomain()
|
||||
}
|
||||
|
||||
private suspend fun waitForResult(requestId: String): Either<Exception, List<FileDomainModel>> {
|
||||
try {
|
||||
val result = withTimeout(3_000) {
|
||||
|
|
@ -172,7 +182,7 @@ class FilesRemoteDataSourceImpl(
|
|||
isDirectory = it.isDirectory,
|
||||
path = FilePathDomainModel.Real(it.path),
|
||||
size = it.size,
|
||||
lastModified = Instant.Companion.fromEpochMilliseconds(it.lastModified),
|
||||
lastModified = Instant.fromEpochMilliseconds(it.lastModified),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
package com.flocon.data.remote.files.mapper
|
||||
|
||||
import com.flocon.data.remote.files.models.FromDeviceFilesDataModel
|
||||
import com.flocon.data.remote.files.models.FromDeviceFilesResultDataModel
|
||||
import io.github.openflocon.domain.files.models.FromDeviceFilesDomainModel
|
||||
import io.github.openflocon.domain.files.models.FromDeviceFilesResultDomainModel
|
||||
|
||||
// TODO INTERNAL
|
||||
fun FromDeviceFilesResultDataModel.toDomain() = FromDeviceFilesResultDomainModel(
|
||||
requestId = requestId,
|
||||
files = files.map(FromDeviceFilesDataModel::toDomain),
|
||||
)
|
||||
|
||||
fun FromDeviceFilesDataModel.toDomain() = FromDeviceFilesDomainModel(
|
||||
isDirectory = isDirectory,
|
||||
lastModified = lastModified,
|
||||
name = name,
|
||||
size = size,
|
||||
path = path,
|
||||
)
|
||||
|
|
@ -1,12 +1,21 @@
|
|||
package com.flocon.data.remote.files.models
|
||||
|
||||
import io.github.openflocon.domain.files.models.FromDeviceFilesDomainModel
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class FromDeviceFilesDataModel(
|
||||
internal data class FromDeviceFilesDataModel(
|
||||
val name: String,
|
||||
val isDirectory: Boolean,
|
||||
val path: String,
|
||||
val size: Long,
|
||||
val lastModified: Long,
|
||||
)
|
||||
|
||||
internal fun FromDeviceFilesDataModel.toDomain() = FromDeviceFilesDomainModel(
|
||||
name = name,
|
||||
isDirectory = isDirectory,
|
||||
path = path,
|
||||
size = size,
|
||||
lastModified = lastModified
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,15 @@
|
|||
package com.flocon.data.remote.files.models
|
||||
|
||||
import io.github.openflocon.domain.files.models.FromDeviceFilesResultDomainModel
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class FromDeviceFilesResultDataModel(
|
||||
internal data class FromDeviceFilesResultDataModel(
|
||||
val requestId: String,
|
||||
val files: List<FromDeviceFilesDataModel>,
|
||||
)
|
||||
|
||||
internal fun FromDeviceFilesResultDataModel.toDomain() = FromDeviceFilesResultDomainModel(
|
||||
requestId = requestId,
|
||||
files = files.map(FromDeviceFilesDataModel::toDomain)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
package com.flocon.data.remote.messages
|
||||
|
||||
import com.flocon.data.remote.messages.datasource.MessageRemoteDataSourceImpl
|
||||
import com.flocon.data.remote.server.Server
|
||||
import com.flocon.data.remote.server.getServer
|
||||
import io.github.openflocon.data.core.messages.datasource.MessageRemoteDataSource
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.dsl.bind
|
||||
import org.koin.dsl.module
|
||||
|
||||
internal val messagesModule = module {
|
||||
single<Server> { getServer() }
|
||||
singleOf(::MessageRemoteDataSourceImpl) bind MessageRemoteDataSource::class
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.flocon.data.remote.messages.datasource
|
||||
|
||||
import com.flocon.data.remote.messages.mapper.toDomain
|
||||
import com.flocon.data.remote.models.FloconIncomingMessageDataModel
|
||||
import com.flocon.data.remote.server.Server
|
||||
import io.github.openflocon.data.core.messages.datasource.MessageRemoteDataSource
|
||||
import io.github.openflocon.domain.messages.models.FloconIncomingMessageDomainModel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
internal class MessageRemoteDataSourceImpl(
|
||||
private val server: Server
|
||||
) : MessageRemoteDataSource {
|
||||
|
||||
override fun startServer() {
|
||||
server.start()
|
||||
}
|
||||
|
||||
override fun listenMessages(): Flow<FloconIncomingMessageDomainModel> {
|
||||
return server.receivedMessages
|
||||
.map(FloconIncomingMessageDataModel::toDomain)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.flocon.data.remote.messages.mapper
|
||||
|
||||
import com.flocon.data.remote.models.FloconIncomingMessageDataModel
|
||||
import io.github.openflocon.domain.messages.models.FloconIncomingMessageDomainModel
|
||||
|
||||
internal fun FloconIncomingMessageDataModel.toDomain() = FloconIncomingMessageDomainModel(
|
||||
deviceName = deviceName,
|
||||
deviceId = deviceId,
|
||||
appName = appName,
|
||||
appPackageName = appPackageName,
|
||||
method = method,
|
||||
body = body,
|
||||
plugin = plugin
|
||||
)
|
||||
|
|
@ -1,17 +1,28 @@
|
|||
package com.flocon.data.remote.network.datasource
|
||||
|
||||
import com.flocon.data.remote.Protocol
|
||||
import com.flocon.data.remote.common.safeDecodeFromString
|
||||
import com.flocon.data.remote.models.FloconOutgoingMessageDataModel
|
||||
import com.flocon.data.remote.models.toRemote
|
||||
import com.flocon.data.remote.network.mapper.listToRemote
|
||||
import com.flocon.data.remote.network.models.FloconNetworkCallIdDataModel
|
||||
import com.flocon.data.remote.network.models.FloconNetworkRequestDataModel
|
||||
import com.flocon.data.remote.network.models.FloconNetworkResponseDataModel
|
||||
import com.flocon.data.remote.network.models.toDomain
|
||||
import com.flocon.data.remote.server.Server
|
||||
import io.github.openflocon.data.core.network.datasource.NetworkRemoteDataSource
|
||||
import io.github.openflocon.domain.Protocol
|
||||
import io.github.openflocon.domain.device.models.DeviceIdAndPackageNameDomainModel
|
||||
import io.github.openflocon.domain.messages.models.FloconIncomingMessageDomainModel
|
||||
import io.github.openflocon.domain.network.models.FloconNetworkCallDomainModel
|
||||
import io.github.openflocon.domain.network.models.FloconNetworkCallIdDomainModel
|
||||
import io.github.openflocon.domain.network.models.FloconNetworkResponseDomainModel
|
||||
import io.github.openflocon.domain.network.models.FloconNetworkResponseOnlyDomainModel
|
||||
import io.github.openflocon.domain.network.models.MockNetworkDomainModel
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
class NetworkRemoteDataSourceImpl(
|
||||
private val server: Server,
|
||||
private val json: Json
|
||||
) : NetworkRemoteDataSource {
|
||||
|
||||
override suspend fun setupMocks(
|
||||
|
|
@ -29,4 +40,19 @@ class NetworkRemoteDataSourceImpl(
|
|||
),
|
||||
)
|
||||
}
|
||||
|
||||
override fun getRequestData(message: FloconIncomingMessageDomainModel): FloconNetworkCallDomainModel? {
|
||||
return json.safeDecodeFromString<FloconNetworkRequestDataModel>(message.body)
|
||||
?.let { com.flocon.data.remote.network.mapper.toDomain(it) }
|
||||
}
|
||||
|
||||
override fun getCallId(message: FloconIncomingMessageDomainModel): FloconNetworkCallIdDomainModel? {
|
||||
return json.safeDecodeFromString<FloconNetworkCallIdDataModel>(message.body)
|
||||
?.let(FloconNetworkCallIdDataModel::toDomain)
|
||||
}
|
||||
|
||||
override fun getResponseData(message: FloconIncomingMessageDomainModel): FloconNetworkResponseOnlyDomainModel? {
|
||||
return json.safeDecodeFromString<FloconNetworkResponseDataModel>(message.body)
|
||||
?.let(FloconNetworkResponseDataModel::toDomain)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,15 @@
|
|||
package com.flocon.data.remote.network.mapper
|
||||
|
||||
import com.flocon.data.remote.network.models.FloconNetworkRequestDataModel
|
||||
import com.flocon.data.remote.network.models.MockNetworkResponseDataModel
|
||||
import io.github.openflocon.data.core.network.graphql.model.GraphQlExtracted
|
||||
import io.github.openflocon.data.core.network.graphql.model.GraphQlRequestBody
|
||||
import io.github.openflocon.data.core.network.graphql.model.GraphQlResponseBody
|
||||
import io.github.openflocon.domain.network.models.FloconNetworkCallDomainModel
|
||||
import io.github.openflocon.domain.network.models.FloconNetworkRequestDomainModel
|
||||
import io.github.openflocon.domain.network.models.MockNetworkDomainModel
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlin.uuid.ExperimentalUuidApi
|
||||
|
||||
fun listToRemote(mocks: List<MockNetworkDomainModel>): List<MockNetworkResponseDataModel> = mocks.map { toRemote(it) }
|
||||
|
||||
|
|
@ -18,3 +26,99 @@ fun toRemote(mock: MockNetworkDomainModel): MockNetworkResponseDataModel = MockN
|
|||
headers = mock.response.headers,
|
||||
),
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalUuidApi::class)
|
||||
fun toDomain(decoded: FloconNetworkRequestDataModel): FloconNetworkCallDomainModel? = try {
|
||||
val graphQl = extractGraphQl(decoded)
|
||||
|
||||
val callId = decoded.floconCallId!!
|
||||
val networkRequest = FloconNetworkRequestDomainModel(
|
||||
url = decoded.url!!,
|
||||
startTime = decoded.startTime!!,
|
||||
method = decoded.method!!,
|
||||
headers = decoded.requestHeaders!!,
|
||||
body = decoded.requestBody,
|
||||
byteSize = decoded.requestSize ?: 0L,
|
||||
isMocked = decoded.isMocked ?: false,
|
||||
)
|
||||
|
||||
when {
|
||||
graphQl != null -> FloconNetworkCallDomainModel.GraphQl(
|
||||
callId = callId,
|
||||
request = FloconNetworkCallDomainModel.GraphQl.Request(
|
||||
query = graphQl.request.queryName ?: "anonymous",
|
||||
operationType = graphQl.request.operationType,
|
||||
networkRequest = networkRequest,
|
||||
),
|
||||
response = null,
|
||||
)
|
||||
|
||||
decoded.floconNetworkType == "grpc" -> FloconNetworkCallDomainModel.Grpc(
|
||||
callId = callId,
|
||||
networkRequest = networkRequest,
|
||||
response = null,
|
||||
)
|
||||
// decoded.floconNetworkType == "http"
|
||||
else -> {
|
||||
FloconNetworkCallDomainModel.Http(
|
||||
callId = callId,
|
||||
networkRequest = networkRequest,
|
||||
response = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
} catch (t: Throwable) {
|
||||
t.printStackTrace()
|
||||
null
|
||||
}
|
||||
|
||||
|
||||
private val graphQlParser = Json {
|
||||
ignoreUnknownKeys = true
|
||||
}
|
||||
|
||||
// maybe use graphql-java
|
||||
fun extractGraphQl(decoded: FloconNetworkRequestDataModel): GraphQlExtracted? {
|
||||
val request = decoded.requestBody?.let {
|
||||
try {
|
||||
val requestBody = graphQlParser.decodeFromString<GraphQlRequestBody>(it)
|
||||
|
||||
val queryName = extractOperationName(requestBody.query)
|
||||
val operationType = extractOperationType(requestBody.query)
|
||||
|
||||
GraphQlExtracted.Request(
|
||||
requestBody = requestBody,
|
||||
queryName = queryName,
|
||||
operationType = operationType ?: return null,
|
||||
)
|
||||
} catch (t: Throwable) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
return if (request != null) {
|
||||
GraphQlExtracted(
|
||||
request = request,
|
||||
)
|
||||
} else null
|
||||
}
|
||||
|
||||
fun extractOperationType(query: String): String? {
|
||||
val regex = Regex("""\b(query|mutation|subscription)\b""")
|
||||
val matchResult = regex.find(query.trim())
|
||||
return matchResult?.value
|
||||
}
|
||||
|
||||
private fun extractOperationName(query: String): String? {
|
||||
val regex = Regex("""\b(query|mutation|subscription)\s+(\w+)""")
|
||||
val matchResult = regex.find(query.trim())
|
||||
return matchResult?.groups?.get(2)?.value
|
||||
}
|
||||
|
||||
fun computeIsGraphQlSuccess(
|
||||
responseHttpCode: Int,
|
||||
response: GraphQlResponseBody?,
|
||||
): Boolean {
|
||||
if (responseHttpCode !in 200..299) return false
|
||||
return response?.errors?.takeUnless { it.isEmpty() } == null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
package com.flocon.data.remote.network.models
|
||||
|
||||
import io.github.openflocon.domain.network.models.FloconNetworkCallIdDomainModel
|
||||
import io.github.openflocon.domain.network.models.FloconNetworkRequestDomainModel
|
||||
import io.github.openflocon.domain.network.models.FloconNetworkResponseDomainModel
|
||||
import io.github.openflocon.domain.network.models.FloconNetworkResponseOnlyDomainModel
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class FloconNetworkRequestDataModel(
|
||||
val floconCallId: String? = null,
|
||||
val floconNetworkType: String? = null,
|
||||
|
||||
val url: String? = null,
|
||||
val method: String? = null,
|
||||
val startTime: Long? = null,
|
||||
// request
|
||||
val requestHeaders: Map<String, String>? = null,
|
||||
val requestBody: String? = null,
|
||||
val requestSize: Long? = null,
|
||||
val isMocked: Boolean? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class FloconNetworkCallIdDataModel(
|
||||
val floconCallId: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class FloconNetworkResponseDataModel(
|
||||
val floconCallId: String? = null,
|
||||
val floconNetworkType: String? = null,
|
||||
|
||||
val durationMs: Double? = null,
|
||||
val responseHttpCode: Int? = null, // ex: 200
|
||||
val responseContentType: String? = null,
|
||||
val responseBody: String? = null,
|
||||
val responseHeaders: Map<String, String>? = null,
|
||||
val responseSize: Long? = null,
|
||||
val responseGrpcStatus: String? = null,
|
||||
)
|
||||
|
||||
internal fun FloconNetworkResponseDataModel.toDomain() : FloconNetworkResponseOnlyDomainModel? {
|
||||
return try {
|
||||
val callId = floconCallId!!
|
||||
val networkResponse = FloconNetworkResponseDomainModel(
|
||||
durationMs = durationMs ?: 0.0,
|
||||
body = responseBody,
|
||||
byteSize = responseSize ?: 0L,
|
||||
headers = responseHeaders.orEmpty(),
|
||||
contentType = responseContentType,
|
||||
)
|
||||
when (floconNetworkType) {
|
||||
"grpc" -> FloconNetworkResponseOnlyDomainModel.Grpc(
|
||||
floconCallId = callId,
|
||||
networkResponse = networkResponse,
|
||||
grpcStatus = responseGrpcStatus!!,
|
||||
)
|
||||
// otherwise tread like http
|
||||
else -> FloconNetworkResponseOnlyDomainModel.Http(
|
||||
floconCallId = callId,
|
||||
networkResponse = networkResponse,
|
||||
httpCode = responseHttpCode!!,
|
||||
)
|
||||
}
|
||||
} catch (t: Throwable) {
|
||||
t.printStackTrace()
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
internal fun FloconNetworkCallIdDataModel.toDomain(): FloconNetworkCallIdDomainModel? {
|
||||
return FloconNetworkCallIdDomainModel(
|
||||
floconCallId = floconCallId ?: return null
|
||||
)
|
||||
}
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
package com.flocon.data.remote.sharedpreference
|
||||
|
||||
import com.flocon.data.remote.sharedpreference.datasource.DeviceSharedPreferencesRemoteDataSource
|
||||
import com.flocon.data.remote.sharedpreference.datasource.DeviceSharedPreferencesRemoteDataSourceImpl
|
||||
import io.github.openflocon.data.core.sharedpreference.datasource.DeviceSharedPreferencesRemoteDataSource
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.dsl.bind
|
||||
import org.koin.dsl.module
|
||||
|
||||
internal val sharedPreferencesModule = module {
|
||||
singleOf(::DeviceSharedPreferencesRemoteDataSource)
|
||||
singleOf(::DeviceSharedPreferencesRemoteDataSourceImpl) bind DeviceSharedPreferencesRemoteDataSource::class
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,32 @@
|
|||
package com.flocon.data.remote.sharedpreference.datasource
|
||||
|
||||
import com.flocon.data.remote.Protocol
|
||||
import com.flocon.data.remote.common.safeDecodeFromString
|
||||
import com.flocon.data.remote.models.FloconOutgoingMessageDataModel
|
||||
import com.flocon.data.remote.models.toRemote
|
||||
import com.flocon.data.remote.server.Server
|
||||
import com.flocon.data.remote.server.newRequestId
|
||||
import com.flocon.data.remote.sharedpreference.mapper.SharedPreferenceValuesResponse
|
||||
import com.flocon.data.remote.sharedpreference.mapper.toSharedPreferenceValuesResponseDomain
|
||||
import com.flocon.data.remote.sharedpreference.models.DeviceSharedPreferenceDataModel
|
||||
import com.flocon.data.remote.sharedpreference.models.ToDeviceEditSharedPreferenceValueMessage
|
||||
import com.flocon.data.remote.sharedpreference.models.ToDeviceGetSharedPreferenceValueMessage
|
||||
import com.flocon.data.remote.sharedpreference.models.toDeviceSharedPreferenceDomain
|
||||
import io.github.openflocon.data.core.sharedpreference.datasource.DeviceSharedPreferencesRemoteDataSource
|
||||
import io.github.openflocon.domain.Protocol
|
||||
import io.github.openflocon.domain.device.models.DeviceIdAndPackageNameDomainModel
|
||||
import io.github.openflocon.domain.messages.models.FloconIncomingMessageDomainModel
|
||||
import io.github.openflocon.domain.sharedpreference.models.DeviceSharedPreferenceDomainModel
|
||||
import io.github.openflocon.domain.sharedpreference.models.DeviceSharedPreferenceId
|
||||
import io.github.openflocon.domain.sharedpreference.models.SharedPreferenceRowDomainModel
|
||||
import io.github.openflocon.domain.sharedpreference.models.SharedPreferenceValuesResponseDomainModel
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
class DeviceSharedPreferencesRemoteDataSource(
|
||||
class DeviceSharedPreferencesRemoteDataSourceImpl(
|
||||
private val server: Server,
|
||||
) {
|
||||
suspend fun askForDeviceSharedPreferences(
|
||||
private val json: Json
|
||||
) : DeviceSharedPreferencesRemoteDataSource {
|
||||
|
||||
override suspend fun askForDeviceSharedPreferences(
|
||||
deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel,
|
||||
) {
|
||||
server.sendMessageToClient(
|
||||
|
|
@ -29,7 +39,7 @@ class DeviceSharedPreferencesRemoteDataSource(
|
|||
)
|
||||
}
|
||||
|
||||
suspend fun getDeviceSharedPreferencesValues(
|
||||
override suspend fun getDeviceSharedPreferencesValues(
|
||||
deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel,
|
||||
sharedPreferenceId: DeviceSharedPreferenceId,
|
||||
) {
|
||||
|
|
@ -49,7 +59,7 @@ class DeviceSharedPreferencesRemoteDataSource(
|
|||
)
|
||||
}
|
||||
|
||||
suspend fun editSharedPrefField(
|
||||
override suspend fun editSharedPrefField(
|
||||
deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel,
|
||||
sharedPreference: DeviceSharedPreferenceDomainModel,
|
||||
key: String,
|
||||
|
|
@ -77,4 +87,16 @@ class DeviceSharedPreferencesRemoteDataSource(
|
|||
),
|
||||
)
|
||||
}
|
||||
|
||||
override fun getPreferences(message: FloconIncomingMessageDomainModel): List<DeviceSharedPreferenceDomainModel> {
|
||||
return json.safeDecodeFromString<List<DeviceSharedPreferenceDataModel>>(message.body)
|
||||
?.let { toDeviceSharedPreferenceDomain(it) }
|
||||
.orEmpty()
|
||||
}
|
||||
|
||||
override fun getValues(message: FloconIncomingMessageDomainModel): SharedPreferenceValuesResponseDomainModel? {
|
||||
return json.safeDecodeFromString<SharedPreferenceValuesResponse>(message.body)
|
||||
?.let { toSharedPreferenceValuesResponseDomain(it) }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
package com.flocon.data.remote.sharedpreference.mapper
|
||||
|
||||
import com.flocon.data.remote.sharedpreference.models.DeviceSharedPreferenceDataModel
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
// maybe inject
|
||||
private val sharedPreferencesJsonParser = Json {
|
||||
ignoreUnknownKeys = true
|
||||
}
|
||||
|
||||
// TODO Internal
|
||||
fun decodeDeviceSharedPreferences(body: String): List<DeviceSharedPreferenceDataModel>? = try {
|
||||
sharedPreferencesJsonParser.decodeFromString<List<DeviceSharedPreferenceDataModel>>(body)
|
||||
} catch (t: Throwable) {
|
||||
t.printStackTrace()
|
||||
null
|
||||
}
|
||||
|
||||
fun decodeSharedPreferenceValuesResponse(body: String): SharedPreferenceValuesResponse? = try {
|
||||
sharedPreferencesJsonParser.decodeFromString<SharedPreferenceValuesResponse>(body)
|
||||
} catch (t: Throwable) {
|
||||
t.printStackTrace()
|
||||
null
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ import io.github.openflocon.domain.sharedpreference.models.SharedPreferenceValue
|
|||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class SharedPreferenceValuesResponse(
|
||||
internal data class SharedPreferenceValuesResponse(
|
||||
val requestId: String,
|
||||
val sharedPreferenceName: String,
|
||||
val rows: List<Row>,
|
||||
|
|
@ -22,48 +22,49 @@ data class SharedPreferenceValuesResponse(
|
|||
)
|
||||
}
|
||||
|
||||
fun toSharedPreferenceValuesResponseDomain(data: SharedPreferenceValuesResponse): SharedPreferenceValuesResponseDomainModel = SharedPreferenceValuesResponseDomainModel(
|
||||
requestId = data.requestId,
|
||||
sharedPreferenceName = data.sharedPreferenceName,
|
||||
rows = data.rows.mapNotNull { row ->
|
||||
row.stringValue?.let { value ->
|
||||
return@mapNotNull SharedPreferenceRowDomainModel(
|
||||
key = row.key,
|
||||
value = SharedPreferenceRowDomainModel.Value.StringValue(value = value),
|
||||
)
|
||||
}
|
||||
row.intValue?.let { value ->
|
||||
return@mapNotNull SharedPreferenceRowDomainModel(
|
||||
key = row.key,
|
||||
value = SharedPreferenceRowDomainModel.Value.IntValue(value),
|
||||
)
|
||||
}
|
||||
row.floatValue?.let { value ->
|
||||
return@mapNotNull SharedPreferenceRowDomainModel(
|
||||
key = row.key,
|
||||
value = SharedPreferenceRowDomainModel.Value.FloatValue(value),
|
||||
)
|
||||
}
|
||||
row.booleanValue?.let { value ->
|
||||
return@mapNotNull SharedPreferenceRowDomainModel(
|
||||
key = row.key,
|
||||
value = SharedPreferenceRowDomainModel.Value.BooleanValue(value),
|
||||
)
|
||||
}
|
||||
row.longValue?.let { value ->
|
||||
return@mapNotNull SharedPreferenceRowDomainModel(
|
||||
key = row.key,
|
||||
value = SharedPreferenceRowDomainModel.Value.LongValue(value),
|
||||
)
|
||||
}
|
||||
row.setStringValue?.let { value ->
|
||||
return@mapNotNull SharedPreferenceRowDomainModel(
|
||||
key = row.key,
|
||||
value = SharedPreferenceRowDomainModel.Value.StringSetValue(value.toSet()),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
internal fun toSharedPreferenceValuesResponseDomain(data: SharedPreferenceValuesResponse): SharedPreferenceValuesResponseDomainModel =
|
||||
SharedPreferenceValuesResponseDomainModel(
|
||||
requestId = data.requestId,
|
||||
sharedPreferenceName = data.sharedPreferenceName,
|
||||
rows = data.rows.mapNotNull { row ->
|
||||
row.stringValue?.let { value ->
|
||||
return@mapNotNull SharedPreferenceRowDomainModel(
|
||||
key = row.key,
|
||||
value = SharedPreferenceRowDomainModel.Value.StringValue(value = value),
|
||||
)
|
||||
}
|
||||
row.intValue?.let { value ->
|
||||
return@mapNotNull SharedPreferenceRowDomainModel(
|
||||
key = row.key,
|
||||
value = SharedPreferenceRowDomainModel.Value.IntValue(value),
|
||||
)
|
||||
}
|
||||
row.floatValue?.let { value ->
|
||||
return@mapNotNull SharedPreferenceRowDomainModel(
|
||||
key = row.key,
|
||||
value = SharedPreferenceRowDomainModel.Value.FloatValue(value),
|
||||
)
|
||||
}
|
||||
row.booleanValue?.let { value ->
|
||||
return@mapNotNull SharedPreferenceRowDomainModel(
|
||||
key = row.key,
|
||||
value = SharedPreferenceRowDomainModel.Value.BooleanValue(value),
|
||||
)
|
||||
}
|
||||
row.longValue?.let { value ->
|
||||
return@mapNotNull SharedPreferenceRowDomainModel(
|
||||
key = row.key,
|
||||
value = SharedPreferenceRowDomainModel.Value.LongValue(value),
|
||||
)
|
||||
}
|
||||
row.setStringValue?.let { value ->
|
||||
return@mapNotNull SharedPreferenceRowDomainModel(
|
||||
key = row.key,
|
||||
value = SharedPreferenceRowDomainModel.Value.StringSetValue(value.toSet()),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
private fun decodeStringToSet(encodedString: String): Set<String> {
|
||||
// Si la chaîne est vide, cela signifie que le set original était vide.
|
||||
|
|
|
|||
|
|
@ -1,25 +1,38 @@
|
|||
package com.flocon.data.remote.table.datasource
|
||||
|
||||
import com.flocon.data.remote.Protocol
|
||||
import com.flocon.data.remote.common.safeDecodeFromString
|
||||
import com.flocon.data.remote.models.FloconOutgoingMessageDataModel
|
||||
import com.flocon.data.remote.models.toRemote
|
||||
import com.flocon.data.remote.server.Server
|
||||
import com.flocon.data.remote.table.mapper.toDomain
|
||||
import com.flocon.data.remote.table.model.TableItemDataModel
|
||||
import io.github.openflocon.data.core.table.datasource.TableRemoteDataSource
|
||||
import io.github.openflocon.domain.Protocol
|
||||
import io.github.openflocon.domain.device.models.DeviceIdAndPackageNameDomainModel
|
||||
import io.github.openflocon.domain.messages.models.FloconIncomingMessageDomainModel
|
||||
import io.github.openflocon.domain.table.models.TableDomainModel
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
class TableRemoteDataSourceImpl(
|
||||
private val server: Server,
|
||||
private val json: Json
|
||||
) : TableRemoteDataSource {
|
||||
|
||||
override suspend fun clearReceivedItem(deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel, items: List<String>) {
|
||||
server.sendMessageToClient(
|
||||
deviceIdAndPackageName = deviceIdAndPackageName.toRemote(),
|
||||
message =
|
||||
FloconOutgoingMessageDataModel(
|
||||
message = FloconOutgoingMessageDataModel(
|
||||
plugin = Protocol.ToDevice.Table.Plugin,
|
||||
method = Protocol.ToDevice.Table.Method.ClearItems,
|
||||
body = Json.Default.encodeToString(items),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
override fun getItems(message: FloconIncomingMessageDomainModel): List<TableDomainModel> {
|
||||
return json.safeDecodeFromString<List<TableItemDataModel>>(message.body)
|
||||
?.map { toDomain(it) }
|
||||
.orEmpty()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
package com.flocon.data.remote.table.mapper
|
||||
|
||||
import io.github.openflocon.domain.table.models.TableDomainModel
|
||||
import com.flocon.data.remote.table.model.TableItemDataModel
|
||||
|
||||
internal fun toDomain(dataModel: TableItemDataModel): TableDomainModel = TableDomainModel(
|
||||
name = dataModel.name,
|
||||
items = listOf(
|
||||
TableDomainModel.TableItem(
|
||||
itemId = dataModel.id,
|
||||
createdAt = dataModel.createdAt,
|
||||
values = dataModel.columns.map { it.value },
|
||||
columns = dataModel.columns.map { it.column },
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.flocon.data.remote.table.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class TableColumnDataModel(
|
||||
val column: String,
|
||||
val value: String,
|
||||
)
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.flocon.data.remote.table.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class TableItemDataModel(
|
||||
val id: String,
|
||||
val name: String,
|
||||
val createdAt: Long,
|
||||
val columns: List<TableColumnDataModel>,
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue