From fd6cba2e34b8258abb6b5dabf12b7def119932cd Mon Sep 17 00:00:00 2001 From: cialloo Date: Sat, 4 Oct 2025 13:40:19 +0800 Subject: [PATCH] update --- src/etc/serverstatistics.yaml | 3 ++ src/go.mod | 5 +- src/go.sum | 2 + src/internal/config/config.go | 5 ++ src/internal/logic/pinglogic.go | 6 +-- src/internal/logic/recentchatmessagelogic.go | 30 +++++++++++- src/internal/logic/recentjoinplayerlogic.go | 35 +++++++++++++- src/internal/logic/recentplayerjoinlogic.go | 20 +++++++- src/internal/logic/recentplaylogic.go | 32 ++++++++++++- src/internal/logic/topplaytimelogic.go | 34 +++++++++++++- .../logic/totalchatmessagecountlogic.go | 32 ++++++++++++- src/internal/logic/totalconnectcountlogic.go | 20 +++++++- src/internal/logic/totaldamagecountlogic.go | 41 ++++++++++++++++- src/internal/logic/totalkillcountlogic.go | 46 ++++++++++++++++++- src/internal/logic/totalplayercountlogic.go | 19 +++++++- src/internal/logic/totalplaytimelogic.go | 20 +++++++- src/internal/svc/servicecontext.go | 20 ++++++++ 17 files changed, 344 insertions(+), 26 deletions(-) diff --git a/src/etc/serverstatistics.yaml b/src/etc/serverstatistics.yaml index 8124a7d..e700975 100644 --- a/src/etc/serverstatistics.yaml +++ b/src/etc/serverstatistics.yaml @@ -1,3 +1,6 @@ Name: ServerStatistics Host: 0.0.0.0 Port: 8888 + +Database: + DSN: "host=localhost port=5432 user=postgres password=your_password dbname=steam_union sslmode=disable" diff --git a/src/go.mod b/src/go.mod index 29268a8..a60164d 100644 --- a/src/go.mod +++ b/src/go.mod @@ -2,7 +2,10 @@ module src go 1.24.4 -require github.com/zeromicro/go-zero v1.9.1 +require ( + github.com/lib/pq v1.10.9 + github.com/zeromicro/go-zero v1.9.1 +) require ( github.com/beorn7/perks v1.0.1 // indirect diff --git a/src/go.sum b/src/go.sum index 84515f6..00d6652 100644 --- a/src/go.sum +++ b/src/go.sum @@ -36,6 +36,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= diff --git a/src/internal/config/config.go b/src/internal/config/config.go index 8da153d..ebd2903 100644 --- a/src/internal/config/config.go +++ b/src/internal/config/config.go @@ -4,4 +4,9 @@ import "github.com/zeromicro/go-zero/rest" type Config struct { rest.RestConf + Database DatabaseConfig +} + +type DatabaseConfig struct { + DSN string // Data Source Name for database connection } diff --git a/src/internal/logic/pinglogic.go b/src/internal/logic/pinglogic.go index 392321b..993b400 100644 --- a/src/internal/logic/pinglogic.go +++ b/src/internal/logic/pinglogic.go @@ -25,7 +25,7 @@ func NewPingLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PingLogic { } func (l *PingLogic) Ping(req *types.PingReq) (resp *types.PingResp, err error) { - // todo: add your logic here and delete this line - - return + return &types.PingResp{ + Ok: true, + }, nil } diff --git a/src/internal/logic/recentchatmessagelogic.go b/src/internal/logic/recentchatmessagelogic.go index ceac8ac..623b3b1 100644 --- a/src/internal/logic/recentchatmessagelogic.go +++ b/src/internal/logic/recentchatmessagelogic.go @@ -25,7 +25,33 @@ func NewRecentChatMessageLogic(ctx context.Context, svcCtx *svc.ServiceContext) } func (l *RecentChatMessageLogic) RecentChatMessage(req *types.RecentChatMessageReq) (resp *types.RecentChatMessageResp, err error) { - // todo: add your logic here and delete this line + query := ` + SELECT steamid64, player_name, message, + EXTRACT(EPOCH FROM message_time)::BIGINT * 1000 as timestamp + FROM steam_union.chat_log + WHERE message_time >= TO_TIMESTAMP($1 / 1000.0) + AND message_time <= TO_TIMESTAMP($2 / 1000.0) + ORDER BY message_time DESC + ` - return + rows, err := l.svcCtx.DB.QueryContext(l.ctx, query, req.TimeRangeStart, req.TimeRangeEnd) + if err != nil { + l.Errorf("Failed to query recent chat messages: %v", err) + return nil, err + } + defer rows.Close() + + var messages []types.RecentChatMessageRespMessage + for rows.Next() { + var msg types.RecentChatMessageRespMessage + if err := rows.Scan(&msg.SteamID64, &msg.UserName, &msg.Message, &msg.TimeStamp); err != nil { + l.Errorf("Failed to scan chat message: %v", err) + continue + } + messages = append(messages, msg) + } + + return &types.RecentChatMessageResp{ + Messages: messages, + }, nil } diff --git a/src/internal/logic/recentjoinplayerlogic.go b/src/internal/logic/recentjoinplayerlogic.go index 7fb631b..4a7ff08 100644 --- a/src/internal/logic/recentjoinplayerlogic.go +++ b/src/internal/logic/recentjoinplayerlogic.go @@ -25,7 +25,38 @@ func NewRecentJoinPlayerLogic(ctx context.Context, svcCtx *svc.ServiceContext) * } func (l *RecentJoinPlayerLogic) RecentJoinPlayer(req *types.RecentJoinPlayerReq) (resp *types.RecentJoinPlayerResp, err error) { - // todo: add your logic here and delete this line + query := ` + SELECT c.steamid64, + EXTRACT(EPOCH FROM c.log_time)::BIGINT * 1000 as join_time, + c.player_name as username, + COALESCE(s.playtime, 0) as playtime + FROM steam_union.connection_log c + LEFT JOIN steam_union.steam_user s ON c.steamid64 = s.steamid64 + WHERE c.connection_type = 1 + AND c.log_time >= TO_TIMESTAMP($1 / 1000.0) + AND c.log_time <= TO_TIMESTAMP($2 / 1000.0) + AND c.steamid64 > 1 + ORDER BY c.log_time DESC + ` - return + rows, err := l.svcCtx.DB.QueryContext(l.ctx, query, req.TimeRangeStart, req.TimeRangeEnd) + if err != nil { + l.Errorf("Failed to query recent join players: %v", err) + return nil, err + } + defer rows.Close() + + var players []types.RecentJoinPlayerRespPlayer + for rows.Next() { + var player types.RecentJoinPlayerRespPlayer + if err := rows.Scan(&player.SteamID64, &player.JoinTime, &player.UserName, &player.PlayTime); err != nil { + l.Errorf("Failed to scan join player: %v", err) + continue + } + players = append(players, player) + } + + return &types.RecentJoinPlayerResp{ + Players: players, + }, nil } diff --git a/src/internal/logic/recentplayerjoinlogic.go b/src/internal/logic/recentplayerjoinlogic.go index 27db675..73a81bd 100644 --- a/src/internal/logic/recentplayerjoinlogic.go +++ b/src/internal/logic/recentplayerjoinlogic.go @@ -25,7 +25,23 @@ func NewRecentPlayerJoinLogic(ctx context.Context, svcCtx *svc.ServiceContext) * } func (l *RecentPlayerJoinLogic) RecentPlayerJoin(req *types.TotalPlayerJoinReq) (resp *types.TotalPlayerJoinResp, err error) { - // todo: add your logic here and delete this line + query := ` + SELECT COUNT(*) + FROM steam_union.connection_log + WHERE connection_type = 1 + AND log_time >= TO_TIMESTAMP($1 / 1000.0) + AND log_time <= TO_TIMESTAMP($2 / 1000.0) + AND steamid64 > 1 + ` - return + var count int64 + err = l.svcCtx.DB.QueryRowContext(l.ctx, query, req.TimeRangeStart, req.TimeRangeEnd).Scan(&count) + if err != nil { + l.Errorf("Failed to query recent player joins: %v", err) + return nil, err + } + + return &types.TotalPlayerJoinResp{ + Count: count, + }, nil } diff --git a/src/internal/logic/recentplaylogic.go b/src/internal/logic/recentplaylogic.go index 0b9deae..70c5328 100644 --- a/src/internal/logic/recentplaylogic.go +++ b/src/internal/logic/recentplaylogic.go @@ -25,7 +25,35 @@ func NewRecentPlayLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Recent } func (l *RecentPlayLogic) RecentPlay(req *types.RecentPlayReq) (resp *types.RecentPlayResp, err error) { - // todo: add your logic here and delete this line + query := ` + SELECT steamid64, player_name, mapname, duration + FROM steam_union.connection_log + WHERE connection_type = 2 + AND log_time >= TO_TIMESTAMP($1 / 1000.0) + AND log_time <= TO_TIMESTAMP($2 / 1000.0) + AND duration >= $3 + AND steamid64 > 1 + ORDER BY duration DESC + ` - return + rows, err := l.svcCtx.DB.QueryContext(l.ctx, query, req.TimeRangeStart, req.TimeRangeEnd, req.LeastPlayTime) + if err != nil { + l.Errorf("Failed to query recent play: %v", err) + return nil, err + } + defer rows.Close() + + var players []types.RecentPlayRespPlayer + for rows.Next() { + var player types.RecentPlayRespPlayer + if err := rows.Scan(&player.SteamID64, &player.UserName, &player.MapName, &player.PlayTime); err != nil { + l.Errorf("Failed to scan recent play: %v", err) + continue + } + players = append(players, player) + } + + return &types.RecentPlayResp{ + Players: players, + }, nil } diff --git a/src/internal/logic/topplaytimelogic.go b/src/internal/logic/topplaytimelogic.go index 62437bd..2bf7fb4 100644 --- a/src/internal/logic/topplaytimelogic.go +++ b/src/internal/logic/topplaytimelogic.go @@ -25,7 +25,37 @@ func NewTopPlayTimeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *TopPl } func (l *TopPlayTimeLogic) TopPlayTime(req *types.TopPlayTimeReq) (resp *types.TopPlayTimeResp, err error) { - // todo: add your logic here and delete this line + query := ` + SELECT c.steamid64, c.player_name, + SUM(c.duration) as total_playtime + FROM steam_union.connection_log c + WHERE c.connection_type = 2 + AND c.log_time >= TO_TIMESTAMP($1 / 1000.0) + AND c.log_time <= TO_TIMESTAMP($2 / 1000.0) + AND c.steamid64 > 1 + GROUP BY c.steamid64, c.player_name + ORDER BY total_playtime DESC + LIMIT 100 + ` - return + rows, err := l.svcCtx.DB.QueryContext(l.ctx, query, req.TimeRangeStart, req.TimeRangeEnd) + if err != nil { + l.Errorf("Failed to query top playtime: %v", err) + return nil, err + } + defer rows.Close() + + var players []types.TopPlayTimeRespPlayer + for rows.Next() { + var player types.TopPlayTimeRespPlayer + if err := rows.Scan(&player.SteamID64, &player.UserName, &player.PlayTime); err != nil { + l.Errorf("Failed to scan top playtime: %v", err) + continue + } + players = append(players, player) + } + + return &types.TopPlayTimeResp{ + Players: players, + }, nil } diff --git a/src/internal/logic/totalchatmessagecountlogic.go b/src/internal/logic/totalchatmessagecountlogic.go index 082b453..072c51e 100644 --- a/src/internal/logic/totalchatmessagecountlogic.go +++ b/src/internal/logic/totalchatmessagecountlogic.go @@ -2,6 +2,7 @@ package logic import ( "context" + "fmt" "src/internal/svc" "src/internal/types" @@ -25,7 +26,34 @@ func NewTotalChatMessageCountLogic(ctx context.Context, svcCtx *svc.ServiceConte } func (l *TotalChatMessageCountLogic) TotalChatMessageCount(req *types.TotalChatMessageCountReq) (resp *types.TotalChatMessageCountResp, err error) { - // todo: add your logic here and delete this line + query := ` + SELECT COUNT(*) + FROM steam_union.chat_log + WHERE message_time >= TO_TIMESTAMP($1 / 1000.0) + AND message_time <= TO_TIMESTAMP($2 / 1000.0) + ` - return + args := []interface{}{req.TimeRangeStart, req.TimeRangeEnd} + + // Add player filter if provided + if len(req.PlayerFilter) > 0 { + query += ` AND steamid64 = ANY($3)` + // Convert []string to []int64 for steamid64 + steamIDs := make([]int64, len(req.PlayerFilter)) + for i, id := range req.PlayerFilter { + fmt.Sscanf(id, "%d", &steamIDs[i]) + } + args = append(args, steamIDs) + } + + var count int64 + err = l.svcCtx.DB.QueryRowContext(l.ctx, query, args...).Scan(&count) + if err != nil { + l.Errorf("Failed to query total chat message count: %v", err) + return nil, err + } + + return &types.TotalChatMessageCountResp{ + TotalChatMessageCount: count, + }, nil } diff --git a/src/internal/logic/totalconnectcountlogic.go b/src/internal/logic/totalconnectcountlogic.go index 29cbfe6..60cd4c3 100644 --- a/src/internal/logic/totalconnectcountlogic.go +++ b/src/internal/logic/totalconnectcountlogic.go @@ -25,7 +25,23 @@ func NewTotalConnectCountLogic(ctx context.Context, svcCtx *svc.ServiceContext) } func (l *TotalConnectCountLogic) TotalConnectCount(req *types.TotalConnectCountReq) (resp *types.TotalConnectCountResp, err error) { - // todo: add your logic here and delete this line + query := ` + SELECT COUNT(*) + FROM steam_union.connection_log + WHERE connection_type = 1 + AND log_time >= TO_TIMESTAMP($1 / 1000.0) + AND log_time <= TO_TIMESTAMP($2 / 1000.0) + AND steamid64 > 1 + ` - return + var count int64 + err = l.svcCtx.DB.QueryRowContext(l.ctx, query, req.TimeRangeStart, req.TimeRangeEnd).Scan(&count) + if err != nil { + l.Errorf("Failed to query total connect count: %v", err) + return nil, err + } + + return &types.TotalConnectCountResp{ + TotalConnectCount: count, + }, nil } diff --git a/src/internal/logic/totaldamagecountlogic.go b/src/internal/logic/totaldamagecountlogic.go index e2cc662..1405852 100644 --- a/src/internal/logic/totaldamagecountlogic.go +++ b/src/internal/logic/totaldamagecountlogic.go @@ -2,6 +2,7 @@ package logic import ( "context" + "fmt" "src/internal/svc" "src/internal/types" @@ -25,7 +26,43 @@ func NewTotalDamageCountLogic(ctx context.Context, svcCtx *svc.ServiceContext) * } func (l *TotalDamageCountLogic) TotalDamageCount(req *types.TotalDamageCountReq) (resp *types.TotalDamageCountResp, err error) { - // todo: add your logic here and delete this line + query := ` + SELECT COALESCE(SUM(dmg_health), 0) + FROM steam_union.event_player_hurt_log + WHERE event_player_hurt_time >= TO_TIMESTAMP($1 / 1000.0) + AND event_player_hurt_time <= TO_TIMESTAMP($2 / 1000.0) + AND attacker_steamid64 > 1 + ` - return + args := []interface{}{req.TimeRangeStart, req.TimeRangeEnd} + argIndex := 3 + + // Add weapon filter if provided + if len(req.WeaponFilter) > 0 { + query += fmt.Sprintf(` AND weapon = ANY($%d)`, argIndex) + args = append(args, req.WeaponFilter) + argIndex++ + } + + // Add player filter if provided + if len(req.PlayerFilter) > 0 { + // Convert []string to []int64 for steamid64 + steamIDs := make([]int64, len(req.PlayerFilter)) + for i, id := range req.PlayerFilter { + fmt.Sscanf(id, "%d", &steamIDs[i]) + } + query += fmt.Sprintf(` AND attacker_steamid64 = ANY($%d)`, argIndex) + args = append(args, steamIDs) + } + + var count int64 + err = l.svcCtx.DB.QueryRowContext(l.ctx, query, args...).Scan(&count) + if err != nil { + l.Errorf("Failed to query total damage count: %v", err) + return nil, err + } + + return &types.TotalDamageCountResp{ + TotalDamageCount: count, + }, nil } diff --git a/src/internal/logic/totalkillcountlogic.go b/src/internal/logic/totalkillcountlogic.go index 34e929d..93323fd 100644 --- a/src/internal/logic/totalkillcountlogic.go +++ b/src/internal/logic/totalkillcountlogic.go @@ -2,6 +2,7 @@ package logic import ( "context" + "fmt" "src/internal/svc" "src/internal/types" @@ -25,7 +26,48 @@ func NewTotalKillCountLogic(ctx context.Context, svcCtx *svc.ServiceContext) *To } func (l *TotalKillCountLogic) TotalKillCount(req *types.TotalKillCountReq) (resp *types.TotalKillCountResp, err error) { - // todo: add your logic here and delete this line + query := ` + SELECT COUNT(*) + FROM steam_union.event_player_death_log + WHERE event_player_death_time >= TO_TIMESTAMP($1 / 1000.0) + AND event_player_death_time <= TO_TIMESTAMP($2 / 1000.0) + AND attacker_steamid64 > 1 + ` - return + args := []interface{}{req.TimeRangeStart, req.TimeRangeEnd} + argIndex := 3 + + // Add headshot filter if requested + if req.HeadshotOnly { + query += ` AND headshot = true` + } + + // Add weapon filter if provided + if len(req.WeaponFilter) > 0 { + query += fmt.Sprintf(` AND weapon = ANY($%d)`, argIndex) + args = append(args, req.WeaponFilter) + argIndex++ + } + + // Add player filter if provided + if len(req.PlayerFilter) > 0 { + // Convert []string to []int64 for steamid64 + steamIDs := make([]int64, len(req.PlayerFilter)) + for i, id := range req.PlayerFilter { + fmt.Sscanf(id, "%d", &steamIDs[i]) + } + query += fmt.Sprintf(` AND attacker_steamid64 = ANY($%d)`, argIndex) + args = append(args, steamIDs) + } + + var count int64 + err = l.svcCtx.DB.QueryRowContext(l.ctx, query, args...).Scan(&count) + if err != nil { + l.Errorf("Failed to query total kill count: %v", err) + return nil, err + } + + return &types.TotalKillCountResp{ + TotalKillCount: count, + }, nil } diff --git a/src/internal/logic/totalplayercountlogic.go b/src/internal/logic/totalplayercountlogic.go index edce7e1..7a1a45a 100644 --- a/src/internal/logic/totalplayercountlogic.go +++ b/src/internal/logic/totalplayercountlogic.go @@ -25,7 +25,22 @@ func NewTotalPlayerCountLogic(ctx context.Context, svcCtx *svc.ServiceContext) * } func (l *TotalPlayerCountLogic) TotalPlayerCount(req *types.TotalPlayerCountReq) (resp *types.TotalPlayerCountResp, err error) { - // todo: add your logic here and delete this line + query := ` + SELECT COUNT(DISTINCT steamid64) + FROM steam_union.connection_log + WHERE log_time >= TO_TIMESTAMP($1 / 1000.0) + AND log_time <= TO_TIMESTAMP($2 / 1000.0) + AND steamid64 > 1 + ` - return + var count int64 + err = l.svcCtx.DB.QueryRowContext(l.ctx, query, req.TimeRangeStart, req.TimeRangeEnd).Scan(&count) + if err != nil { + l.Errorf("Failed to query total player count: %v", err) + return nil, err + } + + return &types.TotalPlayerCountResp{ + Count: count, + }, nil } diff --git a/src/internal/logic/totalplaytimelogic.go b/src/internal/logic/totalplaytimelogic.go index 3c13826..08001f3 100644 --- a/src/internal/logic/totalplaytimelogic.go +++ b/src/internal/logic/totalplaytimelogic.go @@ -25,7 +25,23 @@ func NewTotalPlayTimeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Tot } func (l *TotalPlayTimeLogic) TotalPlayTime(req *types.TotalPlayTimeReq) (resp *types.TotalPlayTimeResp, err error) { - // todo: add your logic here and delete this line + query := ` + SELECT COALESCE(SUM(duration), 0) + FROM steam_union.connection_log + WHERE connection_type = 2 + AND log_time >= TO_TIMESTAMP($1 / 1000.0) + AND log_time <= TO_TIMESTAMP($2 / 1000.0) + AND steamid64 > 1 + ` - return + var totalTime int64 + err = l.svcCtx.DB.QueryRowContext(l.ctx, query, req.TimeRangeStart, req.TimeRangeEnd).Scan(&totalTime) + if err != nil { + l.Errorf("Failed to query total playtime: %v", err) + return nil, err + } + + return &types.TotalPlayTimeResp{ + TotalPlayTime: totalTime, + }, nil } diff --git a/src/internal/svc/servicecontext.go b/src/internal/svc/servicecontext.go index 05b2085..dee7b9a 100644 --- a/src/internal/svc/servicecontext.go +++ b/src/internal/svc/servicecontext.go @@ -1,15 +1,35 @@ package svc import ( + "database/sql" + "log" + "src/internal/config" + + _ "github.com/lib/pq" // PostgreSQL driver ) type ServiceContext struct { Config config.Config + DB *sql.DB } func NewServiceContext(c config.Config) *ServiceContext { + // Initialize database connection + db, err := sql.Open("postgres", c.Database.DSN) + if err != nil { + log.Fatalf("Failed to connect to database: %v", err) + } + + // Test the connection + if err := db.Ping(); err != nil { + log.Fatalf("Failed to ping database: %v", err) + } + + log.Println("Database connection established successfully") + return &ServiceContext{ Config: c, + DB: db, } }