Files
game-driver/leaf/context.go
2024-11-05 18:39:03 +08:00

142 lines
3.0 KiB
Go

package leaf
import (
"context"
"github.com/eclipse/paho.golang/paho"
"math"
"time"
)
// 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
}
func WithDeadline(ctx *Context, t time.Time) context.CancelFunc {
c, cancel := context.WithDeadline(ctx.Context, t)
ctx.Context = c
return cancel
}