| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546 |
- 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)
- }
|