aboutsummaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2017-11-10 04:04:00 -0800
committeriximeow <me@iximeow.net>2017-11-10 04:04:59 -0800
commit83107e0e93cad31152ce71b6a20da466d5216071 (patch)
tree877f3c97781efd2a8a5a28e1803314575b04382c /src/main.rs
parentc2c125a83cfdd3556df37f02907edcb1351d674b (diff)
very hackily add notion of user credentials and PIN auth
also fix bug where cached user info takes precedence over (possibly updated) api json user info
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs184
1 files changed, 96 insertions, 88 deletions
diff --git a/src/main.rs b/src/main.rs
index f8276ed..97d5315 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -39,13 +39,6 @@ mod tw;
mod display;
mod commands;
-//Change these values to your real Twitter API credentials
-static consumer_key: &str = "T879tHWDzd6LvKWdYVfbJL4Su";
-static consumer_secret: &str = "OAXXYYIozAZ4vWSmDziI1EMJCKXPmWPFgLbJpB896iIAMIAdpb";
-static token: &str = "629126745-Qt6LPq2kR7w58s7WHzSqcs4CIdiue64kkfYYB7RI";
-static token_secret: &str = "3BI3YC4WVbKW5icpHORWpsTYqYIj5oAZFkrgyIAoaoKnK";
-static lol_auth_token: &str = "641cdf3a4bbddb72c118b5821e8696aee6300a9a";
-
static STREAMURL: &str = "https://userstream.twitter.com/1.1/user.json?tweet_mode=extended";
static TWEET_LOOKUP_URL: &str = "https://api.twitter.com/1.1/statuses/show.json?tweet_mode=extended";
static USER_LOOKUP_URL: &str = "https://api.twitter.com/1.1/users/show.json";
@@ -64,11 +57,11 @@ pub struct Queryer {
}
impl Queryer {
- fn do_api_get(&mut self, url: &str) -> Result<serde_json::Value, String> {
- self.issue_request(signed_api_get(url))
+ fn do_api_get(&mut self, url: &str, app_cred: &tw::Credential, user_cred: &tw::Credential) -> Result<serde_json::Value, String> {
+ self.issue_request(signed_api_get(url, app_cred, user_cred))
}
- fn do_api_post(&mut self, url: &str) -> Result<serde_json::Value, String> {
- self.issue_request(signed_api_post(url))
+ fn do_api_post(&mut self, url: &str, app_cred: &tw::Credential, user_cred: &tw::Credential) -> Result<serde_json::Value, String> {
+ self.issue_request(signed_api_post(url, app_cred, user_cred))
}
/*
fn do_web_req(&mut self, url: &str) -> Option<serde_json::Value> {
@@ -76,6 +69,10 @@ impl Queryer {
}*/
// TODO: make this return the status as well!
fn issue_request(&mut self, req: hyper::client::Request) -> Result<serde_json::Value, String> {
+ let resp_body = self.raw_issue_request(req);
+ resp_body.and_then(|body| serde_json::from_slice(&body).map_err(|e| e.to_string()))
+ }
+ fn raw_issue_request(&mut self, req: hyper::client::Request) -> Result<Vec<u8>, String> {
let lookup = self.client.request(req);
let resp: hyper::Response = self.core.run(lookup).unwrap();
@@ -84,18 +81,10 @@ impl Queryer {
let chunks: Vec<hyper::Chunk> = self.core.run(resp.body().collect()).unwrap();
let resp_body: Vec<u8> = chunks.into_iter().flat_map(|chunk| chunk.into_iter()).collect();
-
- match serde_json::from_slice(&resp_body) {
- Ok(value) => {
- if status != hyper::StatusCode::Ok {
- Err(format!("!! Requests returned status: {}\n{}", status, value))
- } else {
- Ok(value)
- }
- }
- Err(e) => {
- Err(format!("!! Requests returned status: {}\nerror deserializing json: {}", status, e))
- }
+ if status != hyper::StatusCode::Ok {
+ Err(format!("!! Requests returned status: {} - {:?}", status, std::str::from_utf8(&resp_body)))
+ } else {
+ Ok(resp_body)
}
}
}
@@ -137,15 +126,23 @@ fn signed_web_get(url: &str) -> hyper::client::Request {
}
*/
-fn signed_api_post(url: &str) -> hyper::client::Request {
- signed_api_req(url, Method::Post)
+fn signed_api_post(url: &str, app_cred: &tw::Credential, user_cred: &tw::Credential) -> hyper::client::Request {
+ signed_api_req_with_token(url, Method::Post, app_cred, user_cred)
}
-fn signed_api_get(url: &str) -> hyper::client::Request {
- signed_api_req(url, Method::Get)
+fn signed_api_get(url: &str, app_cred: &tw::Credential, user_cred: &tw::Credential) -> hyper::client::Request {
+ signed_api_req_with_token(url, Method::Get, app_cred, user_cred)
}
-fn signed_api_req(url: &str, method: Method) -> hyper::client::Request {
+fn signed_api_req_with_token(url: &str, method: Method, app_cred: &tw::Credential, user_cred: &tw::Credential) -> hyper::client::Request {
+ inner_signed_api_req(url, method, app_cred, Some(user_cred))
+}
+
+fn signed_api_req(url: &str, method: Method, app_cred: &tw::Credential) -> hyper::client::Request {
+ inner_signed_api_req(url, method, app_cred, None)
+}
+
+fn inner_signed_api_req(url: &str, method: Method, app_cred: &tw::Credential, maybe_user_cred: Option<&tw::Credential>) -> hyper::client::Request {
// let params: Vec<(String, String)> = vec![("track".to_string(), "london".to_string())];
let method_string = match method {
Method::Get => "GET",
@@ -156,15 +153,21 @@ fn signed_api_req(url: &str, method: Method) -> hyper::client::Request {
let params: Vec<(String, String)> = vec![];
let _param_string: String = params.iter().map(|p| p.0.clone() + &"=".to_string() + &p.1).collect::<Vec<String>>().join("&");
- let header = oauthcli::OAuthAuthorizationHeaderBuilder::new(
+ let parsed_url = url::Url::parse(url).unwrap();
+
+ let mut builder = oauthcli::OAuthAuthorizationHeaderBuilder::new(
method_string,
- &url::Url::parse(url).unwrap(),
- consumer_key,
- consumer_secret,
+ &parsed_url,
+ app_cred.key.to_owned(),
+ app_cred.secret.to_owned(),
oauthcli::SignatureMethod::HmacSha1,
- )
- .token(token, token_secret)
- .finish();
+ );
+
+ if let Some(user_cred) = maybe_user_cred {
+ builder.token(user_cred.key.to_owned(), user_cred.secret.to_owned());
+ }
+
+ let header = builder.finish();
let mut req = Request::new(method, url.parse().unwrap());
@@ -185,14 +188,6 @@ fn main() {
let (ui_tx, mut ui_rx) = chan::sync::<Result<termion::event::Event, std::io::Error>>(0);
- let mut twete_rx = connect_twitter_stream();
-
- std::thread::spawn(move || {
- for input in stdin().events() {
- ui_tx.send(input);
- }
- });
-
// I *would* want to load this before spawning the thread, but..
// tokio_core::reactor::Inner can't be moved between threads safely
// and beacuse it's an Option-al field, it might be present
@@ -205,6 +200,14 @@ fn main() {
println!("Loaded cache!");
+ let mut maybe_twete_rx: Option<chan::Receiver<Vec<u8>>> = tweeter.profile.clone().map(|user_creds| connect_twitter_stream(tweeter.app_key.clone(), user_creds));
+
+ std::thread::spawn(move || {
+ for input in stdin().events() {
+ ui_tx.send(input);
+ }
+ });
+
let c2 = Core::new().unwrap(); // i swear this is not where the botnet lives
let handle = &c2.handle();
let secondary_connector = HttpsConnector::new(4, handle).unwrap();
@@ -226,10 +229,10 @@ fn main() {
tcsetattr(0, TCSANOW, &new_termios).unwrap();
loop {
- match do_ui(ui_rx, twete_rx, &mut tweeter, &mut queryer) {
- Some((new_ui_rx, new_twete_rx)) => {
+ match do_ui(ui_rx, maybe_twete_rx, &mut tweeter, &mut queryer) {
+ Some((new_ui_rx, new_maybe_twete_rx)) => {
ui_rx = new_ui_rx;
- twete_rx = new_twete_rx;
+ maybe_twete_rx = new_maybe_twete_rx;
},
None => {
break;
@@ -266,6 +269,7 @@ fn handle_input(event: termion::event::Event, tweeter: &mut tw::TwitterCache, qu
_ => {}
}
}
+ // TODO: ctrl+u, ctrl+w
Event::Key(Key::Char(x)) => {
match tweeter.display_info.mode.clone() {
None => {
@@ -311,62 +315,66 @@ fn handle_input(event: termion::event::Event, tweeter: &mut tw::TwitterCache, qu
}
}
-fn do_ui(ui_rx_orig: chan::Receiver<Result<termion::event::Event, std::io::Error>>, twete_rx: chan::Receiver<Vec<u8>>, mut tweeter: &mut tw::TwitterCache, mut queryer: &mut ::Queryer) -> Option<(chan::Receiver<Result<termion::event::Event, std::io::Error>>, chan::Receiver<Vec<u8>>)> {
+fn handle_twitter_line(line: Vec<u8>, mut tweeter: &mut tw::TwitterCache, mut queryer: &mut ::Queryer) {
+ let jsonstr = std::str::from_utf8(&line).unwrap().trim();
+ /* TODO: replace from_str with from_slice */
+ match serde_json::from_str(&jsonstr) {
+ Ok(json) => {
+ tw::handle_message(json, &mut tweeter, &mut queryer);
+ if tweeter.needs_save && tweeter.caching_permitted {
+ tweeter.store_cache();
+ }
+ },
+ Err(e) =>
+ tweeter.display_info.status(format!("Error reading twitter line: {}", jsonstr))
+ }
+}
+
+fn do_ui(ui_rx_orig: chan::Receiver<Result<termion::event::Event, std::io::Error>>, maybe_twete_rx: Option<chan::Receiver<Vec<u8>>>, mut tweeter: &mut tw::TwitterCache, mut queryer: &mut ::Queryer) -> Option<(chan::Receiver<Result<termion::event::Event, std::io::Error>>, Option<chan::Receiver<Vec<u8>>>)> {
loop {
let ui_rx_a = &ui_rx_orig;
let ui_rx_b = &ui_rx_orig;
- chan_select! {
- twete_rx.recv() -> twete => match twete {
- Some(line) => {
- let jsonstr = std::str::from_utf8(&line).unwrap().trim();
- /* TODO: replace from_str with from_slice */
- let json: serde_json::Value = serde_json::from_str(&jsonstr).unwrap();
- tw::handle_message(json, &mut tweeter, &mut queryer);
- if tweeter.needs_save && tweeter.caching_permitted {
- tweeter.store_cache();
- }
- }
- None => {
- tweeter.display_info.status("Twitter stream hung up...".to_owned());
- chan_select! {
- ui_rx_b.recv() -> input => match input {
- Some(maybe_event) => {
- if let Ok(event) = maybe_event {
- handle_input(event, tweeter, queryer);
- } else {
- // stdin closed?
- }
- }
- // twitter stream closed, ui thread closed, uhh..
- None => std::process::exit(0)
+ match &maybe_twete_rx {
+ &Some(ref twete_rx) => {
+ chan_select! {
+ twete_rx.recv() -> twete => match twete {
+ Some(line) => handle_twitter_line(line, tweeter, queryer),
+ None => {
+ tweeter.display_info.status("Twitter stream hung up...".to_owned());
+ return Some((ui_rx_orig.clone(), None))
}
+ },
+ ui_rx_a.recv() -> user_input => match user_input {
+ Some(Ok(event)) => handle_input(event, tweeter, queryer),
+ Some(Err(_)) => (), /* stdin closed? */
+ None => return None // UI ded
}
}
},
- ui_rx_a.recv() -> user_input => match user_input {
- Some(maybe_event) => {
- if let Ok(event) = maybe_event {
- handle_input(event, tweeter, queryer); // eventually DisplayInfo too, as a separate piece of data...
- } else {
- // dunno how we'd reach this... stdin closed?
+ &None => {
+ chan_select! {
+ ui_rx_a.recv() -> user_input => match user_input {
+ Some(Ok(event)) => handle_input(event, tweeter, queryer),
+ Some(Err(_)) => (), /* stdin closed? */
+ None => return None // UI ded
}
- },
- None => tweeter.display_info.status("UI thread hung up...".to_owned())
+ }
}
- // and then we can introduce a channel that just sends a message every 100 ms or so
- // that acts as a clock!
}
- match tweeter.state {
- tw::AppState::Reconnect => return Some((ui_rx_orig.clone(), connect_twitter_stream())),
- _ => ()
- };
-
// one day display_info should be distinct
match display::paint(tweeter) {
Ok(_) => (),
Err(e) => println!("{}", e) // TODO: we got here because writing to stdout failed. what to do now?
};
+
+ match tweeter.state {
+ tw::AppState::Reconnect => {
+ tweeter.state = tw::AppState::View;
+ return Some((ui_rx_orig.clone(), tweeter.profile.clone().map(|creds| connect_twitter_stream(tweeter.app_key.clone(), creds))));
+ }
+ _ => ()
+ };
}
}
@@ -402,7 +410,7 @@ fn url_encode(s: &str) -> String {
.replace("]", "%5d")
}
-fn connect_twitter_stream() -> chan::Receiver<Vec<u8>> {
+fn connect_twitter_stream(app_cred: tw::Credential, user_cred: tw::Credential) -> chan::Receiver<Vec<u8>> {
let (twete_tx, twete_rx) = chan::sync::<Vec<u8>>(0);
std::thread::spawn(move || {
@@ -415,7 +423,7 @@ fn connect_twitter_stream() -> chan::Receiver<Vec<u8>> {
.connector(connector)
.build(&core.handle());
- let req = signed_api_get(STREAMURL);
+ let req = signed_api_get(STREAMURL, &app_cred, &user_cred);
let work = client.request(req).and_then(|res| {
let status = res.status();
if status != hyper::StatusCode::Ok {