Implement daily stats
This commit is contained in:
111
database/db.go
111
database/db.go
@@ -3,7 +3,9 @@ package database
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"pool-stats/helpers"
|
||||
"pool-stats/models"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/ostafen/clover/v2"
|
||||
@@ -16,6 +18,7 @@ const (
|
||||
CollectionName = "shares"
|
||||
TopSharesCollectionName = "TopShares"
|
||||
TimeWindowHighShareCollectionName = "TimeWindowHighShareStat"
|
||||
DailyStatsCollectionName = "DailyStats"
|
||||
)
|
||||
|
||||
func InitDatabase(path string) (*clover.DB, error) {
|
||||
@@ -79,6 +82,20 @@ func InitDatabase(path string) (*clover.DB, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// Init DailyStats collection
|
||||
hasDailyStatsCollection, err := db.HasCollection(DailyStatsCollectionName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to check DailyStats collection: %v", err)
|
||||
}
|
||||
if !hasDailyStatsCollection {
|
||||
if err := db.CreateCollection(DailyStatsCollectionName); err != nil {
|
||||
return nil, fmt.Errorf("failed to create DailyStats collection: %v", err)
|
||||
}
|
||||
if err := db.CreateIndex(DailyStatsCollectionName, "Date"); err != nil {
|
||||
return nil, fmt.Errorf("failed to create index for DailyStats: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
@@ -211,3 +228,97 @@ func SetTimeWindowHighShare(db *clover.DB, share models.TimeWindowHighShare) err
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ListSharesInTimeRange(db *clover.DB, since time.Time, till time.Time) []models.ShareLog {
|
||||
lower := since.Unix()
|
||||
upper := till.Unix()
|
||||
|
||||
results, err := db.FindAll(c.NewQuery(CollectionName).
|
||||
Where(c.Field("CreateDate").GtEq(fmt.Sprint(lower)).
|
||||
And(c.Field("CreateDate").LtEq(fmt.Sprint(upper)))).
|
||||
Sort(c.SortOption{Field: "CreateDate", Direction: -1}))
|
||||
|
||||
if err != nil {
|
||||
log.Printf("failed to list shares in time range: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
shareLogs := make([]models.ShareLog, len(results))
|
||||
for idx, doc := range results {
|
||||
var shareLog models.ShareLog
|
||||
doc.Unmarshal(&shareLog)
|
||||
shareLogs[idx] = shareLog
|
||||
}
|
||||
|
||||
return shareLogs
|
||||
}
|
||||
|
||||
// GetStatsForDay retrieves daily statistics for a given date
|
||||
// Tries to find from DailyStats collection, calculates on the fly if not found and stores
|
||||
func GetDailyStats(db *clover.DB, date time.Time) (*models.DailyStats, error) {
|
||||
dateStr := date.Format(time.DateOnly)
|
||||
|
||||
// Check if stats already exist
|
||||
isToday := dateStr == time.Now().UTC().Format(time.DateOnly)
|
||||
existingDoc, err := db.FindFirst(c.NewQuery(DailyStatsCollectionName).
|
||||
Where(c.Field("Date").Eq(dateStr)))
|
||||
if !isToday && err == nil && existingDoc != nil {
|
||||
var stats models.DailyStats
|
||||
if err := existingDoc.Unmarshal(&stats); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal daily stats: %v", err)
|
||||
}
|
||||
return &stats, nil
|
||||
}
|
||||
|
||||
// Get shares in range
|
||||
since := date.Truncate(24 * time.Hour)
|
||||
till := since.Add(24 * time.Hour)
|
||||
shares := ListSharesInTimeRange(db, since, till)
|
||||
sort.Slice(shares, func(i, j int) bool {
|
||||
return shares[i].SDiff > shares[j].SDiff
|
||||
})
|
||||
|
||||
// Calculate daily stats
|
||||
stats := &models.DailyStats{
|
||||
Date: dateStr,
|
||||
ShareCount: len(shares),
|
||||
Workers: make(map[string]models.WorkerDailyStats),
|
||||
}
|
||||
|
||||
if len(shares) > 0 {
|
||||
stats.TopShare = shares[0]
|
||||
stats.PoolHashrate = helpers.CalculateAverageHashrate(shares)
|
||||
}
|
||||
|
||||
// Calculate worker stats
|
||||
sharesByWorker := make(map[string][]models.ShareLog)
|
||||
for _, share := range shares {
|
||||
sharesByWorker[share.WorkerName] = append(sharesByWorker[share.WorkerName], share)
|
||||
}
|
||||
for workerName, workerShares := range sharesByWorker {
|
||||
workerHashrate := helpers.CalculateAverageHashrate(workerShares)
|
||||
workerTopShare := workerShares[0] // Already sorted by SDiff
|
||||
|
||||
stats.Workers[workerName] = models.WorkerDailyStats{
|
||||
TopShare: workerTopShare,
|
||||
Hashrate: workerHashrate,
|
||||
Shares: len(workerShares),
|
||||
}
|
||||
}
|
||||
|
||||
// Insert or update the daily stats in the collection
|
||||
doc := document.NewDocumentOf(stats)
|
||||
if _, err := db.InsertOne(DailyStatsCollectionName, doc); err != nil {
|
||||
return nil, fmt.Errorf("failed to insert daily stats: %v", err)
|
||||
}
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
func ClearDailyStats(db *clover.DB) error {
|
||||
// Delete all documents in DailyStats collection
|
||||
if err := db.Delete(c.NewQuery(DailyStatsCollectionName)); err != nil {
|
||||
return fmt.Errorf("failed to clear DailyStats collection: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user