summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/cli.rs23
-rw-r--r--src/err.rs2
-rw-r--r--src/sock.rs61
3 files changed, 68 insertions, 18 deletions
diff --git a/examples/cli.rs b/examples/cli.rs
index 39c4b0f..2995bac 100644
--- a/examples/cli.rs
+++ b/examples/cli.rs
@@ -1,8 +1,27 @@
+use std::sync::Arc;
+
fn main() {
- let s = torctl::spawn("/usr/bin/tor", "tor-data", "").unwrap();
+ let s = Arc::new( torctl::spawn("/usr/bin/tor", "tor-data", "").unwrap() );
+
+ let slisten = s.clone();
+ std::thread::spawn(move || {
+ loop {
+ match slisten.read_event() {
+ Ok(ev) => println!("Event: {:?}", ev),
+ Err(e) => {
+ println!("Error reading event: {}", e);
+ break;
+ },
+ }
+ }
+ });
+ s.setevents(&["NOTICE", "INFO", "WARN", "ERR"]).unwrap();
+
s.setconf(&[("SocksPort", Some("10245"))]).unwrap();
dbg!(s.getconf(&["ContactInfo", "DataDirectory", "HiddenServiceOptions"]).unwrap());
- dbg!(s.getinfo(&["version", "config-text", "md/all"]).unwrap());
+ dbg!(s.getinfo(&["version", "config-text"]).unwrap());
+
+ std::thread::sleep(std::time::Duration::from_secs(5));
s.quit().unwrap();
std::thread::sleep(std::time::Duration::from_secs(500));
diff --git a/src/err.rs b/src/err.rs
index aa39ede..473dd2f 100644
--- a/src/err.rs
+++ b/src/err.rs
@@ -14,6 +14,7 @@ pub(crate) enum ErrorImpl {
ProcTimeout,
Status(crate::sock::ReplyLine),
Parse, // This could be more specific
+ UnknownEvent(String),
Keyword(String),
}
@@ -26,6 +27,7 @@ impl std::fmt::Display for Error {
ProcTimeout => write!(f, "Timeout while waiting for Tor process to start"),
Status(s) => write!(f, "Unexpected reply ({})", s),
Parse => write!(f, "Error parsing reply"),
+ UnknownEvent(s) => write!(f, "Unknown event: {}", s),
Keyword(s) => write!(f, "Invalid keyword '{}'", s),
}
}
diff --git a/src/sock.rs b/src/sock.rs
index 8102ebc..1724509 100644
--- a/src/sock.rs
+++ b/src/sock.rs
@@ -123,6 +123,16 @@ pub enum Auth {
}
+#[derive(Debug)]
+pub enum Event {
+ // Log messages
+ Debug(String),
+ Info(String),
+ Notice(String),
+ Warn(String),
+ Err(String),
+}
+
// A double-quoted string where only \ and " are escaped.
@@ -356,8 +366,6 @@ impl Sock {
// XXX: This IntoIterator works with &[..] and &vec![..]. Haven't tested HashMap/BTreeMap yet,
// but I suspect their signature doesn't match.
- // Warning: There's no validation on the key string format, so this command allows protocol
- // injection.
fn setresetconf<'a,T>(&self, mut msg: String, settings: T) -> Result<()>
where T: IntoIterator<Item = &'a (&'a str, Option<&'a str>)>,
{
@@ -451,24 +459,45 @@ impl Sock {
Ok(res)
}
- pub fn events(&'a self, list: ..) -> Result<Events<'a>> {
+ // TODO: Create an enum for supported event types, rather than this string thing. We don't
+ // support reading all types of events anyway.
+ pub fn setevents<'a,T: IntoIterator<Item = &'a &'a str>>(&self, events: T) -> Result<()> {
+ let mut msg = "SETEVENTS".to_string();
+ for e in events {
+ is_keyword(e)?;
+ msg.push(' ');
+ msg.push_str(e);
+ }
+ msg.push_str("\r\n");
+ self.cmd(msg).map(|_|())
}
-}
+ /// Read an event from the socket. This method blocks until an event has been received.
+ pub fn read_event(&self) -> Result<Event> {
+ let mut ret = self.get_reply(true)?;
+ let ev = ret.remove(0);
-pub struct Events<'a> {
- sock: &'a Sock
-}
-
-impl<'a> Drop for Events<'a> {
- fn drop(&mut self) {
- self.sock.cmd("SETEVENTS\r\n").is_ok();
- }
-}
+ fn logmsg(r: ReplyLine, skip: usize) -> String {
+ if r.data.is_empty() {
+ (&r.text[skip..]).trim().to_owned()
+ } else {
+ String::from_utf8_lossy(&r.data).trim().to_owned()
+ }
+ }
-impl<'a> Iterator for Events<'a> {
- type Item = Result<Event>;
- fn next(&mut self) -> Option<Self::Item> {
+ if ev.status == 650 && ev.text.starts_with("DEBUG") {
+ Ok(Event::Debug(logmsg(ev, 6)))
+ } else if ev.status == 650 && ev.text.starts_with("NOTICE") {
+ Ok(Event::Notice(logmsg(ev, 7)))
+ } else if ev.status == 650 && ev.text.starts_with("INFO") {
+ Ok(Event::Info(logmsg(ev, 5)))
+ } else if ev.status == 650 && ev.text.starts_with("WARN") {
+ Ok(Event::Warn(logmsg(ev, 5)))
+ } else if ev.status == 650 && ev.text.starts_with("ERR") {
+ Ok(Event::Err(logmsg(ev, 4)))
+ } else {
+ Err(err!(UnknownEvent, ev.text))
+ }
}
}