diff --git a/cmd/scout-client/main.go b/cmd/scout-client/main.go index f626d10..399e269 100644 --- a/cmd/scout-client/main.go +++ b/cmd/scout-client/main.go @@ -4,7 +4,6 @@ import ( "context" "flag" "fmt" - "io" "os" "path/filepath" "strings" @@ -157,5 +156,3 @@ func printUsage() { fmt.Println("用法:scout-client [参数]") fmt.Println("upload 用于开发者上传,check、download、watch 用于客户端更新流程") } - -var _ io.Reader diff --git a/pkg/client/client.go b/pkg/client/client.go index 7230cc5..da92eca 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -304,9 +304,14 @@ func checkResponse(response *http.Response) error { func readUpdates(ctx context.Context, body io.ReadCloser, updates chan<- Update) { defer close(updates) defer body.Close() + stopCloser := make(chan struct{}) + defer close(stopCloser) go func() { - <-ctx.Done() - _ = body.Close() + select { + case <-ctx.Done(): + _ = body.Close() + case <-stopCloser: + } }() scanner := bufio.NewScanner(body) scanner.Buffer(make([]byte, 4096), 4<<20) diff --git a/使用说明.md b/使用说明.md index dccac49..7bf3c06 100644 --- a/使用说明.md +++ b/使用说明.md @@ -128,3 +128,120 @@ npm.cmd run build ``` 当前版本是可运行的最小版本。后续如果用于公网环境,建议继续增加用户/组织权限、签名包、断点续传、对象存储、数据库索引和通知鉴权。 + +## Go 客户端模块 + +如果你的客户端本身也是 Go 程序,可以直接导入 `scout/pkg/client`,不需要复制 HTTP 请求代码。 + +创建客户端: + +```go +api, err := client.New( + "http://127.0.0.1:8080", + client.WithHTTPClient(http.DefaultClient), +) +if err != nil { + return err +} +``` + +检查更新: + +```go +latest, available, err := api.CheckUpdate(ctx, "demo-core", "1.0.0") +if err != nil { + return err +} +if available { + fmt.Println("发现新版本:", latest.Version) +} +``` + +下载并校验包: + +```go +item, err := api.Download(ctx, "demo-core", latest.Version, "./demo-core.pkg") +if err != nil { + return err +} +fmt.Println("下载完成:", item.SHA256) +``` + +监听更新通知: + +```go +updates, err := api.WatchUpdates(ctx, "demo-core") +if err != nil { + return err +} +for update := range updates { + fmt.Println("收到更新:", update.Package.Name, update.Package.Version) +} +``` + +开发者上传包: + +```go +api, err := client.New( + "http://127.0.0.1:8080", + client.WithDeveloperToken(os.Getenv("SCOUT_DEVELOPER_TOKEN")), +) +if err != nil { + return err +} +file, err := os.Open("./demo-core.pkg") +if err != nil { + return err +} +defer file.Close() +_, err = api.Upload(ctx, client.UploadRequest{ + Name: "demo-core", + Version: "1.1.0", + Description: "示例包", + Platform: "windows", + Architecture: "amd64", + FileName: "demo-core.pkg", + File: file, +}) +return err +``` + +### 客户端接口调用顺序 + +普通客户端更新流程如下: + +```text +1. GET /api/v1/packages/{name} +2. 比较服务端 version 与客户端当前版本 +3. 如果服务端版本更新: +4. GET /api/v1/packages/{name}/{version}/download +5. 读取响应头 X-Scout-SHA256 +6. 下载过程中计算 SHA-256 +7. 校验通过后完成本地包更新 +``` + +实时更新流程如下: + +```text +1. GET /api/v1/updates/stream?packages=包名 +2. 保持 HTTP 连接 +3. 服务端上传新版本后发送 SSE data +4. 客户端收到 package_updated 事件 +5. 再次调用最新版本接口确认元数据 +6. 调用下载接口获取新包 +``` + +`pkg/client` 当前提供的方法: + +| 方法 | 用途 | +| --- | --- | +| `New` | 创建客户端 | +| `ListPackages` | 获取全部包的最新版本 | +| `GetLatest` | 获取指定包的最新版本 | +| `ListVersions` | 获取指定包的全部版本 | +| `CheckUpdate` | 比较当前版本并判断是否有更新 | +| `Download` | 下载指定版本或最新版本,并校验 SHA-256 | +| `WatchUpdates` | 监听 SSE 更新通知 | +| `Upload` | 使用开发者令牌上传包 | + +命令行客户端 `cmd/scout-client` 现在也是基于这个模块实现的,可以作为客户端调用参考。