From 2875f4460662bf8f0dd1f4d9f317c3325a76de57 Mon Sep 17 00:00:00 2001 From: zijiren233 Date: Sat, 9 Dec 2023 00:08:19 +0800 Subject: [PATCH] Fix: cache and vendor db error --- internal/db/db.go | 8 ++- internal/op/movie.go | 12 ++-- server/handlers/movie.go | 62 ++++++++----------- server/handlers/vendors/vendorAlist/me.go | 16 ++++- server/handlers/vendors/vendorAlist/parse.go | 2 +- .../vendors/vendorBilibili/bilibili.go | 19 +++--- server/handlers/vendors/vendorBilibili/me.go | 18 +++++- server/model/vendor.go | 6 ++ utils/utils.go | 2 +- 9 files changed, 89 insertions(+), 56 deletions(-) create mode 100644 server/model/vendor.go diff --git a/internal/db/db.go b/internal/db/db.go index 96a979d..e9513f7 100644 --- a/internal/db/db.go +++ b/internal/db/db.go @@ -286,9 +286,15 @@ func WhereRoomUserStatus(status model.RoomUserStatus) func(db *gorm.DB) *gorm.DB } } +type ErrNotFound string + +func (e ErrNotFound) Error() string { + return fmt.Sprintf("%s not found", string(e)) +} + func HandleNotFound(err error, errMsg ...string) error { if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { - return fmt.Errorf("%s not found", strings.Join(errMsg, " ")) + return ErrNotFound(strings.Join(errMsg, " ")) } return err } diff --git a/internal/op/movie.go b/internal/op/movie.go index feb648f..f422410 100644 --- a/internal/op/movie.go +++ b/internal/op/movie.go @@ -12,7 +12,6 @@ import ( "github.com/synctv-org/synctv/internal/model" "github.com/synctv-org/synctv/internal/settings" "github.com/synctv-org/synctv/utils" - "github.com/zijiren233/gencontainer/refreshcache" "github.com/zijiren233/livelib/av" "github.com/zijiren233/livelib/container/flv" "github.com/zijiren233/livelib/protocol/hls" @@ -31,12 +30,12 @@ type Movie struct { type BaseCache struct { lock sync.RWMutex - cache map[string]*refreshcache.RefreshCache[any] + cache map[string]any } func newBaseCache() *BaseCache { return &BaseCache{ - cache: make(map[string]*refreshcache.RefreshCache[any]), + cache: make(map[string]any), } } @@ -50,7 +49,7 @@ func (b *BaseCache) clear() { maps.Clear(b.cache) } -func (b *BaseCache) InitOrLoadCache(id string, refreshFunc func() (any, error), maxAge time.Duration) (*refreshcache.RefreshCache[any], error) { +func (b *BaseCache) InitOrLoadCache(id string, refreshFunc func() (any, error), maxAge time.Duration) (any, error) { b.lock.RLock() c, loaded := b.cache[id] if loaded { @@ -66,7 +65,10 @@ func (b *BaseCache) InitOrLoadCache(id string, refreshFunc func() (any, error), return c, nil } - c = refreshcache.NewRefreshCache[any](refreshFunc, maxAge) + c, err := refreshFunc() + if err != nil { + return nil, err + } b.cache[id] = c return c, nil } diff --git a/server/handlers/movie.go b/server/handlers/movie.go index 5f1503d..3c731a0 100644 --- a/server/handlers/movie.go +++ b/server/handlers/movie.go @@ -469,12 +469,7 @@ func ProxyMovie(ctx *gin.Context) { switch m.Movie.Base.Type { case "mpd": - mpdCache, err := m.Cache().InitOrLoadCache("", initDashCache(ctx, &m.Movie), time.Minute*5) - if err != nil { - ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err)) - return - } - mpdI, err := mpdCache.Get() + mpdI, err := m.Cache().InitOrLoadCache("", initDashCache(ctx, &m.Movie), time.Minute*5) if err != nil { ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err)) return @@ -673,16 +668,21 @@ type bilibiliCache struct { func initBilibiliMPDCache(ctx context.Context, movie dbModel.Movie) func() (any, error) { return func() (any, error) { - v, err := db.FirstOrCreateVendorByUserIDAndVendor(movie.CreatorID, dbModel.StreamingVendorBilibili) + var cookies []*http.Cookie + vendorInfo, err := db.GetVendorByUserIDAndVendor(movie.CreatorID, dbModel.StreamingVendorBilibili) if err != nil { - return nil, err + if !errors.Is(err, db.ErrNotFound("vendor")) { + return nil, err + } + } else { + cookies = vendorInfo.Cookies } cli := vendor.BilibiliClient(movie.Base.VendorInfo.Backend) var m, hevcM *mpd.MPD biliInfo := movie.Base.VendorInfo.Bilibili if biliInfo.Bvid != "" && biliInfo.Cid != 0 { resp, err := cli.GetDashVideoURL(ctx, &bilibili.GetDashVideoURLReq{ - Cookies: utils.HttpCookieToMap(v.Cookies), + Cookies: utils.HttpCookieToMap(cookies), Bvid: biliInfo.Bvid, Cid: biliInfo.Cid, }) @@ -700,7 +700,7 @@ func initBilibiliMPDCache(ctx context.Context, movie dbModel.Movie) func() (any, } else if biliInfo.Epid != 0 { resp, err := cli.GetDashPGCURL(ctx, &bilibili.GetDashPGCURLReq{ - Cookies: utils.HttpCookieToMap(v.Cookies), + Cookies: utils.HttpCookieToMap(cookies), Epid: biliInfo.Epid, }) if err != nil { @@ -761,34 +761,39 @@ func initBilibiliMPDCache(ctx context.Context, movie dbModel.Movie) func() (any, func initBilibiliShareCache(ctx context.Context, movie dbModel.Movie) func() (any, error) { return func() (any, error) { - v, err := db.FirstOrCreateVendorByUserIDAndVendor(movie.CreatorID, dbModel.StreamingVendorBilibili) + var cookies []*http.Cookie + vendorInfo, err := db.GetVendorByUserIDAndVendor(movie.CreatorID, dbModel.StreamingVendorBilibili) if err != nil { - return "", err + if !errors.Is(err, db.ErrNotFound("vendor")) { + return nil, err + } + } else { + cookies = vendorInfo.Cookies } cli := vendor.BilibiliClient(movie.Base.VendorInfo.Backend) var u string biliInfo := movie.Base.VendorInfo.Bilibili if biliInfo.Bvid != "" { resp, err := cli.GetVideoURL(ctx, &bilibili.GetVideoURLReq{ - Cookies: utils.HttpCookieToMap(v.Cookies), + Cookies: utils.HttpCookieToMap(cookies), Bvid: biliInfo.Bvid, Cid: biliInfo.Cid, }) if err != nil { - return "", err + return nil, err } u = resp.Url } else if biliInfo.Epid != 0 { resp, err := cli.GetPGCURL(ctx, &bilibili.GetPGCURLReq{ - Cookies: utils.HttpCookieToMap(v.Cookies), + Cookies: utils.HttpCookieToMap(cookies), Epid: biliInfo.Epid, }) if err != nil { - return "", err + return nil, err } u = resp.Url } else { - return "", errors.New("bvid and epid are empty") + return nil, errors.New("bvid and epid are empty") } return u, nil } @@ -800,7 +805,7 @@ type alistCache struct { func initAlistCache(ctx context.Context, movie dbModel.Movie) func() (any, error) { return func() (any, error) { - v, err := db.FirstOrCreateVendorByUserIDAndVendor(movie.CreatorID, dbModel.StreamingVendorAlist) + v, err := db.GetVendorByUserIDAndVendor(movie.CreatorID, dbModel.StreamingVendorAlist) if err != nil { return nil, err } @@ -849,12 +854,7 @@ func proxyVendorMovie(ctx *gin.Context, movie *op.Movie) { if t != "hevc" { t = "" } - bvc, err := movie.Cache().InitOrLoadCache(t, initBilibiliMPDCache(ctx, movie.Movie), time.Minute*119) - if err != nil { - ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err)) - return - } - mpdI, err := bvc.Get() + mpdI, err := movie.Cache().InitOrLoadCache(t, initBilibiliMPDCache(ctx, movie.Movie), time.Minute*119) if err != nil { ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err)) return @@ -899,12 +899,7 @@ func parse2VendorMovie(ctx context.Context, userID string, movie *op.Movie) (err switch movie.Movie.Base.VendorInfo.Vendor { case dbModel.StreamingVendorBilibili: if !movie.Movie.Base.Proxy { - cache, err := movie.Cache().InitOrLoadCache(userID, initBilibiliShareCache(ctx, movie.Movie), time.Minute*119) - if err != nil { - return err - } - - dataI, err := cache.Get() + dataI, err := movie.Cache().InitOrLoadCache(userID, initBilibiliShareCache(ctx, movie.Movie), time.Minute*119) if err != nil { return err } @@ -921,12 +916,7 @@ func parse2VendorMovie(ctx context.Context, userID string, movie *op.Movie) (err return nil case dbModel.StreamingVendorAlist: - cache, err := movie.Cache().InitOrLoadCache("", initAlistCache(ctx, movie.Movie), time.Minute*15) - if err != nil { - return err - } - - dataI, err := cache.Get() + dataI, err := movie.Cache().InitOrLoadCache("", initAlistCache(ctx, movie.Movie), time.Minute*15) if err != nil { return err } diff --git a/server/handlers/vendors/vendorAlist/me.go b/server/handlers/vendors/vendorAlist/me.go index 80b3d32..b60f51a 100644 --- a/server/handlers/vendors/vendorAlist/me.go +++ b/server/handlers/vendors/vendorAlist/me.go @@ -1,6 +1,7 @@ package vendorAlist import ( + "errors" "net/http" "github.com/gin-gonic/gin" @@ -12,10 +13,18 @@ import ( "github.com/synctv-org/vendors/api/alist" ) +type AlistMeResp = model.VendorMeResp[*alist.MeResp] + func Me(ctx *gin.Context) { user := ctx.MustGet("user").(*op.User) - v, err := db.FirstOrCreateVendorByUserIDAndVendor(user.ID, dbModel.StreamingVendorAlist) + v, err := db.GetVendorByUserIDAndVendor(user.ID, dbModel.StreamingVendorAlist) if err != nil { + if errors.Is(err, db.ErrNotFound("vendor")) { + ctx.JSON(http.StatusOK, model.NewApiDataResp(&AlistMeResp{ + IsLogin: false, + })) + return + } ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err)) return } @@ -29,5 +38,8 @@ func Me(ctx *gin.Context) { return } - ctx.JSON(http.StatusOK, model.NewApiDataResp(resp)) + ctx.JSON(http.StatusOK, model.NewApiDataResp(&AlistMeResp{ + IsLogin: false, + Info: resp, + })) } diff --git a/server/handlers/vendors/vendorAlist/parse.go b/server/handlers/vendors/vendorAlist/parse.go index d3d8205..90cce20 100644 --- a/server/handlers/vendors/vendorAlist/parse.go +++ b/server/handlers/vendors/vendorAlist/parse.go @@ -40,7 +40,7 @@ func List(ctx *gin.Context) { return } - v, err := db.FirstOrCreateVendorByUserIDAndVendor(user.ID, dbModel.StreamingVendorAlist) + v, err := db.GetVendorByUserIDAndVendor(user.ID, dbModel.StreamingVendorAlist) if err != nil { ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err)) return diff --git a/server/handlers/vendors/vendorBilibili/bilibili.go b/server/handlers/vendors/vendorBilibili/bilibili.go index 13e98a5..ed54ae4 100644 --- a/server/handlers/vendors/vendorBilibili/bilibili.go +++ b/server/handlers/vendors/vendorBilibili/bilibili.go @@ -50,16 +50,21 @@ func Parse(ctx *gin.Context) { return } - v, err := db.FirstOrCreateVendorByUserIDAndVendor(user.ID, dbModel.StreamingVendorBilibili) + var cookies []*http.Cookie + vendorInfo, err := db.GetVendorByUserIDAndVendor(user.ID, dbModel.StreamingVendorBilibili) if err != nil { - ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err)) - return + if !errors.Is(err, db.ErrNotFound("vendor")) { + ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err)) + return + } + } else { + cookies = vendorInfo.Cookies } switch resp.Type { case "bv": resp, err := cli.ParseVideoPage(ctx, &bilibili.ParseVideoPageReq{ - Cookies: utils.HttpCookieToMap(v.Cookies), + Cookies: utils.HttpCookieToMap(cookies), Bvid: resp.Id, Sections: ctx.DefaultQuery("sections", "false") == "true", }) @@ -75,7 +80,7 @@ func Parse(ctx *gin.Context) { return } resp, err := cli.ParseVideoPage(ctx, &bilibili.ParseVideoPageReq{ - Cookies: utils.HttpCookieToMap(v.Cookies), + Cookies: utils.HttpCookieToMap(cookies), Aid: aid, Sections: ctx.DefaultQuery("sections", "false") == "true", }) @@ -91,7 +96,7 @@ func Parse(ctx *gin.Context) { return } resp, err := cli.ParsePGCPage(ctx, &bilibili.ParsePGCPageReq{ - Cookies: utils.HttpCookieToMap(v.Cookies), + Cookies: utils.HttpCookieToMap(cookies), Epid: epid, }) if err != nil { @@ -106,7 +111,7 @@ func Parse(ctx *gin.Context) { return } resp, err := cli.ParsePGCPage(ctx, &bilibili.ParsePGCPageReq{ - Cookies: utils.HttpCookieToMap(v.Cookies), + Cookies: utils.HttpCookieToMap(cookies), Ssid: ssid, }) if err != nil { diff --git a/server/handlers/vendors/vendorBilibili/me.go b/server/handlers/vendors/vendorBilibili/me.go index 6b3b93d..011f018 100644 --- a/server/handlers/vendors/vendorBilibili/me.go +++ b/server/handlers/vendors/vendorBilibili/me.go @@ -1,6 +1,7 @@ package vendorBilibili import ( + "errors" "net/http" "github.com/gin-gonic/gin" @@ -13,15 +14,23 @@ import ( "github.com/synctv-org/vendors/api/bilibili" ) +type BilibiliMeResp = model.VendorMeResp[*bilibili.UserInfoResp] + func Me(ctx *gin.Context) { user := ctx.MustGet("user").(*op.User) - v, err := db.FirstOrCreateVendorByUserIDAndVendor(user.ID, dbModel.StreamingVendorBilibili) + v, err := db.GetVendorByUserIDAndVendor(user.ID, dbModel.StreamingVendorBilibili) if err != nil { + if errors.Is(err, db.ErrNotFound("vendor")) { + ctx.JSON(http.StatusOK, model.NewApiDataResp(&BilibiliMeResp{ + IsLogin: false, + })) + return + } ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err)) return } if len(v.Cookies) == 0 { - ctx.JSON(http.StatusOK, model.NewApiDataResp(&bilibili.UserInfoResp{ + ctx.JSON(http.StatusOK, model.NewApiDataResp(&BilibiliMeResp{ IsLogin: false, })) return @@ -34,5 +43,8 @@ func Me(ctx *gin.Context) { return } - ctx.JSON(http.StatusOK, model.NewApiDataResp(resp)) + ctx.JSON(http.StatusOK, model.NewApiDataResp(&BilibiliMeResp{ + IsLogin: resp.IsLogin, + Info: resp, + })) } diff --git a/server/model/vendor.go b/server/model/vendor.go new file mode 100644 index 0000000..1aece34 --- /dev/null +++ b/server/model/vendor.go @@ -0,0 +1,6 @@ +package model + +type VendorMeResp[T any] struct { + IsLogin bool `json:"isLogin"` + Info T `json:"info,omitempty"` +} diff --git a/utils/utils.go b/utils/utils.go index 653f08b..70ca11a 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -314,7 +314,7 @@ func SortUUID() string { } func HttpCookieToMap(c []*http.Cookie) map[string]string { - m := make(map[string]string) + m := make(map[string]string, len(c)) for _, v := range c { m[v.Name] = v.Value }