Improve marketplace list loading (#16965)

- 直接使用 stage 索引中的 package 数据,不再为每个包单独请求 JSON
- 统一索引获取逻辑,使用 singleflight 合并并发请求
- 优化在线状态检查耗时,改用 https://oss.b3logfile.com/204
- 改进 disallowInstallBazaarPackage 函数性能

Co-authored-by: D <845765@qq.com>
This commit is contained in:
Jeffrey Chen 2026-02-03 10:07:16 +08:00 committed by GitHub
parent 9642f486bd
commit 4eec7b5944
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 385 additions and 473 deletions

View file

@ -22,11 +22,8 @@ import (
"runtime"
"sort"
"strings"
"sync"
"github.com/88250/go-humanize"
ants "github.com/panjf2000/ants/v2"
"github.com/siyuan-note/httpclient"
"github.com/siyuan-note/logging"
"github.com/siyuan-note/siyuan/kernel/util"
)
@ -36,103 +33,70 @@ type Plugin struct {
Enabled bool `json:"enabled"`
}
// Plugins 返回集市插件列表
func Plugins(frontend string) (plugins []*Plugin) {
plugins = []*Plugin{}
result := getStageAndBazaar("plugins")
isOnline := isBazzarOnline()
if !isOnline {
if !result.Online {
return
}
if result.StageErr != nil {
return
}
if 1 > len(result.BazaarIndex) {
return
}
stageIndex, err := getStageIndex("plugins")
if err != nil {
return
for _, repo := range result.StageIndex.Repos {
if nil == repo.Package {
continue
}
plugin := buildPluginFromStageRepo(repo, frontend, result.BazaarIndex)
if nil != plugin {
plugins = append(plugins, plugin)
}
}
bazaarIndex := getBazaarIndex()
if 1 > len(bazaarIndex) {
return
}
requestFailed := false
waitGroup := &sync.WaitGroup{}
lock := &sync.Mutex{}
p, _ := ants.NewPoolWithFunc(8, func(arg interface{}) {
defer waitGroup.Done()
repo := arg.(*StageRepo)
repoURL := repo.URL
if pkg, found := packageCache.Get(repoURL); found {
lock.Lock()
plugins = append(plugins, pkg.(*Plugin))
lock.Unlock()
return
}
if requestFailed {
return
}
plugin := &Plugin{}
innerU := util.BazaarOSSServer + "/package/" + repoURL + "/plugin.json"
innerResp, innerErr := httpclient.NewBrowserRequest().SetSuccessResult(plugin).Get(innerU)
if nil != innerErr {
logging.LogErrorf("get bazaar package [%s] failed: %s", repoURL, innerErr)
requestFailed = true
return
}
if 200 != innerResp.StatusCode {
logging.LogErrorf("get bazaar package [%s] failed: %d", innerU, innerResp.StatusCode)
requestFailed = true
return
}
plugin.DisallowInstall = disallowInstallBazaarPackage(plugin.Package)
plugin.DisallowUpdate = disallowInstallBazaarPackage(plugin.Package)
plugin.UpdateRequiredMinAppVer = plugin.MinAppVersion
plugin.Incompatible = isIncompatiblePlugin(plugin, frontend)
plugin.URL = strings.TrimSuffix(plugin.URL, "/")
repoURLHash := strings.Split(repoURL, "@")
plugin.RepoURL = "https://github.com/" + repoURLHash[0]
plugin.RepoHash = repoURLHash[1]
plugin.PreviewURL = util.BazaarOSSServer + "/package/" + repoURL + "/preview.png?imageslim"
plugin.PreviewURLThumb = util.BazaarOSSServer + "/package/" + repoURL + "/preview.png?imageView2/2/w/436/h/232"
plugin.IconURL = util.BazaarOSSServer + "/package/" + repoURL + "/icon.png"
plugin.Funding = repo.Package.Funding
plugin.PreferredFunding = getPreferredFunding(plugin.Funding)
plugin.PreferredName = GetPreferredName(plugin.Package)
plugin.PreferredDesc = getPreferredDesc(plugin.Description)
plugin.Updated = repo.Updated
plugin.Stars = repo.Stars
plugin.OpenIssues = repo.OpenIssues
plugin.Size = repo.Size
plugin.HSize = humanize.BytesCustomCeil(uint64(plugin.Size), 2)
plugin.InstallSize = repo.InstallSize
plugin.HInstallSize = humanize.BytesCustomCeil(uint64(plugin.InstallSize), 2)
packageInstallSizeCache.SetDefault(plugin.RepoURL, plugin.InstallSize)
plugin.HUpdated = formatUpdated(plugin.Updated)
pkg := bazaarIndex[strings.Split(repoURL, "@")[0]]
if nil != pkg {
plugin.Downloads = pkg.Downloads
}
lock.Lock()
plugins = append(plugins, plugin)
lock.Unlock()
packageCache.SetDefault(repoURL, plugin)
})
for _, repo := range stageIndex.Repos {
waitGroup.Add(1)
p.Invoke(repo)
}
waitGroup.Wait()
p.Release()
sort.Slice(plugins, func(i, j int) bool { return plugins[i].Updated > plugins[j].Updated })
return
}
// buildPluginFromStageRepo 使用 stage 内嵌的 package 构建 *Plugin不发起 HTTP 请求。
func buildPluginFromStageRepo(repo *StageRepo, frontend string, bazaarIndex map[string]*bazaarPackage) *Plugin {
pkg := *repo.Package
pkg.URL = strings.TrimSuffix(pkg.URL, "/")
repoURLHash := strings.Split(repo.URL, "@")
if 2 != len(repoURLHash) {
return nil
}
pkg.RepoURL = "https://github.com/" + repoURLHash[0]
pkg.RepoHash = repoURLHash[1]
pkg.PreviewURL = util.BazaarOSSServer + "/package/" + repo.URL + "/preview.png?imageslim"
pkg.PreviewURLThumb = util.BazaarOSSServer + "/package/" + repo.URL + "/preview.png?imageView2/2/w/436/h/232"
pkg.IconURL = util.BazaarOSSServer + "/package/" + repo.URL + "/icon.png"
pkg.Updated = repo.Updated
pkg.Stars = repo.Stars
pkg.OpenIssues = repo.OpenIssues
pkg.Size = repo.Size
pkg.HSize = humanize.BytesCustomCeil(uint64(pkg.Size), 2)
pkg.InstallSize = repo.InstallSize
pkg.HInstallSize = humanize.BytesCustomCeil(uint64(pkg.InstallSize), 2)
pkg.HUpdated = formatUpdated(pkg.Updated)
pkg.PreferredFunding = getPreferredFunding(pkg.Funding)
pkg.PreferredName = GetPreferredName(&pkg)
pkg.PreferredDesc = getPreferredDesc(pkg.Description)
pkg.DisallowInstall = disallowInstallBazaarPackage(&pkg)
pkg.DisallowUpdate = disallowInstallBazaarPackage(&pkg)
pkg.UpdateRequiredMinAppVer = pkg.MinAppVersion
pkg.Incompatible = isIncompatiblePlugin(&Plugin{Package: &pkg}, frontend)
if bp := bazaarIndex[repoURLHash[0]]; nil != bp {
pkg.Downloads = bp.Downloads
}
packageInstallSizeCache.SetDefault(pkg.RepoURL, pkg.InstallSize)
return &Plugin{Package: &pkg}
}
func ParseInstalledPlugin(name, frontend string) (found bool, displayName string, incompatible, disabledInPublish, disallowInstall bool) {
pluginsPath := filepath.Join(util.DataDir, "plugins")
if !util.IsPathRegularDirOrSymlinkDir(pluginsPath) {