@@ -0,0 +1,14 @@
|
||||
package appg
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// AICallbackURL returns the externally reachable Web callback URL for AI jobs.
|
||||
func AICallbackURL(path string) (string, error) {
|
||||
if Conf == nil || strings.TrimSpace(Conf.URL.AiImageToVideoCallbackUrl) == "" {
|
||||
return "", errors.New("ai callback url is not configured")
|
||||
}
|
||||
return strings.TrimRight(strings.TrimSpace(Conf.URL.AiImageToVideoCallbackUrl), "/") + "/" + strings.TrimLeft(path, "/"), nil
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
package appg
|
||||
|
||||
import (
|
||||
"91porn-server/common/constant"
|
||||
"91porn-server/common/db"
|
||||
"91porn-server/common/elastic"
|
||||
"91porn-server/common/email"
|
||||
"91porn-server/common/httputil"
|
||||
"91porn-server/common/laosiji_app"
|
||||
"91porn-server/common/redis"
|
||||
"91porn-server/common/sms"
|
||||
"91porn-server/common/tg"
|
||||
)
|
||||
|
||||
var (
|
||||
Conf *GlobalConfig
|
||||
Static *StaticSource
|
||||
Name *NameSource
|
||||
Redis *redis.Client
|
||||
VideoDB *db.MongoDB
|
||||
LogDB *db.MongoDB
|
||||
StatDB *db.MongoDB
|
||||
Bot *tg.Bot
|
||||
VideoES *elastic.Client // ES搜索
|
||||
ProxyCfg *httputil.ProxyCfg
|
||||
ImAuth string //im token
|
||||
)
|
||||
|
||||
// ShouldEnforceIPRateLimit reports whether IP-based request restrictions should
|
||||
// be applied. The shared test environment intentionally skips these checks so
|
||||
// NAT traffic from testers cannot block login, registration, SMS, or comments.
|
||||
func ShouldEnforceIPRateLimit() bool {
|
||||
return Conf == nil || Conf.Base.Env != constant.TestRunmod
|
||||
}
|
||||
|
||||
// H265URLForApp 提供统一的 App H.265 熔断开关。
|
||||
// 未配置或配置为 true 时返回原地址;显式为 false 时所有 App 接口隐藏地址。
|
||||
func H265URLForApp(rawURL string) string {
|
||||
if Conf != nil && Conf.Hevc.EnableApp != nil && !*Conf.Hevc.EnableApp {
|
||||
return ""
|
||||
}
|
||||
return rawURL
|
||||
}
|
||||
|
||||
type StaticSource struct {
|
||||
Portrait []string `json:"portrait"`
|
||||
SysUser []uint64 `json:"sysUser"`
|
||||
TagFilter []string `json:"tagFilter"`
|
||||
VerifyCodeForFake string `json:"verifyCodeForFake"` //马甲号验证码
|
||||
}
|
||||
|
||||
type NameSource struct {
|
||||
FamilyNames []string `json:"familyNames"`
|
||||
MiddleNames []string `json:"middleNames"`
|
||||
AfterNames []string `json:"afterNames"`
|
||||
}
|
||||
|
||||
type ReplayAttackConfig struct {
|
||||
Enable bool `json:"enable"`
|
||||
Key string `json:"key"`
|
||||
WindowDurationSeconds int64 `json:"windowDurationSeconds"`
|
||||
}
|
||||
|
||||
type GlobalConfig struct {
|
||||
Base struct {
|
||||
Port int64 `json:"port"`
|
||||
PProf bool `json:"pprof"`
|
||||
Env string `json:"env"`
|
||||
JwtKey string `json:"jwtKey"`
|
||||
ResKey string `json:"resKey"`
|
||||
ResKey360 string `json:"resKey360"`
|
||||
DevIDSignKey string `json:"devIDSignKey"`
|
||||
WebJwtKey string `json:"webJwtKey"`
|
||||
ReplayAttack ReplayAttackConfig `json:"replayAttack"`
|
||||
DemarcatAmout uint64 `json:"demarcatAmout"`
|
||||
TotalWatch uint64 `json:"totalWatch"`
|
||||
StoreEncryptKey string `json:"storeEncryptKey"`
|
||||
// H5M3u8TicketKey H5 m3u8 播放防盗链票据的服务端密钥(建议 openssl rand -base64 32)。
|
||||
// 留空时保持旧逻辑(不签票、不验票),便于先发布代码再由运维配置密钥开启严格模式。
|
||||
H5M3u8TicketKey string `json:"h5M3u8TicketKey"`
|
||||
// 媒体分片(TS)鉴权签名密钥对象(含 keyVersion/key);未配置时回退内置默认(版本 default + constant.MediaSourceAuthKey)
|
||||
TsAuth constant.TsAuthKeyConfig `json:"tsAuth"`
|
||||
} `json:"base"`
|
||||
Log struct {
|
||||
Level string `json:"level"`
|
||||
DisableStacktrace bool `json:"disableStacktrace"`
|
||||
} `json:"log"`
|
||||
MonitorReport struct {
|
||||
GroupId string `json:"groupId"`
|
||||
SecretKey string `json:"secretKey"`
|
||||
} `json:"monitorReport"`
|
||||
Kefu struct {
|
||||
AppID string `json:"appId"`
|
||||
AppSecret string `json:"appSecret"`
|
||||
PlatName string `json:"platName"`
|
||||
Theme string `json:"theme"`
|
||||
} `json:"kefu"`
|
||||
DataReport struct {
|
||||
Url string `json:"url"`
|
||||
AppUrl string `json:"appUrl"`
|
||||
} `json:"dataReport"`
|
||||
DaiChong struct {
|
||||
AppID string `json:"appId"`
|
||||
AppSecret string `json:"appSecret"`
|
||||
PlatName string `json:"platName"`
|
||||
Domain string `json:"domain"`
|
||||
UploadUrl string `json:"uploadUrl"`
|
||||
H5domain string `json:"h5domain"`
|
||||
H5domainQP string `json:"h5domainQP"`
|
||||
} `json:"daichong"`
|
||||
Customer struct {
|
||||
Url string `json:"url"`
|
||||
AppId string `json:"appId"` // 客服中心给的appid
|
||||
Secret string `json:"secret"`
|
||||
} `json:"customer"`
|
||||
PayCenter struct {
|
||||
AppName string `json:"appName"` // APP名称
|
||||
CallbackUrl string `json:"callbackUrl"` // 回调地址(APP服务地址)
|
||||
ApiUrl string `json:"apiUrl"` // 新支付中心地址
|
||||
MercID string `json:"mercID"` // 商户ID
|
||||
MercSecret string `json:"mercSecret"` // 商户密钥
|
||||
} `json:"payCenter"`
|
||||
Im struct {
|
||||
AppID string `json:"appId"`
|
||||
AppName string `json:"appName"`
|
||||
AppSecret string `json:"appSecret"`
|
||||
AppJwtKey string `json:"appJwtKey"`
|
||||
} `json:"im"`
|
||||
ImV2 struct {
|
||||
BaseURL string `json:"baseUrl"`
|
||||
DynamicConfigDomain string `json:"dynamicConfigDomain"`
|
||||
SocketURL string `json:"socketUrl"`
|
||||
MerchantCode string `json:"merchantCode"`
|
||||
TenantCode string `json:"tenantCode"`
|
||||
AppKey string `json:"appKey"`
|
||||
ClientID string `json:"clientId"`
|
||||
ClientSecret string `json:"clientSecret"`
|
||||
} `json:"imv2"`
|
||||
Elastic struct {
|
||||
VideoUrl string `json:"videoUrl"`
|
||||
IsActive bool `json:"isActive"`
|
||||
UserName string `json:"userName"`
|
||||
PassWord string `json:"passWord"`
|
||||
} `json:"elastic"`
|
||||
Mongo struct {
|
||||
VideoDbUrl string `json:"videoDbUrl"` //主数据库 存放强业务相关的数据
|
||||
StatDbUrl string `json:"statDbUrl"` //统计数据库 存放统计 日志 渠道相关的数据
|
||||
LogDbUrl string `json:"logDbUrl"` //日志数据库
|
||||
LogReadDBUrl string `json:"logDbUrlRead"` //读日志数据库
|
||||
} `json:"mongo"`
|
||||
Redis struct {
|
||||
URL string `json:"url"`
|
||||
} `json:"redis"`
|
||||
ShortRecommend ShortRecommendConfig `json:"shortRecommend"`
|
||||
Game struct {
|
||||
URL string `json:"url"`
|
||||
MercId int `json:"mercId"`
|
||||
} `json:"game"`
|
||||
URL struct {
|
||||
ImCenterUrl string `json:"imCenterUrl"`
|
||||
OriginUrl string `json:"originUrl"`
|
||||
JH1BOriginUrl string `json:"jH1BOriginUrl"`
|
||||
LaoSiJiOriginUrl string `json:"laoSiJiOriginUrl"`
|
||||
LaoSiJiTSCdn string `json:"laoSiJiTSCdn"`
|
||||
UploadUrl string `json:"uploadUrl"`
|
||||
UploadImgUrl string `json:"uploadImgUrl"`
|
||||
SendSingleFile string `json:"sendSingleFile"`
|
||||
SendBatchFile string `json:"sendBatchFile"`
|
||||
FileInfoUrl string `json:"fileInfoUrl"`
|
||||
CoverInfoUrl string `json:"coverInfoUrl"`
|
||||
LocalWebUrl string `json:"localWebUrl"`
|
||||
CdnUrl string `json:"cdnUrl"`
|
||||
HttpProxy string `json:"httpProxy"`
|
||||
TransactionUrl string `json:"transactionUrl"` // 支付下单地址
|
||||
DataCentreURL string `json:"dataCentreUrl"` // 数据中心
|
||||
ApiUrls []string `json:"apiUrls"` // api域名
|
||||
ProductUrl string `json:"productUrl"` // 产品中心
|
||||
//Active2023 string `json:"active2023"` // 2023新春抽奖地址
|
||||
NavigateUrl string `json:"navigateUrl"` // 导航站地址
|
||||
HlH5Url string `json:"hlH5Url"` // 黑料h5url
|
||||
LuckyDrawH5 string `json:"luckyDrawH5"` // 抽奖H5链接
|
||||
StoreUrl string `json:"storeUrl"` // 原味商城url
|
||||
AiServer string `json:"aiServer"` //ai订单请求地址
|
||||
AiUndressServer string `json:"aiUndressServer"` // AI图片脱衣服务地址
|
||||
AiImageToVideoUrl string `json:"aiImageToVideoUrl"` // AI图生视频请求地址
|
||||
AiImageToVideoCallbackUrl string `json:"aiImageToVideoCallbackUrl"` // AI图生视频回调地址
|
||||
AIMateH5 string `json:"aiMateH5"` // AI伴侣链接
|
||||
} `json:"url"`
|
||||
Limit struct {
|
||||
GlobalLimit int64 `json:"globalLimit"` // 全局接口访问频率限制
|
||||
CommentLimit int64 `json:"commentLimit"` // 评论接口限制
|
||||
RechargeLimit int64 `json:"rechargeLimit"` // 充值接口限制
|
||||
LoginLimit int64 `json:"loginLimit"` // 登陆注册接口限制
|
||||
SMSIPLimit int64 `json:"smsIPLimit"` // 短信验证码 IP 频率限制(次/自然日)
|
||||
} `json:"limit"`
|
||||
Hevc struct {
|
||||
EnableApp *bool `json:"enableApp"` // false 时隐藏 App 响应里的 H265 播放地址;未配置时默认返回
|
||||
PullSecret string `json:"pullSecret"` // SKD 与 App 共享的 H265 拉流签名密钥,至少 32 个随机字节
|
||||
} `json:"hevc"`
|
||||
CmtLimit struct {
|
||||
CmtLimitExpire int64 `json:"cmtLimitExpire"` // 发表评论限制过期时间(秒)
|
||||
CommentCount int64 `json:"commentCount"` // 发表评论次数限制
|
||||
} `json:"cmtLimit"`
|
||||
HttpOptions struct {
|
||||
DcCtxTimeOut uint64 `json:"dcCtxTimeOut"` //代充http请求 超时ctx取消时间
|
||||
} `json:"httpOptions"`
|
||||
AWS struct {
|
||||
SES email.Config `json:"ses"`
|
||||
} `json:"aws"`
|
||||
Kafka struct {
|
||||
Url string `yaml:"url"`
|
||||
Group string `yaml:"group"`
|
||||
} `yaml:"kafka"`
|
||||
AdCenter struct {
|
||||
ApiDomain string `json:"apiDomain"` // api地址 如:https://adopenapi.adcs01.top
|
||||
MerchantCode string `json:"merchantCode"` // 商户 code
|
||||
AppCode string `json:"appCode"` // 应用 code
|
||||
AesKey string `json:"aesKey"` // 数据解密KEY
|
||||
} `json:"adCenter"`
|
||||
RandomBanner string `json:"randomBanner"` // 随机banner
|
||||
AiFreeUnDressDailyLimit int `json:"aiFreeUnDressDailyLimit"` // AI免费脱衣每日限额
|
||||
SMS sms.Config `json:"sms"`
|
||||
ActivityServer struct {
|
||||
AppId string `json:"appId"` // 活动服应用ID
|
||||
SecretKey string `json:"secretKey"` // 活动服回调签名密钥(Base64编码)
|
||||
ApiUrl string `json:"apiUrl"` // 活动服API地址,用于拉取域名等
|
||||
} `json:"activityServer"`
|
||||
LaoSiJiAiMate laosiji_app.Config `json:"laoSiJiAiMate"` // 老司机AI女友V2第三方配置
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package appg
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"91porn-server/common/elastic"
|
||||
"91porn-server/common/log"
|
||||
)
|
||||
|
||||
func InitElastic() {
|
||||
opts := elastic.Options{
|
||||
Address: []string{Conf.Elastic.VideoUrl},
|
||||
MaxIdleConnsPerHost: 10,
|
||||
IdleConnTimeout: 30,
|
||||
UserName: Conf.Elastic.UserName,
|
||||
PassWord: Conf.Elastic.PassWord,
|
||||
}
|
||||
c, err := elastic.InitElastic(opts)
|
||||
if err != nil {
|
||||
log.Error("startUp VideoES InitElastic error", log.E(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
VideoES = c
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package appg
|
||||
|
||||
import (
|
||||
"91porn-server/common/db"
|
||||
"91porn-server/models"
|
||||
)
|
||||
|
||||
func InitMongodbParam(registerPool []models.Register) ([]db.DBmap, []db.Register) {
|
||||
pri := db.DBmap{
|
||||
Key: models.VideoDb,
|
||||
URL: Conf.Mongo.VideoDbUrl,
|
||||
}
|
||||
sta := db.DBmap{
|
||||
Key: models.StatDb,
|
||||
URL: Conf.Mongo.StatDbUrl,
|
||||
}
|
||||
log := db.DBmap{
|
||||
Key: models.LogDb,
|
||||
URL: Conf.Mongo.LogDbUrl,
|
||||
}
|
||||
readLog := db.DBmap{
|
||||
Key: models.LogReadDb,
|
||||
URL: Conf.Mongo.LogReadDBUrl,
|
||||
}
|
||||
dbgister := make([]db.Register, len(registerPool))
|
||||
for i, v := range registerPool {
|
||||
dbgister[i] = db.Register{Key: v.Key, Table: v.Table}
|
||||
}
|
||||
dbmaps := []db.DBmap{pri, sta, log, readLog}
|
||||
return dbmaps, dbgister
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package appg
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"91porn-server/common/log"
|
||||
"91porn-server/common/redis"
|
||||
)
|
||||
|
||||
func InitRedis() {
|
||||
r, err := redis.WithURL(Conf.Redis.URL)
|
||||
if err != nil {
|
||||
log.Error("startUp vdb redis error", log.E(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
Redis = r
|
||||
}
|
||||
|
||||
func RedisClose() error {
|
||||
if Redis != nil {
|
||||
err := Redis.Close()
|
||||
if err != nil {
|
||||
log.Error("RUdb Redis Close Error", log.E(err))
|
||||
return err
|
||||
}
|
||||
log.Info("RUdb Redis Close OK")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package appg
|
||||
|
||||
import "time"
|
||||
|
||||
const (
|
||||
defaultShortRecommendRequestTimeout = 3 * time.Second
|
||||
defaultShortRecommendKeyTTLHours = 72
|
||||
)
|
||||
|
||||
// ShortRecommendConfig 控制App侧短视频环形队列读取行为。
|
||||
// Enabled 使用指针是为了兼容旧配置:未配置时默认启用。
|
||||
type ShortRecommendConfig struct {
|
||||
Enabled *bool `json:"enabled"`
|
||||
RequestTimeoutMs int `json:"requestTimeoutMs"`
|
||||
MaxBatches int `json:"maxBatches"`
|
||||
ScanMultiplier int `json:"scanMultiplier"`
|
||||
KeyTTLHours int `json:"keyTTLHours"`
|
||||
}
|
||||
|
||||
func (c *GlobalConfig) ShortRecommendEnabled() bool {
|
||||
return c == nil || c.ShortRecommend.Enabled == nil || *c.ShortRecommend.Enabled
|
||||
}
|
||||
|
||||
func (c *GlobalConfig) ShortRecommendRequestTimeout() time.Duration {
|
||||
if c == nil || c.ShortRecommend.RequestTimeoutMs <= 0 {
|
||||
return defaultShortRecommendRequestTimeout
|
||||
}
|
||||
timeout := time.Duration(c.ShortRecommend.RequestTimeoutMs) * time.Millisecond
|
||||
if timeout < 100*time.Millisecond {
|
||||
return 100 * time.Millisecond
|
||||
}
|
||||
if timeout > 10*time.Second {
|
||||
return 10 * time.Second
|
||||
}
|
||||
return timeout
|
||||
}
|
||||
|
||||
func (c *GlobalConfig) ShortRecommendKeyTTL() int {
|
||||
if c == nil || c.ShortRecommend.KeyTTLHours <= 0 {
|
||||
return defaultShortRecommendKeyTTLHours
|
||||
}
|
||||
return c.ShortRecommend.KeyTTLHours
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package appg
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestShortRecommendDefaultsPreserveLegacyDeployment(t *testing.T) {
|
||||
var nilConfig *GlobalConfig
|
||||
if !nilConfig.ShortRecommendEnabled() {
|
||||
t.Fatal("nil config should default to enabled")
|
||||
}
|
||||
if got := nilConfig.ShortRecommendRequestTimeout(); got != 3*time.Second {
|
||||
t.Fatalf("timeout = %v, want 3s", got)
|
||||
}
|
||||
if got := nilConfig.ShortRecommendKeyTTL(); got != 72 {
|
||||
t.Fatalf("TTL hours = %d, want 72", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShortRecommendConfigBoundsTimeout(t *testing.T) {
|
||||
disabled := false
|
||||
cfg := &GlobalConfig{}
|
||||
cfg.ShortRecommend.Enabled = &disabled
|
||||
cfg.ShortRecommend.RequestTimeoutMs = 1
|
||||
if cfg.ShortRecommendEnabled() {
|
||||
t.Fatal("configured disabled should be honored")
|
||||
}
|
||||
if got := cfg.ShortRecommendRequestTimeout(); got != 100*time.Millisecond {
|
||||
t.Fatalf("minimum timeout = %v, want 100ms", got)
|
||||
}
|
||||
cfg.ShortRecommend.RequestTimeoutMs = 20_000
|
||||
if got := cfg.ShortRecommendRequestTimeout(); got != 10*time.Second {
|
||||
t.Fatalf("maximum timeout = %v, want 10s", got)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package appg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"91porn-server/common/conf"
|
||||
)
|
||||
|
||||
func InitStatic() {
|
||||
initName()
|
||||
initStatic()
|
||||
}
|
||||
|
||||
func initName() {
|
||||
name := NameSource{}
|
||||
err := conf.LoadJSON("config/names.json", &name)
|
||||
if err != nil {
|
||||
fmt.Printf("startUp load names error: %v\n", err)
|
||||
}
|
||||
Name = &name
|
||||
}
|
||||
|
||||
func initStatic() {
|
||||
static := StaticSource{}
|
||||
err := conf.LoadJSON("config/static.json", &static)
|
||||
if err != nil {
|
||||
fmt.Printf("startUp load static error: %v\n", err)
|
||||
}
|
||||
Static = &static
|
||||
}
|
||||
Reference in New Issue
Block a user