From 35d896af23d98faae7eb384df6c0e4e5a751d61f Mon Sep 17 00:00:00 2001 From: Florent CHAMPIGNY Date: Thu, 21 Aug 2025 10:25:03 +0200 Subject: [PATCH] Refact network model (#123) * refact: [NETWORK] model with error * refact: [NETWORK] model with error * refact: [NETWORK] model with error * refact: [NETWORK] model with error * refact: [NETWORK] model with error * refact * merged with main --------- Co-authored-by: Florent Champigny --- .../plugins/network/FloconNetworkPlugin.kt | 3 - .../network/model/FloconHttpRequest.kt | 1 + .../mapper/FloconNetworkRequestToJson.kt | 1 + .../flocon/grpc/FloconGrpcInterceptor.kt | 1 + .../flocon/ktor/FloconKtorPlugin.kt | 3 +- .../flocon/okhttp/OkHttpInterceptor.kt | 8 +- .../41.json | 13 +- .../flocondesktop/common/db/AppDatabase.kt | 2 +- .../detail/mapper/NetworkDetailUiMapper.kt | 92 ++++++---- .../detail/model/NetworkDetailViewState.kt | 17 +- .../network/detail/view/NetworkDetailView.kt | 167 ++++++++++-------- .../features/network/list/NetworkViewModel.kt | 2 +- .../network/list/mapper/MethodUiMapper.kt | 10 +- .../network/list/mapper/NetworkUiMapper.kt | 19 +- .../network/list/mapper/StatusUiMapper.kt | 44 +++-- .../network/list/mapper/TypeUiMapper.kt | 16 +- .../SortAndFilterNetworkItemsProcessor.kt | 4 +- .../images/repository/ImagesRepositoryImpl.kt | 6 +- .../datasource/NetworkRemoteDataSource.kt | 1 - .../repository/NetworkRepositoryImpl.kt | 60 +++---- .../data/local/network/mapper/MapperLite.kt | 115 ++++++------ .../local/network/mapper/MapperToDomain.kt | 108 +++++------ .../local/network/mapper/MapperToEntity.kt | 106 ++++++----- .../models/FloconNetwockCallEntityLite.kt | 1 + .../network/models/FloconNetworkCallEntity.kt | 1 + .../com/flocon/data/remote/common/JsonExt.kt | 3 +- .../data/remote/network/mapper/Mapper.kt | 42 ++--- .../models/FloconNetworkRequestDataModel.kt | 46 +++-- .../models/FloconNetworkCallDomainModel.kt | 152 ++++++++-------- .../usecase/GenerateCurlCommandUseCase.kt | 8 +- ...nerateNetworkMockFromNetworkCallUseCase.kt | 23 +-- 31 files changed, 571 insertions(+), 504 deletions(-) diff --git a/FloconAndroid/flocon-base/src/main/java/io/github/openflocon/flocon/plugins/network/FloconNetworkPlugin.kt b/FloconAndroid/flocon-base/src/main/java/io/github/openflocon/flocon/plugins/network/FloconNetworkPlugin.kt index cd1cc26f..74ef572a 100644 --- a/FloconAndroid/flocon-base/src/main/java/io/github/openflocon/flocon/plugins/network/FloconNetworkPlugin.kt +++ b/FloconAndroid/flocon-base/src/main/java/io/github/openflocon/flocon/plugins/network/FloconNetworkPlugin.kt @@ -2,11 +2,8 @@ package io.github.openflocon.flocon.plugins.network import io.github.openflocon.flocon.core.FloconPlugin import io.github.openflocon.flocon.plugins.network.model.BadQualityConfig -import io.github.openflocon.flocon.plugins.network.model.FloconNetworkCall import io.github.openflocon.flocon.plugins.network.model.FloconNetworkCallRequest import io.github.openflocon.flocon.plugins.network.model.FloconNetworkCallResponse -import io.github.openflocon.flocon.plugins.network.model.FloconNetworkRequest -import io.github.openflocon.flocon.plugins.network.model.FloconNetworkResponse import io.github.openflocon.flocon.plugins.network.model.MockNetworkResponse interface FloconNetworkPlugin : FloconPlugin { diff --git a/FloconAndroid/flocon-base/src/main/java/io/github/openflocon/flocon/plugins/network/model/FloconHttpRequest.kt b/FloconAndroid/flocon-base/src/main/java/io/github/openflocon/flocon/plugins/network/model/FloconHttpRequest.kt index 7bf0b2a4..51dee2ac 100644 --- a/FloconAndroid/flocon-base/src/main/java/io/github/openflocon/flocon/plugins/network/model/FloconHttpRequest.kt +++ b/FloconAndroid/flocon-base/src/main/java/io/github/openflocon/flocon/plugins/network/model/FloconHttpRequest.kt @@ -25,4 +25,5 @@ data class FloconNetworkResponse( val body: String?, val size: Long?, val headers: Map, + val error: String?, ) \ No newline at end of file diff --git a/FloconAndroid/flocon/src/main/java/io/github/openflocon/flocon/plugins/network/mapper/FloconNetworkRequestToJson.kt b/FloconAndroid/flocon/src/main/java/io/github/openflocon/flocon/plugins/network/mapper/FloconNetworkRequestToJson.kt index 69c2c98b..89a6342c 100644 --- a/FloconAndroid/flocon/src/main/java/io/github/openflocon/flocon/plugins/network/mapper/FloconNetworkRequestToJson.kt +++ b/FloconAndroid/flocon/src/main/java/io/github/openflocon/flocon/plugins/network/mapper/FloconNetworkRequestToJson.kt @@ -39,6 +39,7 @@ fun floconNetworkCallResponseToJson(network: FloconNetworkCallResponse): JSONObj response.body?.let { json.put("responseBody", it) } json.put("responseHeaders", JSONObject(response.headers)) json.put("responseSize", response.size) + response.error?.let { json.put("responseError", it) } } return json diff --git a/FloconAndroid/grpc-interceptor/src/main/java/io/github/openflocon/flocon/grpc/FloconGrpcInterceptor.kt b/FloconAndroid/grpc-interceptor/src/main/java/io/github/openflocon/flocon/grpc/FloconGrpcInterceptor.kt index 3c609e38..74116a76 100644 --- a/FloconAndroid/grpc-interceptor/src/main/java/io/github/openflocon/flocon/grpc/FloconGrpcInterceptor.kt +++ b/FloconAndroid/grpc-interceptor/src/main/java/io/github/openflocon/flocon/grpc/FloconGrpcInterceptor.kt @@ -148,6 +148,7 @@ private class LoggingClientCallListener( contentType = "grpc", size = 0L, grpcStatus = status.code.toString(), + error = null, ), ) } diff --git a/FloconAndroid/ktor-interceptor/src/main/java/io/github/openflocon/flocon/ktor/FloconKtorPlugin.kt b/FloconAndroid/ktor-interceptor/src/main/java/io/github/openflocon/flocon/ktor/FloconKtorPlugin.kt index 4a83ba93..1793ee1d 100644 --- a/FloconAndroid/ktor-interceptor/src/main/java/io/github/openflocon/flocon/ktor/FloconKtorPlugin.kt +++ b/FloconAndroid/ktor-interceptor/src/main/java/io/github/openflocon/flocon/ktor/FloconKtorPlugin.kt @@ -110,7 +110,8 @@ val FloconKtorPlugin = createClientPlugin("FloconKtorPlugin") { body = bodyString.takeUnless { isImage }, headers = responseHeadersMap, size = responseSize, - grpcStatus = null + grpcStatus = null, + error = null, ) floconNetworkPlugin.logResponse( diff --git a/FloconAndroid/okhttp-interceptor/src/main/java/io/github/openflocon/flocon/okhttp/OkHttpInterceptor.kt b/FloconAndroid/okhttp-interceptor/src/main/java/io/github/openflocon/flocon/okhttp/OkHttpInterceptor.kt index 15b18f83..27846f31 100644 --- a/FloconAndroid/okhttp-interceptor/src/main/java/io/github/openflocon/flocon/okhttp/OkHttpInterceptor.kt +++ b/FloconAndroid/okhttp-interceptor/src/main/java/io/github/openflocon/flocon/okhttp/OkHttpInterceptor.kt @@ -149,6 +149,7 @@ class FloconOkhttpInterceptor() : Interceptor { headers = responseHeadersMap, size = responseSize, grpcStatus = null, + error = null, ) floconNetworkPlugin.logResponse( @@ -171,12 +172,13 @@ class FloconOkhttpInterceptor() : Interceptor { val durationMs: Double = (endTime - startTime) / 1e6 val floconCallResponse = FloconNetworkResponse( - httpCode = 0, - contentType = "error", - body = e.message, // TODO better handle of errors + httpCode = null, + contentType = null, + body = null, headers = emptyMap(), size = null, grpcStatus = null, + error = e.message ?: e.javaClass.simpleName, ) floconNetworkPlugin.logResponse( diff --git a/FloconDesktop/composeApp/schemas/io.github.openflocon.flocondesktop.common.db.AppDatabase/41.json b/FloconDesktop/composeApp/schemas/io.github.openflocon.flocondesktop.common.db.AppDatabase/41.json index 29df1dd3..29c6bf6b 100644 --- a/FloconDesktop/composeApp/schemas/io.github.openflocon.flocondesktop.common.db.AppDatabase/41.json +++ b/FloconDesktop/composeApp/schemas/io.github.openflocon.flocondesktop.common.db.AppDatabase/41.json @@ -2,11 +2,11 @@ "formatVersion": 1, "database": { "version": 41, - "identityHash": "d699dfc54e3dbaa0e3ae992b29140a1e", + "identityHash": "f1dea53a3a26fcc273eacc8cb3f47879", "entities": [ { "tableName": "FloconNetworkCallEntity", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`callId` TEXT NOT NULL, `deviceId` TEXT NOT NULL, `packageName` TEXT NOT NULL, `type` TEXT NOT NULL, `request_url` TEXT NOT NULL, `request_method` TEXT NOT NULL, `request_startTime` INTEGER NOT NULL, `request_requestHeaders` TEXT NOT NULL, `request_requestBody` TEXT, `request_requestByteSize` INTEGER NOT NULL, `request_isMocked` INTEGER NOT NULL, `request_graphql_query` TEXT, `request_graphql_operationType` TEXT, `response_durationMs` REAL, `response_responseContentType` TEXT, `response_responseBody` TEXT, `response_responseHeaders` TEXT, `response_responseByteSize` INTEGER, `response_graphql_isSuccess` INTEGER, `response_graphql_responseHttpCode` INTEGER, `response_http_responseHttpCode` INTEGER, `response_grpc_responseStatus` TEXT, PRIMARY KEY(`callId`))", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`callId` TEXT NOT NULL, `deviceId` TEXT NOT NULL, `packageName` TEXT NOT NULL, `type` TEXT NOT NULL, `request_url` TEXT NOT NULL, `request_method` TEXT NOT NULL, `request_startTime` INTEGER NOT NULL, `request_requestHeaders` TEXT NOT NULL, `request_requestBody` TEXT, `request_requestByteSize` INTEGER NOT NULL, `request_isMocked` INTEGER NOT NULL, `request_graphql_query` TEXT, `request_graphql_operationType` TEXT, `response_durationMs` INTEGER, `response_responseContentType` TEXT, `response_responseBody` TEXT, `response_responseHeaders` TEXT, `response_responseByteSize` INTEGER, `response_responseError` TEXT, `response_graphql_isSuccess` INTEGER, `response_graphql_responseHttpCode` INTEGER, `response_http_responseHttpCode` INTEGER, `response_grpc_responseStatus` TEXT, PRIMARY KEY(`callId`))", "fields": [ { "fieldPath": "callId", @@ -86,7 +86,7 @@ { "fieldPath": "response.durationMs", "columnName": "response_durationMs", - "affinity": "REAL" + "affinity": "INTEGER" }, { "fieldPath": "response.responseContentType", @@ -108,6 +108,11 @@ "columnName": "response_responseByteSize", "affinity": "INTEGER" }, + { + "fieldPath": "response.responseError", + "columnName": "response_responseError", + "affinity": "TEXT" + }, { "fieldPath": "response.graphql.isSuccess", "columnName": "response_graphql_isSuccess", @@ -1089,7 +1094,7 @@ ], "setupQueries": [ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'd699dfc54e3dbaa0e3ae992b29140a1e')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f1dea53a3a26fcc273eacc8cb3f47879')" ] } } \ No newline at end of file diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/db/AppDatabase.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/db/AppDatabase.kt index 0be884e9..19f684db 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/db/AppDatabase.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/db/AppDatabase.kt @@ -36,7 +36,7 @@ import io.github.openflocon.flocondesktop.common.db.converters.MapStringsConvert import kotlinx.coroutines.Dispatchers @Database( - version = 41, + version = 43, entities = [ FloconNetworkCallEntity::class, FileEntity::class, diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/mapper/NetworkDetailUiMapper.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/mapper/NetworkDetailUiMapper.kt index 87cc3781..672de4b4 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/mapper/NetworkDetailUiMapper.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/mapper/NetworkDetailUiMapper.kt @@ -1,6 +1,7 @@ package io.github.openflocon.flocondesktop.features.network.detail.mapper import io.github.openflocon.domain.network.models.FloconNetworkCallDomainModel +import io.github.openflocon.domain.network.models.httpCode import io.github.openflocon.flocondesktop.common.ui.ByteFormatter import io.github.openflocon.flocondesktop.common.ui.JsonPrettyPrinter import io.github.openflocon.flocondesktop.features.network.detail.model.NetworkDetailHeaderUi @@ -17,43 +18,70 @@ import io.github.openflocon.flocondesktop.features.network.list.model.NetworkSta fun toDetailUi(request: FloconNetworkCallDomainModel): NetworkDetailViewState = NetworkDetailViewState( callId = request.callId, - fullUrl = request.networkRequest.url, + fullUrl = request.request.url, method = toDetailMethodUi(request), status = toDetailHttpStatusUi(request), - requestTimeFormatted = request.networkRequest.startTime.let { formatTimestamp(it) }, - durationFormatted = request.networkResponse?.durationMs?.let { formatDuration(it) }, + requestTimeFormatted = request.request.startTime.let { formatTimestamp(it) }, + durationFormatted = request.response?.durationMs?.let { formatDuration(it) }, // request - requestBody = httpBodyToUi(request.networkRequest.body), - requestHeaders = toNetworkHeadersUi(request.networkRequest.headers), - requestSize = ByteFormatter.formatBytes(request.networkRequest.byteSize), + requestBody = httpBodyToUi(request.request.body), + requestHeaders = toNetworkHeadersUi(request.request.headers), + requestSize = ByteFormatter.formatBytes(request.request.byteSize), // response - response = request.networkResponse?.let { - NetworkDetailViewState.Response( - body = httpBodyToUi(it.body), - size = ByteFormatter.formatBytes(it.byteSize), - headers = toNetworkHeadersUi(it.headers), - ) + response = request.response?.let { + when(it) { + is FloconNetworkCallDomainModel.Response.Failure -> NetworkDetailViewState.Response.Error( + issue = it.issue, + ) + is FloconNetworkCallDomainModel.Response.Success -> NetworkDetailViewState.Response.Success( + body = httpBodyToUi(it.body), + size = ByteFormatter.formatBytes(it.byteSize), + headers = toNetworkHeadersUi(it.headers), + ) + + } + }, graphQlSection = graphQlSection(request), ) -private fun toDetailHttpStatusUi(networkCall: FloconNetworkCallDomainModel): NetworkStatusUi = networkCall.networkResponse?.let { response -> - when (networkCall) { - is FloconNetworkCallDomainModel.Grpc -> toGrpcNetworkStatusUi(networkCall) - // here for grphql we want the http code, the graphql status will be displayed on the specific graphql section - is FloconNetworkCallDomainModel.GraphQl -> toNetworkStatusUi(code = networkCall.response!!.httpCode) - is FloconNetworkCallDomainModel.Http -> toNetworkStatusUi(code = networkCall.response!!.httpCode) +private fun toDetailHttpStatusUi(networkCall: FloconNetworkCallDomainModel): NetworkStatusUi = networkCall.response?.let { response -> + when (response) { + is FloconNetworkCallDomainModel.Response.Failure -> NetworkStatusUi( + text = response.issue, + status = NetworkStatusUi.Status.ERROR, + ) + is FloconNetworkCallDomainModel.Response.Success -> when(val s = response.specificInfos) { + is FloconNetworkCallDomainModel.Response.Success.SpecificInfos.Grpc -> toGrpcNetworkStatusUi(networkCall) + // here for grphql we want the http code, the graphql status will be displayed on the specific graphql section + is FloconNetworkCallDomainModel.Response.Success.SpecificInfos.GraphQl -> toNetworkStatusUi(code = s.httpCode) + is FloconNetworkCallDomainModel.Response.Success.SpecificInfos.Http -> toNetworkStatusUi(code = s.httpCode) + } } } ?: loadingStatus() -fun graphQlSection(networkCall: FloconNetworkCallDomainModel): NetworkDetailViewState.GraphQlSection? = (networkCall as? FloconNetworkCallDomainModel.GraphQl)?.let { - NetworkDetailViewState.GraphQlSection( - queryName = it.request.query, - method = getMethodUi(networkCall), - status = it.response?.isSuccess?.let { - toGraphQlNetworkStatusUi(isSuccess = it) - } ?: loadingStatus(), - ) +fun graphQlSection(networkCall: FloconNetworkCallDomainModel): NetworkDetailViewState.GraphQlSection? { + return (networkCall.request.specificInfos as? FloconNetworkCallDomainModel.Request.SpecificInfos.GraphQl)?.let { + NetworkDetailViewState.GraphQlSection( + queryName = it.query, + method = getMethodUi(networkCall), + status = graphQlStatus(networkCall) ?: return null + ) + } +} + +private fun graphQlStatus(networkCall: FloconNetworkCallDomainModel) : NetworkStatusUi? { + return when(val r = networkCall.response) { + is FloconNetworkCallDomainModel.Response.Failure -> NetworkStatusUi( + text = r.issue, + status = NetworkStatusUi.Status.ERROR, + ) + is FloconNetworkCallDomainModel.Response.Success -> when(val s = r.specificInfos) { + is FloconNetworkCallDomainModel.Response.Success.SpecificInfos.GraphQl -> toGraphQlNetworkStatusUi(isSuccess = s.isSuccess) + else -> null + } + null -> loadingStatus() + } } fun httpBodyToUi(body: String?): String = body?.let { JsonPrettyPrinter.prettyPrint(body) } ?: "" @@ -68,12 +96,12 @@ fun toNetworkHeadersUi(headers: Map?): List NetworkDetailViewState.Method.MethodName( - name = request.networkRequest.method, +fun toDetailMethodUi(request: FloconNetworkCallDomainModel): NetworkDetailViewState.Method = when (request.request.specificInfos) { + is FloconNetworkCallDomainModel.Request.SpecificInfos.Grpc -> NetworkDetailViewState.Method.MethodName( + name = request.request.method, ) - is FloconNetworkCallDomainModel.GraphQl, - is FloconNetworkCallDomainModel.Http, - -> NetworkDetailViewState.Method.Http(toHttpMethodUi(request.networkRequest.method)) + is FloconNetworkCallDomainModel.Request.SpecificInfos.GraphQl, + is FloconNetworkCallDomainModel.Request.SpecificInfos.Http, + -> NetworkDetailViewState.Method.Http(toHttpMethodUi(request.request.method)) } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/model/NetworkDetailViewState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/model/NetworkDetailViewState.kt index da5ea2b3..32e56074 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/model/NetworkDetailViewState.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/model/NetworkDetailViewState.kt @@ -24,11 +24,18 @@ data class NetworkDetailViewState( val response: Response?, ) { @Immutable - data class Response( - val body: String, - val size: String, - val headers: List, - ) + sealed interface Response { + @Immutable + data class Success( + val body: String, + val size: String, + val headers: List, + ) : Response + @Immutable + data class Error( + val issue: String, + ) : Response + } @Immutable data class GraphQlSection( diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/view/NetworkDetailView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/view/NetworkDetailView.kt index 35dd3701..4751b806 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/view/NetworkDetailView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/view/NetworkDetailView.kt @@ -122,11 +122,11 @@ private fun Request( Column { Column( modifier = - Modifier - .background( - color = FloconTheme.colorPalette.surfaceVariant, - shape = RoundedCornerShape(12.dp), - ).padding(horizontal = 8.dp, vertical = 4.dp), + Modifier + .background( + color = FloconTheme.colorPalette.surfaceVariant, + shape = RoundedCornerShape(12.dp), + ).padding(horizontal = 8.dp, vertical = 4.dp), ) { DetailLineTextView( modifier = Modifier.fillMaxWidth(), @@ -198,11 +198,11 @@ private fun Request( ) { Column( modifier = - Modifier - .background( - color = FloconTheme.colorPalette.surfaceVariant, - shape = RoundedCornerShape(12.dp), - ).padding(horizontal = 8.dp, vertical = 4.dp), + Modifier + .background( + color = FloconTheme.colorPalette.surfaceVariant, + shape = RoundedCornerShape(12.dp), + ).padding(horizontal = 8.dp, vertical = 4.dp), ) { DetailLineTextView( modifier = Modifier.fillMaxWidth(), @@ -304,53 +304,72 @@ private fun Response( expanded = isResponseExpanded, ) { // headers - Column { - DetailSectionTitleView( - isExpanded = isResponseHeadersExpanded, - title = "Response Headers", - onCopy = null, - onToggle = { - isResponseHeadersExpanded = it - }, - modifier = Modifier.fillMaxWidth(), - ) - FloconSectionExpandable( - modifier = Modifier.fillMaxWidth(), - expanded = isResponseHeadersExpanded, - ) { - DetailHeadersView( - headers = response.headers, - modifier = Modifier.fillMaxWidth(), - labelWidth = headersLabelWidth, - ) - } + Column( + modifier = Modifier + .fillMaxWidth() + ) { + when (response) { + is NetworkDetailViewState.Response.Error -> { + FloconSectionExpandable( + modifier = Modifier.fillMaxWidth(), + expanded = isResponseBodyExpanded, + ) { + CodeBlockView( + code = response.issue, + modifier = Modifier.fillMaxWidth(), + ) + } + } - // body - DetailSectionTitleView( - isExpanded = isResponseBodyExpanded, - title = "Response Body", - onCopy = { onAction(NetworkAction.CopyText(response.body)) }, - onToggle = { - isResponseBodyExpanded = it - }, - onDetail = { - onAction( - NetworkAction.JsonDetail( - state.callId + "response", - response.body, - ), + is NetworkDetailViewState.Response.Success -> { + DetailSectionTitleView( + isExpanded = isResponseHeadersExpanded, + title = "Response Headers", + onCopy = null, + onToggle = { + isResponseHeadersExpanded = it + }, + modifier = Modifier.fillMaxWidth(), ) - }, - modifier = Modifier.fillMaxWidth(), - ) - FloconSectionExpandable( - modifier = Modifier.fillMaxWidth(), - expanded = isResponseBodyExpanded, - ) { - CodeBlockView( - code = response.body, - modifier = Modifier.fillMaxWidth(), - ) + FloconSectionExpandable( + modifier = Modifier.fillMaxWidth(), + expanded = isResponseHeadersExpanded, + ) { + DetailHeadersView( + headers = response.headers, + modifier = Modifier.fillMaxWidth(), + labelWidth = headersLabelWidth, + ) + } + + // body + DetailSectionTitleView( + isExpanded = isResponseBodyExpanded, + title = "Response Body", + onCopy = { onAction(NetworkAction.CopyText(response.body)) }, + onToggle = { + isResponseBodyExpanded = it + }, + onDetail = { + onAction( + NetworkAction.JsonDetail( + state.callId + "response", + response.body, + ), + ) + }, + modifier = Modifier.fillMaxWidth(), + ) + FloconSectionExpandable( + modifier = Modifier.fillMaxWidth(), + expanded = isResponseBodyExpanded, + ) { + CodeBlockView( + code = response.body, + modifier = Modifier.fillMaxWidth(), + ) + } + } } } } @@ -367,18 +386,18 @@ private fun NetworkDetailViewPreview() { fullUrl = "http://www.google.com", method = NetworkDetailViewState.Method.Http(NetworkMethodUi.Http.GET), status = - NetworkStatusUi( - text = "200", - status = NetworkStatusUi.Status.SUCCESS, - ), + NetworkStatusUi( + text = "200", + status = NetworkStatusUi.Status.SUCCESS, + ), requestHeaders = - listOf( - previewNetworkDetailHeaderUi(), - previewNetworkDetailHeaderUi(), - previewNetworkDetailHeaderUi(), - ), + listOf( + previewNetworkDetailHeaderUi(), + previewNetworkDetailHeaderUi(), + previewNetworkDetailHeaderUi(), + ), requestBody = - """ + """ { "id": "123", "name": "Flocon App", @@ -394,9 +413,9 @@ private fun NetworkDetailViewPreview() { requestTimeFormatted = "00:00:00.000", durationFormatted = "300ms", requestSize = "0kb", - response = NetworkDetailViewState.Response( + response = NetworkDetailViewState.Response.Success( body = - """ + """ { "networkStatusUi": "success", "message": "Data received and processed.", @@ -408,13 +427,13 @@ private fun NetworkDetailViewPreview() { """.trimIndent(), size = "0kb", headers = - listOf( - previewNetworkDetailHeaderUi(), - previewNetworkDetailHeaderUi(), - previewNetworkDetailHeaderUi(), - previewNetworkDetailHeaderUi(), - previewNetworkDetailHeaderUi(), - ), + listOf( + previewNetworkDetailHeaderUi(), + previewNetworkDetailHeaderUi(), + previewNetworkDetailHeaderUi(), + previewNetworkDetailHeaderUi(), + previewNetworkDetailHeaderUi(), + ), ), graphQlSection = null, ), diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/NetworkViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/NetworkViewModel.kt index f77c2402..f7ac33ec 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/NetworkViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/NetworkViewModel.kt @@ -245,7 +245,7 @@ class NetworkViewModel( viewModelScope.launch(dispatcherProvider.viewModel) { val domainModel = observeHttpRequestsByIdUseCase(action.item.uuid).firstOrNull() ?: return@launch - copyToClipboard(domainModel.networkRequest.url) + copyToClipboard(domainModel.request.url) } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/mapper/MethodUiMapper.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/mapper/MethodUiMapper.kt index a7de5cd6..dd9f3a48 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/mapper/MethodUiMapper.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/mapper/MethodUiMapper.kt @@ -3,14 +3,14 @@ package io.github.openflocon.flocondesktop.features.network.list.mapper import io.github.openflocon.domain.network.models.FloconNetworkCallDomainModel import io.github.openflocon.flocondesktop.features.network.list.model.NetworkMethodUi -fun getMethodUi(networkRequest: FloconNetworkCallDomainModel): NetworkMethodUi = when (networkRequest) { - is FloconNetworkCallDomainModel.GraphQl -> when (val t = networkRequest.request.operationType.lowercase()) { +fun getMethodUi(networkCall: FloconNetworkCallDomainModel): NetworkMethodUi = when (val s = networkCall.request.specificInfos) { + is FloconNetworkCallDomainModel.Request.SpecificInfos.GraphQl -> when (val t = s.operationType.lowercase()) { "query" -> NetworkMethodUi.GraphQl.QUERY "mutation" -> NetworkMethodUi.GraphQl.MUTATION - else -> NetworkMethodUi.OTHER(networkRequest.request.operationType, icon = null) + else -> NetworkMethodUi.OTHER(s.operationType, icon = null) } - is FloconNetworkCallDomainModel.Http -> toHttpMethodUi(networkRequest.networkRequest.method) - is FloconNetworkCallDomainModel.Grpc -> NetworkMethodUi.Grpc + is FloconNetworkCallDomainModel.Request.SpecificInfos.Http -> toHttpMethodUi(networkCall.request.method) + is FloconNetworkCallDomainModel.Request.SpecificInfos.Grpc -> NetworkMethodUi.Grpc } fun toHttpMethodUi(httpMethod: String): NetworkMethodUi = when (httpMethod.lowercase()) { diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/mapper/NetworkUiMapper.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/mapper/NetworkUiMapper.kt index 0831bf20..74cf3dc6 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/mapper/NetworkUiMapper.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/mapper/NetworkUiMapper.kt @@ -1,6 +1,7 @@ package io.github.openflocon.flocondesktop.features.network.list.mapper import io.github.openflocon.domain.network.models.FloconNetworkCallDomainModel +import io.github.openflocon.domain.network.models.byteSize import io.github.openflocon.flocondesktop.common.ui.ByteFormatter import io.github.openflocon.flocondesktop.features.network.list.model.NetworkItemViewState import io.ktor.http.Url @@ -43,21 +44,21 @@ fun extractPath(url: String): String { fun toUi(networkCall: FloconNetworkCallDomainModel): NetworkItemViewState = NetworkItemViewState( uuid = networkCall.callId, - dateFormatted = formatTimestamp(networkCall.networkRequest.startTime), - timeFormatted = networkCall.networkResponse?.durationMs?.let { formatDuration(it) }, - requestSize = ByteFormatter.formatBytes(networkCall.networkRequest.byteSize), - responseSize = networkCall.networkResponse?.byteSize?.let { ByteFormatter.formatBytes(it) }, + dateFormatted = formatTimestamp(networkCall.request.startTime), + timeFormatted = networkCall.response?.durationMs?.let { formatDuration(it) }, + requestSize = ByteFormatter.formatBytes(networkCall.request.byteSize), + responseSize = networkCall.byteSize()?.let { ByteFormatter.formatBytes(it) }, domain = getDomainUi(networkCall), type = toTypeUi(networkCall), method = getMethodUi(networkCall), status = getStatusUi(networkCall), - isMocked = networkCall.networkRequest.isMocked, + isMocked = networkCall.request.isMocked, ) -fun getDomainUi(networkRequest: FloconNetworkCallDomainModel): String = when (networkRequest) { - is FloconNetworkCallDomainModel.GraphQl -> extractDomainAndPath(networkRequest.networkRequest.url) - is FloconNetworkCallDomainModel.Http -> extractDomain(networkRequest.networkRequest.url) - is FloconNetworkCallDomainModel.Grpc -> networkRequest.networkRequest.url +fun getDomainUi(networkRequest: FloconNetworkCallDomainModel): String = when (networkRequest.request.specificInfos) { + is FloconNetworkCallDomainModel.Request.SpecificInfos.GraphQl -> extractDomainAndPath(networkRequest.request.url) + is FloconNetworkCallDomainModel.Request.SpecificInfos.Http -> extractDomain(networkRequest.request.url) + is FloconNetworkCallDomainModel.Request.SpecificInfos.Grpc -> networkRequest.request.url } fun formatDuration(duration: Double): String = duration.milliseconds.toString(unit = DurationUnit.MILLISECONDS) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/mapper/StatusUiMapper.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/mapper/StatusUiMapper.kt index 27f9a71e..444e4f07 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/mapper/StatusUiMapper.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/mapper/StatusUiMapper.kt @@ -8,11 +8,17 @@ fun loadingStatus() = NetworkStatusUi( status = NetworkStatusUi.Status.LOADING, ) -fun getStatusUi(networkCall: FloconNetworkCallDomainModel): NetworkStatusUi = networkCall.networkResponse?.let { response -> - when (val t = networkCall) { - is FloconNetworkCallDomainModel.GraphQl -> toGraphQlNetworkStatusUi(isSuccess = t.response!!.isSuccess) - is FloconNetworkCallDomainModel.Http -> toNetworkStatusUi(networkCall.response!!.httpCode) - is FloconNetworkCallDomainModel.Grpc -> toGrpcNetworkStatusUi(t) +fun getStatusUi(networkCall: FloconNetworkCallDomainModel): NetworkStatusUi = networkCall.response?.let { response -> + when(response) { + is FloconNetworkCallDomainModel.Response.Failure -> NetworkStatusUi( + text = response.issue, + status = NetworkStatusUi.Status.ERROR, + ) + is FloconNetworkCallDomainModel.Response.Success -> when (val s = response.specificInfos) { + is FloconNetworkCallDomainModel.Response.Success.SpecificInfos.GraphQl -> toGraphQlNetworkStatusUi(isSuccess = s.isSuccess) + is FloconNetworkCallDomainModel.Response.Success.SpecificInfos.Http -> toNetworkStatusUi(s.httpCode) + is FloconNetworkCallDomainModel.Response.Success.SpecificInfos.Grpc -> toGrpcNetworkStatusUi(networkCall) + } } } ?: loadingStatus() @@ -26,11 +32,27 @@ fun toGraphQlNetworkStatusUi(isSuccess: Boolean): NetworkStatusUi = NetworkStatu status = if (isSuccess) NetworkStatusUi.Status.SUCCESS else NetworkStatusUi.Status.ERROR, ) -fun toGrpcNetworkStatusUi(call: FloconNetworkCallDomainModel.Grpc): NetworkStatusUi { +fun toGrpcNetworkStatusUi(call: FloconNetworkCallDomainModel): NetworkStatusUi { val response = call.response ?: return loadingStatus() - val isSuccess = response.responseStatus == "OK" - return NetworkStatusUi( - text = response.responseStatus, - status = if (isSuccess) NetworkStatusUi.Status.SUCCESS else NetworkStatusUi.Status.ERROR, - ) + return when(response) { + is FloconNetworkCallDomainModel.Response.Failure -> NetworkStatusUi( + text = response.issue, + status = NetworkStatusUi.Status.ERROR, + ) + is FloconNetworkCallDomainModel.Response.Success -> { + when(val s = response.specificInfos) { + is FloconNetworkCallDomainModel.Response.Success.SpecificInfos.Grpc -> { + val isSuccess = s.grpcStatus == "OK" + NetworkStatusUi( + text = s.grpcStatus, + status = if (isSuccess) NetworkStatusUi.Status.SUCCESS else NetworkStatusUi.Status.ERROR, + ) + } + else -> NetworkStatusUi( + text = "not a grpc response", + status = NetworkStatusUi.Status.ERROR, + ) + } + } + } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/mapper/TypeUiMapper.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/mapper/TypeUiMapper.kt index 978a4561..0fb3a5db 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/mapper/TypeUiMapper.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/mapper/TypeUiMapper.kt @@ -3,22 +3,22 @@ package io.github.openflocon.flocondesktop.features.network.list.mapper import io.github.openflocon.domain.network.models.FloconNetworkCallDomainModel import io.github.openflocon.flocondesktop.features.network.list.model.NetworkItemViewState -fun toTypeUi(call: FloconNetworkCallDomainModel): NetworkItemViewState.NetworkTypeUi = when (call) { - is FloconNetworkCallDomainModel.GraphQl -> NetworkItemViewState.NetworkTypeUi.GraphQl( - queryName = call.request.query, +fun toTypeUi(call: FloconNetworkCallDomainModel): NetworkItemViewState.NetworkTypeUi = when (val s = call.request.specificInfos) { + is FloconNetworkCallDomainModel.Request.SpecificInfos.GraphQl -> NetworkItemViewState.NetworkTypeUi.GraphQl( + queryName = s.query, ) - is FloconNetworkCallDomainModel.Http -> { - val query = extractPath(call.networkRequest.url) + is FloconNetworkCallDomainModel.Request.SpecificInfos.Http -> { + val query = extractPath(call.request.url) NetworkItemViewState.NetworkTypeUi.Url( query = query, - method = call.networkRequest.method, + method = call.request.method, ) } - is FloconNetworkCallDomainModel.Grpc -> { + is FloconNetworkCallDomainModel.Request.SpecificInfos.Grpc -> { NetworkItemViewState.NetworkTypeUi.Grpc( - method = call.networkRequest.method, + method = call.request.method, ) } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/processor/SortAndFilterNetworkItemsProcessor.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/processor/SortAndFilterNetworkItemsProcessor.kt index 548f7a65..a5aabc6c 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/processor/SortAndFilterNetworkItemsProcessor.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/processor/SortAndFilterNetworkItemsProcessor.kt @@ -45,12 +45,12 @@ private fun sort( } val comparator = when (sorted.column) { - NetworkColumnsTypeUiModel.RequestTime -> compareBy> { it.first.networkRequest.startTime } + NetworkColumnsTypeUiModel.RequestTime -> compareBy> { it.first.request.startTime } NetworkColumnsTypeUiModel.Method -> compareBy { it.second.method.text } NetworkColumnsTypeUiModel.Domain -> compareBy { it.second.domain } NetworkColumnsTypeUiModel.Query -> compareBy { it.second.type.text } NetworkColumnsTypeUiModel.Status -> compareBy { it.second.status.text } - NetworkColumnsTypeUiModel.Time -> compareBy { it.first.networkResponse?.durationMs } + NetworkColumnsTypeUiModel.Time -> compareBy { it.first.response?.durationMs } } val sortedComparator = when (sorted.sort) { diff --git a/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/images/repository/ImagesRepositoryImpl.kt b/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/images/repository/ImagesRepositoryImpl.kt index 3d776464..7aba1f46 100644 --- a/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/images/repository/ImagesRepositoryImpl.kt +++ b/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/images/repository/ImagesRepositoryImpl.kt @@ -38,12 +38,12 @@ class ImagesRepositoryImpl( deviceId: String, call: FloconNetworkCallDomainModel, ) { - val duration = call.networkResponse?.durationMs ?: return + val duration = call.response?.durationMs ?: return imagesLocalDataSource.addImage( deviceId = deviceId, image = DeviceImageDomainModel( - url = call.networkRequest.url, - time = (call.networkRequest.startTime + duration).toLong(), + url = call.request.url, + time = (call.request.startTime + duration).toLong(), ), ) } diff --git a/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/datasource/NetworkRemoteDataSource.kt b/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/datasource/NetworkRemoteDataSource.kt index 9ff74e23..1c4683bd 100644 --- a/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/datasource/NetworkRemoteDataSource.kt +++ b/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/datasource/NetworkRemoteDataSource.kt @@ -5,7 +5,6 @@ import io.github.openflocon.domain.messages.models.FloconIncomingMessageDomainMo import io.github.openflocon.domain.network.models.BadQualityConfigDomainModel 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 diff --git a/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/repository/NetworkRepositoryImpl.kt b/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/repository/NetworkRepositoryImpl.kt index a9292b79..90ef3274 100644 --- a/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/repository/NetworkRepositoryImpl.kt +++ b/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/repository/NetworkRepositoryImpl.kt @@ -14,6 +14,7 @@ import io.github.openflocon.domain.network.models.BadQualityConfigId import io.github.openflocon.domain.network.models.FloconNetworkCallDomainModel import io.github.openflocon.domain.network.models.FloconNetworkResponseOnlyDomainModel import io.github.openflocon.domain.network.models.MockNetworkDomainModel +import io.github.openflocon.domain.network.models.getContentType import io.github.openflocon.domain.network.repository.NetworkBadQualityRepository import io.github.openflocon.domain.network.repository.NetworkImageRepository import io.github.openflocon.domain.network.repository.NetworkMocksRepository @@ -100,7 +101,7 @@ class NetworkRepositoryImpl( } toDomainForResponse(response = response, request = request) }?.let { call -> - if (call.networkResponse?.contentType?.startsWith("image/") == true) { + if (call.response?.getContentType()?.startsWith("image/") == true) { networkImageRepository.onImageReceived(deviceId = deviceId, call = call) } networkLocalDataSource.save( @@ -159,48 +160,31 @@ class NetworkRepositoryImpl( response: FloconNetworkResponseOnlyDomainModel, request: FloconNetworkCallDomainModel, ): FloconNetworkCallDomainModel? { - try { - val networkResponse = response.networkResponse - - return when (request) { - is FloconNetworkCallDomainModel.GraphQl -> { - // throw an exception if not http - val responseHttp = response as FloconNetworkResponseOnlyDomainModel.Http - val response = FloconNetworkCallDomainModel.GraphQl.Response( - networkResponse = networkResponse, - httpCode = responseHttp.httpCode, - isSuccess = responseHttp.httpCode in 200..299, - ) - request.copy( - response = response, - ) + return try { + val response = when (val r = response.response) { + is FloconNetworkCallDomainModel.Response.Success -> { + // specific case : map to graphQl if needed + when (val s = r.specificInfos) { + is FloconNetworkCallDomainModel.Response.Success.SpecificInfos.Http -> { + r.copy( + specificInfos = FloconNetworkCallDomainModel.Response.Success.SpecificInfos.GraphQl( + httpCode = s.httpCode, + isSuccess = s.httpCode in 200..299 + ) + ) + } + else -> r + } } - is FloconNetworkCallDomainModel.Grpc -> { - val responseHttp = response as FloconNetworkResponseOnlyDomainModel.Grpc - val response = FloconNetworkCallDomainModel.Grpc.Response( - networkResponse = networkResponse, - responseStatus = responseHttp.grpcStatus, - ) - request.copy( - response = response, - ) - } - - is FloconNetworkCallDomainModel.Http -> { - val responseHttp = response as FloconNetworkResponseOnlyDomainModel.Http - val response = FloconNetworkCallDomainModel.Http.Response( - networkResponse = networkResponse, - httpCode = responseHttp.httpCode, - ) - request.copy( - response = response, - ) - } + is FloconNetworkCallDomainModel.Response.Failure -> response.response } + request.copy( + response = response, + ) } catch (t: Throwable) { t.printStackTrace() - return null + null } } diff --git a/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/mapper/MapperLite.kt b/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/mapper/MapperLite.kt index 791ff3cb..8fd06728 100644 --- a/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/mapper/MapperLite.kt +++ b/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/mapper/MapperLite.kt @@ -2,81 +2,68 @@ package io.github.openflocon.data.local.network.mapper import io.github.openflocon.data.local.network.models.FloconNetwockCallEntityLite import io.github.openflocon.data.local.network.models.FloconNetworkCallType -import io.github.openflocon.data.local.network.models.FloconNetworkRequestLiteEmbedded import io.github.openflocon.data.local.network.models.FloconNetworkResponseLiteEmbedded import io.github.openflocon.domain.network.models.FloconNetworkCallDomainModel -import io.github.openflocon.domain.network.models.FloconNetworkRequestDomainModel -import io.github.openflocon.domain.network.models.FloconNetworkResponseDomainModel -import kotlin.Boolean - -fun toDomainModel(request: FloconNetworkRequestLiteEmbedded): FloconNetworkRequestDomainModel { - return with(request) { - FloconNetworkRequestDomainModel( - url = this.url, - method = this.method, - startTime = this.startTime, - headers = this.requestHeaders, - body = null, // null on lite - byteSize = this.requestByteSize, - isMocked = this.isMocked, - ) - } -} fun FloconNetwockCallEntityLite.toDomainModel(): FloconNetworkCallDomainModel? { return try { - val networkRequest = toDomainModel(request) - when (type) { - FloconNetworkCallType.HTTP -> FloconNetworkCallDomainModel.Http( - callId = callId, - networkRequest = networkRequest, - response = response?.let { - FloconNetworkCallDomainModel.Http.Response( - httpCode = response.http!!.responseHttpCode, - networkResponse = toDomainModel(response), - ) - } - ) - - FloconNetworkCallType.GRAPHQL -> FloconNetworkCallDomainModel.GraphQl( - callId = callId, - request = FloconNetworkCallDomainModel.GraphQl.Request( - networkRequest = networkRequest, - query = request.graphql!!.query, - operationType = request.graphql.operationType, - ), - response = response?.let { - FloconNetworkCallDomainModel.GraphQl.Response( - httpCode = response.graphql!!.responseHttpCode, - isSuccess = response.graphql.isSuccess, - networkResponse = toDomainModel(response), - ) - } - ) - - FloconNetworkCallType.GRPC -> FloconNetworkCallDomainModel.Grpc( - callId = callId, - networkRequest = networkRequest, - response = response?.let { - FloconNetworkCallDomainModel.Grpc.Response( - networkResponse = toDomainModel(response), - responseStatus = response.grpc!!.responseStatus, - ) - } - ) - } + FloconNetworkCallDomainModel( + callId = callId, + request = toRequestDomainModel(), + response = response?.toDomainModel(), + ) } catch (t: Throwable) { t.printStackTrace() return null } } -private fun toDomainModel(response: FloconNetworkResponseLiteEmbedded): FloconNetworkResponseDomainModel = with(response) { - FloconNetworkResponseDomainModel( - contentType = responseContentType, +private fun FloconNetwockCallEntityLite.toRequestDomainModel(): FloconNetworkCallDomainModel.Request = + FloconNetworkCallDomainModel.Request( + url = request.url, + method = request.method, + startTime = request.startTime, + headers = request.requestHeaders, body = null, // null on lite - headers = responseHeaders, - byteSize = responseByteSize, - durationMs = durationMs, + byteSize = request.requestByteSize, + isMocked = request.isMocked, + specificInfos = when (type) { + FloconNetworkCallType.HTTP -> FloconNetworkCallDomainModel.Request.SpecificInfos.Http + FloconNetworkCallType.GRAPHQL -> FloconNetworkCallDomainModel.Request.SpecificInfos.GraphQl( + query = request.graphql!!.query, + operationType = request.graphql.operationType, + ) + + FloconNetworkCallType.GRPC -> FloconNetworkCallDomainModel.Request.SpecificInfos.Grpc + }, ) + +private fun FloconNetworkResponseLiteEmbedded.toDomainModel(): FloconNetworkCallDomainModel.Response? { + return if(responseError != null) { + FloconNetworkCallDomainModel.Response.Failure( + durationMs = durationMs, + responseError + ) + } else { + FloconNetworkCallDomainModel.Response.Success( + contentType = responseContentType, + body = null, // null on lite + headers = responseHeaders, + byteSize = responseByteSize, + durationMs = durationMs, + specificInfos = when { + graphql != null -> FloconNetworkCallDomainModel.Response.Success.SpecificInfos.GraphQl( + httpCode = graphql.responseHttpCode, + isSuccess = graphql.isSuccess, + ) + grpc != null -> FloconNetworkCallDomainModel.Response.Success.SpecificInfos.Grpc( + grpcStatus = grpc.responseStatus, + ) + http != null -> FloconNetworkCallDomainModel.Response.Success.SpecificInfos.Http( + httpCode = http.responseHttpCode, + ) + else -> return null + } + ) + } } diff --git a/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/mapper/MapperToDomain.kt b/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/mapper/MapperToDomain.kt index 49e9ff0c..9bcdb49e 100644 --- a/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/mapper/MapperToDomain.kt +++ b/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/mapper/MapperToDomain.kt @@ -2,82 +2,70 @@ package io.github.openflocon.data.local.network.mapper import io.github.openflocon.data.local.network.models.FloconNetworkCallEntity import io.github.openflocon.data.local.network.models.FloconNetworkCallType -import io.github.openflocon.data.local.network.models.FloconNetworkRequestEmbedded import io.github.openflocon.data.local.network.models.FloconNetworkResponseEmbedded import io.github.openflocon.domain.network.models.FloconNetworkCallDomainModel -import io.github.openflocon.domain.network.models.FloconNetworkRequestDomainModel -import io.github.openflocon.domain.network.models.FloconNetworkResponseDomainModel - -private fun toDomainModel(request: FloconNetworkRequestEmbedded): FloconNetworkRequestDomainModel { - return with(request) { - FloconNetworkRequestDomainModel( - url = this.url, - method = this.method, - startTime = this.startTime, - headers = this.requestHeaders, - body = this.requestBody, - byteSize = this.requestByteSize, - isMocked = this.isMocked, - ) - } -} fun FloconNetworkCallEntity.toDomainModel(): FloconNetworkCallDomainModel? { return try { - val networkRequest = toDomainModel(request) - when (type) { - FloconNetworkCallType.HTTP -> FloconNetworkCallDomainModel.Http( - callId = callId, - networkRequest = networkRequest, - response = response?.let { - FloconNetworkCallDomainModel.Http.Response( - httpCode = response.http!!.responseHttpCode, - networkResponse = toDomainModel(response), - ) - } - ) - - FloconNetworkCallType.GRAPHQL -> FloconNetworkCallDomainModel.GraphQl( - callId = callId, - request = FloconNetworkCallDomainModel.GraphQl.Request( - networkRequest = networkRequest, - query = request.graphql!!.query, - operationType = request.graphql.operationType, - ), - response = response?.let { - FloconNetworkCallDomainModel.GraphQl.Response( - httpCode = response.graphql!!.responseHttpCode, - isSuccess = response.graphql.isSuccess, - networkResponse = toDomainModel(response), - ) - } - ) - - FloconNetworkCallType.GRPC -> FloconNetworkCallDomainModel.Grpc( - callId = callId, - networkRequest = networkRequest, - response = response?.let { - FloconNetworkCallDomainModel.Grpc.Response( - networkResponse = toDomainModel(response), - responseStatus = response.grpc!!.responseStatus, - ) - } - ) - } + FloconNetworkCallDomainModel( + callId = callId, + request = toRequestDomainModel(), + response = response?.toDomainModel(), + ) } catch (t: Throwable) { t.printStackTrace() return null } } -private fun toDomainModel(response: FloconNetworkResponseEmbedded): FloconNetworkResponseDomainModel = - with(response) { - FloconNetworkResponseDomainModel( +private fun FloconNetworkCallEntity.toRequestDomainModel(): FloconNetworkCallDomainModel.Request = + FloconNetworkCallDomainModel.Request( + url = request.url, + method = request.method, + startTime = request.startTime, + headers = request.requestHeaders, + body = request.requestBody, + byteSize = request.requestByteSize, + isMocked = request.isMocked, + specificInfos = when (type) { + FloconNetworkCallType.HTTP -> FloconNetworkCallDomainModel.Request.SpecificInfos.Http + FloconNetworkCallType.GRAPHQL -> FloconNetworkCallDomainModel.Request.SpecificInfos.GraphQl( + query = request.graphql!!.query, + operationType = request.graphql.operationType, + ) + + FloconNetworkCallType.GRPC -> FloconNetworkCallDomainModel.Request.SpecificInfos.Grpc + }, + ) + + +private fun FloconNetworkResponseEmbedded.toDomainModel(): FloconNetworkCallDomainModel.Response? { + return if(responseError != null) { + FloconNetworkCallDomainModel.Response.Failure( + durationMs = durationMs, + issue = responseError + ) + } else { + FloconNetworkCallDomainModel.Response.Success( contentType = responseContentType, body = responseBody, headers = responseHeaders, byteSize = responseByteSize, durationMs = durationMs, + specificInfos = when { + graphql != null -> FloconNetworkCallDomainModel.Response.Success.SpecificInfos.GraphQl( + httpCode = graphql.responseHttpCode, + isSuccess = graphql.isSuccess, + ) + grpc != null -> FloconNetworkCallDomainModel.Response.Success.SpecificInfos.Grpc( + grpcStatus = grpc.responseStatus, + ) + http != null -> FloconNetworkCallDomainModel.Response.Success.SpecificInfos.Http( + httpCode = http.responseHttpCode, + ) + else -> return null + } ) } +} diff --git a/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/mapper/MapperToEntity.kt b/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/mapper/MapperToEntity.kt index ae18a420..ad939e3a 100644 --- a/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/mapper/MapperToEntity.kt +++ b/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/mapper/MapperToEntity.kt @@ -19,61 +19,75 @@ fun FloconNetworkCallDomainModel.toEntity( callId = callId, deviceId = deviceId, packageName = packageName, - type = when (this) { - is FloconNetworkCallDomainModel.Http -> FloconNetworkCallType.HTTP - is FloconNetworkCallDomainModel.GraphQl -> FloconNetworkCallType.GRAPHQL - is FloconNetworkCallDomainModel.Grpc -> FloconNetworkCallType.GRPC + type = when (this.request.specificInfos) { + is FloconNetworkCallDomainModel.Request.SpecificInfos.Http -> FloconNetworkCallType.HTTP + is FloconNetworkCallDomainModel.Request.SpecificInfos.GraphQl -> FloconNetworkCallType.GRAPHQL + is FloconNetworkCallDomainModel.Request.SpecificInfos.Grpc -> FloconNetworkCallType.GRPC }, request = FloconNetworkRequestEmbedded( - url = networkRequest.url, - method = networkRequest.method, - startTime = networkRequest.startTime, - requestHeaders = networkRequest.headers, - requestBody = networkRequest.body, - requestByteSize = networkRequest.byteSize, - isMocked = networkRequest.isMocked, - graphql = when (this) { - is FloconNetworkCallDomainModel.GraphQl -> NetworkCallGraphQlRequestEmbedded( - query = this.request.query, - operationType = this.request.operationType, + url = request.url, + method = request.method, + startTime = request.startTime, + requestHeaders = request.headers, + requestBody = request.body, + requestByteSize = request.byteSize, + isMocked = request.isMocked, + graphql = when (val s = this.request.specificInfos) { + is FloconNetworkCallDomainModel.Request.SpecificInfos.GraphQl -> NetworkCallGraphQlRequestEmbedded( + query = s.query, + operationType = s.operationType, ) else -> null } ), - response = networkResponse?.let { networkResponse -> - FloconNetworkResponseEmbedded( - durationMs = networkResponse.durationMs, - responseContentType = networkResponse.contentType, - responseBody = networkResponse.body, - responseHeaders = networkResponse.headers, - responseByteSize = networkResponse.byteSize, - graphql = when (this) { - is FloconNetworkCallDomainModel.GraphQl -> NetworkCallGraphQlResponseEmbedded( - responseHttpCode = (this.response as FloconNetworkCallDomainModel.GraphQl.Response).httpCode, - isSuccess = (this.response as FloconNetworkCallDomainModel.GraphQl.Response).isSuccess, + response = response?.let { networkResponse -> + when(networkResponse) { + is FloconNetworkCallDomainModel.Response.Failure -> { + FloconNetworkResponseEmbedded( + durationMs = networkResponse.durationMs, + responseError = networkResponse.issue, + graphql = null, + http = null, + grpc = null, + responseContentType = null, + responseBody = null, + responseHeaders = emptyMap(), + responseByteSize = 0, ) - - is FloconNetworkCallDomainModel.Grpc, - is FloconNetworkCallDomainModel.Http -> null - }, - http = when (this) { - is FloconNetworkCallDomainModel.Http -> NetworkCallHttpResponseEmbedded( - responseHttpCode = (this.response as FloconNetworkCallDomainModel.Http.Response).httpCode, - ) - - is FloconNetworkCallDomainModel.Grpc, - is FloconNetworkCallDomainModel.GraphQl -> null - }, - grpc = when (this) { - is FloconNetworkCallDomainModel.Grpc -> NetworkCallGrpcResponseEmbedded( - responseStatus = (this.response as FloconNetworkCallDomainModel.Grpc.Response).responseStatus, - ) - - is FloconNetworkCallDomainModel.Http, - is FloconNetworkCallDomainModel.GraphQl -> null } - ) + is FloconNetworkCallDomainModel.Response.Success -> { + FloconNetworkResponseEmbedded( + durationMs = networkResponse.durationMs, + responseContentType = networkResponse.contentType, + responseBody = networkResponse.body, + responseHeaders = networkResponse.headers, + responseByteSize = networkResponse.byteSize, + responseError = null, + graphql = when (val s = networkResponse.specificInfos) { + is FloconNetworkCallDomainModel.Response.Success.SpecificInfos.GraphQl -> NetworkCallGraphQlResponseEmbedded( + responseHttpCode = s.httpCode, + isSuccess = s.isSuccess, + ) + + else -> null + }, + http = when (val s = networkResponse.specificInfos) { + is FloconNetworkCallDomainModel.Response.Success.SpecificInfos.Http -> NetworkCallHttpResponseEmbedded( + responseHttpCode = s.httpCode, + ) + + else -> null + }, + grpc = when (val s = networkResponse.specificInfos) { + is FloconNetworkCallDomainModel.Response.Success.SpecificInfos.Grpc -> NetworkCallGrpcResponseEmbedded( + responseStatus = s.grpcStatus, + ) + else -> null + } + ) + } + } } ) } diff --git a/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/models/FloconNetwockCallEntityLite.kt b/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/models/FloconNetwockCallEntityLite.kt index 95bda77f..51da9cd7 100644 --- a/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/models/FloconNetwockCallEntityLite.kt +++ b/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/models/FloconNetwockCallEntityLite.kt @@ -36,6 +36,7 @@ data class FloconNetworkRequestLiteEmbedded( data class FloconNetworkResponseLiteEmbedded( val durationMs: Double, + val responseError: String?, val responseContentType: String?, //val responseBody: String?, val responseHeaders: Map, diff --git a/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/models/FloconNetworkCallEntity.kt b/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/models/FloconNetworkCallEntity.kt index 9fc9f6a6..54f15c98 100644 --- a/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/models/FloconNetworkCallEntity.kt +++ b/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/models/FloconNetworkCallEntity.kt @@ -54,6 +54,7 @@ data class FloconNetworkResponseEmbedded( val responseBody: String?, val responseHeaders: Map, val responseByteSize: Long, + val responseError: String?, @Embedded(prefix = "graphql_") val graphql: NetworkCallGraphQlResponseEmbedded?, diff --git a/FloconDesktop/data/remote/src/commonMain/kotlin/com/flocon/data/remote/common/JsonExt.kt b/FloconDesktop/data/remote/src/commonMain/kotlin/com/flocon/data/remote/common/JsonExt.kt index d11b90db..b86d30c0 100644 --- a/FloconDesktop/data/remote/src/commonMain/kotlin/com/flocon/data/remote/common/JsonExt.kt +++ b/FloconDesktop/data/remote/src/commonMain/kotlin/com/flocon/data/remote/common/JsonExt.kt @@ -4,6 +4,7 @@ import kotlinx.serialization.json.Json internal inline fun Json.safeDecodeFromString(data: String): T? = try { decodeFromString(data) -} catch (e: Throwable) { +} catch (t: Throwable) { + t.printStackTrace() null } diff --git a/FloconDesktop/data/remote/src/commonMain/kotlin/com/flocon/data/remote/network/mapper/Mapper.kt b/FloconDesktop/data/remote/src/commonMain/kotlin/com/flocon/data/remote/network/mapper/Mapper.kt index f93ae790..6909164b 100644 --- a/FloconDesktop/data/remote/src/commonMain/kotlin/com/flocon/data/remote/network/mapper/Mapper.kt +++ b/FloconDesktop/data/remote/src/commonMain/kotlin/com/flocon/data/remote/network/mapper/Mapper.kt @@ -8,7 +8,6 @@ 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.BadQualityConfigDomainModel 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 @@ -34,7 +33,8 @@ fun toDomain(decoded: FloconNetworkRequestDataModel): FloconNetworkCallDomainMod val graphQl = extractGraphQl(decoded) val callId = decoded.floconCallId!! - val networkRequest = FloconNetworkRequestDomainModel( + + val request = FloconNetworkCallDomainModel.Request( url = decoded.url!!, startTime = decoded.startTime!!, method = decoded.method!!, @@ -42,33 +42,21 @@ fun toDomain(decoded: FloconNetworkRequestDataModel): FloconNetworkCallDomainMod body = decoded.requestBody, byteSize = decoded.requestSize ?: 0L, isMocked = decoded.isMocked ?: false, + specificInfos = when { + graphQl != null -> FloconNetworkCallDomainModel.Request.SpecificInfos.GraphQl( + query = graphQl.request.requestBody.query, + operationType = graphQl.request.operationType, + ) + decoded.floconNetworkType == "grpc" -> FloconNetworkCallDomainModel.Request.SpecificInfos.Grpc + else -> FloconNetworkCallDomainModel.Request.SpecificInfos.Http + } ) - 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, - ) - } - } + FloconNetworkCallDomainModel( + callId = callId, + request = request, + response = null, // for now it's null + ) } catch (t: Throwable) { t.printStackTrace() null diff --git a/FloconDesktop/data/remote/src/commonMain/kotlin/com/flocon/data/remote/network/models/FloconNetworkRequestDataModel.kt b/FloconDesktop/data/remote/src/commonMain/kotlin/com/flocon/data/remote/network/models/FloconNetworkRequestDataModel.kt index 39938a67..7aecb367 100644 --- a/FloconDesktop/data/remote/src/commonMain/kotlin/com/flocon/data/remote/network/models/FloconNetworkRequestDataModel.kt +++ b/FloconDesktop/data/remote/src/commonMain/kotlin/com/flocon/data/remote/network/models/FloconNetworkRequestDataModel.kt @@ -1,7 +1,7 @@ package com.flocon.data.remote.network.models +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 kotlinx.serialization.Serializable @@ -37,31 +37,41 @@ data class FloconNetworkResponseDataModel( val responseHeaders: Map? = null, val responseSize: Long? = null, val responseGrpcStatus: String? = null, + val responseError: 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!!, + val durationMs = durationMs ?: 0.0 + + val response = if (responseError != null) { + FloconNetworkCallDomainModel.Response.Failure( + durationMs = durationMs, + issue = responseError, ) - // otherwise tread like http - else -> FloconNetworkResponseOnlyDomainModel.Http( - floconCallId = callId, - networkResponse = networkResponse, - httpCode = responseHttpCode!!, + } else { + FloconNetworkCallDomainModel.Response.Success( + durationMs = durationMs, + contentType = responseContentType, + body = responseBody, + headers = responseHeaders.orEmpty(), + byteSize = responseSize ?: 0L, + specificInfos = when (floconNetworkType) { + "grpc" -> FloconNetworkCallDomainModel.Response.Success.SpecificInfos.Grpc( + grpcStatus = responseGrpcStatus!!, + ) + // otherwise tread like http + else -> FloconNetworkCallDomainModel.Response.Success.SpecificInfos.Http( + httpCode = responseHttpCode!!, + ) + } ) } + FloconNetworkResponseOnlyDomainModel( + floconCallId = callId, + response = response, + ) } catch (t: Throwable) { t.printStackTrace() return null diff --git a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/models/FloconNetworkCallDomainModel.kt b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/models/FloconNetworkCallDomainModel.kt index 191f03d3..270dbff9 100644 --- a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/models/FloconNetworkCallDomainModel.kt +++ b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/models/FloconNetworkCallDomainModel.kt @@ -1,65 +1,89 @@ package io.github.openflocon.domain.network.models -sealed interface FloconNetworkCallDomainModel { - val callId: String - val networkRequest: FloconNetworkRequestDomainModel - val networkResponse: FloconNetworkResponseDomainModel? +data class FloconNetworkCallDomainModel( + val callId: String, + val request: Request, + val response: Response?, +) { - data class Http( - override val callId: String, - override val networkRequest: FloconNetworkRequestDomainModel, - val response: Response?, - ) : FloconNetworkCallDomainModel { - data class Response( - val networkResponse: FloconNetworkResponseDomainModel, - val httpCode: Int, // ex: 200 - ) - - override val networkResponse = response?.networkResponse + data class Request( + val url: String, + val startTime: Long, + val method: String, + val headers: Map, + val body: String?, + val byteSize: Long, + val isMocked: Boolean, + val specificInfos: SpecificInfos, + ) { + sealed interface SpecificInfos { + data object Http: SpecificInfos + data class GraphQl( + val query: String, + val operationType: String, + ) : SpecificInfos + data object Grpc : SpecificInfos + } } - data class GraphQl( - override val callId: String, - val request: Request, - val response: Response?, - ) : FloconNetworkCallDomainModel { + sealed interface Response { - data class Request( - val networkRequest: FloconNetworkRequestDomainModel, - val query: String, - val operationType: String, - ) + val durationMs: Double - data class Response( - val httpCode: Int, // ex: 200 - val isSuccess: Boolean, - val networkResponse: FloconNetworkResponseDomainModel, - ) - - override val networkRequest = request.networkRequest - override val networkResponse = response?.networkResponse - } - - data class Grpc( - override val callId: String, - override val networkRequest: FloconNetworkRequestDomainModel, - val response: Response?, - ) : FloconNetworkCallDomainModel { - data class Response( - val networkResponse: FloconNetworkResponseDomainModel, - val responseStatus: String, - ) - - override val networkResponse = response?.networkResponse + data class Success( + override val durationMs: Double, + val contentType: String? = null, + val body: String? = null, + val headers: Map, + val byteSize: Long, + val specificInfos: SpecificInfos, + ) : Response { + sealed interface SpecificInfos { + data class Http( + val httpCode: Int, // ex: 200 + ) : SpecificInfos + data class GraphQl( + val httpCode: Int, // ex: 200 + val isSuccess: Boolean, + ) : SpecificInfos + data class Grpc( + val grpcStatus: String, + ) : SpecificInfos + } + } + data class Failure( + override val durationMs: Double, + val issue: String, + ) : Response } +} +fun FloconNetworkCallDomainModel.Response.Success.SpecificInfos.httpCode() : Int? = when(this) { + is FloconNetworkCallDomainModel.Response.Success.SpecificInfos.GraphQl -> httpCode + is FloconNetworkCallDomainModel.Response.Success.SpecificInfos.Http -> httpCode + is FloconNetworkCallDomainModel.Response.Success.SpecificInfos.Grpc -> null } fun FloconNetworkCallDomainModel.httpCode(): Int? { - return when (this) { - is FloconNetworkCallDomainModel.Http -> this.response?.httpCode - is FloconNetworkCallDomainModel.GraphQl -> this.response?.httpCode - else -> null + return when(this.response) { + is FloconNetworkCallDomainModel.Response.Failure -> null + is FloconNetworkCallDomainModel.Response.Success -> this.response.specificInfos.httpCode() + null -> null + } +} + +fun FloconNetworkCallDomainModel.byteSize(): Long? { + return when(this.response) { + is FloconNetworkCallDomainModel.Response.Failure -> null + is FloconNetworkCallDomainModel.Response.Success -> this.response.byteSize + null -> null + } +} + +fun FloconNetworkCallDomainModel.Response.getContentType(): String? { + return when(this) { + is FloconNetworkCallDomainModel.Response.Failure -> null + is FloconNetworkCallDomainModel.Response.Success -> this.contentType } } @@ -67,6 +91,7 @@ data class FloconNetworkCallIdDomainModel( val floconCallId: String, ) +/* data class FloconNetworkRequestDomainModel( val url: String, val startTime: Long, @@ -76,28 +101,9 @@ data class FloconNetworkRequestDomainModel( val byteSize: Long, val isMocked: Boolean, ) + */ -sealed interface FloconNetworkResponseOnlyDomainModel { - val floconCallId: String - val networkResponse: FloconNetworkResponseDomainModel - - data class Http( - override val floconCallId: String, - override val networkResponse: FloconNetworkResponseDomainModel, - val httpCode: Int, // ex: 200 - ) : FloconNetworkResponseOnlyDomainModel - - data class Grpc( - override val floconCallId: String, - override val networkResponse: FloconNetworkResponseDomainModel, - val grpcStatus: String, - ) : FloconNetworkResponseOnlyDomainModel -} - -data class FloconNetworkResponseDomainModel( - val contentType: String? = null, - val body: String? = null, - val headers: Map, - val byteSize: Long, - val durationMs: Double +data class FloconNetworkResponseOnlyDomainModel( + val floconCallId: String, + val response: FloconNetworkCallDomainModel.Response, ) diff --git a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/GenerateCurlCommandUseCase.kt b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/GenerateCurlCommandUseCase.kt index cac8b803..be93ad7b 100644 --- a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/GenerateCurlCommandUseCase.kt +++ b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/GenerateCurlCommandUseCase.kt @@ -4,21 +4,21 @@ import io.github.openflocon.domain.network.models.FloconNetworkCallDomainModel class GenerateCurlCommandUseCase { operator fun invoke(infos: FloconNetworkCallDomainModel): String { - val url = infos.networkRequest.url + val url = infos.request.url val commandBuilder = StringBuilder("curl") // 1. Add HTTP Method - commandBuilder.append(" -X ${infos.networkRequest.method}") + commandBuilder.append(" -X ${infos.request.method}") // 2. Add Request Headers - infos.networkRequest.headers.forEach { (key, value) -> + infos.request.headers.forEach { (key, value) -> // Escape double quotes within header values if they exist val escapedValue = value.replace("\"", "\\\"") commandBuilder.append(" -H \"$key: $escapedValue\"") } // 3. Add Request Body (if present) - infos.networkRequest.body?.let { body -> + infos.request.body?.let { body -> if (body.isNotEmpty()) { // Escape single quotes within the body for shell compatibility // ' -> '\'' (closes current single quote, adds escaped single quote, reopens single quote) diff --git a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/mocks/GenerateNetworkMockFromNetworkCallUseCase.kt b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/mocks/GenerateNetworkMockFromNetworkCallUseCase.kt index 0fcfb959..65b92758 100644 --- a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/mocks/GenerateNetworkMockFromNetworkCallUseCase.kt +++ b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/mocks/GenerateNetworkMockFromNetworkCallUseCase.kt @@ -23,18 +23,21 @@ class GenerateNetworkMockFromNetworkCallUseCase( MockNetworkDomainModel( id = Uuid.random().toString(), // generate expectation = MockNetworkDomainModel.Expectation( - urlPattern = request.networkRequest.url, - method = request.networkRequest.method, + urlPattern = request.request.url, + method = request.request.method, ), isEnabled = true, // enabled by default - response = request.networkResponse?.let { - MockNetworkDomainModel.Response( - httpCode = request.httpCode() ?: 200, - body = it.body ?: "", - mediaType = it.headers["Content-Type"] ?: "", - delay = 0, - headers = it.headers, - ) + response = request.response?.let { + when(it) { + is FloconNetworkCallDomainModel.Response.Failure -> null // maybe generate error response in this case + is FloconNetworkCallDomainModel.Response.Success -> MockNetworkDomainModel.Response( + httpCode = request.httpCode() ?: 200, + body = it.body ?: "", + mediaType = it.headers["Content-Type"] ?: "", + delay = 0, + headers = it.headers, + ) + } } ?: MockNetworkDomainModel.Response( httpCode = 200, body = "",