feat(api): update server total data response to use 'OnlineUsers' and implement daily traffic statistics logging
This commit is contained in:
parent
9ff965bbea
commit
4184a32c0f
@ -21,7 +21,7 @@ type (
|
|||||||
Download int64 `json:"download"`
|
Download int64 `json:"download"`
|
||||||
}
|
}
|
||||||
ServerTotalDataResponse {
|
ServerTotalDataResponse {
|
||||||
OnlineUserIPs int64 `json:"online_user_ips"`
|
OnlineUsers int64 `json:"online_users"`
|
||||||
OnlineServers int64 `json:"online_servers"`
|
OnlineServers int64 `json:"online_servers"`
|
||||||
OfflineServers int64 `json:"offline_servers"`
|
OfflineServers int64 `json:"offline_servers"`
|
||||||
TodayUpload int64 `json:"today_upload"`
|
TodayUpload int64 `json:"today_upload"`
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/perfect-panel/server/internal/model/log"
|
"github.com/perfect-panel/server/internal/model/log"
|
||||||
|
"github.com/perfect-panel/server/internal/model/node"
|
||||||
"github.com/perfect-panel/server/internal/model/traffic"
|
"github.com/perfect-panel/server/internal/model/traffic"
|
||||||
"github.com/perfect-panel/server/internal/svc"
|
"github.com/perfect-panel/server/internal/svc"
|
||||||
"github.com/perfect-panel/server/internal/types"
|
"github.com/perfect-panel/server/internal/types"
|
||||||
@ -149,7 +150,78 @@ func (l *QueryServerTotalDataLogic) QueryServerTotalData() (resp *types.ServerTo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// query online user count
|
||||||
|
onlineUsers, err := l.svcCtx.NodeModel.OnlineUserSubscribeGlobal(l.ctx)
|
||||||
|
if err != nil {
|
||||||
|
l.Errorw("[QueryServerTotalDataLogic] OnlineUserSubscribeGlobal error", logger.Field("error", err.Error()))
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "OnlineUserSubscribeGlobal error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// query online/offline server count
|
||||||
|
var onlineServers, offlineServers int64
|
||||||
|
err = query.Model(&node.Server{}).Where("`last_reported_at` > ?", now.Add(-5*time.Minute)).Count(&onlineServers).Error
|
||||||
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
l.Errorw("[QueryServerTotalDataLogic] Count online servers error", logger.Field("error", err.Error()))
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Count online servers error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = query.Model(&node.Server{}).Where("`last_reported_at` <= ? OR `last_reported_at` IS NULL", now.Add(-5*time.Minute)).Count(&offlineServers).Error
|
||||||
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
l.Errorw("[QueryServerTotalDataLogic] Count offline servers error", logger.Field("error", err.Error()))
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Count offline servers error: %v", err)
|
||||||
|
}
|
||||||
|
// TodayUpload, TodayDownload, MonthlyUpload, MonthlyDownload
|
||||||
|
var todayUpload, todayDownload, monthlyUpload, monthlyDownload int64
|
||||||
|
|
||||||
|
type trafficSum struct {
|
||||||
|
Upload int64
|
||||||
|
Download int64
|
||||||
|
}
|
||||||
|
var todayTraffic trafficSum
|
||||||
|
// Today
|
||||||
|
err = query.Model(&traffic.TrafficLog{}).Select("SUM(upload) AS upload, SUM(download) AS download").
|
||||||
|
Where("timestamp BETWEEN ? AND ?", todayStart, todayEnd).
|
||||||
|
Scan(&todayTraffic).Error
|
||||||
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
l.Errorw("[QueryServerTotalDataLogic] Sum today traffic error", logger.Field("error", err.Error()))
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Sum today traffic error: %v", err)
|
||||||
|
}
|
||||||
|
todayUpload = todayTraffic.Upload
|
||||||
|
todayDownload = todayTraffic.Download
|
||||||
|
|
||||||
|
// Monthly
|
||||||
|
monthlyUpload += todayUpload
|
||||||
|
monthlyDownload += todayDownload
|
||||||
|
|
||||||
|
for i := now.Day() - 1; i >= 1; i-- {
|
||||||
|
var logInfo log.SystemLog
|
||||||
|
date := time.Date(now.Year(), now.Month(), i, 0, 0, 0, 0, now.Location()).Format(time.DateOnly)
|
||||||
|
err = query.Model(&log.SystemLog{}).Where("`date` = ? AND `type` = ?", date, log.TypeTrafficStat).First(&logInfo).Error
|
||||||
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
l.Errorw("[QueryServerTotalDataLogic] Query daily traffic stat log error", logger.Field("error", err.Error()), logger.Field("date", date))
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Query daily traffic stat log error: %v", err)
|
||||||
|
}
|
||||||
|
if logInfo.Id > 0 {
|
||||||
|
var stat log.TrafficStat
|
||||||
|
err = stat.Unmarshal([]byte(logInfo.Content))
|
||||||
|
if err != nil {
|
||||||
|
l.Errorw("[QueryServerTotalDataLogic] Unmarshal daily traffic stat log error", logger.Field("error", err.Error()), logger.Field("date", date))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
monthlyUpload += stat.Upload
|
||||||
|
monthlyDownload += stat.Download
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
resp = &types.ServerTotalDataResponse{
|
resp = &types.ServerTotalDataResponse{
|
||||||
|
OnlineUsers: onlineUsers,
|
||||||
|
OnlineServers: onlineServers,
|
||||||
|
OfflineServers: offlineServers,
|
||||||
|
TodayUpload: todayUpload,
|
||||||
|
TodayDownload: todayDownload,
|
||||||
|
MonthlyUpload: monthlyUpload,
|
||||||
|
MonthlyDownload: monthlyDownload,
|
||||||
|
UpdatedAt: now.Unix(),
|
||||||
ServerTrafficRankingToday: todayServerRanking,
|
ServerTrafficRankingToday: todayServerRanking,
|
||||||
ServerTrafficRankingYesterday: yesterdayTop10Server,
|
ServerTrafficRankingYesterday: yesterdayTop10Server,
|
||||||
UserTrafficRankingToday: userTodayTrafficRanking,
|
UserTrafficRankingToday: userTodayTrafficRanking,
|
||||||
@ -214,7 +286,7 @@ func (l *QueryServerTotalDataLogic) mockRevenueStatistics() *types.ServerTotalDa
|
|||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
return &types.ServerTotalDataResponse{
|
return &types.ServerTotalDataResponse{
|
||||||
OnlineUserIPs: 1688,
|
OnlineUsers: 1688,
|
||||||
OnlineServers: 8,
|
OnlineServers: 8,
|
||||||
OfflineServers: 2,
|
OfflineServers: 2,
|
||||||
TodayUpload: 8888888888, // ~8.3GB
|
TodayUpload: 8888888888, // ~8.3GB
|
||||||
|
|||||||
@ -30,6 +30,7 @@ const (
|
|||||||
TypeGift Type = 34 // Gift log
|
TypeGift Type = 34 // Gift log
|
||||||
TypeUserTrafficRank Type = 40 // Top 10 User traffic rank log
|
TypeUserTrafficRank Type = 40 // Top 10 User traffic rank log
|
||||||
TypeServerTrafficRank Type = 41 // Top 10 Server traffic rank log
|
TypeServerTrafficRank Type = 41 // Top 10 Server traffic rank log
|
||||||
|
TypeTrafficStat Type = 42 // Daily traffic statistics log
|
||||||
)
|
)
|
||||||
const (
|
const (
|
||||||
ResetSubscribeTypeAuto uint16 = 231 // Auto reset
|
ResetSubscribeTypeAuto uint16 = 231 // Auto reset
|
||||||
@ -393,3 +394,27 @@ func (s *ServerTrafficRank) Unmarshal(data []byte) error {
|
|||||||
aux := (*Alias)(s)
|
aux := (*Alias)(s)
|
||||||
return json.Unmarshal(data, aux)
|
return json.Unmarshal(data, aux)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TrafficStat represents a daily traffic statistics log entry.
|
||||||
|
type TrafficStat struct {
|
||||||
|
Upload int64 `json:"upload"`
|
||||||
|
Download int64 `json:"download"`
|
||||||
|
Total int64 `json:"total"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal implements the json.Marshaler interface for TrafficStat.
|
||||||
|
func (t *TrafficStat) Marshal() ([]byte, error) {
|
||||||
|
type Alias TrafficStat
|
||||||
|
return json.Marshal(&struct {
|
||||||
|
*Alias
|
||||||
|
}{
|
||||||
|
Alias: (*Alias)(t),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal implements the json.Unmarshaler interface for TrafficStat.
|
||||||
|
func (t *TrafficStat) Unmarshal(data []byte) error {
|
||||||
|
type Alias TrafficStat
|
||||||
|
aux := (*Alias)(t)
|
||||||
|
return json.Unmarshal(data, aux)
|
||||||
|
}
|
||||||
|
|||||||
@ -1739,7 +1739,7 @@ type ServerStatus struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ServerTotalDataResponse struct {
|
type ServerTotalDataResponse struct {
|
||||||
OnlineUserIPs int64 `json:"online_user_ips"`
|
OnlineUsers int64 `json:"online_users"`
|
||||||
OnlineServers int64 `json:"online_servers"`
|
OnlineServers int64 `json:"online_servers"`
|
||||||
OfflineServers int64 `json:"offline_servers"`
|
OfflineServers int64 `json:"offline_servers"`
|
||||||
TodayUpload int64 `json:"today_upload"`
|
TodayUpload int64 `json:"today_upload"`
|
||||||
|
|||||||
@ -141,6 +141,30 @@ func (l *StatLogic) ProcessTask(ctx context.Context, _ *asynq.Task) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// traffic stat
|
||||||
|
var stat log.TrafficStat
|
||||||
|
err = tx.WithContext(ctx).Model(&traffic.TrafficLog{}).
|
||||||
|
Select("SUM(download + upload) AS total, SUM(download) AS download, SUM(upload) AS upload").
|
||||||
|
Where("timestamp BETWEEN ? AND ?", start, end).
|
||||||
|
Scan(&stat).Error
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("[Traffic Stat Queue] Query traffic stat failed: %v", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新流量统计日志
|
||||||
|
content, _ := stat.Marshal()
|
||||||
|
err = tx.WithContext(ctx).Model(&log.SystemLog{}).Create(&log.SystemLog{
|
||||||
|
Type: log.TypeTrafficStat.Uint8(),
|
||||||
|
Date: date,
|
||||||
|
ObjectID: 0,
|
||||||
|
Content: string(content),
|
||||||
|
}).Error
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("[Traffic Stat Queue] Create traffic stat log failed: %v", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Delete old traffic logs
|
// Delete old traffic logs
|
||||||
err = tx.WithContext(ctx).Model(&traffic.TrafficLog{}).Where("created_at <= ?", end).Delete(&traffic.TrafficLog{}).Error
|
err = tx.WithContext(ctx).Model(&traffic.TrafficLog{}).Where("created_at <= ?", end).Delete(&traffic.TrafficLog{}).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user