security measures
This commit is contained in:
@@ -3,11 +3,11 @@ package service
|
||||
import (
|
||||
"acc-server-manager/local/model"
|
||||
"acc-server-manager/local/repository"
|
||||
"acc-server-manager/local/utl/logging"
|
||||
"sort"
|
||||
"time"
|
||||
"acc-server-manager/pkg/logging"
|
||||
"sync"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
type StateHistoryService struct {
|
||||
@@ -15,18 +15,9 @@ type StateHistoryService struct {
|
||||
}
|
||||
|
||||
func NewStateHistoryService(repository *repository.StateHistoryRepository) *StateHistoryService {
|
||||
return &StateHistoryService{
|
||||
repository: repository,
|
||||
}
|
||||
return &StateHistoryService{repository: repository}
|
||||
}
|
||||
|
||||
// GetAll
|
||||
// Gets All rows from StateHistory table.
|
||||
//
|
||||
// Args:
|
||||
// context.Context: Application context
|
||||
// Returns:
|
||||
// string: Application version
|
||||
func (s *StateHistoryService) GetAll(ctx *fiber.Ctx, filter *model.StateHistoryFilter) (*[]model.StateHistory, error) {
|
||||
result, err := s.repository.GetAll(ctx.UserContext(), filter)
|
||||
if err != nil {
|
||||
@@ -44,168 +35,99 @@ func (s *StateHistoryService) Insert(ctx *fiber.Ctx, model *model.StateHistory)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *StateHistoryService) GetLastSessionID(ctx *fiber.Ctx, serverID uint) (uint, error) {
|
||||
return s.repository.GetLastSessionID(ctx.UserContext(), serverID)
|
||||
}
|
||||
|
||||
func (s *StateHistoryService) GetStatistics(ctx *fiber.Ctx, filter *model.StateHistoryFilter) (*model.StateHistoryStats, error) {
|
||||
// Get all state history entries based on filter
|
||||
entries, err := s.repository.GetAll(ctx.UserContext(), filter)
|
||||
if err != nil {
|
||||
logging.Error("Error getting state history for statistics: %v", err)
|
||||
stats := &model.StateHistoryStats{}
|
||||
var mu sync.Mutex
|
||||
|
||||
eg, gCtx := errgroup.WithContext(ctx.UserContext())
|
||||
|
||||
// Get Summary Stats (Peak/Avg Players, Total Sessions)
|
||||
eg.Go(func() error {
|
||||
summary, err := s.repository.GetSummaryStats(gCtx, filter)
|
||||
if err != nil {
|
||||
logging.Error("Error getting summary stats: %v", err)
|
||||
return err
|
||||
}
|
||||
mu.Lock()
|
||||
stats.PeakPlayers = summary.PeakPlayers
|
||||
stats.AveragePlayers = summary.AveragePlayers
|
||||
stats.TotalSessions = summary.TotalSessions
|
||||
mu.Unlock()
|
||||
return nil
|
||||
})
|
||||
|
||||
// Get Total Playtime
|
||||
eg.Go(func() error {
|
||||
playtime, err := s.repository.GetTotalPlaytime(gCtx, filter)
|
||||
if err != nil {
|
||||
logging.Error("Error getting total playtime: %v", err)
|
||||
return err
|
||||
}
|
||||
mu.Lock()
|
||||
stats.TotalPlaytime = playtime
|
||||
mu.Unlock()
|
||||
return nil
|
||||
})
|
||||
|
||||
// Get Player Count Over Time
|
||||
eg.Go(func() error {
|
||||
playerCount, err := s.repository.GetPlayerCountOverTime(gCtx, filter)
|
||||
if err != nil {
|
||||
logging.Error("Error getting player count over time: %v", err)
|
||||
return err
|
||||
}
|
||||
mu.Lock()
|
||||
stats.PlayerCountOverTime = playerCount
|
||||
mu.Unlock()
|
||||
return nil
|
||||
})
|
||||
|
||||
// Get Session Types
|
||||
eg.Go(func() error {
|
||||
sessionTypes, err := s.repository.GetSessionTypes(gCtx, filter)
|
||||
if err != nil {
|
||||
logging.Error("Error getting session types: %v", err)
|
||||
return err
|
||||
}
|
||||
mu.Lock()
|
||||
stats.SessionTypes = sessionTypes
|
||||
mu.Unlock()
|
||||
return nil
|
||||
})
|
||||
|
||||
// Get Daily Activity
|
||||
eg.Go(func() error {
|
||||
dailyActivity, err := s.repository.GetDailyActivity(gCtx, filter)
|
||||
if err != nil {
|
||||
logging.Error("Error getting daily activity: %v", err)
|
||||
return err
|
||||
}
|
||||
mu.Lock()
|
||||
stats.DailyActivity = dailyActivity
|
||||
mu.Unlock()
|
||||
return nil
|
||||
})
|
||||
|
||||
// Get Recent Sessions
|
||||
eg.Go(func() error {
|
||||
recentSessions, err := s.repository.GetRecentSessions(gCtx, filter)
|
||||
if err != nil {
|
||||
logging.Error("Error getting recent sessions: %v", err)
|
||||
return err
|
||||
}
|
||||
mu.Lock()
|
||||
stats.RecentSessions = recentSessions
|
||||
mu.Unlock()
|
||||
return nil
|
||||
})
|
||||
|
||||
if err := eg.Wait(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stats := &model.StateHistoryStats{
|
||||
PlayerCountOverTime: make([]model.PlayerCountPoint, 0),
|
||||
SessionTypes: make([]model.SessionCount, 0),
|
||||
DailyActivity: make([]model.DailyActivity, 0),
|
||||
RecentSessions: make([]model.RecentSession, 0),
|
||||
}
|
||||
|
||||
if len(*entries) == 0 {
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
// Maps to track unique sessions and their details
|
||||
sessionMap := make(map[uint]*struct {
|
||||
StartTime time.Time
|
||||
EndTime time.Time
|
||||
Session string
|
||||
Track string
|
||||
MaxPlayers int
|
||||
SessionConcluded bool
|
||||
})
|
||||
|
||||
// Maps for aggregating statistics
|
||||
dailySessionCount := make(map[string]int)
|
||||
sessionTypeCount := make(map[string]int)
|
||||
totalPlayers := 0
|
||||
peakPlayers := 0
|
||||
|
||||
// Process each state history entry
|
||||
for _, entry := range *entries {
|
||||
// Track player count over time
|
||||
stats.PlayerCountOverTime = append(stats.PlayerCountOverTime, model.PlayerCountPoint{
|
||||
Timestamp: entry.DateCreated,
|
||||
Count: entry.PlayerCount,
|
||||
})
|
||||
|
||||
// Update peak players
|
||||
if entry.PlayerCount > peakPlayers {
|
||||
peakPlayers = entry.PlayerCount
|
||||
}
|
||||
|
||||
totalPlayers += entry.PlayerCount
|
||||
|
||||
// Process session information using SessionID
|
||||
if _, exists := sessionMap[entry.SessionID]; !exists {
|
||||
sessionMap[entry.SessionID] = &struct {
|
||||
StartTime time.Time
|
||||
EndTime time.Time
|
||||
Session string
|
||||
Track string
|
||||
MaxPlayers int
|
||||
SessionConcluded bool
|
||||
}{
|
||||
StartTime: entry.DateCreated,
|
||||
Session: entry.Session,
|
||||
Track: entry.Track,
|
||||
MaxPlayers: entry.PlayerCount,
|
||||
SessionConcluded: false,
|
||||
}
|
||||
|
||||
// Count session types
|
||||
sessionTypeCount[entry.Session]++
|
||||
|
||||
// Count daily sessions
|
||||
dateStr := entry.DateCreated.Format("2006-01-02")
|
||||
dailySessionCount[dateStr]++
|
||||
} else {
|
||||
session := sessionMap[entry.SessionID]
|
||||
if session.SessionConcluded {
|
||||
continue
|
||||
}
|
||||
if (entry.PlayerCount == 0) {
|
||||
session.SessionConcluded = true
|
||||
}
|
||||
session.EndTime = entry.DateCreated
|
||||
if entry.PlayerCount > session.MaxPlayers {
|
||||
session.MaxPlayers = entry.PlayerCount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for key, session := range sessionMap {
|
||||
if !session.SessionConcluded {
|
||||
session.SessionConcluded = true
|
||||
}
|
||||
if (session.MaxPlayers == 0) {
|
||||
delete(sessionMap, key)
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate statistics
|
||||
stats.PeakPlayers = peakPlayers
|
||||
stats.TotalSessions = len(sessionMap)
|
||||
if len(*entries) > 0 {
|
||||
stats.AveragePlayers = float64(totalPlayers) / float64(len(*entries))
|
||||
}
|
||||
|
||||
// Process session types
|
||||
for sessionType, count := range sessionTypeCount {
|
||||
stats.SessionTypes = append(stats.SessionTypes, model.SessionCount{
|
||||
Name: sessionType,
|
||||
Count: count,
|
||||
})
|
||||
}
|
||||
|
||||
// Process daily activity
|
||||
for dateStr, count := range dailySessionCount {
|
||||
date, _ := time.Parse("2006-01-02", dateStr)
|
||||
stats.DailyActivity = append(stats.DailyActivity, model.DailyActivity{
|
||||
Date: date,
|
||||
SessionsCount: count,
|
||||
})
|
||||
}
|
||||
|
||||
// Calculate total playtime and prepare recent sessions
|
||||
var recentSessions []model.RecentSession
|
||||
totalPlaytime := 0
|
||||
|
||||
for sessionID, session := range sessionMap {
|
||||
if !session.EndTime.IsZero() {
|
||||
duration := int(session.EndTime.Sub(session.StartTime).Minutes())
|
||||
totalPlaytime += duration
|
||||
|
||||
recentSessions = append(recentSessions, model.RecentSession{
|
||||
ID: sessionID,
|
||||
Date: session.StartTime,
|
||||
Type: session.Session,
|
||||
Track: session.Track,
|
||||
Duration: duration,
|
||||
Players: session.MaxPlayers,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
stats.TotalPlaytime = totalPlaytime
|
||||
|
||||
// Sort recent sessions by date (newest first) and limit to last 10
|
||||
sort.Slice(recentSessions, func(i, j int) bool {
|
||||
return recentSessions[i].Date.After(recentSessions[j].Date)
|
||||
})
|
||||
|
||||
if len(recentSessions) > 10 {
|
||||
recentSessions = recentSessions[:10]
|
||||
}
|
||||
stats.RecentSessions = recentSessions
|
||||
|
||||
// Sort daily activity by date
|
||||
sort.Slice(stats.DailyActivity, func(i, j int) bool {
|
||||
return stats.DailyActivity[i].Date.Before(stats.DailyActivity[j].Date)
|
||||
})
|
||||
|
||||
// Sort player count over time by timestamp
|
||||
sort.Slice(stats.PlayerCountOverTime, func(i, j int) bool {
|
||||
return stats.PlayerCountOverTime[i].Timestamp.Before(stats.PlayerCountOverTime[j].Timestamp)
|
||||
})
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
Reference in New Issue
Block a user