use crate::filters::core::Filter;
use std::future::Future;
use std::pin::Pin;
use std::sync::{Arc, LazyLock};
use super::core::BoxFilter;
#[cfg(feature = "fsm")]
use crate::fsm::{FsmState, StateContext, StateKey, StateKeyStrategy, StateStorage};
use crate::middleware::{BoxFuture, DispatchResult, Middleware, Next, PanicRecoveryMiddleware};
use crate::update::{CallbackQuery, IncomingMessage, InlineQuery, InlineSend, Update};
type MsgFuture = Pin<Box<dyn Future<Output = ()> + Send + 'static>>;
type HandlerFn = Arc<dyn Fn(IncomingMessage) -> MsgFuture + Send + Sync + 'static>;
type CallbackHandlerFn = Arc<dyn Fn(CallbackQuery) -> MsgFuture + Send + Sync + 'static>;
type InlineQueryHandlerFn = Arc<dyn Fn(InlineQuery) -> MsgFuture + Send + Sync + 'static>;
type InlineSendHandlerFn = Arc<dyn Fn(InlineSend) -> MsgFuture + Send + Sync + 'static>;
#[cfg(feature = "fsm")]
type FsmHandlerFn = Arc<dyn Fn(IncomingMessage, StateContext) -> MsgFuture + Send + Sync + 'static>;
#[cfg(feature = "fsm")]
type FsmCallbackHandlerFn =
Arc<dyn Fn(CallbackQuery, StateContext) -> MsgFuture + Send + Sync + 'static>;
#[derive(Clone)]
pub(crate) struct MessageHandler {
filter: BoxFilter,
handler: HandlerFn,
}
#[derive(Clone)]
pub(crate) struct CallbackHandler {
filter: BoxFilter<CallbackQuery>,
handler: CallbackHandlerFn,
}
#[derive(Clone)]
pub(crate) struct InlineQueryHandler {
filter: BoxFilter<InlineQuery>,
handler: InlineQueryHandlerFn,
}
#[derive(Clone)]
pub(crate) struct InlineSendHandler {
filter: BoxFilter<InlineSend>,
handler: InlineSendHandlerFn,
}
#[cfg(feature = "fsm")]
#[derive(Clone)]
pub(crate) struct FsmMessageHandler {
filter: BoxFilter,
expected_state: String,
handler: FsmHandlerFn,
}
#[cfg(feature = "fsm")]
#[derive(Clone)]
pub(crate) struct FsmCallbackHandler {
filter: BoxFilter<CallbackQuery>,
expected_state: String,
handler: FsmCallbackHandlerFn,
}
static EMPTY_CALLBACK: LazyLock<Arc<Vec<CallbackHandler>>> = LazyLock::new(|| Arc::new(Vec::new()));
static EMPTY_INLINE_QUERY: LazyLock<Arc<Vec<InlineQueryHandler>>> =
LazyLock::new(|| Arc::new(Vec::new()));
static EMPTY_INLINE_SEND: LazyLock<Arc<Vec<InlineSendHandler>>> =
LazyLock::new(|| Arc::new(Vec::new()));
#[cfg(feature = "fsm")]
static EMPTY_FSM_CALLBACK: LazyLock<Arc<Vec<FsmCallbackHandler>>> =
LazyLock::new(|| Arc::new(Vec::new()));
fn snapshot<T: Clone>(handlers: &[T], empty: &Arc<Vec<T>>) -> Arc<Vec<T>> {
if handlers.is_empty() {
Arc::clone(empty)
} else {
Arc::new(handlers.to_vec())
}
}
pub struct Router {
scope: Option<BoxFilter>,
new_msg: Vec<MessageHandler>,
edited_msg: Vec<MessageHandler>,
callback_query: Vec<CallbackHandler>,
inline_query: Vec<InlineQueryHandler>,
inline_send: Vec<InlineSendHandler>,
#[cfg(feature = "fsm")]
fsm_new_msg: Vec<FsmMessageHandler>,
#[cfg(feature = "fsm")]
fsm_edited_msg: Vec<FsmMessageHandler>,
#[cfg(feature = "fsm")]
fsm_callback_query: Vec<FsmCallbackHandler>,
children: Vec<Router>,
}
impl Router {
pub fn new() -> Self {
Self {
scope: None,
new_msg: Vec::new(),
edited_msg: Vec::new(),
callback_query: Vec::new(),
inline_query: Vec::new(),
inline_send: Vec::new(),
#[cfg(feature = "fsm")]
fsm_new_msg: Vec::new(),
#[cfg(feature = "fsm")]
fsm_edited_msg: Vec::new(),
#[cfg(feature = "fsm")]
fsm_callback_query: Vec::new(),
children: Vec::new(),
}
}
pub fn scope(mut self, filter: BoxFilter) -> Self {
self.scope = Some(filter);
self
}
pub fn on_message<H, Fut>(&mut self, filter: BoxFilter, handler: H)
where
H: Fn(IncomingMessage) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
let hfn: HandlerFn = Arc::new(move |msg| Box::pin(handler(msg)) as MsgFuture);
self.new_msg.push(MessageHandler {
filter,
handler: hfn,
});
}
pub fn on_edit<H, Fut>(&mut self, filter: BoxFilter, handler: H)
where
H: Fn(IncomingMessage) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
let hfn: HandlerFn = Arc::new(move |msg| Box::pin(handler(msg)) as MsgFuture);
self.edited_msg.push(MessageHandler {
filter,
handler: hfn,
});
}
pub fn on_callback_query<H, Fut>(&mut self, filter: BoxFilter<CallbackQuery>, handler: H)
where
H: Fn(CallbackQuery) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
let hfn: CallbackHandlerFn = Arc::new(move |cb| Box::pin(handler(cb)) as MsgFuture);
self.callback_query.push(CallbackHandler {
filter,
handler: hfn,
});
}
pub fn on_inline_query<H, Fut>(&mut self, filter: BoxFilter<InlineQuery>, handler: H)
where
H: Fn(InlineQuery) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
let hfn: InlineQueryHandlerFn = Arc::new(move |iq| Box::pin(handler(iq)) as MsgFuture);
self.inline_query.push(InlineQueryHandler {
filter,
handler: hfn,
});
}
pub fn on_inline_send<H, Fut>(&mut self, filter: BoxFilter<InlineSend>, handler: H)
where
H: Fn(InlineSend) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
let hfn: InlineSendHandlerFn = Arc::new(move |is| Box::pin(handler(is)) as MsgFuture);
self.inline_send.push(InlineSendHandler {
filter,
handler: hfn,
});
}
#[cfg(feature = "fsm")]
pub fn on_message_fsm<S, H, Fut>(&mut self, filter: BoxFilter, state: S, handler: H)
where
S: FsmState,
H: Fn(IncomingMessage, StateContext) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
let expected_state = state.as_key();
let hfn: FsmHandlerFn = Arc::new(move |msg, ctx| Box::pin(handler(msg, ctx)) as MsgFuture);
self.fsm_new_msg.push(FsmMessageHandler {
filter,
expected_state,
handler: hfn,
});
}
#[cfg(feature = "fsm")]
pub fn on_edit_fsm<S, H, Fut>(&mut self, filter: BoxFilter, state: S, handler: H)
where
S: FsmState,
H: Fn(IncomingMessage, StateContext) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
let expected_state = state.as_key();
let hfn: FsmHandlerFn = Arc::new(move |msg, ctx| Box::pin(handler(msg, ctx)) as MsgFuture);
self.fsm_edited_msg.push(FsmMessageHandler {
filter,
expected_state,
handler: hfn,
});
}
#[cfg(feature = "fsm")]
pub fn on_callback_query_fsm<S, H, Fut>(
&mut self,
filter: BoxFilter<CallbackQuery>,
state: S,
handler: H,
) where
S: FsmState,
H: Fn(CallbackQuery, StateContext) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
let expected_state = state.as_key();
let hfn: FsmCallbackHandlerFn =
Arc::new(move |cb, ctx| Box::pin(handler(cb, ctx)) as MsgFuture);
self.fsm_callback_query.push(FsmCallbackHandler {
filter,
expected_state,
handler: hfn,
});
}
pub fn include(&mut self, router: Router) {
self.children.push(router);
}
pub(crate) fn flatten(self, parent_scope: Option<BoxFilter>) -> FlatHandlers {
let combined_scope = combine_scopes(parent_scope, self.scope);
let mut flat = FlatHandlers::default();
for h in self.new_msg {
flat.new_msg.push(scoped(h, combined_scope.as_ref()));
}
for h in self.edited_msg {
flat.edited_msg.push(scoped(h, combined_scope.as_ref()));
}
flat.callback_query.extend(self.callback_query);
flat.inline_query.extend(self.inline_query);
flat.inline_send.extend(self.inline_send);
#[cfg(feature = "fsm")]
for h in self.fsm_new_msg {
flat.fsm_new_msg
.push(scoped_fsm(h, combined_scope.as_ref()));
}
#[cfg(feature = "fsm")]
for h in self.fsm_edited_msg {
flat.fsm_edited_msg
.push(scoped_fsm(h, combined_scope.as_ref()));
}
#[cfg(feature = "fsm")]
flat.fsm_callback_query.extend(self.fsm_callback_query);
for child in self.children {
let child_flat = child.flatten(combined_scope.clone());
flat.new_msg.extend(child_flat.new_msg);
flat.edited_msg.extend(child_flat.edited_msg);
flat.callback_query.extend(child_flat.callback_query);
flat.inline_query.extend(child_flat.inline_query);
flat.inline_send.extend(child_flat.inline_send);
#[cfg(feature = "fsm")]
flat.fsm_new_msg.extend(child_flat.fsm_new_msg);
#[cfg(feature = "fsm")]
flat.fsm_edited_msg.extend(child_flat.fsm_edited_msg);
#[cfg(feature = "fsm")]
flat.fsm_callback_query
.extend(child_flat.fsm_callback_query);
}
flat
}
}
fn combine_scopes(parent: Option<BoxFilter>, own: Option<BoxFilter>) -> Option<BoxFilter> {
match (parent, own) {
(Some(p), Some(s)) => Some(p & s),
(Some(p), None) | (None, Some(p)) => Some(p),
(None, None) => None,
}
}
fn scoped(h: MessageHandler, scope: Option<&BoxFilter>) -> MessageHandler {
match scope {
Some(s) => MessageHandler {
filter: s.clone() & h.filter,
handler: h.handler,
},
None => h,
}
}
#[cfg(feature = "fsm")]
fn scoped_fsm(h: FsmMessageHandler, scope: Option<&BoxFilter>) -> FsmMessageHandler {
match scope {
Some(s) => FsmMessageHandler {
filter: s.clone() & h.filter,
..h
},
None => h,
}
}
impl Default for Router {
fn default() -> Self {
Self::new()
}
}
#[derive(Default)]
pub(crate) struct FlatHandlers {
pub new_msg: Vec<MessageHandler>,
pub edited_msg: Vec<MessageHandler>,
pub callback_query: Vec<CallbackHandler>,
pub inline_query: Vec<InlineQueryHandler>,
pub inline_send: Vec<InlineSendHandler>,
#[cfg(feature = "fsm")]
pub fsm_new_msg: Vec<FsmMessageHandler>,
#[cfg(feature = "fsm")]
pub fsm_edited_msg: Vec<FsmMessageHandler>,
#[cfg(feature = "fsm")]
pub fsm_callback_query: Vec<FsmCallbackHandler>,
}
pub struct Dispatcher {
new_msg: Vec<MessageHandler>,
edited_msg: Vec<MessageHandler>,
callback_query: Vec<CallbackHandler>,
inline_query: Vec<InlineQueryHandler>,
inline_send: Vec<InlineSendHandler>,
#[cfg(feature = "fsm")]
fsm_new_msg: Vec<FsmMessageHandler>,
#[cfg(feature = "fsm")]
fsm_edited_msg: Vec<FsmMessageHandler>,
#[cfg(feature = "fsm")]
fsm_callback_query: Vec<FsmCallbackHandler>,
middlewares: Vec<Arc<dyn Middleware>>,
#[cfg(feature = "fsm")]
state_storage: Option<Arc<dyn StateStorage>>,
#[cfg(feature = "fsm")]
key_strategy: StateKeyStrategy,
}
impl Dispatcher {
pub fn new() -> Self {
Self {
new_msg: Vec::new(),
edited_msg: Vec::new(),
callback_query: Vec::new(),
inline_query: Vec::new(),
inline_send: Vec::new(),
#[cfg(feature = "fsm")]
fsm_new_msg: Vec::new(),
#[cfg(feature = "fsm")]
fsm_edited_msg: Vec::new(),
#[cfg(feature = "fsm")]
fsm_callback_query: Vec::new(),
middlewares: vec![Arc::new(PanicRecoveryMiddleware::new())],
#[cfg(feature = "fsm")]
state_storage: None,
#[cfg(feature = "fsm")]
key_strategy: StateKeyStrategy::default(),
}
}
pub fn middleware(&mut self, mw: impl Middleware) {
self.middlewares.push(Arc::new(mw));
}
#[cfg(feature = "fsm")]
pub fn with_state_storage(&mut self, storage: Arc<dyn StateStorage>) {
self.state_storage = Some(storage);
}
#[cfg(feature = "fsm")]
pub fn with_key_strategy(&mut self, strategy: StateKeyStrategy) {
self.key_strategy = strategy;
}
pub fn on_message<H, Fut>(&mut self, filter: BoxFilter, handler: H)
where
H: Fn(IncomingMessage) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
let hfn: HandlerFn = Arc::new(move |msg| Box::pin(handler(msg)) as MsgFuture);
self.new_msg.push(MessageHandler {
filter,
handler: hfn,
});
}
pub fn on_edit<H, Fut>(&mut self, filter: BoxFilter, handler: H)
where
H: Fn(IncomingMessage) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
let hfn: HandlerFn = Arc::new(move |msg| Box::pin(handler(msg)) as MsgFuture);
self.edited_msg.push(MessageHandler {
filter,
handler: hfn,
});
}
pub fn on_callback_query<H, Fut>(&mut self, filter: BoxFilter<CallbackQuery>, handler: H)
where
H: Fn(CallbackQuery) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
let hfn: CallbackHandlerFn = Arc::new(move |cb| Box::pin(handler(cb)) as MsgFuture);
self.callback_query.push(CallbackHandler {
filter,
handler: hfn,
});
}
pub fn on_inline_query<H, Fut>(&mut self, filter: BoxFilter<InlineQuery>, handler: H)
where
H: Fn(InlineQuery) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
let hfn: InlineQueryHandlerFn = Arc::new(move |iq| Box::pin(handler(iq)) as MsgFuture);
self.inline_query.push(InlineQueryHandler {
filter,
handler: hfn,
});
}
pub fn on_inline_send<H, Fut>(&mut self, filter: BoxFilter<InlineSend>, handler: H)
where
H: Fn(InlineSend) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
let hfn: InlineSendHandlerFn = Arc::new(move |is| Box::pin(handler(is)) as MsgFuture);
self.inline_send.push(InlineSendHandler {
filter,
handler: hfn,
});
}
#[cfg(feature = "fsm")]
pub fn on_message_fsm<S, H, Fut>(&mut self, filter: BoxFilter, state: S, handler: H)
where
S: FsmState,
H: Fn(IncomingMessage, StateContext) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
if self.state_storage.is_none() {
tracing::warn!(
"[ferogram::router] on_message_fsm handler registered but no StateStorage is set -- \
this handler will never fire. Call dp.with_state_storage(storage) before dispatching."
);
}
let expected_state = state.as_key();
let hfn: FsmHandlerFn = Arc::new(move |msg, ctx| Box::pin(handler(msg, ctx)) as MsgFuture);
self.fsm_new_msg.push(FsmMessageHandler {
filter,
expected_state,
handler: hfn,
});
}
#[cfg(feature = "fsm")]
pub fn on_edit_fsm<S, H, Fut>(&mut self, filter: BoxFilter, state: S, handler: H)
where
S: FsmState,
H: Fn(IncomingMessage, StateContext) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
if self.state_storage.is_none() {
tracing::warn!(
"[ferogram::router] on_edit_fsm handler registered but no StateStorage is set -- \
this handler will never fire. Call dp.with_state_storage(storage) before dispatching."
);
}
let expected_state = state.as_key();
let hfn: FsmHandlerFn = Arc::new(move |msg, ctx| Box::pin(handler(msg, ctx)) as MsgFuture);
self.fsm_edited_msg.push(FsmMessageHandler {
filter,
expected_state,
handler: hfn,
});
}
#[cfg(feature = "fsm")]
pub fn on_callback_query_fsm<S, H, Fut>(
&mut self,
filter: BoxFilter<CallbackQuery>,
state: S,
handler: H,
) where
S: FsmState,
H: Fn(CallbackQuery, StateContext) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
if self.state_storage.is_none() {
tracing::warn!(
"[ferogram::router] on_callback_query_fsm handler registered but no StateStorage is set -- \
this handler will never fire. Call dp.with_state_storage(storage) before dispatching."
);
}
let expected_state = state.as_key();
let hfn: FsmCallbackHandlerFn =
Arc::new(move |cb, ctx| Box::pin(handler(cb, ctx)) as MsgFuture);
self.fsm_callback_query.push(FsmCallbackHandler {
filter,
expected_state,
handler: hfn,
});
}
pub fn include(&mut self, router: Router) {
let flat = router.flatten(None);
self.new_msg.extend(flat.new_msg);
self.edited_msg.extend(flat.edited_msg);
self.callback_query.extend(flat.callback_query);
self.inline_query.extend(flat.inline_query);
self.inline_send.extend(flat.inline_send);
#[cfg(feature = "fsm")]
self.fsm_new_msg.extend(flat.fsm_new_msg);
#[cfg(feature = "fsm")]
self.fsm_edited_msg.extend(flat.fsm_edited_msg);
#[cfg(feature = "fsm")]
self.fsm_callback_query.extend(flat.fsm_callback_query);
}
pub async fn dispatch(&self, update: Update) {
let new_msg = Arc::new(self.new_msg.clone());
let edited_msg = Arc::new(self.edited_msg.clone());
let callback_query = snapshot(&self.callback_query, &EMPTY_CALLBACK);
let inline_query = snapshot(&self.inline_query, &EMPTY_INLINE_QUERY);
let inline_send = snapshot(&self.inline_send, &EMPTY_INLINE_SEND);
#[cfg(feature = "fsm")]
let fsm_new = Arc::new(self.fsm_new_msg.clone());
#[cfg(feature = "fsm")]
let fsm_edited = Arc::new(self.fsm_edited_msg.clone());
#[cfg(feature = "fsm")]
let fsm_callback = snapshot(&self.fsm_callback_query, &EMPTY_FSM_CALLBACK);
#[cfg(feature = "fsm")]
let storage = self.state_storage.clone();
#[cfg(feature = "fsm")]
let strategy = self.key_strategy;
let endpoint: Arc<dyn Fn(Update) -> BoxFuture + Send + Sync> =
Arc::new(move |upd: Update| {
let new_msg = Arc::clone(&new_msg);
let edited_msg = Arc::clone(&edited_msg);
let callback_query = Arc::clone(&callback_query);
let inline_query = Arc::clone(&inline_query);
let inline_send = Arc::clone(&inline_send);
#[cfg(feature = "fsm")]
let fsm_new = Arc::clone(&fsm_new);
#[cfg(feature = "fsm")]
let fsm_edited = Arc::clone(&fsm_edited);
#[cfg(feature = "fsm")]
let fsm_callback = Arc::clone(&fsm_callback);
#[cfg(feature = "fsm")]
let storage = storage.clone();
Box::pin(async move {
dispatch_to_handlers(
upd,
&new_msg,
&edited_msg,
&callback_query,
&inline_query,
&inline_send,
#[cfg(feature = "fsm")]
&fsm_new,
#[cfg(feature = "fsm")]
&fsm_edited,
#[cfg(feature = "fsm")]
&fsm_callback,
#[cfg(feature = "fsm")]
storage,
#[cfg(feature = "fsm")]
strategy,
)
.await;
Ok(()) as DispatchResult
})
});
if self.middlewares.is_empty() {
if let Err(e) = (endpoint)(update).await {
tracing::error!(error = %e, "[ferogram::router] handler returned an error");
}
return;
}
let chain: Arc<[Arc<dyn Middleware>]> = self.middlewares.clone().into();
let next = Next::new(chain, endpoint);
if let Err(e) = next.run(update).await {
tracing::error!(error = %e, "[ferogram::router] handler returned an error");
}
}
}
impl Default for Dispatcher {
fn default() -> Self {
Self::new()
}
}
#[allow(clippy::too_many_arguments)]
async fn dispatch_to_handlers(
update: Update,
new_msg: &[MessageHandler],
edited_msg: &[MessageHandler],
callback_query: &[CallbackHandler],
inline_query: &[InlineQueryHandler],
inline_send: &[InlineSendHandler],
#[cfg(feature = "fsm")] fsm_new: &[FsmMessageHandler],
#[cfg(feature = "fsm")] fsm_edited: &[FsmMessageHandler],
#[cfg(feature = "fsm")] fsm_callback: &[FsmCallbackHandler],
#[cfg(feature = "fsm")] storage: Option<Arc<dyn StateStorage>>,
#[cfg(feature = "fsm")] strategy: StateKeyStrategy,
) {
match update {
Update::NewMessage(msg) => {
run_message(
msg,
new_msg,
#[cfg(feature = "fsm")]
fsm_new,
#[cfg(feature = "fsm")]
storage,
#[cfg(feature = "fsm")]
strategy,
)
.await;
}
Update::MessageEdited(msg) => {
run_message(
msg,
edited_msg,
#[cfg(feature = "fsm")]
fsm_edited,
#[cfg(feature = "fsm")]
storage,
#[cfg(feature = "fsm")]
strategy,
)
.await;
}
Update::CallbackQuery(cb) => {
run_callback(
cb,
callback_query,
#[cfg(feature = "fsm")]
fsm_callback,
#[cfg(feature = "fsm")]
storage,
#[cfg(feature = "fsm")]
strategy,
)
.await;
}
Update::InlineQuery(iq) => {
run_inline_query(iq, inline_query).await;
}
Update::InlineSend(is) => {
run_inline_send(is, inline_send).await;
}
_ => {}
}
}
async fn run_message(
msg: IncomingMessage,
regular: &[MessageHandler],
#[cfg(feature = "fsm")] fsm: &[FsmMessageHandler],
#[cfg(feature = "fsm")] storage: Option<Arc<dyn StateStorage>>,
#[cfg(feature = "fsm")] strategy: StateKeyStrategy,
) {
#[cfg(feature = "fsm")]
if let Some(ref arc_storage) = storage
&& !fsm.is_empty()
{
let key = StateKey::from_message(&msg, strategy);
let current_state = match arc_storage.get_state(key.clone()).await {
Ok(s) => s,
Err(e) => {
tracing::error!(error = %e, "[ferogram::router] FSM: state storage read failed; skipping FSM handlers for this update");
None
}
};
if let Some(ref current) = current_state {
let matched_idx = fsm
.iter()
.position(|h| h.expected_state == *current && h.filter.check(&msg));
if let Some(idx) = matched_idx {
let ctx = StateContext::new(Arc::clone(arc_storage), key, current.clone());
(fsm[idx].handler)(msg, ctx).await;
return;
}
}
}
let matched_idxs: Vec<usize> = regular
.iter()
.enumerate()
.filter(|(_, h)| h.filter.check(&msg))
.map(|(i, _)| i)
.collect();
if let Some((&last, rest)) = matched_idxs.split_last() {
for &idx in rest {
(regular[idx].handler)(msg.clone()).await;
}
(regular[last].handler)(msg).await;
}
}
async fn run_callback(
cb: CallbackQuery,
regular: &[CallbackHandler],
#[cfg(feature = "fsm")] fsm: &[FsmCallbackHandler],
#[cfg(feature = "fsm")] storage: Option<Arc<dyn StateStorage>>,
#[cfg(feature = "fsm")] strategy: StateKeyStrategy,
) {
#[cfg(feature = "fsm")]
if let Some(ref arc_storage) = storage
&& !fsm.is_empty()
{
let key = StateKey::from_message(&cb, strategy);
let current_state = match arc_storage.get_state(key.clone()).await {
Ok(s) => s,
Err(e) => {
tracing::error!(error = %e, "[ferogram::router] FSM: state storage read failed; skipping FSM handlers for this callback query");
None
}
};
if let Some(ref current) = current_state {
let matched_idx = fsm
.iter()
.position(|h| h.expected_state == *current && h.filter.check(&cb));
if let Some(idx) = matched_idx {
let ctx = StateContext::new(Arc::clone(arc_storage), key, current.clone());
(fsm[idx].handler)(cb, ctx).await;
return;
}
}
}
let matched_idxs: Vec<usize> = regular
.iter()
.enumerate()
.filter(|(_, h)| h.filter.check(&cb))
.map(|(i, _)| i)
.collect();
if let Some((&last, rest)) = matched_idxs.split_last() {
for &idx in rest {
(regular[idx].handler)(cb.clone()).await;
}
(regular[last].handler)(cb).await;
}
}
async fn run_inline_query(iq: InlineQuery, regular: &[InlineQueryHandler]) {
let matched_idxs: Vec<usize> = regular
.iter()
.enumerate()
.filter(|(_, h)| h.filter.check(&iq))
.map(|(i, _)| i)
.collect();
if let Some((&last, rest)) = matched_idxs.split_last() {
for &idx in rest {
(regular[idx].handler)(iq.clone()).await;
}
(regular[last].handler)(iq).await;
}
}
async fn run_inline_send(is: InlineSend, regular: &[InlineSendHandler]) {
let matched_idxs: Vec<usize> = regular
.iter()
.enumerate()
.filter(|(_, h)| h.filter.check(&is))
.map(|(i, _)| i)
.collect();
if let Some((&last, rest)) = matched_idxs.split_last() {
for &idx in rest {
(regular[idx].handler)(is.clone()).await;
}
(regular[last].handler)(is).await;
}
}