mirror of
https://github.com/kataras/iris.git
synced 2025-01-22 18:21:03 +01:00
216 lines
6.3 KiB
Go
216 lines
6.3 KiB
Go
package iris
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/kataras/iris/v12/context"
|
|
)
|
|
|
|
type (
|
|
// ContextSetter is an interface which can be implemented by a struct
|
|
// to set the iris.Context to the struct.
|
|
// The receiver must be a pointer of the struct.
|
|
ContextSetter interface {
|
|
// SetContext sets the iris.Context to the struct.
|
|
SetContext(Context)
|
|
}
|
|
|
|
// ContextSetterPtr is a pointer of T which implements the `ContextSetter` interface.
|
|
// The T must be a struct.
|
|
ContextSetterPtr[T any] interface {
|
|
*T
|
|
ContextSetter
|
|
}
|
|
|
|
// emptyContextSetter is an empty struct which implements the `ContextSetter` interface.
|
|
emptyContextSetter struct{}
|
|
)
|
|
|
|
// SetContext method implements `ContextSetter` interface.
|
|
func (*emptyContextSetter) SetContext(Context) {}
|
|
|
|
// ContextPool is a pool of T. It's used to acquire and release custom context.
|
|
// Use of custom implementation or `NewContextPool`.
|
|
//
|
|
// See `NewContextWrapper` and `NewContextPool` for more.
|
|
type (
|
|
ContextPool[T any] interface {
|
|
// Acquire must return a new T from a pool.
|
|
Acquire(ctx Context) T
|
|
// Release must put the T back to the pool.
|
|
Release(T)
|
|
}
|
|
|
|
// syncContextPool is a sync pool implementation of T.
|
|
// It's used to acquire and release T.
|
|
// The contextPtr is acquired from the sync pool and released back to the sync pool after the handler's execution.
|
|
// The contextPtr is passed to the handler as an argument.
|
|
// ThecontextPtr is not shared between requests.
|
|
// The contextPtr must implement the `ContextSetter` interface.
|
|
// The T must be a struct.
|
|
// The contextPtr must be a pointer of T.
|
|
syncContextPool[T any, contextPtr ContextSetterPtr[T]] struct {
|
|
pool *sync.Pool
|
|
}
|
|
)
|
|
|
|
// Ensure that syncContextPool implements ContextPool.
|
|
var _ ContextPool[*emptyContextSetter] = (*syncContextPool[emptyContextSetter, *emptyContextSetter])(nil)
|
|
|
|
// NewContextPool returns a new ContextPool default implementation which
|
|
// uses sync.Pool to implement its Acquire and Release methods.
|
|
// The contextPtr is acquired from the sync pool and released back to the sync pool after the handler's execution.
|
|
// The contextPtr is passed to the handler as an argument.
|
|
// ThecontextPtr is not shared between requests.
|
|
// The contextPtr must implement the `ContextSetter` interface.
|
|
// The T must be a struct.
|
|
// The contextPtr must be a pointer of T.
|
|
//
|
|
// Example:
|
|
// w := iris.NewContextWrapper(iris.NewContextPool[myCustomContext, *myCustomContext]())
|
|
func NewContextPool[T any, contextPtr ContextSetterPtr[T]]() ContextPool[contextPtr] {
|
|
return &syncContextPool[T, contextPtr]{
|
|
pool: &sync.Pool{
|
|
New: func() interface{} {
|
|
var t contextPtr = new(T)
|
|
return t
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// Acquire returns a new T from the sync pool.
|
|
func (p *syncContextPool[T, contextPtr]) Acquire(ctx Context) contextPtr {
|
|
// var t contextPtr
|
|
// if v := p.pool.Get(); v == nil {
|
|
// t = new(T)
|
|
// } else {
|
|
// t = v.(contextPtr)
|
|
// }
|
|
|
|
t := p.pool.Get().(contextPtr)
|
|
t.SetContext(ctx)
|
|
return t
|
|
}
|
|
|
|
// Release puts the T back to the sync pool.
|
|
func (p *syncContextPool[T, contextPtr]) Release(t contextPtr) {
|
|
p.pool.Put(t)
|
|
}
|
|
|
|
// ContextWrapper is a wrapper for handlers which expect a T instead of iris.Context.
|
|
//
|
|
// See the `NewContextWrapper` function for more.
|
|
type ContextWrapper[T any] struct {
|
|
pool ContextPool[T]
|
|
}
|
|
|
|
// NewContextWrapper returns a new ContextWrapper.
|
|
// If pool is nil, a default pool is used.
|
|
// The default pool's AcquireFunc returns a zero value of T.
|
|
// The default pool's ReleaseFunc does nothing.
|
|
// The default pool is used when the pool is nil.
|
|
// Use the `iris.NewContextPool[T, *T]()` to pass a simple context pool.
|
|
// Then, use the `Handler` method to wrap custom handlers to iris ones.
|
|
//
|
|
// Example: https://github.com/kataras/iris/tree/main/_examples/routing/custom-context
|
|
func NewContextWrapper[T any](pool ContextPool[T]) *ContextWrapper[T] {
|
|
if pool == nil {
|
|
panic("pool cannot be nil")
|
|
}
|
|
|
|
return &ContextWrapper[T]{
|
|
pool: pool,
|
|
}
|
|
}
|
|
|
|
// Pool returns the pool, useful when manually Acquire and Release of custom context is required.
|
|
func (w *ContextWrapper[T]) Pool() ContextPool[T] {
|
|
return w.pool
|
|
}
|
|
|
|
// Handler wraps the handler with the pool's Acquire and Release methods.
|
|
// It returns a new handler which expects a T instead of iris.Context.
|
|
// The T is the type of the pool.
|
|
// The T is acquired from the pool and released back to the pool after the handler's execution.
|
|
// The T is passed to the handler as an argument.
|
|
// The T is not shared between requests.
|
|
func (w *ContextWrapper[T]) Handler(handler func(T)) Handler {
|
|
if handler == nil {
|
|
return nil
|
|
}
|
|
|
|
return func(ctx Context) {
|
|
newT := w.pool.Acquire(ctx)
|
|
handler(newT)
|
|
w.pool.Release(newT)
|
|
}
|
|
}
|
|
|
|
// Handlers wraps the handlers with the pool's Acquire and Release methods.
|
|
func (w *ContextWrapper[T]) Handlers(handlers ...func(T)) context.Handlers {
|
|
newHandlers := make(context.Handlers, len(handlers))
|
|
for i, handler := range handlers {
|
|
newHandlers[i] = w.Handler(handler)
|
|
}
|
|
|
|
return newHandlers
|
|
}
|
|
|
|
// HandlerReturnError same as `Handler` but it converts a handler which returns an error.
|
|
func (w *ContextWrapper[T]) HandlerReturnError(handler func(T) error) func(Context) error {
|
|
if handler == nil {
|
|
return nil
|
|
}
|
|
|
|
return func(ctx Context) error {
|
|
newT := w.pool.Acquire(ctx)
|
|
err := handler(newT)
|
|
w.pool.Release(newT)
|
|
return err
|
|
}
|
|
}
|
|
|
|
// HandlerReturnDuration same as `Handler` but it converts a handler which returns a time.Duration.
|
|
func (w *ContextWrapper[T]) HandlerReturnDuration(handler func(T) time.Duration) func(Context) time.Duration {
|
|
if handler == nil {
|
|
return nil
|
|
}
|
|
|
|
return func(ctx Context) time.Duration {
|
|
newT := w.pool.Acquire(ctx)
|
|
duration := handler(newT)
|
|
w.pool.Release(newT)
|
|
return duration
|
|
}
|
|
}
|
|
|
|
// Filter same as `Handler` but it converts a handler to Filter.
|
|
func (w *ContextWrapper[T]) Filter(handler func(T) bool) Filter {
|
|
if handler == nil {
|
|
return nil
|
|
}
|
|
|
|
return func(ctx Context) bool {
|
|
newT := w.pool.Acquire(ctx)
|
|
shouldContinue := handler(newT)
|
|
w.pool.Release(newT)
|
|
return shouldContinue
|
|
}
|
|
}
|
|
|
|
// FallbackViewFunc same as `Handler` but it converts a handler to FallbackViewFunc.
|
|
func (w *ContextWrapper[T]) FallbackViewFunc(handler func(ctx T, err ErrViewNotExist) error) FallbackViewFunc {
|
|
if handler == nil {
|
|
return nil
|
|
}
|
|
|
|
return func(ctx Context, err ErrViewNotExist) error {
|
|
newT := w.pool.Acquire(ctx)
|
|
returningErr := handler(newT, err)
|
|
w.pool.Release(newT)
|
|
return returningErr
|
|
}
|
|
}
|