server: Go 服务器(REST+WSS 网关+JWT+Argon2+配对+素材直链+任务状态机);修复并发下线 send-on-closed-channel、下发查询 SQL 优先级、配对码原子占用、上传体积上限、JWT 默认密钥告警
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/joho/godotenv"
|
||||
|
||||
"everypublish/server/internal/api"
|
||||
"everypublish/server/internal/cache"
|
||||
"everypublish/server/internal/config"
|
||||
"everypublish/server/internal/db"
|
||||
"everypublish/server/internal/models"
|
||||
"everypublish/server/internal/ws"
|
||||
)
|
||||
|
||||
func main() {
|
||||
_ = godotenv.Load() // 本地开发读 .env,生产用环境变量
|
||||
cfg := config.Load()
|
||||
|
||||
gdb, err := db.Connect(cfg)
|
||||
if err != nil {
|
||||
log.Fatalf("db connect failed: %v", err)
|
||||
}
|
||||
if err = db.AutoMigrate(gdb); err != nil {
|
||||
log.Fatalf("auto migrate failed: %v", err)
|
||||
}
|
||||
// 启动自愈:上次异常退出残留的 online 状态重置为 offline(真实状态以连接为准)
|
||||
_ = gdb.Model(&models.AgentDevice{}).Where("status = ?", "online").Update("status", "offline").Error
|
||||
log.Println("mysql connected & migrated")
|
||||
|
||||
rds := cache.New(cfg)
|
||||
if err = rds.Ping(); err != nil {
|
||||
log.Fatalf("redis ping failed: %v", err)
|
||||
}
|
||||
log.Println("redis connected")
|
||||
|
||||
serverKey, err := ws.LoadOrCreateServerKey("./data/server_ed25519.key")
|
||||
if err != nil {
|
||||
log.Fatalf("server ed25519 key failed: %v", err)
|
||||
}
|
||||
hub := ws.NewHub()
|
||||
dsp := ws.NewDispatcher(gdb, hub, cfg)
|
||||
|
||||
ctx, stopFn := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
defer stopFn()
|
||||
go dsp.Start(ctx.Done())
|
||||
|
||||
router := api.Router(cfg, gdb, rds, hub, serverKey, dsp)
|
||||
|
||||
// 托管前端生产构建(STATIC_DIR 存在 index.html 时启用),SPA 回退
|
||||
if cfg.StaticDir != "" {
|
||||
if _, err := os.Stat(filepath.Join(cfg.StaticDir, "index.html")); err == nil {
|
||||
router.Static("/assets", filepath.Join(cfg.StaticDir, "assets"))
|
||||
router.StaticFile("/favicon.ico", filepath.Join(cfg.StaticDir, "favicon.ico"))
|
||||
router.NoRoute(func(c *gin.Context) {
|
||||
if strings.HasPrefix(c.Request.URL.Path, "/api/") {
|
||||
c.JSON(404, gin.H{"code": 404, "message": "接口不存在"})
|
||||
return
|
||||
}
|
||||
c.File(filepath.Join(cfg.StaticDir, "index.html"))
|
||||
})
|
||||
log.Printf("serving frontend from %s", cfg.StaticDir)
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("everypublish-server listening on %s", cfg.ServerAddr)
|
||||
if err = router.Run(cfg.ServerAddr); err != nil {
|
||||
log.Fatalf("server exited: %v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user