use crate::client::Client;
use crate::criteria::CritUpstreamNode;
use crate::ifs::jay_client_trace::JayClientTrace;
use crate::leaks::Tracker;
use crate::object::BreakLoops;
use crate::object::Version;
use crate::utils::copyhashmap::CopyHashMap;
use crate::wire::JayClientTraceId;
use crate::wire::JayGlobalTracerId;
use crate::wire::jay_global_tracer::*;
use jay_proc::Object;
use std::convert::Infallible;
use std::rc::Rc;
#[derive(Default)]
pub struct GlobalTracers {
ids: GlobalTracerIds,
map: CopyHashMap<GlobalTracerId, Rc<JayGlobalTracer>>,
}
linear_ids!(GlobalTracerIds, GlobalTracerId, u64);
#[derive(Object)]
#[break_loops]
pub struct JayGlobalTracer {
id: JayGlobalTracerId,
tracer_id: GlobalTracerId,
client: Rc<Client>,
tracker: Tracker<Self>,
version: Version,
m: Rc<dyn CritUpstreamNode<Rc<Client>>>,
}
impl GlobalTracers {
pub fn clear(&self) {
self.map.clear();
}
pub fn announce(&self, client: &Rc<Client>) {
for v in self.map.lock().values() {
v.announce_client(client);
}
}
}
impl JayGlobalTracer {
pub fn install(
id: JayGlobalTracerId,
client: &Rc<Client>,
m: &Rc<dyn CritUpstreamNode<Rc<Client>>>,
version: Version,
) {
let state = &client.state;
let slf = Rc::new(JayGlobalTracer {
id,
tracer_id: state.global_tracers.ids.next(),
client: client.clone(),
tracker: Default::default(),
version,
m: m.clone(),
});
track!(client, slf);
client.add_client_obj(&slf);
state.global_tracers.map.set(slf.tracer_id, slf.clone());
let clients: Vec<_> = state
.clients
.clients
.borrow()
.values()
.map(|c| &c.data)
.filter(|c| slf.m.pull(c))
.cloned()
.collect();
for client in &clients {
slf.announce_client_unchecked(client);
}
}
fn announce_client(&self, target: &Rc<Client>) {
if !self.m.pull(target) {
return;
}
self.announce_client_unchecked(target);
}
fn announce_client_unchecked(&self, target: &Rc<Client>) {
let id = self.client.new_id(self);
self.send_client_trace(id);
JayClientTrace::install(id, &self.client, Some(target), self.version, true);
}
fn send_stopped(&self) {
self.client.event(Stopped { self_id: self.id });
}
fn send_client_trace(&self, id: JayClientTraceId) {
self.client.event(ClientTrace {
self_id: self.id,
id,
});
}
fn detach(&self) {
self.client.state.global_tracers.map.remove(&self.tracer_id);
}
}
impl JayGlobalTracerRequestHandler for JayGlobalTracer {
type Error = Infallible;
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.detach();
self.client.remove_obj(self);
Ok(())
}
fn stop(&self, _req: Stop, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.detach();
self.send_stopped();
Ok(())
}
}
impl BreakLoops for JayGlobalTracer {
fn break_loops(self: Rc<Self>) {
self.detach();
}
}