99 lines
2.7 KiB
Go
99 lines
2.7 KiB
Go
package app
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"douyu_go/internal/constants"
|
|
"douyu_go/internal/logger"
|
|
"douyu_go/internal/types"
|
|
"douyu_go/internal/utils"
|
|
)
|
|
|
|
// LoadProducts 刷新商品列表。refresh=true 时从斗鱼实时拉取。
|
|
func (a *App) LoadProducts(refresh bool) types.ProductPayload {
|
|
if refresh {
|
|
cfg := a.getCfg()
|
|
options := types.XiaodianProductListOptions{PageSize: cfg.XiaodianPageSize}
|
|
var products []types.Product
|
|
err := fmt.Errorf("没有可用账号 Cookie")
|
|
accounts := a.scheduler.AccountSnapshot()
|
|
for _, account := range accounts {
|
|
if strings.TrimSpace(account.Cookie) == "" {
|
|
continue
|
|
}
|
|
products, err = a.getClient().Products(account.Cookie, options)
|
|
if err == nil {
|
|
break
|
|
}
|
|
logger.LogEvent("商品", "warn", "账号 %s 获取和平小店角色失败,尝试下一个账号: %v", account.Name, err)
|
|
}
|
|
if err != nil {
|
|
logger.LogEvent("商品", "error", "商品刷新失败: %v", err)
|
|
return types.ProductPayload{Success: false}
|
|
}
|
|
fetchedAt := time.Now()
|
|
a.setProducts(products, fetchedAt)
|
|
logger.LogEvent("商品", "success", "商品刷新完成: %d 个,刷新时间=%s", len(products), fetchedAt.In(constants.CST).Format("15:04:05.000"))
|
|
return a.productPayload("live")
|
|
}
|
|
return a.productPayload("cache")
|
|
}
|
|
|
|
// GetAccounts 返回账号列表。
|
|
func (a *App) GetAccounts() []types.AccountView {
|
|
accounts := a.scheduler.AccountSnapshot()
|
|
list := make([]types.AccountView, 0, len(accounts))
|
|
for i, account := range accounts {
|
|
list = append(list, types.AccountView{
|
|
Index: i,
|
|
Name: account.Name,
|
|
Cookie: utils.MaskCookie(account.Cookie),
|
|
})
|
|
}
|
|
return list
|
|
}
|
|
|
|
// ReloadAccounts 重新加载内部账号库。
|
|
func (a *App) ReloadAccounts() types.ReloadAccountsResult {
|
|
a.scheduler.LoadAccounts()
|
|
return types.ReloadAccountsResult{Success: true, Count: a.scheduler.AccountCount()}
|
|
}
|
|
|
|
// ==================== 内部辅助方法 ====================
|
|
|
|
func (a *App) setProducts(products []types.Product, fetchedAt time.Time) {
|
|
a.productsMu.Lock()
|
|
a.products = products
|
|
a.productsAt = fetchedAt
|
|
a.productsMu.Unlock()
|
|
if a.scheduler != nil {
|
|
a.scheduler.UpdateProducts(products)
|
|
}
|
|
}
|
|
|
|
func (a *App) productPayload(source string) types.ProductPayload {
|
|
a.productsMu.RLock()
|
|
defer a.productsMu.RUnlock()
|
|
|
|
payload := types.ProductPayload{
|
|
Success: true,
|
|
Source: source,
|
|
Products: a.products,
|
|
Count: len(a.products),
|
|
}
|
|
if !a.productsAt.IsZero() {
|
|
age := time.Since(a.productsAt)
|
|
if age < 0 {
|
|
age = 0
|
|
}
|
|
payload.FetchedAt = a.productsAt.In(constants.CST).Format("2006-01-02 15:04:05.000")
|
|
payload.AgeSecond = int(age.Seconds())
|
|
payload.Stale = age > constants.ProductCacheTTL
|
|
} else {
|
|
payload.Stale = true
|
|
}
|
|
return payload
|
|
}
|