diff --git a/src/bootstrap.rs b/src/bootstrap.rs index cc401d8..474a394 100644 --- a/src/bootstrap.rs +++ b/src/bootstrap.rs @@ -3,6 +3,13 @@ use std::io::Read; use failure::Fallible; use serde::Deserialize; use serde::Serialize; +use crate::store::Store; +use crate::Config; +use elefren::{Registration, Mastodon}; +use elefren::http_send::HttpSender; +use elefren::helpers::cli; +use elefren::scopes::Scopes; +use std::str::FromStr; const CONFIG_FILE: &str = "manabu.toml"; @@ -12,20 +19,11 @@ const SOFTWARE_NAME: &str = env!("CARGO_PKG_NAME"); /// to allow using e.g. TRACE without drowing our custom messages const SPAMMY_LIBS: [&str; 6] = ["tokio_reactor", "hyper", "reqwest", "mio", "want", "elefren"]; -#[derive(SmartDefault,Serialize,Deserialize,Debug)] -#[serde(default)] -pub struct Config { - #[default="info"] - logging: String, - pub instance: String, - #[default="manabu_store.json"] - pub store: String, -} - const LOG_LEVELS: [&str; 5] = ["error", "warn", "info", "debug", "trace"]; + /// Load the shared config file -fn load_config(file: &str) -> Fallible { +pub fn load_config(file: &str) -> Fallible { let mut file = File::open(file)?; let mut buf = String::new(); @@ -41,7 +39,7 @@ fn load_config(file: &str) -> Fallible { Ok(config) } -pub(crate) fn init() -> Fallible { +pub fn handle_cli_args_and_load_config() -> Fallible { let version = format!("{}, built from {}", env!("CARGO_PKG_VERSION"), env!("GIT_REV")); let argv = clap::App::new(SOFTWARE_NAME) diff --git a/src/ele.rs b/src/ele.rs new file mode 100644 index 0000000..eedb91a --- /dev/null +++ b/src/ele.rs @@ -0,0 +1,87 @@ +use std::fs::File; +use std::io::Read; +use failure::Fallible; +use serde::Deserialize; +use serde::Serialize; +use crate::store::Store; +use crate::Config; +use elefren::{Registration, Mastodon}; +use elefren::http_send::HttpSender; +use elefren::helpers::cli; +use elefren::scopes::Scopes; +use std::str::FromStr; + +const KEY_OAUTH_REGISTRATION: &str = "oauth.registration"; +const KEY_OAUTH_SESSION: &str = "oauth.session"; + +pub type EleRegistratered = elefren::registration::Registered; +pub type EleSession = elefren::Mastodon; +pub type EleWebsocket = websocket::sync::Client>; + +/// Wrapper for the long tuple with Registration state +#[derive(Serialize,Deserialize,Debug)] +pub struct ElefrenRegistration { + pub parts: (String, String, String, String, Scopes, bool), +} + + +/// Register "app" in the server software +pub fn register(store : &mut Store, config : &Config) -> EleRegistratered { + match store.get::(KEY_OAUTH_REGISTRATION) { + Some(reg) => { + info!("Loaded registration from store"); + + EleRegistratered::from_parts( + // this sucks + ®.parts.0, ®.parts.1, ®.parts.2, ®.parts.3, reg.parts.4, reg.parts.5 + ) + } + None => { + info!("Creating a new registration"); + + let registered = Registration::new(&format!("https://{}", config.instance)) + .client_name("manabu") + .scopes(Scopes::from_str("read write").expect("err parse scopes")) + .build().expect("error register"); + store.put(KEY_OAUTH_REGISTRATION, ElefrenRegistration { parts : registered.clone().into_parts() }); + registered + } + } +} + +pub fn open_session(store : &mut Store, registered: EleRegistratered) -> EleSession { + match store.get::(KEY_OAUTH_SESSION) { + Some(data) => { + info!("Reusing saved authorization."); + + let cli = Mastodon::from(data); + // TODO check if the session is live, somehow + cli + } + None => { + info!("Creating new authorization."); + + let cli = cli::authenticate(registered).expect("error auth"); + store.put(KEY_OAUTH_SESSION, cli.data.clone()); + cli + } + } +} + +pub fn open_stream_websocket(session : &EleSession, stream_name : &str) -> EleWebsocket { + let connector = native_tls::TlsConnector::new().unwrap(); + + let hostname = &session.data.base[session.data.base.find("://").unwrap()+3..]; + + let url = format!("wss://{host}/api/v1/streaming/?stream={sname}&access_token={token}", + host=hostname, + sname=stream_name, + token=session.data.token); + + debug!("WS url = {}", &url); + + websocket::ClientBuilder::new(&url) + .expect("Error create ClientBuilder") + .connect_secure(Some(connector)) + .expect("Error connect to wss") +} diff --git a/src/main.rs b/src/main.rs index c63808e..71c5222 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,54 +15,46 @@ use elefren::{ }; use failure::Fallible; -use crate::bootstrap::Config; -use crate::store::Store; - use native_tls::TlsConnector; use std::io::{Read, Write}; use std::net::TcpStream; -use websocket::OwnedMessage; +use websocket::{OwnedMessage, ClientBuilder}; mod bootstrap; mod store; +mod ele; -type EleRegistratered = elefren::registration::Registered; +use crate::bootstrap::handle_cli_args_and_load_config; -/// Wrapper for the long tuple with Registration state -#[derive(Serialize,Deserialize,Debug)] -struct ElefrenRegistration { - parts: (String, String, String, String, Scopes, bool), -} +use crate::store::Store; -const KEY_OAUTH_REGISTRATION: &str = "elefren.registration"; -const KEY_OAUTH_SESSION: &str = "elefren.session"; +#[derive(SmartDefault,Serialize,Deserialize,Debug)] +#[serde(default)] +pub struct Config { + #[default="info"] + pub logging: String, + pub instance: String, + #[default="manabu_store.json"] + pub store: String, +} fn main() { - let config : Config = bootstrap::init().expect("error init config"); + let config : Config = handle_cli_args_and_load_config().expect("error init"); debug!("Loaded config: {:#?}", config); let mut store = Store::from_file(&config.store); store.set_autosave(true); - let registered = register(&mut store, &config); + let registered = ele::register(&mut store, &config); - let client = open_session(&mut store, registered); + let session = ele::open_session(&mut store, registered); debug!("Listening to events"); - let connector = TlsConnector::new().unwrap(); - - use websocket::ClientBuilder; + let mut socket = ele::open_stream_websocket(&session, "user"); - let url = format!("wss://{host}/api/v1/streaming/?stream=user&access_token={token}", host=config.instance, token=client.data.token); - debug!("WS url = {}", &url); - let mut client = ClientBuilder::new(&url) - .expect("Error create ClientBuilder") - .connect_secure(Some(connector)) - .expect("Error connect to wss"); - - for m in client.incoming_messages() { + for m in socket.incoming_messages() { match m { Ok(OwnedMessage::Text(text)) => { debug!("Got msg: {}", text); @@ -82,44 +74,3 @@ fn main() { } info!("Exit."); } - -fn register(store : &mut Store, config : &Config) -> EleRegistratered { - match store.get::(KEY_OAUTH_REGISTRATION) { - Some(reg) => { - info!("Loaded registration from store"); - - EleRegistratered::from_parts( - // this sucks - ®.parts.0, ®.parts.1, ®.parts.2, ®.parts.3, reg.parts.4, reg.parts.5 - ) - } - None => { - info!("Creating a new registration"); - - let registered = Registration::new(&format!("https://{}", config.instance)) - .client_name("manabu") - .build().expect("error register"); - store.put(KEY_OAUTH_REGISTRATION, ElefrenRegistration { parts : registered.clone().into_parts() }); - registered - } - } -} - -fn open_session(store : &mut Store, registered: EleRegistratered) -> Mastodon { - match store.get::(KEY_OAUTH_SESSION) { - Some(data) => { - info!("Reusing saved authorization."); - - let cli = Mastodon::from(data); - // TODO check if the session is live, somehow - cli - } - None => { - info!("Creating new authorization."); - - let cli = cli::authenticate(registered).expect("error auth"); - store.put(KEY_OAUTH_SESSION, cli.data.clone()); - cli - } - } -}