mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-08-24 22:29:22 +00:00
feat: adding rpc interfaces into sequencer and node
This commit is contained in:
+39
-1
@@ -1 +1,39 @@
|
||||
//ToDo: Add node_rpc module
|
||||
pub mod net_utils;
|
||||
pub mod process;
|
||||
pub mod types;
|
||||
|
||||
use rpc_primitives::{
|
||||
errors::{RpcError, RpcErrorKind},
|
||||
RpcPollingConfig,
|
||||
};
|
||||
use serde::Serialize;
|
||||
use serde_json::Value;
|
||||
|
||||
pub use net_utils::*;
|
||||
|
||||
use self::types::err_rpc::RpcErr;
|
||||
|
||||
//ToDo: Add necessary fields
|
||||
pub struct JsonHandler {
|
||||
pub polling_config: RpcPollingConfig,
|
||||
}
|
||||
|
||||
fn respond<T: Serialize>(val: T) -> Result<Value, RpcErr> {
|
||||
Ok(serde_json::to_value(val)?)
|
||||
}
|
||||
|
||||
pub fn rpc_error_responce_inverter(err: RpcError) -> RpcError {
|
||||
let mut content: Option<Value> = None;
|
||||
if err.error_struct.is_some() {
|
||||
content = match err.error_struct.clone().unwrap() {
|
||||
RpcErrorKind::HandlerError(val) | RpcErrorKind::InternalError(val) => Some(val),
|
||||
RpcErrorKind::RequestValidationError(vall) => Some(serde_json::to_value(vall).unwrap()),
|
||||
};
|
||||
}
|
||||
RpcError {
|
||||
error_struct: None,
|
||||
code: err.code,
|
||||
message: err.message,
|
||||
data: content,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
use std::io;
|
||||
|
||||
use actix_cors::Cors;
|
||||
use actix_web::{http, middleware, web, App, Error as HttpError, HttpResponse, HttpServer};
|
||||
use futures::Future;
|
||||
use futures::FutureExt;
|
||||
use log::info;
|
||||
|
||||
use rpc_primitives::message::Message;
|
||||
use rpc_primitives::RpcConfig;
|
||||
|
||||
use super::JsonHandler;
|
||||
|
||||
pub const SHUTDOWN_TIMEOUT_SECS: u64 = 10;
|
||||
|
||||
fn rpc_handler(
|
||||
message: web::Json<Message>,
|
||||
handler: web::Data<JsonHandler>,
|
||||
) -> impl Future<Output = Result<HttpResponse, HttpError>> {
|
||||
let response = async move {
|
||||
let message = handler.process(message.0).await?;
|
||||
Ok(HttpResponse::Ok().json(&message))
|
||||
};
|
||||
response.boxed()
|
||||
}
|
||||
|
||||
fn get_cors(cors_allowed_origins: &[String]) -> Cors {
|
||||
let mut cors = Cors::permissive();
|
||||
if cors_allowed_origins != ["*".to_string()] {
|
||||
for origin in cors_allowed_origins {
|
||||
cors = cors.allowed_origin(origin);
|
||||
}
|
||||
}
|
||||
cors.allowed_methods(vec!["GET", "POST"])
|
||||
.allowed_headers(vec![http::header::AUTHORIZATION, http::header::ACCEPT])
|
||||
.allowed_header(http::header::CONTENT_TYPE)
|
||||
.max_age(3600)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new_http_server(config: RpcConfig) -> io::Result<actix_web::dev::Server> {
|
||||
let RpcConfig {
|
||||
addr,
|
||||
cors_allowed_origins,
|
||||
polling_config,
|
||||
limits_config,
|
||||
} = config;
|
||||
info!(target:"network", "Starting http server at {}", addr);
|
||||
let handler = web::Data::new(JsonHandler { polling_config });
|
||||
|
||||
// HTTP server
|
||||
Ok(HttpServer::new(move || {
|
||||
App::new()
|
||||
.wrap(get_cors(&cors_allowed_origins))
|
||||
.app_data(handler.clone())
|
||||
.app_data(web::JsonConfig::default().limit(limits_config.json_payload_max_size))
|
||||
.wrap(middleware::Logger::default())
|
||||
.service(web::resource("/").route(web::post().to(rpc_handler)))
|
||||
})
|
||||
.bind(addr)?
|
||||
.shutdown_timeout(SHUTDOWN_TIMEOUT_SECS)
|
||||
.disable_signals()
|
||||
.run())
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
use actix_web::Error as HttpError;
|
||||
use serde_json::Value;
|
||||
|
||||
use rpc_primitives::{
|
||||
errors::RpcError,
|
||||
message::{Message, Request},
|
||||
parser::RpcRequest,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
rpc_error_responce_inverter,
|
||||
types::rpc_structs::{HelloRequest, HelloResponse},
|
||||
};
|
||||
|
||||
use super::{respond, types::err_rpc::RpcErr, JsonHandler};
|
||||
|
||||
impl JsonHandler {
|
||||
pub async fn process(&self, message: Message) -> Result<Message, HttpError> {
|
||||
let id = message.id();
|
||||
if let Message::Request(request) = message {
|
||||
let message_inner = self
|
||||
.process_request_internal(request)
|
||||
.await
|
||||
.map_err(|e| e.0)
|
||||
.map_err(rpc_error_responce_inverter);
|
||||
Ok(Message::response(id, message_inner))
|
||||
} else {
|
||||
Ok(Message::error(RpcError::parse_error(
|
||||
"JSON RPC Request format was expected".to_owned(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::unused_async)]
|
||||
///Example of request processing
|
||||
async fn process_temp_hello(&self, request: Request) -> Result<Value, RpcErr> {
|
||||
let _hello_request = HelloRequest::parse(Some(request.params))?;
|
||||
|
||||
let helperstruct = HelloResponse {
|
||||
greeting: "HELLO_FROM_NODE".to_string(),
|
||||
};
|
||||
|
||||
respond(helperstruct)
|
||||
}
|
||||
|
||||
pub async fn process_request_internal(&self, request: Request) -> Result<Value, RpcErr> {
|
||||
match request.method.as_ref() {
|
||||
//Todo : Add handling of more JSON RPC methods
|
||||
"hello" => self.process_temp_hello(request).await,
|
||||
_ => Err(RpcErr(RpcError::method_not_found(request.method))),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
use log::debug;
|
||||
|
||||
use rpc_primitives::errors::{RpcError, RpcParseError};
|
||||
|
||||
pub struct RpcErr(pub RpcError);
|
||||
|
||||
pub type RpcErrInternal = anyhow::Error;
|
||||
|
||||
pub trait RpcErrKind: 'static {
|
||||
fn into_rpc_err(self) -> RpcError;
|
||||
}
|
||||
|
||||
impl<T: RpcErrKind> From<T> for RpcErr {
|
||||
fn from(e: T) -> Self {
|
||||
Self(e.into_rpc_err())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! standard_rpc_err_kind {
|
||||
($type_name:path) => {
|
||||
impl RpcErrKind for $type_name {
|
||||
fn into_rpc_err(self) -> RpcError {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
standard_rpc_err_kind!(RpcError);
|
||||
standard_rpc_err_kind!(RpcParseError);
|
||||
|
||||
impl RpcErrKind for serde_json::Error {
|
||||
fn into_rpc_err(self) -> RpcError {
|
||||
RpcError::serialization_error(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl RpcErrKind for RpcErrInternal {
|
||||
fn into_rpc_err(self) -> RpcError {
|
||||
RpcError::new_internal_error(None, &format!("{self:#?}"))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
pub fn from_rpc_err_into_anyhow_err(rpc_err: RpcError) -> anyhow::Error {
|
||||
debug!("Rpc error cast to anyhow error : err {rpc_err:?}");
|
||||
anyhow::anyhow!(format!("{rpc_err:#?}"))
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
pub mod err_rpc;
|
||||
pub mod parse;
|
||||
pub mod rpc_structs;
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
use rpc_primitives::errors::RpcParseError;
|
||||
use rpc_primitives::parse_request;
|
||||
use rpc_primitives::parser::parse_params;
|
||||
use rpc_primitives::parser::RpcRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct HelloRequest {}
|
||||
|
||||
parse_request!(HelloRequest);
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct HelloResponse {
|
||||
pub greeting: String,
|
||||
}
|
||||
Reference in New Issue
Block a user