Cleanup & Fixes

This commit is contained in:
Bommels05 2025-02-05 18:36:16 +01:00
parent 340b8db1b9
commit 68de25838c
6 changed files with 510 additions and 765 deletions

View File

@ -1,4 +1,5 @@
[workspace]
resolver = "3"
members = [ "bankcli","banklib"]
[workspace.package]

View File

@ -17,6 +17,7 @@ clap.workspace = true
url.workspace = true
lalrpop-util = "0.22.1"
error-stack.workspace = true
flume.workspace = true
[build-dependencies]
lalrpop = "0.22.1"

View File

@ -1,21 +1,18 @@
use std::future::pending;
use banklib::{AuthenticatedMessage, BankClient, BankError, BankResult, Response};
use banklib::config::{load_config, save_config};
use banklib::extended::{Client, Credentials, State};
use banklib::{AuthenticatedMessage, BankClient, BankError, BankResult, ClientAction, Response, ResponseMessage};
use clap::Parser;
use std::ops::{Add, Deref};
use std::time::Duration;
use std::io;
use std::io::BufRead;
use std::thread::yield_now;
use error_stack::{report, Report};
use tokio::io::BufReader;
use flume::Receiver;
use std::io::stdin;
use std::ops::Add;
use std::time::Duration;
use std::thread;
use tokio::select;
use tokio::task::JoinHandle;
use tracing::metadata::LevelFilter;
use tracing::{error, info, warn};
use tracing_subscriber::EnvFilter;
use url::Url;
use banklib::config::{load_config, save_config};
use banklib::extended::{Client, Credentials, State};
#[derive(Debug, Parser)]
struct Args {
@ -62,7 +59,8 @@ async fn main() {
url = arg;
} else {
if !config.server.last_server.is_empty() && config.general.use_last_server {
url = Url::parse(&config.server.last_server).expect("Invalid last server url in config");
url =
Url::parse(&config.server.last_server).expect("Invalid last server url in config");
} else {
error!("Cannot use last server url - You need to provide one using --url");
return;
@ -70,19 +68,31 @@ async fn main() {
}
let client = BankClient::connect(url.clone()).await;
let mut client = Client { client, config, state: State::default() };
let mut client = Client {
client,
config,
state: State::default(),
};
client.config.server.last_server = url.to_string();
save_config(&client.config);
if client.config.general.use_default_account {
let password = client.config.accounts.accounts.get(&client.config.accounts.default_account);
let password = client
.config
.accounts
.accounts
.get(&client.config.accounts.default_account);
if let Some(password) = password {
let username = client.config.accounts.default_account.clone();
let password = password.clone();
try_login(&mut client, Credentials { password, username }).await;
}
} else if client.config.general.use_last_account {
let password = client.config.accounts.accounts.get(&client.config.accounts.last_account);
let password = client
.config
.accounts
.accounts
.get(&client.config.accounts.last_account);
if let Some(password) = password {
let username = client.config.accounts.last_account.clone();
let password = password.clone();
@ -90,8 +100,139 @@ async fn main() {
}
}
let lines = read_lines();
let messages = client.client.receiver_msg().clone();
let actions = client.client.receiver_act().clone();
for _ in actions.try_iter() {}
loop {
let line = read_line(Some(&mut client)).await;
select! {
Ok(line) = lines.recv_async() => {
if handle_line(&mut client, &lines, line).await {
break;
}
},
Ok(message) = messages.recv_async() => {
handle_message(&mut client, message).await;
},
Ok(action) = actions.recv_async() => {
handle_action(&mut client, action).await;
},
}
}
tokio::time::sleep(Duration::from_secs(2)).await;
}
async fn try_login(client: &mut Client, credentials: Credentials) -> bool {
let result = client.login(credentials).await;
if let Err(error) = &result {
match error.current_context() {
BankError::AuthenticationError => {
if let Some(last_credentials) = &client.state.last_credentials {
let result = client.login(last_credentials.clone()).await;
if result.is_err() {
info!("Error login in with old credentials - You may need to enter a new username and password");
}
}
}
_ => handle_error(&result),
}
} else {
return true;
}
false
}
async fn setup_new_account(client: &mut Client, rx: &Receiver<String>, credentials: Credentials, old_credentials: Option<Credentials>) {
if !client.config.accounts.default_account.eq(&credentials.username) {
if ask_confirmation(rx, "Do you want to make this account your default account?").await {
client.config.accounts.default_account = credentials.username.clone();
}
}
if !ask_confirmation(rx, "Do you want to use this account now?").await {
if let Some(old_credentials) = old_credentials {
if !old_credentials.eq(&credentials) {
let result = client.login(old_credentials).await;
if result.is_err() {
info!("Error logging in with old credentials - You may need to enter a new username and password");
}
} else {
handle_error(&client.logout().await);
}
} else {
handle_error(&client.logout().await);
}
}
}
fn read_lines() -> Receiver<String> {
let (tx, rx) = flume::bounded::<String>(16);
thread::spawn(move || {
let mut input = stdin().lines();
while let Some(line) = input.next() {
match line {
Ok(line) => {
tx.send(line).unwrap();
}
Err(err) => {
error!("\n{:#?}", Report::new(err));
break;
}
}
}
});
rx
}
async fn ask_confirmation(rx: &Receiver<String>, prompt: &str) -> bool {
println!("{} (y/n): ", prompt);
let answer = rx.recv_async().await.unwrap();
answer.as_str() == "y"
}
fn try_parse_bool(value: Option<&str>) -> Result<bool, ()> {
let parsed = value.unwrap().parse();
if !parsed.is_ok() {
println!("The value needs to be true or false");
}
parsed.map_err(|_| ())
}
async fn expect_credentials(mut split: std::str::Split<'_, char>, client: &mut Client, try_last_login: bool) -> Option<Credentials> {
let username = split.next();
let password = split.next();
if username.is_none() || password.is_none() {
if try_last_login {
if let Some(last_credentials) = &client.state.last_credentials {
let result = client.login(last_credentials.clone()).await;
if result.is_err() {
info!("Error login in with old credentials - You may need to enter a new username and password");
}
} else {
info!("You need to enter a username and password");
}
}
None
} else {
let username: String = username.unwrap().into();
let password: String = password.unwrap().into();
Some(Credentials { username, password })
}
}
fn handle_error<T>(result: &BankResult<T, BankError>) {
if let Err(error) = result {
print_error(error)
}
}
fn print_error(error: &Report<BankError>) {
//error!("\n{:?}", error);
error!("{}", error.as_error().to_string());
}
async fn handle_line(client: &mut Client, rx: &Receiver<String>, line: String) -> bool {
let mut split = line.split(' ');
let command: &str = split.next().unwrap();
@ -99,25 +240,28 @@ async fn main() {
"account" => {
let argument = split.next().or(Some("")).unwrap();
if argument == "add" {
let credentials = expect_credentials(split, &mut client, false).await;
let credentials = expect_credentials(split, client, false).await;
if let Some(credentials) = credentials {
client.config.accounts.accounts.insert(credentials.username.clone(), credentials.password.clone());
if client.config.accounts.default_account.is_empty() {
client.config.accounts.default_account = credentials.username.clone();
}
save_config(&client.config);
if ask_confirmation("Do you want to test the account now?").await {
if ask_confirmation(rx, "Do you want to test the account now?").await {
let old_credentials = client.state.last_credentials.clone();
let success = try_login(&mut client, credentials.clone()).await;
let success = try_login(client, credentials.clone()).await;
if success {
setup_new_account(&mut client, credentials.clone(), old_credentials).await;
setup_new_account(client, rx, credentials.clone(), old_credentials).await;
} else {
if ask_confirmation("The login was not successful - Do you want to register this account instead?").await {
if ask_confirmation(rx, "The login was not successful - Do you want to register this account instead?").await {
let result = client.register(credentials.clone()).await;
if let Some(last_credentials) = &client.state.last_credentials {
handle_error(&client.client.set_credentials(last_credentials.username.clone(), last_credentials.password.clone()));
}
if result.is_ok() {
let result = client.login(credentials.clone()).await;
if result.is_ok() {
setup_new_account(&mut client, credentials, old_credentials).await;
setup_new_account(client, rx, credentials, old_credentials).await;
} else {
handle_error(&result);
warn!("The login was not successful but the account was most likely still registered - Please try to login again")
@ -135,7 +279,7 @@ async fn main() {
let username: &str = split.next().or(Some("")).unwrap();
if client.config.accounts.accounts.contains_key(username) {
let password = client.config.accounts.accounts.get(username).unwrap().clone();
try_login(&mut client, Credentials { username: username.into(), password }).await;
try_login(client, Credentials { username: username.into(), password }).await;
} else {
println!("You need to enter a valid username")
}
@ -175,34 +319,33 @@ async fn main() {
let setting = split.next();
let value = split.next();
if setting.is_some() && value.is_some() {
{
match setting.unwrap() {
"show_motd_after_login" => {
if let Ok(value) = try_parse_bool(value) {
client.config.general.show_motd_after_login = value;
} else {
break;
return false;
}
}
"show_inbox_count_after_login" => {
if let Ok(value) = try_parse_bool(value) {
client.config.general.show_inbox_count_after_login = value;
} else {
break;
return false;
}
}
"show_pm_inbox_count_after_login" => {
if let Ok(value) = try_parse_bool(value) {
client.config.general.show_pm_inbox_count_after_login = value;
} else {
break;
return false;
}
}
"show_balance_after_payment" => {
if let Ok(value) = try_parse_bool(value) {
client.config.general.show_balance_after_payment = value;
} else {
break;
return false;
}
}
"use_default_account" => {
@ -212,7 +355,7 @@ async fn main() {
client.config.general.use_last_account = false;
}
} else {
break;
return false;
}
}
"use_last_account" => {
@ -222,68 +365,42 @@ async fn main() {
client.config.general.use_default_account = false;
}
} else {
break;
return false;
}
}
"use_last_server" => {
if let Ok(value) = try_parse_bool(value) {
client.config.general.use_last_server = value;
} else {
break;
return false;
}
}
_ => {
error!("Invalid setting")
}
_ => { error!("Invalid setting") }
}
info!("Setting changed");
save_config(&client.config);
}
} else {
println!("You need to enter a setting and value");
}
} else if argument == "list" {
println!("--- Settings ---");
println!(
"show_motd_after_login: {}",
client.config.general.show_motd_after_login
);
println!(
"show_inbox_count_after_login: {}",
client.config.general.show_inbox_count_after_login
);
println!(
"show_pm_inbox_count_after_login: {}",
client.config.general.show_pm_inbox_count_after_login
);
println!(
"show_balance_after_payment: {}",
client.config.general.show_balance_after_payment
);
println!(
"use_default_account: {}",
client.config.general.use_default_account
);
println!(
"use_last_account: {}",
client.config.general.use_last_account
);
println!(
"use_last_server: {}",
client.config.general.use_last_server
);
println!("show_motd_after_login: {}", client.config.general.show_motd_after_login);
println!("show_inbox_count_after_login: {}", client.config.general.show_inbox_count_after_login);
println!("show_pm_inbox_count_after_login: {}", client.config.general.show_pm_inbox_count_after_login);
println!("show_balance_after_payment: {}", client.config.general.show_balance_after_payment);
println!("use_default_account: {}", client.config.general.use_default_account);
println!("use_last_account: {}", client.config.general.use_last_account);
println!("use_last_server: {}", client.config.general.use_last_server);
} else if argument == "help" {
println!("--- Available Commands ---");
println!(
"settings set <setting> <value> - Set a setting to the specified value"
);
println!("settings set <setting> <value> - Set a setting to the specified value");
println!("settings list - List all settings");
} else {
println!("Invalid subcommand! Use settings help for a list of valid subcommands");
}
}
"register" => {
let credentials = expect_credentials(split, &mut client, true).await;
let credentials = expect_credentials(split, client, true).await;
if let Some(credentials) = credentials {
let result = client.register(credentials.clone()).await;
if let Some(last_credentials) = &client.state.last_credentials {
@ -293,23 +410,23 @@ async fn main() {
match error.current_context() {
BankError::AuthenticationError => {
error!("Username is already taken");
if ask_confirmation("Do you want to login instead?").await {
try_login(&mut client, credentials).await;
if ask_confirmation(rx, "Do you want to login instead?").await {
try_login(client, credentials).await;
}
}
_ => print_error(&error)
_ => print_error(&error),
}
} else {
if ask_confirmation("Do you want to login with your new account?").await {
try_login(&mut client, credentials).await;
if ask_confirmation(rx, "Do you want to login with your new account?").await {
try_login(client, credentials).await;
}
}
}
}
"login" => {
let credentials = expect_credentials(split, &mut client, true).await;
let credentials = expect_credentials(split, client, true).await;
if let Some(credentials) = credentials {
try_login(&mut client, credentials).await;
try_login(client, credentials).await;
}
}
"balance" => {
@ -417,7 +534,7 @@ async fn main() {
}
client.client.close("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nBefator verabschiedet sich!\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n".into());
save_config(&client.config);
break;
return true;
}
"spam" => {
for _ in 0..100 {
@ -459,67 +576,15 @@ async fn main() {
println!("help [extended] - See a (extended) list of commands");
}
}
_ => {
println!("Unknown command - Use help for a list of commands")
}
}
_ => { println!("Unknown command - Use help for a list of commands") }
}
tokio::time::sleep(Duration::from_secs(3)).await;
}
async fn try_login(client: &mut Client, credentials: Credentials) -> bool {
let result = client.login(credentials).await;
if let Err(error) = &result {
match error.current_context() {
BankError::AuthenticationError => {
if let Some(last_credentials) = &client.state.last_credentials {
let result = client.login(last_credentials.clone()).await;
if result.is_err() {
info!("Error login in with old credentials - You may need to enter a new username and password");
}
}
}
_ => handle_error(&result)
}
} else {
return true;
}
false
}
async fn setup_new_account(client: &mut Client, credentials: Credentials, old_credentials: Option<Credentials>) {
if !client.config.accounts.default_account.eq(&credentials.username) {
if ask_confirmation("Do you want to make this account your default account?").await {
client.config.accounts.default_account = credentials.username.clone();
}
}
if !ask_confirmation("Do you want to use this account now?").await {
if let Some(old_credentials) = old_credentials {
if !old_credentials.eq(&credentials) {
let result = client.login(old_credentials).await;
if result.is_err() {
info!("Error logging in with old credentials - You may need to enter a new username and password");
}
} else {
handle_error(&client.logout().await);
}
} else {
handle_error(&client.logout().await);
}
}
}
async fn read_line(client: Option<&Client>) -> String {
let mut thread: Option<JoinHandle<_>> = None;
if let Some(client) = client {
thread = Some(tokio::spawn(async move {
/*loop {
if let Ok(message) = client.client.receiver().recv() {
match message.message {
Response::DisplayMessage { message, id, .. } => {
match id.as_str() {
async fn handle_message(client: &mut Client, response: ResponseMessage) {
match response.clone().message {
Response::DisplayMessage { message, id, .. } => match id.as_str() {
"pay.received" => {
println!("{}", message);
if client.config.general.show_balance_after_payment {
@ -534,70 +599,20 @@ async fn read_line(client: Option<&Client>) -> String {
"pm_inbox.received" => {
println!("{}", message);
}
_ => { print_error(&report!(BankError::UnexpectedMessage)); }
}
}
_ => { print_error(&report!(BankError::UnexpectedMessage)); }
}
}
}*/
}));
}
let mut line = String::new();
io::stdin().read_line(&mut line).unwrap();
let result = line.replace("\n", "").replace("\r", "");
if let Some(thread) = thread {
thread.abort();
}
result
}
async fn ask_confirmation(prompt: &str) -> bool {
println!("{} (y/n): ", prompt);
let answer = read_line(None).await;
answer.as_str() == "y"
}
fn try_parse_bool(value: Option<&str>) -> Result<bool, ()> {
let parsed = value.unwrap().parse();
if !parsed.is_ok() {
println!("The value needs to be true or false");
}
parsed.map_err(|_| ())
}
async fn expect_credentials(
mut split: std::str::Split<'_, char>,
client: &mut Client,
try_last_login: bool,
) -> Option<Credentials> {
let username = split.next();
let password = split.next();
if username.is_none() || password.is_none() {
if try_last_login {
if let Some(last_credentials) = &client.state.last_credentials {
let result = client.login(last_credentials.clone()).await;
if result.is_err() {
info!("Error login in with old credentials - You may need to enter a new username and password");
}
} else {
info!("You need to enter a username and password");
}
}
None
} else {
let username: String = username.unwrap().into();
let password: String = password.unwrap().into();
Some(Credentials { username, password })
_ => { print_error(&report!(BankError::UnexpectedMessage(response))); }
},
_ => { print_error(&report!(BankError::UnexpectedMessage(response))); }
}
}
fn handle_error<T>(result: &BankResult<T, BankError>) {
if let Err(error) = result {
print_error(error)
async fn handle_action(client: &mut Client, action: ClientAction) {
match action {
ClientAction::Connected => {
if client.state.logged_in {
client.state.logged_in = false;
handle_error(&client.login(client.state.last_credentials.clone().unwrap()).await);
}
}
fn print_error(error: &Report<BankError>) {
error!("\n{:?}", error);
ClientAction::Disconnected => {}
}
}

View File

@ -23,11 +23,12 @@ pub mod config;
pub struct BankClient {
client: Client<Handler>,
rx: Receiver<ResponseMessage>,
rx_msg: Receiver<ResponseMessage>,
rx_act: Receiver<ClientAction>,
handle: JoinHandle<Result<(), Box<dyn std::error::Error + Send + Sync>>>
}
#[derive(Error, Debug)]
#[derive(Error, Debug, Clone)]
pub enum BankError {
#[error("Request timed out")]
TimedOut,
@ -41,8 +42,8 @@ pub enum BankError {
DestinationUnknown,
#[error("You don't have enough Steam Coins")]
NotEnoughMoney,
#[error("Unknown unexpected message received")]
UnexpectedMessage
#[error("Unknown unexpected message received {_0:?}")]
UnexpectedMessage(ResponseMessage)
}
pub type BankResult<T, E = BankError> = error_stack::Result<T, E>;
@ -52,42 +53,38 @@ impl BankClient {
let url = url.into();
let client_config = ClientConfig::new(url);
let random: u8 = random();
let (tx, rx) = flume::unbounded();
let (tx_msg, rx_msg) = flume::unbounded();
let (tx_act, rx_act) = flume::unbounded();
let (client, future) = ezsockets::connect(
move |client| Handler {
client,
tx,
tx_msg,
tx_act,
username: String::new(),
password: String::new(),
id: random as i32,
receivers: VecDeque::new(),
},
client_config,
}, client_config,
).await;
let handle = tokio::spawn(future);
Self {
client,
rx,
handle,
Self { client, rx_msg, rx_act, handle }
}
}
pub async fn send_authenticated(
&self,
message: AuthenticatedMessage,
accept: fn(&ResponseMessage) -> bool,
) -> BankResult<Response> {
pub async fn send_authenticated(&self, message: AuthenticatedMessage, accept: fn(&ResponseMessage) -> bool) -> BankResult<Response> {
self.check_running()?;
let (tx, rx) = oneshot::channel();
self.client.call(ClientCommand::SendAuthenticatedNew {message, accept, tx}).map_err(|_| report!(BankError::InternalError))?;
tokio::time::timeout(Duration::from_secs(2), rx.into_future()).await.map_err(|_| report!(BankError::TimedOut))?.map_err(|_| report!(BankError::InternalError))?.map_err(|err| report!(err))
tokio::time::timeout(Duration::from_secs(5), rx.into_future()).await.map_err(|_| report!(BankError::TimedOut))?.map_err(|_| report!(BankError::InternalError))?.map_err(|err| report!(err))
}
pub fn set_credentials(&self, username: String, password: String) -> BankResult<()> {
self.client.call(ClientCommand::ChangeCredentials {username, password}).map_err(|_| report!(BankError::InternalError))
}
pub fn receiver(&self) -> &Receiver<ResponseMessage> {
&self.rx
pub fn receiver_msg(&self) -> &Receiver<ResponseMessage> {
&self.rx_msg
}
pub fn receiver_act(&self) -> &Receiver<ClientAction> {
&self.rx_act
}
fn check_running(&self) -> BankResult<(), BankError>{
@ -108,22 +105,11 @@ impl BankClient {
struct Handler {
client: Client<Handler>,
//config: Arc<Mutex<Config>>,
tx: Sender<ResponseMessage>,
tx_msg: Sender<ResponseMessage>,
tx_act: Sender<ClientAction>,
username: String,
password: String,
//last_username: String,
//last_password: String,
id: i32,
//logged_in: bool,
/*message_queue: VecDeque<(
AuthenticatedMessage,
Box<dyn Future<Output = ()> + Send + Unpin>,
)>,
send_time: SystemTime,
retry_count: u8,
inbox_message_count: u8,
pm_message_count: u8,*/
receivers: VecDeque<(fn(&ResponseMessage) -> bool, oneshot::Sender<Result<Response, BankError>>)>
}
@ -135,34 +121,7 @@ impl Handler {
}
}
/*fn last_credentials(&self) -> Credentials {
Credentials {
username: &self.last_username,
password: &self.last_password,
}
}*/
/*fn send_authenticated(&mut self, message: AuthenticatedMessage) {
self.send_authenticated_callback(message);
}*/
/*fn send_authenticated_callback(
&mut self,
message: AuthenticatedMessage,
callback: Box<dyn Future<Output = ()> + Send + Unpin>,
) {
if self.message_queue.is_empty() {
self.send_authenticated_now(message, callback);
} else {
self.message_queue.push_back((message, callback));
}
}*/
fn send_authenticated(
&mut self,
message: AuthenticatedMessage,
//callback: Box<dyn Future<Output = ()> + Send + Unpin>,
) {
fn send_authenticated(&mut self, message: AuthenticatedMessage) {
#[derive(Serialize)]
struct WithCredentials<'a> {
#[serde(flatten)]
@ -172,40 +131,20 @@ impl Handler {
id: i32,
}
/*if message == AuthenticatedMessage::Authenticate && self.logged_in {
self.send_authenticated_now(AuthenticatedMessage::Logout, Box::new(Box::pin(async {})));
self.send_authenticated(message);
return;
}*/
//self.send_time = SystemTime::now();
//self.message_queue.push_front((message.clone(), callback));
debug!("Sending: {message:?}");
let credentials: Credentials = self.credentials();
self.client
.text(
serde_json::to_string(&WithCredentials {
self.client.text(serde_json::to_string(&WithCredentials {
credentials,
message,
id: self.id,
})
.unwrap(),
)
.expect("Could not send authenticated message");
}).unwrap(), ).expect("Could not send authenticated message");
}
/*fn backup_auth(&mut self) {
if !self.last_username.is_empty() && !self.last_password.is_empty() {
self.username = self.last_username.clone();
self.password = self.last_password.clone();
self.send_authenticated(AuthenticatedMessage::Authenticate)
fn clear_receivers(&mut self, error: BankError) {
for (_, tx) in self.receivers.drain(..) {
let _ = tx.send(Err(error.clone()));
}
}
fn auth_error(&self) {
warn!("Authentication error while logged in. Did the password change?");
}*/
}
#[derive(Debug, Clone, Serialize, Deserialize)]
@ -254,7 +193,7 @@ pub enum AuthenticatedMessage {
Motd,
}
#[derive(Deserialize)]
#[derive(Deserialize, Clone, Debug)]
#[serde(tag = "action", rename_all = "camelCase")]
pub enum Response {
DisplayMessage {
@ -286,7 +225,7 @@ pub enum Response {
},
}
#[derive(Deserialize)]
#[derive(Deserialize, Clone, Debug)]
pub struct ResponseMessage {
#[serde(flatten)]
pub message: Response,
@ -309,7 +248,6 @@ impl ezsockets::ClientExt for Handler {
async fn on_text(&mut self, text: String) -> Result<(), Error> {
debug!("Received: {text}");
let message: ResponseMessage =
serde_json::from_str(text.as_str()).expect("Error decoding message");
if message.id == self.id || message.id == -1 {
@ -325,163 +263,21 @@ impl ezsockets::ClientExt for Handler {
_ => {}
}
if let Some((index, (_, _))) = self.receivers.iter().enumerate().find(|(_, (accept, _))| accept(&message)) {
let mut found = false;
while let Some((index, (_, _))) = self.receivers.iter().enumerate().find(|(_, (accept, _))| accept(&message)) {
let (_, tx) = self.receivers.remove(index).unwrap();
if let Err(_) = tx.send(Ok(message.message)) {
warn!("Message receiver dropped");
found = true;
if let Err(message) = tx.send(Ok(message.message.clone())) {
warn!("Message receiver dropped {:?}", message);
continue;
}
return Ok(());
}
let _ = self.tx.send(message);
/*if self.message_queue.is_empty() {
warn!("Received unexpected message from server");
if !found {
let _ = self.tx_msg.send(message);
}
match message.message {
Response::DisplayMessage { message, id, value } => {
if !message.is_empty() {
println!("{message}");
}
let config = self.config.lock().unwrap();
let show_motd_after_login = config.general.show_motd_after_login;
let show_inbox_count_after_login = config.general.show_inbox_count_after_login;
let show_pm_inbox_count_after_login =
config.general.show_pm_inbox_count_after_login;
let show_balance_after_payment = config.general.show_balance_after_payment;
drop(config);
match id.as_str() {
"auth.success" => {
self.id = value as i32;
self.last_username = self.username.clone();
self.last_password = self.password.clone();
self.logged_in = true;
if show_motd_after_login {
self.send_authenticated(AuthenticatedMessage::Motd);
}
if show_inbox_count_after_login {
self.send_authenticated(AuthenticatedMessage::GetInbox {
message_id: -1,
})
}
if show_pm_inbox_count_after_login {
self.send_authenticated(AuthenticatedMessage::GetPmInbox {
message_id: -1,
})
}
println!("(Client Id: {})", self.id);
}
"auth.fail.credentials" => {
self.backup_auth();
}
"register.success" => {
self.send_authenticated(AuthenticatedMessage::Authenticate);
}
"register.fail.usernameTaken" => {
self.backup_auth();
}
"logout.success" => {
self.logged_in = false;
}
"logout.fail.credentials" => {
self.auth_error();
}
"logout.fail.notloggedin" => {
self.logged_in = false;
}
"balance.success" => {}
"balance.fail.credentials" => {
self.auth_error();
}
"pay.fail.negative_amount" => {
panic!("Should not be able to send a negative amount")
}
"pay.fail.orig_user_unknown" => {
self.auth_error();
}
"pay.fail.credentials" => {
self.auth_error();
}
"pay.fail.unknown_dest" => {}
"pay.fail.not_enough_money" => {
if show_balance_after_payment {
self.send_authenticated(AuthenticatedMessage::GetBalance);
}
}
"pay.fail.unknown_error" => {}
"pay.success" => {
if show_balance_after_payment {
self.send_authenticated(AuthenticatedMessage::GetBalance);
}
}
"pay.received" => {
if show_balance_after_payment {
self.send_authenticated(AuthenticatedMessage::GetBalance);
}
}
"message_count" => {
self.inbox_message_count = value as u8;
println!(
"You have {} unread message{}",
self.inbox_message_count,
if self.inbox_message_count == 1 {
""
} else {
"s"
}
)
}
"pm_message_count" => {
self.pm_message_count = value as u8;
println!(
"You have {} unread private message{}",
self.pm_message_count,
if self.pm_message_count == 1 { "" } else { "s" }
)
}
"pm_inbox.send.success" => {}
"pm_inbox.dest.unkown" => {}
"read_inbox.success" => {}
"read_inbox.fail.credentials" => {
self.auth_error();
}
"read_pm.success" => {}
"read_pm.fail.credentials" => {
self.auth_error();
}
_ => {
warn!("Unknown message id: {}", id)
}
}
}
Response::Inbox {
message_id,
message,
} => {
println!("{}. {}", message_id, message);
}
Response::PmInbox {
message_id,
message,
} => {
println!("{}. {}", message_id, message);
}
Response::Motd { motd } => {
println!("--- {motd} ---");
}
}
if !self.message_queue.is_empty() {
self.message_queue.pop_front().unwrap().1.await;
if !self.message_queue.is_empty() {
let queued = self.message_queue.pop_front().unwrap();
self.send_authenticated_now(queued.0, queued.1);
}
}*/
} else {
debug!("ignoring message for other id")
}
@ -495,11 +291,7 @@ impl ezsockets::ClientExt for Handler {
async fn on_call(&mut self, call: Self::Call) -> Result<(), Error> {
match call {
ClientCommand::SendAuthenticatedNew {
message,
accept,
tx,
} => {
ClientCommand::SendAuthenticatedNew { message, accept, tx, } => {
self.send_authenticated(message);
self.receivers.push_back((accept, tx));
}
@ -510,116 +302,50 @@ impl ezsockets::ClientExt for Handler {
self.username = username;
self.password = password;
}
/*ClientCommand::TryLastLogin => {
if self.last_username.is_empty() || self.last_password.is_empty() {
println!("You need to enter a username and password");
} else {
self.send_authenticated(AuthenticatedMessage::Authenticate);
}
}
ClientCommand::CheckTimeout => {
if !self.message_queue.is_empty() && self.send_time.elapsed().unwrap().as_secs() > 5
{
if self.retry_count >= 3 {
self.message_queue.pop_front();
self.retry_count = 0;
println!("Request Timeout - All Retries failed")
} else {
self.retry_count += 1;
println!("Request Timeout - Retrying {}/3", self.retry_count);
}
if !self.message_queue.is_empty() {
let queued = self.message_queue.pop_front().unwrap();
self.send_authenticated_now(queued.0, queued.1);
}
}
}
ClientCommand::SendWithCallback(message, callback) => {
self.send_authenticated_callback(message, callback);
}
ClientCommand::PrintInbox => {
for i in 0..self.inbox_message_count {
self.send_authenticated(AuthenticatedMessage::GetInbox {
message_id: (i + 1) as i8,
})
}
}
ClientCommand::PrintPmInbox => {
for i in 0..self.pm_message_count {
self.send_authenticated(AuthenticatedMessage::GetPmInbox {
message_id: (i + 1) as i8,
})
}
}
ClientCommand::TryAccount(success, error) => {
//let last_username = self.last_username.clone();
//let last_password = self.last_password.clone();
self.last_username = String::new();
self.last_password = String::new();
/*self.send_authenticated_callback(AuthenticatedMessage::Authenticate, Box::new(Box::pin(async move {
if !self.logged_in {
self.send_authenticated_callback(AuthenticatedMessage::Register, Box::new(Box::pin(async move {
if !self.logged_in {
error.await;
} else {
success.await;
}
})));
} else {
success.await;
}
})));
*/
}*/
}
Ok(())
}
async fn on_connect(&mut self) -> Result<(), Error> {
info!("Successfully connected to the Server");
if !self.username.is_empty() && !self.password.is_empty() {
self.send_authenticated(AuthenticatedMessage::Authenticate);
}
let _ = self.tx_act.send(ClientAction::Connected);
Ok(())
}
async fn on_connect_fail(&mut self, _error: WSError) -> Result<ClientCloseMode, Error> {
info!("Disconnected, reconnecting...");
info!("Connection failed, reconnecting...");
Ok(ClientCloseMode::Reconnect)
}
async fn on_close(&mut self, _frame: Option<CloseFrame>) -> Result<ClientCloseMode, Error> {
self.clear_receivers(BankError::Disconnected);
let _ = self.tx_act.send(ClientAction::Disconnected);
info!("Disconnected, reconnecting...");
Ok(ClientCloseMode::Reconnect)
}
async fn on_disconnect(&mut self) -> Result<ClientCloseMode, Error> {
self.clear_receivers(BankError::Disconnected);
let _ = self.tx_act.send(ClientAction::Disconnected);
info!("Disconnected, reconnecting...");
Ok(ClientCloseMode::Reconnect)
}
}
pub enum ClientAction {
Connected,
Disconnected
}
pub enum ClientCommand {
SendAuthenticatedNew {
message: AuthenticatedMessage,
accept: fn(&ResponseMessage) -> bool,
tx: tokio::sync::oneshot::Sender<Result<Response, BankError>>,
tx: oneshot::Sender<Result<Response, BankError>>,
},
SendAuthenticated(AuthenticatedMessage),
/*SendWithCallback(
AuthenticatedMessage,
Box<dyn Future<Output = ()> + Send + Unpin>,
),
PrintInbox,
PrintPmInbox,*/
ChangeCredentials {
username: String,
password: String,
},
/*TryLastLogin,
CheckTimeout,
TryAccount(
Box<dyn Future<Output = ()> + Send + Unpin>,
Box<dyn Future<Output = ()> + Send + Unpin>,
),*/
}

2
rust-toolchain.toml Normal file
View File

@ -0,0 +1,2 @@
[toolchain]
channel = "nightly"