From 02f8e5b3bf8fc60225ebe764f061d8ffc51a3cee Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Thu, 25 Sep 2025 22:44:35 +0300 Subject: Bump version to 0.12.0 --- docs/coverage.html | 100 ++++++++++++++++++++++++++--------------------------- 1 file changed, 50 insertions(+), 50 deletions(-) (limited to 'docs/coverage.html') diff --git a/docs/coverage.html b/docs/coverage.html index 4a3153b..18886c9 100644 --- a/docs/coverage.html +++ b/docs/coverage.html @@ -7213,9 +7213,9 @@ import ( "golang.org/x/sys/unix" ) -func tryLockFile(fd uintptr) error { - if err := unix.Flock(int(fd), unix.LOCK_EX|unix.LOCK_NB); err != nil { - if errors.Is(err, unix.EWOULDBLOCK) { +func tryLockFile(fd uintptr) error { + if err := unix.Flock(int(fd), unix.LOCK_EX|unix.LOCK_NB); err != nil { + if errors.Is(err, unix.EWOULDBLOCK) { return errLockWouldBlock } return err @@ -7259,18 +7259,18 @@ var windowSeconds int64 = int64(defaultWindow.Seconds()) var errLockWouldBlock = errors.New("stats: lock would block") // SetWindow sets the sliding window used for pruning and aggregation. -func SetWindow(d time.Duration) { +func SetWindow(d time.Duration) { if d < time.Second { d = time.Second } - if d > 24*time.Hour { + if d > 24*time.Hour { d = 24 * time.Hour } - atomic.StoreInt64(&windowSeconds, int64(d.Seconds())) + atomic.StoreInt64(&windowSeconds, int64(d.Seconds())) } // Window returns the current sliding window. -func Window() time.Duration { return time.Duration(atomic.LoadInt64(&windowSeconds)) * time.Second } +func Window() time.Duration { return time.Duration(atomic.LoadInt64(&windowSeconds)) * time.Second } // Event represents a single request/response with sizes. type Event struct { @@ -7305,108 +7305,108 @@ type Snapshot struct { } // Update appends one event and prunes old entries under lock. -func Update(ctx context.Context, provider, model string, sentBytes, recvBytes int) error { +func Update(ctx context.Context, provider, model string, sentBytes, recvBytes int) error { dir, err := CacheDir() if err != nil { return err } - if err := os.MkdirAll(dir, 0o755); err != nil { + if err := os.MkdirAll(dir, 0o755); err != nil { return err } - lockPath := filepath.Join(dir, lockFileName) + lockPath := filepath.Join(dir, lockFileName) f, err := os.OpenFile(lockPath, os.O_CREATE|os.O_RDWR, 0o600) if err != nil { return err } - defer f.Close() + defer f.Close() unlock, err := acquireFileLock(ctx, f) if err != nil { return err } - defer func() { _ = unlock() }() + defer func() { _ = unlock() }() // Read existing file (if any) - path := filepath.Join(dir, fileName) + path := filepath.Join(dir, fileName) var sf File - if b, rerr := os.ReadFile(path); rerr == nil { + if b, rerr := os.ReadFile(path); rerr == nil { _ = json.Unmarshal(b, &sf) } - if sf.Version != fileVersion { + if sf.Version != fileVersion { sf = File{Version: fileVersion} } - now := time.Now() + now := time.Now() win := Window() sf.WindowSeconds = int(win.Seconds()) // Append event sf.Events = append(sf.Events, Event{TS: now, Provider: provider, Model: model, Sent: int64(sentBytes), Recv: int64(recvBytes)}) // Prune old cutoff := now.Add(-win) - if len(sf.Events) > 0 { + if len(sf.Events) > 0 { // Find first >= cutoff i := 0 - for ; i < len(sf.Events); i++ { - if !sf.Events[i].TS.Before(cutoff) { + for ; i < len(sf.Events); i++ { + if !sf.Events[i].TS.Before(cutoff) { break } } - if i > 0 { + if i > 0 { sf.Events = append([]Event(nil), sf.Events[i:]...) } } - sf.UpdatedAt = now + sf.UpdatedAt = now // Write atomically tmp, err := os.CreateTemp(dir, fileName+".tmp.") if err != nil { return err } - enc := json.NewEncoder(tmp) + enc := json.NewEncoder(tmp) enc.SetEscapeHTML(false) if err := enc.Encode(&sf); err != nil { tmp.Close() os.Remove(tmp.Name()) return err } - if err := tmp.Sync(); err != nil { + if err := tmp.Sync(); err != nil { tmp.Close() os.Remove(tmp.Name()) return err } - if err := tmp.Close(); err != nil { + if err := tmp.Close(); err != nil { os.Remove(tmp.Name()) return err } - if err := os.Rename(tmp.Name(), path); err != nil { + if err := os.Rename(tmp.Name(), path); err != nil { os.Remove(tmp.Name()) return err } - return nil + return nil } -func acquireFileLock(ctx context.Context, f *os.File) (func() error, error) { +func acquireFileLock(ctx context.Context, f *os.File) (func() error, error) { fd := f.Fd() - for { + for { err := tryLockFile(fd) - if err == nil { - return func() error { return unlockFile(fd) }, nil + if err == nil { + return func() error { return unlockFile(fd) }, nil } - if errors.Is(err, errLockWouldBlock) { + if errors.Is(err, errLockWouldBlock) { select { case <-ctx.Done(): return nil, ctx.Err() - case <-time.After(5 * time.Millisecond): + case <-time.After(5 * time.Millisecond): } - continue + continue } return nil, err } } // Snapshot reads and aggregates events within the configured window. -func TakeSnapshot() (Snapshot, error) { +func TakeSnapshot() (Snapshot, error) { dir, err := CacheDir() if err != nil { return Snapshot{}, err } - path := filepath.Join(dir, fileName) + path := filepath.Join(dir, fileName) b, err := os.ReadFile(path) if err != nil { if errors.Is(err, os.ErrNotExist) { @@ -7414,30 +7414,30 @@ func TakeSnapshot() (Snapshot, error) { } return Snapshot{}, err } - var sf File + var sf File if err := json.Unmarshal(b, &sf); err != nil { return Snapshot{}, err } - win := time.Duration(sf.WindowSeconds) * time.Second + win := time.Duration(sf.WindowSeconds) * time.Second if win <= 0 { win = Window() - } else { + } else { SetWindow(win) // align process with file window if changed elsewhere } - cutoff := time.Now().Add(-win) + cutoff := time.Now().Add(-win) snap := Snapshot{Providers: make(map[string]ProviderEntry), Window: win} - for _, ev := range sf.Events { + for _, ev := range sf.Events { if ev.TS.Before(cutoff) { continue } - snap.Global.Reqs++ + snap.Global.Reqs++ snap.Global.Sent += ev.Sent snap.Global.Recv += ev.Recv pe := snap.Providers[ev.Provider] - if pe.Models == nil { + if pe.Models == nil { pe.Models = make(map[string]Counters) } - pe.Totals.Reqs++ + pe.Totals.Reqs++ pe.Totals.Sent += ev.Sent pe.Totals.Recv += ev.Recv mc := pe.Models[ev.Model] @@ -7447,17 +7447,17 @@ func TakeSnapshot() (Snapshot, error) { pe.Models[ev.Model] = mc snap.Providers[ev.Provider] = pe } - mins := win.Minutes() + mins := win.Minutes() if mins <= 0 { mins = 0.001 } - snap.RPM = float64(snap.Global.Reqs) / mins + snap.RPM = float64(snap.Global.Reqs) / mins return snap, nil } // CacheDir resolves the cache directory for stats. -func CacheDir() (string, error) { - if x := os.Getenv("XDG_CACHE_HOME"); stringsTrim(x) != "" { +func CacheDir() (string, error) { + if x := os.Getenv("XDG_CACHE_HOME"); stringsTrim(x) != "" { return filepath.Join(x, "hexai"), nil } home, err := os.UserHomeDir() @@ -7468,16 +7468,16 @@ func CacheDir() (string, error) { } // stringsTrim is a tiny helper to avoid importing strings everywhere here. -func stringsTrim(s string) string { +func stringsTrim(s string) string { i := 0 j := len(s) for i < j && (s[i] == ' ' || s[i] == '\t' || s[i] == '\n' || s[i] == '\r') { i++ } - for j > i && (s[j-1] == ' ' || s[j-1] == '\t' || s[j-1] == '\n' || s[j-1] == '\r') { + for j > i && (s[j-1] == ' ' || s[j-1] == '\t' || s[j-1] == '\n' || s[j-1] == '\r') { j-- } - if i == 0 && j == len(s) { + if i == 0 && j == len(s) { return s } return s[i:j] -- cgit v1.2.3