package httpx import ( "encoding/json" "net/http" "sync" "time" ) // JSON پاسخ JSON با کد وضعیت می‌نویسد. func JSON(w http.ResponseWriter, status int, body any) { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(status) _ = json.NewEncoder(w).Encode(body) } // Error پاسخ خطای استاندارد { "message": ... }. func Error(w http.ResponseWriter, status int, msg string) { JSON(w, status, map[string]string{"message": msg}) } // Throttle محدودکننده ساده in-memory بر اساس کلید (مثل IP یا موبایل). // معادل throttle:max,perMinutes در Laravel — بدون نیاز به Redis. type Throttle struct { mu sync.Mutex hits map[string][]time.Time max int window time.Duration } func NewThrottle(max int, window time.Duration) *Throttle { return &Throttle{hits: make(map[string][]time.Time), max: max, window: window} } // Allow بررسی می‌کند آیا کلید در پنجره زمانی مجاز است. func (t *Throttle) Allow(key string) bool { t.mu.Lock() defer t.mu.Unlock() now := time.Now() cutoff := now.Add(-t.window) kept := t.hits[key][:0] for _, ts := range t.hits[key] { if ts.After(cutoff) { kept = append(kept, ts) } } if len(kept) >= t.max { t.hits[key] = kept return false } t.hits[key] = append(kept, now) return true }