mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-04-24 06:35:39 +00:00
C:/Program Files/Git/api/visualize -> /visualize/rbx, added /visualize/imfs
This commit is contained in:
@@ -18,6 +18,6 @@ pub mod rbx_session;
|
|||||||
pub mod rbx_snapshot;
|
pub mod rbx_snapshot;
|
||||||
pub mod session;
|
pub mod session;
|
||||||
pub mod session_id;
|
pub mod session_id;
|
||||||
pub mod visualize_tree;
|
pub mod visualize;
|
||||||
pub mod web;
|
pub mod web;
|
||||||
pub mod web_util;
|
pub mod web_util;
|
||||||
@@ -18,6 +18,7 @@ pub struct Session {
|
|||||||
pub session_id: SessionId,
|
pub session_id: SessionId,
|
||||||
pub message_queue: Arc<MessageQueue<InstanceChanges>>,
|
pub message_queue: Arc<MessageQueue<InstanceChanges>>,
|
||||||
pub rbx_session: Arc<Mutex<RbxSession>>,
|
pub rbx_session: Arc<Mutex<RbxSession>>,
|
||||||
|
pub imfs: Arc<Mutex<Imfs>>,
|
||||||
_fs_watcher: FsWatcher,
|
_fs_watcher: FsWatcher,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,6 +51,7 @@ impl Session {
|
|||||||
session_id,
|
session_id,
|
||||||
message_queue,
|
message_queue,
|
||||||
rbx_session,
|
rbx_session,
|
||||||
|
imfs,
|
||||||
_fs_watcher: fs_watcher,
|
_fs_watcher: fs_watcher,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
128
server/src/visualize.rs
Normal file
128
server/src/visualize.rs
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
use std::{
|
||||||
|
fmt,
|
||||||
|
io::Write,
|
||||||
|
path::Path,
|
||||||
|
process::{Command, Stdio},
|
||||||
|
};
|
||||||
|
|
||||||
|
use rbx_tree::{RbxTree, RbxId};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
imfs::{Imfs, ImfsItem},
|
||||||
|
};
|
||||||
|
|
||||||
|
static GRAPHVIZ_HEADER: &str = r#"
|
||||||
|
digraph RojoTree {
|
||||||
|
rankdir = "LR";
|
||||||
|
graph [
|
||||||
|
ranksep = "0.7",
|
||||||
|
nodesep = "0.5",
|
||||||
|
];
|
||||||
|
node [
|
||||||
|
fontname = "Hack",
|
||||||
|
shape = "record",
|
||||||
|
];
|
||||||
|
"#;
|
||||||
|
|
||||||
|
pub fn graphviz_to_svg(source: &str) -> String {
|
||||||
|
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(source.as_bytes()).expect("Failed to write to stdin");
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = child.wait_with_output().expect("Failed to read stdout");
|
||||||
|
String::from_utf8(output.stdout).expect("Failed to parse stdout as UTF-8")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct VisualizeRbxTree<'a>(pub &'a RbxTree);
|
||||||
|
|
||||||
|
impl<'a> fmt::Display for VisualizeRbxTree<'a> {
|
||||||
|
fn fmt(&self, output: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
writeln!(output, "{}", GRAPHVIZ_HEADER)?;
|
||||||
|
|
||||||
|
visualize_rbx_node(self.0, self.0.get_root_id(), output)?;
|
||||||
|
|
||||||
|
writeln!(output, "}}")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visualize_rbx_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_rbx_node(tree, child_id, output)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct VisualizeImfs<'a>(pub &'a Imfs);
|
||||||
|
|
||||||
|
impl<'a> fmt::Display for VisualizeImfs<'a> {
|
||||||
|
fn fmt(&self, output: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
writeln!(output, "{}", GRAPHVIZ_HEADER)?;
|
||||||
|
|
||||||
|
for root_path in self.0.get_roots() {
|
||||||
|
visualize_root_path(self.0, root_path, output)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeln!(output, "}}")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normalize_name(path: &Path) -> String {
|
||||||
|
path.to_str().unwrap().replace("\\", "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visualize_root_path(imfs: &Imfs, path: &Path, output: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let normalized_name = normalize_name(path);
|
||||||
|
let item = imfs.get(path).unwrap();
|
||||||
|
|
||||||
|
writeln!(output, " \"{}\"", normalized_name)?;
|
||||||
|
|
||||||
|
match item {
|
||||||
|
ImfsItem::File(_) => {},
|
||||||
|
ImfsItem::Directory(directory) => {
|
||||||
|
for child_path in &directory.children {
|
||||||
|
writeln!(output, " \"{}\" -> \"{}\"", normalized_name, normalize_name(child_path))?;
|
||||||
|
visualize_path(imfs, child_path, output)?;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visualize_path(imfs: &Imfs, path: &Path, output: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let normalized_name = normalize_name(path);
|
||||||
|
let short_name = path.file_name().unwrap().to_string_lossy();
|
||||||
|
let item = imfs.get(path).unwrap();
|
||||||
|
|
||||||
|
writeln!(output, " \"{}\" [label = \"{}\"]", normalized_name, short_name)?;
|
||||||
|
|
||||||
|
match item {
|
||||||
|
ImfsItem::File(_) => {},
|
||||||
|
ImfsItem::Directory(directory) => {
|
||||||
|
for child_path in &directory.children {
|
||||||
|
writeln!(output, " \"{}\" -> \"{}\"", normalized_name, normalize_name(child_path))?;
|
||||||
|
visualize_path(imfs, child_path, output)?;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
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(())
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
io::Write,
|
|
||||||
process::{Command, Stdio},
|
|
||||||
sync::{mpsc, Arc},
|
sync::{mpsc, Arc},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -19,7 +17,7 @@ use crate::{
|
|||||||
session_id::SessionId,
|
session_id::SessionId,
|
||||||
project::InstanceProjectNodeMetadata,
|
project::InstanceProjectNodeMetadata,
|
||||||
rbx_snapshot::InstanceChanges,
|
rbx_snapshot::InstanceChanges,
|
||||||
visualize_tree::VisualizeTree,
|
visualize::{VisualizeRbxTree, VisualizeImfs, graphviz_to_svg},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
@@ -163,27 +161,21 @@ impl Server {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
(GET) (/api/visualize) => {
|
(GET) (/visualize/rbx) => {
|
||||||
let rbx_session = self.session.rbx_session.lock().unwrap();
|
let rbx_session = self.session.rbx_session.lock().unwrap();
|
||||||
let tree = rbx_session.get_tree();
|
let tree = rbx_session.get_tree();
|
||||||
|
|
||||||
let dot_source = format!("{}", VisualizeTree(tree));
|
let dot_source = format!("{}", VisualizeRbxTree(tree));
|
||||||
|
|
||||||
let mut child = Command::new("dot")
|
Response::svg(graphviz_to_svg(&dot_source))
|
||||||
.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");
|
|
||||||
|
|
||||||
{
|
(GET) (/visualize/imfs) => {
|
||||||
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
|
let imfs = self.session.imfs.lock().unwrap();
|
||||||
stdin.write_all(dot_source.as_bytes()).expect("Failed to write to stdin");
|
|
||||||
}
|
|
||||||
|
|
||||||
let output = child.wait_with_output().expect("Failed to read stdout");
|
let dot_source = format!("{}", VisualizeImfs(&imfs));
|
||||||
|
|
||||||
Response::svg(String::from_utf8_lossy(&output.stdout))
|
Response::svg(graphviz_to_svg(&dot_source))
|
||||||
},
|
},
|
||||||
|
|
||||||
_ => Response::empty_404()
|
_ => Response::empty_404()
|
||||||
|
|||||||
Reference in New Issue
Block a user