Skip to content

Commit

Permalink
[feature] 增加一个随机图片接口
Browse files Browse the repository at this point in the history
  • Loading branch information
kyrie committed Jan 27, 2023
1 parent e223bb0 commit 9f28a74
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 1 deletion.
8 changes: 7 additions & 1 deletion cmd/api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"

"git.vtb.link/eoefans/internal/app"
"git.vtb.link/eoefans/internal/app/api/service"
"git.vtb.link/eoefans/internal/launcher"
"git.vtb.link/eoefans/internal/pkg/database"
"git.vtb.link/eoefans/internal/pkg/httpserver"
Expand All @@ -23,7 +24,7 @@ func newAPI() fx.Option {
)
}

func lc(lifecycle fx.Lifecycle, ginServer *httpserver.Server) {
func lc(lifecycle fx.Lifecycle, ginServer *httpserver.Server, randPicsCache *service.RandomPicsCache) {
lifecycle.Append(fx.Hook{
OnStart: func(ctx context.Context) error {
return ginServer.Start()
Expand All @@ -32,4 +33,9 @@ func lc(lifecycle fx.Lifecycle, ginServer *httpserver.Server) {
return ginServer.Stop()
},
})
lifecycle.Append(fx.Hook{
OnStart: func(ctx context.Context) error {
return randPicsCache.Run()
},
})
}
11 changes: 11 additions & 0 deletions internal/app/api/handler/bilbil_picture.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,14 @@ func BilibiliRecommendPics(s *service.BilbilPicture) func(ctx *gin.Context) {
}
}
}

func BilibiliRandomPic(s *service.BilbilPicture) func(ctx *gin.Context) {
return func(ctx *gin.Context) {
if resp, err := s.Random(ctx); err != nil {
_ = ctx.Error(err)
return
} else {
ctx.JSON(http.StatusOK, help.SuccessJson(resp))
}
}
}
5 changes: 5 additions & 0 deletions internal/app/api/idl/bilibili_picture.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ type BilibiliPicturesRecommendResp struct {
Page int `json:"page"`
Total int `json:"total"`
}

