135 lines
2.9 KiB
Go
135 lines
2.9 KiB
Go
package leaf
|
|
|
|
import (
|
|
"context"
|
|
"github.com/eclipse/paho.golang/paho"
|
|
"math"
|
|
)
|
|
|
|
// abortIndex represents a typical value used in abort functions.
|
|
const abortIndex int8 = math.MaxInt8 >> 1
|
|
|
|
type endKeyType = string
|
|
|
|
const EndKey endKeyType = "end"
|
|
|
|
type EndType int
|
|
|
|
const (
|
|
EndTimer EndType = iota + 1
|
|
EndStop
|
|
)
|
|
|
|
type KeyValue struct {
|
|
parent *KeyValue
|
|
key any
|
|
value any
|
|
}
|
|
|
|
var rootKeyType = &KeyValue{}
|
|
|
|
type Context struct {
|
|
context.Context
|
|
*paho.Publish
|
|
engine *Engine
|
|
|
|
index int8
|
|
handlers HandlersChain
|
|
|
|
value *KeyValue
|
|
}
|
|
|
|
func WithLeafContext(c context.Context, p *paho.Publish, engine *Engine, handlers HandlersChain) *Context {
|
|
return &Context{
|
|
Context: c,
|
|
Publish: p,
|
|
engine: engine,
|
|
index: -1,
|
|
handlers: handlers,
|
|
value: rootKeyType,
|
|
}
|
|
}
|
|
|
|
// HandlerName returns the main handler's name. For example if the handler is "handleGetUsers()",
|
|
// this function will return "main.handleGetUsers".
|
|
func (c *Context) HandlerName() string {
|
|
return nameOfFunction(c.handlers.Last())
|
|
}
|
|
|
|
// HandlerNames returns a list of all registered handlers for this context in descending order,
|
|
// following the semantics of HandlerName()
|
|
func (c *Context) HandlerNames() []string {
|
|
hn := make([]string, 0, len(c.handlers))
|
|
for _, val := range c.handlers {
|
|
if val == nil {
|
|
continue
|
|
}
|
|
hn = append(hn, nameOfFunction(val))
|
|
}
|
|
return hn
|
|
}
|
|
|
|
// Handler returns the main handler.
|
|
func (c *Context) Handler() HandlerFunc {
|
|
return c.handlers.Last()
|
|
}
|
|
|
|
/************************************/
|
|
/*********** FLOW CONTROL ***********/
|
|
/************************************/
|
|
|
|
// Next should be used only inside middleware.
|
|
// It executes the pending handlers in the chain inside the calling handler.
|
|
// See example in GitHub.
|
|
func (c *Context) Next() {
|
|
c.index++
|
|
for c.index < int8(len(c.handlers)) {
|
|
if c.handlers[c.index] == nil {
|
|
continue
|
|
}
|
|
c.handlers[c.index](c)
|
|
c.index++
|
|
}
|
|
}
|
|
|
|
// IsAborted returns true if the current context was aborted.
|
|
func (c *Context) IsAborted() bool {
|
|
return c.index >= abortIndex
|
|
}
|
|
|
|
// Abort prevents pending handlers from being called. Note that this will not stop the current handler.
|
|
// Let's say you have an authorization middleware that validates that the current request is authorized.
|
|
// If the authorization fails (ex: the password does not match), call Abort to ensure the remaining handlers
|
|
// for this request are not called.
|
|
func (c *Context) Abort() {
|
|
c.index = abortIndex
|
|
}
|
|
|
|
func WithValue[T any](ctx *Context, k any, v T) {
|
|
ctx.value = &KeyValue{
|
|
parent: ctx.value,
|
|
key: k,
|
|
value: v,
|
|
}
|
|
}
|
|
|
|
func Value[T any](ctx *Context, k any) (v T) {
|
|
vo := ctx.value
|
|
for {
|
|
if vo.key == k {
|
|
v, _ = vo.value.(T)
|
|
break
|
|
} else if vo.parent == rootKeyType {
|
|
break
|
|
}
|
|
vo = vo.parent
|
|
}
|
|
return
|
|
}
|
|
|
|
func WithCancel(ctx *Context) context.CancelFunc {
|
|
c, cancel := context.WithCancel(ctx.Context)
|
|
ctx.Context = c
|
|
return cancel
|
|
}
|