pub extern crate inventory;
pub use futures;
use futures::{future::BoxFuture, FutureExt};
use once_cell::sync::Lazy;
use serde_json::Value;
use std::collections::HashMap;
pub type CommandHandler = fn(Value) -> BoxFuture<'static, Result<Value, String>>;
pub struct Command {
pub name: &'static str,
pub handler: CommandHandler,
}
inventory::collect!(Command);
pub fn handle_command(cmd: &str, args: Value) -> BoxFuture<'static, Result<Value, String>> {
for cmd_def in inventory::iter::<Command> {
if cmd_def.name == cmd {
return (cmd_def.handler)(args);
}
}
futures::future::ready(Err(format!("Unknown command: {}", cmd))).boxed()
}
#[macro_export]
macro_rules! use_wry_cmd_protocol {
($scheme:expr) => {{
let scheme = $scheme.to_string();
move |_webview_id: wry::WebViewId<'_>,
request: wry::http::Request<Vec<u8>>,
responder: wry::RequestAsyncResponder| {
use wry::http::{Method, Response, StatusCode};
use ::std::borrow::Cow;
use ::serde_json::Value;
if request.method() == &Method::OPTIONS {
let resp = Response::builder()
.status(StatusCode::NO_CONTENT)
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "POST, OPTIONS")
.header("Access-Control-Allow-Headers", "Content-Type")
.body(Cow::Borrowed(&[][..]))
.unwrap();
responder.respond(resp);
return;
}
if request.method() != &Method::POST {
let resp = Response::builder()
.status(StatusCode::METHOD_NOT_ALLOWED)
.header("Allow", "POST, OPTIONS")
.header("Access-Control-Allow-Origin", "*")
.body(Cow::Borrowed(b"Method Not Allowed".as_ref()))
.unwrap();
responder.respond(resp);
return;
}
let uri = request.uri();
let cmd = uri
.authority()
.map(|a| a.as_str().to_string())
.or_else(|| {
uri.path_and_query()
.map(|pq| pq.path().trim_start_matches('/').to_string())
})
.unwrap_or_default();
let args: Value = serde_json::from_slice(request.body()).unwrap_or_default();
std::thread::spawn(move || {
let fut = $crate::handle_command(&cmd, args);
let result_json = $crate::futures::executor::block_on(fut);
let response_value = match result_json {
Ok(v) => v,
Err(e) => serde_json::json!({ "error": e }),
};
let body = serde_json::to_vec(&response_value).unwrap_or_default();
let resp = Response::builder()
.status(StatusCode::OK)
.header("Content-Type", "application/json")
.header("Access-Control-Allow-Origin", "*")
.body(Cow::Owned(body))
.unwrap();
responder.respond(resp);
});
}
}};
}