mirror of
https://github.com/OpenListTeam/OpenList.git
synced 2026-09-09 17:21:21 +08:00
* feat(drivers/github): add optional accurate modified time
* refactor(github): 简化准确修改时间查询
- 将最多 200 个路径合并到一次 GraphQL history 查询,并用 ^{commit} 统一解析 ref
- 删除分批和冗余响应解析,保留失败降级、tree fallback 与缓存行为
- 使用 JSON 字符串字面量支持控制字符路径,并收敛行为测试
---------
Co-authored-by: Pikachu Ren <40362270+PIKACHUIM@users.noreply.github.com>
107 lines
2.7 KiB
Go
107 lines
2.7 KiB
Go
package github
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/OpenListTeam/OpenList/v4/internal/model"
|
|
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
const (
|
|
mtimeMaxEntries = 200
|
|
githubGraphQLEndpoint = "https://api.github.com/graphql"
|
|
)
|
|
|
|
var githubZeroTime = time.Unix(0, 0)
|
|
|
|
type graphQLHistory struct {
|
|
Nodes []struct {
|
|
CommittedDate time.Time `json:"committedDate"`
|
|
} `json:"nodes"`
|
|
}
|
|
|
|
type graphQLMtimeResponse struct {
|
|
Data struct {
|
|
Repository struct {
|
|
Commit map[string]graphQLHistory `json:"commit"`
|
|
} `json:"repository"`
|
|
} `json:"data"`
|
|
Errors []struct{} `json:"errors"`
|
|
}
|
|
|
|
func quoteGraphQLString(value string) string {
|
|
quoted, _ := json.Marshal(value)
|
|
return string(quoted)
|
|
}
|
|
|
|
func buildMtimeQuery(owner, repo, ref string, objs []model.Obj) string {
|
|
histories := make([]string, 0, len(objs))
|
|
for i, obj := range objs {
|
|
path := strings.TrimPrefix(obj.GetPath(), "/")
|
|
histories = append(histories, fmt.Sprintf(`p%d: history(first: 1, path: %s) { nodes { committedDate } }`, i, quoteGraphQLString(path)))
|
|
}
|
|
|
|
return fmt.Sprintf(`query {
|
|
repository(owner: %s, name: %s) {
|
|
commit: object(expression: %s) {
|
|
... on Commit {
|
|
%s
|
|
}
|
|
}
|
|
}
|
|
}`,
|
|
quoteGraphQLString(owner),
|
|
quoteGraphQLString(repo),
|
|
quoteGraphQLString(ref+"^{commit}"),
|
|
strings.Join(histories, "\n\t\t\t\t"),
|
|
)
|
|
}
|
|
|
|
func (d *Github) fetchAccurateModifiedTimes(ctx context.Context, dirPath string, objs []model.Obj) {
|
|
token := strings.TrimSpace(d.Token)
|
|
if !d.AccurateModifiedTime || token == "" || len(objs) == 0 || len(objs) > mtimeMaxEntries {
|
|
return
|
|
}
|
|
|
|
res, err := d.client.R().
|
|
SetContext(ctx).
|
|
SetHeader("Accept", "application/vnd.github+json").
|
|
SetHeader("Authorization", "Bearer "+token).
|
|
SetBody(map[string]string{"query": buildMtimeQuery(d.Owner, d.Repo, d.Ref, objs)}).
|
|
Post(githubGraphQLEndpoint)
|
|
if err != nil {
|
|
log.WithError(err).Warnf("github accurate mtime failed for %s: transport", dirPath)
|
|
return
|
|
}
|
|
if res.StatusCode() != http.StatusOK {
|
|
log.Warnf("github accurate mtime failed for %s: http_%d", dirPath, res.StatusCode())
|
|
return
|
|
}
|
|
|
|
var response graphQLMtimeResponse
|
|
if err := utils.Json.Unmarshal(res.Body(), &response); err != nil {
|
|
log.WithError(err).Warnf("github accurate mtime failed for %s: graphql", dirPath)
|
|
return
|
|
}
|
|
if len(response.Errors) > 0 || response.Data.Repository.Commit == nil {
|
|
log.Warnf("github accurate mtime failed for %s: graphql", dirPath)
|
|
return
|
|
}
|
|
|
|
for i, obj := range objs {
|
|
history := response.Data.Repository.Commit[fmt.Sprintf("p%d", i)]
|
|
if len(history.Nodes) == 0 {
|
|
continue
|
|
}
|
|
if raw, ok := obj.(*model.Object); ok {
|
|
raw.Modified = history.Nodes[0].CommittedDate
|
|
}
|
|
}
|
|
}
|