Skip to content

Commit 41a5825

Browse files
committed
Update.
1 parent d4bff63 commit 41a5825

File tree

5 files changed

+165
-26
lines changed

5 files changed

+165
-26
lines changed

model/server.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,22 @@ type Server struct {
2626

2727
DDNSProfilesRaw string `gorm:"default:'[]';column:ddns_profiles_raw" json:"-"`
2828

29-
Host *Host `gorm:"-"`
30-
State *HostState `gorm:"-"`
31-
LastActive time.Time `gorm:"-"`
29+
Host *Host `gorm:"-"`
30+
State *HostState `gorm:"-"`
31+
LastActive time.Time `gorm:"-"`
32+
LastStateBeforeOffline *HostState `gorm:"-" json:"-"` // 离线前最后一次状态
33+
IsOnline bool `gorm:"-" json:"is_online"` // 是否在线
3234

33-
TaskClose chan error `gorm:"-" json:"-"`
34-
TaskCloseLock *sync.Mutex `gorm:"-" json:"-"`
35+
TaskClose chan error `gorm:"-" json:"-"`
36+
TaskCloseLock *sync.Mutex `gorm:"-" json:"-"`
3537
TaskStream pb.ServerService_RequestTaskServer `gorm:"-" json:"-"`
3638

3739
PrevTransferInSnapshot int64 `gorm:"-" json:"-"` // 上次数据点时的入站使用量
3840
PrevTransferOutSnapshot int64 `gorm:"-" json:"-"` // 上次数据点时的出站使用量
41+
42+
// 累计流量数据
43+
CumulativeNetInTransfer uint64 `gorm:"default:0" json:"cumulative_net_in_transfer"` // 累计入站使用量
44+
CumulativeNetOutTransfer uint64 `gorm:"default:0" json:"cumulative_net_out_transfer"` // 累计出站使用量
3945
}
4046

