gcli2api / internal /syncer /space.go
a3216's picture
chore: 同步到上游 1.12.0-panel + 凭证同步/独立启动器/保活
6d60378 verified
Raw History Blame Contribute Delete
2.28 kB
package syncer
import (
"context"
"fmt"
"io"
"net/http"
"net/url"
"strings"
"time"
)
// RestartSpace 请求 Hugging Face 重启一个 Space。
//
// 为什么需要它:Space 上的网关只在**启动时**扫一遍凭证目录(没有文件监听),
// 所以往桶里推了新账号之后,正在运行的 Space 并不会加载它——签到时候就会漏掉这个号。
// 重启一次(30~60s 冷启动)即可让它从挂载卷重新读齐。
//
// 这也是配置成"只在推了 auths/ 下的文件时才做"的原因:改 state.json 之类不必重启,
// 白白打断正在进行中的签到任务。
func RestartSpace(ctx context.Context, endpoint, spaceID, token string, timeout time.Duration, insecureSkipVerify bool) error {
if strings.TrimSpace(spaceID) == "" {
return fmt.Errorf("restart_space 未配置")
}
if strings.TrimSpace(endpoint) == "" {
endpoint = DefaultEndpoint
}
if timeout <= 0 {
timeout = 60 * time.Second
}
endpoint = strings.TrimRight(endpoint, "/")
u := fmt.Sprintf("%s/api/spaces/%s/restart", endpoint, strings.Trim(spaceID, "/"))
req, err := http.NewRequestWithContext(ctx, http.MethodPost, u, nil)
if err != nil {
return err
}
if token != "" {
req.Header.Set("Authorization", "Bearer "+token)
}
req.Header.Set("User-Agent", userAgent)
cli := newHTTPClient(timeout, insecureSkipVerify, "")
resp, err := cli.Do(req)
if err != nil {
// 把 URL 里的信息去掉,避免日志里出现带着鉴权语义的完整地址。
return fmt.Errorf("请求重启 Space 失败: %w", err)
}
defer func() { _ = resp.Body.Close() }()
body, _ := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
if resp.StatusCode < 200 || resp.StatusCode > 299 {
return fmt.Errorf("重启 Space 返回 %d: %s", resp.StatusCode, truncate(string(body), 300))
}
return nil
}
// SpaceIDFromBucket 不是必须的辅助函数,但留一个把桶 ID 归一化的入口,
// 便于调用方传 "a3216/wb2api-storage" 或 "https://huggingface.co/..." 两种写法。
func SpaceIDFromBucket(raw string) string {
raw = strings.TrimSpace(raw)
if raw == "" {
return ""
}
if strings.Contains(raw, "://") {
if u, err := url.Parse(raw); err == nil {
raw = strings.Trim(u.Path, "/")
}
}
return strings.Trim(raw, "/")
}