From 063658a90d9f5bf32ab8cf046b0e04cc6a760785 Mon Sep 17 00:00:00 2001 From: Liuxinyu176 <1041316040@qq.com> Date: Sat, 10 Oct 2026 11:39:28 +0800 Subject: [PATCH] =?UTF-8?q?fix(proxy):=20=E6=B5=8B=E8=AF=95=E6=8C=89?= =?UTF-8?q?=E5=8C=BA=E5=9F=9F=E9=80=89=E5=87=AD=E6=8D=AE=E4=B8=8D=E5=86=8D?= =?UTF-8?q?=E8=AF=AF=E7=94=A8=E9=BB=98=E8=AE=A4=E8=B4=A6=E5=8F=B7=EF=BC=9B?= =?UTF-8?q?=E7=AD=BE=E5=88=B0=E6=88=90=E5=8A=9F/=E5=B7=B2=E7=AD=BE?= =?UTF-8?q?=E5=8D=B3=E6=97=B6=E8=90=BD=E6=9C=AC=E5=9C=B0=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rainy/token/data/proxy/TraeChatProxy.kt | 28 ++++++- .../token/data/proxy/WorkBuddyChatProxy.kt | 28 ++++++- .../autocheckin/AutoCheckinManager.kt | 78 ++++++++++++++----- 3 files changed, 109 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/com/rainy/token/data/proxy/TraeChatProxy.kt b/app/src/main/java/com/rainy/token/data/proxy/TraeChatProxy.kt index 3f791a4..abc3ad4 100644 --- a/app/src/main/java/com/rainy/token/data/proxy/TraeChatProxy.kt +++ b/app/src/main/java/com/rainy/token/data/proxy/TraeChatProxy.kt @@ -46,7 +46,7 @@ class TraeChatProxy @Inject constructor( forcedRegion: ProviderRegion? = null, ): ProxyUpstreamResponse? = withContext(Dispatchers.IO) { - val credential = credentialRepository.get(ServiceType.TRAE, accountId) + val credential = pickCredential(accountId, forcedRegion) ?: return@withContext null if (credential !is Credential.TraeCredential) return@withContext null val jwt = credential.jwt.trim().takeIf { it.isNotBlank() } @@ -81,7 +81,7 @@ class TraeChatProxy @Inject constructor( accountId: String? = null, forcedRegion: ProviderRegion? = null, ): ProxyUpstreamStream? = withContext(Dispatchers.IO) { - val credential = credentialRepository.get(ServiceType.TRAE, accountId) + val credential = pickCredential(accountId, forcedRegion) ?: return@withContext null if (credential !is Credential.TraeCredential) return@withContext null val jwt = credential.jwt.trim().takeIf { it.isNotBlank() } @@ -233,6 +233,30 @@ class TraeChatProxy @Inject constructor( * INTL 统一走 Web 网关 core-normal.trae.ai(实测 api-us-east/a0ai 均不提供 * llm_utils_chat 路由);CN 走 IDE 网关 trae-api-cn.mchost.guru。 */ + /** 按区域选凭据:显式 accountId 优先;未指定时优先同区域账号,再兼容默认账号。 */ + private suspend fun pickCredential( + accountId: String?, + region: ProviderRegion?, + ): Credential.TraeCredential? { + if (!accountId.isNullOrBlank()) { + return credentialRepository.get(ServiceType.TRAE, accountId) as? Credential.TraeCredential + } + val accounts = credentialRepository.accountsFor(ServiceType.TRAE) + if (accounts.isEmpty()) { + val legacy = credentialRepository.get(ServiceType.TRAE, null) as? Credential.TraeCredential + ?: return null + return if (region == null || legacy.region.equals(region.name, ignoreCase = true)) legacy else null + } + val all = accounts.mapNotNull { account -> + credentialRepository.get(ServiceType.TRAE, account.id) as? Credential.TraeCredential + } + if (all.isEmpty()) return null + if (region != null) { + all.firstOrNull { it.region.equals(region.name, ignoreCase = true) }?.let { return it } + } + return all.first() + } + private fun chatBase(region: ProviderRegion?): String = if (region == ProviderRegion.INTL) { "https://core-normal.trae.ai" diff --git a/app/src/main/java/com/rainy/token/data/proxy/WorkBuddyChatProxy.kt b/app/src/main/java/com/rainy/token/data/proxy/WorkBuddyChatProxy.kt index e72c758..70ba638 100644 --- a/app/src/main/java/com/rainy/token/data/proxy/WorkBuddyChatProxy.kt +++ b/app/src/main/java/com/rainy/token/data/proxy/WorkBuddyChatProxy.kt @@ -36,7 +36,7 @@ class WorkBuddyChatProxy @Inject constructor( forcedRegion: ProviderRegion? = null, ): ProxyUpstreamResponse? = withContext(Dispatchers.IO) { - val credential = credentialRepository.get(ServiceType.WORKBUDDY, accountId) + val credential = pickCredential(accountId, forcedRegion) ?: return@withContext null if (credential !is Credential.WorkBuddyCredential) return@withContext null val accessToken = credential.accessToken.trim().takeIf { it.isNotBlank() } @@ -78,7 +78,7 @@ class WorkBuddyChatProxy @Inject constructor( accountId: String? = null, forcedRegion: ProviderRegion? = null, ): ProxyUpstreamStream? = withContext(Dispatchers.IO) { - val credential = credentialRepository.get(ServiceType.WORKBUDDY, accountId) + val credential = pickCredential(accountId, forcedRegion) ?: return@withContext null if (credential !is Credential.WorkBuddyCredential) return@withContext null val accessToken = credential.accessToken.trim().takeIf { it.isNotBlank() } @@ -120,6 +120,30 @@ class WorkBuddyChatProxy @Inject constructor( return@withContext null } + /** 按区域选凭据:显式 accountId 优先;未指定时优先同区域账号,再兼容单账号旧档。 */ + private suspend fun pickCredential( + accountId: String?, + region: ProviderRegion?, + ): Credential.WorkBuddyCredential? { + if (!accountId.isNullOrBlank()) { + return credentialRepository.get(ServiceType.WORKBUDDY, accountId) as? Credential.WorkBuddyCredential + } + val accounts = credentialRepository.accountsFor(ServiceType.WORKBUDDY) + if (accounts.isEmpty()) { + val legacy = credentialRepository.get(ServiceType.WORKBUDDY, null) as? Credential.WorkBuddyCredential + ?: return null + return if (region == null || legacy.region.equals(region.name, ignoreCase = true)) legacy else null + } + val all = accounts.mapNotNull { account -> + credentialRepository.get(ServiceType.WORKBUDDY, account.id) as? Credential.WorkBuddyCredential + } + if (all.isEmpty()) return null + if (region != null) { + all.firstOrNull { it.region.equals(region.name, ignoreCase = true) }?.let { return it } + } + return all.first() + } + private fun buildChatRequest( base: String, path: String, diff --git a/app/src/main/java/com/rainy/token/ui/dashboard/autocheckin/AutoCheckinManager.kt b/app/src/main/java/com/rainy/token/ui/dashboard/autocheckin/AutoCheckinManager.kt index ab39c65..c5c5cd1 100644 --- a/app/src/main/java/com/rainy/token/ui/dashboard/autocheckin/AutoCheckinManager.kt +++ b/app/src/main/java/com/rainy/token/ui/dashboard/autocheckin/AutoCheckinManager.kt @@ -166,17 +166,32 @@ class AutoCheckinManager @Inject constructor( ServiceType.TRAE -> refreshBalanceUseCase.checkInTrae(account.id).fold( onSuccess = { r -> when (r.outcome) { - TraeRepository.CheckinOutcome.SUCCESS -> ServiceResult( - service = service, - accountLabel = label, - newlyCheckedIn = true, - checkedInToday = true, - creditsGained = r.points, - message = "", - failed = false - ) - TraeRepository.CheckinOutcome.ALREADY -> + TraeRepository.CheckinOutcome.SUCCESS -> { + checkinStatusStore.record( + ServiceType.TRAE, + account.id, + CheckinStatusStore.STATUS_SUCCESS, + checkinId = java.util.UUID.randomUUID().toString(), + credits = r.points + ) + ServiceResult( + service = service, + accountLabel = label, + newlyCheckedIn = true, + checkedInToday = true, + creditsGained = r.points, + message = "", + failed = false + ) + } + TraeRepository.CheckinOutcome.ALREADY -> { + checkinStatusStore.record( + ServiceType.TRAE, + account.id, + CheckinStatusStore.STATUS_ALREADY + ) ServiceResult(service, label, false, true, 0, "", false) + } // INTL 不支持签到:静默跳过,不进弹窗(避免误报「已签到」) TraeRepository.CheckinOutcome.INTL_UNSUPPORTED -> null TraeRepository.CheckinOutcome.DEVICE_BLOCKED -> { @@ -201,19 +216,40 @@ class AutoCheckinManager @Inject constructor( ServiceType.WORKBUDDY -> refreshBalanceUseCase.checkInWorkBuddy(account.id).fold( onSuccess = { s -> when (s.outcome) { - WorkBuddyRepository.CheckinOutcome.SUCCESS -> ServiceResult( - service = service, - accountLabel = label, - newlyCheckedIn = true, - checkedInToday = true, - creditsGained = (s.todayCredit.takeIf { it > 0 } ?: s.dailyCredit), - message = "", - failed = false - ) - WorkBuddyRepository.CheckinOutcome.ALREADY -> + WorkBuddyRepository.CheckinOutcome.SUCCESS -> { + checkinStatusStore.record( + ServiceType.WORKBUDDY, + account.id, + CheckinStatusStore.STATUS_SUCCESS, + checkinId = java.util.UUID.randomUUID().toString(), + credits = (s.todayCredit.takeIf { it > 0 } ?: s.dailyCredit) + ) + ServiceResult( + service = service, + accountLabel = label, + newlyCheckedIn = true, + checkedInToday = true, + creditsGained = (s.todayCredit.takeIf { it > 0 } ?: s.dailyCredit), + message = "", + failed = false + ) + } + WorkBuddyRepository.CheckinOutcome.ALREADY -> { + checkinStatusStore.record( + ServiceType.WORKBUDDY, + account.id, + CheckinStatusStore.STATUS_ALREADY + ) ServiceResult(service, label, false, true, 0, "", false) - WorkBuddyRepository.CheckinOutcome.QUERY -> + } + WorkBuddyRepository.CheckinOutcome.QUERY -> { + checkinStatusStore.record( + ServiceType.WORKBUDDY, + account.id, + CheckinStatusStore.STATUS_ALREADY + ) ServiceResult(service, label, false, true, 0, "", false) + } WorkBuddyRepository.CheckinOutcome.NO_CAMPAIGN -> // 国际站没有签到活动不是账号失败:静默跳过,不记失败日志 ServiceResult(service, label, false, false, 0, s.message, false)