1use std::{collections::HashSet, io::BufRead};
2
3use holochain_types::prelude::*;
4use once_cell::sync::OnceCell;
5use tracing_subscriber::{prelude::__tracing_subscriber_SubscriberExt, util::SubscriberInitExt};
6
7use super::*;
8
9pub type ContextSubscriber = aitia::logging::AitiaSubscriber<Context>;
10
11pub type CtxError = String;
13pub type ContextResult<T> = Result<T, CtxError>;
14
15pub fn init_subscriber() -> ContextSubscriber {
16 let w = SUBSCRIBER.get_or_init(ContextSubscriber::default).clone();
17 let ww = w.clone();
18 tracing_subscriber::registry()
19 .with(holochain_trace::standard_layer(std::io::stderr).unwrap())
20 .with(aitia::logging::tracing_layer(move || ww.clone()))
21 .init();
22 w
23}
24
25pub static SUBSCRIBER: OnceCell<ContextSubscriber> = OnceCell::new();
26
27#[derive(Default, Debug)]
28pub struct Context {
29 pub facts: HashSet<Event>,
31
32 pub map_node_to_agents: HashMap<SleuthId, HashSet<AgentPubKey>>,
34
35 pub map_agent_to_node: HashMap<AgentPubKey, SleuthId>,
37
38 pub map_op_to_sysval_dep_hashes: HashMap<OpRef, Vec<ActionHash>>,
40
41 pub map_op_to_appval_dep_hash: HashMap<OpRef, HashSet<AnyDhtHash>>,
43
44 pub map_dep_hash_to_op: HashMap<AnyDhtHash, OpRef>,
46
47 pub map_action_to_op: HashMap<ChainOpAction, OpRef>,
49
50 pub op_info: HashMap<OpRef, OpInfo>,
52}
53
54impl Context {
55 pub fn from_file(mut r: impl BufRead) -> Self {
56 use aitia::logging::Log;
57 let mut la = Self::default();
58 let mut line = String::new();
59 while let Ok(_bytes) = r.read_line(&mut line) {
60 if let Some(fact) = Self::parse(&line) {
61 la.apply(fact);
62 }
63 }
64 la
65 }
66
67 pub fn check(&self, fact: &Event) -> bool {
68 self.facts.contains(fact)
69 }
70
71 pub fn node_agents(&self, id: &SleuthId) -> ContextResult<&HashSet<AgentPubKey>> {
72 self.map_node_to_agents
73 .get(id)
74 .ok_or(format!("node_agents({id})"))
75 }
76
77 pub fn agent_node(&self, agent: &AgentPubKey) -> ContextResult<&SleuthId> {
78 self.map_agent_to_node
79 .get(agent)
80 .ok_or(format!("agent_node({agent})"))
81 }
82
83 pub fn sysval_op_deps(&self, op: &OpRef) -> ContextResult<Vec<&OpInfo>> {
85 self.map_op_to_sysval_dep_hashes
86 .get(op)
87 .ok_or(format!("map_op_to_sysval_dep_hash({op})"))?
88 .iter()
89 .map(|h| {
90 self.map_dep_hash_to_op
91 .get(&h.clone().into())
92 .ok_or(format!("map_dep_hash_to_op({h})"))
93 .and_then(|d| self.op_info(d))
94 })
95 .collect::<Result<Vec<_>, _>>()
96 }
97
98 pub fn appval_op_deps(&self, op: &OpRef) -> ContextResult<HashSet<&OpInfo>> {
100 self.map_op_to_appval_dep_hash
101 .get(op)
102 .ok_or(format!("map_op_to_appval_dep_hash({op})"))?
103 .iter()
104 .map(|h| {
105 self.map_dep_hash_to_op
106 .get(h)
107 .ok_or(format!("map_dep_hash_to_op({h})"))
108 })
109 .collect::<Result<Vec<_>, _>>()?
110 .into_iter()
111 .map(|d| self.op_info(d))
112 .collect()
113 }
114
115 pub fn op_info(&self, op: &OpRef) -> ContextResult<&OpInfo> {
116 self.op_info.get(op).ok_or(format!("op_info({op})"))
117 }
118
119 pub fn op_from_action(&self, action: ActionHash, op_type: ChainOpType) -> ContextResult<OpRef> {
120 let oa = ChainOpAction(action, op_type);
121 self.map_action_to_op
122 .get(&oa)
123 .cloned()
124 .ok_or(format!("map_action_to_op({oa:?})"))
125 }
126
127 pub fn as_if(&mut self) {
128 todo!()
129 }
130
131 pub fn all_events_for_topic() {}
132}
133
134impl aitia::logging::Log for Context {
135 type Fact = Event;
136
137 fn apply(&mut self, fact: Event) {
138 match fact.clone() {
139 Event::Integrated { .. } => {}
140 Event::AppValidated { .. } => {}
141 Event::SysValidated { .. } => {}
142 Event::MissingAppValDep { by: _, op, deps } => {
143 self.map_op_to_appval_dep_hash
144 .entry(op)
145 .or_default()
146 .extend(deps);
147 }
148 Event::Fetched { .. } => {}
149 Event::ReceivedHash { .. } => {}
150 Event::SentHash { .. } => {}
151 Event::Authored { by: _, op } => {
152 let op_hash = op.as_hash();
154 let a = match &op.op {
155 DhtOpLite::Chain(op) => ChainOpAction::from((**op).clone()),
156 _ => unimplemented!("hc_sleuth can only handle chain ops"),
157 };
158 for h in op.fetch_dependency_hashes() {
159 self.map_dep_hash_to_op.insert(h, op_hash.clone());
160 }
161 self.map_action_to_op.insert(a, op_hash.clone());
162 self.map_op_to_sysval_dep_hashes
163 .insert(op_hash.clone(), op.dep.clone());
164 self.op_info.insert(op_hash.clone(), op);
165 }
166 Event::AgentJoined { node, agent } => {
167 self.map_agent_to_node.insert(agent.clone(), node.clone());
168 self.map_node_to_agents
169 .entry(node)
170 .or_default()
171 .insert(agent);
172 }
173 Event::SweetConductorShutdown { node } => {
174 if let Some(agents) = self.map_node_to_agents.remove(&node) {
175 for a in agents {
176 self.map_agent_to_node.remove(&a);
177 }
178 }
179 }
180 }
181 let duplicate = self.facts.insert(fact.clone());
182 if duplicate {
183 tracing::warn!("Duplicate fact {:?}", fact);
184 }
185 }
186}