type BilibiliPictureRandomResp struct {
BilibiliDynamicPicture
}
type BilibiliDynamicDTO struct {
DynamicID uint64 `json:"dynamic_id"`
Pictures BilibiliDynamicPictures `json:"pictures"`
Expand All @@ -90,4 +94,5 @@ type BilibiliPictureRepository interface {
FindAllByPubDate(from, to time.Time, page, size int64) (list []*BilibiliDynamic, err error)
Latest(page, size, topicID int) (list []*BilibiliDynamic, err error)
Recommend(from, to time.Time, page, size, topicID int) (list []*BilibiliDynamic, err error)
Random(rand float64) (list []*BilibiliDynamic, err error)
}
1 change: 1 addition & 0 deletions internal/app/api/router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func InitRouters(
{
picApi.GET("/latest", handler.BilibiliLatestPics(picService))
picApi.GET("/recommend", handler.BilibiliRecommendPics(picService))
picApi.GET("/random", handler.BilibiliRandomPic(picService))
}
// Auth相关
authApi := r.Group("/v1/auth")
Expand Down
107 changes: 107 additions & 0 deletions internal/app/api/service/bilbil_picture.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,88 @@ package service

import (
"context"
"errors"
"math/rand"
"sync"
"time"

"git.vtb.link/eoefans/internal/app/api/idl"
"git.vtb.link/eoefans/internal/repository"
"go.uber.org/zap"
"gorm.io/gorm"
)

const (
picRecommendDefaultSize = 20
)

type RandomPicKey string

const (
overall RandomPicKey = "overall"
)

var (
errRandomPictureNotFound = errors.New("random picture was not found")
)
var (
randomPicsCache *RandomPicsCache = &RandomPicsCache{
syncMap: &sync.Map{},
}
)

type RandomPicsCache struct {
syncMap *sync.Map
success bool
db *gorm.DB
log *zap.Logger
}

func NewRandomPicsCache(db *gorm.DB, log *zap.Logger) *RandomPicsCache {
randomPicsCache.db = db
randomPicsCache.log = log
return randomPicsCache
}

func (c *RandomPicsCache) Run() error {
tk := time.NewTicker(5 * time.Second)
go func() {
c.flush()
}()
go func(_tk *time.Ticker) {
for {
select {
case <-_tk.C:
c.flush()
default:
continue
}
}
}(tk)
return nil
}

func (c *RandomPicsCache) flush() {
now := time.Now()
rand.Seed(now.UnixNano())
tx := c.db.WithContext(context.Background())
picRepository := repository.NewBilibiliPicture(tx)
list, err := picRepository.Random(rand.Float64())
if err != nil || len(list) == 0 {
c.success = false
c.log.Error("randomPicsCache flush error ", zap.Error(err), zap.Time("time", now), zap.Int("list", len(list)))
return
}
pictures := make(idl.BilibiliDynamicPictures, 0)
for i := range list {
for j := range list[i].Pictures {
pictures = append(pictures, list[i].Pictures[j])
}
}
c.syncMap.Store(overall, pictures)
c.success = true
}

type BilbilPicture struct {
db *gorm.DB
}
Expand Down Expand Up @@ -63,3 +134,39 @@ func (service *BilbilPicture) Recommend(ctx context.Context, req idl.BilibiliPic
}
return &resp, nil
}

func (service *BilbilPicture) Random(ctx context.Context) (*idl.BilibiliPictureRandomResp, error) {
if randomPicsCache.success {
value, ok := randomPicsCache.syncMap.Load(overall)
if ok {
pictures, ok := value.(idl.BilibiliDynamicPictures)
if ok && len(pictures) != 0 {
idx := rand.Intn(len(pictures))
resp := &idl.BilibiliPictureRandomResp{}
resp.BilibiliDynamicPicture = pictures[idx]
return resp, nil
}
}
}
now := time.Now()
rand.Seed(now.UnixNano())
tx := service.db.WithContext(ctx)
picRepository := repository.NewBilibiliPicture(tx)
list, err := picRepository.Random(rand.Float64())
if err != nil {
return nil, err
}
if len(list) == 0 {
return nil, errRandomPictureNotFound
}
pictures := make(idl.BilibiliDynamicPictures, 0)
for i := range list {
for j := range list[i].Pictures {
pictures = append(pictures, list[i].Pictures[j])
}
}
idx := rand.Intn(len(pictures))
resp := &idl.BilibiliPictureRandomResp{}
resp.BilibiliDynamicPicture = pictures[idx]
return resp, nil
}
1 change: 1 addition & 0 deletions internal/app/provide.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,6 @@ func ServiceProvider() fx.Option {
service.NewAuth,
service.NewUser,
service.NewTool,
service.NewRandomPicsCache,
)
}
20 changes: 20 additions & 0 deletions internal/repository/bilibili_picture.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package repository

import (
"math"
"time"

"git.vtb.link/eoefans/internal/app/api/idl"
Expand Down Expand Up @@ -90,3 +91,22 @@ func (impl *BilibiliPictureMysqlImpl) Recommend(from, to time.Time, page, size,
}
return list, nil
}

func (impl *BilibiliPictureMysqlImpl) Random(rand float64) (list []*idl.BilibiliDynamic, err error) {
conn := impl.tx.Table(idl.BilibiliDynamic{}.TableName())
type Pair struct {
MaxId float64
MinId float64
}
var pair Pair
err = conn.Select("max(id) as max_id,min(id) as min_id").Scan(&pair).Error
if err != nil {
return nil, err
}
offset := math.Floor((pair.MaxId - pair.MinId) * rand)
err = conn.Where("id >= ?", uint64(pair.MinId+offset)).Select("pictures").Limit(5).Find(&list).Error
if err != nil {
return nil, err
}
return list, nil
}

0 comments on commit 9f28a74

Please sign in to comment.