use crate::proto::{send_msg, Out};
use serde_json::{json, Value};
use std::collections::{HashMap, HashSet};
use std::sync::{Mutex, OnceLock};
struct Subscriber {
out: Out,
topics: HashSet<String>,
}
#[derive(Default)]
struct Broker {
next_id: u64,
subs: HashMap<u64, Subscriber>,
}
fn broker() -> &'static Mutex<Broker> {
static B: OnceLock<Mutex<Broker>> = OnceLock::new();
B.get_or_init(|| Mutex::new(Broker::default()))
}
pub fn register(out: &Out) -> u64 {
let mut b = broker().lock().unwrap();
b.next_id += 1;
let id = b.next_id;
b.subs.insert(
id,
Subscriber {
out: out.clone(),
topics: HashSet::new(),
},
);
id
}
pub fn unregister(id: u64) {
broker().lock().unwrap().subs.remove(&id);
}
pub fn subscribe(id: u64, topic: &str) {
if let Some(s) = broker().lock().unwrap().subs.get_mut(&id) {
s.topics.insert(topic.to_string());
}
}
pub fn unsubscribe(id: u64, topic: &str) {
if let Some(s) = broker().lock().unwrap().subs.get_mut(&id) {
s.topics.remove(topic);
}
}
pub fn send_one(out: &Out, topic: &str, data: &Value) {
let frame = json!({ "ev": "pub", "topic": topic, "data": data });
let _ = send_msg(out, &frame);
}
pub fn publish(topic: &str, data: &Value) -> usize {
let targets: Vec<Out> = {
let b = broker().lock().unwrap();
b.subs
.values()
.filter(|s| s.topics.contains(topic))
.map(|s| s.out.clone())
.collect()
};
let frame = json!({ "ev": "pub", "topic": topic, "data": data });
targets
.iter()
.filter(|out| send_msg(out, &frame).is_ok())
.count()
}