Files
nym/common/wasm/utils/src/websocket/mod.rs
T
Jędrzej Stuczyński 4a1ce8154a chore: resolve 1.87 clippy warnings (#5802)
* Clippy in wallet & sdk

* Clippy in wallet

* Pin rust to 1.86 in builder

* apply changes from b7da75a18c

* missing nym-node features

* Box all the things

* additional boxes in the wallet

* post rebasing clippy

---------

Co-authored-by: dynco-nym <173912580+dynco-nym@users.noreply.github.com>
2025-05-27 11:08:36 +01:00

114 lines
3.9 KiB
Rust

// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::console_log;
use futures::{Sink, Stream};
use gloo_net::websocket::futures::WebSocket;
use gloo_net::websocket::{Message, WebSocketError};
use gloo_utils::errors::JsError;
use std::fmt::{self, Formatter};
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use tungstenite::{Error as WsError, Message as WsMessage}; // use tungstenite Message and Error types for easier compatibility with `ClientHandshake`
// Unfortunately this can't be cleanly done with TryFrom/TryInto traits as both are foreign types
fn into_tungstenite_message(msg: gloo_net::websocket::Message) -> WsMessage {
match msg {
Message::Text(text) => WsMessage::Text(text),
Message::Bytes(bytes) => WsMessage::Binary(bytes),
}
}
fn map_ws_error(err: WebSocketError) -> WsError {
match err {
// TODO: are we preserving correct semantics?
WebSocketError::ConnectionError => WsError::ConnectionClosed,
WebSocketError::ConnectionClose(_event) => WsError::ConnectionClosed,
WebSocketError::MessageSendError(err) => WsError::Io(io::Error::other(err.to_string())),
_ => WsError::Io(io::Error::other("new websocket error")),
}
}
fn try_from_tungstenite_message(msg: WsMessage) -> Result<gloo_net::websocket::Message, WsError> {
match msg {
WsMessage::Text(text) => Ok(gloo_net::websocket::Message::Text(text)),
WsMessage::Binary(bytes) => Ok(gloo_net::websocket::Message::Bytes(bytes)),
_ => Err(WsError::Io(io::Error::from(io::ErrorKind::InvalidInput))),
}
}
// Safety: when compiled to wasm32 everything is going to be running on a single thread and so there
// is no shared memory right now.
//
// ************************************
// SUPER IMPORTANT TODO: ONCE WASM IN RUST MATURES AND BECOMES MULTI-THREADED THIS MIGHT
// LEAD TO RUNTIME MEMORY CORRUPTION!!
// ************************************
//
// note: https://github.com/rustwasm/gloo/issues/109
unsafe impl Send for JSWebsocket {}
#[allow(clippy::upper_case_acronyms)]
pub struct JSWebsocket {
inner: WebSocket,
}
impl JSWebsocket {
pub fn new(url: &str) -> Result<Self, JsError> {
let inner = WebSocket::open(url)?;
console_log!("Websocket to {:?} is now open!", url);
Ok(JSWebsocket { inner })
}
pub async fn close(self, code: Option<u16>, reason: Option<&str>) -> Result<(), JsError> {
self.inner.close(code, reason)
}
}
impl Stream for JSWebsocket {
type Item = Result<WsMessage, WsError>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
Pin::new(&mut self.inner).poll_next(cx).map(|maybe_item| {
maybe_item.map(|item| item.map(into_tungstenite_message).map_err(map_ws_error))
})
}
}
impl fmt::Debug for JSWebsocket {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "JSWebSocket")
}
}
impl Sink<WsMessage> for JSWebsocket {
type Error = WsError;
fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Pin::new(&mut self.inner)
.poll_ready(cx)
.map(|ready_res| ready_res.map_err(map_ws_error))
}
fn start_send(mut self: Pin<&mut Self>, item: WsMessage) -> Result<(), Self::Error> {
let item = try_from_tungstenite_message(item)?;
Pin::new(&mut self.inner)
.start_send(item)
.map_err(map_ws_error)
}
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Pin::new(&mut self.inner)
.poll_flush(cx)
.map(|flush_res| flush_res.map_err(map_ws_error))
}
fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Pin::new(&mut self.inner)
.poll_close(cx)
.map(|close_res| close_res.map_err(map_ws_error))
}
}