diff --git a/cmd/root.go b/cmd/root.go index 7b6fdf2..7cf7b4b 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -2,6 +2,7 @@ package cmd import ( "fmt" + "log" "os" "github.com/gookit/event" @@ -43,8 +44,11 @@ Made by Akizon77 with love.`, } func Execute() { - event.Trigger(eventType.ProcessStart, nil) - defer event.Trigger(eventType.ProcessExit, nil) + err, _ := event.Trigger(eventType.ProcessStart, event.M{}) + if err != nil { + log.Fatalf("Something went wrong during process start: %v", err) + os.Exit(1) + } if err := RootCmd.Execute(); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) diff --git a/cmd/server.go b/cmd/server.go index 18127ab..fe091f7 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -7,7 +7,6 @@ import ( "net/http" "os" "os/signal" - "strings" "syscall" "time" @@ -20,15 +19,11 @@ import ( "github.com/komari-monitor/komari/internal/database/auditlog" "github.com/komari-monitor/komari/internal/database/dbcore" "github.com/komari-monitor/komari/internal/database/models" - d_notification "github.com/komari-monitor/komari/internal/database/notification" "github.com/komari-monitor/komari/internal/database/records" "github.com/komari-monitor/komari/internal/database/tasks" "github.com/komari-monitor/komari/internal/eventType" logutil "github.com/komari-monitor/komari/internal/log" - "github.com/komari-monitor/komari/internal/messageSender" "github.com/komari-monitor/komari/internal/patch" - "github.com/komari-monitor/komari/internal/restore" - "github.com/komari-monitor/komari/pkg/cloudflared" "github.com/komari-monitor/komari/server" "github.com/spf13/cobra" ) @@ -55,54 +50,44 @@ func RunServer() { if err := os.MkdirAll("./data/theme", os.ModePerm); err != nil { log.Fatalf("Failed to create theme directory: %v", err) } - // 进行备份恢复 - if restore.NeedBackupRestore() { - restore.RestoreBackup() - } - conf.Load() - InitDatabase() - patch.ApplyPatch() if conf.Version != conf.Version_Development { gin.SetMode(gin.ReleaseMode) } - config, err := conf.GetWithV1Format() - if err != nil { - log.Fatal(err) - } - r := gin.New() r.Use(logutil.GinLogger()) r.Use(logutil.GinRecovery()) - event.Trigger(eventType.ServerInitializeStart, event.M{"config": config, "engine": r}) + InitDatabase() + patch.Apply() + err, _ := event.Trigger(eventType.ServerInitializeStart, event.M{"engine": r}) + if err != nil { + log.Fatalf("Something went wrong during ServerInitializeStart event: %v", err) + os.Exit(1) + } + config, err := conf.GetWithV1Format() + if err != nil { + log.Fatal(err) + } go DoScheduledWork() - go messageSender.Initialize() server.StartNezhaGRPCServer(config.NezhaCompatListen) - // 初始化 cloudflared - if strings.ToLower(GetEnv("KOMARI_ENABLE_CLOUDFLARED", "false")) == "true" { - err := cloudflared.RunCloudflared() // 阻塞,确保cloudflared跑起来 - if err != nil { - log.Fatalf("Failed to run cloudflared: %v", err) - } - } - server.Init(r) srv := &http.Server{ Addr: flags.Listen, Handler: r, } - - event.Trigger(eventType.ServerInitializeDone, event.M{"config": config}) - log.Printf("Starting server on %s ...", flags.Listen) + event.Trigger(eventType.ServerInitializeDone, event.M{}) + ScheduledEventTasksInit() + if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { OnFatal(err) + event.Trigger(eventType.ProcessExit, event.M{}) log.Fatalf("listen: %s\n", err) } quit := make(chan os.Signal, 1) @@ -119,18 +104,6 @@ func RunServer() { } func InitDatabase() { - // // 打印数据库类型和连接信息 - // if flags.DatabaseType == "mysql" { - // log.Printf("使用 MySQL 数据库连接: %s@%s:%s/%s", - // flags.DatabaseUser, flags.DatabaseHost, flags.DatabasePort, flags.DatabaseName) - // log.Printf("环境变量配置: [KOMARI_DB_TYPE=%s] [KOMARI_DB_HOST=%s] [KOMARI_DB_PORT=%s] [KOMARI_DB_USER=%s] [KOMARI_DB_NAME=%s]", - // os.Getenv("KOMARI_DB_TYPE"), os.Getenv("KOMARI_DB_HOST"), os.Getenv("KOMARI_DB_PORT"), - // os.Getenv("KOMARI_DB_USER"), os.Getenv("KOMARI_DB_NAME")) - // } else { - // log.Printf("使用 SQLite 数据库文件: %s", flags.DatabaseFile) - // log.Printf("环境变量配置: [KOMARI_DB_TYPE=%s] [KOMARI_DB_FILE=%s]", - // os.Getenv("KOMARI_DB_TYPE"), os.Getenv("KOMARI_DB_FILE")) - // } var count int64 = 0 if dbcore.GetDBInstance().Model(&models.User{}).Count(&count); count == 0 { user, passwd, err := accounts.CreateDefaultAdminAccount() @@ -144,12 +117,10 @@ func InitDatabase() { // #region 定时任务 func DoScheduledWork() { tasks.ReloadPingSchedule() - d_notification.ReloadLoadNotificationSchedule() //records.DeleteRecordBefore(time.Now().Add(-time.Hour * 24 * 30)) records.CompactRecord() - ScheduledEventTasksInit() event.On(eventType.SchedulerEvery30Minutes, event.ListenerFunc(func(e event.Event) error { cfg, err := conf.GetWithV1Format() @@ -183,12 +154,10 @@ func DoScheduledWork() { func OnShutdown() { auditlog.Log("", "", "server is shutting down", "info") - cloudflared.Kill() } func OnFatal(err error) { auditlog.Log("", "", "server encountered a fatal error: "+err.Error(), "error") - cloudflared.Kill() } func ScheduledEventTasksInit() { @@ -198,22 +167,17 @@ func ScheduledEventTasksInit() { every1h := time.NewTicker(1 * time.Hour) every1d := time.NewTicker(24 * time.Hour) for { - var err error = nil - var e event.Event select { case <-every1m.C: - err, e = event.Trigger(eventType.SchedulerEveryMinute, event.M{"interval": "1m"}) + event.Async(eventType.SchedulerEveryMinute, event.M{"interval": "1m"}) case <-every5m.C: - err, e = event.Trigger(eventType.SchedulerEvery5Minutes, event.M{"interval": "5m"}) + event.Async(eventType.SchedulerEvery5Minutes, event.M{"interval": "5m"}) case <-every30m.C: - err, e = event.Trigger(eventType.SchedulerEvery30Minutes, event.M{"interval": "30m"}) + event.Async(eventType.SchedulerEvery30Minutes, event.M{"interval": "30m"}) case <-every1h.C: - err, e = event.Trigger(eventType.SchedulerEveryHour, event.M{"interval": "1h"}) + event.Async(eventType.SchedulerEveryHour, event.M{"interval": "1h"}) case <-every1d.C: - err, e = event.Trigger(eventType.SchedulerEveryDay, event.M{"interval": "1d"}) - } - if err != nil { - slog.Warn("Scheduled task error:", "error", err, "event", e) + event.Async(eventType.SchedulerEveryDay, event.M{"interval": "1d"}) } } } diff --git a/internal/all.go b/internal/all.go index e8e6da3..6cc6612 100644 --- a/internal/all.go +++ b/internal/all.go @@ -4,6 +4,7 @@ import ( // Import all internal packages to ensure their init() functions are executed _ "github.com/komari-monitor/komari/internal/api_rpc" _ "github.com/komari-monitor/komari/internal/client" + _ "github.com/komari-monitor/komari/internal/cloudflared" _ "github.com/komari-monitor/komari/internal/common" _ "github.com/komari-monitor/komari/internal/conf" _ "github.com/komari-monitor/komari/internal/database" diff --git a/pkg/cloudflared/cloudflared.go b/internal/cloudflared/cloudflared.go similarity index 100% rename from pkg/cloudflared/cloudflared.go rename to internal/cloudflared/cloudflared.go diff --git a/pkg/cloudflared/cloudflared_test.go b/internal/cloudflared/cloudflared_test.go similarity index 85% rename from pkg/cloudflared/cloudflared_test.go rename to internal/cloudflared/cloudflared_test.go index abc1013..afd849e 100644 --- a/pkg/cloudflared/cloudflared_test.go +++ b/internal/cloudflared/cloudflared_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/komari-monitor/komari/pkg/cloudflared" + "github.com/komari-monitor/komari/internal/cloudflared" ) func TestRunCloudflared(t *testing.T) { diff --git a/internal/cloudflared/init.go b/internal/cloudflared/init.go new file mode 100644 index 0000000..907a7ab --- /dev/null +++ b/internal/cloudflared/init.go @@ -0,0 +1,28 @@ +package cloudflared + +import ( + "fmt" + "os" + "strings" + + "github.com/gookit/event" + "github.com/komari-monitor/komari/internal/eventType" +) + +func init() { + event.On(eventType.ServerInitializeStart, event.ListenerFunc(func(e event.Event) error { + if strings.ToLower(strings.ToLower(os.Getenv("KOMARI_ENABLE_CLOUDFLARED"))) == "true" { + err := RunCloudflared() + if err != nil { + // Error in ServerInitializeStart will cause the process to exit + return fmt.Errorf("failed to run cloudflared: %v", err) + } + } + return nil + })) + + event.On(eventType.ProcessExit, event.ListenerFunc(func(e event.Event) error { + Kill() + return nil + })) +} diff --git a/internal/conf/config.go b/internal/conf/config.go index 6b9c483..fd91a3a 100644 --- a/internal/conf/config.go +++ b/internal/conf/config.go @@ -97,19 +97,6 @@ func SaveFull(cst Config) error { return Override(cst) } -func Load() (*Config, error) { - b, err := os.ReadFile(flags.ConfigFile) - if err != nil { - return nil, err - } - cst := &Config{} - if err := json.Unmarshal(b, cst); err != nil { - return nil, err - } - Conf = cst - return cst, nil -} - // GetWithV1Format 以 v1 API 格式获取配置对象,使用 Conf 直接获取对象引用 func GetWithV1Format() (V1Struct, error) { return Conf.ToV1Format(), nil diff --git a/internal/conf/init.go b/internal/conf/init.go new file mode 100644 index 0000000..53d63a7 --- /dev/null +++ b/internal/conf/init.go @@ -0,0 +1,35 @@ +package conf + +import ( + "encoding/json" + "os" + + "github.com/gookit/event" + "github.com/komari-monitor/komari/cmd/flags" + "github.com/komari-monitor/komari/internal/eventType" +) + +func Init() { + + b, err := os.ReadFile(flags.ConfigFile) + if err != nil { + panic(err) + } + cst := &Config{} + if err := json.Unmarshal(b, cst); err != nil { + panic(err) + } + Conf = cst + event.Trigger(eventType.ConfigUpdated, event.M{ + "old": Config{}, + "new": *Conf, + }) +} + +func init() { + Conf = &Config{} + event.On(eventType.ProcessStart, event.ListenerFunc(func(e event.Event) error { + Init() + return nil + })) +} diff --git a/internal/database/dbcore/dbcore.go b/internal/database/dbcore/dbcore.go index fa3fbac..df1369f 100644 --- a/internal/database/dbcore/dbcore.go +++ b/internal/database/dbcore/dbcore.go @@ -5,8 +5,10 @@ import ( "log" "sync" + "github.com/gookit/event" "github.com/komari-monitor/komari/cmd/flags" "github.com/komari-monitor/komari/internal/database/models" + "github.com/komari-monitor/komari/internal/eventType" logutil "github.com/komari-monitor/komari/internal/log" "gorm.io/driver/mysql" "gorm.io/driver/sqlite" @@ -106,3 +108,10 @@ func GetDBInstance() *gorm.DB { }) return instance } + +func init() { + event.On(eventType.SchedulerEvery5Minutes, event.ListenerFunc(func(e event.Event) error { + instance.Exec("PRAGMA wal_checkpoint(TRUNCATE);") + return nil + })) +} diff --git a/internal/database/tasks/ping.go b/internal/database/tasks/ping.go index e58d66e..6104dbc 100644 --- a/internal/database/tasks/ping.go +++ b/internal/database/tasks/ping.go @@ -84,13 +84,9 @@ func DeleteAllPingRecords() error { } return result.Error } + func ReloadPingSchedule() error { - db := dbcore.GetDBInstance() - var pingTasks []models.PingTask - if err := db.Find(&pingTasks).Error; err != nil { - return err - } - return pingSchedule.ReloadPingSchedule(pingTasks) + return pingSchedule.ReloadPingSchedule() } func GetPingRecords(uuid string, taskId int, start, end time.Time) ([]models.PingRecord, error) { diff --git a/internal/eventType/events.go b/internal/eventType/events.go index 3afc4b9..841635c 100644 --- a/internal/eventType/events.go +++ b/internal/eventType/events.go @@ -21,12 +21,12 @@ const ( LoginFailed = "user.login.failed" // 用户登录失败 - ConfigUpdated = "config.updated" // 配置更改 + ConfigUpdated = "config.updated" // 配置更改。当服务器第一次启动载入配置时也会触发此事件,其中 old 全部为go类型零值, new 为载入的配置内容,若在配置载入前读取Conf,返回的将是零值配置。 - ProcessStart = "process.start" // 进程启动 + ProcessStart = "process.start" // 进程启动,如果在此事件的监听器中返回错误,进程将退出 ProcessExit = "process.exit" // 进程停止 - ServerInitializeStart = "server.routers.start" // 服务器路由初始化开始 + ServerInitializeStart = "server.routers.start" // 服务器路由初始化开始,如果在此事件的监听器中返回错误,进程将退出 ServerInitializeDone = "server.routers.done" // 服务器路由初始化完成 ServerListenGrpcStart = "server.listen.grpc.start" // 服务器开始监听 gRPC ServerListenGrpcStop = "server.listen.grpc.stop" // 服务器停止监听 gRPC @@ -41,7 +41,7 @@ const ( SchedulerEvery5Minutes = "scheduler.every5minutes" // 每五分钟定时触发 SchedulerEvery30Minutes = "scheduler.every30minutes" // 每三十分钟定时触发 SchedulerEveryHour = "scheduler.everyhour" // 每小时定时触发 - SchedulerEveryDay = "scheduler.everyday" // 每天定时触发 + SchedulerEveryDay = "scheduler.everyday" // 每天定时触发,服务器启动的当天不会触发此事件 NotificationSent = "notification.sent" // 通知发送 NotificationFailed = "notification.failed" // 通知发送失败 diff --git a/internal/geoip/geoip.go b/internal/geoip/geoip.go index dee5adc..5f4f00e 100644 --- a/internal/geoip/geoip.go +++ b/internal/geoip/geoip.go @@ -25,7 +25,7 @@ func init() { CurrentProvider = &EmptyProvider{} geoCache = cache.New(48*time.Hour, 1*time.Hour) - err := SetProvider(conf.Conf.GeoIp.GeoIpProvider) + err := SetProvider("empty") if err != nil { log.Printf("Failed to set initial GeoIP provider: %v", err) } diff --git a/internal/notifier/init.go b/internal/notifier/init.go index 8644af5..ffdda45 100644 --- a/internal/notifier/init.go +++ b/internal/notifier/init.go @@ -6,9 +6,13 @@ import ( ) func init() { - go CheckExpireScheduledWork() event.On(eventType.SchedulerEveryMinute, event.ListenerFunc(func(e event.Event) error { CheckTraffic() return nil })) + event.On(eventType.ServerInitializeDone, event.ListenerFunc(func(e event.Event) error { + go CheckExpireScheduledWork() + ReloadLoadNotification() + return nil + })) } diff --git a/internal/oauth/oauth.go b/internal/oauth/oauth.go index 870432f..a450480 100644 --- a/internal/oauth/oauth.go +++ b/internal/oauth/oauth.go @@ -71,19 +71,19 @@ func init() { } } - cfg, _ := conf.GetWithV1Format() - if cfg.OAuthProvider == "" || cfg.OAuthProvider == "none" { - LoadProvider("empty", "{}") - } - provider, err := database.GetOidcConfigByName(cfg.OAuthProvider) - if err != nil { - // 如果没有找到配置,使用empty provider - LoadProvider("empty", "{}") - } - err = LoadProvider(provider.Name, provider.Addition) - if err != nil { - log.Printf("Failed to load OIDC provider %s: %v", provider.Name, err) - } + // cfg, _ := conf.GetWithV1Format() + // if cfg.OAuthProvider == "" || cfg.OAuthProvider == "none" { + // LoadProvider("empty", "{}") + // } + // provider, err := database.GetOidcConfigByName(cfg.OAuthProvider) + // if err != nil { + // // 如果没有找到配置,使用empty provider + // LoadProvider("empty", "{}") + // } + // err = LoadProvider(provider.Name, provider.Addition) + // if err != nil { + // log.Printf("Failed to load OIDC provider %s: %v", provider.Name, err) + // } event.On(eventType.ConfigUpdated, event.ListenerFunc(func(e event.Event) error { oldConf, newConf, err := conf.FromEvent(e) diff --git a/internal/patch/patch.go b/internal/patch/patch.go index dca66a7..813d6d3 100644 --- a/internal/patch/patch.go +++ b/internal/patch/patch.go @@ -8,7 +8,8 @@ import ( "github.com/komari-monitor/komari/internal/database/models" ) -func ApplyPatch() { +func Apply() { + db := dbcore.GetDBInstance() // 0.0.5 迁移ClientInfo if db.Migrator().HasTable("client_infos") { diff --git a/internal/pingSchedule/init.go b/internal/pingSchedule/init.go new file mode 100644 index 0000000..6e7c694 --- /dev/null +++ b/internal/pingSchedule/init.go @@ -0,0 +1,12 @@ +package pingSchedule + +import ( + "github.com/gookit/event" + "github.com/komari-monitor/komari/internal/eventType" +) + +func init() { + event.On(eventType.ServerInitializeDone, event.ListenerFunc(func(e event.Event) error { + return ReloadPingSchedule() + })) +} diff --git a/internal/pingSchedule/pingSchedule.go b/internal/pingSchedule/pingSchedule.go index ddc0699..294aa0a 100644 --- a/internal/pingSchedule/pingSchedule.go +++ b/internal/pingSchedule/pingSchedule.go @@ -5,6 +5,7 @@ import ( "sync" "time" + "github.com/komari-monitor/komari/internal/database/dbcore" "github.com/komari-monitor/komari/internal/database/models" "github.com/komari-monitor/komari/internal/ws" ) @@ -107,7 +108,16 @@ func executePingTask(ctx context.Context, task models.PingTask, onlineClients ma } } -// ReloadPingSchedule 加载或重载时间表 -func ReloadPingSchedule(pingTasks []models.PingTask) error { +// ReloadPingScheduleWithTasks 加载或重载时间表 +func ReloadPingScheduleWithTasks(pingTasks []models.PingTask) error { + return manager.Reload(pingTasks) +} + +func ReloadPingSchedule() error { + db := dbcore.GetDBInstance() + var pingTasks []models.PingTask + if err := db.Find(&pingTasks).Error; err != nil { + return err + } return manager.Reload(pingTasks) } diff --git a/internal/restore/init.go b/internal/restore/init.go new file mode 100644 index 0000000..553910e --- /dev/null +++ b/internal/restore/init.go @@ -0,0 +1,15 @@ +package restore + +import ( + "github.com/gookit/event" + "github.com/komari-monitor/komari/internal/eventType" +) + +func init() { + event.On(eventType.ProcessStart, event.ListenerFunc(func(e event.Event) error { + if NeedBackupRestore() { + RestoreBackup() + } + return nil + })) +}