@@ -21,7 +21,7 @@ type Handler func(c *Context) error
2121
2222// Predicate reports whether a Handler should run for an update. A Handler runs
2323// only if all of its predicates return true.
24- type Predicate func (u * Update ) bool
24+ type Predicate func (c * Context ) bool
2525
2626// Middleware wraps a Handler, returning a new one. Middleware registered with
2727// Bot.Use runs for every handled update, outermost first.
@@ -33,9 +33,9 @@ type route struct {
3333 mws []Middleware
3434}
3535
36- func (r route ) matches (u * Update ) bool {
36+ func (r route ) matches (c * Context ) bool {
3737 for _ , p := range r .predicates {
38- if ! p (u ) {
38+ if ! p (c ) {
3939 return false
4040 }
4141 }
@@ -49,6 +49,7 @@ type router struct {
4949 mu sync.RWMutex
5050 routes []route
5151 mws []Middleware
52+ preMws []Middleware
5253}
5354
5455// Use registers global middleware applied to every handled update. Middleware
@@ -60,6 +61,16 @@ func (b *Bot) Use(mws ...Middleware) {
6061 b .router .mws = append (b .router .mws , mws ... )
6162}
6263
64+ // UseOuter registers global middleware applied to every update BEFORE route matching.
65+ // This is the outermost layer of the pipeline, useful for logging, recovery, and tracing.
66+ // Middleware runs outermost-first in registration order. Call before Run.
67+ func (b * Bot ) UseOuter (mws ... Middleware ) {
68+ b .router .mu .Lock ()
69+ defer b .router .mu .Unlock ()
70+
71+ b .router .preMws = append (b .router .preMws , mws ... )
72+ }
73+
6374// on registers a handler guarded by the given predicates.
6475func (b * Bot ) on (handler Handler , predicates ... Predicate ) {
6576 b .onWith (handler , nil , predicates )
@@ -82,31 +93,41 @@ func (b *Bot) route(ctx context.Context, u *Update) {
8293 u .botUsername = b .self .Username
8394 }
8495
96+ c := & Context {Context : ctx , Bot : b , Update : u }
97+
8598 b .router .mu .RLock ()
8699
100+ preMws := b .router .preMws
87101 routes := b .router .routes
88102 mws := b .router .mws
89103 b .router .mu .RUnlock ()
90104
91- for _ , r := range routes {
92- if ! r .matches (u ) {
93- continue
94- }
105+ var routingHandler Handler = func (c * Context ) error {
106+ for _ , r := range routes {
107+ if ! r .matches (c ) {
108+ continue
109+ }
95110
96- h := r .handler
97- for i := len (r .mws ) - 1 ; i >= 0 ; i -- {
98- h = r.mws [i ](h )
99- }
111+ h := r .handler
112+ for i := len (r .mws ) - 1 ; i >= 0 ; i -- {
113+ h = r.mws [i ](h )
114+ }
100115
101- for i := len (mws ) - 1 ; i >= 0 ; i -- {
102- h = mws [i ](h )
103- }
116+ for i := len (mws ) - 1 ; i >= 0 ; i -- {
117+ h = mws [i ](h )
118+ }
104119
105- c := & Context {Context : ctx , Bot : b , Update : u }
106- if err := h (c ); err != nil {
107- b .logger ().Error (ctx , "Handler error" , log .Error (err ))
120+ return h (c )
108121 }
109122
110- return
123+ return nil
124+ }
125+
126+ for i := len (preMws ) - 1 ; i >= 0 ; i -- {
127+ routingHandler = preMws [i ](routingHandler )
128+ }
129+
130+ if err := routingHandler (c ); err != nil {
131+ b .logger ().Error (c .Context , "Pipeline error" , log .Error (err ))
111132 }
112133}
0 commit comments