mirror of
https://github.com/kataras/iris.git
synced 2025-02-02 15:30:36 +01:00
improvements of the new ContextWrapper
This commit is contained in:
parent
ec69670edc
commit
4d13ff3622
|
@ -23,7 +23,7 @@ Developers are not forced to upgrade if they don't really need it. Upgrade whene
|
||||||
|
|
||||||
Changes apply to `main` branch.
|
Changes apply to `main` branch.
|
||||||
|
|
||||||
- A new way to customize the handler's parameter among with the `hero` and `mvc` packages. New `iris.NewContextWrapper` method and `iris.DefaultContextPool` struct were added to wrap a handler and use a custom context instead of the iris.Context directly.
|
- A new way to customize the handler's parameter among with the `hero` and `mvc` packages. New `iris.NewContextWrapper` and `iris.NewContextPool` methods were added to wrap a handler and use a custom context instead of the iris.Context directly. Example at: https://github.com/kataras/iris/tree/main/_examples/routing/custom-context.
|
||||||
|
|
||||||
- The `cache` sub-package has an update, after 4 years:
|
- The `cache` sub-package has an update, after 4 years:
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/kataras/iris/v12"
|
"github.com/kataras/iris/v12"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -8,22 +10,12 @@ func main() {
|
||||||
// 1. Create the iris app instance.
|
// 1. Create the iris app instance.
|
||||||
app := iris.New()
|
app := iris.New()
|
||||||
|
|
||||||
/*
|
|
||||||
w := iris.NewContextWrapper(&iris.DefaultContextPool[*myCustomContext]{
|
|
||||||
AcquireFunc: func(ctx iris.Context) *myCustomContext {
|
|
||||||
return &myCustomContext{
|
|
||||||
Context: ctx,
|
|
||||||
// custom fields here...
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ReleaseFunc: func(t *myCustomContext) {
|
|
||||||
// do nothing
|
|
||||||
},
|
|
||||||
})
|
|
||||||
OR: */
|
|
||||||
// 2. Create the Context Wrapper which will be used to wrap the handlers
|
// 2. Create the Context Wrapper which will be used to wrap the handlers
|
||||||
// that expect a *myCustomContext instead of iris.Context.
|
// that expect a *myCustomContext instead of iris.Context.
|
||||||
w := iris.NewContextWrapper(&myCustomContextPool{})
|
w := iris.NewContextWrapper(&myCustomContextPool{})
|
||||||
|
// OR:
|
||||||
|
// w := iris.NewContextWrapper(iris.NewContextPool[myCustomContext, *myCustomContext]())
|
||||||
|
// The example custom context pool operates exactly the same as the result of iris.NewContextPool.
|
||||||
|
|
||||||
// 3. Register the handler(s) which expects a *myCustomContext instead of iris.Context.
|
// 3. Register the handler(s) which expects a *myCustomContext instead of iris.Context.
|
||||||
// The `w.Handler` will wrap the handler and will call the `Acquire` and `Release`
|
// The `w.Handler` will wrap the handler and will call the `Acquire` and `Release`
|
||||||
|
@ -38,6 +30,38 @@ func index(ctx *myCustomContext) {
|
||||||
ctx.HTML("<h1>Hello, World!</h1>")
|
ctx.HTML("<h1>Hello, World!</h1>")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Custom Context Pool
|
||||||
|
*/
|
||||||
|
// Create the context sync pool for our custom context,
|
||||||
|
// the pool must implement Acquire() T and Release(T) methods to satisfy the iris.ContextPool interface.
|
||||||
|
type myCustomContextPool struct {
|
||||||
|
pool sync.Pool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Acquire returns a new custom context from the pool.
|
||||||
|
func (p *myCustomContextPool) Acquire(ctx iris.Context) *myCustomContext {
|
||||||
|
v := p.pool.Get()
|
||||||
|
if v == nil {
|
||||||
|
v = &myCustomContext{
|
||||||
|
Context: ctx,
|
||||||
|
// custom fields here...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return v.(*myCustomContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release puts a custom context back to the pool.
|
||||||
|
func (p *myCustomContextPool) Release(t *myCustomContext) {
|
||||||
|
// You can take advantage of this method to clear the context
|
||||||
|
// and re-use it on the Acquire method, use the sync.Pool.
|
||||||
|
p.pool.Put(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Custom Context
|
||||||
|
*/
|
||||||
// Create a custom context.
|
// Create a custom context.
|
||||||
type myCustomContext struct {
|
type myCustomContext struct {
|
||||||
// It's just an embedded field which is set on AcquireFunc,
|
// It's just an embedded field which is set on AcquireFunc,
|
||||||
|
@ -47,28 +71,16 @@ type myCustomContext struct {
|
||||||
iris.Context
|
iris.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetContext sets the original iris.Context,
|
||||||
|
// should be implemented by custom context type(s) when
|
||||||
|
// the ContextWrapper uses a context Pool through the iris.NewContextPool function.
|
||||||
|
// Comment line 15, uncomment line 17 and the method below.
|
||||||
|
func (c *myCustomContext) SetContext(ctx iris.Context) {
|
||||||
|
c.Context = ctx
|
||||||
|
}
|
||||||
|
|
||||||
func (c *myCustomContext) HTML(format string, args ...interface{}) (int, error) {
|
func (c *myCustomContext) HTML(format string, args ...interface{}) (int, error) {
|
||||||
c.Application().Logger().Info("HTML was called from custom Context")
|
c.Application().Logger().Info("HTML was called from custom Context")
|
||||||
|
|
||||||
return c.Context.HTML(format, args...)
|
return c.Context.HTML(format, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the context memory pool for your custom context,
|
|
||||||
// the pool must contain Acquire() T and Release(T) methods.
|
|
||||||
type myCustomContextPool struct{}
|
|
||||||
|
|
||||||
// Acquire returns a new custom context from the pool.
|
|
||||||
func (p *myCustomContextPool) Acquire(ctx iris.Context) *myCustomContext {
|
|
||||||
return &myCustomContext{
|
|
||||||
Context: ctx,
|
|
||||||
// custom fields here...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release puts a custom context back to the pool.
|
|
||||||
func (p *myCustomContextPool) Release(t *myCustomContext) {
|
|
||||||
// You can take advantage of this method to clear the context
|
|
||||||
// and re-use it on the Acquire method, use the sync.Pool.
|
|
||||||
//
|
|
||||||
// We do nothing for the shake of the exampel.
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,51 +1,101 @@
|
||||||
package iris
|
package iris
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/kataras/iris/v12/context"
|
"github.com/kataras/iris/v12/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContextPool is a pool of T.
|
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 `ContextPool` for more.
|
// See `NewContextWrapper` and `NewContextPool` for more.
|
||||||
type ContextPool[T any] interface {
|
type (
|
||||||
|
ContextPool[T any] interface {
|
||||||
|
// Acquire must return a new T from a pool.
|
||||||
Acquire(ctx Context) T
|
Acquire(ctx Context) T
|
||||||
|
// Release must put the T back to the pool.
|
||||||
Release(T)
|
Release(T)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultContextPool is a pool of T.
|
// syncContextPool is a sync pool implementation of T.
|
||||||
// It's used to acquire and release T.
|
// It's used to acquire and release T.
|
||||||
// The T is acquired from the pool and released back to the pool after the handler's execution.
|
// The contextPtr is acquired from the sync pool and released back to the sync pool after the handler's execution.
|
||||||
// The T is passed to the handler as an argument.
|
// The contextPtr is passed to the handler as an argument.
|
||||||
// The T is not shared between requests.
|
// ThecontextPtr is not shared between requests.
|
||||||
type DefaultContextPool[T any] struct {
|
// The contextPtr must implement the `ContextSetter` interface.
|
||||||
AcquireFunc func(Context) T
|
// The T must be a struct.
|
||||||
ReleaseFunc func(T)
|
// The contextPtr must be a pointer of T.
|
||||||
}
|
syncContextPool[T any, contextPtr ContextSetterPtr[T]] struct {
|
||||||
|
pool *sync.Pool
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// Ensure that DefaultContextPool[T] implements ContextPool[T].
|
// Ensure that syncContextPool implements ContextPool.
|
||||||
var _ ContextPool[any] = (*DefaultContextPool[any])(nil)
|
var _ ContextPool[*emptyContextSetter] = (*syncContextPool[emptyContextSetter, *emptyContextSetter])(nil)
|
||||||
|
|
||||||
// Acquire returns a new T from the pool's AcquireFunc.
|
// NewContextPool returns a new ContextPool default implementation which
|
||||||
func (p *DefaultContextPool[T]) Acquire(ctx Context) T {
|
// uses sync.Pool to implement its Acquire and Release methods.
|
||||||
acquire := p.AcquireFunc
|
// The contextPtr is acquired from the sync pool and released back to the sync pool after the handler's execution.
|
||||||
if p.AcquireFunc == nil {
|
// The contextPtr is passed to the handler as an argument.
|
||||||
acquire = func(ctx Context) T {
|
// ThecontextPtr is not shared between requests.
|
||||||
var t T
|
// 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
|
return t
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return acquire(ctx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release does nothing if the pool's ReleaseFunc is nil.
|
// Acquire returns a new T from the sync pool.
|
||||||
func (p *DefaultContextPool[T]) Release(t T) {
|
func (p *syncContextPool[T, contextPtr]) Acquire(ctx Context) contextPtr {
|
||||||
release := p.ReleaseFunc
|
// var t contextPtr
|
||||||
if p.ReleaseFunc == nil {
|
// if v := p.pool.Get(); v == nil {
|
||||||
release = func(t T) {}
|
// t = new(T)
|
||||||
}
|
// } else {
|
||||||
|
// t = v.(contextPtr)
|
||||||
|
// }
|
||||||
|
|
||||||
release(t)
|
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.
|
// ContextWrapper is a wrapper for handlers which expect a T instead of iris.Context.
|
||||||
|
@ -60,19 +110,13 @@ type ContextWrapper[T any] struct {
|
||||||
// The default pool's AcquireFunc returns a zero value of T.
|
// The default pool's AcquireFunc returns a zero value of T.
|
||||||
// The default pool's ReleaseFunc does nothing.
|
// The default pool's ReleaseFunc does nothing.
|
||||||
// The default pool is used when the pool is nil.
|
// The default pool is used when the pool is nil.
|
||||||
// Use the `&iris.DefaultContextPool{...}` to pass a simple context pool.
|
// Use the `iris.NewContextPool[T, *T]()` to pass a simple context pool.
|
||||||
|
// Then, use the `Handler` method to wrap custom handlers to iris ones.
|
||||||
//
|
//
|
||||||
// See the `Handler` method for more.
|
|
||||||
// Example: https://github.com/kataras/iris/tree/main/_examples/routing/custom-context
|
// Example: https://github.com/kataras/iris/tree/main/_examples/routing/custom-context
|
||||||
func NewContextWrapper[T any](pool ContextPool[T]) *ContextWrapper[T] {
|
func NewContextWrapper[T any](pool ContextPool[T]) *ContextWrapper[T] {
|
||||||
if pool == nil {
|
if pool == nil {
|
||||||
pool = &DefaultContextPool[T]{
|
panic("pool cannot be nil")
|
||||||
AcquireFunc: func(ctx Context) T {
|
|
||||||
var t T
|
|
||||||
return t
|
|
||||||
},
|
|
||||||
ReleaseFunc: func(t T) {},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ContextWrapper[T]{
|
return &ContextWrapper[T]{
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -35,7 +35,7 @@ require (
|
||||||
github.com/redis/go-redis/v9 v9.3.0
|
github.com/redis/go-redis/v9 v9.3.0
|
||||||
github.com/schollz/closestmatch v2.1.0+incompatible
|
github.com/schollz/closestmatch v2.1.0+incompatible
|
||||||
github.com/shirou/gopsutil/v3 v3.23.10
|
github.com/shirou/gopsutil/v3 v3.23.10
|
||||||
github.com/tdewolff/minify/v2 v2.20.5
|
github.com/tdewolff/minify/v2 v2.20.6
|
||||||
github.com/vmihailenco/msgpack/v5 v5.4.1
|
github.com/vmihailenco/msgpack/v5 v5.4.1
|
||||||
github.com/yosssi/ace v0.0.5
|
github.com/yosssi/ace v0.0.5
|
||||||
go.etcd.io/bbolt v1.3.8
|
go.etcd.io/bbolt v1.3.8
|
||||||
|
@ -95,7 +95,7 @@ require (
|
||||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||||
github.com/stretchr/testify v1.8.4 // indirect
|
github.com/stretchr/testify v1.8.4 // indirect
|
||||||
github.com/tdewolff/parse/v2 v2.7.3-0.20231031132452-e7c20a5d77ab // indirect
|
github.com/tdewolff/parse/v2 v2.7.4 // indirect
|
||||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
|
|
12
go.sum
generated
12
go.sum
generated
|
@ -224,12 +224,12 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502/go.mod h1:p9lPsd+cx33L3H9nNoecRRxPssFKUwwI50I3pZ0yT+8=
|
github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502/go.mod h1:p9lPsd+cx33L3H9nNoecRRxPssFKUwwI50I3pZ0yT+8=
|
||||||
github.com/tdewolff/minify/v2 v2.20.5 h1:IbJpmpAFESnuJPdsvFBJWsDcXE5qHsmaVQrRqhOI9sI=
|
github.com/tdewolff/minify/v2 v2.20.6 h1:R4+Iw1ZqJxrqH52WWHtCpukMuhmO/EasY8YlDiSxphw=
|
||||||
github.com/tdewolff/minify/v2 v2.20.5/go.mod h1:N78HtaitkDYAWXFbqhWX/LzgwylwudK0JvybGDVQ+Mw=
|
github.com/tdewolff/minify/v2 v2.20.6/go.mod h1:9t0EY9xySGt1vrP8iscmJfywQwDCQyQBYN6ge+9GwP0=
|
||||||
github.com/tdewolff/parse/v2 v2.7.3-0.20231031132452-e7c20a5d77ab h1:4zj+h84OrVW4pljmp+LABknN7VS1IMAbeHj+eckO6Ao=
|
github.com/tdewolff/parse/v2 v2.7.4 h1:zrUn2CFg9+5llbUZcsycctFlNRyV1D5gFBZRxuGzdzk=
|
||||||
github.com/tdewolff/parse/v2 v2.7.3-0.20231031132452-e7c20a5d77ab/go.mod h1:9p2qMIHpjRSTr1qnFxQr+igogyTUTlwvf9awHSm84h8=
|
github.com/tdewolff/parse/v2 v2.7.4/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA=
|
||||||
github.com/tdewolff/test v1.0.10 h1:uWiheaLgLcNFqHcdWveum7PQfMnIUTf9Kl3bFxrIoew=
|
github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52 h1:gAQliwn+zJrkjAHVcBEYW/RFvd2St4yYimisvozAYlA=
|
||||||
github.com/tdewolff/test v1.0.10/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
|
github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
|
||||||
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
||||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||||
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
||||||
|
|
Loading…
Reference in New Issue
Block a user