Commit 4f68acf2 authored by Paul Woolcock's avatar Paul Woolcock

fix a few operations

turns out, blocking the thread by waiting on a task that needs the
thread to not be blocked is not a good idea ¯\_(ツ)_/¯

not quite done un-f-ing all the functionality, but some of it is back
parent 2cedda73
Pipeline #59802806 failed with stage
in 1 minute and 34 seconds
......@@ -360,7 +360,7 @@ dependencies = [
[[package]]
name = "doc-comment"
version = "0.2.4"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
......@@ -375,11 +375,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "elefren"
version = "0.19.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
version = "0.19.3"
dependencies = [
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"doc-comment 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"doc-comment 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper-old-types 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"isolang 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"reqwest 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -456,7 +455,8 @@ dependencies = [
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"derive-new 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
"elefren 0.19.2 (registry+https://github.com/rust-lang/crates.io-index)",
"elefren 0.19.3",
"futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
"gumdrop 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"reqwest 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -2090,10 +2090,9 @@ dependencies = [
"checksum data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4f47ca1860a761136924ddd2422ba77b2ea54fe8cc75b9040804a0d9d32ad97"
"checksum derive-new 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6ca414e896ae072546f4d789f452daaecf60ddee4c9df5dc6d5936d769e3d87c"
"checksum derive_more 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fbe9f11be34f800b3ecaaed0ec9ec2e015d1d0ba0c8644c1310f73d6e8994615"
"checksum doc-comment 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d25034e821923087403f5d85c5a65b39450400e2f11cf63be27176123b5b7434"
"checksum doc-comment 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "923dea538cea0aa3025e8685b20d6ee21ef99c4f77e954a30febbaac5ec73a97"
"checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd"
"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b"
"checksum elefren 0.19.2 (registry+https://github.com/rust-lang/crates.io-index)" = "600c2d3c35ffcee912d2fc719951654b84977a3fdab24df3d9a7dfa72dc1bf4a"
"checksum encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)" = "4155785c79f2f6701f185eb2e6b4caf0555ec03477cb4c70db67b465311620ed"
"checksum enum-as-inner 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3d58266c97445680766be408285e798d3401c6d4c378ec5552e78737e681e37d"
"checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02"
......
......@@ -7,7 +7,8 @@ edition = "2018"
[dependencies]
tui = "0.5.1"
termion = "1.5.1"
elefren = "0.19"
# elefren = "0.19"
elefren = { path = "../elefren" }
unicode-width = "0.1.5"
soup = "0.3"
reqwest = "0.9"
......@@ -20,3 +21,4 @@ derive-new = "0.5"
toml = "0.5.0"
serde = "1.0.90"
serde_derive = "1.0.90"
futures = "0.1.26"
......@@ -2,6 +2,7 @@ use actix::prelude::*;
use derive_new::new;
use elefren::status_builder::StatusBuilder;
use snafu::{ResultExt, Snafu};
use futures::future::{self, Future};
use crate::{client, logger, repo};
......@@ -23,15 +24,14 @@ impl Error {
#[derive(new)]
pub struct Channel(Addr<Action>, logger::Channel);
impl Channel {
pub fn input_async(&self, s: String) -> Result<(), Error> {
pub fn input(&self, s: String) -> Box<Future<Item=Result<(), Error>, Error=Error>> {
self.1.log(format!("got input '{}'", &s));
self.0.do_send(Wrapper(s));
Ok(())
Box::new(self.0.send(Wrapper(s)).map_err(|e| Error::MailboxError { source: e }))
}
}
#[derive(Debug)]
struct Wrapper(String);
pub struct Wrapper(pub String);
impl From<Wrapper> for String {
fn from(w: Wrapper) -> String {
w.0
......@@ -54,16 +54,29 @@ impl Actor for Action {
fn started(&mut self, _: &mut Context<Self>) {
self.logger.log("Action actor starting");
}
fn stopping(&mut self, _: &mut Context<Self>) -> actix::Running {
self.logger.log("Action actor stopping");
actix::Running::Stop
}
fn stopped(&mut self, _: &mut Context<Self>) {
self.logger.log("Action actor stopped");
}
}
impl Handler<Wrapper> for Action {
type Result = Result<(), Error>;
type Result = Box<Future<Item=(), Error=Error>>;
fn handle(&mut self, msg: Wrapper, _ctx: &mut Context<Self>) -> Self::Result {
self.logger.log(format!("got input {}", msg.0));
let request = parse_post(msg.into(), &self.logger)?;
self.logger.log(format!("handling message {:?}", msg));
let request = match parse_post(msg.into(), &self.logger) {
Ok(r) => r,
Err(e) => return Box::new(future::err(e)),
};
self.logger.log(format!("parsed input is {:?}", request));
match request {
/*
message::Request::Post(post) => {
let vis = self.repo.get_vis().context(RepoError)?;
let status = StatusBuilder {
......@@ -91,11 +104,15 @@ impl Handler<Wrapper> for Action {
self.client.favourite(&post.id).context(ClientError)?;
}
*/
message::Request::ShowMore(ref id) => {
self.repo.show_more(id).context(RepoError)?;
Box::new(self.repo.show_more(id).map_err(|e| Error::RepoError { source: e }))
}
/*
message::Request::Reply(id, content) => {
self.logger.log("About to contact repo");
let entry = self.repo.get(&id).context(RepoError)?;
self.logger.log(format!("got entry {:?}", entry));
let post = entry.status();
let content = format!("@{} {}", &post.account.acct, content);
let status = StatusBuilder {
......@@ -107,18 +124,32 @@ impl Handler<Wrapper> for Action {
};
self.client.new_status(status).context(ClientError)?;
}
message::Request::SetVis(vis) => {
self.repo.set_vis(vis).context(RepoError)?;
}
*/
message::Request::Block(user) => {
self.client.block(user).context(ClientError)?;
Box::new(
self.client
.block(user)
.map_err(|e| Error::ClientError { source: e })
.map(|_| ())
)
}
message::Request::SetVis(vis) => {
Box::new(
self.repo
.set_vis(vis)
.map_err(|e| Error::RepoError { source: e })
.map(|_| ())
)
}
message::Request::Quit => {
self.logger.log("Got message to quit");
System::current().stop();
Box::new(future::ok(()))
}
_ => {
Box::new(future::ok(()))
}
}
Ok(())
}
}
......
......@@ -68,31 +68,38 @@ impl Handler<message::Request> for Client {
self.logger.log(format!("blocking user {}", user));
let search = self.client.search_v2(user, true).context(ElefrenError)?;
let account = if search.accounts.is_empty() {
self.logger.log("Couldn't fitnd account");
return Err(Error::custom(format!("Could not find account '{}'", user)));
} else if search.accounts.len() > 1 {
match find_account(&user, &search.accounts) {
self.logger.log("Found more than one account");
match find_account(&user, &search.accounts, &self.logger) {
Some(account_idx) => &search.accounts[account_idx],
None => return Err(Error::custom(format!("Could not find account '{}'", user))),
}
} else {
self.logger.log(format!("found single account {:?}", &search.accounts[0]));
&search.accounts[0]
};
self.client.block(&account.id).context(ElefrenError)?;
if let Err(e) = self.client.block(&account.id) {
self.logger.log(format!("couldn't block account, error was {:?}", e));
}
message::Response::Empty
}
})
}
}
fn find_account(user: &str, accounts: &[elefren::entities::account::Account]) -> Option<usize> {
fn find_account(user: &str, accounts: &[elefren::entities::account::Account], logger: &logger::Channel) -> Option<usize> {
let mut parts = user.splitn(2, '@');
let username = parts.next()?;
for (i, account) in accounts.iter().enumerate() {
// special case: the account to be blocked is on the same server as the logged-in user
if account.acct == username {
logger.log(format!("returning user {:?}", &account.acct));
return Some(i);
}
if account.acct == user {
logger.log(format!("returning user {:?}", &account.acct));
return Some(i);
}
}
......@@ -176,13 +183,17 @@ impl Channel {
}
}
pub fn block(&self, user: String) -> Result<(), Error> {
let fut = self.0.send(message::Request::Block(user));
pub fn block(&self, user: String) -> impl Future<Item=(), Error=Error> {
self.0.send(message::Request::Block(user))
.map_err(|e: actix::MailboxError| Error::MailboxError { source: e })
.map(|_| ())
/*
let resp = fut.wait().context(MailboxError)?;
if let message::Response::Empty = resp? {
Ok(())
} else {
Err(Error::WrongResponse)
}
*/
}
}
......@@ -57,6 +57,10 @@ fn register(config: &str, server: &str) -> Result<elefren::Data> {
helpers::cli,
prelude::*,
};
if server.trim().is_empty() {
eprintln!("a server must be provided in order to authenticate");
::std::process::exit(1);
}
Ok(match config::Config::from_file(config) {
Ok(t) => t.client,
Err(..) => {
......@@ -115,12 +119,13 @@ fn main() -> Result<()> {
let (ui_repo, ui_logger) = (repo.clone(), logger.clone());
let input_logger = logger.clone();
let action_logger = logger::Channel::with_ctx(logger.clone(), "ActionChannel".to_string());
let ui_action = action.clone();
let ui = Supervisor::start_in_arbiter(&ui_arbiter, move |_| {
Ui::new(
terminal,
ui_repo,
logger::Channel::with_ctx(ui_logger, "UI".to_string()),
action::Channel::new(action.clone(), action_logger),
action::Channel::new(ui_action, action_logger),
)
});
Supervisor::start_in_arbiter(&input_arbiter, move |_| {
......
......@@ -114,6 +114,7 @@ impl Handler<message::Request> for Repo {
}
message::Request::GetVis => message::Response::Vis(self.vis.clone()),
message::Request::SetVis(vis) => {
self.logger.log("got SetVis message");
self.vis = vis;
message::Response::Vis(self.vis.clone())
}
......@@ -166,14 +167,13 @@ impl Channel {
}
}
pub fn show_more(&self, id: &str) -> Result<(), Error> {
pub fn show_more(&self, id: &str) -> Box<Future<Item=(), Error=Error>> {
let fut = self.0.send(message::Request::ShowMore(id.to_string()));
let resp = fut.wait().context(MailboxError)?;
if let message::Response::Empty = resp? {
Ok(())
} else {
Err(Error::WrongResponse)
}
let fut = fut.map_err(|e| Error::MailboxError { source: e});
let fut = fut.map(|e: Result<message::Response, Error>| { // TODO needs to be handled
()
});
Box::new(fut)
}
pub fn get_vis(&self) -> Result<Visibility, Error> {
......@@ -186,14 +186,17 @@ impl Channel {
}
}
pub fn set_vis(&self, visibility: Visibility) -> Result<Visibility, Error> {
let fut = self.0.send(message::Request::SetVis(visibility));
let resp = fut.wait().context(MailboxError)?;
if let message::Response::Vis(visibility) = resp? {
Ok(visibility)
} else {
Err(Error::WrongResponse)
}
pub fn set_vis(&self, visibility: Visibility) -> Box<Future<Item=Visibility, Error=Error>> {
Box::new(self.0.send(message::Request::SetVis(visibility))
.map_err(|e: actix::MailboxError| Error::MailboxError{ source: e })
.and_then(|res: Result<message::Response, Error>| {
match res {
Ok(message::Response::Vis(vis)) => Ok(vis),
Ok(..) => Err(Error::WrongResponse),
Err(e) => Err(e),
}
})
)
}
}
......
use actix::prelude::*;
use actix::utils::IntervalFunc;
use snafu::{ResultExt, Snafu};
use snafu::Snafu;
use std::{io::{self, Write}, time::Duration};
use termion::cursor::Goto;
......@@ -14,6 +14,7 @@ use tui::{
Terminal,
};
use unicode_width::UnicodeWidthStr;
use futures::future::{self, Future};
use crate::{action, logger, repo};
......@@ -110,27 +111,30 @@ impl actix::Supervised for Ui {
}
impl Handler<message::Request> for Ui {
type Result = Result<(), Error>;
type Result = Box<Future<Item=(), Error=Error>>;
fn handle(&mut self, msg: message::Request, _: &mut Context<Self>) -> Self::Result {
Ok(match msg {
match msg {
message::Request::Push(c) => {
self.input.push(c);
Box::new(future::ok(()))
},
message::Request::Pop => {
self.input.pop();
Box::new(future::ok(()))
},
message::Request::Drain => {
self.logger.log("Got drain message");
let input = self.input.drain(..).collect::<String>();
self.logger.log(format!("sending input '{}' to Action actor", &input));
if let Err(e) = self.action.input_async(input).context(ActionError) {
self.logger.log(format!("Got error from action channel: {:?}", e.error));
} else {
};
Box::new(
self.action.input(input)
.map(|_| ()) // TODO the value coming in here is Result<(), action::Error>,
// and the error really needs to be handled
.map_err(|e| Error::ActionError { source: e })
)
}
})
}
}
}
......@@ -148,83 +152,3 @@ pub mod message {
type Result = Result<(), Error>;
}
}
/*
use crossbeam::Sender;
use std::{
default::Default,
io::{self, Write},
};
use crate::error::Result;
use crate::event::{Event, Events};
use crate::{logger, repo};
#[derive(Debug, Default, Clone, PartialEq)]
struct ChatState {
input: String,
}
pub fn run(sender: Sender<String>, repo: repo::Channel, logger: logger::Channel) -> Result<!> {
logger.log("Initializing UI");
let stdout = io::stdout().into_raw_mode()?;
let stdout = AlternateScreen::from(stdout);
let backend = TermionBackend::new(stdout);
let mut terminal = Terminal::new(backend)?;
let mut chat_state = ChatState::default();
let events = Events::new();
loop {
terminal.draw(|mut f| {
let vis = if let Ok(vis) = repo.get_vis() {
vis
} else {
return;
};
let title = format!("TOOT - {:?}", vis);
let chunks = Layout::default()
.direction(Direction::Vertical)
.margin(2)
.constraints([Constraint::Length(3), Constraint::Min(1)].as_ref())
.split(f.size());
Paragraph::new([Text::raw(&chat_state.input)].iter())
.style(Style::default().fg(Color::Yellow))
.block(Block::default().borders(Borders::ALL).title(&title))
.render(&mut f, chunks[0]);
let list_height = chunks[1].height as usize;
let statuses = if let Ok(statuses) = repo.get_latest(list_height) {
statuses
} else {
return;
};
let statuses = statuses
.iter()
.map(|status| Text::raw(format!("{}", status)));
List::new(statuses)
.block(Block::default().borders(Borders::ALL).title("FEED"))
.render(&mut f, chunks[1]);
})?;
write!(
terminal.backend_mut(),
"{}",
Goto(4 + chat_state.input.width() as u16, 4)
)?;
match events.next()? {
Event::Input(input) => match input {
Key::Char('\n') => {
let input = chat_state.input.drain(..).collect::<String>();
sender.send(input)?;
}
Key::Char(c) => {
chat_state.input.push(c);
}
Key::Backspace => {
chat_state.input.pop();
}
_ => {}
},
_ => {}
}
}
}
*/
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment