Initial commit

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 13:57:10 +08:00
co-authored by Claude Opus 5
commit 8679200f41
1897 changed files with 257900 additions and 0 deletions
+325
View File
@@ -0,0 +1,325 @@
package moduleconfmod
import (
"91porn-server/common/log"
"fmt"
"time"
"91porn-server/common/db"
"91porn-server/models"
"91porn-server/models/commod"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var mdb *db.MongoDB
const table = models.ModuleConf
var moduleMetadataCache = newModuleSnapshotCache(loadModuleMetadata, time.Now, moduleSnapshotTTL, moduleSnapshotRetryDelay)
func loadModuleMetadata() (modules []ModuleConf, err error) {
err = coll(nil).Find(&modules, bson.M{})
return
}
// InitIndex 设置index
func initIndex() {
coll := coll(nil)
many := []mongo.IndexModel{
{
Keys: bson.D{{Key: "moduleName", Value: 1}, {Key: "subModuleName", Value: 1}},
Options: options.Index().SetUnique(true),
},
}
if _, err := coll.CreateIndex(many); err != nil {
panic(fmt.Sprintf("%s model set index err ==>[%+v]", table, err))
}
}
func coll(t *db.MongoTool) *db.MongoTool {
if t == nil {
return mdb.Coll(table)
}
return t.Coll(table)
}
// InsertOne 插入一条数据
func InsertOne(p *ModuleConf) error {
p.HaiJiaoStyle.NormalizeRefreshConfig()
if err := p.HaiJiaoStyle.ValidateRefreshConfig(); err != nil {
return err
}
if err := p.ValidateSchedule(); err != nil {
return err
}
p.CreatedAt = time.Now()
_, err := coll(nil).InsertOne(p)
if err == nil {
moduleMetadataCache.invalidate()
}
return err
}
// UpdateOne 更新一条数据
func UpdateOne(set EditSelector) error {
current, err := getByIDFromDB(set.ID)
if err != nil {
return err
}
if set.HaiJiaoStyle != nil {
set.HaiJiaoStyle.NormalizeRefreshConfig()
if err = set.HaiJiaoStyle.ValidateRefreshConfig(); err != nil {
return err
}
}
if set.ClearOnlineAt && set.OnlineAt != nil {
return fmt.Errorf("onlineAt and clearOnlineAt cannot be set together")
}
if set.ClearOfflineAt && set.OfflineAt != nil {
return fmt.Errorf("offlineAt and clearOfflineAt cannot be set together")
}
if set.OnlineAt != nil {
current.OnlineAt = set.OnlineAt
}
if set.OfflineAt != nil {
current.OfflineAt = set.OfflineAt
}
if set.ClearOnlineAt {
current.OnlineAt = nil
}
if set.ClearOfflineAt {
current.OfflineAt = nil
}
if err = current.ValidateSchedule(); err != nil {
return err
}
set.UpdatedAt = time.Now()
update := bson.M{"$set": set}
unset := bson.M{}
if set.ClearOnlineAt {
unset["onlineAt"] = ""
}
if set.ClearOfflineAt {
unset["offlineAt"] = ""
}
if len(unset) > 0 {
update["$unset"] = unset
}
_, err = coll(nil).UpdateOne(bson.M{"_id": set.ID}, update)
if err == nil {
moduleMetadataCache.invalidate()
}
return err
}
func (p ModuleConf) ValidateSchedule() error {
if p.OnlineAt != nil && p.OfflineAt != nil && !p.OfflineAt.After(*p.OnlineAt) {
return fmt.Errorf("offlineAt must be later than onlineAt")
}
return nil
}
func (p ModuleConf) IsActiveAt(now time.Time) bool {
if p.Status != 1 || p.DeletedAt != nil {
return false
}
if p.OnlineAt != nil && p.OnlineAt.After(now) {
return false
}
return p.OfflineAt == nil || p.OfflineAt.After(now)
}
// DeleteOne 删除一条数据
func DeleteOne(id primitive.ObjectID) (err error) {
now := time.Now()
status := uint8(0)
set := EditSelector{ID: id, DeletedAt: &now, Status: &status}
return UpdateOne(set)
}
// GetByID 根据id获取一条记录
func GetByID(id primitive.ObjectID) (conf ModuleConf, err error) {
snapshot, err := moduleMetadataCache.get()
if err != nil {
return ModuleConf{}, err
}
conf, ok := snapshot.findByID(id)
if !ok {
return ModuleConf{}, mongo.ErrNoDocuments
}
return conf, nil
}
func getByIDFromDB(id primitive.ObjectID) (conf ModuleConf, err error) {
err = coll(nil).FindOne(&conf, bson.M{"_id": id})
return
}
// GetModuleConf 获取一个模块下的所有配置
func GetModuleConf(moduleName string) (ret []ModuleConf, err error) {
snapshot, err := moduleMetadataCache.get()
if err != nil {
return nil, err
}
return snapshot.findByModuleName(moduleName), nil
}
// GetModuleConfByType 根据类型获取配置
func GetModuleConfByType(moduleType int) (ret []ModuleConf, err error) {
snapshot, err := moduleMetadataCache.get()
if err != nil {
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "GetModuleConfByType", table, "snapshot", err))
return nil, err
}
return snapshot.findByType(moduleType), nil
}
// GetAllModule 获取所有开启(status=1)的模块配置
func GetAllModule() (ret []ModuleConf, err error) {
snapshot, err := moduleMetadataCache.get()
if err != nil {
return nil, err
}
return snapshot.enabled(), nil
}
// GetAllActiveModule 获取当前处于有效展示时间内的亚模块。
func GetAllActiveModule(now time.Time) (ret []ModuleConf, err error) {
snapshot, err := moduleMetadataCache.get()
if err != nil {
return nil, err
}
return snapshot.activeAt(now), nil
}
// ExcludedVideoModuleIDs 返回指定场景需要从聚合列表排除的亚模块 ID。
func ExcludedVideoModuleIDs(now time.Time, recommend bool) ([]string, error) {
snapshot, err := moduleMetadataCache.get()
if err != nil {
return nil, err
}
return snapshot.excludedVideoModuleIDs(now, recommend), nil
}
// ExcludedSearchModuleIDs 返回配置为不进入搜索列表的亚模块 ID。
func ExcludedSearchModuleIDs() ([]string, error) {
snapshot, err := moduleMetadataCache.get()
if err != nil {
return nil, err
}
return snapshot.excludedSearchModuleIDs(), nil
}
// BlockedOutsideSearchModuleIDs 返回当前仅允许通过搜索入口访问的亚模块 ID 集合。
func BlockedOutsideSearchModuleIDs(moduleIDs []string, now time.Time) (map[string]struct{}, error) {
objectIDs := make([]primitive.ObjectID, 0, len(moduleIDs))
seen := make(map[primitive.ObjectID]struct{}, len(moduleIDs))
for _, moduleID := range moduleIDs {
id, parseErr := primitive.ObjectIDFromHex(moduleID)
if parseErr != nil || id.IsZero() {
continue
}
if _, ok := seen[id]; ok {
continue
}
seen[id] = struct{}{}
objectIDs = append(objectIDs, id)
}
if len(objectIDs) == 0 {
return map[string]struct{}{}, nil
}
snapshot, err := moduleMetadataCache.get()
if err != nil {
return nil, err
}
return snapshot.blockedOutsideSearchModuleIDs(objectIDs, now), nil
}
// CanBrowseModule 判断亚模块是否能从搜索以外的普通入口访问。
func CanBrowseModule(moduleID primitive.ObjectID, now time.Time) (bool, error) {
module, err := GetByID(moduleID)
if err != nil {
return false, err
}
return module.IsActiveAt(now), nil
}
// Search 根据搜索条件检索
func Search(q QuerySelector, page commod.Page) (resp ListResp, err error) {
skip := int64(page.Skip())
limit := int64(page.Limit() + 1)
opts := options.FindOptions{
Skip: &skip,
Limit: &limit,
Sort: bson.D{{Key: "sortNum", Value: 1}},
}
filter := bson.M{}
if err != nil {
return
}
if q.ModuleName != nil {
filter["moduleName"] = primitive.Regex{
Pattern: *q.ModuleName,
}
}
if q.SubModuleName != nil {
filter["subModuleName"] = primitive.Regex{
Pattern: *q.SubModuleName,
}
}
if q.Type != nil {
filter["type"] = *q.Type
}
if q.ShowType != nil {
filter["showType"] = q.ShowType
}
data := []ModuleConf{}
if err = coll(nil).Find(&data, filter, &opts); err != nil {
return
}
total := int64(0)
if total, err = coll(nil).Count(filter); err != nil {
return
}
hasNext := false
if uint64(len(data)) > page.Limit() {
hasNext = true
data = data[:page.Limit()]
}
resp.List = data
resp.Total = total
resp.HasNext = hasNext
return
}
// FindByIDs 根据section id批量获取section详情
func FindByIDs(ids []primitive.ObjectID) (list []ModuleConf, err error) {
if len(ids) == 0 {
return nil, nil
}
snapshot, err := moduleMetadataCache.get()
if err != nil {
return nil, err
}
return snapshot.findByIDs(ids), nil
}
func FindOneById(id primitive.ObjectID) (ModuleConf, error) {
return GetByID(id)
}
// QueryAllList 分页查询文档
func QueryAllList(filter primitive.M, opts ...*options.FindOptions) (out []*ModuleConf, err error) {
if err = coll(nil).Find(&out, filter, opts...); err != nil {
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "QueryAllList", table, "Find", err),
log.Any("filter", filter),
log.Any("opts", opts),
)
return nil, err
}
return
}