// oci-portal 后端服务启动入口。 package main import ( "context" "log" "gorm.io/gorm" "oci-portal/internal/api" "oci-portal/internal/config" "oci-portal/internal/crypto" "oci-portal/internal/database" "oci-portal/internal/oci" "oci-portal/internal/service" ) func main() { if err := run(); err != nil { log.Fatal(err) } } // bootstrap 完成配置加载、数据库打开与加密组件构建。 func bootstrap() (*config.Config, *gorm.DB, *crypto.Cipher, error) { cfg, err := config.Load() if err != nil { return nil, nil, nil, err } db, err := database.Open(cfg.DBPath) if err != nil { return nil, nil, nil, err } cipher, err := crypto.NewCipher(cfg.DataKey) if err != nil { return nil, nil, nil, err } return cfg, db, cipher, nil } func run() error { cfg, db, cipher, err := bootstrap() if err != nil { return err } auth := service.NewAuthService(db, cfg.JWTSecret) auth.SetCipher(cipher) if err := auth.EnsureAdmin(cfg.AdminUsername, cfg.AdminPassword); err != nil { return err } ociClient := oci.NewCachedClient(oci.NewClient()) ociConfigs := service.NewOciConfigService(db, cipher, ociClient) settings := service.NewSettingService(db, cipher) settings.SetEnvPublicURL(cfg.PublicURL) if err := settings.ReloadSecurity(context.Background()); err != nil { return err } notifier := service.NewNotifier(settings) auth.SetNotifier(notifier, settings) oauth := service.NewOAuthService(db, settings, auth) systemLogs := service.NewSystemLogService(db) logEvents := service.NewLogEventService(db) logEvents.SetRelayDeps(ociConfigs, ociClient, cfg.PublicURL) logEvents.SetNotifier(notifier, settings) cleanupCtx, stopCleanup := context.WithCancel(context.Background()) systemLogs.StartCleanup(cleanupCtx) logEvents.StartParser(cleanupCtx) logEvents.StartCleanup(cleanupCtx) aiGateway := service.NewAiGatewayService(db, ociConfigs, ociClient) aiGateway.StartCleanup(cleanupCtx) // defer 为 LIFO:先停调度与清理,再等在途通知与日志写完 defer logEvents.Wait() defer systemLogs.Wait() defer notifier.Wait() defer aiGateway.Wait() defer stopCleanup() tasks := service.NewTaskService(db, ociConfigs, notifier, settings) tasks.AttachAiGateway(aiGateway) aiGateway.SetOnChannelsChanged(tasks.SyncAiProbeTask) if err := tasks.Start(); err != nil { return err } defer tasks.Stop() // 启动时对齐一次探测任务(已有渠道而任务缺失/暂停时自动建立或激活) tasks.SyncAiProbeTask(context.Background()) console := service.NewConsoleService(ociConfigs) proxies := service.NewProxyService(db, cipher) defer proxies.Wait() return api.NewRouter(auth, oauth, ociConfigs, tasks, console, settings, notifier, systemLogs, logEvents, proxies, aiGateway).Run(cfg.Addr) }