79 lines
1.5 KiB
Go
79 lines
1.5 KiB
Go
package internal
|
|
|
|
import (
|
|
"context"
|
|
"iter"
|
|
"sync"
|
|
|
|
"github.com/shopspring/decimal"
|
|
)
|
|
|
|
// AggregatorWriter tracks ReportItem totals.
|
|
type AggregatorWriter struct {
|
|
mu sync.RWMutex
|
|
|
|
items []ReportItem
|
|
|
|
totalEarned decimal.Decimal
|
|
totalSpent decimal.Decimal
|
|
totalFees decimal.Decimal
|
|
totalTaxes decimal.Decimal
|
|
}
|
|
|
|
func NewAggregatorWriter() *AggregatorWriter {
|
|
return &AggregatorWriter{}
|
|
}
|
|
|
|
func (aw *AggregatorWriter) Write(_ context.Context, ri ReportItem) error {
|
|
aw.mu.Lock()
|
|
defer aw.mu.Unlock()
|
|
|
|
aw.items = append(aw.items, ri)
|
|
|
|
aw.totalEarned = aw.totalEarned.Add(ri.SellValue.Round(2))
|
|
aw.totalSpent = aw.totalSpent.Add(ri.BuyValue.Round(2))
|
|
aw.totalFees = aw.totalFees.Add(ri.Fees.Round(2))
|
|
aw.totalTaxes = aw.totalTaxes.Add(ri.Taxes.Round(2))
|
|
|
|
return nil
|
|
}
|
|
|
|
func (aw *AggregatorWriter) Iter() iter.Seq[ReportItem] {
|
|
aw.mu.RLock()
|
|
itemsCopy := make([]ReportItem, len(aw.items))
|
|
copy(itemsCopy, aw.items)
|
|
aw.mu.RUnlock()
|
|
|
|
return func(yield func(ReportItem) bool) {
|
|
for _, ri := range itemsCopy {
|
|
if !yield(ri) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (aw *AggregatorWriter) TotalEarned() decimal.Decimal {
|
|
aw.mu.RLock()
|
|
defer aw.mu.RUnlock()
|
|
return aw.totalEarned
|
|
}
|
|
|
|
func (aw *AggregatorWriter) TotalSpent() decimal.Decimal {
|
|
aw.mu.RLock()
|
|
defer aw.mu.RUnlock()
|
|
return aw.totalSpent
|
|
}
|
|
|
|
func (aw *AggregatorWriter) TotalFees() decimal.Decimal {
|
|
aw.mu.RLock()
|
|
defer aw.mu.RUnlock()
|
|
return aw.totalFees
|
|
}
|
|
|
|
func (aw *AggregatorWriter) TotalTaxes() decimal.Decimal {
|
|
aw.mu.RLock()
|
|
defer aw.mu.RUnlock()
|
|
return aw.totalTaxes
|
|
}
|