Skip to content

Instantly share code, notes, and snippets.

@penso
Forked from rtyler/0.log
Created February 9, 2022 11:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save penso/7486a7b5a60dd8c5c420e9978a322fa5 to your computer and use it in GitHub Desktop.
Save penso/7486a7b5a60dd8c5c420e9978a322fa5 to your computer and use it in GitHub Desktop.
Playing around with syntax sugar around handling websocket messages
INFO otto_eventbus > Listening for WebSocket connections on 127.0.0.1:9311
DEBUG tungstenite::handshake::server > Server handshake done.
DEBUG otto_eventbus > Received: Ok(Text("{\"type\":\"ping\", \"value\" : {\"msg\":\"hi\"}}"))
INFO otto_eventbus > deser: Meow { ttype: "ping", value: Object({"msg": String("hi")}) }
DEBUG otto_eventbus > Handling: Ping { msg: "hi" }
DEBUG otto_eventbus > Received: Ok(Text("{\"type\":\"hello\",\"value\": null}"))
INFO otto_eventbus > deser: Meow { ttype: "hello", value: Null }
DEBUG otto_eventbus > Handling hello: Hello
/**
* Meow is the primary message envolope
*/
#[derive(Debug, Deserialize, Serialize)]
struct Meow {
#[serde(rename = "type")]
ttype: String,
value: serde_json::Value,
}
trait Handler: Send + Sync {
/**
* convert will take the given Value and attempt to convert it to the trait implementer's type
*
* If the conversion cannot be done properly, None will be returned
*/
fn convert(v: serde_json::Value) -> Option<Self> where Self: std::marker::Sized + serde::de::DeserializeOwned {
serde_json::from_value::<Self>(v).map_or(None, |res| Some(res))
}
/**
* handle must be implemented by the trait implementer and should
* do something novel with the value
*/
fn handle(v: serde_json::Value) -> Result<(), std::io::Error>;
}
#[derive(Debug, Deserialize, Serialize)]
struct Ping {
msg: String,
}
impl Handler for Ping {
fn handle(v: serde_json::Value) -> Result<(), std::io::Error> {
if let Some(ping) = Self::convert(v) {
debug!("Handling: {:?}", ping);
}
Ok(())
}
}
#[derive(Debug, Deserialize, Serialize)]
struct Hello;
impl Handler for Hello {
fn handle(v: serde_json::Value) -> Result<(), std::io::Error> {
if let Some(hello) = Self::convert(v) {
debug!("Handling hello: {:?}", hello);
}
Ok(())
}
}
lazy_static! {
static ref REGISTRY: Mutex<HashMap<String, Dispatch>> = {
let mut reg = HashMap::new();
Mutex::new(reg)
};
}
macro_rules! register_handler {
($($t:ty), * => $($e:expr), *) => {
$(
REGISTRY.lock().expect("Failed to unlock registry")
.insert($e.to_string(), Dispatch::new(|v| { <$t>::handle(v); }));
)*
}
}
struct Dispatch {
f: Box<dyn Fn(serde_json::Value) + Send + Sync>,
}
impl Dispatch {
fn new<F>(f: F) -> Self
where
F: Fn(serde_json::Value) + 'static + Send + Sync,
{
Self { f: Box::new(f) }
}
}
async fn handle_ws(mut c: Connection) -> Result<(), std::io::Error> {
register_handler!(Ping => "ping");
register_handler!(Hello => "hello");
while let Some(item) = c.stream.next().await {
debug!("Received: {:?}", item);
match item {
Ok(msg) => {
if let Ok(meow) = serde_json::from_str::<Meow>(msg.to_text().unwrap()) {
info!("deser: {:?}", meow);
if let Ok(registry) = REGISTRY.lock() {
if let Some(container) = registry.get(&meow.ttype) {
(container.f)(meow.value);
}
}
}
},
_ => {
},
}
}
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment