123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- 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
- }
- }
|