From 67e1f060c58d0923cbd72d2005155b8a3805c138 Mon Sep 17 00:00:00 2001 From: Liuxinyu176 <1041316040@qq.com> Date: Fri, 9 Oct 2026 00:04:55 +0800 Subject: [PATCH] =?UTF-8?q?feat(proxy):=20=E7=BD=91=E5=85=B3=E9=9A=8F?= =?UTF-8?q?=E6=9C=BA=20API=20Key=20+=20=E5=90=AF=E5=8A=A8=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SettingsViewModel 每次进程生成随机本机 Key,start 失败时暴露错误信息 - Settings 页显示 API Key 与错误提示 --- .../rainy/token/ui/settings/SettingsScreen.kt | 20 +++++++++++++++++++ .../token/ui/settings/SettingsViewModel.kt | 18 +++++++++++++++-- docs/PROXY-ROADMAP.md | 2 +- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/rainy/token/ui/settings/SettingsScreen.kt b/app/src/main/java/com/rainy/token/ui/settings/SettingsScreen.kt index 9410cfe..843a5be 100644 --- a/app/src/main/java/com/rainy/token/ui/settings/SettingsScreen.kt +++ b/app/src/main/java/com/rainy/token/ui/settings/SettingsScreen.kt @@ -91,6 +91,8 @@ fun SettingsScreen( val uiState by viewModel.uiState.collectAsStateWithLifecycle() val proxyRunning by viewModel.proxyRunning.collectAsStateWithLifecycle() + val proxyApiKey by viewModel.proxyApiKey.collectAsStateWithLifecycle() + val proxyError by viewModel.proxyError.collectAsStateWithLifecycle() var showLanguageDialog by remember { mutableStateOf(false) } Scaffold( @@ -164,6 +166,8 @@ fun SettingsScreen( item { ProxyGatewayCard( running = proxyRunning, + apiKey = proxyApiKey, + error = proxyError, onToggle = viewModel::setProxyEnabled ) } @@ -192,6 +196,8 @@ fun SettingsScreen( @Composable private fun ProxyGatewayCard( running: Boolean, + apiKey: String, + error: String?, onToggle: (Boolean) -> Unit ) { Card( @@ -221,6 +227,20 @@ private fun ProxyGatewayCard( color = InkMuted, modifier = Modifier.padding(top = 2.dp) ) + Text( + text = "API Key:$apiKey", + style = MaterialTheme.typography.bodySmall, + color = InkMuted, + modifier = Modifier.padding(top = 2.dp) + ) + if (error != null) { + Text( + text = error, + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.error, + modifier = Modifier.padding(top = 2.dp) + ) + } } Switch( checked = running, diff --git a/app/src/main/java/com/rainy/token/ui/settings/SettingsViewModel.kt b/app/src/main/java/com/rainy/token/ui/settings/SettingsViewModel.kt index 475743c..dbac1d3 100644 --- a/app/src/main/java/com/rainy/token/ui/settings/SettingsViewModel.kt +++ b/app/src/main/java/com/rainy/token/ui/settings/SettingsViewModel.kt @@ -8,6 +8,7 @@ import com.rainy.token.data.repository.CredentialRepository import com.rainy.token.domain.model.CredentialStatus import com.rainy.token.domain.service.ServiceType import dagger.hilt.android.lifecycle.HiltViewModel +import java.util.UUID import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -31,15 +32,28 @@ class SettingsViewModel @Inject constructor( /** 本地反代服务运行状态。 */ val proxyRunning: StateFlow = localProxyServer.isRunning - /** 启动/停止本地反代服务。M1b 使用固定本地 Key,后续改为可配置。 */ + /** 当前本机 API Key(每次进程随机生成,仅提示用)。 */ + val proxyApiKey: StateFlow = MutableStateFlow(generateProxyKey()) + + /** 启动失败时的错误信息。 */ + private val _proxyError = MutableStateFlow(null) + val proxyError: StateFlow = _proxyError.asStateFlow() + + /** 启动/停止本地反代服务。 */ fun setProxyEnabled(enabled: Boolean) { if (enabled) { - localProxyServer.start(ProxyServerConfig(apiKey = "rainytoken")) + localProxyServer.start(ProxyServerConfig(apiKey = proxyApiKey.value)) + .onSuccess { _proxyError.value = null } + .onFailure { e -> _proxyError.value = e.message ?: "代理网关启动失败" } } else { localProxyServer.stop() + _proxyError.value = null } } + private fun generateProxyKey(): String = + "rainy-" + UUID.randomUUID().toString().replace("-", "").take(16) + init { refresh() } diff --git a/docs/PROXY-ROADMAP.md b/docs/PROXY-ROADMAP.md index 7d9ae0b..abd7ca9 100644 --- a/docs/PROXY-ROADMAP.md +++ b/docs/PROXY-ROADMAP.md @@ -72,7 +72,7 @@ WBAdpt TraeAdpt QoderAdpt RaccoonAdpt OfficialPassthrough - WorkBuddy INTL / Trae SOLO/Work 实际协议归一化 - M3 agent2api 全家桶(Qoder / 小浣熊 / CatPaw / AutoClaw / Cline / Accio / ZCode / CodeArts / Loomy) - Qoder 需 COSY 请求签名/编码(ed25519 类原语),已列为攻坚项 -- M4 长尾 + 官方透传 + 网关配置 UI 完善 +- M4 长尾 + 官方透传 + 网关配置 UI 完善(已做:随机 API Key / 启动失败提示;待做:端口配置 / 状态持久化) ## 4. 里程碑