mirror of
https://github.com/warmbly/warmbly.git
synced 2026-10-19 00:03:04 +00:00
153 lines
4.4 KiB
Go
153 lines
4.4 KiB
Go
package models
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
const (
|
|
WarmupReportBatchSize = 100
|
|
WarmupReportMaxDays = 366
|
|
)
|
|
|
|
type PoolLinkWarmupReportRequest struct {
|
|
RemoteIDs []uuid.UUID `json:"remote_ids"`
|
|
From string `json:"from"`
|
|
To string `json:"to"`
|
|
}
|
|
|
|
func (r PoolLinkWarmupReportRequest) Range() (time.Time, time.Time, error) {
|
|
if len(r.RemoteIDs) == 0 || len(r.RemoteIDs) > WarmupReportBatchSize {
|
|
return time.Time{}, time.Time{}, fmt.Errorf("remote_ids must contain 1 to %d mailboxes", WarmupReportBatchSize)
|
|
}
|
|
period, err := ParseDayRange(r.From, r.To)
|
|
if err != nil {
|
|
return time.Time{}, time.Time{}, err
|
|
}
|
|
if period == nil || period.To.Sub(period.From).Hours()/24 >= WarmupReportMaxDays {
|
|
return time.Time{}, time.Time{}, fmt.Errorf("a warmup report requires a range of at most %d days", WarmupReportMaxDays)
|
|
}
|
|
return period.From, period.To, nil
|
|
}
|
|
|
|
type WarmupPlacementDayRow struct {
|
|
SenderID uuid.UUID `json:"sender_id"`
|
|
Email string `json:"email"`
|
|
Date string `json:"date"`
|
|
Group string `json:"group"`
|
|
Inbox int `json:"inbox"`
|
|
Tabs int `json:"tabs"`
|
|
Spam int `json:"spam"`
|
|
Rescued int `json:"rescued"`
|
|
Unknown int `json:"unknown"`
|
|
Archived int `json:"archived"`
|
|
Custom int `json:"custom"`
|
|
Instrumented int `json:"instrumented_receipts"`
|
|
}
|
|
|
|
type WarmupPlacementHostRow struct {
|
|
Group string `json:"group"`
|
|
Host string `json:"host"`
|
|
Inbox int `json:"inbox"`
|
|
Tabs int `json:"tabs"`
|
|
Spam int `json:"spam"`
|
|
Rescued int `json:"rescued"`
|
|
Unknown int `json:"unknown"`
|
|
Archived int `json:"archived"`
|
|
Custom int `json:"custom"`
|
|
Instrumented int `json:"instrumented_receipts"`
|
|
}
|
|
|
|
type WarmupSenderDayCount struct {
|
|
SenderID uuid.UUID `json:"sender_id"`
|
|
Email string `json:"email"`
|
|
Date string `json:"date"`
|
|
Count int `json:"count"`
|
|
}
|
|
|
|
// WarmupPlacementData carries counts, not rounded rates, so mixed pools are weighted correctly.
|
|
type WarmupPlacementData struct {
|
|
Daily []WarmupPlacementDayRow `json:"daily"`
|
|
Hosts []WarmupPlacementHostRow `json:"hosts"`
|
|
Sent []WarmupSenderDayCount `json:"sent"`
|
|
Unconfirmed []WarmupSenderDayCount `json:"unconfirmed"`
|
|
Windows map[uuid.UUID]WarmupPlacementWindow `json:"windows"`
|
|
}
|
|
|
|
func MergeWarmupStats(local, cloud []WarmupDailyStats) []WarmupDailyStats {
|
|
byDate := make(map[string]WarmupDailyStats, len(local)+len(cloud))
|
|
for _, rows := range [][]WarmupDailyStats{local, cloud} {
|
|
for _, row := range rows {
|
|
day := byDate[row.Date]
|
|
day.Date = row.Date
|
|
day.EmailsSent += row.EmailsSent
|
|
day.EmailsReplied += row.EmailsReplied
|
|
day.EmailsReceived += row.EmailsReceived
|
|
day.TargetVolume += row.TargetVolume
|
|
day.Active = day.Active || row.Active
|
|
byDate[row.Date] = day
|
|
}
|
|
}
|
|
out := make([]WarmupDailyStats, 0, len(byDate))
|
|
for _, day := range byDate {
|
|
out = append(out, day)
|
|
}
|
|
sort.Slice(out, func(i, j int) bool { return out[i].Date < out[j].Date })
|
|
return out
|
|
}
|
|
|
|
func (d *WarmupPlacementData) Add(other *WarmupPlacementData) {
|
|
if other == nil {
|
|
return
|
|
}
|
|
d.Daily = append(d.Daily, other.Daily...)
|
|
d.Hosts = append(d.Hosts, other.Hosts...)
|
|
d.Sent = append(d.Sent, other.Sent...)
|
|
d.Unconfirmed = append(d.Unconfirmed, other.Unconfirmed...)
|
|
if d.Windows == nil {
|
|
d.Windows = make(map[uuid.UUID]WarmupPlacementWindow)
|
|
}
|
|
for id, window := range other.Windows {
|
|
current := d.Windows[id]
|
|
current.Add(window)
|
|
d.Windows[id] = current
|
|
}
|
|
}
|
|
|
|
func (d *WarmupPlacementData) RemapSenders(ids map[uuid.UUID]uuid.UUID) error {
|
|
remap := func(id *uuid.UUID) error {
|
|
target, ok := ids[*id]
|
|
if !ok {
|
|
return fmt.Errorf("unrequested warmup report sender")
|
|
}
|
|
*id = target
|
|
return nil
|
|
}
|
|
for i := range d.Daily {
|
|
if err := remap(&d.Daily[i].SenderID); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
for _, rows := range [][]WarmupSenderDayCount{d.Sent, d.Unconfirmed} {
|
|
for i := range rows {
|
|
if err := remap(&rows[i].SenderID); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
windows := make(map[uuid.UUID]WarmupPlacementWindow, len(d.Windows))
|
|
for id, window := range d.Windows {
|
|
if err := remap(&id); err != nil {
|
|
return err
|
|
}
|
|
current := windows[id]
|
|
current.Add(window)
|
|
windows[id] = current
|
|
}
|
|
d.Windows = windows
|
|
return nil
|
|
}
|