package web import ( "fmt" "math" "slices" "time" ) // window remembers when recent conversions started, so it can tell whether // another one would go over a limit of n conversions per period. type window []time.Time // prune drops entries older than period. func (w *window) prune(now time.Time, period time.Duration) { cut := 0 for cut < len(*w) && now.Sub((*w)[cut]) >= period { cut++ } *w = (*w)[cut:] } // full reports whether n conversions already started within period, and if // so when the oldest of them stops counting. func (w window) full(now time.Time, n int, period time.Duration) (bool, time.Time) { if len(w) < n { return false, time.Time{} } return true, w[len(w)-n].Add(period) } // remove takes back one entry made at t. func (w *window) remove(t time.Time) { if i := slices.Index(*w, t); i >= 0 { *w = slices.Delete(*w, i, i+1) } } // minutes describes d in whole minutes, rounded up. func minutes(d time.Duration) string { m := max(1, int(math.Ceil(d.Minutes()))) if m == 1 { return "1 minute" } return fmt.Sprintf("%d minutes", m) }