GoDoxy/internal/metrics/period/entries.go
Yuzerion 80bc018a7f
feat: custom json marshaling implementation, replace json and yaml library (#89)
* chore: replace gopkg.in/yaml.v3 vs goccy/go-yaml; replace encoding/json with bytedance/sonic

* fix: yaml unmarshal panic

* feat: custom json marshaler implementation

* chore: fix import and err marshal handling

---------

Co-authored-by: yusing <yusing@6uo.me>
2025-04-16 15:02:11 +08:00

80 lines
1.5 KiB
Go

package period
import (
"time"
"github.com/yusing/go-proxy/pkg/json"
)
type Entries[T any] struct {
entries [maxEntries]*T
index int
count int
interval time.Duration
lastAdd time.Time
}
const maxEntries = 100
func newEntries[T any](duration time.Duration) *Entries[T] {
interval := duration / maxEntries
if interval < time.Second {
interval = time.Second
}
return &Entries[T]{
interval: interval,
lastAdd: time.Now(),
}
}
func (e *Entries[T]) Add(now time.Time, info *T) {
if now.Sub(e.lastAdd) < e.interval {
return
}
e.entries[e.index] = info
e.index = (e.index + 1) % maxEntries
if e.count < maxEntries {
e.count++
}
e.lastAdd = now
}
func (e *Entries[T]) Get() []*T {
if e.count < maxEntries {
return e.entries[:e.count]
}
res := make([]*T, maxEntries)
copy(res, e.entries[e.index:])
copy(res[maxEntries-e.index:], e.entries[:e.index])
return res
}
func (e *Entries[T]) MarshalJSONTo(buf []byte) []byte {
return json.MarshalTo(map[string]any{
"entries": e.Get(),
"interval": e.interval,
}, buf)
}
func (e *Entries[T]) UnmarshalJSON(data []byte) error {
var v struct {
Entries []*T `json:"entries"`
Interval time.Duration `json:"interval"`
}
if err := json.Unmarshal(data, &v); err != nil {
return err
}
if len(v.Entries) == 0 {
return nil
}
entries := v.Entries
if len(entries) > maxEntries {
entries = entries[:maxEntries]
}
now := time.Now()
for _, info := range entries {
e.Add(now, info)
}
e.interval = v.Interval
return nil
}