#![allow(dead_code)]
use crate::Context;
use ockam_core::RelayMessage;
#[cfg(feature = "debugger")]
use ockam_core::{Address, Mailbox, Mailboxes};
#[cfg(feature = "debugger")]
use ockam_core::compat::{
collections::BTreeMap,
sync::{Arc, RwLock},
vec::Vec,
};
#[cfg(feature = "debugger")]
use core::{
mem::MaybeUninit,
sync::atomic::{AtomicU32, Ordering},
};
#[cfg(feature = "debugger")]
#[derive(Default)]
struct Debugger {
inherited_mb: Arc<RwLock<BTreeMap<Mailbox, Vec<Mailboxes>>>>,
incoming: Arc<RwLock<BTreeMap<Address, Vec<Address>>>>,
incoming_mb: Arc<RwLock<BTreeMap<Mailbox, Vec<Address>>>>,
outgoing: Arc<RwLock<BTreeMap<Address, Vec<Address>>>>,
}
#[cfg(feature = "debugger")]
#[allow(unsafe_code)]
fn instance() -> &'static Debugger {
static mut INSTANCE: MaybeUninit<Debugger> = MaybeUninit::uninit();
#[cfg(feature = "std")]
{
use std::sync::Once;
static ONCE: Once = Once::new();
ONCE.call_once(|| {
let instance = Debugger::default();
unsafe { INSTANCE.write(instance) };
});
}
#[cfg(not(feature = "std"))]
{
use ockam_core::compat::sync::Mutex;
static ONCE: Mutex<bool> = Mutex::new(true);
if let Ok(mut once) = ONCE.lock() {
if *once {
let instance = Debugger::default();
unsafe {
INSTANCE.write(instance);
}
*once = false;
}
} else {
panic!("Failed to acquire initialization lock for debugger");
}
}
unsafe { INSTANCE.assume_init_ref() }
}
pub fn log_incoming_message(_receiving_ctx: &Context, _relay_msg: &RelayMessage) {
#[cfg(feature = "debugger")]
{
static COUNTER: AtomicU32 = AtomicU32::new(0);
tracing::trace!(
"log_incoming_message #{:03}: {} -> {} ({})",
COUNTER.fetch_add(1, Ordering::Relaxed),
_relay_msg.source(), _relay_msg.destination(), _receiving_ctx.address(), );
match instance().incoming.write() {
Ok(mut incoming) => {
let source = _relay_msg.source().clone();
let destination = _relay_msg.destination().clone();
incoming
.entry(destination)
.or_insert_with(Vec::new)
.push(source);
}
Err(e) => {
tracing::error!("debugger panicked: {}", e);
panic!("log_incoming_message");
}
}
match instance().incoming_mb.write() {
Ok(mut incoming_mb) => {
let source = _relay_msg.source().clone();
let destination = _relay_msg.destination().clone();
if let Some(destination_mb) = _receiving_ctx.mailboxes().find_mailbox(&destination)
{
incoming_mb
.entry(destination_mb.clone())
.or_insert_with(Vec::new)
.push(source);
}
}
Err(e) => {
tracing::error!("debugger panicked: {}", e);
panic!("log_incoming_message");
}
}
}
}
pub fn log_outgoing_message(_sending_ctx: &Context, _relay_msg: &RelayMessage) {
#[cfg(feature = "debugger")]
{
static COUNTER: AtomicU32 = AtomicU32::new(0);
tracing::trace!(
"log_outgoing_message #{:03}: {} ({}) -> {}",
COUNTER.fetch_add(1, Ordering::Relaxed),
_relay_msg.source(), _sending_ctx.address(), _relay_msg.destination(), );
match instance().outgoing.write() {
Ok(mut outgoing) => {
let source = _relay_msg.source().clone();
let destination = _relay_msg.destination().clone();
outgoing
.entry(source)
.or_insert_with(Vec::new)
.push(destination);
}
Err(e) => {
tracing::error!("debugger panicked: {}", e);
panic!("log_incoming_message");
}
}
}
}
pub fn log_inherit_context(_tag: &str, _parent: &Context, _child: &Context) {
#[cfg(feature = "debugger")]
{
static COUNTER: AtomicU32 = AtomicU32::new(0);
tracing::trace!(
"log_inherit_context #{:03}\n{:?}\nBegat {}\n{:?}\n",
COUNTER.fetch_add(1, Ordering::Relaxed),
_parent.mailboxes(),
_tag,
_child.mailboxes(),
);
match instance().inherited_mb.write() {
Ok(mut inherited_mb) => {
let parent = _parent.mailboxes().main_mailbox().clone();
let children = _child.mailboxes().clone();
inherited_mb
.entry(parent)
.or_insert_with(Vec::new)
.push(children);
}
Err(e) => {
tracing::error!("debugger panicked: {}", e);
panic!("log_incoming_message");
}
}
}
}
pub fn _log_start_worker() {
#[cfg(feature = "debugger")]
{}
}
pub fn _log_start_processor() {
#[cfg(feature = "debugger")]
{}
}
#[cfg(all(feature = "debugger", feature = "std"))]
use ockam_core::compat::io::{self, BufWriter, Write};
#[cfg(all(feature = "debugger", feature = "std"))]
pub fn generate_graphs<W: Write>(w: &mut BufWriter<W>) -> io::Result<()> {
fn id(mailbox: &Mailbox) -> String {
mailbox.address().address().replace('.', "_")
}
fn write_mailbox<W: Write>(
w: &mut BufWriter<W>,
mailbox: &Mailbox,
tag: &str,
) -> io::Result<()> {
write!(
w,
" {}{} [label=\"{{ {} | in: {:?} | out: {:?} }} \"]",
tag,
id(mailbox),
mailbox.address(),
mailbox.incoming_access_control(),
mailbox.outgoing_access_control(),
)?;
writeln!(w)?;
Ok(())
}
use ockam_core::compat::collections::BTreeSet;
let mut mailboxes = BTreeSet::new();
if let Ok(inherited_mb) = instance().inherited_mb.read() {
for (parent, children) in inherited_mb.iter() {
for child in children.iter() {
mailboxes.insert(parent.clone());
mailboxes.insert(child.main_mailbox().clone());
for mailbox in child.additional_mailboxes().iter() {
mailboxes.insert(mailbox.clone());
}
}
}
}
writeln!(w, "digraph ockam_node {{")?;
writeln!(w, " fontname=Arial;")?;
writeln!(w, " rankdir=TB;")?;
writeln!(w, " subgraph cluster_Inheritance {{")?;
writeln!(w, " label=\"Inheritance\";")?;
writeln!(w, " fontsize=24.0;")?;
writeln!(w, " labelloc=\"t\";")?;
writeln!(w, " rankdir=TB;")?;
writeln!(w, " edge [fillcolor=\"#a6cee3\"];")?;
writeln!(w, " edge [color=\"#1f78b4\"];")?;
writeln!(w, " node [shape=record];")?;
writeln!(w, " node [fontname=Arial];")?;
writeln!(w, " node [fontsize=12.0];")?;
for mailbox in mailboxes.iter() {
write_mailbox(w, mailbox, "")?;
}
match instance().inherited_mb.read() {
Ok(inherited_mb) => {
for (parent, children) in inherited_mb.iter() {
for child in children.iter() {
let mut child_ids = vec![id(child.main_mailbox())];
for mailbox in child.additional_mailboxes().iter() {
let child_id = id(mailbox);
child_ids.push(child_id);
}
for child_id in child_ids.iter() {
writeln!(w, " {} -> {};", id(parent), child_id,)?;
}
}
}
}
Err(e) => {
tracing::error!("debugger panicked: {}", e);
panic!("display_log");
}
}
writeln!(w, " }}\n")?;
writeln!(w, " subgraph cluster_MessageFlow {{")?;
writeln!(w, " label=\"MessageFlow\";")?;
writeln!(w, " fontsize=24.0;")?;
writeln!(w, " fontname=Arial;")?;
writeln!(w, " labelloc=\"t\";")?;
writeln!(w, " rankdir=TB;")?;
writeln!(w, " edge [fillcolor=\"#a60000\"];")?;
writeln!(w, " edge [color=\"#1f0000\"];")?;
writeln!(w, " node [shape=Mrecord];")?;
writeln!(w, " node [fontname=Arial];")?;
writeln!(w, " node [fontsize=12.0];")?;
for mailbox in mailboxes.iter() {
write_mailbox(w, mailbox, "MF_")?;
}
match instance().incoming_mb.read() {
Ok(incoming_mb) => {
for (destination, sources) in incoming_mb.iter() {
let mut sources = sources.clone();
sources.sort();
sources.dedup();
for source in sources.iter() {
writeln!(
w,
" MF_{} -> MF_{};",
source.address().replace('.', "_"),
id(destination),
)?;
}
}
}
Err(e) => {
tracing::error!("debugger panicked: {}", e);
panic!("display_log");
}
}
writeln!(w, " }}")?;
writeln!(w, "}}")?;
w.flush()?;
Ok(())
}
#[cfg(feature = "debugger")]
pub fn display_log() {
tracing::info!("======================================================================");
tracing::info!(" Contexts Inherited");
tracing::info!("----------------------------------------------------------------------");
match instance().inherited_mb.read() {
Ok(inherited_mb) => {
for (parent, children) in inherited_mb.iter() {
tracing::info!("{:?}", parent);
for child in children.iter() {
tracing::info!(" => {:?}", child);
}
}
}
Err(e) => {
tracing::error!("debugger panicked: {}", e);
panic!("display_log");
}
}
tracing::info!("----------------------------------------------------------------------");
tracing::info!(" Incoming Messages Received");
tracing::info!("----------------------------------------------------------------------");
match instance().incoming_mb.read() {
Ok(incoming_mb) => {
for (destination, sources) in incoming_mb.iter() {
tracing::info!("{:?}", destination);
let mut sources = sources.clone();
sources.sort();
sources.dedup();
for source in sources.iter() {
tracing::info!(" <= {:?}", source);
}
}
}
Err(e) => {
tracing::error!("debugger panicked: {}", e);
panic!("display_log");
}
}
}