Use websockets to exchange data

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 73d3d739e0
commit 6aa9bb0e43
6 changed files with 527 additions and 5 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 => {}
}