feat: add middleware, route groups, and codebase cleanup
* 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
This commit is contained in:
82
middleware.go
Normal file
82
middleware.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package via
|
||||
|
||||
// Middleware wraps a page init function. Call next to continue the chain;
|
||||
// return without calling next to abort (set a view first, e.g. RedirectView).
|
||||
type Middleware func(c *Context, next func())
|
||||
|
||||
// Group is a route group with a shared prefix and middleware stack.
|
||||
type Group struct {
|
||||
v *V
|
||||
prefix string
|
||||
middleware []Middleware
|
||||
}
|
||||
|
||||
// Use appends middleware to the global stack.
|
||||
// Global middleware runs before every page handler.
|
||||
func (v *V) Use(mw ...Middleware) {
|
||||
v.middleware = append(v.middleware, mw...)
|
||||
}
|
||||
|
||||
// Group creates a route group with the given path prefix and middleware.
|
||||
// Routes registered on the group are prefixed and run the group's middleware
|
||||
// after any global middleware.
|
||||
func (v *V) Group(prefix string, mw ...Middleware) *Group {
|
||||
return &Group{
|
||||
v: v,
|
||||
prefix: prefix,
|
||||
middleware: mw,
|
||||
}
|
||||
}
|
||||
|
||||
// Page registers a route on this group. The full route is the group prefix
|
||||
// concatenated with route.
|
||||
func (g *Group) Page(route string, initContextFn func(c *Context)) {
|
||||
fullRoute := g.prefix + route
|
||||
allMw := make([]Middleware, 0, len(g.v.middleware)+len(g.middleware))
|
||||
allMw = append(allMw, g.v.middleware...)
|
||||
allMw = append(allMw, g.middleware...)
|
||||
wrapped := chainMiddleware(allMw, initContextFn)
|
||||
g.v.page(fullRoute, initContextFn, wrapped)
|
||||
}
|
||||
|
||||
// Group creates a nested sub-group that inherits this group's prefix and
|
||||
// middleware, then adds its own.
|
||||
func (g *Group) Group(prefix string, mw ...Middleware) *Group {
|
||||
combined := make([]Middleware, len(g.middleware), len(g.middleware)+len(mw))
|
||||
copy(combined, g.middleware)
|
||||
combined = append(combined, mw...)
|
||||
return &Group{
|
||||
v: g.v,
|
||||
prefix: g.prefix + prefix,
|
||||
middleware: combined,
|
||||
}
|
||||
}
|
||||
|
||||
// Use appends middleware to this group's stack.
|
||||
func (g *Group) Use(mw ...Middleware) {
|
||||
g.middleware = append(g.middleware, mw...)
|
||||
}
|
||||
|
||||
// WithMiddleware returns an ActionOption that attaches middleware to an action.
|
||||
// Action middleware runs after CSRF/rate-limit checks and signal injection.
|
||||
func WithMiddleware(mw ...Middleware) ActionOption {
|
||||
return func(e *actionEntry) {
|
||||
e.middleware = append(e.middleware, mw...)
|
||||
}
|
||||
}
|
||||
|
||||
// chainMiddleware wraps handler with the given middleware, outer-first.
|
||||
func chainMiddleware(mws []Middleware, handler func(*Context)) func(*Context) {
|
||||
if len(mws) == 0 {
|
||||
return handler
|
||||
}
|
||||
chained := handler
|
||||
for i := len(mws) - 1; i >= 0; i-- {
|
||||
mw := mws[i]
|
||||
next := chained
|
||||
chained = func(c *Context) {
|
||||
mw(c, func() { next(c) })
|
||||
}
|
||||
}
|
||||
return chained
|
||||
}
|
||||
Reference in New Issue
Block a user