package service import ( "time" "with_you/internal/cache" "with_you/internal/model" "with_you/internal/repository" ) // 频道全量列表缓存 TTL(频道变更少,可较长;管理端写入后会主动失效) const channelAllListCacheTTL = 10 * time.Minute type ChannelService interface { ListActive() ([]*model.Channel, error) ListAll() ([]*model.Channel, error) MapByIDs(ids []string) (map[string]*model.Channel, error) Create(name, slug, description string, sortOrder int, isActive bool) (*model.Channel, error) Update(id, name, slug, description string, sortOrder int, isActive bool) (*model.Channel, error) Delete(id string) error } type channelServiceImpl struct { channelRepo repository.ChannelRepository cache cache.Cache } func NewChannelService(channelRepo repository.ChannelRepository, c cache.Cache) ChannelService { return &channelServiceImpl{channelRepo: channelRepo, cache: c} } func (s *channelServiceImpl) invalidateChannelListCache() { if s.cache != nil { cache.InvalidateChannelList(s.cache) } } func (s *channelServiceImpl) listAllFromDB() ([]*model.Channel, error) { return s.channelRepo.ListAll() } func (s *channelServiceImpl) ListAll() ([]*model.Channel, error) { if s.cache == nil { return s.listAllFromDB() } cs := cache.GetSettings() return cache.GetOrLoadTyped(s.cache, cache.ChannelsAllListKey(), channelAllListCacheTTL, cs.JitterRatio, cs.NullTTL, s.listAllFromDB) } func (s *channelServiceImpl) ListActive() ([]*model.Channel, error) { all, err := s.ListAll() if err != nil { return nil, err } out := make([]*model.Channel, 0, len(all)) for _, ch := range all { if ch != nil && ch.IsActive { c := *ch out = append(out, &c) } } return out, nil } // MapByIDs 始终基于全量频道列表(Redis 命中则零 SQL,否则一次 ListAll),与 ListActive / 公开列表共用同一缓存快照。 func (s *channelServiceImpl) MapByIDs(ids []string) (map[string]*model.Channel, error) { if len(ids) == 0 { return nil, nil } all, err := s.ListAll() if err != nil { return nil, err } byID := make(map[string]*model.Channel, len(all)) for _, ch := range all { if ch != nil { byID[ch.ID] = ch } } out := make(map[string]*model.Channel, len(ids)) for _, id := range ids { if ch, ok := byID[id]; ok { out[id] = ch } } return out, nil } func (s *channelServiceImpl) Create(name, slug, description string, sortOrder int, isActive bool) (*model.Channel, error) { channel := &model.Channel{ Name: name, Slug: slug, Description: description, SortOrder: sortOrder, IsActive: isActive, } if err := s.channelRepo.Create(channel); err != nil { return nil, err } s.invalidateChannelListCache() return channel, nil } func (s *channelServiceImpl) Update(id, name, slug, description string, sortOrder int, isActive bool) (*model.Channel, error) { channel, err := s.channelRepo.GetByID(id) if err != nil { return nil, err } channel.Name = name channel.Slug = slug channel.Description = description channel.SortOrder = sortOrder channel.IsActive = isActive if err := s.channelRepo.Update(channel); err != nil { return nil, err } s.invalidateChannelListCache() return channel, nil } func (s *channelServiceImpl) Delete(id string) error { err := s.channelRepo.Delete(id) if err != nil { return err } s.invalidateChannelListCache() return nil }