Files
Nexus/server/utils/sync_error_message.py
T
Nexus Agent a14fbb3df3 fix(ssh): 快速添加跳过主机密钥校验并中文化错误
凭据轮询在 SSH_STRICT 默认 true 时因 HostKeyNotVerifiable 在认证前失败;
探测始终 known_hosts=None,默认 strict 改为 false,错误信息统一中文。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-07 21:31:38 +08:00

86 lines
4.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Translate rsync/SSH push error text to Chinese for sync_logs and API responses."""
from __future__ import annotations
import re
# Order matters: more specific patterns first.
_PATTERNS: list[tuple[re.Pattern[str], str]] = [
(re.compile(r"rsync:\s*connection unexpectedly closed", re.I), "rsync:连接意外关闭"),
(re.compile(r"rsync error:\s*some files/attrs were not transferred", re.I), "rsync 错误:部分文件或属性未能传输"),
(re.compile(r"rsync error:\s*error in rsync protocol data stream", re.I), "rsync 错误:协议数据流异常"),
(re.compile(r"rsync error:\s*", re.I), "rsync 错误:"),
(re.compile(r"rsync:\s*", re.I), "rsync"),
(re.compile(r"Host key is not trusted for host", re.I), "SSH 主机密钥未信任(未知主机)"),
(re.compile(r"Host key verification failed", re.I), "SSH 主机密钥验证失败"),
(re.compile(r"Permission denied for user .+ on host", re.I), "SSH 认证失败:用户名或密码/密钥不正确"),
(re.compile(r"Login failed for user", re.I), "SSH 登录失败:用户名或密码/密钥不正确"),
(re.compile(r"Key exchange failed", re.I), "SSH 密钥交换失败"),
(re.compile(r"Disconnect reason:", re.I), "SSH 连接断开:"),
(re.compile(r"OpenSSH protocol error", re.I), "SSH 协议错误"),
(re.compile(r"Connection lost", re.I), "SSH 连接丢失"),
(re.compile(r"Connection closed", re.I), "SSH 连接已关闭"),
(re.compile(r"Could not resolve hostname", re.I), "无法解析主机名"),
(re.compile(r"Permission denied,\s*please try again", re.I), "权限被拒绝,请重试"),
(re.compile(r"Permission denied\s*\(publickey", re.I), "公钥认证失败,权限被拒绝"),
(re.compile(r"Permission denied", re.I), "权限被拒绝"),
(re.compile(r"No such file or directory", re.I), "文件或目录不存在"),
(re.compile(r"Connection refused", re.I), "连接被拒绝"),
(re.compile(r"Connection timed out", re.I), "连接超时"),
(re.compile(r"Connection reset by peer", re.I), "连接被对端重置"),
(re.compile(r"Network is unreachable", re.I), "网络不可达"),
(re.compile(r"No route to host", re.I), "无法路由到主机"),
(re.compile(r"No space left on device", re.I), "磁盘空间不足"),
(re.compile(r"Read-only file system", re.I), "文件系统为只读"),
(re.compile(r"Operation timed out", re.I), "操作超时"),
(re.compile(r"Operation not permitted", re.I), "操作不允许"),
(re.compile(r"Authentication failed", re.I), "认证失败"),
(re.compile(r"Broken pipe", re.I), "连接中断(管道破裂)"),
(re.compile(r"Protocol error", re.I), "协议错误"),
(re.compile(r"Too many open files", re.I), "打开的文件过多"),
(re.compile(r"Name or service not known", re.I), "无法解析主机名或服务名"),
(re.compile(r"ssh:\s*connect to host", re.I), "ssh:无法连接到主机"),
(re.compile(r"ssh:\s*", re.I), "ssh"),
(re.compile(r"Command failed\s*\(exit\s*(\d+)\)", re.I), r"命令失败(退出码 \1"),
(re.compile(r"rsync exited with code\s*(\d+)", re.I), r"rsync 退出码 \1"),
(re.compile(r"\bexit code\s*(\d+)", re.I), r"退出码 \1"),
(re.compile(r"Server not found", re.I), "服务器不存在"),
(re.compile(r"failed to set times on", re.I), "无法设置文件时间戳:"),
(re.compile(r"sender", re.I), "发送端"),
(re.compile(r"receiver", re.I), "接收端"),
]
_CJK_RE = re.compile(r"[\u4e00-\u9fff\u3400-\u4dbf]")
def _is_primarily_chinese(text: str) -> bool:
cjk = len(_CJK_RE.findall(text))
if cjk == 0:
return False
# Heuristic: any CJK and CJK chars >= 20% of non-whitespace length
compact = re.sub(r"\s+", "", text)
if not compact:
return False
return cjk / len(compact) >= 0.2
def translate_ssh_error_message(message: str | None) -> str | None:
"""Return a Chinese-localized SSH/rsync error string, or the original if already Chinese."""
return translate_sync_error_message(message)
def translate_sync_error_message(message: str | None) -> str | None:
"""Return a Chinese-localized push/sync error string, or the original if already Chinese."""
if message is None:
return None
text = message.strip()
if not text:
return message
if _is_primarily_chinese(text):
return message
result = text
for pattern, repl in _PATTERNS:
result = pattern.sub(repl, result)
return result