2023-04-17 03:57:12 +01:00
|
|
|
use std::sync::atomic::{AtomicU64, Ordering};
|
|
|
|
|
|
|
|
use futures::{SinkExt, StreamExt};
|
2023-06-04 19:05:33 +01:00
|
|
|
use gloo_net::websocket::{futures::WebSocket, Message};
|
|
|
|
use nrpc::{ClientHandler, ServiceError, _helpers::async_trait, _helpers::bytes};
|
|
|
|
use wasm_bindgen_futures::spawn_local;
|
2023-04-17 03:57:12 +01:00
|
|
|
|
|
|
|
static LAST_ID: AtomicU64 = AtomicU64::new(0);
|
|
|
|
|
2023-06-04 19:05:33 +01:00
|
|
|
/// Websocket client.
|
|
|
|
/// In most cases, this shouldn't be used directly, but generated code will use this.
|
2023-04-17 03:57:12 +01:00
|
|
|
pub struct WebSocketHandler {
|
|
|
|
port: u16,
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn send_recv_ws(url: String, input: bytes::Bytes) -> Result<Vec<u8>, String> {
|
|
|
|
let mut ws = WebSocket::open(&url).map_err(|e| e.to_string())?;
|
2023-06-04 19:05:33 +01:00
|
|
|
ws.send(Message::Bytes(input.into()))
|
|
|
|
.await
|
|
|
|
.map_err(|e| e.to_string())?;
|
2023-04-17 03:57:12 +01:00
|
|
|
|
|
|
|
read_next_incoming(ws).await
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn read_next_incoming(mut ws: WebSocket) -> Result<Vec<u8>, String> {
|
|
|
|
if let Some(msg) = ws.next().await {
|
|
|
|
match msg.map_err(|e| e.to_string())? {
|
|
|
|
Message::Bytes(b) => Ok(b),
|
|
|
|
Message::Text(_) => Err("Message::Text not allowed".into()),
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Err("No response received".into())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct ErrorStr(String);
|
|
|
|
|
|
|
|
impl std::fmt::Display for ErrorStr {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
write!(f, "Error message: {}", self.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::error::Error for ErrorStr {}
|
|
|
|
|
|
|
|
impl WebSocketHandler {
|
2023-06-04 19:05:33 +01:00
|
|
|
/// Instantiate the web socket client for connecting on the specified port
|
2023-04-17 03:57:12 +01:00
|
|
|
pub fn new(port: u16) -> Self {
|
|
|
|
Self { port }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[async_trait::async_trait]
|
|
|
|
impl ClientHandler for WebSocketHandler {
|
2023-06-04 19:05:33 +01:00
|
|
|
async fn call(
|
2023-06-29 03:21:56 +01:00
|
|
|
&self,
|
2023-06-04 19:05:33 +01:00
|
|
|
package: &str,
|
|
|
|
service: &str,
|
|
|
|
method: &str,
|
|
|
|
input: bytes::Bytes,
|
|
|
|
output: &mut bytes::BytesMut,
|
|
|
|
) -> Result<(), ServiceError> {
|
2023-04-17 03:57:12 +01:00
|
|
|
let id = LAST_ID.fetch_add(1, Ordering::SeqCst);
|
|
|
|
let url = format!(
|
2023-04-24 04:03:10 +01:00
|
|
|
"ws://usdpl-ws-{}.localhost:{}/{}.{}/{}",
|
2023-06-04 19:05:33 +01:00
|
|
|
id, self.port, package, service, method,
|
2023-04-17 03:57:12 +01:00
|
|
|
);
|
|
|
|
let (tx, rx) = async_channel::bounded(1);
|
|
|
|
spawn_local(async move {
|
2023-06-04 19:05:33 +01:00
|
|
|
tx.send(send_recv_ws(url, input).await).await.unwrap_or(());
|
2023-04-17 03:57:12 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
output.extend_from_slice(
|
2023-06-04 19:05:33 +01:00
|
|
|
&rx.recv()
|
|
|
|
.await
|
2023-04-17 03:57:12 +01:00
|
|
|
.map_err(|e| ServiceError::Method(Box::new(e)))?
|
2023-06-04 19:05:33 +01:00
|
|
|
.map_err(|e| ServiceError::Method(Box::new(ErrorStr(e))))?,
|
2023-04-17 03:57:12 +01:00
|
|
|
);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|