Browse Source
I've simplified the project, removing all the tokio communication stuff and the ruma-client, calling directly to the Matrix.org API using the reqwest rust lib.environments/review-jsparber-h-cxnwl8/deployments/1
8 changed files with 282 additions and 1465 deletions
@ -0,0 +1,6 @@
|
||||
Guillotine |
||||
========== |
||||
|
||||
This project is based on ruma-gtk https://github.com/jplatte/ruma-gtk |
||||
|
||||
But derives in a new one using directly the matrix.org API. |
||||
@ -0,0 +1,175 @@
|
||||
extern crate url; |
||||
extern crate reqwest; |
||||
|
||||
use std::sync::{Arc, Mutex}; |
||||
use std::thread; |
||||
use std::collections::HashMap; |
||||
use self::url::Url; |
||||
use std::sync::mpsc::Sender; |
||||
|
||||
// TODO: send errors to the frontend
|
||||
|
||||
macro_rules! get { |
||||
($url: expr, $attrs: expr, $resp: ident, $okcb: expr) => { |
||||
query!(get, $url, $attrs, $resp, $okcb, |err| { |
||||
println!("ERROR {:?}", err); |
||||
}); |
||||
}; |
||||
} |
||||
|
||||
macro_rules! post { |
||||
($url: expr, $attrs: expr, $resp: ident, $okcb: expr) => { |
||||
query!(post, $url, $attrs, $resp, $okcb, |err| { |
||||
println!("ERROR {:?}", err); |
||||
}); |
||||
}; |
||||
} |
||||
|
||||
macro_rules! query { |
||||
($method: ident, $url: expr, $attrs: expr, $resp: ident, $okcb: expr, $errcb: expr) => { |
||||
// TODO: remove unwrap and manage errors
|
||||
thread::spawn(move || { |
||||
let client = reqwest::Client::new().unwrap(); |
||||
let mut conn = client.$method($url.as_str()).unwrap(); |
||||
let conn2 = conn.json(&$attrs).unwrap(); |
||||
let mut res = conn2.send().unwrap(); |
||||
|
||||
let js: Result<$resp, _> = res.json(); |
||||
|
||||
match js { |
||||
Ok(r) => { |
||||
$okcb(r) |
||||
}, |
||||
Err(err) => { |
||||
$errcb(err) |
||||
} |
||||
} |
||||
//let mut content = String::new();
|
||||
//res.read_to_string(&mut content);
|
||||
//cb(content);
|
||||
}); |
||||
}; |
||||
} |
||||
|
||||
|
||||
#[derive(Debug)] |
||||
pub enum Error { |
||||
BackendError, |
||||
ReqwestError(reqwest::Error), |
||||
} |
||||
|
||||
impl From<reqwest::Error> for Error { |
||||
fn from(err: reqwest::Error) -> Error { |
||||
Error::ReqwestError(err) |
||||
} |
||||
} |
||||
|
||||
impl From<url::ParseError> for Error { |
||||
fn from(_: url::ParseError) -> Error { |
||||
Error::BackendError |
||||
} |
||||
} |
||||
|
||||
pub struct BackendData { |
||||
user_id: String, |
||||
access_token: String, |
||||
server_url: String, |
||||
} |
||||
|
||||
pub struct Backend { |
||||
tx: Sender<BKResponse>, |
||||
data: Arc<Mutex<BackendData>>, |
||||
} |
||||
|
||||
#[derive(Debug)] |
||||
pub enum BKResponse { |
||||
Token(String, String), |
||||
Name(String), |
||||
} |
||||
|
||||
#[derive(Deserialize)] |
||||
#[derive(Debug)] |
||||
pub struct Response { |
||||
user_id: String, |
||||
access_token: String, |
||||
} |
||||
|
||||
#[derive(Deserialize)] |
||||
#[derive(Debug)] |
||||
pub struct DisplayNameResponse { |
||||
displayname: String, |
||||
} |
||||
|
||||
impl Backend { |
||||
pub fn new(tx: Sender<BKResponse>) -> Backend { |
||||
let data = BackendData { |
||||
user_id: String::from("Guest"), |
||||
access_token: String::from(""), |
||||
server_url: String::from("https://matrix.org"), |
||||
}; |
||||
Backend { tx: tx, data: Arc::new(Mutex::new(data)) } |
||||
} |
||||
|
||||
pub fn guest(&self, server: String) -> Result<(), Error> { |
||||
let s = server.clone(); |
||||
let url = Url::parse(&s).unwrap().join("/_matrix/client/r0/register?kind=guest")?; |
||||
self.data.lock().unwrap().server_url = s; |
||||
|
||||
let map: HashMap<String, String> = HashMap::new(); |
||||
|
||||
let data = self.data.clone(); |
||||
let tx = self.tx.clone(); |
||||
post!(url, map, Response, |
||||
|r: Response| { |
||||
let uid = r.user_id.clone(); |
||||
let tk = r.access_token.clone(); |
||||
data.lock().unwrap().user_id = uid.clone(); |
||||
data.lock().unwrap().access_token = tk.clone(); |
||||
tx.send(BKResponse::Token(uid, tk)).unwrap(); |
||||
} |
||||
); |
||||
|
||||
Ok(()) |
||||
} |
||||
|
||||
pub fn login(&self, user: String, password: String, server: String) -> Result<(), Error> { |
||||
let s = server.clone(); |
||||
let url = Url::parse(&s)?.join("/_matrix/client/r0/login")?; |
||||
self.data.lock().unwrap().server_url = s; |
||||
|
||||
let mut map = HashMap::new(); |
||||
map.insert("type", String::from("m.login.password")); |
||||
map.insert("user", user); |
||||
map.insert("password", password); |
||||
|
||||
let data = self.data.clone(); |
||||
let tx = self.tx.clone(); |
||||
post!(url, map, Response, |
||||
|r: Response| { |
||||
let uid = r.user_id.clone(); |
||||
let tk = r.access_token.clone(); |
||||
data.lock().unwrap().user_id = uid.clone(); |
||||
data.lock().unwrap().access_token = tk.clone(); |
||||
tx.send(BKResponse::Token(uid, tk)).unwrap(); |
||||
} |
||||
); |
||||
|
||||
Ok(()) |
||||
} |
||||
|
||||
pub fn get_username(&self) -> Result<(), Error> { |
||||
let s = self.data.lock().unwrap().server_url.clone(); |
||||
let id = self.data.lock().unwrap().user_id.clone() + "/"; |
||||
let url = Url::parse(&s)?.join("/_matrix/client/r0/profile/")?.join(&id)?.join("displayname")?; |
||||
let map: HashMap<String, String> = HashMap::new(); |
||||
|
||||
let tx = self.tx.clone(); |
||||
get!(url, map, DisplayNameResponse, |
||||
|r: DisplayNameResponse| { |
||||
tx.send(BKResponse::Name(r.displayname.clone())).unwrap(); |
||||
} |
||||
); |
||||
|
||||
Ok(()) |
||||
} |
||||
} |
||||
@ -1,121 +0,0 @@
|
||||
use std; |
||||
|
||||
use futures; |
||||
use futures::future::{self, Loop, Future}; |
||||
use futures::stream::Stream; |
||||
use gtk; |
||||
use ruma_client::{self, Client as RumaClient}; |
||||
use tokio_core::reactor::{Core as TokioCore, Handle as TokioHandle}; |
||||
use url::Url; |
||||
|
||||
pub enum Command { |
||||
Connect { |
||||
homeserver_url: Url, |
||||
connection_method: ConnectionMethod, |
||||
}, |
||||
} |
||||
|
||||
#[derive(Clone)] |
||||
pub enum ConnectionMethod { |
||||
Login { username: String, password: String }, |
||||
Guest, |
||||
//Register,
|
||||
} |
||||
|
||||
#[derive(Debug)] |
||||
enum Error { |
||||
RumaClientError(ruma_client::Error), |
||||
RecvError(std::sync::mpsc::RecvError), |
||||
} |
||||
|
||||
impl From<ruma_client::Error> for Error { |
||||
fn from(err: ruma_client::Error) -> Error { |
||||
Error::RumaClientError(err) |
||||
} |
||||
} |
||||
|
||||
impl From<std::sync::mpsc::RecvError> for Error { |
||||
fn from(err: std::sync::mpsc::RecvError) -> Error { |
||||
Error::RecvError(err) |
||||
} |
||||
} |
||||
|
||||
fn bg_main<'a>( |
||||
tokio_handle: &'a TokioHandle, |
||||
command_chan_rx: futures::sync::mpsc::Receiver<Command>, |
||||
ui_dispatch_chan_tx: std::sync::mpsc::Sender<Box<Fn(>k::Builder) + Send>>, |
||||
) -> impl Future<Item = (), Error = Error> + 'a { |
||||
future::loop_fn(command_chan_rx, move |command_chan_rx| { |
||||
command_chan_rx |
||||
.into_future() |
||||
// Some sort of error occurred that is not the channel being closed?! Error type is (),
|
||||
// so it doesn't even impl Error. Assume this will never happen (for now).
|
||||
.map_err(|_| unreachable!()) |
||||
.and_then(|(opt_command, command_chan_rx)| match opt_command { |
||||
Some(command) => { |
||||
let (homeserver_url, connection_method) = match command { |
||||
Command::Connect { homeserver_url, connection_method } |
||||
=> (homeserver_url, connection_method), |
||||
//_ => unimplemented!(),
|
||||
}; |
||||
|
||||
Ok((homeserver_url, connection_method, command_chan_rx)) |
||||
} |
||||
None => Err(std::sync::mpsc::RecvError.into()), |
||||
}).and_then(move |(homeserver_url, connection_method, command_chan_rx)| { |
||||
let client = RumaClient::https(tokio_handle, homeserver_url, None).unwrap(); |
||||
|
||||
match connection_method { |
||||
ConnectionMethod::Login { username, password } => { |
||||
future::Either::A(client.log_in(username, password)) |
||||
} |
||||
ConnectionMethod::Guest => future::Either::B(client.register_guest()), |
||||
}.and_then(move |_| { |
||||
future::loop_fn((), move |_| { |
||||
use ruma_client::api::r0::sync::sync_events; |
||||
|
||||
sync_events::call(client.clone(), sync_events::Request { |
||||
filter: None, |
||||
since: None, |
||||
full_state: None, |
||||
set_presence: None, |
||||
timeout: None, |
||||
}).map(|res| { |
||||
println!("{:?}", res); |
||||
|
||||
Loop::Continue(()) |
||||
}) |
||||
}) |
||||
}).map_err(Error::from) |
||||
//.select(command_chan_rx.into_future())
|
||||
}) |
||||
}) |
||||
|
||||
/*ui_dispatch_chan_tx.send(box move |builder| {
|
||||
builder |
||||
.get_object::<gtk::Stack>("user_button_stack") |
||||
.expect("Can't find user_button_stack in ui file.") |
||||
.set_visible_child_name("user_connected_page"); |
||||
|
||||
builder |
||||
.get_object::<gtk::Label>("display_name_label") |
||||
.expect("Can't find display_name_label in ui file.") |
||||
.set_text("Guest"); |
||||
});*/ |
||||
} |
||||
|
||||
pub fn run( |
||||
command_chan_rx: futures::sync::mpsc::Receiver<Command>, |
||||
ui_dispatch_chan_tx: std::sync::mpsc::Sender<Box<Fn(>k::Builder) + Send>>, |
||||
) { |
||||
let mut core = TokioCore::new().unwrap(); |
||||
let tokio_handle = core.handle(); |
||||
|
||||
match core.run(bg_main(&tokio_handle, command_chan_rx, ui_dispatch_chan_tx)) { |
||||
Ok(_) => {} |
||||
Err(e) => { |
||||
// TODO: Show error message in UI. Quit / restart thread?
|
||||
eprintln!("ruma_gtk: background thread error: {:?}", e); |
||||
} |
||||
}; |
||||
} |
||||
@ -1,36 +1,16 @@
|
||||
#![feature(box_syntax)] |
||||
#![feature(conservative_impl_trait)] |
||||
|
||||
// not using this yet because rustfmt doesn't support it:
|
||||
// https://github.com/rust-lang-nursery/rustfmt/issues/1215
|
||||
//#![feature(field_init_shorthand)]
|
||||
|
||||
extern crate futures; |
||||
extern crate hyper; |
||||
extern crate gio; |
||||
extern crate gtk; |
||||
extern crate ruma_client; |
||||
extern crate tokio_core; |
||||
extern crate url; |
||||
// extern crate xdg;
|
||||
#[macro_use] |
||||
extern crate serde_derive; |
||||
|
||||
#[macro_use] |
||||
mod util; |
||||
|
||||
mod backend; |
||||
mod app; |
||||
mod bg_thread; |
||||
|
||||
use app::App; |
||||
// use std::fs::File;
|
||||
// use std::path::Path;
|
||||
|
||||
fn main() { |
||||
// let xdg_dirs = xdg::BaseDirectories::with_prefix("ruma_gtk").unwrap();
|
||||
// let data_path = xdg_dirs.place_data_file("data.yml").unwrap();
|
||||
// TODO: Read settings
|
||||
|
||||
fn main() { |
||||
let app = App::new(); |
||||
app.run(); |
||||
|
||||
// TODO: Save settings
|
||||
} |
||||
|
||||
Loading…
Reference in new issue