Skip to content

Commit 62ac6bd

Browse files
committed
Update.
1 parent dec815b commit 62ac6bd

File tree

9 files changed

+445
-127
lines changed

9 files changed

+445
-127
lines changed

cmd/dashboard/controller/api_v1.go

Lines changed: 115 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/xos/serverstatus/db"
1313
"github.com/xos/serverstatus/model"
1414
"github.com/xos/serverstatus/pkg/mygin"
15+
"github.com/xos/serverstatus/pkg/utils"
1516
"github.com/xos/serverstatus/service/singleton"
1617
)
1718

@@ -24,11 +25,26 @@ var (
2425
monitorCacheMu sync.Mutex
2526
monitorCache = map[uint64]struct {
2627
ts time.Time
27-
data []*model.MonitorHistory
28+
data []byte // pre-encoded JSON payload
2829
dur time.Duration
2930
}{}
31+
// serverList/serverDetails 短时缓存
32+
listCacheMu sync.Mutex
33+
listCache = map[string]struct {
34+
ts time.Time
35+
data []byte
36+
}{}
3037
)
3138

39+
// writeJSONPayload 使用已编码的 JSON 字节并按需 gzip 输出
40+
func writeJSONPayload(c *gin.Context, status int, payload []byte) {
41+
c.Status(status)
42+
c.Writer.Header().Set("Content-Type", "application/json; charset=utf-8")
43+
if _, gz, _ := utils.GzipIfAccepted(c.Writer, c.Request, payload); !gz {
44+
_, _ = c.Writer.Write(payload)
45+
}
46+
}
47+
3248
func (v *apiV1) serve() {
3349
r := v.r.Group("")
3450
// 强制认证的 API
@@ -66,11 +82,33 @@ func (v *apiV1) serve() {
6682
// query: tag (服务器分组)
6783
func (v *apiV1) serverList(c *gin.Context) {
6884
tag := c.Query("tag")
69-
if tag != "" {
70-
c.JSON(200, singleton.ServerAPI.GetListByTag(tag))
85+
cacheKey := "serverList:tag=" + tag
86+
listCacheMu.Lock()
87+
if ce, ok := listCache[cacheKey]; ok && time.Since(ce.ts) <= 500*time.Millisecond {
88+
payload := ce.data
89+
listCacheMu.Unlock()
90+
writeJSONPayload(c, 200, payload)
7191
return
7292
}
73-
c.JSON(200, singleton.ServerAPI.GetAllList())
93+
listCacheMu.Unlock()
94+
95+
var res interface{}
96+
if tag != "" {
97+
res = singleton.ServerAPI.GetListByTag(tag)
98+
} else {
99+
res = singleton.ServerAPI.GetAllList()
100+
}
101+
payload, err := utils.EncodeJSON(res)
102+
if err != nil {
103+
payload, _ = utils.EncodeJSON([]any{})
104+
}
105+
listCacheMu.Lock()
106+
listCache[cacheKey] = struct {
107+
ts time.Time
108+
data []byte
109+
}{ts: time.Now(), data: payload}
110+
listCacheMu.Unlock()
111+
writeJSONPayload(c, 200, payload)
74112
}
75113

76114
// serverDetails 获取服务器信息 不传入Query参数则获取全部
@@ -88,15 +126,35 @@ func (v *apiV1) serverDetails(c *gin.Context) {
88126
}
89127
}
90128
tag := c.Query("tag")
91-
if tag != "" {
92-
c.JSON(200, singleton.ServerAPI.GetStatusByTag(tag))
129+
cacheKey := "serverDetails:id=" + c.Query("id") + "&tag=" + tag
130+
listCacheMu.Lock()
131+
if ce, ok := listCache[cacheKey]; ok && time.Since(ce.ts) <= 500*time.Millisecond {
132+
payload := ce.data
133+
listCacheMu.Unlock()
134+
writeJSONPayload(c, 200, payload)
93135
return
94136
}
95-
if len(idList) != 0 {
96-
c.JSON(200, singleton.ServerAPI.GetStatusByIDList(idList))
97-
return
137+
listCacheMu.Unlock()
138+
139+
var res interface{}
140+
if tag != "" {
141+
res = singleton.ServerAPI.GetStatusByTag(tag)
142+
} else if len(idList) != 0 {
143+
res = singleton.ServerAPI.GetStatusByIDList(idList)
144+
} else {
145+
res = singleton.ServerAPI.GetAllStatus()
98146
}
99-
c.JSON(200, singleton.ServerAPI.GetAllStatus())
147+
payload, err := utils.EncodeJSON(res)
148+
if err != nil {
149+
payload, _ = utils.EncodeJSON([]any{})
150+
}
151+
listCacheMu.Lock()
152+
listCache[cacheKey] = struct {
153+
ts time.Time
154+
data []byte
155+
}{ts: time.Now(), data: payload}
156+
listCacheMu.Unlock()
157+
writeJSONPayload(c, 200, payload)
100158
}
101159

102160
// RegisterServer adds a server and responds with the full ServerRegisterResponse
@@ -107,7 +165,7 @@ func (v *apiV1) RegisterServer(c *gin.Context) {
107165
var rs singleton.RegisterServer
108166
// Attempt to bind JSON to RegisterServer struct
109167
if err := c.ShouldBindJSON(&rs); err != nil {
110-
c.JSON(400, singleton.ServerRegisterResponse{
168+
WriteJSON(c, 400, singleton.ServerRegisterResponse{
111169
CommonResponse: singleton.CommonResponse{
112170
Code: 400,
113171
Message: "Parse JSON failed",
@@ -131,9 +189,9 @@ func (v *apiV1) RegisterServer(c *gin.Context) {
131189
response := singleton.ServerAPI.Register(&rs)
132190
// Respond with Secret only if in simple mode, otherwise full response
133191
if simple {
134-
c.JSON(response.Code, response.Secret)
192+
WriteJSON(c, response.Code, response.Secret)
135193
} else {
136-
c.JSON(response.Code, response)
194+
WriteJSON(c, response.Code, response)
137195
}
138196
}
139197

@@ -180,13 +238,17 @@ func (v *apiV1) monitorHistoriesById(c *gin.Context) {
180238
endTime := time.Now()
181239
startTime := endTime.Add(-duration)
182240

183-
// 命中短时缓存则直接返回
241+
// 命中短时缓存则直接返回(预编码 JSON)
184242
monitorCacheMu.Lock()
185243
if ce, ok := monitorCache[server.ID]; ok {
186244
if time.Since(ce.ts) <= 500*time.Millisecond && ce.dur == duration {
187-
data := ce.data
245+
payload := ce.data
188246
monitorCacheMu.Unlock()
189-
c.JSON(200, data)
247+
c.Status(200)
248+
c.Writer.Header().Set("Content-Type", "application/json; charset=utf-8")
249+
if _, gz, _ := utils.GzipIfAccepted(c.Writer, c.Request, payload); !gz {
250+
_, _ = c.Writer.Write(payload)
251+
}
190252
return
191253
}
192254
}
@@ -262,19 +324,35 @@ func (v *apiV1) monitorHistoriesById(c *gin.Context) {
262324
networkHistories = sampled
263325
}
264326

327+
// 预编码 JSON,减少后续重复编码
328+
payload, err := utils.EncodeJSON(networkHistories)
329+
if err != nil {
330+
// 回退到空数组
331+
payload, _ = utils.EncodeJSON([]any{})
332+
}
333+
265334
// 写入短时缓存
266335
monitorCacheMu.Lock()
267336
monitorCache[server.ID] = struct {
268337
ts time.Time
269-
data []*model.MonitorHistory
338+
data []byte
270339
dur time.Duration
271-
}{ts: time.Now(), data: networkHistories, dur: duration}
340+
}{ts: time.Now(), data: payload, dur: duration}
272341
monitorCacheMu.Unlock()
273342

274343
log.Printf("API /monitor/%d 返回 %d 条记录(范围: %v,所有监控器)", server.ID, len(networkHistories), duration)
275-
c.JSON(200, networkHistories)
344+
c.Status(200)
345+
c.Writer.Header().Set("Content-Type", "application/json; charset=utf-8")
346+
if _, gz, _ := utils.GzipIfAccepted(c.Writer, c.Request, payload); !gz {
347+
_, _ = c.Writer.Write(payload)
348+
}
276349
} else {
277-
c.JSON(200, []any{})
350+
payload, _ := utils.EncodeJSON([]any{})
351+
c.Status(200)
352+
c.Writer.Header().Set("Content-Type", "application/json; charset=utf-8")
353+
if _, gz, _ := utils.GzipIfAccepted(c.Writer, c.Request, payload); !gz {
354+
_, _ = c.Writer.Write(payload)
355+
}
278356
}
279357
} else {
280358
// SQLite 模式下恢复原始查询逻辑
@@ -289,13 +367,25 @@ func (v *apiV1) monitorHistoriesById(c *gin.Context) {
289367
Order("created_at DESC").
290368
Find(&networkHistories).Error
291369

370+
var payload []byte
292371
if err != nil {
293-
c.JSON(200, []any{})
372+
payload, _ = utils.EncodeJSON([]any{})
294373
} else {
295-
c.JSON(200, networkHistories)
374+
// 与 Badger 分支一致:预编码 + gzip 按需
375+
payload, _ = utils.EncodeJSON(networkHistories)
376+
}
377+
c.Status(200)
378+
c.Writer.Header().Set("Content-Type", "application/json; charset=utf-8")
379+
if _, gz, _ := utils.GzipIfAccepted(c.Writer, c.Request, payload); !gz {
380+
_, _ = c.Writer.Write(payload)
296381
}
297382
} else {
298-
c.JSON(200, []any{})
383+
payload, _ := utils.EncodeJSON([]any{})
384+
c.Status(200)
385+
c.Writer.Header().Set("Content-Type", "application/json; charset=utf-8")
386+
if _, gz, _ := utils.GzipIfAccepted(c.Writer, c.Request, payload); !gz {
387+
_, _ = c.Writer.Write(payload)
388+
}
299389
}
300390
}
301391
}
@@ -304,8 +394,8 @@ func (v *apiV1) monitorConfigs(c *gin.Context) {
304394
// 获取监控配置列表
305395
if singleton.ServiceSentinelShared != nil {
306396
monitors := singleton.ServiceSentinelShared.Monitors()
307-
c.JSON(200, monitors)
397+
WriteJSON(c, 200, monitors)
308398
} else {
309-
c.JSON(200, []interface{}{})
399+
WriteJSON(c, 200, []interface{}{})
310400
}
311401
}

0 commit comments

Comments
 (0)