feat: 认证失败时停止重连并提示用户

密码错误、账户禁用、令牌过期或限流等永久性认证错误不再无限
重连,改为置 StateError 并通过 EvError 弹窗告知用户具体原因
(中英文本地化)。网络错误仍正常指数退避重试。

- protocol: 新增 AuthErrorCode 类型与消息映射
- transport: AuthError/ServerError 携带 Code 字段
- vpn: run() 循环识别致命认证错误并停止,新增 onError 回调
- ipc/daemon/ui: 打通错误码到 UI 的本地化展示
This commit is contained in:
2026-07-07 14:37:26 +08:00
parent 6daa73fdb0
commit 56102589f6
8 changed files with 150 additions and 8 deletions
+11 -3
View File
@@ -158,7 +158,7 @@ func (c *Conn) passwordAuth(username, password string) error {
return fmt.Errorf("parse auth response: %w", err)
}
if resp.Type == protocol.TypeAuthErr {
return &AuthError{Message: resp.Message}
return &AuthError{Message: resp.Message, Code: protocol.AuthErrorCodeFromMessage(resp.Message)}
}
if resp.Type != protocol.TypeAuthOK {
return fmt.Errorf("unexpected auth response type: %s", resp.Type)
@@ -186,7 +186,11 @@ func (c *Conn) readInit() (protocol.InitMessage, error) {
return protocol.InitMessage{}, fmt.Errorf("parse init/error: %w (raw: %s)", err, data)
}
if ctrl.Type == protocol.TypeError || ctrl.Type == protocol.TypeAuthErr {
return protocol.InitMessage{}, &ServerError{Type: ctrl.Type, Message: ctrl.Message}
return protocol.InitMessage{}, &ServerError{
Type: ctrl.Type,
Message: ctrl.Message,
Code: protocol.AuthErrorCodeFromMessage(ctrl.Message),
}
}
return protocol.InitMessage{}, fmt.Errorf("unexpected message type: %s", ctrl.Type)
}
@@ -254,7 +258,10 @@ func (c *Conn) Close() error {
}
// AuthError indicates authentication failure (auth_err from server).
type AuthError struct{ Message string }
type AuthError struct {
Message string
Code protocol.AuthErrorCode
}
func (e *AuthError) Error() string { return "auth failed: " + e.Message }
@@ -262,6 +269,7 @@ func (e *AuthError) Error() string { return "auth failed: " + e.Message }
type ServerError struct {
Type string
Message string
Code protocol.AuthErrorCode
}
func (e *ServerError) Error() string {