Download internal/upstream/device_token.go from a3216/gcli2api: direct link, hf CLI and curl.
- Browser
- Download file 3.09 kB
-
https://huggingface.co/spaces/a3216/gcli2api/resolve/main/internal/upstream/device_token.go
- Command line
-
hf download hf://spaces/a3216/gcli2api/internal/upstream/device_token.go
-
curl -L -o device_token.go https://huggingface.co/spaces/a3216/gcli2api/resolve/main/internal/upstream/device_token.go
3.09 kB
| // device_token.go X-Device-Token 的文件兜底读取(与桌面端共用状态文件)。 | |
| // | |
| // 容器内无桌面端 Turing Shield SDK,无法像 Python fork(xiaofan6ya/converter.py)那样 | |
| // 现取 token。这里提供另一条路径:宿主把桌面端生成的 device token 落 /app/data/device_token | |
| // (或任意挂载路径),网关定期读取注入。读取频率限 5 分钟一次缓存,>1KB 或读失败则忽略 | |
| // (优雅降级不注入,不影响主流程)。 | |
| package upstream | |
| import ( | |
| "errors" | |
| "os" | |
| "strings" | |
| "sync" | |
| "time" | |
| ) | |
| var errDeviceTokenTooLarge = errors.New("device token file too large") | |
| // deviceTokenFile 文件读取缓存 TTL(秒)。桌面端 SDK 自身也有缓存,这里再兜一层 | |
| // 避免每次出站请求都 stat+read 文件。 | |
| const deviceTokenFileTTL = 5 * time.Minute | |
| // deviceTokenFileMaxLen token 文件最大字节数。token 通常几百字节;超过 1KB | |
| // 视为异常(非 token 内容 / 文件被误用),忽略不注入。 | |
| const deviceTokenFileMaxLen = 1024 | |
| // deviceTokenFileCache 缓存 device token 文件读取结果(path → token+读取时刻)。 | |
| type deviceTokenFileCache struct { | |
| mu sync.Mutex | |
| path string | |
| token string | |
| readAt time.Time | |
| lastErr error | |
| } | |
| var dtFileCache = &deviceTokenFileCache{} | |
| // readDeviceTokenFile 读取并缓存 device token 文件;5 分钟内复用上次结果。 | |
| // 返回空串表示无可用 token(文件未配置 / 读失败 / 内容过长 / 空白)。 | |
| func readDeviceTokenFile(path string) string { | |
| if path == "" { | |
| return "" | |
| } | |
| // 快路径:缓存命中且未过期,直接返回缓存值。注意全程持锁(defer Unlock)—— | |
| // 含 5 分钟一次的过期重读(锁内读文件)。调用频率极低(每 5min 最多一次 | |
| // 文件 IO,文件上限 1KB),锁内 IO 可接受;若未来出现 NFS 挂载 + 高并发的 | |
| // 部署形态,再上 singleflight 包住重读段(YAGNI,现在不做)。 | |
| dtFileCache.mu.Lock() | |
| defer dtFileCache.mu.Unlock() | |
| if path == dtFileCache.path && time.Since(dtFileCache.readAt) < deviceTokenFileTTL { | |
| return dtFileCache.token | |
| } | |
| // 缓存未命中或过期:重新读文件。 | |
| dtFileCache.path = path | |
| tok, err := readTrimmedFile(path, deviceTokenFileMaxLen) | |
| if err != nil { | |
| // 读失败:清空缓存 token,避免注入过期/错误的值。 | |
| dtFileCache.token = "" | |
| dtFileCache.lastErr = err | |
| dtFileCache.readAt = time.Now() | |
| return "" | |
| } | |
| dtFileCache.token = tok | |
| dtFileCache.lastErr = nil | |
| dtFileCache.readAt = time.Now() | |
| return tok | |
| } | |
| // readTrimmedFile 读文件并 trim 首尾空白,超过 maxLen 返回错误(拒绝过长内容)。 | |
| func readTrimmedFile(path string, maxLen int) (string, error) { | |
| info, err := os.Stat(path) | |
| if err != nil { | |
| return "", err | |
| } | |
| if info.Size() > int64(maxLen) { | |
| return "", errDeviceTokenTooLarge | |
| } | |
| raw, err := os.ReadFile(path) | |
| if err != nil { | |
| return "", err | |
| } | |
| return strings.TrimSpace(string(raw)), nil | |
| } | |