package sourcemod import ( "encoding/json" "fmt" "time" "91porn-server/app/appg" "91porn-server/common" "91porn-server/common/cachev2" "91porn-server/common/constant/redisconst" "91porn-server/common/db" "91porn-server/common/log" "91porn-server/models" "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.Source const ( pingListCacheKey = "source:ping-list:v1" pingListCacheTTL = time.Minute ) type pingListCache struct { Domains []string `json:"domains"` Sources []*SourceRes `json:"sources"` } func coll(t *db.MongoTool) *db.MongoTool { if t == nil { return mdb.Coll(table) } return t.Coll(table) } // initIndex 索引设置 func initIndex() { many := []mongo.IndexModel{ { Keys: bson.D{{Key: "type", Value: 1}}, Options: options.Index().SetUnique(true).SetSparse(true), }, { Keys: bson.D{{Key: "domain", Value: 1}}, }, { Keys: bson.D{{Key: "isActive", Value: 1}}, }, { Keys: bson.D{{Key: "createdAt", Value: -1}}, }, } if _, err := coll(nil).CreateIndex(many); err != nil { panic(fmt.Sprintf("%s model set index err ==>[%+v]", table, err)) } } // PingList 返回 func PingList() (rd []string, rs []*SourceRes) { // 域名配置体积较大且更新频率低,通过共享缓存避免每次启动请求都读取 MongoDB。 result := pingListCache{} _, err := cachev2.Classes(). CacheTime(pingListCacheTTL). Key(pingListCacheKey). ResBind(&result). Cache(loadPingList) if err != nil { log.Error("PingList cache error", log.E(err)) result = loadPingList() } return result.Domains, result.Sources } func loadPingList() pingListCache { return buildPingList(List()) } func buildPingList(data []*SourceRes) pingListCache { if len(data) == 0 { return pingListCache{} } dataLen := len(data) d := make([]string, 0, dataLen) s := make([]*SourceRes, 0, dataLen) for _, v := range data { switch v.Type { case Ping: for _, v := range v.Domain { d = append(d, v.Url) } case Image, Audio, Common, Group, Telegram, Guide, PROXYRULE, FAQ, QRCODE, WELFARE, ACT, PromoteURL, AppStore, BusinessCooperation, ShareURL, PreSaleBgImg: s = append(s, v) case Vid: s = append(s, v) } } d = d[:len(d):len(d)] s = s[:len(s):len(s)] return pingListCache{Domains: d, Sources: s} } func clearPingListCache() { if _, err := cachev2.Classes().Delete(pingListCacheKey); err != nil { log.Error("clear PingList cache error", log.E(err)) } } // GetCdnURL GetCdnURL func GetCdnURL() (rd []Domain) { data := List() if len(data) == 0 { return } var d []Domain for _, v := range data { switch v.Type { case Common, Vid: d = append(d, v.Domain...) } } rd = d return } // List 返回 func List() (array []*SourceRes) { if err := coll(nil).Find(&array, bson.M{"isActive": true}); err != nil { log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "List", table, "Find", err)) } return } // List 返回 func WebList() (array []*SourceRes) { if err := coll(nil).Find(&array, bson.M{}); err != nil { log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "WebList", table, "Find", err)) } return } // GetCustomerStat 获取客服状态 func GetCustomerStat() bool { var s *SourceRes if err := coll(nil).FindOne(&s, bson.M{"type": Customer}); err != nil { log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "GetCustomerStat", table, "FindOne", err)) return true } if s == nil { return true } return s.IsActive } // 随机获取推广页域名 func GetRandomPromotionURL() string { if cnt, err := appg.Redis.SCard(redisconst.LandDomainCacheKey); cnt == 0 || err != nil { purls := GetPromoteURLArray() if len(purls) > 0 { _, _ = appg.Redis.SAdd(redisconst.LandDomainCacheKey, purls) } } purl, err := appg.Redis.SRandMember(redisconst.LandDomainCacheKey) if err != nil { return getPromoteURL() } return purl } // 获取推广url数组 func GetPromoteURLArray() []string { data := GetPromoteURLList() purls := make([]string, 0) if data != nil { purls = make([]string, 0, len(data.Domain)) for _, v := range data.Domain { purls = append(purls, v.Url) } } return purls } // GetPromoteURLList 返回 func GetPromoteURLList() (data *SourceWebRes) { if err := coll(nil).FindOne(&data, bson.M{"type": PromoteURL, "isActive": true}); err != nil { log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "GetPromoteURLList", table, "FindOne", err)) } return } // getPromoteURL 返回 func getPromoteURL() string { var s *SourceRes if err := coll(nil).FindOne(&s, bson.M{"type": PromoteURL, "isActive": true}); err != nil { log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "getPromoteURL", table, "FindOne", err)) } if s != nil { return s.Domain[0].Url } return "" } // Insert SourceInsert func Insert(s *Source) error { s.UpdatedAt = time.Now() s.CreatedAt = time.Now() if _, err := coll(nil).InsertOne(&s); err != nil { log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "Insert", table, "InsertOne", err)) return err } clearPingListCache() return nil } // Update 修改 func Update(id primitive.ObjectID, sType SourceType, set *SourceEdit) error { set.UpdatedAt = time.Now() if _, err := coll(nil).UpdateOne(bson.M{"_id": id, "type": sType}, bson.M{"$set": set}); err != nil { log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "Update", table, "UpdateOne", err), log.Any("id", id), log.Any("sType", sType), log.Any("set", set), ) return err } clearPingListCache() return nil } // EditDomain 修改 func EditDomain(id primitive.ObjectID, edit *SourceEdit) error { edit.UpdatedAt = time.Now() update, _ := common.ToBsonM(edit) if _, err := coll(nil).UpdateOne(bson.M{"_id": id}, bson.M{"$set": update}); err != nil { log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "EditDomain", table, "UpdateOne", err), log.Any("id", id), log.Any("edit", *edit), ) return err } clearPingListCache() return nil } // Remove SourceRemove func Remove(ids []primitive.ObjectID) error { if _, err := coll(nil).DeleteMany(bson.M{"_id": bson.M{"$in": ids}}); err != nil { log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "Remove", table, "DeleteMany", err), log.Any("ids", ids), ) return err } clearPingListCache() return nil } func GetWeightCdnURL() string { var cho []common.Choice data, err := appg.Redis.Get(redisconst.CdnCacheKey) //不存在cdn缓存 if err != nil || data == nil { var choice []common.Choice cdn := GetCdnURL() for _, v := range cdn { if v.Weight == 0 { continue } choice = append(choice, common.Choice{Weight: int(v.Weight), Item: v.Url}) } cbyte, _ := json.Marshal(choice) _ = appg.Redis.Set(redisconst.CdnCacheKey, cbyte, redisconst.CdnCacheExpire) c, err := common.WeightedChoice(choice) if err != nil { if len(cdn) > 0 { return cdn[0].Url } } return c.Item.(string) } _ = json.Unmarshal([]byte(*data), &cho) c, _ := common.WeightedChoice(cho) return c.Item.(string) } func GetVideoAndImgCdn() (videoCdn []string, imgCdn []string) { data := List() if len(data) == 0 { return } dataLen := len(data) videoCdn = make([]string, 0, dataLen) imgCdn = make([]string, 0, dataLen) for _, v := range data { if v.Type == Vid { for _, d := range v.Domain { videoCdn = append(videoCdn, d.Url) } } if v.Type == Image { for _, d := range v.Domain { imgCdn = append(imgCdn, d.Url) } } } return }