1extern crate easyjack as jack;
2extern crate getopts;
3
4use getopts::Options;
5use std::env;
6use std::io::Write;
7use std::io::stderr;
8use std::process::exit;
9use std::sync::mpsc::{Sender, Receiver};
10use std::sync::mpsc;
11
12use jack::Port;
14
15enum Mode {
16 Connect(String, String),
17 Disconnect(String, String),
18}
19
20struct Connector<'a> {
27 client: jack::Client<'a>,
28
29 incoming: Receiver<(jack::PortId, jack::PortId, jack::PortConnectStatus)>,
32}
33
34impl<'a> Connector<'a> {
35 fn new(servername: Option<String>) -> Result<Self, jack::status::Status> {
36 let opts = jack::options::NO_START_SERVER;
38 let myname = "connector";
39 let client = match servername {
40 None => jack::Client::open(myname, opts),
41 Some(servername) => jack::Client::open_connection_to(myname, &*servername, opts),
42 };
43
44 let client = match client {
45 Ok((cl, _)) => cl,
46 Err(code) => return Err(code)
47 };
48
49 let (tx, rx) = mpsc::channel();
51
52 let handler = ConnectorHandler { outgoing: tx };
54
55 let mut conn = Connector { client: client, incoming: rx };
57 conn.client.set_metadata_handler(handler).unwrap();
58
59 Ok(conn)
60 }
61
62 fn activate(&mut self) -> Result<(), jack::status::Status> {
63 self.client.activate()
64 }
65
66 fn connect(&mut self, port1: &str, port2: &str) -> Result<(), jack::status::Status> {
67 self.client.connect_ports(port1, port2)
68 }
69
70 fn disconnect(&mut self, port1: &str, port2: &str) -> Result<(), jack::status::Status> {
71 self.client.disconnect_ports(port1, port2)
72 }
73
74 fn wait_and_shutdown(self) {
75 let (a, b, stat) = self.incoming.recv().unwrap();
76 let n1 = self.client.get_port_by_id(a).unwrap().get_name();
77 let n2 = self.client.get_port_by_id(b).unwrap().get_name();
78
79 match stat {
80 jack::PortConnectStatus::PortsConnected =>
81 println!("ports connected: {} and {}", n1, n2),
82
83 jack::PortConnectStatus::PortsDisconnected =>
84 println!("ports disconnected: {} and {}", n1, n2)
85 }
86 }
87}
88
89
90struct ConnectorHandler {
92 outgoing: Sender<(jack::PortId, jack::PortId, jack::PortConnectStatus)>
93}
94
95impl jack::MetadataHandler for ConnectorHandler {
96 fn on_port_connect(&mut self, a: jack::PortId, b: jack::PortId, status: jack::PortConnectStatus) {
97 self.outgoing.send( (a, b, status) ).unwrap();
102 }
103
104 fn callbacks_of_interest(&self) -> Vec<jack::MetadataHandlers> {
105 vec![jack::MetadataHandlers::PortConnect]
106 }
107}
108
109fn do_connect(server: Option<String>, mode: Mode) {
110 let mut connector = match Connector::new(server) {
112 Ok(conn) => conn,
113 Err(code) => {
114 println!("could not create connector: {:?}", code);
115 return
116 }
117 };
118
119 match connector.activate() {
121 Ok(()) => (),
122 Err(code) => {
123 println!("could not activate client: {:?}", code);
124 return
125 }
126 }
127
128
129 match mode {
131 Mode::Connect(p1, p2) => {
132 match connector.connect(p1.as_str(), p2.as_str()) {
133 Ok(()) => (),
134 Err(code) => {
135 println!("Connect failed because: {:?}", code);
136 return
137 }
138 }
139 },
140
141 Mode::Disconnect(p1, p2) => {
142 match connector.disconnect(p1.as_str(), p2.as_str()) {
143 Ok(()) => (),
144 Err(code) => {
145 println!("Disconnect failed because: {:?}", code);
146 return
147 }
148 }
149 }
150 }
151
152 connector.wait_and_shutdown();
154}
155
156fn usage_with_error(exe: String, err: &str, opts: Options) -> ! {
157 let brief = format!("Error! {}\n{} port1 port2", err, opts.short_usage(&exe));
158 let use_me = opts.usage(&brief);
159 writeln!(&mut stderr(), "{}", use_me).unwrap();
160 exit(1);
161}
162
163fn main() {
164 let mut opts = Options::new();
167 opts.optopt("s", "servername", "name of the server to connect to", "NAME");
168
169 opts.optflag("c", "connect", "run in connect mode");
171 opts.optflag("d", "disconnect", "run in disconnect mode");
172
173 let args: Vec<String> = env::args().collect();
174 let exe = args[0].clone();
175 let matches = match opts.parse(&args[1..]) {
176 Ok(m) => m,
177 Err(f) => panic!(f.to_string())
178 };
179
180 if !matches.opt_present("c") && !matches.opt_present("d") {
182 usage_with_error(exe, "Did not specify either -c or -d", opts);
183 }
184
185 if matches.opt_present("c") && matches.opt_present("d") {
186 usage_with_error(exe, "Cannot specify both -c and -d", opts);
187 }
188
189 if matches.free.len() != 2 {
190 usage_with_error(exe, "Did not specify exactly 2 ports!", opts);
191 }
192
193 let port1 = matches.free[0].clone();
195 let port2 = matches.free[1].clone();
196 let server_name = matches.opt_str("s");
197
198 let mode = if matches.opt_present("c") {
199 Mode::Connect(port1, port2)
200 } else {
201 Mode::Disconnect(port1, port2)
202 };
203
204 do_connect(server_name, mode)
205}