151 lines
4.4 KiB
Rust
151 lines
4.4 KiB
Rust
#[macro_use]
|
|
extern crate serde_derive;
|
|
extern crate serde_yaml;
|
|
use std::path::Path;
|
|
|
|
mod parsing;
|
|
|
|
fn main() {
|
|
//read the files
|
|
//let paths = [Path::new("test.yml")];
|
|
let filenames: Vec<_> = std::env::args_os().skip(1).collect();
|
|
let hosts: Vec<Host> = filenames.iter()
|
|
.map(Path::new)
|
|
.map(|path| Host::from_file(&path))
|
|
.collect();
|
|
|
|
//build dot-graph
|
|
let nodes = hosts.iter().map(Host::to_dot_node);
|
|
let edges = hosts.iter().flat_map(Host::to_dot_edge);
|
|
|
|
//render it
|
|
println!("graph antennen {{");
|
|
for node in nodes {
|
|
println!("{}", node);
|
|
}
|
|
for edge in edges {
|
|
println!("{}", edge);
|
|
}
|
|
println!("}}");
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct Host {
|
|
name: String,
|
|
ip: String,
|
|
parent: String,
|
|
kind: HostKind,
|
|
}
|
|
impl Host {
|
|
fn from_file(path: &Path) -> Self {
|
|
let (host, hostname) = parsing::RawHost::from_file(path);
|
|
host.parse(hostname)
|
|
}
|
|
fn to_dot_node(&self) -> String {
|
|
let mut attributes = vec!
|
|
[ "shape=record".to_string()
|
|
, "style=filled".into()
|
|
];
|
|
|
|
let record;
|
|
|
|
// type-specific handling
|
|
use HostKind::*;
|
|
match self.kind {
|
|
Client {coordinates, ref subnet, ref mac, .. } =>
|
|
{ attributes.push("fillcolor=lightgray".into())
|
|
; if let Some(coordinates) = coordinates
|
|
{ attributes.push(format!("pos=\"{breitengrad},{längengrad}\""
|
|
, längengrad=coordinates[0], breitengrad=coordinates[1]))
|
|
}
|
|
; record =
|
|
( self.name.clone()
|
|
, (self.kind.name(), mac.clone())
|
|
, (self.ip.clone(), subnet.clone())
|
|
, ("no ipv6", "no 6-subnet")
|
|
).recordify()
|
|
},
|
|
AccessPoint { ref mac, .. } => record =
|
|
( self.name.clone()
|
|
, (self.kind.name(), mac.clone() )
|
|
, self.ip.clone()
|
|
).recordify(),
|
|
_ => record = (self.name.clone(), self.kind.name(), self.ip.clone()).recordify(),
|
|
};
|
|
attributes.push(format!("label=\"{}\"", record));
|
|
|
|
let attributes = attributes.join(", ");
|
|
|
|
format!("\"{name}\" [{attributes}]", name=self.name, attributes=attributes)
|
|
}
|
|
fn to_dot_edge(&self) -> Option<String> {
|
|
match self.kind {
|
|
HostKind::Client { ref ssid, .. } =>
|
|
format!("\"{name}\" -- \"{parent}\" [label=\"{ssid}\"]", name=self.name, parent=self.parent, ssid=ssid).into(),
|
|
// hier eventuelle ausnahmen für bestimmte typen die keine parents haben eintragen
|
|
// mainly template und sol
|
|
_ =>
|
|
format!("\"{name}\" -- \"{parent}\"", name=self.name, parent=self.parent).into(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
enum HostKind {
|
|
Client { mac: String, subnet: String, coordinates: Option<[f64;2]>, ssid: String },
|
|
AccessPoint { mac: String, ssid: String },
|
|
Service,
|
|
Other,
|
|
}
|
|
|
|
impl HostKind {
|
|
fn name(&self) -> &'static str {
|
|
use HostKind::*;
|
|
match *self {
|
|
Client { .. } => "Client",
|
|
AccessPoint { .. } => "AccessPoint",
|
|
Service => "Service",
|
|
Other => "Other",
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/** dieser Trait ermöglicht es verschachtelte tupel in ein label für einen record-shaped-node für
|
|
dotfiles umzuwandeln. inputwerte werden nicht escaped
|
|
|
|
assert_eq!(
|
|
("a", ("b", "c", "d"), ("e","f"), "g").recordify(),
|
|
"{a|{b|c|d}|{e|f}|g}".into())
|
|
*/
|
|
pub trait DotRecord {
|
|
fn recordify(self) -> String;
|
|
}
|
|
|
|
impl DotRecord for String {
|
|
fn recordify(self) -> String { self }
|
|
}
|
|
impl<'a> DotRecord for &'a str {
|
|
fn recordify(self) -> String { self.into() }
|
|
}
|
|
impl<A: DotRecord, B: DotRecord> DotRecord for (A,B) {
|
|
fn recordify(self) -> String {
|
|
format!("{{{}|{}}}", self.0.recordify(), self.1.recordify())
|
|
}
|
|
}
|
|
impl<A: DotRecord, B: DotRecord, C: DotRecord> DotRecord for (A,B,C) {
|
|
fn recordify(self) -> String {
|
|
format!("{{{}|{}|{}}}", self.0.recordify(), self.1.recordify(), self.2.recordify())
|
|
}
|
|
}
|
|
impl<A: DotRecord, B: DotRecord, C: DotRecord, D: DotRecord> DotRecord for (A,B,C,D) {
|
|
fn recordify(self) -> String {
|
|
format!("{{{}|{}|{}|{}}}", self.0.recordify(), self.1.recordify(), self.2.recordify(), self.3.recordify())
|
|
}
|
|
}
|
|
impl<A: DotRecord, B: DotRecord, C: DotRecord, D: DotRecord, E: DotRecord> DotRecord for (A,B,C,D,E) {
|
|
fn recordify(self) -> String {
|
|
format!("{{{}|{}|{}|{}|{}}}", self.0.recordify(), self.1.recordify(), self.2.recordify(), self.3.recordify(), self.4.recordify())
|
|
}
|
|
}
|