Files
claude-statusline/internal/fetcher/cache.go
Axel Meyer 7f17a40b7c
Some checks failed
Release / build (push) Failing after 21s
Rewrite in Go: static binaries, zero runtime dependencies
Replace Node.js + Python codebase with three Go binaries:
- claude-statusline: CLI status bar for Claude Code
- claude-fetcher: standalone cron job for API usage
- claude-widget: system tray icon (fyne-io/systray + fogleman/gg)

All CGO-free for trivial cross-compilation. Add nfpm .deb packaging
with autostart and cron. CI pipeline produces Linux + Windows binaries,
.deb, .tar.gz, and .zip release assets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 15:27:10 +00:00

86 lines
2.0 KiB
Go

package fetcher
import (
"encoding/json"
"os"
"runtime"
"time"
)
// CacheData represents the JSON structure written to the cache file.
// It mirrors the raw API response (five_hour, seven_day) plus error fields.
type CacheData struct {
FiveHour *UsageWindow `json:"five_hour,omitempty"`
SevenDay *UsageWindow `json:"seven_day,omitempty"`
Error string `json:"_error,omitempty"`
Status int `json:"_status,omitempty"`
Message string `json:"_message,omitempty"`
}
// UsageWindow represents a single usage window from the API.
type UsageWindow struct {
Utilization float64 `json:"utilization"`
ResetsAt string `json:"resets_at"`
}
// CachePath returns the cache file path.
func CachePath() string {
if v := os.Getenv("CLAUDE_USAGE_CACHE"); v != "" {
return v
}
if runtime.GOOS == "windows" {
if tmp := os.Getenv("TEMP"); tmp != "" {
return tmp + `\claude_usage.json`
}
return os.TempDir() + `\claude_usage.json`
}
return "/tmp/claude_usage.json"
}
// WriteCache writes data to the cache file as JSON.
func WriteCache(data *CacheData) error {
b, err := json.MarshalIndent(data, "", " ")
if err != nil {
return err
}
return os.WriteFile(CachePath(), b, 0o644)
}
// ReadCache reads and parses the cache file. Returns data and file age.
// Returns nil if file doesn't exist or can't be parsed.
func ReadCache() (*CacheData, time.Duration) {
path := CachePath()
info, err := os.Stat(path)
if err != nil {
return nil, 0
}
age := time.Since(info.ModTime())
raw, err := os.ReadFile(path)
if err != nil {
return nil, 0
}
var data CacheData
if err := json.Unmarshal(raw, &data); err != nil {
return nil, 0
}
return &data, age
}
// ReadCacheIfFresh reads cache only if it's younger than maxAge.
// Error caches are always returned regardless of age.
func ReadCacheIfFresh(maxAge time.Duration) *CacheData {
data, age := ReadCache()
if data == nil {
return nil
}
if data.Error != "" {
return data
}
if age > maxAge {
return nil
}
return data
}