Removing ruma and renaming the project to Guillotine
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.
This commit is contained in:
parent
d9a7369df8
commit
98ba736040
8 changed files with 281 additions and 1464 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,2 +1,4 @@
|
|||
target
|
||||
*~
|
||||
*.swp
|
||||
*.swo
|
||||
|
|
1226
Cargo.lock
generated
1226
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
15
Cargo.toml
15
Cargo.toml
|
@ -1,19 +1,16 @@
|
|||
[package]
|
||||
authors = ["Jonas Platte <mail@jonasplatte.de>"]
|
||||
name = "ruma-gtk"
|
||||
authors = ["Daniel Garcia <danigm@wadobo.com>"]
|
||||
name = "guillotine"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
futures = "0.1.14"
|
||||
gio = "0.1.3"
|
||||
hyper = "0.11.1"
|
||||
tokio-core = "0.1.8"
|
||||
reqwest = "0.7.2"
|
||||
serde = "1.0.11"
|
||||
serde_derive = "1.0.11"
|
||||
serde_json = "1.0.2"
|
||||
url = "1.5.1"
|
||||
|
||||
[dependencies.gtk]
|
||||
features = ["v3_12"]
|
||||
version = "0.1.3"
|
||||
|
||||
[dependencies.ruma-client]
|
||||
git = "https://github.com/jplatte/ruma-client.git"
|
||||
branch = "synapse-workarounds"
|
||||
|
|
6
README.md
Normal file
6
README.md
Normal file
|
@ -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.
|
172
src/app.rs
172
src/app.rs
|
@ -1,29 +1,27 @@
|
|||
use std::{self, env, thread};
|
||||
use std::time::Duration;
|
||||
extern crate gtk;
|
||||
extern crate gio;
|
||||
|
||||
use std::env;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::mpsc::channel;
|
||||
use std::sync::mpsc::{Sender, Receiver};
|
||||
|
||||
use futures::{self, Sink};
|
||||
use gio;
|
||||
use gtk;
|
||||
use gtk::prelude::*;
|
||||
use url::Url;
|
||||
use self::gtk::prelude::*;
|
||||
|
||||
use backend::Backend;
|
||||
use backend;
|
||||
|
||||
use bg_thread::{self, Command, ConnectionMethod};
|
||||
|
||||
// TODO: Is this the correct format for GApplication IDs?
|
||||
const APP_ID: &'static str = "jplatte.ruma_gtk";
|
||||
const APP_ID: &'static str = "org.gnome.guillotine";
|
||||
|
||||
|
||||
struct AppLogic {
|
||||
struct AppOp {
|
||||
gtk_builder: gtk::Builder,
|
||||
|
||||
/// Sender for the matrix channel.
|
||||
///
|
||||
/// This channel is used to send commands to the background thread.
|
||||
command_chan_tx: futures::sink::Wait<futures::sync::mpsc::Sender<bg_thread::Command>>,
|
||||
backend: Backend,
|
||||
}
|
||||
|
||||
impl AppLogic {
|
||||
impl AppOp {
|
||||
pub fn login(&mut self) {
|
||||
let user_entry: gtk::Entry = self.gtk_builder.get_object("login_username").unwrap();
|
||||
let pass_entry: gtk::Entry = self.gtk_builder.get_object("login_password").unwrap();
|
||||
|
@ -32,8 +30,6 @@ impl AppLogic {
|
|||
let username = match user_entry.get_text() { Some(s) => s, None => String::from("") };
|
||||
let password = match pass_entry.get_text() { Some(s) => s, None => String::from("") };
|
||||
|
||||
println!("Login: {}, {}", username, password);
|
||||
|
||||
self.connect(username, password, server_entry.get_text());
|
||||
}
|
||||
|
||||
|
@ -43,19 +39,9 @@ impl AppLogic {
|
|||
None => String::from("https://matrix.org")
|
||||
};
|
||||
|
||||
let res = self.command_chan_tx
|
||||
.send(Command::Connect {
|
||||
homeserver_url: Url::parse(&server_url).unwrap(),
|
||||
connection_method: ConnectionMethod::Login {
|
||||
username: username,
|
||||
password: password,
|
||||
},
|
||||
});
|
||||
|
||||
match res {
|
||||
Ok(_) => {},
|
||||
Err(error) => println!("{:?}", error)
|
||||
}
|
||||
self.show_loading();
|
||||
self.backend.login(username, password, server_url).unwrap();
|
||||
self.hide_popup();
|
||||
}
|
||||
|
||||
pub fn connect_guest(&mut self, server: Option<String>) {
|
||||
|
@ -64,16 +50,44 @@ impl AppLogic {
|
|||
None => String::from("https://matrix.org")
|
||||
};
|
||||
|
||||
let res = self.command_chan_tx
|
||||
.send(Command::Connect {
|
||||
homeserver_url: Url::parse(&server_url).unwrap(),
|
||||
connection_method: ConnectionMethod::Guest
|
||||
});
|
||||
self.show_loading();
|
||||
self.backend.guest(server_url).unwrap();
|
||||
}
|
||||
|
||||
match res {
|
||||
Ok(_) => {},
|
||||
Err(error) => println!("{:?}", error)
|
||||
}
|
||||
pub fn get_username(&self) {
|
||||
self.backend.get_username().unwrap();
|
||||
}
|
||||
|
||||
pub fn set_username(&self, username: &str) {
|
||||
self.gtk_builder
|
||||
.get_object::<gtk::Label>("display_name_label")
|
||||
.expect("Can't find display_name_label in ui file.")
|
||||
.set_text(username);
|
||||
self.show_username();
|
||||
}
|
||||
|
||||
pub fn show_username(&self) {
|
||||
self.gtk_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");
|
||||
}
|
||||
|
||||
pub fn show_loading(&self) {
|
||||
self.gtk_builder
|
||||
.get_object::<gtk::Stack>("user_button_stack")
|
||||
.expect("Can't find user_button_stack in ui file.")
|
||||
.set_visible_child_name("user_loading_page");
|
||||
}
|
||||
|
||||
pub fn hide_popup(&self) {
|
||||
let user_menu: gtk::Popover = self.gtk_builder.get_object("user_menu")
|
||||
.expect("Couldn't find user_menu in ui file.");
|
||||
user_menu.hide();
|
||||
}
|
||||
|
||||
pub fn disconnect(&mut self) {
|
||||
println!("Disconnecting");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,18 +102,7 @@ pub struct App {
|
|||
/// Used to access the UI elements.
|
||||
gtk_builder: gtk::Builder,
|
||||
|
||||
/// Channel receiver which allows to run actions from the matrix connection thread.
|
||||
///
|
||||
/// Long polling is required to receive messages from the rooms and so they have to
|
||||
/// run in separate threads. In order to allow those threads to modify the gtk content,
|
||||
/// they will send closures to the main thread using this channel.
|
||||
ui_dispatch_chan_rx: std::sync::mpsc::Receiver<Box<Fn(>k::Builder) + Send>>,
|
||||
|
||||
/// Matrix communication thread join handler used to clean up the tread when
|
||||
/// closing the application.
|
||||
bg_thread_join_handle: thread::JoinHandle<()>,
|
||||
|
||||
logic: Arc<Mutex<AppLogic>>,
|
||||
op: Arc<Mutex<AppOp>>,
|
||||
}
|
||||
|
||||
impl App {
|
||||
|
@ -108,25 +111,37 @@ impl App {
|
|||
let gtk_app = gtk::Application::new(Some(APP_ID), gio::ApplicationFlags::empty())
|
||||
.expect("Failed to initialize GtkApplication");
|
||||
|
||||
let (tx, rx): (Sender<backend::BKResponse>, Receiver<backend::BKResponse>) = channel();
|
||||
|
||||
let gtk_builder = gtk::Builder::new_from_file("res/main_window.glade");
|
||||
let op = Arc::new(Mutex::new(
|
||||
AppOp{
|
||||
gtk_builder: gtk_builder.clone(),
|
||||
backend: Backend::new(tx),
|
||||
}
|
||||
));
|
||||
|
||||
let (command_chan_tx, command_chan_rx) = futures::sync::mpsc::channel(1);
|
||||
let command_chan_tx = command_chan_tx.wait();
|
||||
let theop = op.clone();
|
||||
gtk::timeout_add(500, move || {
|
||||
let recv = rx.try_recv();
|
||||
match recv {
|
||||
Ok(backend::BKResponse::Token(uid, _)) => {
|
||||
theop.lock().unwrap().set_username(&uid);
|
||||
theop.lock().unwrap().get_username();
|
||||
},
|
||||
Ok(backend::BKResponse::Name(username)) => {
|
||||
theop.lock().unwrap().set_username(&username);
|
||||
},
|
||||
Err(_) => { },
|
||||
};
|
||||
|
||||
// Create channel to allow the matrix connection thread to send closures to the main loop.
|
||||
let (ui_dispatch_chan_tx, ui_dispatch_chan_rx) = std::sync::mpsc::channel();
|
||||
|
||||
let bg_thread_join_handle =
|
||||
thread::spawn(move || bg_thread::run(command_chan_rx, ui_dispatch_chan_tx));
|
||||
|
||||
let logic = Arc::new(Mutex::new(AppLogic{ gtk_builder: gtk_builder.clone(), command_chan_tx }));
|
||||
gtk::Continue(true)
|
||||
});
|
||||
|
||||
let app = App {
|
||||
gtk_app,
|
||||
gtk_builder,
|
||||
ui_dispatch_chan_rx,
|
||||
bg_thread_join_handle,
|
||||
logic: logic.clone(),
|
||||
op: op.clone(),
|
||||
};
|
||||
|
||||
app.connect_gtk();
|
||||
|
@ -135,13 +150,17 @@ impl App {
|
|||
|
||||
pub fn connect_gtk(&self) {
|
||||
let gtk_builder = self.gtk_builder.clone();
|
||||
let logic = self.logic.clone();
|
||||
let op = self.op.clone();
|
||||
self.gtk_app.connect_activate(move |app| {
|
||||
// Set up shutdown callback
|
||||
let window: gtk::Window = gtk_builder.get_object("main_window")
|
||||
.expect("Couldn't find main_window in ui file.");
|
||||
|
||||
window.set_title("Guillotine");
|
||||
|
||||
let op_c = op.clone();
|
||||
window.connect_delete_event(clone!(app => move |_, _| {
|
||||
op_c.lock().unwrap().disconnect();
|
||||
app.quit();
|
||||
Inhibit(false)
|
||||
}));
|
||||
|
@ -158,8 +177,8 @@ impl App {
|
|||
// Login click
|
||||
let login_btn: gtk::Button = gtk_builder.get_object("login_button")
|
||||
.expect("Couldn't find login_button in ui file.");
|
||||
let logic_c = logic.clone();
|
||||
login_btn.connect_clicked(move |_| logic_c.lock().unwrap().login());
|
||||
let op_c = op.clone();
|
||||
login_btn.connect_clicked(move |_| op_c.lock().unwrap().login());
|
||||
|
||||
// Associate window with the Application and show it
|
||||
window.set_application(Some(app));
|
||||
|
@ -167,7 +186,7 @@ impl App {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn run(mut self) {
|
||||
pub fn run(self) {
|
||||
// Convert the args to a Vec<&str>. Application::run requires argv as &[&str]
|
||||
// and envd::args() returns an iterator of Strings.
|
||||
let args = env::args().collect::<Vec<_>>();
|
||||
|
@ -175,24 +194,9 @@ impl App {
|
|||
|
||||
// connecting as guest
|
||||
// TODO: Use stored user if exists
|
||||
self.logic.lock().unwrap().connect_guest(None);
|
||||
|
||||
// Poll the matrix communication thread channel and run the closures to allow
|
||||
// the threads to run actions in the main loop.
|
||||
let ui_dispatch_chan_rx = self.ui_dispatch_chan_rx;
|
||||
let gtk_builder = self.gtk_builder;
|
||||
gtk::idle_add(move || {
|
||||
if let Ok(dispatch_fn) = ui_dispatch_chan_rx.recv_timeout(Duration::from_millis(5)) {
|
||||
dispatch_fn(>k_builder);
|
||||
}
|
||||
|
||||
Continue(true)
|
||||
});
|
||||
self.op.lock().unwrap().connect_guest(None);
|
||||
|
||||
// Run the main loop.
|
||||
self.gtk_app.run(args_refs.len() as i32, &args_refs);
|
||||
|
||||
// Clean up
|
||||
self.bg_thread_join_handle.join().unwrap();
|
||||
}
|
||||
}
|
||||
|
|
175
src/backend.rs
Normal file
175
src/backend.rs
Normal file
|
@ -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(())
|
||||
}
|
||||
}
|
121
src/bg_thread.rs
121
src/bg_thread.rs
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
28
src/main.rs
28
src/main.rs
|
@ -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
|
||||
|
||||
let app = App::new();
|
||||
app.run();
|
||||
|
||||
// TODO: Save settings
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue