mirror of
https://github.com/speatzle/nfsense.git
synced 2025-05-11 02:48:21 +00:00
Get JsonRPC Working
This commit is contained in:
parent
0a603b6642
commit
42cc14cb14
6 changed files with 160 additions and 66 deletions
48
src/api/mod.rs
Normal file
48
src/api/mod.rs
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
mod network;
|
||||||
|
mod system;
|
||||||
|
|
||||||
|
use crate::state::RpcState;
|
||||||
|
use jsonrpsee::{
|
||||||
|
types::{error::ErrorCode, ErrorObject},
|
||||||
|
RpcModule,
|
||||||
|
};
|
||||||
|
|
||||||
|
use custom_error::custom_error;
|
||||||
|
use tracing::info;
|
||||||
|
|
||||||
|
custom_error! { pub ApiError
|
||||||
|
InvalidParams = "Invalid Parameters",
|
||||||
|
Leet = "1337",
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<ErrorObject<'static>> for ApiError {
|
||||||
|
fn into(self) -> ErrorObject<'static> {
|
||||||
|
match self {
|
||||||
|
Self::InvalidParams => ErrorCode::InvalidParams,
|
||||||
|
Self::Leet => ErrorCode::ServerError(1337),
|
||||||
|
_ => ErrorCode::InternalError,
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_rpc_module(state: RpcState) -> RpcModule<RpcState> {
|
||||||
|
let mut module = RpcModule::new(state);
|
||||||
|
|
||||||
|
module
|
||||||
|
.register_method("ping", |_, _| {
|
||||||
|
info!("ping called");
|
||||||
|
"pong"
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
module
|
||||||
|
.register_method("System.GetUsers", system::get_users)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
module
|
||||||
|
.register_method("Network.GetStaticRoutes", network::get_static_routes)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
module
|
||||||
|
}
|
13
src/api/network.rs
Normal file
13
src/api/network.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
use jsonrpsee::types::Params;
|
||||||
|
|
||||||
|
use crate::{definitions::network::StaticRoute, state::RpcState};
|
||||||
|
|
||||||
|
use super::ApiError;
|
||||||
|
|
||||||
|
pub fn get_static_routes(_: Params, state: &RpcState) -> Result<Vec<StaticRoute>, ApiError> {
|
||||||
|
Ok(state
|
||||||
|
.config_manager
|
||||||
|
.get_pending_config()
|
||||||
|
.network
|
||||||
|
.static_routes)
|
||||||
|
}
|
10
src/api/system.rs
Normal file
10
src/api/system.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::{definitions::system::User, state::RpcState};
|
||||||
|
use jsonrpsee::types::Params;
|
||||||
|
|
||||||
|
use super::ApiError;
|
||||||
|
|
||||||
|
pub fn get_users(_: Params, state: &RpcState) -> Result<HashMap<String, User>, ApiError> {
|
||||||
|
Ok(state.config_manager.get_pending_config().system.users)
|
||||||
|
}
|
15
src/main.rs
15
src/main.rs
|
@ -5,6 +5,7 @@ use std::{
|
||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::state::RpcState;
|
||||||
use axum::{middleware, Router};
|
use axum::{middleware, Router};
|
||||||
use config_manager::ConfigManager;
|
use config_manager::ConfigManager;
|
||||||
use state::AppState;
|
use state::AppState;
|
||||||
|
@ -15,6 +16,7 @@ use tracing::info;
|
||||||
use tracing_subscriber;
|
use tracing_subscriber;
|
||||||
use web::auth::SessionState;
|
use web::auth::SessionState;
|
||||||
|
|
||||||
|
mod api;
|
||||||
mod config_manager;
|
mod config_manager;
|
||||||
mod definitions;
|
mod definitions;
|
||||||
mod state;
|
mod state;
|
||||||
|
@ -41,12 +43,17 @@ async fn main() {
|
||||||
|
|
||||||
// TODO Check Config Manager Setup Error
|
// TODO Check Config Manager Setup Error
|
||||||
let config_manager = ConfigManager::new().unwrap();
|
let config_manager = ConfigManager::new().unwrap();
|
||||||
|
let session_state = SessionState {
|
||||||
|
sessions: Arc::new(RwLock::new(HashMap::new())),
|
||||||
|
};
|
||||||
|
|
||||||
let app_state = AppState {
|
let app_state = AppState {
|
||||||
config_manager,
|
config_manager: config_manager.clone(),
|
||||||
session_state: SessionState {
|
session_state: session_state.clone(),
|
||||||
sessions: Arc::new(RwLock::new(HashMap::new())),
|
rpc_module: api::new_rpc_module(RpcState {
|
||||||
},
|
config_manager,
|
||||||
|
session_state,
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Note: The Router Works Bottom Up, So the auth middleware will only applies to everything above it.
|
// Note: The Router Works Bottom Up, So the auth middleware will only applies to everything above it.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use jsonrpsee::RpcModule;
|
||||||
|
|
||||||
use super::config_manager::ConfigManager;
|
use super::config_manager::ConfigManager;
|
||||||
use super::web::auth::SessionState;
|
use super::web::auth::SessionState;
|
||||||
|
|
||||||
|
@ -5,4 +7,11 @@ use super::web::auth::SessionState;
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
pub config_manager: ConfigManager,
|
pub config_manager: ConfigManager,
|
||||||
pub session_state: SessionState,
|
pub session_state: SessionState,
|
||||||
|
pub rpc_module: RpcModule<RpcState>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct RpcState {
|
||||||
|
pub config_manager: ConfigManager,
|
||||||
|
pub session_state: SessionState,
|
||||||
}
|
}
|
||||||
|
|
131
src/web/rpc.rs
131
src/web/rpc.rs
|
@ -1,42 +1,60 @@
|
||||||
use std::collections::HashMap;
|
use crate::AppState;
|
||||||
|
|
||||||
use super::super::definitions::network::StaticRoute;
|
|
||||||
use super::super::definitions::system::User;
|
|
||||||
use super::super::AppState;
|
|
||||||
use axum::routing::post;
|
use axum::routing::post;
|
||||||
use axum::{Json, Router};
|
use axum::{Json, Router};
|
||||||
use jsonrpsee::types::Params;
|
use jsonrpsee::core::traits::ToRpcParams;
|
||||||
use tower_cookies::{Cookie, Cookies};
|
use jsonrpsee::core::Error;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_json::value::RawValue;
|
||||||
|
|
||||||
use axum::{
|
use axum::{extract::Extension, extract::State, response::IntoResponse};
|
||||||
extract::Extension,
|
|
||||||
extract::State,
|
|
||||||
http::{Request, StatusCode},
|
|
||||||
middleware::{self, Next},
|
|
||||||
response::{IntoResponse, Response},
|
|
||||||
};
|
|
||||||
|
|
||||||
use jsonrpsee::server::{RpcModule, Server};
|
|
||||||
|
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
use custom_error::custom_error;
|
// TODO fix this "workaround"
|
||||||
|
struct ParamConverter {
|
||||||
custom_error! { ApiError
|
params: Option<Box<RawValue>>,
|
||||||
BadRequest = "Bad Request Parameters",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RpcRequest<'a> {
|
impl ToRpcParams for ParamConverter {
|
||||||
|
fn to_rpc_params(self) -> Result<Option<Box<RawValue>>, Error> {
|
||||||
|
let s = String::from_utf8(serde_json::to_vec(&self.params)?);
|
||||||
|
match s {
|
||||||
|
Ok(s) => {
|
||||||
|
return RawValue::from_string(s)
|
||||||
|
.map(Some)
|
||||||
|
.map_err(Error::ParseError)
|
||||||
|
}
|
||||||
|
// TODO make this a Parse error wrapping Utf8Error
|
||||||
|
Err(err) => return Err(Error::AlreadyStopped),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct RpcRequest {
|
||||||
id: i64,
|
id: i64,
|
||||||
params: Params<'a>,
|
params: Option<Box<RawValue>>,
|
||||||
jsonrpc: String,
|
jsonrpc: String,
|
||||||
method: String,
|
method: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RpcResponse<'a> {
|
#[derive(Clone, Deserialize, Serialize)]
|
||||||
|
struct RpcResponse {
|
||||||
id: i64,
|
id: i64,
|
||||||
payload: Params<'a>,
|
|
||||||
jsonrpc: String,
|
jsonrpc: String,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
result: Option<Box<RawValue>>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
error: Option<RpcErrorObject>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Deserialize, Serialize)]
|
||||||
|
|
||||||
|
struct RpcErrorObject {
|
||||||
|
code: i64,
|
||||||
|
message: String,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
data: Option<Box<RawValue>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn routes() -> Router<super::super::AppState> {
|
pub fn routes() -> Router<super::super::AppState> {
|
||||||
|
@ -46,49 +64,38 @@ pub fn routes() -> Router<super::super::AppState> {
|
||||||
async fn api_handler(
|
async fn api_handler(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
session: Extension<super::auth::Session>,
|
session: Extension<super::auth::Session>,
|
||||||
Json(rpc_request): Json<RpcRequest<'_>>,
|
body: String,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
info!("api hit! user: {:?}", session.username);
|
info!("api hit! user: {:?}", session.username);
|
||||||
let module = RpcModule::new(state);
|
|
||||||
module
|
|
||||||
.register_method("say_hello", |_, _| {
|
|
||||||
println!("say_hello method called!");
|
|
||||||
"Hello there!!"
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
module
|
// TODO handle Parse Error
|
||||||
.register_method("System.GetUsers", get_users)
|
let req: RpcRequest = serde_json::from_str(&body).unwrap();
|
||||||
.unwrap();
|
|
||||||
module
|
|
||||||
.register_method("Network.GetStaticRoutes", get_static_routes)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let res = module.call(&rpc_request.method, rpc_request.params).await;
|
// TODO check version
|
||||||
|
|
||||||
|
let params = ParamConverter { params: req.params };
|
||||||
|
|
||||||
|
// TODO check Permissions for method here?
|
||||||
|
|
||||||
|
let res: Result<Option<Box<RawValue>>, Error> =
|
||||||
|
state.rpc_module.call(&req.method, params).await;
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
Ok(res) => RpcResponse {
|
Ok(res) => Json(RpcResponse {
|
||||||
id: rpc_request.id,
|
id: req.id,
|
||||||
jsonrpc: rpc_request.jsonrpc,
|
jsonrpc: req.jsonrpc,
|
||||||
payload: res,
|
result: res,
|
||||||
},
|
error: None,
|
||||||
// TODO make Error Response
|
}),
|
||||||
Err(err) => RpcResponse {
|
Err(err) => Json(RpcResponse {
|
||||||
id: rpc_request.id,
|
id: req.id,
|
||||||
jsonrpc: rpc_request.jsonrpc,
|
jsonrpc: req.jsonrpc,
|
||||||
payload: res,
|
result: None,
|
||||||
},
|
error: Some(RpcErrorObject {
|
||||||
|
code: 10,
|
||||||
|
message: err.to_string(),
|
||||||
|
data: None,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_users(_: Params, state: &AppState) -> Result<HashMap<String, User>, String> {
|
|
||||||
Ok(state.config_manager.get_pending_config().system.users)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_static_routes(_: Params, state: &AppState) -> Result<Vec<StaticRoute>, String> {
|
|
||||||
Ok(state
|
|
||||||
.config_manager
|
|
||||||
.get_pending_config()
|
|
||||||
.network
|
|
||||||
.static_routes)
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue