2025-12-05 14:40:33 +08:00
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
2026-05-15 10:28:17 +08:00
|
|
|
|
"cid/controller/dataengine"
|
|
|
|
|
|
"cid/controller/yidun"
|
|
|
|
|
|
serviceDataengine "cid/service/dataengine"
|
2026-05-08 09:33:40 +08:00
|
|
|
|
serviceYidun "cid/service/yidun"
|
2026-05-15 10:28:17 +08:00
|
|
|
|
"context"
|
2026-05-08 09:33:40 +08:00
|
|
|
|
"fmt"
|
2026-05-15 10:28:17 +08:00
|
|
|
|
"os"
|
|
|
|
|
|
"path/filepath"
|
|
|
|
|
|
"time"
|
2025-12-05 14:40:33 +08:00
|
|
|
|
|
2026-06-10 15:41:58 +08:00
|
|
|
|
_ "gitea.redpowerfuture.com/red-future/common/consul"
|
|
|
|
|
|
"gitea.redpowerfuture.com/red-future/common/http"
|
|
|
|
|
|
"gitea.redpowerfuture.com/red-future/common/jaeger"
|
2026-05-15 10:28:17 +08:00
|
|
|
|
_ "github.com/gogf/gf/contrib/drivers/pgsql/v2"
|
2025-12-05 14:40:33 +08:00
|
|
|
|
_ "github.com/gogf/gf/contrib/nosql/redis/v2"
|
2026-05-15 10:28:17 +08:00
|
|
|
|
"github.com/gogf/gf/v2/frame/g"
|
|
|
|
|
|
"github.com/gogf/gf/v2/net/ghttp"
|
2025-12-05 14:40:33 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
func main() {
|
2025-12-09 13:32:43 +08:00
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
defer jaeger.ShutDown(ctx)
|
|
|
|
|
|
|
2026-05-15 10:28:17 +08:00
|
|
|
|
// 设置时区为东八区
|
|
|
|
|
|
loc, err := time.LoadLocation("Asia/Shanghai")
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
time.Local = loc
|
|
|
|
|
|
}
|
|
|
|
|
|
// 关键:设置 PGTZ 环境变量,lib/pq 驱动在连接 pg 时会自动设置 session timezone
|
|
|
|
|
|
// 确保从数据库读取 TIMESTAMPTZ 时返回的是东八区时间,gtime.Time 序列化输出北京时间
|
|
|
|
|
|
os.Setenv("PGTZ", "Asia/Shanghai")
|
|
|
|
|
|
|
2026-05-08 09:33:40 +08:00
|
|
|
|
// 初始化易盾客户端
|
|
|
|
|
|
if err := serviceYidun.InitYidunClients(ctx); err != nil {
|
|
|
|
|
|
panic(fmt.Sprintf("初始化易盾客户端失败: %v", err))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-15 10:28:17 +08:00
|
|
|
|
g.Log().Info(ctx, "易盾客户端初始化成功")
|
|
|
|
|
|
|
|
|
|
|
|
// 启动内容送检定时任务
|
|
|
|
|
|
startContentCheckService(ctx)
|
|
|
|
|
|
|
|
|
|
|
|
// 获取前端目录
|
|
|
|
|
|
frontendDir := getFrontendDir()
|
|
|
|
|
|
|
|
|
|
|
|
// 注册前端静态文件路由(在使用 http.Httpserver 之前)
|
|
|
|
|
|
registerFrontendRoutes(frontendDir)
|
|
|
|
|
|
|
|
|
|
|
|
// 注册 API 路由并启动服务器
|
2025-12-05 14:40:33 +08:00
|
|
|
|
http.RouteRegister([]interface{}{
|
2026-05-21 11:21:56 +08:00
|
|
|
|
yidun.YidunController,
|
|
|
|
|
|
yidun.YidunCallback,
|
2026-05-15 10:28:17 +08:00
|
|
|
|
yidun.ContentCheck,
|
|
|
|
|
|
dataengine.MaterialVerify,
|
2025-12-05 14:40:33 +08:00
|
|
|
|
})
|
2026-05-15 10:28:17 +08:00
|
|
|
|
|
|
|
|
|
|
// 打印前端访问地址
|
|
|
|
|
|
port := g.Cfg().MustGet(ctx, "server.address", ":3001").String()
|
|
|
|
|
|
g.Log().Info(ctx, "============================================")
|
|
|
|
|
|
g.Log().Infof(ctx, "🌐 前端访问地址: http://localhost%s", port)
|
|
|
|
|
|
g.Log().Info(ctx, "============================================")
|
|
|
|
|
|
|
2025-12-05 14:40:33 +08:00
|
|
|
|
select {}
|
|
|
|
|
|
}
|
2026-05-15 10:28:17 +08:00
|
|
|
|
|
|
|
|
|
|
// getFrontendDir 获取前端目录路径
|
|
|
|
|
|
func getFrontendDir() string {
|
|
|
|
|
|
execPath, _ := os.Executable()
|
|
|
|
|
|
execDir := filepath.Dir(execPath)
|
|
|
|
|
|
frontendDir := filepath.Join(execDir, "resource", "frontend")
|
|
|
|
|
|
|
|
|
|
|
|
if _, err := os.Stat(frontendDir); os.IsNotExist(err) {
|
|
|
|
|
|
cwd, _ := os.Getwd()
|
|
|
|
|
|
frontendDir = filepath.Join(cwd, "resource", "frontend")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return frontendDir
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// registerFrontendRoutes 注册前端静态文件路由
|
|
|
|
|
|
func registerFrontendRoutes(frontendDir string) {
|
|
|
|
|
|
if _, err := os.Stat(frontendDir); os.IsNotExist(err) {
|
|
|
|
|
|
g.Log().Warningf(context.Background(), "前端目录不存在: %s", frontendDir)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
s := http.Httpserver
|
|
|
|
|
|
|
|
|
|
|
|
// 静态资源路由
|
|
|
|
|
|
s.BindHandler("/frontend/{file}", func(r *ghttp.Request) {
|
|
|
|
|
|
file := r.Get("file").String()
|
|
|
|
|
|
filePath := filepath.Join(frontendDir, file)
|
|
|
|
|
|
if _, err := os.Stat(filePath); err == nil {
|
|
|
|
|
|
r.Response.ServeFile(filePath)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
r.Response.WriteStatus(404)
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 首页/主入口
|
|
|
|
|
|
s.BindHandler("/", func(r *ghttp.Request) {
|
|
|
|
|
|
indexFile := filepath.Join(frontendDir, "material-verify.html")
|
|
|
|
|
|
if _, err := os.Stat(indexFile); err == nil {
|
|
|
|
|
|
r.Response.ServeFile(indexFile)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
r.Response.Write("<html><body><h1>CID Backend Service</h1><p>前端页面未找到</p></body></html>")
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// startContentCheckService 启动内容送检服务
|
|
|
|
|
|
func startContentCheckService(ctx context.Context) {
|
|
|
|
|
|
// 检查是否启用定时送检任务
|
|
|
|
|
|
schedulerEnabled := g.Cfg().MustGet(ctx, "content_check.scheduler_enabled", true).Bool()
|
|
|
|
|
|
if !schedulerEnabled {
|
|
|
|
|
|
g.Log().Info(ctx, "定时送检任务已禁用(scheduler_enabled=false),仅支持API手动送检")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 配置送检服务参数
|
|
|
|
|
|
config := serviceDataengine.ContentCheckConfig{
|
|
|
|
|
|
BatchSize: g.Cfg().MustGet(ctx, "content_check.batch_size", 10).Int(),
|
|
|
|
|
|
ImageEnabled: g.Cfg().MustGet(ctx, "content_check.image_enabled", true).Bool(),
|
|
|
|
|
|
VideoEnabled: g.Cfg().MustGet(ctx, "content_check.video_enabled", true).Bool(),
|
|
|
|
|
|
IntervalSeconds: g.Cfg().MustGet(ctx, "content_check.interval_seconds", 30).Int(),
|
|
|
|
|
|
}
|
|
|
|
|
|
serviceDataengine.TencentContentCheck.SetConfig(config)
|
|
|
|
|
|
|
|
|
|
|
|
// 启动服务
|
|
|
|
|
|
if err := serviceDataengine.TencentContentCheck.Start(ctx); err != nil {
|
|
|
|
|
|
g.Log().Errorf(ctx, "启动内容送检服务失败: %v", err)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
g.Log().Info(ctx, "内容送检服务启动成功")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|