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 ( End = iota EndTimeout 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() } // Hold 在当前中保留一个锚点,以便后续可以从此恢复后续处理程序。 func (c *Context) Hold() int8 { return c.index } // Resume 从 Hold 保留的锚点恢复后续处理程序。 func (c *Context) Resume(index int8) { c.index = index c.Next() } /************************************/ /*********** 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 (c *Context) Done() <-chan struct{} { return c.Context.Done() } 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 }