Add visualization stuff using GraphViz at /api/visualize

This commit is contained in:
Lucien Greathouse
2019-01-02 00:18:28 -08:00
parent a3cc39cd92
commit 9bf5bd11e2
3 changed files with 69 additions and 0 deletions

View File

@@ -18,5 +18,6 @@ pub mod rbx_session;
pub mod rbx_snapshot;
pub mod session;
pub mod session_id;
pub mod visualize_tree;
pub mod web;
pub mod web_util;

View File

@@ -0,0 +1,42 @@
use std::fmt;
use rbx_tree::{RbxTree, RbxId};
static GRAPHVIZ_HEADER: &str = r#"
digraph RojoTree {
rankdir = "LR";
graph [
ranksep = "0.7",
nodesep = "0.5",
];
node [
fontname = "Hack",
shape = "record",
];
"#;
pub struct VisualizeTree<'a>(pub &'a RbxTree);
impl<'a> fmt::Display for VisualizeTree<'a> {
fn fmt(&self, output: &mut fmt::Formatter) -> fmt::Result {
writeln!(output, "{}", GRAPHVIZ_HEADER)?;
visualize_node(self.0, self.0.get_root_id(), output)?;
writeln!(output, "}}")?;
Ok(())
}
}
fn visualize_node(tree: &RbxTree, id: RbxId, output: &mut fmt::Formatter) -> fmt::Result {
let node = tree.get_instance(id).unwrap();
writeln!(output, " \"{}\" [label=\"{}\"]", id, node.name)?;
for &child_id in node.get_children_ids() {
writeln!(output, " \"{}\" -> \"{}\"", id, child_id)?;
visualize_node(tree, child_id, output)?;
}
Ok(())
}

View File

@@ -1,6 +1,8 @@
use std::{
borrow::Cow,
collections::HashMap,
io::Write,
process::{Command, Stdio},
sync::{mpsc, Arc},
};
@@ -17,6 +19,7 @@ use crate::{
session_id::SessionId,
project::InstanceProjectNodeMetadata,
rbx_snapshot::InstanceChanges,
visualize_tree::VisualizeTree,
};
#[derive(Debug, Serialize, Deserialize)]
@@ -160,6 +163,29 @@ impl Server {
})
},
(GET) (/api/visualize) => {
let rbx_session = self.session.rbx_session.lock().unwrap();
let tree = rbx_session.get_tree();
let dot_source = format!("{}", VisualizeTree(tree));
let mut child = Command::new("dot")
.arg("-Tsvg")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.expect("Failed to spawn GraphViz process -- make sure it's installed in order to use /api/visualize");
{
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
stdin.write_all(dot_source.as_bytes()).expect("Failed to write to stdin");
}
let output = child.wait_with_output().expect("Failed to read stdout");
Response::svg(String::from_utf8_lossy(&output.stdout))
},
_ => Response::empty_404()
)
}