#![warn(missing_docs)]
use core::future::Future;
use std::pin::Pin;
#[cfg(feature = "browser")]
pub use self::browser::build_handler;
#[cfg(feature = "browser")]
pub use self::browser::HandlerType;
#[cfg(feature = "node")]
pub use self::default::build_handler;
#[cfg(feature = "node")]
pub use self::default::HandlerType;
use super::server;
use super::server::RpcMeta;
use crate::prelude::jsonrpc_core::Params;
use crate::prelude::jsonrpc_core::Result;
use crate::prelude::jsonrpc_core::Value;
use crate::prelude::rings_rpc::method::Method;
#[cfg(feature = "node")]
pub type MethodFnBox = Box<
dyn Fn(Params, RpcMeta) -> Pin<Box<dyn Future<Output = Result<Value>> + Send>> + Send + Sync,
>;
#[cfg(feature = "browser")]
pub type MethodFnBox = Box<dyn Fn(Params, RpcMeta) -> Pin<Box<dyn Future<Output = Result<Value>>>>>;
macro_rules! pin {
($fn:path) => {
Box::new(|params, meta| Box::pin($fn(params, meta)))
};
}
pub fn methods() -> Vec<(Method, MethodFnBox)> {
vec![
(
Method::ConnectPeerViaHttp,
pin!(server::connect_peer_via_http),
),
(
Method::ConnectPeerViaHttp,
pin!(server::connect_peer_via_http),
),
(Method::ConnectWithSeed, pin!(server::connect_with_seed)),
(Method::AnswerOffer, pin!(server::answer_offer)),
(Method::ConnectWithDid, pin!(server::connect_with_did)),
(Method::CreateOffer, pin!(server::create_offer)),
(Method::AcceptAnswer, pin!(server::accept_answer)),
(Method::ListPeers, pin!(server::list_peers)),
(Method::Disconnect, pin!(server::close_connection)),
(Method::SendTo, pin!(server::send_raw_message)),
(
Method::SendHttpRequestMessage,
pin!(server::send_http_request_message),
),
(
Method::SendSimpleText,
pin!(server::send_simple_text_message),
),
(Method::SendCustomMessage, pin!(server::send_custom_message)),
(
Method::PublishMessageToTopic,
pin!(server::publish_message_to_topic),
),
(
Method::FetchMessagesOfTopic,
pin!(server::fetch_messages_of_topic),
),
(Method::RegisterService, pin!(server::register_service)),
(Method::LookupService, pin!(server::lookup_service)),
(Method::NodeInfo, pin!(server::node_info)),
(Method::NodeDid, pin!(server::node_did)),
#[cfg(feature = "node")]
(Method::PollMessage, pin!(default::poll_backend_message)),
]
}
#[cfg(feature = "browser")]
pub mod browser {
use std::collections::HashMap;
use std::sync::Arc;
use async_trait::async_trait;
use super::*;
use crate::prelude::jsonrpc_core::types::error::Error;
use crate::prelude::jsonrpc_core::types::error::ErrorCode;
use crate::prelude::jsonrpc_core::types::request::MethodCall;
use crate::prelude::jsonrpc_core::types::response::Output;
use crate::processor::Processor;
pub type HandlerType = MessageHandler<server::RpcMeta>;
#[derive(Clone)]
pub struct MessageHandler<T: Clone> {
meta: T,
methods: HashMap<String, Arc<MethodFnBox>>,
}
impl From<Arc<Processor>> for MessageHandler<server::RpcMeta> {
fn from(p: Arc<Processor>) -> Self {
let meta: server::RpcMeta = p.into();
Self::new(meta)
}
}
pub trait MethodRegister {
fn register(&mut self, name: &str, func: MethodFnBox);
}
#[cfg_attr(feature = "browser", async_trait(?Send))]
pub trait MethodHandler {
async fn handle_request(&self, request: MethodCall) -> Result<Output>;
}
impl MessageHandler<server::RpcMeta> {
pub fn new(meta: server::RpcMeta) -> Self {
Self {
meta,
methods: HashMap::new(),
}
}
}
impl<T: Clone> MethodRegister for MessageHandler<T> {
fn register(&mut self, name: &str, func: MethodFnBox) {
self.methods.insert(name.to_string(), Arc::new(func));
}
}
#[cfg_attr(feature = "browser", async_trait(?Send))]
#[cfg_attr(not(feature = "browser"), async_trait)]
impl MethodHandler for MessageHandler<server::RpcMeta> {
async fn handle_request(&self, request: MethodCall) -> Result<Output> {
let output: Result<Value> = if let Some(handler) = self.methods.get(&request.method) {
let ret = handler(request.params, self.meta.clone()).await?;
Ok(ret)
} else {
Err(Error {
code: ErrorCode::MethodNotFound,
message: format!("method {} is not found", &request.method),
data: None,
})
};
Ok(Output::from(output, request.id, None))
}
}
pub async fn build_handler(handler: &mut MessageHandler<server::RpcMeta>) {
for m in methods() {
handler.register(m.0.as_str(), m.1);
}
}
}
#[cfg(feature = "node")]
pub mod default {
use super::*;
use crate::error::Error as ServerError;
use crate::prelude::jsonrpc_core::Error;
use crate::prelude::jsonrpc_core::MetaIoHandler as MessageHandler;
use crate::prelude::rings_rpc::response::CustomBackendMessage;
pub type HandlerType = MessageHandler<server::RpcMeta>;
pub async fn build_handler(handler: &mut MessageHandler<server::RpcMeta>) {
for m in methods() {
handler.add_method_with_meta(m.0.as_str(), m.1);
}
}
pub async fn poll_backend_message(params: Params, meta: server::RpcMeta) -> Result<Value> {
let receiver = if let Some(value) = meta.receiver {
value
} else {
return Ok(serde_json::Value::Null);
};
let params: Vec<serde_json::Value> = params.parse()?;
let wait_recv = params
.get(0)
.map(|v| v.as_bool().unwrap_or(false))
.unwrap_or(false);
let message = if wait_recv {
let mut recv = receiver.lock().await;
recv.recv().await.ok()
} else {
let mut recv = receiver.lock().await;
recv.try_recv().ok()
};
let message = if let Some(msg) = message {
serde_json::to_value(CustomBackendMessage::from(msg))
.map_err(|_| Error::from(ServerError::EncodeError))?
} else {
serde_json::Value::Null
};
Ok(serde_json::json!({
"message": message,
}))
}
}