📊 统计模型
pkg/domain 中描述 Packagist 统计与变更跟踪数据的结构体。对应以下接口:
https://packagist.org/statistics.json→StatisticsResponsehttps://packagist.org/packages/<vendor>/<name>/stats.json→PackageStatsResponsehttps://packagist.org/metadata/changes.json?since=<timestamp>→ChangeTrackingResponse
类型总览
| 类型 | 角色 | 来源接口 |
|---|---|---|
StatisticsResponse | 仓库整体统计顶层 | /statistics.json |
Totals | 仓库总量(下载/包/版本) | 嵌套于 StatisticsResponse |
PackageStatsResponse | 单包下载统计 | /<package>/stats.json |
ChangeTrackingResponse | 元数据变更跟踪响应 | /metadata/changes.json |
ChangeAction | 单条变更操作 | 嵌套于 ChangeTrackingResponse |
📈 StatisticsResponse
Packagist 仓库整体统计的顶层结构。
go
type StatisticsResponse struct {
Totals Totals `json:"totals"`
}| 字段 | 类型 | 说明 |
|---|---|---|
Totals | Totals | 仓库总计统计,见下节 |
🔢 Totals
仓库总体统计信息。
go
type Totals struct {
Downloads int64 `json:"downloads"`
Packages int `json:"packages"`
Versions int `json:"versions"`
}| 字段 | 类型 | 说明 | 示例 |
|---|---|---|---|
Downloads | int64 | 所有包的总下载次数 | 10000000000 |
Packages | int | 仓库中的包总数 | 300000 |
Versions | int | 所有包的版本总数 | 2500000 |
Downloads 用 int64
全站下载量级可达百亿,超过 32 位 int 范围,因此 Downloads 显式使用 int64。做累加或比较时请勿赋给 int 变量(在 32 位平台上会溢出)。
📉 PackageStatsResponse
单个包的下载统计。Downloads 字段复用了 package.md 中的 PackageDownloads 类型。
go
type PackageStatsResponse struct {
Downloads PackageDownloads `json:"downloads"`
Versions []string `json:"versions"`
Date string `json:"date"`
}| 字段 | 类型 | 说明 |
|---|---|---|
Downloads | PackageDownloads | 下载统计(Total/Monthly/Daily) |
Versions | []string | 可用版本列表 |
Date | string | 统计开始日期 |
🔄 ChangeTrackingResponse
元数据变更跟踪响应。用于增量同步:传入一个 since 时间戳,Packagist 返回该时间点之后的所有包变更操作。
go
type ChangeTrackingResponse struct {
Error string `json:"error,omitempty"`
Timestamp int64 `json:"timestamp"`
Actions []ChangeAction `json:"actions,omitempty"`
}| 字段 | 类型 | 说明 |
|---|---|---|
Error | string | 当 since 参数缺失或无效时返回的错误信息(正常时为空) |
Timestamp | int64 | 当前响应的时间戳(Unix 秒) |
Actions | []ChangeAction | 变更操作列表,见下节 |
增量同步模式
典型用法:本地保存上次的 Timestamp,下次请求时作为 since 传入,逐步追赶 Actions 中的 update/delete。若 Error 非空,说明 since 过期或无效,需重新全量同步。
⚡ ChangeAction
单条变更操作。
go
type ChangeAction struct {
Type string `json:"type"`
Package string `json:"package"`
Time int64 `json:"time"`
}| 字段 | 类型 | 说明 | 取值 |
|---|---|---|---|
Type | string | 操作类型 | "update" 或 "delete" |
Package | string | 被操作的包名 | symfony/console |
Time | int64 | 操作发生时间的 Unix 时间戳 | 1700000000 |
🚀 示例
仓库总量统计
go
package main
import (
"fmt"
"log"
"time"
"github.com/scagogogo/composer-skills/pkg/client"
)
func main() {
c := client.NewComposerClient(30 * time.Second)
stats, err := c.GetStatistics()
if err != nil {
log.Fatal(err)
}
fmt.Printf("包总数: %d\n", stats.Totals.Packages)
fmt.Printf("版本总数: %d\n", stats.Totals.Versions)
fmt.Printf("总下载量: %d\n", stats.Totals.Downloads)
}单包下载统计
go
stats, _ := c.GetPackageStats("monolog/monolog")
fmt.Printf("今日下载: %d, 本月: %d, 总计: %d\n",
stats.Downloads.Daily, stats.Downloads.Monthly, stats.Downloads.Total)增量变更跟踪
go
package main
import (
"context"
"fmt"
"log"
"github.com/scagogogo/composer-skills/pkg/client"
)
func main() {
c := client.NewComposerClient(60)
var since int64 = 1700000000 // 上次同步的时间戳
changes, err := c.GetPackageChanges(context.Background(), since)
if err != nil {
log.Fatal(err)
}
if changes.Error != "" {
log.Fatalf("API 返回错误: %s(since 可能已过期,需全量同步)", changes.Error)
}
fmt.Printf("当前时间戳: %d, 变更数: %d\n", changes.Timestamp, len(changes.Actions))
for _, a := range changes.Actions {
fmt.Printf(" [%s] %s @ %d\n", a.Type, a.Package, a.Time)
}
// 下次用 changes.Timestamp 作为新的 since
}📚 相关文档
- 🔙 返回 Domain 概览
- 📦
PackageDownloads定义 → package.md - 🛠️ 创建/列表模型 → create-package.md