mirror of
https://github.com/gazer-x/komari.git
synced 2026-06-21 15:55:51 +08:00
refactor: 重构服务器启动、路由加载的初始化
This commit is contained in:
+6
-2
@@ -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)
|
||||
|
||||
+20
-56
@@ -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"})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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) {
|
||||
@@ -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
|
||||
}))
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}))
|
||||
}
|
||||
@@ -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
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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" // 通知发送失败
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}))
|
||||
}
|
||||
|
||||
+13
-13
@@ -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)
|
||||
|
||||
@@ -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") {
|
||||
|
||||
@@ -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()
|
||||
}))
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}))
|
||||
}
|
||||
Reference in New Issue
Block a user