easee-rs/src/signalr.rs
2024-08-29 15:00:27 +02:00

137 lines
3.5 KiB
Rust

use serde_json::{json, Value};
use thiserror::Error;
use crate::stream::RecvError;
/* This entire module can be rewritten in two lines when
https://github.com/serde-rs/serde/issues/745
is merged */
#[derive(Debug)]
pub enum Message {
Empty,
Invocation {
target: String,
arguments: Vec<Value>,
},
InvocationResult {
id: String,
result: serde_json::Value,
},
Ping,
Other(serde_json::Value),
}
#[derive(Debug, Error)]
pub enum ParseError {
#[error("Expecting object, received {0}")]
ExpectingObject(Value),
#[error("Missing `type` key")]
MissingTypeKey,
#[error("`type` is not a number")]
TypeNotANumber,
#[error("Unknown type {0}")]
UnknownType(u64),
#[error("Missing expected key {0}")]
MissingKey(&'static str),
#[error("Expecting string")]
ExpectingString,
#[error("Expecting array")]
ExpectingArray,
}
impl Message {
pub fn from_json(msg: Value) -> Result<Self, ParseError> {
let Some(obj) = msg.as_object() else {
return Err(ParseError::ExpectingObject(msg));
};
if obj.is_empty() {
return Ok(Message::Empty);
}
let typ = obj
.get("type")
.ok_or(ParseError::MissingTypeKey)?
.as_number()
.and_then(|n| n.as_u64())
.ok_or(ParseError::TypeNotANumber)?;
match typ {
1 => Ok(Message::Invocation {
target: obj
.get("target")
.ok_or(ParseError::MissingKey("target"))?
.as_str()
.ok_or(ParseError::ExpectingString)?
.to_owned(),
arguments: obj
.get("arguments")
.ok_or(ParseError::MissingKey("arguments"))?
.as_array()
.ok_or(ParseError::ExpectingArray)?
.to_owned(),
}),
3 => Ok(Message::InvocationResult {
id: obj
.get("invocationId")
.ok_or(ParseError::MissingKey("invocationId"))?
.as_str()
.ok_or(ParseError::ExpectingString)?
.to_owned(),
result: obj
.get("result")
.ok_or(ParseError::MissingKey("result"))?
.to_owned(),
}),
6 => Ok(Message::Ping),
_ => Ok(Message::Other(msg)),
}
}
}
#[derive(Debug, Error)]
pub enum StreamError {
#[error("Parse error: {0}")]
ParseError(#[from] ParseError),
#[error("Recv error: {0}")]
StreamError(#[from] RecvError),
}
pub struct Stream {
buffer: Vec<serde_json::Value>,
ws: super::stream::Stream,
}
impl Stream {
pub fn from_ws(ws: super::stream::Stream) -> Self {
Self { ws, buffer: vec![] }
}
pub async fn recv(&mut self) -> Result<Message, StreamError> {
while self.buffer.is_empty() {
self.buffer = self.ws.recv().await?;
self.buffer.reverse();
}
let json = self.buffer.pop().unwrap();
Ok(Message::from_json(json)?)
}
pub async fn invoke(
&mut self,
target: &str,
args: serde_json::Value,
) -> Result<(), tungstenite::Error> {
self.ws.send(json!( { "arguments": args,
"invocationId": "0",
"target": target,
"type": 1} )).await
}
}