Skip to content

Commit 39f849d

Browse files
committed
wip: 引入事件驱动
1 parent 53b3d7d commit 39f849d

File tree

12 files changed

+368
-207
lines changed

12 files changed

+368
-207
lines changed

cmd/root.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import (
44
"fmt"
55
"os"
66

7+
"github.com/gookit/event"
78
"github.com/komari-monitor/komari/cmd/flags"
9+
"github.com/komari-monitor/komari/internal/eventType"
810

911
"github.com/spf13/cobra"
1012
)
@@ -40,6 +42,8 @@ Made by Akizon77 with love.`,
4042
}
4143

4244
func Execute() {
45+
event.Trigger(eventType.ProcessStart, nil)
46+
defer event.Trigger(eventType.ProcessExit, nil)
4347
if err := RootCmd.Execute(); err != nil {
4448
fmt.Fprintln(os.Stderr, err)
4549
os.Exit(1)

cmd/server.go

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"time"
1313

1414
"github.com/gin-gonic/gin"
15+
"github.com/gookit/event"
1516
"github.com/komari-monitor/komari/cmd/flags"
1617
api "github.com/komari-monitor/komari/internal/api_v1"
1718
"github.com/komari-monitor/komari/internal/database"
@@ -23,6 +24,7 @@ import (
2324
d_notification "github.com/komari-monitor/komari/internal/database/notification"
2425
"github.com/komari-monitor/komari/internal/database/records"
2526
"github.com/komari-monitor/komari/internal/database/tasks"
27+
"github.com/komari-monitor/komari/internal/eventType"
2628
"github.com/komari-monitor/komari/internal/geoip"
2729
logutil "github.com/komari-monitor/komari/internal/log"
2830
"github.com/komari-monitor/komari/internal/messageSender"
@@ -57,25 +59,35 @@ func RunServer() {
5759
log.Fatalf("Failed to create theme directory: %v", err)
5860
}
5961
InitDatabase()
62+
6063
if version.VersionHash != "unknown" {
6164
gin.SetMode(gin.ReleaseMode)
6265
}
66+
6367
conf, err := config.Get()
6468
if err != nil {
6569
log.Fatal(err)
6670
}
71+
72+
r := gin.New()
73+
r.Use(logutil.GinLogger())
74+
r.Use(logutil.GinRecovery())
75+
76+
event.Trigger(eventType.ServerInitializeStart, event.M{"config": conf, "engine": r})
77+
defer event.Trigger(eventType.ServerInitializeDone, event.M{"config": conf})
78+
6779
go geoip.InitGeoIp()
6880
go DoScheduledWork()
6981
go messageSender.Initialize()
7082
go oauth.Initialize()
7183

72-
if conf.NezhaCompatEnabled {
73-
server.StartNezhaGRPCServer(conf.NezhaCompatListen)
74-
}
84+
server.StartNezhaGRPCServer(conf.NezhaCompatListen)
7585

76-
config.Subscribe(func(event config.ConfigEvent) {
77-
if event.New.OAuthProvider != event.Old.OAuthProvider {
78-
oidcProvider, err := database.GetOidcConfigByName(event.New.OAuthProvider)
86+
event.On(eventType.ConfigUpdated, event.ListenerFunc(func(e event.Event) error {
87+
newConf := e.Get("new").(models.Config)
88+
oldConf := e.Get("old").(models.Config)
89+
if newConf.OAuthProvider != oldConf.OAuthProvider {
90+
oidcProvider, err := database.GetOidcConfigByName(newConf.OAuthProvider)
7991
if err != nil {
8092
log.Printf("Failed to get OIDC provider config: %v", err)
8193
} else {
@@ -86,10 +98,11 @@ func RunServer() {
8698
auditlog.EventLog("error", fmt.Sprintf("Failed to load OIDC provider: %v", err))
8799
}
88100
}
89-
if event.New.NotificationMethod != event.Old.NotificationMethod {
101+
if newConf.NotificationMethod != oldConf.NotificationMethod {
90102
messageSender.Initialize()
91103
}
92-
})
104+
return nil
105+
}), event.Max)
93106

94107
// 初始化 cloudflared
95108
if strings.ToLower(GetEnv("KOMARI_ENABLE_CLOUDFLARED", "false")) == "true" {
@@ -99,9 +112,6 @@ func RunServer() {
99112
}
100113
}
101114

102-
r := gin.New()
103-
r.Use(logutil.GinLogger())
104-
r.Use(logutil.GinRecovery())
105115
server.Init(r)
106116

107117
srv := &http.Server{

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ require (
4848
github.com/go-sql-driver/mysql v1.9.2 // indirect
4949
github.com/goccy/go-json v0.10.5 // indirect
5050
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect
51+
github.com/gookit/event v1.2.0 // indirect
52+
github.com/gookit/goutil v0.7.1 // indirect
5153
github.com/inconshreveable/mousetrap v1.1.0 // indirect
5254
github.com/jinzhu/inflection v1.0.0 // indirect
5355
github.com/jinzhu/now v1.1.5 // indirect

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQu
6363
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
6464
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
6565
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
66+
github.com/gookit/event v1.2.0 h1:aa8ouNVlo4E/NRhHVXNU/JbWvlr91Gjh423WtCDYQ4Q=
67+
github.com/gookit/event v1.2.0/go.mod h1:gGYybJL0HEEo/+UmBN+MgLqUBIxcCGOP8FrLPk+J8w4=
68+
github.com/gookit/goutil v0.7.1 h1:AaFJPN9mrdeYBv8HOybri26EHGCC34WJVT7jUStGJsI=
69+
github.com/gookit/goutil v0.7.1/go.mod h1:vJS9HXctYTCLtCsZot5L5xF+O1oR17cDYO9R0HxBmnU=
6670
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
6771
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
6872
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=

internal/database/config/config.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ import (
66
"sync"
77
"time"
88

9+
"github.com/gookit/event"
910
"github.com/komari-monitor/komari/internal/database/dbcore"
1011
"github.com/komari-monitor/komari/internal/database/models"
12+
"github.com/komari-monitor/komari/internal/eventType"
1113
"gorm.io/gorm"
1214
)
1315

@@ -61,6 +63,7 @@ func Save(cst models.Config) error {
6163
}
6264
newConfig, _ := Get()
6365
publishEvent(oldConfig, newConfig)
66+
event.Trigger(eventType.ConfigUpdated, event.M{"old": oldConfig, "new": newConfig})
6467
return nil
6568
}
6669

@@ -103,6 +106,7 @@ func Update(cst map[string]interface{}) error {
103106
if err := tx.Where("id = ?", oldConfig.ID).First(newConfig).Error; err != nil {
104107
return errors.Join(err, errors.New("failed to retrieve updated configuration"))
105108
}
109+
event.Trigger(eventType.ConfigUpdated, event.M{"old": oldConfig, "new": *newConfig})
106110
publishEvent(oldConfig, *newConfig)
107111
return nil
108112
})

internal/eventType/events.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package eventType
2+
3+
const (
4+
ClientWebsocketConnected = "client.websocket.connected" // 客户端通过 websocket 连接
5+
ClientWebsocketDisconnected = "client.websocket.disconnected" // 客户端断开 websocket 连接
6+
ClientMessageReceived = "client.message.received" // 收到客户端消息
7+
ClientCreated = "client.created" // 新客户端创建
8+
ClientUpdated = "client.updated" // 客户端信息更新
9+
ClientDeleted = "client.deleted" // 客户端删除
10+
ClientRenewed = "client.renewed" // 客户端续期
11+
12+
UserUpdateUsername = "user.update.username" // 用户更改用户名
13+
UserUpdatePassword = "user.update.password" // 用户更改密码
14+
UserLogin = "user.login.succeeded" // 用户登录
15+
UserLogout = "user.logout" // 用户登出
16+
UserOidcBound = "user.oidc.bound" // 用户绑定 OIDC
17+
UserOidcUnbound = "user.oidc.unbound" // 用户解绑 OIDC
18+
UserTwoFaAdded = "user.2fa.added" // 用户添加 2FA
19+
UserTwoFaRemoved = "user.2fa.removed" // 用户移除 2FA
20+
UserSessionRevoked = "user.session.revoked" // 用户会话撤销
21+
22+
LoginFailed = "user.login.failed" // 用户登录失败
23+
24+
ConfigUpdated = "config.updated" // 配置更改
25+
26+
ProcessStart = "process.start" // 进程启动
27+
ProcessExit = "process.exit" // 进程停止
28+
29+
ServerInitializeStart = "server.routers.start" // 服务器路由初始化开始
30+
ServerInitializeDone = "server.routers.done" // 服务器路由初始化完成
31+
ServerListenGrpcStart = "server.listen.grpc.start" // 服务器开始监听 gRPC
32+
ServerListenGrpcStop = "server.listen.grpc.stop" // 服务器停止监听 gRPC
33+
34+
TaskCreated = "task.created" // 任务创建
35+
TaskUpdated = "task.updated" // 任务更新
36+
37+
HttpRequestReceived = "http.request.received" // 收到 HTTP 请求
38+
39+
SchedulerDatabase = "scheduler.database" // 数据库定时任务
40+
SchedulerEveryMinute = "scheduler.everyminute" // 每分钟定时触发
41+
SchedulerEvery5Minutes = "scheduler.every5minutes" // 每五分钟定时触发
42+
SchedulerEvery30Minutes = "scheduler.every30minutes" // 每三十分钟定时触发
43+
SchedulerEveryHour = "scheduler.everyhour" // 每小时定时触发
44+
SchedulerEveryDay = "scheduler.everyday" // 每天定时触发
45+
46+
NotificationSent = "notification.sent" // 通知发送
47+
NotificationFailed = "notification.failed" // 通知发送失败
48+
49+
TerminalEstablished = "terminal.established" // 终端连接建立
50+
TerminalClosed = "terminal.closed" // 终端连接关闭
51+
52+
GeoIpUpdateStart = "geoip.update.start" // GeoIP 数据库更新开始
53+
GeoIpUpdateDone = "geoip.update.done" // GeoIP 数据库更新完成
54+
GeoIpUpdateFailed = "geoip.update.failed" // GeoIP 数据库更新失败
55+
)

internal/internal.go

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
package internal
2+
3+
import (
4+
"github.com/gin-gonic/gin"
5+
api "github.com/komari-monitor/komari/internal/api_v1"
6+
"github.com/komari-monitor/komari/internal/api_v1/admin"
7+
"github.com/komari-monitor/komari/internal/api_v1/admin/clipboard"
8+
log_api "github.com/komari-monitor/komari/internal/api_v1/admin/log"
9+
"github.com/komari-monitor/komari/internal/api_v1/admin/notification"
10+
"github.com/komari-monitor/komari/internal/api_v1/admin/test"
11+
"github.com/komari-monitor/komari/internal/api_v1/admin/update"
12+
"github.com/komari-monitor/komari/internal/api_v1/client"
13+
"github.com/komari-monitor/komari/internal/api_v1/jsonRpc"
14+
"github.com/komari-monitor/komari/internal/api_v1/record"
15+
"github.com/komari-monitor/komari/internal/api_v1/task"
16+
"github.com/komari-monitor/komari/internal/database/models"
17+
)
18+
19+
func LoadApiV1Routes(r *gin.Engine, conf models.Config) {
20+
r.Use(func(c *gin.Context) {
21+
if len(c.Request.URL.Path) >= 4 && c.Request.URL.Path[:4] == "/api" {
22+
c.Header("Cache-Control", "no-store")
23+
}
24+
c.Next()
25+
})
26+
27+
r.Use(api.PrivateSiteMiddleware())
28+
29+
r.Any("/ping", func(c *gin.Context) {
30+
c.String(200, "pong")
31+
})
32+
// #region 公开路由
33+
r.POST("/api/login", api.Login)
34+
r.GET("/api/me", api.GetMe)
35+
r.GET("/api/clients", api.GetClients)
36+
r.GET("/api/nodes", api.GetNodesInformation)
37+
r.GET("/api/public", api.GetPublicSettings)
38+
r.GET("/api/oauth", api.OAuth)
39+
r.GET("/api/oauth_callback", api.OAuthCallback)
40+
r.GET("/api/logout", api.Logout)
41+
r.GET("/api/version", api.GetVersion)
42+
r.GET("/api/recent/:uuid", api.GetClientRecentRecords)
43+
44+
r.GET("/api/records/load", record.GetRecordsByUUID)
45+
r.GET("/api/records/ping", record.GetPingRecords)
46+
r.GET("/api/task/ping", task.GetPublicPingTasks)
47+
r.GET("/api/rpc2", jsonRpc.OnRpcRequest)
48+
r.POST("/api/rpc2", jsonRpc.OnRpcRequest)
49+
50+
// #region Agent
51+
r.POST("/api/clients/register", client.RegisterClient)
52+
tokenAuthrized := r.Group("/api/clients", api.TokenAuthMiddleware())
53+
{
54+
tokenAuthrized.GET("/report", client.WebSocketReport) // websocket
55+
tokenAuthrized.POST("/uploadBasicInfo", client.UploadBasicInfo)
56+
tokenAuthrized.POST("/report", client.UploadReport)
57+
tokenAuthrized.GET("/terminal", client.EstablishConnection)
58+
tokenAuthrized.POST("/task/result", client.TaskResult)
59+
}
60+
// #region 管理员
61+
adminAuthrized := r.Group("/api/admin", api.AdminAuthMiddleware())
62+
{
63+
adminAuthrized.GET("/download/backup", admin.DownloadBackup)
64+
adminAuthrized.POST("/upload/backup", admin.UploadBackup)
65+
// test
66+
testGroup := adminAuthrized.Group("/test")
67+
{
68+
testGroup.GET("/geoip", test.TestGeoIp)
69+
testGroup.POST("/sendMessage", test.TestSendMessage)
70+
}
71+
// update
72+
updateGroup := adminAuthrized.Group("/update")
73+
{
74+
updateGroup.POST("/mmdb", update.UpdateMmdbGeoIP)
75+
updateGroup.POST("/user", update.UpdateUser)
76+
updateGroup.PUT("/favicon", update.UploadFavicon)
77+
updateGroup.POST("/favicon", update.DeleteFavicon)
78+
}
79+
// tasks
80+
taskGroup := adminAuthrized.Group("/task")
81+
{
82+
taskGroup.GET("/all", admin.GetTasks)
83+
taskGroup.POST("/exec", admin.Exec)
84+
taskGroup.GET("/:task_id", admin.GetTaskById)
85+
taskGroup.GET("/:task_id/result", admin.GetTaskResultsByTaskId)
86+
taskGroup.GET("/:task_id/result/:uuid", admin.GetSpecificTaskResult)
87+
taskGroup.GET("/client/:uuid", admin.GetTasksByClientId)
88+
}
89+
// settings
90+
settingsGroup := adminAuthrized.Group("/settings")
91+
{
92+
settingsGroup.GET("/", admin.GetSettings)
93+
settingsGroup.POST("/", admin.EditSettings)
94+
settingsGroup.POST("/oidc", admin.SetOidcProvider)
95+
settingsGroup.GET("/oidc", admin.GetOidcProvider)
96+
settingsGroup.POST("/message-sender", admin.SetMessageSenderProvider)
97+
settingsGroup.GET("/message-sender", admin.GetMessageSenderProvider)
98+
}
99+
// themes
100+
themeGroup := adminAuthrized.Group("/theme")
101+
{
102+
themeGroup.PUT("/upload", admin.UploadTheme)
103+
themeGroup.GET("/list", admin.ListThemes)
104+
themeGroup.POST("/delete", admin.DeleteTheme)
105+
themeGroup.GET("/set", admin.SetTheme)
106+
themeGroup.POST("/update", admin.UpdateTheme)
107+
themeGroup.POST("/settings", admin.UpdateThemeSettings)
108+
}
109+
// clients
110+
clientGroup := adminAuthrized.Group("/client")
111+
{
112+
clientGroup.POST("/add", admin.AddClient)
113+
clientGroup.GET("/list", admin.ListClients)
114+
clientGroup.GET("/:uuid", admin.GetClient)
115+
clientGroup.POST("/:uuid/edit", admin.EditClient)
116+
clientGroup.POST("/:uuid/remove", admin.RemoveClient)
117+
clientGroup.GET("/:uuid/token", admin.GetClientToken)
118+
clientGroup.POST("/order", admin.OrderWeight)
119+
// client terminal
120+
clientGroup.GET("/:uuid/terminal", api.RequestTerminal)
121+
}
122+
123+
// records
124+
recordGroup := adminAuthrized.Group("/record")
125+
{
126+
recordGroup.POST("/clear", admin.ClearRecord)
127+
recordGroup.POST("/clear/all", admin.ClearAllRecords)
128+
}
129+
// oauth2
130+
oauth2Group := adminAuthrized.Group("/oauth2")
131+
{
132+
oauth2Group.GET("/bind", admin.BindingExternalAccount)
133+
oauth2Group.POST("/unbind", admin.UnbindExternalAccount)
134+
}
135+
sessionGroup := adminAuthrized.Group("/session")
136+
{
137+
sessionGroup.GET("/get", admin.GetSessions)
138+
sessionGroup.POST("/remove", admin.DeleteSession)
139+
sessionGroup.POST("/remove/all", admin.DeleteAllSession)
140+
}
141+
two_factorGroup := adminAuthrized.Group("/2fa")
142+
{
143+
two_factorGroup.GET("/generate", admin.Generate2FA)
144+
two_factorGroup.POST("/enable", admin.Enable2FA)
145+
two_factorGroup.POST("/disable", admin.Disable2FA)
146+
}
147+
adminAuthrized.GET("/logs", log_api.GetLogs)
148+
149+
// clipboard
150+
clipboardGroup := adminAuthrized.Group("/clipboard")
151+
{
152+
clipboardGroup.GET("/:id", clipboard.GetClipboard)
153+
clipboardGroup.GET("", clipboard.ListClipboard)
154+
clipboardGroup.POST("", clipboard.CreateClipboard)
155+
clipboardGroup.POST("/:id", clipboard.UpdateClipboard)
156+
clipboardGroup.POST("/remove", clipboard.BatchDeleteClipboard)
157+
clipboardGroup.POST("/:id/remove", clipboard.DeleteClipboard)
158+
}
159+
160+
notificationGroup := adminAuthrized.Group("/notification")
161+
{
162+
// offline notifications
163+
notificationGroup.GET("/offline", notification.ListOfflineNotifications)
164+
notificationGroup.POST("/offline/edit", notification.EditOfflineNotification)
165+
notificationGroup.POST("/offline/enable", notification.EnableOfflineNotification)
166+
notificationGroup.POST("/offline/disable", notification.DisableOfflineNotification)
167+
loadAlertGroup := notificationGroup.Group("/load")
168+
{
169+
loadAlertGroup.GET("/", notification.GetAllLoadNotifications)
170+
loadAlertGroup.POST("/add", notification.AddLoadNotification)
171+
loadAlertGroup.POST("/delete", notification.DeleteLoadNotification)
172+
loadAlertGroup.POST("/edit", notification.EditLoadNotification)
173+
}
174+
}
175+
176+
pingTaskGroup := adminAuthrized.Group("/ping")
177+
{
178+
pingTaskGroup.GET("/", admin.GetAllPingTasks)
179+
pingTaskGroup.POST("/add", admin.AddPingTask)
180+
pingTaskGroup.POST("/delete", admin.DeletePingTask)
181+
pingTaskGroup.POST("/edit", admin.EditPingTask)
182+
183+
}
184+
185+
}
186+
}

0 commit comments

Comments
 (0)