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
+24
View File
@@ -0,0 +1,24 @@
package skdg
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
}
+28
View File
@@ -0,0 +1,28 @@
package skdg
import (
"os"
"91porn-server/common/log"
"91porn-server/common/redis"
)
func InitRedis() {
var err error
Redis, err = redis.WithURL(Conf.Redis.URL)
if err != nil {
log.Error("startUp udb redis error", log.E(err))
os.Exit(1)
}
}
func RedisClose() (err error) {
if Redis != nil {
if err := Redis.Close(); err != nil {
log.Error("RUdb Redis Close Error", log.E(err))
return err
}
log.Info("RUdb Redis Close OK")
}
return nil
}
+49
View File
@@ -0,0 +1,49 @@
package skdg
const (
defaultShortRecommendCron = "CRON_TZ=Asia/Shanghai 0 5/10 * * * ?"
defaultShortRecommendKeyTTLHours = 72
defaultProdInitializationLimit = 50_000
)
// ShortRecommendConfig 控制定时队列生成。Enabled 未配置时默认启用。
type ShortRecommendConfig struct {
Enabled *bool `json:"enabled"`
Cron string `json:"cron"`
KeyTTLHours int `json:"keyTTLHours"`
MaxInitializationWrites *int64 `json:"maxInitializationWrites"`
}
func (c *GlobalConfig) ShortRecommendEnabled() bool {
return c == nil || c.ShortRecommend.Enabled == nil || *c.ShortRecommend.Enabled
}
func (c *GlobalConfig) ShortRecommendCron() string {
if c == nil || c.ShortRecommend.Cron == "" {
return defaultShortRecommendCron
}
return c.ShortRecommend.Cron
}
func (c *GlobalConfig) ShortRecommendKeyTTL() int {
if c == nil || c.ShortRecommend.KeyTTLHours <= 0 {
return defaultShortRecommendKeyTTLHours
}
return c.ShortRecommend.KeyTTLHours
}
func (c *GlobalConfig) ShortRecommendInitializationLimit() int64 {
if c == nil {
return 0
}
if c.ShortRecommend.MaxInitializationWrites != nil {
if *c.ShortRecommend.MaxInitializationWrites < 0 {
return 0
}
return *c.ShortRecommend.MaxInitializationWrites
}
if c.Base.Env == "prod" {
return defaultProdInitializationLimit
}
return 0
}
+51
View File
@@ -0,0 +1,51 @@
package skdg
import "testing"
func TestShortRecommendDefaultsPreserveLegacyDeployment(t *testing.T) {
var nilConfig *GlobalConfig
if !nilConfig.ShortRecommendEnabled() {
t.Fatal("nil config should default to enabled")
}
if got := nilConfig.ShortRecommendCron(); got != defaultShortRecommendCron {
t.Fatalf("cron = %q, want %q", got, defaultShortRecommendCron)
}
if got := nilConfig.ShortRecommendKeyTTL(); got != 72 {
t.Fatalf("TTL hours = %d, want 72", got)
}
}
func TestShortRecommendExplicitConfig(t *testing.T) {
disabled := false
cfg := &GlobalConfig{}
cfg.ShortRecommend.Enabled = &disabled
cfg.ShortRecommend.Cron = "0 0 5 * * ?"
cfg.ShortRecommend.KeyTTLHours = 96
initializationLimit := int64(10_000)
cfg.ShortRecommend.MaxInitializationWrites = &initializationLimit
if cfg.ShortRecommendEnabled() {
t.Fatal("configured disabled should be honored")
}
if got := cfg.ShortRecommendCron(); got != cfg.ShortRecommend.Cron {
t.Fatalf("cron = %q", got)
}
if got := cfg.ShortRecommendKeyTTL(); got != 96 {
t.Fatalf("TTL hours = %d", got)
}
if got := cfg.ShortRecommendInitializationLimit(); got != 10_000 {
t.Fatalf("initialization limit = %d", got)
}
}
func TestShortRecommendProductionDefaultsToFailClosedInitializationGuard(t *testing.T) {
cfg := &GlobalConfig{}
cfg.Base.Env = "prod"
if got := cfg.ShortRecommendInitializationLimit(); got != defaultProdInitializationLimit {
t.Fatalf("initialization limit = %d, want %d", got, defaultProdInitializationLimit)
}
unlimited := int64(0)
cfg.ShortRecommend.MaxInitializationWrites = &unlimited
if got := cfg.ShortRecommendInitializationLimit(); got != 0 {
t.Fatalf("explicit initialization limit = %d, want 0", got)
}
}
+105
View File
@@ -0,0 +1,105 @@
package skdg
import (
"91porn-server/common/constant"
"91porn-server/common/db"
"91porn-server/common/elastic"
"91porn-server/common/redis"
"91porn-server/common/tg"
)
type GlobalConfig struct {
Base struct {
Port int64 `json:"port"`
Env string `json:"env"`
// 媒体分片(TS)鉴权签名密钥对象(含 keyVersion/key);未配置时回退内置默认(版本 default + constant.MediaSourceAuthKey)
TsAuth constant.TsAuthKeyConfig `json:"tsAuth"`
} `json:"base"`
Mongo struct {
VideoDbUrl string `json:"videoDbUrl"` //主数据库 存放强业务相关的数据
StatDbUrl string `json:"statDbUrl"` //统计数据库 存放统计 日志 渠道相关的数据
LogDbUrl string `json:"logDbUrl"` //日志数据库
SpiderDbUrl string `json:"spiderDbUrl"` //爬虫库
} `json:"mongo"`
Log struct {
Level string `json:"level"`
} `json:"log"`
Redis struct {
URL string `json:"url"`
} `json:"redis"`
ShortRecommend ShortRecommendConfig `json:"shortRecommend"`
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"`
} `json:"daichong"`
LSJ struct {
AppID string `json:"appId"`
APIKey string `json:"apiKey"`
APIUrl string `json:"apiUrl"`
ImageYuan string `json:"imageYuan"`
NoticeURL string `json:"noticeUrl"`
} `json:"lsj"`
Hevc struct {
EnableTranscode *bool `json:"enableTranscode"` // nil: 仅生产环境默认开启;true: 显式开启;false: 所有环境熔断
PullSecret string `json:"pullSecret"` // 与 App 共享的 H265 拉流签名密钥,至少 32 个随机字节
} `json:"hevc"`
AdCenter struct {
ApiDomain string `json:"apiDomain"` // api 地址
MerchantCode string `json:"merchantCode"` // 商户 code
AppCode string `json:"appCode"` // 应用 code
AesKey string `json:"aesKey"` // 数据解密 KEY
} `json:"adCenter"`
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"`
UserName string `json:"userName"`
PassWord string `json:"passWord"`
} `json:"elastic"`
Url struct {
CheckUrl string `json:"checkUrl"`
SpiderDataURL string `json:"spiderDataUrl"` //统计中心数据同步域名
PullFileInfo string `json:"pullFileInfo"`
AiServer string `json:"aiServer"` //ai订单请求地址
AppApiUrl string `json:"appApiUrl"` // App 对外 HTTPS origin(无路径),供 H265 云转码拉取源 m3u8
} `json:"url"`
Switch struct {
NotifyExpire bool `json:"notifyExpire"`
} `json:"switch"`
StartDate string `json:"startDate"`
MediaResourcesCfg struct {
UploadMediaUrl string `json:"uploadMediaUrl"` // 请求域名
ProId string `json:"proId"` // 商户号
AppSecret string `json:"appSecret"` // 商户密钥
} `json:"mediaResourceCfg"` //媒体资源库配置
}
var (
Conf *GlobalConfig
Redis *redis.Client
VideoES *elastic.Client
Static *StaticSource
StatDB *db.MongoDB
VideoDB *db.MongoDB
LogDB *db.MongoDB
SpiderDB *db.MongoDB
Bot *tg.Bot
)
type StaticSource struct {
Portrait []string `json:"portrait"`
}
+20
View File
@@ -0,0 +1,20 @@
package skdg
import (
"fmt"
"91porn-server/common/conf"
)
func InitStatic() {
initStatic()
}
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
}