feat: 网络

This commit is contained in:
yangxisong 2025-11-13 10:30:42 +08:00
parent 4327a8638c
commit f8b5f3a395
2 changed files with 0 additions and 136 deletions

View File

@ -4,7 +4,6 @@ import android.app.Application
import com.yuanxuan.rokid.device.DeviceServiceManager
import com.yuanxuan.rokid.network.http.ApiRepository
import com.yuanxuan.rokid.network.http.ApiService
import com.yuanxuan.rokid.network.http.OkHttpManager
import com.yuanxuan.rokid.network.http.RetrofitClient
import com.yuanxuan.rokid.network.websocket.WebSocketManager
import kotlinx.coroutines.CoroutineScope

View File

@ -1,135 +0,0 @@
package com.yuanxuan.rokid.network.http
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.yuanxuan.rokid.network.NetUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.isActive
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
import okhttp3.Call
import okhttp3.Callback
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import okhttp3.logging.HttpLoggingInterceptor
import timber.log.Timber
import java.io.IOException
import java.lang.Exception
import java.lang.reflect.Type
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.time.Duration.Companion.milliseconds
class OkHttpManager {
private val soTimeoutMillis = 30.milliseconds
private val gson by lazy {
Gson()
}
private val okhttpClient by lazy {
val httpLoggingInterceptor by lazy {
HttpLoggingInterceptor { message ->
Timber.tag("OkHttp").d(message)
}.apply {
level = HttpLoggingInterceptor.Level.BODY
}
}
OkHttpClient.Builder()
.connectTimeout(soTimeoutMillis)
.readTimeout(soTimeoutMillis)
.addInterceptor(httpLoggingInterceptor)
.build()
}
suspend fun testApi(): Test {
return makeRequest<Test>(
path = "",
method = "GET",
)
}
private suspend inline fun <reified T> makeRequest(
path: String,
method: String,
jsonBody: String? = null,
headers: Map<String, String> = emptyMap(),
): T = withContext(Dispatchers.IO) {
val requestBody = jsonBody?.toRequestBody("application/json".toMediaTypeOrNull())
val request = buildRequest(
path = path,
method = method,
body = requestBody,
headers = headers
)
try {
val response = okhttpClient.newCall(request).executeAwait()
val responseBody = response.body.string()
//过滤http错误
if (response.isSuccessful.not()) {
throw NetworkException(
message = "Http error: ${response.code} ${response.message}"
)
}
val typeToken = object : TypeToken<ApiResponse<T>>() {}
val typeOfT: Type = typeToken.type
val apiResponse: ApiResponse<Test> = gson.fromJson(responseBody, typeOfT)
if (apiResponse.isSuccess().not()) {
throw NetworkException(
message = "Business error: ${apiResponse.code} ${apiResponse.message}"
)
}
return@withContext apiResponse.data as T
} catch (e: Exception) {
throw NetworkException("Http error: ${e.message}")
}
}
private fun buildRequest(
path: String,
method: String,
body: RequestBody?,
headers: Map<String, String>
): Request {
val request = Request.Builder()
.url(NetUtils.getBaseUrl() + path)
.method(method, body)
headers.forEach { (key, value) ->
request.addHeader(key, value)
}
return request.build()
}
private suspend fun Call.executeAwait(): Response =
suspendCancellableCoroutine { continuation ->
enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
if (continuation.context.isActive) {
continuation.resumeWithException(e)
}
}
override fun onResponse(call: Call, response: Response) {
//协程被取消忽略请求结果
if (continuation.context.isActive) {
continuation.resume(response)
}
}
})
continuation.invokeOnCancellation {
try {
//协程被取消 终端网络请求
cancel()
} catch (_: Throwable) {
// Ignore
}
}
}
}