(new): rich message support
Golang lint / lint (pull_request) Successful in 1m20s
Golang lint / lint (push) Successful in 4m8s

(fix): runtime reliability
(tests): regression coverage
(doc): v1.1 release notes
This commit is contained in:
2026-08-12 16:34:44 +03:00
parent 48ddf66540
commit f03a081ed6
83 changed files with 6122 additions and 1925 deletions
+31 -1
View File
@@ -2,6 +2,7 @@ package laniakea
import (
"errors"
"fmt"
"git.scuroneko.dev/scuroneko/extypes"
"git.scuroneko.dev/scuroneko/laniakea/tgapi"
@@ -292,6 +293,9 @@ func (p *Plugin[T]) executeMiddlewares(ctx *MessageContext, db T) bool {
// If async, return value is ignored.
type MiddlewareExecutor[T AppData] func(ctx *MessageContext, db T) bool
// ErrMiddlewareExecutorNil reports an attempt to execute middleware without a callback.
var ErrMiddlewareExecutorNil = errors.New("middleware executor is nil")
// Middleware represents a reusable execution interceptor.
// Can be synchronous (blocking) or asynchronous (non-blocking).
type Middleware[T AppData] struct {
@@ -306,7 +310,7 @@ func NewMiddleware[T AppData](name string, executor MiddlewareExecutor[T]) Middl
return Middleware[T]{name, executor, 0, false}
}
// SetOrder sets the execution order (currently ignored).
// SetOrder sets the bot-level middleware execution order.
func (m Middleware[T]) SetOrder(order int) Middleware[T] {
m.order = order
return m
@@ -330,12 +334,38 @@ func (m Middleware[T]) SetAsync(async bool) Middleware[T] {
// must treat those fields as read-only — mutating them races the sync chain
// that mutates the same context concurrently.
func (m Middleware[T]) Execute(ctx *MessageContext, db T) bool {
if m.executor == nil {
reportMiddlewareError(ctx, m.name, ErrMiddlewareExecutorNil)
return false
}
if m.async {
ctxCopy := *ctx
go func(ctx MessageContext) {
defer func() {
if recovered := recover(); recovered != nil {
reportMiddlewareError(&ctx, m.name, fmt.Errorf("middleware %q panicked: %v", m.name, recovered))
}
}()
m.executor(&ctx, db)
}(ctxCopy)
return true
}
return m.executor(ctx, db)
}
func reportMiddlewareError(ctx *MessageContext, name string, err error) {
event := ErrorEvent{
Plugin: "bot",
HandlerKind: HandlerMiddlewareKind,
HandlerName: name,
Err: err,
UserFacing: false,
}
if ctx != nil {
event.UpdateID = ctx.Update.UpdateID
event.UpdateType = ctx.Update.Type
event.FromID = ctx.FromID
event.ChatID = ctx.ChatID
}
emitContextError(ctx, event)
}