mirror of
https://github.com/pcvolkmer/arsnova-client.git
synced 2025-04-19 19:16:51 +00:00
feat: improve error handling
This commit is contained in:
parent
320fe0fa97
commit
c37a75cfcf
@ -64,20 +64,20 @@ async fn main() -> Result<(), ()> {
|
|||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout().execute(EnterAlternateScreen).map_err(|_| ())?;
|
|
||||||
enable_raw_mode().map_err(|_| ())?;
|
|
||||||
let mut terminal = Terminal::new(CrosstermBackend::new(stdout())).map_err(|_| ())?;
|
|
||||||
terminal.clear().map_err(|_| ())?;
|
|
||||||
|
|
||||||
let (tx, rx) = channel::<Feedback>(10);
|
let (tx, rx) = channel::<Feedback>(10);
|
||||||
|
|
||||||
let l1 = client.on_feedback_changed(&cli.room, FeedbackHandler::Sender(tx.clone()));
|
|
||||||
|
|
||||||
let _ = tx
|
let _ = tx
|
||||||
.clone()
|
.clone()
|
||||||
.send(client.get_feedback(&cli.room).await.unwrap())
|
.send(client.get_feedback(&cli.room).await.unwrap())
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
stdout().execute(EnterAlternateScreen).map_err(|_| ())?;
|
||||||
|
enable_raw_mode().map_err(|_| ())?;
|
||||||
|
let mut terminal = Terminal::new(CrosstermBackend::new(stdout())).map_err(|_| ())?;
|
||||||
|
terminal.clear().map_err(|_| ())?;
|
||||||
|
|
||||||
|
let l1 = client.on_feedback_changed(&cli.room, FeedbackHandler::Sender(tx.clone()));
|
||||||
|
|
||||||
let room_info = client.get_room_info(&cli.room).await.map_err(|_| ())?;
|
let room_info = client.get_room_info(&cli.room).await.map_err(|_| ())?;
|
||||||
let title = format!("Live Feedback: {} ({})", room_info.name, room_info.short_id);
|
let title = format!("Live Feedback: {} ({})", room_info.name, room_info.short_id);
|
||||||
|
|
||||||
|
@ -17,10 +17,12 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use std::error;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use futures_util::{SinkExt, StreamExt};
|
use futures_util::{SinkExt, StreamExt};
|
||||||
|
use reqwest::StatusCode;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tokio::join;
|
use tokio::join;
|
||||||
use tokio::sync::mpsc::Sender;
|
use tokio::sync::mpsc::Sender;
|
||||||
@ -28,6 +30,8 @@ use tokio_tungstenite::connect_async;
|
|||||||
use tokio_tungstenite::tungstenite::Message;
|
use tokio_tungstenite::tungstenite::Message;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
use crate::client::ClientError::{ConnectionError, LoginError, ParserError, RoomNotFoundError};
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
struct LoginResponse {
|
struct LoginResponse {
|
||||||
#[serde(rename = "token")]
|
#[serde(rename = "token")]
|
||||||
@ -174,6 +178,27 @@ pub enum FeedbackHandler {
|
|||||||
Sender(Sender<Feedback>),
|
Sender(Sender<Feedback>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum ClientError {
|
||||||
|
ConnectionError,
|
||||||
|
LoginError,
|
||||||
|
RoomNotFoundError,
|
||||||
|
ParserError(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ClientError {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
ConnectionError => write!(f, "Cannot connect"),
|
||||||
|
LoginError => write!(f, "Cannot login"),
|
||||||
|
RoomNotFoundError => write!(f, "Requested room not found"),
|
||||||
|
ParserError(msg) => write!(f, "Cannot parse response: {}", msg),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl error::Error for ClientError {}
|
||||||
|
|
||||||
pub struct Client {
|
pub struct Client {
|
||||||
api_url: String,
|
api_url: String,
|
||||||
http_client: reqwest::Client,
|
http_client: reqwest::Client,
|
||||||
@ -181,11 +206,11 @@ pub struct Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
pub fn new(api_url: &str) -> Result<Client, ()> {
|
pub fn new(api_url: &str) -> Result<Client, ClientError> {
|
||||||
let client = reqwest::Client::builder()
|
let client = reqwest::Client::builder()
|
||||||
.user_agent(format!("arsnova-cli-client/{}", env!("CARGO_PKG_VERSION")))
|
.user_agent(format!("arsnova-cli-client/{}", env!("CARGO_PKG_VERSION")))
|
||||||
.build()
|
.build()
|
||||||
.map_err(|_| ())?;
|
.map_err(|_| ConnectionError)?;
|
||||||
|
|
||||||
Ok(Client {
|
Ok(Client {
|
||||||
api_url: api_url.to_string(),
|
api_url: api_url.to_string(),
|
||||||
@ -194,7 +219,7 @@ impl Client {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn guest_login(&mut self) -> Result<(), ()> {
|
pub async fn guest_login(&mut self) -> Result<(), ClientError> {
|
||||||
match self
|
match self
|
||||||
.http_client
|
.http_client
|
||||||
.post(format!("{}/auth/login/guest", self.api_url))
|
.post(format!("{}/auth/login/guest", self.api_url))
|
||||||
@ -206,13 +231,13 @@ impl Client {
|
|||||||
self.token = Some(res.token);
|
self.token = Some(res.token);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(_) => Err(()),
|
Err(_) => Err(LoginError),
|
||||||
},
|
},
|
||||||
Err(_) => Err(()),
|
Err(_) => Err(ConnectionError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_room_info(&self, short_id: &str) -> Result<RoomInfo, ()> {
|
pub async fn get_room_info(&self, short_id: &str) -> Result<RoomInfo, ClientError> {
|
||||||
let token = self.token.as_ref().unwrap();
|
let token = self.token.as_ref().unwrap();
|
||||||
|
|
||||||
let membership_response = match self
|
let membership_response = match self
|
||||||
@ -228,10 +253,16 @@ impl Client {
|
|||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(res) => res.json::<MembershipResponse>().await.unwrap(),
|
Ok(res) => match res.status() {
|
||||||
Err(err) => {
|
StatusCode::OK => res
|
||||||
eprintln!("{}", err);
|
.json::<MembershipResponse>()
|
||||||
return Err(());
|
.await
|
||||||
|
.map_err(|err| ParserError(err.to_string()))?,
|
||||||
|
StatusCode::NOT_FOUND => return Err(RoomNotFoundError),
|
||||||
|
_ => return Err(ConnectionError),
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
return Err(ConnectionError);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -243,31 +274,40 @@ impl Client {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_feedback(&self, short_id: &str) -> Result<Feedback, ()> {
|
pub async fn get_feedback(&self, short_id: &str) -> Result<Feedback, ClientError> {
|
||||||
let room_info = self.get_room_info(short_id).await?;
|
let room_info = self.get_room_info(short_id).await?;
|
||||||
|
|
||||||
let res = self
|
match self
|
||||||
.http_client
|
.http_client
|
||||||
.get(format!("{}/room/{}/survey", self.api_url, room_info.id))
|
.get(format!("{}/room/{}/survey", self.api_url, room_info.id))
|
||||||
.bearer_auth(self.token.as_ref().unwrap_or(&"".to_string()).to_string())
|
.bearer_auth(self.token.as_ref().unwrap_or(&"".to_string()).to_string())
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.map_err(|_| ())?;
|
{
|
||||||
|
Ok(res) => match res.status() {
|
||||||
Ok(Feedback::from_values(res.json::<Vec<u16>>().await.unwrap()))
|
StatusCode::OK => Ok(Feedback::from_values(
|
||||||
|
res.json::<Vec<u16>>()
|
||||||
|
.await
|
||||||
|
.map_err(|err| ParserError(err.to_string()))?,
|
||||||
|
)),
|
||||||
|
StatusCode::NOT_FOUND => Err(RoomNotFoundError),
|
||||||
|
_ => Err(ConnectionError),
|
||||||
|
},
|
||||||
|
Err(_) => Err(ConnectionError),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn on_feedback_changed(
|
pub async fn on_feedback_changed(
|
||||||
&self,
|
&self,
|
||||||
short_id: &str,
|
short_id: &str,
|
||||||
handler: FeedbackHandler,
|
handler: FeedbackHandler,
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), ClientError> {
|
||||||
let room_info = self.get_room_info(short_id).await?;
|
let room_info = self.get_room_info(short_id).await?;
|
||||||
|
|
||||||
let ws_url = self.api_url.replace("http", "ws");
|
let ws_url = self.api_url.replace("http", "ws");
|
||||||
let (socket, _) = connect_async(Url::parse(&format!("{}/ws/websocket", ws_url)).unwrap())
|
let (socket, _) = connect_async(Url::parse(&format!("{}/ws/websocket", ws_url)).unwrap())
|
||||||
.await
|
.await
|
||||||
.map_err(|_| ())?;
|
.map_err(|_| ConnectionError)?;
|
||||||
|
|
||||||
let (mut write, read) = socket.split();
|
let (mut write, read) = socket.split();
|
||||||
|
|
||||||
@ -285,7 +325,7 @@ impl Client {
|
|||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(_) => return Err(()),
|
Err(_) => return Err(ConnectionError),
|
||||||
}
|
}
|
||||||
|
|
||||||
let jh1 = read.for_each(|msg| async {
|
let jh1 = read.for_each(|msg| async {
|
||||||
@ -317,6 +357,6 @@ impl Client {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(())
|
Err(ConnectionError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user