4147
func (s *Server) CopyFromRunningServer(old *Server) {
@@ -47,6 +53,10 @@ func (s *Server) CopyFromRunningServer(old *Server) {
4753
s.TaskStream = old.TaskStream
4854
s.PrevTransferInSnapshot = old.PrevTransferInSnapshot
4955
s.PrevTransferOutSnapshot = old.PrevTransferOutSnapshot
56+
s.LastStateBeforeOffline = old.LastStateBeforeOffline
57+
s.IsOnline = old.IsOnline
58+
s.CumulativeNetInTransfer = old.CumulativeNetInTransfer
59+
s.CumulativeNetOutTransfer = old.CumulativeNetOutTransfer
5060
}
5161

5262
func (s *Server) AfterFind(tx *gorm.DB) error {

service/rpc/server.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,23 @@ func (s *ServerHandler) ReportSystemState(c context.Context, r *pb.State) (*pb.R
111111
state := model.PB2State(r)
112112
singleton.ServerLock.RLock()
113113
defer singleton.ServerLock.RUnlock()
114+
115+
// 更新服务器在线状态
116+
singleton.ServerList[clientID].IsOnline = true
114117
singleton.ServerList[clientID].LastActive = time.Now()
118+
119+
// 将当前状态与以前累计的流量合并
120+
state.NetInTransfer += singleton.ServerList[clientID].CumulativeNetInTransfer
121+
state.NetOutTransfer += singleton.ServerList[clientID].CumulativeNetOutTransfer
122+
123+
// 保存当前状态
115124
singleton.ServerList[clientID].State = &state
116125

126+
// 备份当前状态,用于离线后显示
127+
lastState := model.HostState{}
128+
copier.Copy(&lastState, &state)
129+
singleton.ServerList[clientID].LastStateBeforeOffline = &lastState
130+
117131
// 应对 dashboard 重启的情况,如果从未记录过,先打点,等到小时时间点时入库
118132
if singleton.ServerList[clientID].PrevTransferInSnapshot == 0 || singleton.ServerList[clientID].PrevTransferOutSnapshot == 0 {
119133
singleton.ServerList[clientID].PrevTransferInSnapshot = int64(state.NetInTransfer)
@@ -175,6 +189,19 @@ func (s *ServerHandler) ReportSystemInfo(c context.Context, r *pb.Host) (*pb.Rec
175189
* 这是可以借助上报顺序的空档,将停机前的流量统计数据标记下来,加到下一个小时的数据点上
176190
*/
177191
if singleton.ServerList[clientID].Host != nil && singleton.ServerList[clientID].Host.BootTime < host.BootTime {
192+
// 服务器重启了,将当前的流量数据保存到累计数据中
193+
if singleton.ServerList[clientID].State != nil {
194+
// 更新累计流量
195+
singleton.ServerList[clientID].CumulativeNetInTransfer = singleton.ServerList[clientID].State.NetInTransfer
196+
singleton.ServerList[clientID].CumulativeNetOutTransfer = singleton.ServerList[clientID].State.NetOutTransfer
197+
198+
// 保存累计流量到数据库
199+
singleton.DB.Model(singleton.ServerList[clientID]).Updates(map[string]interface{}{
200+
"cumulative_net_in_transfer": singleton.ServerList[clientID].CumulativeNetInTransfer,
201+
"cumulative_net_out_transfer": singleton.ServerList[clientID].CumulativeNetOutTransfer,
202+
})
203+
}
204+
178205
singleton.ServerList[clientID].PrevTransferInSnapshot = singleton.ServerList[clientID].PrevTransferInSnapshot - int64(singleton.ServerList[clientID].State.NetInTransfer)
179206
singleton.ServerList[clientID].PrevTransferOutSnapshot = singleton.ServerList[clientID].PrevTransferOutSnapshot - int64(singleton.ServerList[clientID].State.NetOutTransfer)
180207
}

service/singleton/api.go

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,17 @@ type CommonResponse struct {
2626
}
2727

2828
type RegisterServer struct {
29-
Name string
30-
Tag string
31-
Note string
29+
Name string
30+
Tag string
31+
Note string
3232
HideForGuest string
3333
}
3434

3535
type ServerRegisterResponse struct {
3636
CommonResponse
37-
Secret string `json:"secret"`
37+
Secret string `json:"secret"`
3838
}
3939

40-
4140
type CommonServerInfo struct {
4241
ID uint64 `json:"id"`
4342
Name string `json:"name"`
@@ -116,19 +115,34 @@ func (s *ServerAPIService) GetStatusByIDList(idList []uint64) *ServerStatusRespo
116115
}
117116
ipv4, ipv6, validIP := utils.SplitIPAddr(server.Host.IP)
118117
info := CommonServerInfo{
119-
ID: server.ID,
120-
Name: server.Name,
121-
Tag: server.Tag,
122-
LastActive: server.LastActive.Unix(),
123-
IPV4: ipv4,
124-
IPV6: ipv6,
125-
ValidIP: validIP,
118+
ID: server.ID,
119+
Name: server.Name,
120+
Tag: server.Tag,
121+
LastActive: server.LastActive.Unix(),
122+
IPV4: ipv4,
123+
IPV6: ipv6,
124+
ValidIP: validIP,
125+
DisplayIndex: server.DisplayIndex,
126+
HideForGuest: server.HideForGuest,
126127
}
127-
res.Result = append(res.Result, &StatusResponse{
128-
CommonServerInfo: info,
129-
Host: server.Host,
130-
Status: server.State,
131-
})
128+
129+
// 如果服务器离线但有最后状态,使用最后状态
130+
var statusData *StatusResponse
131+
if !server.IsOnline && server.LastStateBeforeOffline != nil {
132+
statusData = &StatusResponse{
133+
CommonServerInfo: info,
134+
Host: server.Host,
135+
Status: server.LastStateBeforeOffline,
136+
}
137+
} else {
138+
statusData = &StatusResponse{
139+
CommonServerInfo: info,
140+
Host: server.Host,
141+
Status: server.State,
142+
}
143+
}
144+
145+
res.Result = append(res.Result, statusData)
132146
}
133147
res.CommonResponse = CommonResponse{
134148
Code: 0,
@@ -166,10 +180,19 @@ func (s *ServerAPIService) GetAllStatus() *ServerStatusResponse {
166180
DisplayIndex: v.DisplayIndex,
167181
HideForGuest: v.HideForGuest,
168182
}
183+
184+
// 如果服务器离线但有最后状态,使用最后状态
185+
var status *model.HostState
186+
if !v.IsOnline && v.LastStateBeforeOffline != nil {
187+
status = v.LastStateBeforeOffline
188+
} else {
189+
status = v.State
190+
}
191+
169192
res.Result = append(res.Result, &StatusResponse{
170193
CommonServerInfo: info,
171194
Host: v.Host,
172-
Status: v.State,
195+
Status: status,
173196
})
174197
}
175198
res.CommonResponse = CommonResponse{

service/singleton/server.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ func loadServers() {
3434
innerS := s
3535
innerS.Host = &model.Host{}
3636
innerS.State = &model.HostState{}
37+
innerS.LastStateBeforeOffline = nil
38+
innerS.IsOnline = false // 初始状态为离线,等待agent报告
3739
innerS.TaskCloseLock = new(sync.Mutex)
3840
ServerList[innerS.ID] = &innerS
3941
SecretToID[innerS.Secret] = innerS.ID

service/singleton/singleton.go

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"gorm.io/driver/sqlite"
99
"gorm.io/gorm"
1010

11+
"github.com/jinzhu/copier"
1112
"github.com/xos/serverstatus/model"
1213
"github.com/xos/serverstatus/pkg/utils"
1314
)
@@ -39,6 +40,9 @@ func LoadSingleton() {
3940
loadAPI()
4041
initNAT()
4142
initDDNS()
43+
44+
// 添加定时检查在线状态的任务,每分钟检查一次
45+
Cron.AddFunc("*/1 * * * *", CheckServerOnlineStatus)
4246
}
4347

4448
// InitConfigFromPath 从给出的文件路径中加载配置
@@ -69,6 +73,21 @@ func InitDBFromPath(path string) {
6973
if err != nil {
7074
panic(err)
7175
}
76+
77+
// 检查并添加新字段
78+
if !DB.Migrator().HasColumn(&model.Server{}, "cumulative_net_in_transfer") {
79+
err = DB.Migrator().AddColumn(&model.Server{}, "cumulative_net_in_transfer")
80+
if err != nil {
81+
log.Println("NG>> 添加cumulative_net_in_transfer字段失败:", err)
82+
}
83+
}
84+
85+
if !DB.Migrator().HasColumn(&model.Server{}, "cumulative_net_out_transfer") {
86+
err = DB.Migrator().AddColumn(&model.Server{}, "cumulative_net_out_transfer")
87+
if err != nil {
88+
log.Println("NG>> 添加cumulative_net_out_transfer字段失败:", err)
89+
}
90+
}
7291
}
7392

7493
// RecordTransferHourlyUsage 对流量记录进行打点
@@ -78,7 +97,13 @@ func RecordTransferHourlyUsage() {
7897
now := time.Now()
7998
nowTrimSeconds := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location())
8099
var txs []model.Transfer
100+
var serversToUpdate []model.Server
101+
81102
for id, server := range ServerList {
103+
if server.State == nil {
104+
continue
105+
}
106+
82107
tx := model.Transfer{
83108
ServerID: id,
84109
In: utils.Uint64SubInt64(server.State.NetInTransfer, server.PrevTransferInSnapshot),
@@ -89,13 +114,33 @@ func RecordTransferHourlyUsage() {
89114
}
90115
server.PrevTransferInSnapshot = int64(server.State.NetInTransfer)
91116
server.PrevTransferOutSnapshot = int64(server.State.NetOutTransfer)
117+
118+
// 每次记录时更新累计流量到数据库
119+
if server.State.NetInTransfer > 0 || server.State.NetOutTransfer > 0 {
120+
serversToUpdate = append(serversToUpdate, model.Server{
121+
Common: model.Common{ID: id},
122+
CumulativeNetInTransfer: server.State.NetInTransfer,
123+
CumulativeNetOutTransfer: server.State.NetOutTransfer,
124+
})
125+
}
126+
92127
tx.CreatedAt = nowTrimSeconds
93128
txs = append(txs, tx)
94129
}
95-
if len(txs) == 0 {
96-
return
130+
131+
if len(txs) > 0 {
132+
log.Println("NG>> Cron 流量统计入库", len(txs), DB.Create(txs).Error)
133+
}
134+
135+
// 批量更新累计流量数据
136+
if len(serversToUpdate) > 0 {
137+
for _, server := range serversToUpdate {
138+
DB.Model(&server).Updates(map[string]interface{}{
139+
"cumulative_net_in_transfer": server.CumulativeNetInTransfer,
140+
"cumulative_net_out_transfer": server.CumulativeNetOutTransfer,
141+
})
142+
}
97143
}
98-
log.Println("NG>> Cron 流量统计入库", len(txs), DB.Create(txs).Error)
99144
}
100145

101146
// CleanMonitorHistory 清理无效或过时的 监控记录 和 流量记录
@@ -154,3 +199,35 @@ func IPDesensitize(ip string) string {
154199
}
155200
return utils.IPDesensitize(ip)
156201
}
202+
203+
// CheckServerOnlineStatus 检查服务器在线状态,将超时未上报的服务器标记为离线
204+
func CheckServerOnlineStatus() {
205+
ServerLock.Lock()
206+
defer ServerLock.Unlock()
207+
208+
now := time.Now()
209+
offlineTimeout := time.Minute * 2 // 2分钟无心跳视为离线
210+
211+
for _, server := range ServerList {
212+
// 已经标记为在线且长时间未活动,标记为离线
213+
if server.IsOnline && now.Sub(server.LastActive) > offlineTimeout {
214+
server.IsOnline = false
215+
216+
// 如果还没有保存离线前状态,保存当前状态
217+
if server.LastStateBeforeOffline == nil && server.State != nil {
218+
lastState := model.HostState{}
219+
if err := copier.Copy(&lastState, server.State); err == nil {
220+
server.LastStateBeforeOffline = &lastState
221+
}
222+
}
223+
224+
// 离线前保存累计流量数据到数据库
225+
if server.State != nil {
226+
DB.Model(server).Updates(map[string]interface{}{
227+
"cumulative_net_in_transfer": server.State.NetInTransfer,
228+
"cumulative_net_out_transfer": server.State.NetOutTransfer,
229+
})
230+
}
231+
}
232+
}
233+
}

0 commit comments

Comments
 (0)