use crate::{
dto::icrc21::{ConsentMessageRequest, ConsentMessageResponse, ErrorInfo, Icrc21Error},
log,
log::Topic,
};
use std::{cell::RefCell, collections::HashMap, sync::Arc};
thread_local! {
static ICRC_21_REGISTRY: RefCell<HashMap<String, RegisteredConsentHandler>> = RefCell::new(HashMap::new());
}
#[derive(Clone)]
struct RegisteredConsentHandler {
handler: Arc<dyn Fn(ConsentMessageRequest) -> ConsentMessageResponse + 'static>,
}
impl RegisteredConsentHandler {
fn new<F>(handler: F) -> Self
where
F: Fn(ConsentMessageRequest) -> ConsentMessageResponse + 'static,
{
Self {
handler: Arc::new(handler),
}
}
fn handle(&self, req: ConsentMessageRequest) -> ConsentMessageResponse {
self.handler.as_ref()(req)
}
}
pub struct Icrc21Dispatcher;
impl Icrc21Dispatcher {
pub fn register<F>(method: &str, handler: F)
where
F: Fn(ConsentMessageRequest) -> ConsentMessageResponse + 'static,
{
ICRC_21_REGISTRY.with_borrow_mut(|reg| {
let replaced = reg.insert(method.to_string(), RegisteredConsentHandler::new(handler));
if replaced.is_some() {
log!(
Topic::Icrc,
Warn,
"icrc21 handler replaced for method={method}"
);
}
});
}
#[must_use]
fn get_handler(method: &str) -> Option<RegisteredConsentHandler> {
ICRC_21_REGISTRY.with_borrow(|reg| reg.get(method).cloned())
}
#[must_use]
pub fn consent_message(req: ConsentMessageRequest) -> ConsentMessageResponse {
match Self::get_handler(&req.method) {
Some(handler) => handler.handle(req),
None => ConsentMessageResponse::Err(Icrc21Error::UnsupportedCanisterCall(ErrorInfo {
description: "No handler registered for this method.".to_string(),
})),
}
}
}