Initial commit
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
</manifest>
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package ru.tanexc.hemoanalysis.core.network.util
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.engine.okhttp.OkHttp
|
||||
|
||||
internal actual fun PlatformHttpClient(declaration: HttpClientConfig<*>.() -> Unit): HttpClient = HttpClient(
|
||||
engineFactory = OkHttp,
|
||||
block = declaration,
|
||||
)
|
||||
@@ -0,0 +1,3 @@
|
||||
package ru.tanexc.hemoanalysis.core.network
|
||||
|
||||
internal const val DEFAULT_BASE_URL = "http://111.88.154.194:8000"
|
||||
@@ -0,0 +1,67 @@
|
||||
package ru.tanexc.hemoanalysis.core.network
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.request.header
|
||||
import io.ktor.client.request.parameter
|
||||
import io.ktor.client.statement.HttpResponse
|
||||
import io.ktor.client.statement.bodyAsChannel
|
||||
import io.ktor.http.ContentType
|
||||
import io.ktor.http.HttpStatusCode
|
||||
import io.ktor.http.contentType
|
||||
import io.ktor.http.isSuccess
|
||||
import io.ktor.util.logging.KtorSimpleLogger
|
||||
import io.ktor.utils.io.availableForRead
|
||||
import io.ktor.utils.io.readBuffer
|
||||
import kotlinx.io.readByteArray
|
||||
import ru.tanexc.hemoanalysis.core.network.response.ModelDownloadResponse
|
||||
import ru.tanexc.hemoanalysis.core.network.response.ModelMetaResponse
|
||||
import ru.tanexc.hemoanalysis.core.network.util.get
|
||||
import ru.tanexc.hemoanalysis.domain.usecase.BytesReader
|
||||
import kotlin.math.log
|
||||
import io.ktor.client.request.get as ktorGet
|
||||
|
||||
class ModelApi(
|
||||
private val httpClient: HttpClient,
|
||||
) {
|
||||
suspend fun getLatestModelInfo(apiKey: String): RequestState<ModelMetaResponse> =
|
||||
httpClient.get(url = "$DEFAULT_BASE_URL/models/latest") {
|
||||
header("X-API-KEY", apiKey)
|
||||
}
|
||||
|
||||
suspend fun downloadLatestModel(
|
||||
apiKey: String,
|
||||
version: String,
|
||||
filename: String
|
||||
): RequestState<ModelDownloadResponse> = runCatching {
|
||||
val response: HttpResponse =
|
||||
httpClient.ktorGet("$DEFAULT_BASE_URL/models/latest/download") {
|
||||
header("X-API-KEY", apiKey)
|
||||
parameter("version", version)
|
||||
parameter("filename", filename)
|
||||
contentType(ContentType.Application.OctetStream)
|
||||
}
|
||||
when {
|
||||
response.status.isSuccess() -> {
|
||||
val buffer = response.bodyAsChannel()
|
||||
val bytesReader = object : BytesReader {
|
||||
override suspend fun readNext(size: Int): ByteArray {
|
||||
return buffer.readBuffer(size).readByteArray()
|
||||
}
|
||||
}
|
||||
RequestState.Success(
|
||||
ModelDownloadResponse(
|
||||
bytesReader = bytesReader,
|
||||
totalBytes = buffer.availableForRead
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
response.status == HttpStatusCode.NotFound -> RequestState.Error("Model not found")
|
||||
else -> RequestState.Error(response.status.description)
|
||||
}
|
||||
}.getOrElse {
|
||||
RequestState.Error(
|
||||
message = it.message ?: "Request error: $DEFAULT_BASE_URL/models/latest/download"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package ru.tanexc.hemoanalysis.core.network
|
||||
|
||||
sealed interface RequestState<out T> {
|
||||
data class Success<T>(val data: T): RequestState<T>
|
||||
|
||||
data class Error(val message: String): RequestState<Nothing>
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package ru.tanexc.hemoanalysis.core.network.di
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
||||
import io.ktor.client.plugins.logging.DEFAULT
|
||||
import io.ktor.client.plugins.logging.LogLevel
|
||||
import io.ktor.client.plugins.logging.Logger
|
||||
import io.ktor.client.plugins.logging.Logging
|
||||
import io.ktor.client.plugins.logging.SIMPLE
|
||||
import io.ktor.serialization.kotlinx.json.json
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.dsl.module
|
||||
import ru.tanexc.hemoanalysis.core.network.ModelApi
|
||||
import ru.tanexc.hemoanalysis.core.network.util.PlatformHttpClient
|
||||
|
||||
val networkModule = module {
|
||||
single<HttpClient> {
|
||||
PlatformHttpClient {
|
||||
install(ContentNegotiation) {
|
||||
json(Json { ignoreUnknownKeys = true })
|
||||
}
|
||||
|
||||
install(Logging) {
|
||||
level = LogLevel.HEADERS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
singleOf(::ModelApi)
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package ru.tanexc.hemoanalysis.core.network.response
|
||||
|
||||
import ru.tanexc.hemoanalysis.domain.usecase.BytesReader
|
||||
|
||||
data class ModelDownloadResponse(
|
||||
val bytesReader: BytesReader,
|
||||
val totalBytes: Int
|
||||
)
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package ru.tanexc.hemoanalysis.core.network.response
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ModelMetaResponse(
|
||||
val version: String,
|
||||
@SerialName("created_at")
|
||||
val createdAt: String,
|
||||
val filename: String
|
||||
)
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package ru.tanexc.hemoanalysis.core.network.util
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.HttpClientConfig
|
||||
import org.koin.core.scope.Scope
|
||||
|
||||
internal expect fun PlatformHttpClient(declaration: HttpClientConfig<*>.() -> Unit): HttpClient
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package ru.tanexc.hemoanalysis.core.network.util
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.call.body
|
||||
import io.ktor.client.request.HttpRequestBuilder
|
||||
import io.ktor.client.request.get
|
||||
import io.ktor.client.request.post
|
||||
import io.ktor.client.request.setBody
|
||||
import io.ktor.client.statement.HttpResponse
|
||||
import io.ktor.http.ContentType
|
||||
import io.ktor.http.contentType
|
||||
import io.ktor.http.isSuccess
|
||||
import ru.tanexc.hemoanalysis.core.network.RequestState
|
||||
|
||||
internal suspend inline fun <reified T> HttpClient.get(
|
||||
url: String,
|
||||
block: HttpRequestBuilder.() -> Unit = {}
|
||||
): RequestState<T> = runCatching {
|
||||
get(
|
||||
urlString = url,
|
||||
block = block
|
||||
).handleResponse<T>()
|
||||
}.getOrElse { RequestState.Error(message = it.message ?: "Request error: $url") }
|
||||
|
||||
internal suspend inline fun <reified T> HttpResponse.handleResponse(): RequestState<T> = when {
|
||||
status.isSuccess() -> RequestState.Success(body())
|
||||
else -> RequestState.Error(status.description)
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package ru.tanexc.hemoanalysis.core.network.util
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.engine.darwin.Darwin
|
||||
|
||||
internal actual fun PlatformHttpClient(declaration: HttpClientConfig<*>.() -> Unit): HttpClient = HttpClient(
|
||||
engineFactory = Darwin,
|
||||
block = declaration
|
||||
)
|
||||
Reference in New Issue
Block a user