Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
Vanessa 2026-02-04 17:29:22 +08:00
commit 0328020aec
4 changed files with 76 additions and 23 deletions

View file

@ -286,6 +286,7 @@ type StageBazaarResult struct {
} }
var stageBazaarFlight singleflight.Group var stageBazaarFlight singleflight.Group
var onlineCheckFlight singleflight.Group
// getStageAndBazaar 获取 stage 索引和 bazaar 索引,相同 pkgType 的并发调用会合并为一次实际请求 (single-flight) // getStageAndBazaar 获取 stage 索引和 bazaar 索引,相同 pkgType 的并发调用会合并为一次实际请求 (single-flight)
func getStageAndBazaar(pkgType string) (result StageBazaarResult) { func getStageAndBazaar(pkgType string) (result StageBazaarResult) {
@ -317,14 +318,13 @@ func getStageAndBazaar0(pkgType string) (result StageBazaarResult) {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel() defer cancel()
var onlineResult bool var onlineResult bool
onlineDone := make(chan bool, 1)
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
wg.Add(3) wg.Add(3)
go func() { go func() {
defer wg.Done() defer wg.Done()
onlineResult = isBazzarOnline() onlineResult = isBazzarOnline()
if !onlineResult { onlineDone <- true
cancel()
}
}() }()
go func() { go func() {
defer wg.Done() defer wg.Done()
@ -334,6 +334,20 @@ func getStageAndBazaar0(pkgType string) (result StageBazaarResult) {
defer wg.Done() defer wg.Done()
bazaarIndex = getBazaarIndex(ctx) bazaarIndex = getBazaarIndex(ctx)
}() }()
<-onlineDone
if !onlineResult {
// 不在线时立即取消其他请求并返回结果,避免等待 HTTP 请求超时
cancel()
return StageBazaarResult{
StageIndex: stageIndex,
BazaarIndex: bazaarIndex,
Online: false,
StageErr: stageErr,
}
}
// 在线时等待所有请求完成
wg.Wait() wg.Wait()
return StageBazaarResult{ return StageBazaarResult{
@ -365,7 +379,7 @@ func getStageIndex(ctx context.Context, pkgType string) (ret *StageIndex, err er
} }
var rhyRet map[string]interface{} var rhyRet map[string]interface{}
rhyRet, err = util.GetRhyResult(false) rhyRet, err = util.GetRhyResult(ctx, false)
if nil != err { if nil != err {
return return
} }
@ -494,7 +508,17 @@ func isOutdatedTemplate(template *Template, bazaarTemplates []*Template) bool {
return false return false
} }
func isBazzarOnline() (ret bool) { func isBazzarOnline() bool {
v, err, _ := onlineCheckFlight.Do("bazaarOnline", func() (interface{}, error) {
return isBazzarOnline0(), nil
})
if err != nil {
return false
}
return v.(bool)
}
func isBazzarOnline0() (ret bool) {
// Improve marketplace loading when offline https://github.com/siyuan-note/siyuan/issues/12050 // Improve marketplace loading when offline https://github.com/siyuan-note/siyuan/issues/12050
ret = util.IsOnline(util.BazaarOSSServer+"/204", true, 3000) ret = util.IsOnline(util.BazaarOSSServer+"/204", true, 3000)
if !ret { if !ret {

View file

@ -214,8 +214,11 @@ func BazaarPlugins(frontend, keyword string) (plugins []*bazaar.Plugin) {
} }
func filterPlugins(plugins []*bazaar.Plugin, keyword string) (ret []*bazaar.Plugin) { func filterPlugins(plugins []*bazaar.Plugin, keyword string) (ret []*bazaar.Plugin) {
ret = []*bazaar.Plugin{}
keywords := getSearchKeywords(keyword) keywords := getSearchKeywords(keyword)
if 0 == len(keywords) {
return plugins
}
ret = []*bazaar.Plugin{}
for _, plugin := range plugins { for _, plugin := range plugins {
if matchPackage(keywords, plugin.Package) { if matchPackage(keywords, plugin.Package) {
ret = append(ret, plugin) ret = append(ret, plugin)
@ -285,8 +288,11 @@ func BazaarWidgets(keyword string) (widgets []*bazaar.Widget) {
} }
func filterWidgets(widgets []*bazaar.Widget, keyword string) (ret []*bazaar.Widget) { func filterWidgets(widgets []*bazaar.Widget, keyword string) (ret []*bazaar.Widget) {
ret = []*bazaar.Widget{}
keywords := getSearchKeywords(keyword) keywords := getSearchKeywords(keyword)
if 0 == len(keywords) {
return widgets
}
ret = []*bazaar.Widget{}
for _, w := range widgets { for _, w := range widgets {
if matchPackage(keywords, w.Package) { if matchPackage(keywords, w.Package) {
ret = append(ret, w) ret = append(ret, w)
@ -337,8 +343,11 @@ func BazaarIcons(keyword string) (icons []*bazaar.Icon) {
} }
func filterIcons(icons []*bazaar.Icon, keyword string) (ret []*bazaar.Icon) { func filterIcons(icons []*bazaar.Icon, keyword string) (ret []*bazaar.Icon) {
ret = []*bazaar.Icon{}
keywords := getSearchKeywords(keyword) keywords := getSearchKeywords(keyword)
if 0 == len(keywords) {
return icons
}
ret = []*bazaar.Icon{}
for _, i := range icons { for _, i := range icons {
if matchPackage(keywords, i.Package) { if matchPackage(keywords, i.Package) {
ret = append(ret, i) ret = append(ret, i)
@ -400,8 +409,11 @@ func BazaarThemes(keyword string) (ret []*bazaar.Theme) {
} }
func filterThemes(themes []*bazaar.Theme, keyword string) (ret []*bazaar.Theme) { func filterThemes(themes []*bazaar.Theme, keyword string) (ret []*bazaar.Theme) {
ret = []*bazaar.Theme{}
keywords := getSearchKeywords(keyword) keywords := getSearchKeywords(keyword)
if 0 == len(keywords) {
return themes
}
ret = []*bazaar.Theme{}
for _, t := range themes { for _, t := range themes {
if matchPackage(keywords, t.Package) { if matchPackage(keywords, t.Package) {
ret = append(ret, t) ret = append(ret, t)
@ -475,8 +487,11 @@ func BazaarTemplates(keyword string) (templates []*bazaar.Template) {
} }
func filterTemplates(templates []*bazaar.Template, keyword string) (ret []*bazaar.Template) { func filterTemplates(templates []*bazaar.Template, keyword string) (ret []*bazaar.Template) {
ret = []*bazaar.Template{}
keywords := getSearchKeywords(keyword) keywords := getSearchKeywords(keyword)
if 0 == len(keywords) {
return templates
}
ret = []*bazaar.Template{}
for _, t := range templates { for _, t := range templates {
if matchPackage(keywords, t.Package) { if matchPackage(keywords, t.Package) {
ret = append(ret, t) ret = append(ret, t)

View file

@ -18,6 +18,7 @@ package model
import ( import (
"bufio" "bufio"
"context"
"crypto/sha256" "crypto/sha256"
"fmt" "fmt"
"io" "io"
@ -120,7 +121,7 @@ func checkDownloadInstallPkg() {
func getUpdatePkg() (downloadPkgURLs []string, checksum string, err error) { func getUpdatePkg() (downloadPkgURLs []string, checksum string, err error) {
defer logging.Recover() defer logging.Recover()
result, err := util.GetRhyResult(false) result, err := util.GetRhyResult(context.TODO(), false)
if err != nil { if err != nil {
return return
} }
@ -246,7 +247,7 @@ type Announcement struct {
} }
func getAnnouncements() (ret []*Announcement) { func getAnnouncements() (ret []*Announcement) {
result, err := util.GetRhyResult(false) result, err := util.GetRhyResult(context.TODO(), false)
if err != nil { if err != nil {
logging.LogErrorf("get announcement failed: %s", err) logging.LogErrorf("get announcement failed: %s", err)
return return
@ -278,7 +279,7 @@ func CheckUpdate(showMsg bool) {
return return
} }
result, err := util.GetRhyResult(showMsg) result, err := util.GetRhyResult(context.TODO(), showMsg)
if err != nil { if err != nil {
return return
} }

View file

@ -17,6 +17,7 @@
package util package util
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"sync" "sync"
@ -24,6 +25,7 @@ import (
"github.com/siyuan-note/httpclient" "github.com/siyuan-note/httpclient"
"github.com/siyuan-note/logging" "github.com/siyuan-note/logging"
"golang.org/x/sync/singleflight"
) )
var ( var (
@ -32,23 +34,34 @@ var (
cachedRhyResult = map[string]interface{}{} cachedRhyResult = map[string]interface{}{}
rhyResultCacheTime int64 rhyResultCacheTime int64
rhyResultLock = sync.Mutex{} rhyResultLock = sync.Mutex{}
rhyResultFlight singleflight.Group
) )
func GetRhyResult(force bool) (map[string]interface{}, error) { func GetRhyResult(ctx context.Context, force bool) (map[string]interface{}, error) {
rhyResultLock.Lock()
defer rhyResultLock.Unlock()
if ContainerDocker == Container { if ContainerDocker == Container {
RhyCacheDuration = int64(3600 * 24) RhyCacheDuration = int64(3600 * 24)
} }
now := time.Now().Unix() if RhyCacheDuration >= time.Now().Unix()-rhyResultCacheTime && !force && 0 < len(cachedRhyResult) {
if RhyCacheDuration >= now-rhyResultCacheTime && !force && 0 < len(cachedRhyResult) {
return cachedRhyResult, nil return cachedRhyResult, nil
} }
// 并发调用只执行一次实际请求
v, err, _ := rhyResultFlight.Do("rhyResult", func() (interface{}, error) {
return getRhyResult0(ctx)
})
if err != nil {
return nil, err
}
return v.(map[string]interface{}), nil
}
func getRhyResult0(ctx context.Context) (map[string]interface{}, error) {
rhyResultLock.Lock()
defer rhyResultLock.Unlock()
request := httpclient.NewCloudRequest30s() request := httpclient.NewCloudRequest30s()
resp, err := request.SetSuccessResult(&cachedRhyResult).Get(GetCloudServer() + "/apis/siyuan/version?ver=" + Ver) resp, err := request.SetContext(ctx).SetSuccessResult(&cachedRhyResult).Get(GetCloudServer() + "/apis/siyuan/version?ver=" + Ver)
if err != nil { if err != nil {
logging.LogErrorf("get version info failed: %s", err) logging.LogErrorf("get version info failed: %s", err)
return nil, err return nil, err
@ -58,17 +71,17 @@ func GetRhyResult(force bool) (map[string]interface{}, error) {
logging.LogErrorf(msg) logging.LogErrorf(msg)
return nil, errors.New(msg) return nil, errors.New(msg)
} }
rhyResultCacheTime = now rhyResultCacheTime = time.Now().Unix()
return cachedRhyResult, nil return cachedRhyResult, nil
} }
func RefreshRhyResultJob() { func RefreshRhyResultJob() {
_, err := GetRhyResult(true) _, err := GetRhyResult(context.TODO(), true)
if nil != err { if nil != err {
// 系统唤醒后可能还没有网络连接,这里等待后再重试 // 系统唤醒后可能还没有网络连接,这里等待后再重试
go func() { go func() {
time.Sleep(7 * time.Second) time.Sleep(7 * time.Second)
GetRhyResult(true) GetRhyResult(context.TODO(), true)
}() }()
} }
} }