* feat: add middleware example demonstrating route groups Self-contained example covering v.Use(), v.Group(), nested groups, Group.Use(), and middleware chaining with role-based access control. * feat: add per-action middleware via WithMiddleware ActionOption Reuses the existing Middleware type so the same auth/logging functions work at both page and action level. Middleware runs after CSRF and rate-limit checks, with full access to session and signals. * feat: add RedirectView helper and refactor session example to use middleware RedirectView lets middleware abort and redirect in one step. The session example now uses an authRequired middleware on a route group instead of an inline check inside the view. * fix: remove dead code, fix double Load and extractParams mismatch - Remove componentRegistry (written, never read) - Remove unused signal methods: Bytes, Int64, Float - Remove unreachable nil check in registerCtx - Simplify injectRouteParams (extractParams already returns fresh map) - Fix double sync.Map.Load in injectSignals - Merge Shutdown/shutdown into single method - Inline currSessionNum - Fix extractParams: mismatched literal segment now returns nil - Minor: new(bytes.Buffer), go c.Sync(), genRandID reads 4 bytes
50 lines
1.3 KiB
Go
50 lines
1.3 KiB
Go
package via
|
|
|
|
import "golang.org/x/time/rate"
|
|
|
|
const (
|
|
defaultActionRate float64 = 10.0
|
|
defaultActionBurst int = 20
|
|
)
|
|
|
|
// RateLimitConfig configures token-bucket rate limiting for actions.
|
|
// Zero values fall back to defaults. Rate of -1 disables limiting entirely.
|
|
type RateLimitConfig struct {
|
|
Rate float64
|
|
Burst int
|
|
}
|
|
|
|
// ActionOption configures per-action behaviour when passed to Context.Action.
|
|
type ActionOption func(*actionEntry)
|
|
|
|
type actionEntry struct {
|
|
fn func()
|
|
limiter *rate.Limiter // nil = use context default
|
|
middleware []Middleware
|
|
}
|
|
|
|
// WithRateLimit returns an ActionOption that gives this action its own
|
|
// token-bucket limiter, overriding the context-level default.
|
|
func WithRateLimit(r float64, burst int) ActionOption {
|
|
return func(e *actionEntry) {
|
|
e.limiter = newLimiter(RateLimitConfig{Rate: r, Burst: burst}, defaultActionRate, defaultActionBurst)
|
|
}
|
|
}
|
|
|
|
// newLimiter creates a *rate.Limiter from cfg, substituting defaults for zero
|
|
// values. A Rate of -1 disables limiting (returns nil).
|
|
func newLimiter(cfg RateLimitConfig, defaultRate float64, defaultBurst int) *rate.Limiter {
|
|
r := cfg.Rate
|
|
b := cfg.Burst
|
|
if r == -1 {
|
|
return nil
|
|
}
|
|
if r == 0 {
|
|
r = defaultRate
|
|
}
|
|
if b == 0 {
|
|
b = defaultBurst
|
|
}
|
|
return rate.NewLimiter(rate.Limit(r), b)
|
|
}
|