Exchange data via websockets

Use websockets to send binary messages to the server. The server logs
the time taken by the client, as well as the time calculated with the
received messages sent by the client.
This commit is contained in:
finga 2022-09-20 16:23:45 +02:00
parent b12b8765a9
commit afa1d19dd8
6 changed files with 559 additions and 42 deletions

View file

@ -14,5 +14,12 @@ yew = "0.19"
console_error_panic_hook = "0.1"
log = "0.4"
wasm-logger = "0.2"
futures = "0.3"
gloo-timers = "0.2"
gloo-net = "0.2"
instant = { version = "0.1", features = [ "wasm-bindgen" ] }
wasm-bindgen-futures = "0.4"
bincode = "1"
yew-router = "0.16"
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", default-features = false, features = ["sync"] }

9
client/src/lib.rs Normal file
View file

@ -0,0 +1,9 @@
use serde::{Deserialize, Serialize};
use std::time::Duration;
#[derive(Debug, Deserialize, Serialize)]
pub enum Message {
Start,
Stop,
Duration(Duration),
}

View file

@ -1,6 +1,58 @@
use futures::{
stream::{SplitSink, SplitStream},
SinkExt, StreamExt,
};
use gloo_net::websocket::{futures::WebSocket, Message};
use gloo_timers::callback::Interval;
use instant::Instant;
use log::debug;
use std::sync::Arc;
use tokio::sync::Mutex;
use wasm_bindgen_futures::spawn_local;
use yew::prelude::*;
use yew_router::prelude::*;
#[derive(Clone, Debug, Eq, PartialEq, Routable)]
pub enum Route {
#[at("/")]
LockWatch,
#[not_found]
#[at("/404")]
NotFound,
}
struct WebSocketHandle {
writer: Arc<Mutex<SplitSink<WebSocket, Message>>>,
_reader: Arc<Mutex<SplitStream<WebSocket>>>,
}
impl WebSocketHandle {
fn connect(url: &str) -> Self {
debug!("connecting to websocket `{}`", url);
let ws = WebSocket::open(url)
.unwrap_or_else(|_| panic!("could not connect to websocket `{}`", url));
let (writer, reader) = ws.split();
Self {
writer: Arc::new(Mutex::new(writer)),
_reader: Arc::new(Mutex::new(reader)),
}
}
fn send(&self, msg: client::Message) {
let writer = self.writer.clone();
spawn_local(async move {
writer
.lock()
.await
.send(Message::Bytes(
bincode::serialize(&msg).expect("could not serialize websocket message"),
))
.await
.expect("could not send websocket message");
});
}
}
enum Msg {
Start,
@ -9,6 +61,7 @@ enum Msg {
}
struct LockWatch {
websocket: WebSocketHandle,
duration: Option<Instant>,
duration_handle: Option<Interval>,
}
@ -38,6 +91,7 @@ impl Component for LockWatch {
fn create(_ctx: &Context<Self>) -> Self {
Self {
websocket: WebSocketHandle::connect("ws://localhost:3000/api/ws"),
duration: None,
duration_handle: None,
}
@ -47,6 +101,8 @@ impl Component for LockWatch {
match msg {
Msg::Start => {
self.duration = Some(Instant::now());
self.websocket.send(client::Message::Start);
self.duration_handle = {
let link = ctx.link().clone();
Some(Interval::new(1, move || {
@ -54,7 +110,12 @@ impl Component for LockWatch {
}))
};
}
Msg::Stop => self.duration_handle = None,
Msg::Stop => {
self.duration_handle = None;
self.websocket.send(client::Message::Stop);
let duration = self.duration.expect("could not get duration").elapsed();
self.websocket.send(client::Message::Duration(duration));
}
Msg::UpdateDuration => {}
}