extern crate easyjack as jack;
extern crate getopts;
use getopts::Options;
use std::env;
use std::io::Write;
use std::io::stderr;
use std::process::exit;
use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc;
use jack::Port;
enum Mode {
Connect(String, String),
Disconnect(String, String),
}
struct Connector<'a> {
client: jack::Client<'a>,
incoming: Receiver<(jack::PortId, jack::PortId, jack::PortConnectStatus)>,
}
impl<'a> Connector<'a> {
fn new(servername: Option<String>) -> Result<Self, jack::status::Status> {
let opts = jack::options::NO_START_SERVER;
let myname = "connector";
let client = match servername {
None => jack::Client::open(myname, opts),
Some(servername) => jack::Client::open_connection_to(myname, &*servername, opts),
};
let client = match client {
Ok((cl, _)) => cl,
Err(code) => return Err(code)
};
let (tx, rx) = mpsc::channel();
let handler = ConnectorHandler { outgoing: tx };
let mut conn = Connector { client: client, incoming: rx };
conn.client.set_metadata_handler(handler).unwrap();
Ok(conn)
}
fn activate(&mut self) -> Result<(), jack::status::Status> {
self.client.activate()
}
fn connect(&mut self, port1: &str, port2: &str) -> Result<(), jack::status::Status> {
self.client.connect_ports(port1, port2)
}
fn disconnect(&mut self, port1: &str, port2: &str) -> Result<(), jack::status::Status> {
self.client.disconnect_ports(port1, port2)
}
fn wait_and_shutdown(self) {
let (a, b, stat) = self.incoming.recv().unwrap();
let n1 = self.client.get_port_by_id(a).unwrap().get_name();
let n2 = self.client.get_port_by_id(b).unwrap().get_name();
match stat {
jack::PortConnectStatus::PortsConnected =>
println!("ports connected: {} and {}", n1, n2),
jack::PortConnectStatus::PortsDisconnected =>
println!("ports disconnected: {} and {}", n1, n2)
}
}
}
struct ConnectorHandler {
outgoing: Sender<(jack::PortId, jack::PortId, jack::PortConnectStatus)>
}
impl jack::MetadataHandler for ConnectorHandler {
fn on_port_connect(&mut self, a: jack::PortId, b: jack::PortId, status: jack::PortConnectStatus) {
self.outgoing.send( (a, b, status) ).unwrap();
}
fn callbacks_of_interest(&self) -> Vec<jack::MetadataHandlers> {
vec![jack::MetadataHandlers::PortConnect]
}
}
fn do_connect(server: Option<String>, mode: Mode) {
let mut connector = match Connector::new(server) {
Ok(conn) => conn,
Err(code) => {
println!("could not create connector: {:?}", code);
return
}
};
match connector.activate() {
Ok(()) => (),
Err(code) => {
println!("could not activate client: {:?}", code);
return
}
}
match mode {
Mode::Connect(p1, p2) => {
match connector.connect(p1.as_str(), p2.as_str()) {
Ok(()) => (),
Err(code) => {
println!("Connect failed because: {:?}", code);
return
}
}
},
Mode::Disconnect(p1, p2) => {
match connector.disconnect(p1.as_str(), p2.as_str()) {
Ok(()) => (),
Err(code) => {
println!("Disconnect failed because: {:?}", code);
return
}
}
}
}
connector.wait_and_shutdown();
}
fn usage_with_error(exe: String, err: &str, opts: Options) -> ! {
let brief = format!("Error! {}\n{} port1 port2", err, opts.short_usage(&exe));
let use_me = opts.usage(&brief);
writeln!(&mut stderr(), "{}", use_me).unwrap();
exit(1);
}
fn main() {
let mut opts = Options::new();
opts.optopt("s", "servername", "name of the server to connect to", "NAME");
opts.optflag("c", "connect", "run in connect mode");
opts.optflag("d", "disconnect", "run in disconnect mode");
let args: Vec<String> = env::args().collect();
let exe = args[0].clone();
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => panic!(f.to_string())
};
if !matches.opt_present("c") && !matches.opt_present("d") {
usage_with_error(exe, "Did not specify either -c or -d", opts);
}
if matches.opt_present("c") && matches.opt_present("d") {
usage_with_error(exe, "Cannot specify both -c and -d", opts);
}
if matches.free.len() != 2 {
usage_with_error(exe, "Did not specify exactly 2 ports!", opts);
}
let port1 = matches.free[0].clone();
let port2 = matches.free[1].clone();
let server_name = matches.opt_str("s");
let mode = if matches.opt_present("c") {
Mode::Connect(port1, port2)
} else {
Mode::Disconnect(port1, port2)
};
do_connect(server_name, mode)
}