mirror of
https://github.com/pcvolkmer/arsnova-client.git
synced 2025-04-19 19:16:51 +00:00
feat: add method for bidirectional feedback handling
This commit is contained in:
parent
c7469fc320
commit
8dc166fad4
33
README.md
33
README.md
@ -25,6 +25,16 @@ let room_info = client.get_room_info("12345678").await.expect("room information"
|
|||||||
|
|
||||||
You can get feedback information in two different ways: Direct request and getting notified about changes.
|
You can get feedback information in two different ways: Direct request and getting notified about changes.
|
||||||
|
|
||||||
|
#### Send feedback
|
||||||
|
|
||||||
|
Register a channel receiver and send incoming feedback using the client.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let (fb_tx, fb_rx) = channel::<FeedbackValue>(10);
|
||||||
|
|
||||||
|
let _ = client.register_feedback_receiver(&cli.room, fb_rx).await;
|
||||||
|
```
|
||||||
|
|
||||||
#### Direct request
|
#### Direct request
|
||||||
|
|
||||||
You can request (poll) the current feedback:
|
You can request (poll) the current feedback:
|
||||||
@ -46,19 +56,30 @@ let _ = client.on_feedback_changed(&cli.room, FeedbackHandler::Fn(|feedback| {/*
|
|||||||
Forward feedback to a channel:
|
Forward feedback to a channel:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let (tx, rx) = tokio::sync::mpsc::channel::<Feedback>(10);
|
let (in_tx, in_rx) = tokio::sync::mpsc::channel::<Feedback>(10);
|
||||||
|
|
||||||
let _ = client.on_feedback_changed(&cli.room, FeedbackHandler::Sender(tx.clone())).await;
|
let _ = client.on_feedback_changed(&cli.room, FeedbackHandler::Sender(in_tx)).await;
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Send feedback
|
#### Both: Send and receive Feedback updates
|
||||||
|
|
||||||
Register a channel receiver and send incoming feedback using the client.
|
Handle remote feedback changes and feedback updates to be sent:
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
UI["`**UI**`"] --> A[out_tx]
|
||||||
|
A[out_tx] -->|FeedbackValue| B[out_rx]
|
||||||
|
B --> W["`*WebSocket connection*`"]
|
||||||
|
D[in_tx] --> |Feedback| C[in_rx]
|
||||||
|
W --> D
|
||||||
|
C --> UI
|
||||||
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let (fb_tx, fb_rx) = channel::<FeedbackValue>(10);
|
let (in_tx, inrx) = channel::<Feedback>(10); // Incoming from remote
|
||||||
|
let (out_tx, out_rx) = channel::<FeedbackValue>(10); // Outgoing to remote
|
||||||
|
|
||||||
let _ = client.register_feedback_receiver(&cli.room, fb_rx).await;
|
let _ = client.on_feedback_changed(&cli.room, FeedbackHandler::SenderReceiver(in_tx, out_rx)).await;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
@ -62,11 +62,10 @@ async fn main() -> Result<(), ()> {
|
|||||||
|
|
||||||
let client = client.guest_login().await.map_err(|_| ())?;
|
let client = client.guest_login().await.map_err(|_| ())?;
|
||||||
|
|
||||||
let (tx, rx) = channel::<Feedback>(10);
|
let (in_tx, in_rx) = channel::<Feedback>(10);
|
||||||
|
let (out_tx, out_rx) = channel::<FeedbackValue>(10);
|
||||||
|
|
||||||
let (fb_tx, fb_rx) = channel::<FeedbackValue>(10);
|
let _ = in_tx
|
||||||
|
|
||||||
let _ = tx
|
|
||||||
.clone()
|
.clone()
|
||||||
.send(client.get_feedback(&cli.room).await.unwrap())
|
.send(client.get_feedback(&cli.room).await.unwrap())
|
||||||
.await;
|
.await;
|
||||||
@ -76,12 +75,12 @@ async fn main() -> Result<(), ()> {
|
|||||||
let mut terminal = Terminal::new(CrosstermBackend::new(stdout())).map_err(|_| ())?;
|
let mut terminal = Terminal::new(CrosstermBackend::new(stdout())).map_err(|_| ())?;
|
||||||
terminal.clear().map_err(|_| ())?;
|
terminal.clear().map_err(|_| ())?;
|
||||||
|
|
||||||
let l1 = client.on_feedback_changed(&cli.room, FeedbackHandler::Sender(tx.clone()));
|
let l1 = client.on_feedback_changed(&cli.room, FeedbackHandler::SenderReceiver(in_tx, out_rx));
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
let l2 = create_ui(&mut terminal, &title, rx);
|
let l2 = create_ui(&mut terminal, &title, in_rx);
|
||||||
|
|
||||||
let l3 = tokio::spawn(async move {
|
let l3 = tokio::spawn(async move {
|
||||||
loop {
|
loop {
|
||||||
@ -94,16 +93,16 @@ async fn main() -> Result<(), ()> {
|
|||||||
match key.code {
|
match key.code {
|
||||||
KeyCode::Esc => break,
|
KeyCode::Esc => break,
|
||||||
KeyCode::Char('a') | KeyCode::Char('1') => {
|
KeyCode::Char('a') | KeyCode::Char('1') => {
|
||||||
let _ = fb_tx.send(FeedbackValue::VeryGood).await;
|
let _ = out_tx.send(FeedbackValue::VeryGood).await;
|
||||||
}
|
}
|
||||||
KeyCode::Char('b') | KeyCode::Char('2') => {
|
KeyCode::Char('b') | KeyCode::Char('2') => {
|
||||||
let _ = fb_tx.send(FeedbackValue::Good).await;
|
let _ = out_tx.send(FeedbackValue::Good).await;
|
||||||
}
|
}
|
||||||
KeyCode::Char('c') | KeyCode::Char('3') => {
|
KeyCode::Char('c') | KeyCode::Char('3') => {
|
||||||
let _ = fb_tx.send(FeedbackValue::Bad).await;
|
let _ = out_tx.send(FeedbackValue::Bad).await;
|
||||||
}
|
}
|
||||||
KeyCode::Char('d') | KeyCode::Char('4') => {
|
KeyCode::Char('d') | KeyCode::Char('4') => {
|
||||||
let _ = fb_tx.send(FeedbackValue::VeryBad).await;
|
let _ = out_tx.send(FeedbackValue::VeryBad).await;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
@ -113,13 +112,10 @@ async fn main() -> Result<(), ()> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let l4 = client.register_feedback_receiver(&cli.room, fb_rx);
|
|
||||||
|
|
||||||
select! {
|
select! {
|
||||||
_ = l1 => {},
|
_ = l1 => {},
|
||||||
_ = l2 => {},
|
_ = l2 => {},
|
||||||
_ = l3 => {},
|
_ = l3 => {}
|
||||||
_ = l4 => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = stdout().execute(LeaveAlternateScreen).map_err(|_| ());
|
let _ = stdout().execute(LeaveAlternateScreen).map_err(|_| ());
|
||||||
|
@ -207,8 +207,12 @@ impl Feedback {
|
|||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub enum FeedbackHandler {
|
pub enum FeedbackHandler {
|
||||||
|
/// Handle incoming `Feedback` using a fn
|
||||||
Fn(fn(&Feedback)),
|
Fn(fn(&Feedback)),
|
||||||
|
/// Handle incoming `Feedback` by sending it to a `Sender<Feedback>`
|
||||||
Sender(Sender<Feedback>),
|
Sender(Sender<Feedback>),
|
||||||
|
/// Bidirectional handler for incoming `Feedback` and outgoing `FeedbackValue`
|
||||||
|
SenderReceiver(Sender<Feedback>, Receiver<FeedbackValue>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A possible feedback value
|
/// A possible feedback value
|
||||||
@ -508,25 +512,12 @@ impl Client<LoggedIn> {
|
|||||||
))
|
))
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(_) => loop {
|
Ok(_) => match handler {
|
||||||
|
FeedbackHandler::Fn(f) => loop {
|
||||||
select! {
|
select! {
|
||||||
Some(next) = read.next() => {
|
Some(next) = read.next() => {
|
||||||
match &next {
|
match &next {
|
||||||
Ok(msg) => {
|
Ok(msg) => self.handle_incoming_feedback_with_fn(msg, &f).await,
|
||||||
if msg.is_text() && msg.clone().into_text().unwrap().starts_with("MESSAGE") {
|
|
||||||
if let Ok(msg) = WsFeedbackMessage::parse(msg.to_text().unwrap()) {
|
|
||||||
if msg.body.body_type == "FeedbackChanged" {
|
|
||||||
let feedback = msg.body.payload.get_feedback();
|
|
||||||
match &handler {
|
|
||||||
FeedbackHandler::Fn(f) => f(&feedback),
|
|
||||||
FeedbackHandler::Sender(tx) => {
|
|
||||||
let _ = tx.send(feedback).await;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => break
|
Err(_) => break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -535,10 +526,64 @@ impl Client<LoggedIn> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
FeedbackHandler::Sender(tx) => loop {
|
||||||
|
select! {
|
||||||
|
Some(next) = read.next() => {
|
||||||
|
match &next {
|
||||||
|
Ok(msg) => self.handle_incoming_feedback_with_sender(msg, &tx).await,
|
||||||
|
Err(_) => break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ = tokio::time::sleep(Duration::from_secs(15)) => {
|
||||||
|
let _ = write.send(Message::Text("\n".to_string())).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
FeedbackHandler::SenderReceiver(tx, mut rx) => loop {
|
||||||
|
select! {
|
||||||
|
Some(next) = read.next() => {
|
||||||
|
match &next {
|
||||||
|
Ok(msg) => self.handle_incoming_feedback_with_sender(msg, &tx).await,
|
||||||
|
Err(_) => break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(value) = rx.recv() => {
|
||||||
|
let user_id = self.get_user_id().unwrap_or_default();
|
||||||
|
let msg = WsCreateFeedbackMessage::new(&room_info.id, &user_id, value.to_owned()).to_string();
|
||||||
|
let _ = write.send(Message::Text(msg)).await;
|
||||||
|
}
|
||||||
|
_ = tokio::time::sleep(Duration::from_secs(15)) => {
|
||||||
|
let _ = write.send(Message::Text("\n".to_string())).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
Err(_) => return Err(ConnectionError),
|
Err(_) => return Err(ConnectionError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(ConnectionError)
|
Err(ConnectionError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn handle_incoming_feedback_with_fn(&self, msg: &Message, f: &fn(&Feedback)) {
|
||||||
|
if msg.is_text() && msg.clone().into_text().unwrap().starts_with("MESSAGE") {
|
||||||
|
if let Ok(msg) = WsFeedbackMessage::parse(msg.to_text().unwrap()) {
|
||||||
|
if msg.body.body_type == "FeedbackChanged" {
|
||||||
|
let feedback = msg.body.payload.get_feedback();
|
||||||
|
f(&feedback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_incoming_feedback_with_sender(&self, msg: &Message, tx: &Sender<Feedback>) {
|
||||||
|
if msg.is_text() && msg.clone().into_text().unwrap().starts_with("MESSAGE") {
|
||||||
|
if let Ok(msg) = WsFeedbackMessage::parse(msg.to_text().unwrap()) {
|
||||||
|
if msg.body.body_type == "FeedbackChanged" {
|
||||||
|
let feedback = msg.body.payload.get_feedback();
|
||||||
|
let _ = tx.send(feedback).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user