|
|
@@ -0,0 +1,820 @@
|
|
|
+package com.narutohuo.xindazhou.common.network.response
|
|
|
+
|
|
|
+import com.narutohuo.xindazhou.common.network.exception.ApiException
|
|
|
+import kotlinx.coroutines.flow.Flow
|
|
|
+import kotlinx.coroutines.flow.flow
|
|
|
+
|
|
|
+/**
|
|
|
+ * ApiResponse 扩展函数(参考 Sandwich)
|
|
|
+ *
|
|
|
+ * 提供链式调用,简化响应处理
|
|
|
+ *
|
|
|
+ * 使用方式:
|
|
|
+ * ```kotlin
|
|
|
+ * apiResponse
|
|
|
+ * .onSuccess { data -> /* 处理成功 */ }
|
|
|
+ * .onError { code, message -> /* 处理业务错误 */ }
|
|
|
+ * .onException { exception -> /* 处理异常 */ }
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+
|
|
|
+/**
|
|
|
+ * 成功时执行
|
|
|
+ *
|
|
|
+ * 当响应为 Success 时执行指定的动作
|
|
|
+ *
|
|
|
+ * @param action 成功时执行的动作,参数为数据
|
|
|
+ * @return 返回自身,支持链式调用
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * response.onSuccess { data ->
|
|
|
+ * println("成功: $data")
|
|
|
+ * }
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+inline fun <T> ApiResponse<T>.onSuccess(action: (T) -> Unit): ApiResponse<T> {
|
|
|
+ if (this is ApiResponse.Success) {
|
|
|
+ action(data)
|
|
|
+ }
|
|
|
+ return this
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 业务错误时执行
|
|
|
+ *
|
|
|
+ * 当响应为 Error 时执行指定的动作
|
|
|
+ *
|
|
|
+ * @param action 业务错误时执行的动作,参数为错误码和错误消息
|
|
|
+ * @return 返回自身,支持链式调用
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * response.onError { code, message ->
|
|
|
+ * println("业务错误: $code - $message")
|
|
|
+ * }
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+inline fun <T> ApiResponse<T>.onError(action: (code: Int, message: String) -> Unit): ApiResponse<T> {
|
|
|
+ if (this is ApiResponse.Error) {
|
|
|
+ action(code, message)
|
|
|
+ }
|
|
|
+ return this
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 异常时执行
|
|
|
+ *
|
|
|
+ * 当响应为 Exception 时执行指定的动作
|
|
|
+ *
|
|
|
+ * @param action 异常时执行的动作,参数为异常对象
|
|
|
+ * @return 返回自身,支持链式调用
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * response.onException { exception ->
|
|
|
+ * println("异常: ${exception.message}")
|
|
|
+ * }
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+inline fun <T> ApiResponse<T>.onException(action: (ApiException) -> Unit): ApiResponse<T> {
|
|
|
+ if (this is ApiResponse.Exception) {
|
|
|
+ action(exception)
|
|
|
+ }
|
|
|
+ return this
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 转换数据
|
|
|
+ *
|
|
|
+ * 如果响应成功,将数据转换为新类型
|
|
|
+ * 如果响应失败,保持原样
|
|
|
+ *
|
|
|
+ * @param transform 数据转换函数
|
|
|
+ * @return 转换后的 ApiResponse
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * val userResponse: ApiResponse<User> = api.getUser()
|
|
|
+ * val nameResponse: ApiResponse<String> = userResponse.map { it.name }
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+inline fun <T, R> ApiResponse<T>.map(transform: (T) -> R): ApiResponse<R> {
|
|
|
+ return when (this) {
|
|
|
+ is ApiResponse.Success -> ApiResponse.Success(transform(data))
|
|
|
+ is ApiResponse.Error -> ApiResponse.Error(code, message, body)
|
|
|
+ is ApiResponse.Exception -> ApiResponse.Exception(exception)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 只转换成功数据
|
|
|
+ *
|
|
|
+ * 如果响应成功,将数据转换为新类型
|
|
|
+ * 如果响应失败,保持原样
|
|
|
+ *
|
|
|
+ * 与 map() 的区别:mapSuccess() 语义更清晰,明确表示只转换成功数据
|
|
|
+ *
|
|
|
+ * @param transform 数据转换函数
|
|
|
+ * @return 转换后的 ApiResponse
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * val userResponse: ApiResponse<User> = api.getUser()
|
|
|
+ * val nameResponse: ApiResponse<String> = userResponse.mapSuccess { it.name }
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+inline fun <T, R> ApiResponse<T>.mapSuccess(transform: (T) -> R): ApiResponse<R> {
|
|
|
+ return when (this) {
|
|
|
+ is ApiResponse.Success -> ApiResponse.Success(transform(data))
|
|
|
+ is ApiResponse.Error -> ApiResponse.Error(code, message, body)
|
|
|
+ is ApiResponse.Exception -> ApiResponse.Exception(exception)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 转换失败数据
|
|
|
+ *
|
|
|
+ * 如果响应失败(Error 或 Exception),转换失败信息
|
|
|
+ * 如果响应成功,保持原样
|
|
|
+ *
|
|
|
+ * @param transformError 业务错误转换函数
|
|
|
+ * @param transformException 异常转换函数
|
|
|
+ * @return 转换后的 ApiResponse
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * val response: ApiResponse<User> = api.getUser()
|
|
|
+ * val mappedResponse = response.mapFailure(
|
|
|
+ * transformError = { code, message -> "业务错误: $code - $message" },
|
|
|
+ * transformException = { exception -> "网络错误: ${exception.message}" }
|
|
|
+ * )
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+inline fun <T> ApiResponse<T>.mapFailure(
|
|
|
+ crossinline transformError: (Int, String) -> ApiResponse.Error<T>,
|
|
|
+ crossinline transformException: (ApiException) -> ApiResponse.Exception<T>
|
|
|
+): ApiResponse<T> {
|
|
|
+ return when (this) {
|
|
|
+ is ApiResponse.Success -> this
|
|
|
+ is ApiResponse.Error -> transformError(code, message)
|
|
|
+ is ApiResponse.Exception -> transformException(exception)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 数据验证
|
|
|
+ *
|
|
|
+ * 如果响应成功,验证数据是否符合条件
|
|
|
+ * 如果验证失败,转换为 Error
|
|
|
+ * 如果响应失败,保持原样
|
|
|
+ *
|
|
|
+ * @param predicate 验证条件,返回 true 表示验证通过
|
|
|
+ * @param errorCode 验证失败时的错误码(默认 -1)
|
|
|
+ * @param errorMessage 验证失败时的错误消息
|
|
|
+ * @return 验证后的 ApiResponse
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * val response: ApiResponse<User> = api.getUser()
|
|
|
+ * val validatedResponse = response.validate(
|
|
|
+ * predicate = { it.age >= 18 },
|
|
|
+ * errorMessage = "用户年龄必须大于等于18岁"
|
|
|
+ * )
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+inline fun <T> ApiResponse<T>.validate(
|
|
|
+ crossinline predicate: (T) -> Boolean,
|
|
|
+ errorCode: Int = -1,
|
|
|
+ errorMessage: String = "数据验证失败"
|
|
|
+): ApiResponse<T> {
|
|
|
+ return when (this) {
|
|
|
+ is ApiResponse.Success -> {
|
|
|
+ if (predicate(data)) {
|
|
|
+ this
|
|
|
+ } else {
|
|
|
+ ApiResponse.Error(errorCode, errorMessage, null)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ is ApiResponse.Error -> this
|
|
|
+ is ApiResponse.Exception -> this
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 数据验证(使用 lambda 构建错误消息)
|
|
|
+ *
|
|
|
+ * 如果响应成功,验证数据是否符合条件
|
|
|
+ * 如果验证失败,转换为 Error(错误消息由 lambda 动态生成)
|
|
|
+ * 如果响应失败,保持原样
|
|
|
+ *
|
|
|
+ * @param predicate 验证条件,返回 true 表示验证通过
|
|
|
+ * @param errorCode 验证失败时的错误码(默认 -1)
|
|
|
+ * @param errorMessage 验证失败时的错误消息构建函数
|
|
|
+ * @return 验证后的 ApiResponse
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * val response: ApiResponse<User> = api.getUser()
|
|
|
+ * val validatedResponse = response.validate(
|
|
|
+ * predicate = { it.age >= 18 },
|
|
|
+ * errorMessage = { "用户年龄 ${it.age} 必须大于等于18岁" }
|
|
|
+ * )
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+inline fun <T> ApiResponse<T>.validate(
|
|
|
+ crossinline predicate: (T) -> Boolean,
|
|
|
+ errorCode: Int = -1,
|
|
|
+ crossinline errorMessage: (T) -> String
|
|
|
+): ApiResponse<T> {
|
|
|
+ return when (this) {
|
|
|
+ is ApiResponse.Success -> {
|
|
|
+ if (predicate(data)) {
|
|
|
+ this
|
|
|
+ } else {
|
|
|
+ ApiResponse.Error(errorCode, errorMessage(data), null)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ is ApiResponse.Error -> this
|
|
|
+ is ApiResponse.Exception -> this
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 非空检查
|
|
|
+ *
|
|
|
+ * 从成功数据中提取可能为 null 的字段
|
|
|
+ * 如果提取的字段为 null,转换为 Error
|
|
|
+ * 如果响应失败,保持原样
|
|
|
+ *
|
|
|
+ * @param selector 提取函数,从数据中提取可能为 null 的字段
|
|
|
+ * @param errorCode 字段为 null 时的错误码(默认 -1)
|
|
|
+ * @param errorMessage 字段为 null 时的错误消息
|
|
|
+ * @return 提取后的 ApiResponse(非空类型)
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * val response: ApiResponse<User> = api.getUser()
|
|
|
+ * val profileImageResponse: ApiResponse<String> = response.requireNotNull(
|
|
|
+ * selector = { it.profileImage },
|
|
|
+ * errorMessage = "用户头像不能为空"
|
|
|
+ * )
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+inline fun <T, R> ApiResponse<T>.requireNotNull(
|
|
|
+ crossinline selector: (T) -> R?,
|
|
|
+ errorCode: Int = -1,
|
|
|
+ errorMessage: String = "数据不能为空"
|
|
|
+): ApiResponse<R> {
|
|
|
+ return when (this) {
|
|
|
+ is ApiResponse.Success -> {
|
|
|
+ val value = selector(data)
|
|
|
+ if (value != null) {
|
|
|
+ ApiResponse.Success(value)
|
|
|
+ } else {
|
|
|
+ ApiResponse.Error(errorCode, errorMessage, null)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ is ApiResponse.Error -> ApiResponse.Error(code, message, body)
|
|
|
+ is ApiResponse.Exception -> ApiResponse.Exception(exception)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 非空检查(使用 lambda 构建错误消息)
|
|
|
+ *
|
|
|
+ * 从成功数据中提取可能为 null 的字段
|
|
|
+ * 如果提取的字段为 null,转换为 Error(错误消息由 lambda 动态生成)
|
|
|
+ * 如果响应失败,保持原样
|
|
|
+ *
|
|
|
+ * @param selector 提取函数,从数据中提取可能为 null 的字段
|
|
|
+ * @param errorCode 字段为 null 时的错误码(默认 -1)
|
|
|
+ * @param errorMessage 字段为 null 时的错误消息构建函数
|
|
|
+ * @return 提取后的 ApiResponse(非空类型)
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * val response: ApiResponse<User> = api.getUser()
|
|
|
+ * val profileImageResponse: ApiResponse<String> = response.requireNotNull(
|
|
|
+ * selector = { it.profileImage },
|
|
|
+ * errorMessage = { user -> "用户 ${user.name} 的头像不能为空" }
|
|
|
+ * )
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+inline fun <T, R> ApiResponse<T>.requireNotNull(
|
|
|
+ crossinline selector: (T) -> R?,
|
|
|
+ errorCode: Int = -1,
|
|
|
+ crossinline errorMessage: (T) -> String
|
|
|
+): ApiResponse<R> {
|
|
|
+ return when (this) {
|
|
|
+ is ApiResponse.Success -> {
|
|
|
+ val value = selector(data)
|
|
|
+ if (value != null) {
|
|
|
+ ApiResponse.Success(value)
|
|
|
+ } else {
|
|
|
+ ApiResponse.Error(errorCode, errorMessage(data), null)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ is ApiResponse.Error -> ApiResponse.Error(code, message, body)
|
|
|
+ is ApiResponse.Exception -> ApiResponse.Exception(exception)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 非空检查(suspend 版本)
|
|
|
+ *
|
|
|
+ * 从成功数据中提取可能为 null 的字段
|
|
|
+ * 如果提取的字段为 null,转换为 Error
|
|
|
+ * 如果响应失败,保持原样
|
|
|
+ *
|
|
|
+ * 注意:selector 可以是 suspend 函数,适用于需要异步提取的场景
|
|
|
+ *
|
|
|
+ * @param selector 提取函数(suspend),从数据中提取可能为 null 的字段
|
|
|
+ * @param errorCode 字段为 null 时的错误码(默认 -1)
|
|
|
+ * @param errorMessage 字段为 null 时的错误消息
|
|
|
+ * @return 提取后的 ApiResponse(非空类型)
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * val response: ApiResponse<User> = api.getUser()
|
|
|
+ * val profileImageResponse: ApiResponse<String> = response.suspendRequireNotNull(
|
|
|
+ * selector = { user -> fetchProfileImageFromCache(user.id) },
|
|
|
+ * errorMessage = "用户头像不能为空"
|
|
|
+ * )
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+suspend inline fun <T, R> ApiResponse<T>.suspendRequireNotNull(
|
|
|
+ crossinline selector: suspend (T) -> R?,
|
|
|
+ errorCode: Int = -1,
|
|
|
+ errorMessage: String = "数据不能为空"
|
|
|
+): ApiResponse<R> {
|
|
|
+ return when (this) {
|
|
|
+ is ApiResponse.Success -> {
|
|
|
+ val value = selector(data)
|
|
|
+ if (value != null) {
|
|
|
+ ApiResponse.Success(value)
|
|
|
+ } else {
|
|
|
+ ApiResponse.Error(errorCode, errorMessage, null)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ is ApiResponse.Error -> ApiResponse.Error(code, message, body)
|
|
|
+ is ApiResponse.Exception -> ApiResponse.Exception(exception)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 非空检查(suspend 版本,使用 lambda 构建错误消息)
|
|
|
+ *
|
|
|
+ * 从成功数据中提取可能为 null 的字段
|
|
|
+ * 如果提取的字段为 null,转换为 Error(错误消息由 lambda 动态生成)
|
|
|
+ * 如果响应失败,保持原样
|
|
|
+ *
|
|
|
+ * 注意:selector 和 errorMessage 都可以是 suspend 函数
|
|
|
+ *
|
|
|
+ * @param selector 提取函数(suspend),从数据中提取可能为 null 的字段
|
|
|
+ * @param errorCode 字段为 null 时的错误码(默认 -1)
|
|
|
+ * @param errorMessage 字段为 null 时的错误消息构建函数(suspend)
|
|
|
+ * @return 提取后的 ApiResponse(非空类型)
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * val response: ApiResponse<User> = api.getUser()
|
|
|
+ * val profileImageResponse: ApiResponse<String> = response.suspendRequireNotNull(
|
|
|
+ * selector = { user -> fetchProfileImageFromCache(user.id) },
|
|
|
+ * errorMessage = { user -> "用户 ${user.name} 的头像不能为空" }
|
|
|
+ * )
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+suspend inline fun <T, R> ApiResponse<T>.suspendRequireNotNull(
|
|
|
+ crossinline selector: suspend (T) -> R?,
|
|
|
+ errorCode: Int = -1,
|
|
|
+ crossinline errorMessage: suspend (T) -> String
|
|
|
+): ApiResponse<R> {
|
|
|
+ return when (this) {
|
|
|
+ is ApiResponse.Success -> {
|
|
|
+ val value = selector(data)
|
|
|
+ if (value != null) {
|
|
|
+ ApiResponse.Success(value)
|
|
|
+ } else {
|
|
|
+ ApiResponse.Error(errorCode, errorMessage(data), null)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ is ApiResponse.Error -> ApiResponse.Error(code, message, body)
|
|
|
+ is ApiResponse.Exception -> ApiResponse.Exception(exception)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 失败时返回默认值
|
|
|
+ *
|
|
|
+ * 如果响应失败(Error 或 Exception),返回默认值
|
|
|
+ * 如果响应成功,保持原样
|
|
|
+ *
|
|
|
+ * @param block 默认值生成函数
|
|
|
+ * @return 成功时返回原响应,失败时返回包含默认值的 Success
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * val response: ApiResponse<User> = api.getUser()
|
|
|
+ * val userWithDefault: ApiResponse<User> = response.recover { User.default() }
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+inline fun <T> ApiResponse<T>.recover(block: () -> T): ApiResponse<T> {
|
|
|
+ return when (this) {
|
|
|
+ is ApiResponse.Success -> this
|
|
|
+ else -> ApiResponse.Success(block())
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 失败时返回固定的默认值
|
|
|
+ *
|
|
|
+ * @param defaultValue 默认值
|
|
|
+ * @return 成功时返回原响应,失败时返回包含默认值的 Success
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * val response: ApiResponse<User> = api.getUser()
|
|
|
+ * val userWithDefault: ApiResponse<User> = response.recoverValue(User.default())
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+fun <T> ApiResponse<T>.recoverValue(defaultValue: T): ApiResponse<T> {
|
|
|
+ return when (this) {
|
|
|
+ is ApiResponse.Success -> this
|
|
|
+ else -> ApiResponse.Success(defaultValue)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 失败时返回 null
|
|
|
+ *
|
|
|
+ * 如果响应失败,返回包含 null 的 Success
|
|
|
+ * 如果响应成功,保持原样
|
|
|
+ *
|
|
|
+ * @return 成功时返回原响应,失败时返回包含 null 的 Success
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * val response: ApiResponse<User> = api.getUser()
|
|
|
+ * val userOrNull: ApiResponse<User?> = response.recoverNull()
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+fun <T> ApiResponse<T>.recoverNull(): ApiResponse<T?> {
|
|
|
+ return when (this) {
|
|
|
+ is ApiResponse.Success -> ApiResponse.Success(data)
|
|
|
+ else -> ApiResponse.Success(null)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 失败时返回备用的 ApiResponse
|
|
|
+ *
|
|
|
+ * 如果响应失败(Error 或 Exception),返回备用响应
|
|
|
+ * 如果响应成功,保持原样
|
|
|
+ *
|
|
|
+ * 与 recover() 的区别:recover() 返回默认值(T),recoverWith() 返回备用响应(ApiResponse<T>)
|
|
|
+ *
|
|
|
+ * @param block 备用响应生成函数,参数为失败响应(Error 或 Exception)
|
|
|
+ * @return 成功时返回原响应,失败时返回备用响应
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * val response: ApiResponse<User> = api.getUser()
|
|
|
+ * val recoveredResponse: ApiResponse<User> = response.recoverWith { failure ->
|
|
|
+ * // 从缓存或备用服务器获取
|
|
|
+ * when (failure) {
|
|
|
+ * is ApiResponse.Error -> getCachedUser()
|
|
|
+ * is ApiResponse.Exception -> getFallbackUser()
|
|
|
+ * }
|
|
|
+ * }
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+inline fun <T> ApiResponse<T>.recoverWith(
|
|
|
+ crossinline block: (ApiResponse<T>) -> ApiResponse<T>
|
|
|
+): ApiResponse<T> {
|
|
|
+ return when (this) {
|
|
|
+ is ApiResponse.Success -> this
|
|
|
+ else -> block(this)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 失败时返回备用的 ApiResponse(suspend 版本)
|
|
|
+ *
|
|
|
+ * 如果响应失败(Error 或 Exception),返回备用响应
|
|
|
+ * 如果响应成功,保持原样
|
|
|
+ *
|
|
|
+ * 注意:block 可以是 suspend 函数,适用于需要异步获取备用响应的场景
|
|
|
+ *
|
|
|
+ * @param block 备用响应生成函数(suspend),参数为失败响应(Error 或 Exception)
|
|
|
+ * @return 成功时返回原响应,失败时返回备用响应
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * val response: ApiResponse<User> = api.getUser()
|
|
|
+ * val recoveredResponse: ApiResponse<User> = response.suspendRecoverWith { failure ->
|
|
|
+ * // 从数据库或备用服务器异步获取
|
|
|
+ * when (failure) {
|
|
|
+ * is ApiResponse.Error -> getCachedUserFromDatabase()
|
|
|
+ * is ApiResponse.Exception -> getFallbackUserFromServer()
|
|
|
+ * }
|
|
|
+ * }
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+suspend inline fun <T> ApiResponse<T>.suspendRecoverWith(
|
|
|
+ crossinline block: suspend (ApiResponse<T>) -> ApiResponse<T>
|
|
|
+): ApiResponse<T> {
|
|
|
+ return when (this) {
|
|
|
+ is ApiResponse.Success -> this
|
|
|
+ else -> block(this)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 转换为 Flow
|
|
|
+ *
|
|
|
+ * 将 ApiResponse<T> 转换为 Flow<T>
|
|
|
+ * - 成功时发射数据
|
|
|
+ * - 失败时发射异常(业务错误或网络异常)
|
|
|
+ *
|
|
|
+ * @return Flow<T> 成功时发射数据,失败时发射异常
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * val response: ApiResponse<User> = api.getUser()
|
|
|
+ * response.toFlow()
|
|
|
+ * .catch { exception -> /* 处理异常 */ }
|
|
|
+ * .collect { user -> /* 处理成功数据 */ }
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+fun <T> ApiResponse<T>.toFlow(): Flow<T> {
|
|
|
+ return flow {
|
|
|
+ when (this@toFlow) {
|
|
|
+ is ApiResponse.Success -> emit(data)
|
|
|
+ is ApiResponse.Error -> throw com.narutohuo.xindazhou.common.network.exception.BusinessException(code, message)
|
|
|
+ is ApiResponse.Exception -> throw exception
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 转换为 Flow(保持 ApiResponse 类型)
|
|
|
+ *
|
|
|
+ * 将 ApiResponse<T> 转换为 Flow<ApiResponse<T>>
|
|
|
+ * 保持完整的响应信息
|
|
|
+ *
|
|
|
+ * @return Flow<ApiResponse<T>> 发射完整的响应信息
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * val response: ApiResponse<User> = api.getUser()
|
|
|
+ * response.toFlowResponse()
|
|
|
+ * .collect { apiResponse ->
|
|
|
+ * when (apiResponse) {
|
|
|
+ * is ApiResponse.Success -> { /* 处理成功 */ }
|
|
|
+ * is ApiResponse.Error -> { /* 处理业务错误 */ }
|
|
|
+ * is ApiResponse.Exception -> { /* 处理异常 */ }
|
|
|
+ * }
|
|
|
+ * }
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+fun <T> ApiResponse<T>.toFlowResponse(): Flow<ApiResponse<T>> {
|
|
|
+ return flow {
|
|
|
+ emit(this@toFlowResponse)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// ==================== suspend 版本扩展函数 ====================
|
|
|
+
|
|
|
+/**
|
|
|
+ * 成功时执行(suspend 版本)
|
|
|
+ *
|
|
|
+ * 当响应为 Success 时执行指定的 suspend 动作
|
|
|
+ *
|
|
|
+ * @param action 成功时执行的动作,参数为数据
|
|
|
+ * @return 返回自身,支持链式调用
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * response.suspendOnSuccess { data ->
|
|
|
+ * // 可以调用 suspend 函数
|
|
|
+ * saveToDatabase(data)
|
|
|
+ * }
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+suspend inline fun <T> ApiResponse<T>.suspendOnSuccess(action: suspend (T) -> Unit): ApiResponse<T> {
|
|
|
+ if (this is ApiResponse.Success) {
|
|
|
+ action(data)
|
|
|
+ }
|
|
|
+ return this
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 业务错误时执行(suspend 版本)
|
|
|
+ *
|
|
|
+ * 当响应为 Error 时执行指定的 suspend 动作
|
|
|
+ *
|
|
|
+ * @param action 业务错误时执行的动作,参数为错误码和错误消息
|
|
|
+ * @return 返回自身,支持链式调用
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * response.suspendOnError { code, message ->
|
|
|
+ * // 可以调用 suspend 函数
|
|
|
+ * logError(code, message)
|
|
|
+ * }
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+suspend inline fun <T> ApiResponse<T>.suspendOnError(action: suspend (code: Int, message: String) -> Unit): ApiResponse<T> {
|
|
|
+ if (this is ApiResponse.Error) {
|
|
|
+ action(code, message)
|
|
|
+ }
|
|
|
+ return this
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 异常时执行(suspend 版本)
|
|
|
+ *
|
|
|
+ * 当响应为 Exception 时执行指定的 suspend 动作
|
|
|
+ *
|
|
|
+ * @param action 异常时执行的动作,参数为异常对象
|
|
|
+ * @return 返回自身,支持链式调用
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * response.suspendOnException { exception ->
|
|
|
+ * // 可以调用 suspend 函数
|
|
|
+ * reportException(exception)
|
|
|
+ * }
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+suspend inline fun <T> ApiResponse<T>.suspendOnException(action: suspend (ApiException) -> Unit): ApiResponse<T> {
|
|
|
+ if (this is ApiResponse.Exception) {
|
|
|
+ action(exception)
|
|
|
+ }
|
|
|
+ return this
|
|
|
+}
|
|
|
+
|
|
|
+// ==================== zip 组合函数 ====================
|
|
|
+
|
|
|
+/**
|
|
|
+ * 组合两个 ApiResponse
|
|
|
+ *
|
|
|
+ * 如果两个响应都是 Success,则使用 transform 函数组合数据
|
|
|
+ * 如果任一响应失败,则返回第一个失败响应(短路)
|
|
|
+ *
|
|
|
+ * @param other 另一个 ApiResponse
|
|
|
+ * @param transform 组合函数,参数为两个成功数据
|
|
|
+ * @return 组合后的 ApiResponse
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * val userResponse: ApiResponse<User> = api.getUser()
|
|
|
+ * val profileResponse: ApiResponse<Profile> = api.getProfile()
|
|
|
+ *
|
|
|
+ * val combinedResponse: ApiResponse<UserProfile> = userResponse.zip(profileResponse) { user, profile ->
|
|
|
+ * UserProfile(user, profile)
|
|
|
+ * }
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+inline fun <T1, T2, R> ApiResponse<T1>.zip(
|
|
|
+ other: ApiResponse<T2>,
|
|
|
+ crossinline transform: (T1, T2) -> R
|
|
|
+): ApiResponse<R> {
|
|
|
+ return when {
|
|
|
+ this is ApiResponse.Success && other is ApiResponse.Success -> {
|
|
|
+ ApiResponse.Success(transform(this.data, other.data))
|
|
|
+ }
|
|
|
+ this is ApiResponse.Error -> ApiResponse.Error(code, message, body)
|
|
|
+ this is ApiResponse.Exception -> ApiResponse.Exception(exception)
|
|
|
+ other is ApiResponse.Error -> ApiResponse.Error(other.code, other.message, other.body)
|
|
|
+ other is ApiResponse.Exception -> ApiResponse.Exception(other.exception)
|
|
|
+ else -> throw IllegalStateException("Unexpected state")
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 组合三个 ApiResponse
|
|
|
+ *
|
|
|
+ * 如果三个响应都是 Success,则使用 transform 函数组合数据
|
|
|
+ * 如果任一响应失败,则返回第一个失败响应(短路)
|
|
|
+ *
|
|
|
+ * @param second 第二个 ApiResponse
|
|
|
+ * @param third 第三个 ApiResponse
|
|
|
+ * @param transform 组合函数,参数为三个成功数据
|
|
|
+ * @return 组合后的 ApiResponse
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * val userResponse: ApiResponse<User> = api.getUser()
|
|
|
+ * val profileResponse: ApiResponse<Profile> = api.getProfile()
|
|
|
+ * val settingsResponse: ApiResponse<Settings> = api.getSettings()
|
|
|
+ *
|
|
|
+ * val combinedResponse: ApiResponse<UserProfile> = zip3(
|
|
|
+ * userResponse, profileResponse, settingsResponse
|
|
|
+ * ) { user, profile, settings ->
|
|
|
+ * UserProfile(user, profile, settings)
|
|
|
+ * }
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+inline fun <T1, T2, T3, R> zip3(
|
|
|
+ first: ApiResponse<T1>,
|
|
|
+ second: ApiResponse<T2>,
|
|
|
+ third: ApiResponse<T3>,
|
|
|
+ crossinline transform: (T1, T2, T3) -> R
|
|
|
+): ApiResponse<R> {
|
|
|
+ return when {
|
|
|
+ first is ApiResponse.Success && second is ApiResponse.Success && third is ApiResponse.Success -> {
|
|
|
+ ApiResponse.Success(transform(first.data, second.data, third.data))
|
|
|
+ }
|
|
|
+ first is ApiResponse.Error -> ApiResponse.Error(first.code, first.message, first.body)
|
|
|
+ first is ApiResponse.Exception -> ApiResponse.Exception(first.exception)
|
|
|
+ second is ApiResponse.Error -> ApiResponse.Error(second.code, second.message, second.body)
|
|
|
+ second is ApiResponse.Exception -> ApiResponse.Exception(second.exception)
|
|
|
+ third is ApiResponse.Error -> ApiResponse.Error(third.code, third.message, third.body)
|
|
|
+ third is ApiResponse.Exception -> ApiResponse.Exception(third.exception)
|
|
|
+ else -> throw IllegalStateException("Unexpected state")
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 组合两个 ApiResponse(suspend 版本)
|
|
|
+ *
|
|
|
+ * 如果两个响应都是 Success,则使用 transform 函数组合数据(transform 可以是 suspend 函数)
|
|
|
+ * 如果任一响应失败,则返回第一个失败响应(短路)
|
|
|
+ *
|
|
|
+ * @param other 另一个 ApiResponse
|
|
|
+ * @param transform 组合函数(suspend),参数为两个成功数据
|
|
|
+ * @return 组合后的 ApiResponse
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * val userResponse: ApiResponse<User> = api.getUser()
|
|
|
+ * val profileResponse: ApiResponse<Profile> = api.getProfile()
|
|
|
+ *
|
|
|
+ * val combinedResponse: ApiResponse<UserProfile> = userResponse.suspendZip(profileResponse) { user, profile ->
|
|
|
+ * // 可以调用 suspend 函数进行复杂组合
|
|
|
+ * createUserProfile(user, profile)
|
|
|
+ * }
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+suspend inline fun <T1, T2, R> ApiResponse<T1>.suspendZip(
|
|
|
+ other: ApiResponse<T2>,
|
|
|
+ crossinline transform: suspend (T1, T2) -> R
|
|
|
+): ApiResponse<R> {
|
|
|
+ return when {
|
|
|
+ this is ApiResponse.Success && other is ApiResponse.Success -> {
|
|
|
+ ApiResponse.Success(transform(this.data, other.data))
|
|
|
+ }
|
|
|
+ this is ApiResponse.Error -> ApiResponse.Error(code, message, body)
|
|
|
+ this is ApiResponse.Exception -> ApiResponse.Exception(exception)
|
|
|
+ other is ApiResponse.Error -> ApiResponse.Error(other.code, other.message, other.body)
|
|
|
+ other is ApiResponse.Exception -> ApiResponse.Exception(other.exception)
|
|
|
+ else -> throw IllegalStateException("Unexpected state")
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 组合三个 ApiResponse(suspend 版本)
|
|
|
+ *
|
|
|
+ * 如果三个响应都是 Success,则使用 transform 函数组合数据(transform 可以是 suspend 函数)
|
|
|
+ * 如果任一响应失败,则返回第一个失败响应(短路)
|
|
|
+ *
|
|
|
+ * @param second 第二个 ApiResponse
|
|
|
+ * @param third 第三个 ApiResponse
|
|
|
+ * @param transform 组合函数(suspend),参数为三个成功数据
|
|
|
+ * @return 组合后的 ApiResponse
|
|
|
+ *
|
|
|
+ * 示例:
|
|
|
+ * ```kotlin
|
|
|
+ * val userResponse: ApiResponse<User> = api.getUser()
|
|
|
+ * val profileResponse: ApiResponse<Profile> = api.getProfile()
|
|
|
+ * val settingsResponse: ApiResponse<Settings> = api.getSettings()
|
|
|
+ *
|
|
|
+ * val combinedResponse: ApiResponse<UserProfile> = suspendZip3(
|
|
|
+ * userResponse, profileResponse, settingsResponse
|
|
|
+ * ) { user, profile, settings ->
|
|
|
+ * // 可以调用 suspend 函数进行复杂组合
|
|
|
+ * createUserProfile(user, profile, settings)
|
|
|
+ * }
|
|
|
+ * ```
|
|
|
+ */
|
|
|
+suspend inline fun <T1, T2, T3, R> suspendZip3(
|
|
|
+ first: ApiResponse<T1>,
|
|
|
+ second: ApiResponse<T2>,
|
|
|
+ third: ApiResponse<T3>,
|
|
|
+ crossinline transform: suspend (T1, T2, T3) -> R
|
|
|
+): ApiResponse<R> {
|
|
|
+ return when {
|
|
|
+ first is ApiResponse.Success && second is ApiResponse.Success && third is ApiResponse.Success -> {
|
|
|
+ ApiResponse.Success(transform(first.data, second.data, third.data))
|
|
|
+ }
|
|
|
+ first is ApiResponse.Error -> ApiResponse.Error(first.code, first.message, first.body)
|
|
|
+ first is ApiResponse.Exception -> ApiResponse.Exception(first.exception)
|
|
|
+ second is ApiResponse.Error -> ApiResponse.Error(second.code, second.message, second.body)
|
|
|
+ second is ApiResponse.Exception -> ApiResponse.Exception(second.exception)
|
|
|
+ third is ApiResponse.Error -> ApiResponse.Error(third.code, third.message, third.body)
|
|
|
+ third is ApiResponse.Exception -> ApiResponse.Exception(third.exception)
|
|
|
+ else -> throw IllegalStateException("Unexpected state")
|
|
|
+ }
|
|
|
+}
|