use std::{
collections::HashMap,
sync::{Arc, Mutex},
thread,
};
use crate::logger::tracing::debug;
use serde_json::Value;
use state::Container;
pub static APPLICATION_CONTEXT: Container![Send + Sync] = <Container![Send + Sync]>::new();
#[derive(Clone, Default)]
pub struct RpcContext {}
pub trait Context {
fn get_attachments() -> Option<Arc<Mutex<HashMap<String, Value>>>>;
}
impl Context for RpcContext {
fn get_attachments() -> Option<Arc<Mutex<HashMap<String, Value>>>> {
let local = APPLICATION_CONTEXT.try_get_local::<Arc<Mutex<HashMap<String, Value>>>>();
debug!("{:?} - {:?}", thread::current().id(), local);
match local {
Some(attachment) => Some(attachment.clone()),
None => {
let attachment = HashMap::<String, Value>::new();
let mutex = Arc::new(Mutex::new(attachment));
let mutex_clone = Arc::clone(&mutex);
APPLICATION_CONTEXT.set_local(move || {
return Arc::clone(&mutex_clone);
});
Some(Arc::clone(&mutex))
}
}
}
}
#[cfg(test)]
mod tests {
use tokio::time;
use super::*;
use std::time::Duration;
#[test]
fn context_with_thread_local() {
let rt = tokio::runtime::Builder::new_multi_thread()
.max_blocking_threads(2)
.enable_all()
.build()
.unwrap();
let mut handles = Vec::with_capacity(10);
for i in 0..=10 {
handles.push(rt.spawn(async move {
if let Some(attachments) = RpcContext::get_attachments() {
let mut attachments = attachments.lock().unwrap();
attachments.insert("key1".into(), Value::from(format!("data-{i}")));
assert!(attachments.len() > 0);
};
time::sleep(Duration::from_millis(1000)).await;
if let Some(attachments) = RpcContext::get_attachments() {
let attachments = attachments.lock().unwrap();
assert!(attachments.len() > 0);
};
}));
}
for handle in handles {
rt.block_on(handle).unwrap();
}
}
}