You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
406 lines
9.3 KiB
406 lines
9.3 KiB
package daily |
|
|
|
import ( |
|
"context" |
|
"fmt" |
|
"strconv" |
|
"time" |
|
|
|
"go-common/app/interface/main/app-show/conf" |
|
arcdao "go-common/app/interface/main/app-show/dao/archive" |
|
carddao "go-common/app/interface/main/app-show/dao/card" |
|
tagdao "go-common/app/interface/main/app-show/dao/tag" |
|
"go-common/app/interface/main/app-show/model" |
|
"go-common/app/interface/main/app-show/model/card" |
|
"go-common/app/interface/main/app-show/model/daily" |
|
"go-common/app/service/main/archive/api" |
|
"go-common/library/log" |
|
) |
|
|
|
const ( |
|
_initDailyKey = "daily_key_%d_%d" |
|
_initColumnKey = "column_key_%d_%d" |
|
_initColumnListKey = "columnlist_key_%d_%d" |
|
) |
|
|
|
var ( |
|
_emptyDaily = []*daily.Show{} |
|
_emptyList = []*daily.Item{} |
|
) |
|
|
|
type Service struct { |
|
c *conf.Config |
|
cdao *carddao.Dao |
|
arc *arcdao.Dao |
|
tag *tagdao.Dao |
|
// tick |
|
tick time.Duration |
|
// columnsCache |
|
columnsCache map[string]*card.Column |
|
// card |
|
cardCache map[string][]*daily.Show |
|
columnCache map[string]*daily.Show |
|
columnListCache map[string][]*daily.Item |
|
cardListCache map[string][]*card.ColumnList |
|
} |
|
|
|
// New new a daily service. |
|
func New(c *conf.Config) (s *Service) { |
|
s = &Service{ |
|
c: c, |
|
cdao: carddao.New(c), |
|
arc: arcdao.New(c), |
|
tag: tagdao.New(c), |
|
// tick |
|
tick: time.Duration(c.Tick), |
|
// columnsCache |
|
columnsCache: map[string]*card.Column{}, |
|
// card |
|
cardCache: map[string][]*daily.Show{}, |
|
columnCache: map[string]*daily.Show{}, |
|
columnListCache: map[string][]*daily.Item{}, |
|
cardListCache: map[string][]*card.ColumnList{}, |
|
} |
|
now := time.Now() |
|
s.loadColumnListCache(now) |
|
s.loadColumnsCache() |
|
s.loadNperCache(now) |
|
go s.cacheproc() |
|
return |
|
} |
|
|
|
// Daily |
|
func (s *Service) Daily(c context.Context, plat int8, build, dailyID, pn, ps int) (res []*daily.Show) { |
|
if pn > 0 { |
|
pn = pn - 1 |
|
} |
|
start := pn * ps |
|
end := start + ps |
|
key := fmt.Sprintf(_initColumnKey, plat, dailyID) |
|
if column, ok := s.columnsCache[key]; ok { |
|
if model.InvalidBuild(build, column.Build, column.Condition) { |
|
res = _emptyDaily |
|
return |
|
} |
|
cardKey := fmt.Sprintf(_initDailyKey, plat, dailyID) |
|
if cards, ok := s.cardCache[cardKey]; ok { |
|
for _, sw := range cards { |
|
if model.InvalidBuild(build, sw.Build, sw.Condition) { |
|
continue |
|
} |
|
res = append(res, sw) |
|
} |
|
resLen := len(res) |
|
if resLen > end { |
|
res = res[start:end] |
|
} else if resLen > start { |
|
res = res[start:] |
|
} else { |
|
res = _emptyDaily |
|
} |
|
} |
|
} |
|
if len(res) == 0 { |
|
res = _emptyDaily |
|
} |
|
return |
|
} |
|
|
|
// ColumnList |
|
func (s *Service) ColumnList(plat int8, build, columnID int) (res *daily.ColumnList) { |
|
var ( |
|
column []*daily.ColumnList |
|
) |
|
key := fmt.Sprintf(_initColumnListKey, plat, columnID) |
|
if columns, ok := s.cardListCache[key]; ok { |
|
for _, c := range columns { |
|
if model.InvalidBuild(build, c.Build, c.Condition) { |
|
continue |
|
} |
|
tmp := &daily.ColumnList{ |
|
Cid: c.Cid, |
|
Name: c.Name, |
|
Ceid: c.Ceid, |
|
Cname: c.Cname, |
|
} |
|
column = append(column, tmp) |
|
} |
|
if len(column) > 0 { |
|
res = &daily.ColumnList{ |
|
Ceid: column[0].Ceid, |
|
Name: column[0].Cname, |
|
Children: column, |
|
} |
|
} |
|
} |
|
return |
|
} |
|
|
|
// Category |
|
func (s *Service) Category(plat int8, build, categoryID, columnID, pn, ps int) (res *daily.Show) { |
|
var ( |
|
key string |
|
) |
|
if pn > 0 { |
|
pn = pn - 1 |
|
} |
|
start := pn * ps |
|
end := start + ps |
|
if columnID > 0 { |
|
key = fmt.Sprintf(_initDailyKey, plat, columnID) |
|
} else { |
|
listKey := fmt.Sprintf(_initColumnListKey, plat, categoryID) |
|
if columns, ok := s.cardListCache[listKey]; ok { |
|
for _, c := range columns { |
|
if model.InvalidBuild(build, c.Build, c.Condition) { |
|
continue |
|
} |
|
key = fmt.Sprintf(_initDailyKey, plat, c.Cid) |
|
break |
|
} |
|
} |
|
} |
|
if columns, ok := s.columnCache[key]; ok { |
|
res = columns |
|
if pn*ps > 400 { |
|
res.Body = _emptyList |
|
return |
|
} |
|
if res.Body, ok = s.columnListCache[key]; ok { |
|
resLen := len(res.Body) |
|
if resLen > end { |
|
res.Body = res.Body[start:end] |
|
} else if resLen > start { |
|
res.Body = res.Body[start:] |
|
} else { |
|
res.Body = _emptyList |
|
} |
|
} |
|
if len(res.Body) == 0 { |
|
res.Body = _emptyList |
|
} |
|
} |
|
return |
|
} |
|
|
|
// loadColumnsCache load all columns cache |
|
func (s *Service) loadColumnsCache() { |
|
res, err := s.cdao.Columns(context.TODO()) |
|
if err != nil { |
|
log.Error("s.cdao.Columns error(%v)", err) |
|
return |
|
} |
|
tmp := map[string]*card.Column{} |
|
for plat, columns := range res { |
|
for _, column := range columns { |
|
key := fmt.Sprintf(_initColumnKey, plat, column.ID) |
|
tmp[key] = column |
|
} |
|
} |
|
s.columnsCache = tmp |
|
} |
|
|
|
// loadColumnListCache |
|
func (s *Service) loadColumnListCache(now time.Time) { |
|
var ( |
|
tmp = map[string][]*card.ColumnList{} |
|
) |
|
platColumns, err := s.cdao.ColumnPlatList(context.TODO(), now) |
|
if err != nil { |
|
log.Error("s.cdao.ColumnPlatList error(%v)", err) |
|
return |
|
} |
|
for plat, columns := range platColumns { |
|
for _, column := range columns { |
|
key := fmt.Sprintf(_initColumnListKey, plat, column.Ceid) |
|
tmp[key] = append(tmp[key], column) |
|
} |
|
} |
|
s.cardListCache = tmp |
|
} |
|
|
|
// loadNperCache |
|
func (s *Service) loadNperCache(now time.Time) { |
|
hdm, err := s.cdao.ColumnNpers(context.TODO(), now) |
|
if err != nil { |
|
log.Error("s.cdao.ColumnNpers error(%v)", err) |
|
return |
|
} |
|
itm, aids, err := s.cdao.NperContents(context.TODO(), now) |
|
if err != nil { |
|
log.Error("s.cdao.NperContents error(%v)", err) |
|
return |
|
} |
|
tmp, tmpColumns, tmpList := s.mergeCard(context.TODO(), hdm, itm, aids, now) |
|
s.cardCache = tmp |
|
s.columnCache = tmpColumns |
|
s.columnListCache = tmpList |
|
} |
|
|
|
// cacheproc load all cache. |
|
func (s *Service) cacheproc() { |
|
for { |
|
time.Sleep(s.tick) |
|
now := time.Now() |
|
s.loadColumnListCache(now) |
|
s.loadColumnsCache() |
|
s.loadNperCache(now) |
|
} |
|
} |
|
|
|
// mergeCard |
|
func (s *Service) mergeCard(c context.Context, hdm map[int8][]*card.ColumnNper, itm map[int][]*card.Content, itmaids map[int][]int64, now time.Time) (res map[string][]*daily.Show, columns map[string]*daily.Show, columnList map[string][]*daily.Item) { |
|
var ( |
|
dailyMAX = 31 |
|
) |
|
res = map[string][]*daily.Show{} |
|
columnList = map[string][]*daily.Item{} |
|
columns = map[string]*daily.Show{} |
|
for plat, hds := range hdm { |
|
for _, hd := range hds { |
|
var ( |
|
ok bool |
|
column *card.Column |
|
) |
|
columnskey := fmt.Sprintf(_initColumnKey, plat, hd.ColumnID) |
|
if column, ok = s.columnsCache[columnskey]; !ok { |
|
continue |
|
} |
|
switch column.Type { |
|
case model.GotoDaily: |
|
if dailykey := fmt.Sprintf(_initDailyKey, plat, hd.ColumnID); len(res[dailykey]) > dailyMAX { |
|
continue |
|
} |
|
} |
|
var ( |
|
sis []*daily.Item |
|
) |
|
its, ok := itm[hd.ID] |
|
if !ok { |
|
its = []*card.Content{} |
|
} |
|
switch column.Tpl { |
|
case 1, 2: |
|
var tmpItem = map[int64]*daily.Item{} |
|
if aids, ok := itmaids[hd.ID]; ok { |
|
tmpItem = s.fromCardAids(context.TODO(), aids) |
|
} |
|
for _, ci := range its { |
|
si := s.fillCardItem(ci, tmpItem) |
|
if si.Title == "" { |
|
continue |
|
} |
|
if ci.TagID > 0 { |
|
si.TagName, si.TagID = s.fromTagIDByName(c, ci.TagID, now) |
|
} |
|
sis = append(sis, si) |
|
} |
|
} |
|
if len(sis) == 0 { |
|
continue |
|
} |
|
sw := &daily.Show{} |
|
sw.Head = &daily.Head{ |
|
ColumnID: hd.ID, |
|
Build: hd.Build, |
|
Condition: hd.Condition, |
|
Plat: hd.Plat, |
|
Desc: hd.Desc, |
|
Type: column.Type, |
|
} |
|
if hd.Cover != "" { |
|
sw.Cover = hd.Cover |
|
} |
|
var key string |
|
switch sw.Head.Type { |
|
case model.GotoDaily: |
|
key = fmt.Sprintf(_initDailyKey, plat, hd.ColumnID) |
|
sw.Head.Title = hd.Name |
|
if len(res[key]) == 0 { |
|
sw.Head.Date = now.Unix() |
|
} else { |
|
sw.Head.Date = int64(hd.NperTime) |
|
} |
|
sw.Body = sis |
|
res[key] = append(res[key], sw) |
|
case model.GotoColumn: |
|
key = fmt.Sprintf(_initDailyKey, plat, hd.ID) |
|
sw.Head.Title = hd.Name |
|
sw.Head.Goto = hd.Goto |
|
sw.Head.Param = hd.Param |
|
sw.Head.URI = hd.URI |
|
columnList[key] = sis |
|
columns[key] = sw |
|
} |
|
} |
|
} |
|
return |
|
} |
|
|
|
// fillCardItem |
|
func (s *Service) fillCardItem(csi *card.Content, tsi map[int64]*daily.Item) (si *daily.Item) { |
|
si = &daily.Item{} |
|
switch csi.Type { |
|
case model.CardGotoAv: |
|
si.Goto = model.GotoAv |
|
si.Param = csi.Value |
|
} |
|
si.URI = model.FillURI(si.Goto, si.Param, nil) |
|
if si.Goto == model.GotoAv { |
|
aid, err := strconv.ParseInt(si.Param, 10, 64) |
|
if err != nil { |
|
log.Error("strconv.ParseInt(%s) error(%v)", si.Param, err) |
|
} else { |
|
if it, ok := tsi[aid]; ok { |
|
si = it |
|
if csi.Title != "" { |
|
si.Title = csi.Title |
|
} |
|
} else { |
|
si = &daily.Item{} |
|
} |
|
} |
|
} |
|
return |
|
} |
|
|
|
// fromCardAids get Aids. |
|
func (s *Service) fromCardAids(ctx context.Context, aids []int64) (data map[int64]*daily.Item) { |
|
var ( |
|
arc *api.Arc |
|
ok bool |
|
) |
|
as, err := s.arc.ArchivesPB(ctx, aids) |
|
if err != nil { |
|
log.Error("s.arc.ArchivesPB(%v) error(%v)", aids, err) |
|
return |
|
} |
|
if len(as) == 0 { |
|
log.Warn("s.arc.ArchivesPB(%v) length is 0", aids) |
|
return |
|
} |
|
data = map[int64]*daily.Item{} |
|
for _, aid := range aids { |
|
if arc, ok = as[aid]; ok { |
|
if !arc.IsNormal() { |
|
continue |
|
} |
|
i := &daily.Item{} |
|
i.FromArchivePB(arc) |
|
data[aid] = i |
|
} |
|
} |
|
return |
|
} |
|
|
|
// fromTagIDByName from tag_id by tag_name |
|
func (s *Service) fromTagIDByName(ctx context.Context, tagID int, now time.Time) (tagName string, tagIDInt int64) { |
|
tag, err := s.tag.TagInfo(ctx, 0, tagID, now) |
|
if err != nil { |
|
log.Error("s.tag.TagInfo(%d) error(%v)", tagID, err) |
|
return |
|
} |
|
tagName = tag.Name |
|
tagIDInt = tag.Tid |
|
return |
|
}
|
|
|