add get methods for network rpcs
This commit is contained in:
@ -14,12 +14,15 @@ publish = false
|
||||
maintenance = { status = "actively-developed" }
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.51"
|
||||
env_logger = "0.9"
|
||||
jsonrpc-core = "18"
|
||||
jsonrpc-http-server = "18"
|
||||
log = "0.4"
|
||||
miniserde = "0.1.15"
|
||||
peach-stats = { path = "../peach-stats", features = ["miniserde_support"] }
|
||||
peach-network = { path = "../peach-network", features = ["serde_support"] }
|
||||
peach-stats = { path = "../peach-stats", features = ["serde_support"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
|
||||
[dev-dependencies]
|
||||
jsonrpc-test = "18"
|
||||
|
@ -1,12 +1,18 @@
|
||||
use std::fmt;
|
||||
|
||||
use jsonrpc_core::{Error as JsonRpcError, ErrorCode};
|
||||
use peach_network::NetworkError;
|
||||
use peach_stats::StatsError;
|
||||
use serde_json::Error as SerdeError;
|
||||
|
||||
/// Custom error type encapsulating all possible errors for a JSON-RPC server
|
||||
/// and associated methods.
|
||||
#[derive(Debug)]
|
||||
pub enum JsonRpcServerError {
|
||||
pub enum ServerError {
|
||||
/// An error returned from the `peach-network` library.
|
||||
Network(NetworkError),
|
||||
/// Failed to serialize a data structure.
|
||||
Serialize(SerdeError),
|
||||
/// An error returned from the `peach-stats` library.
|
||||
Stats(StatsError),
|
||||
/// An expected JSON-RPC method parameter was not provided.
|
||||
@ -15,32 +21,48 @@ pub enum JsonRpcServerError {
|
||||
ParseParameter(JsonRpcError),
|
||||
}
|
||||
|
||||
impl fmt::Display for JsonRpcServerError {
|
||||
impl fmt::Display for ServerError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
JsonRpcServerError::ParseParameter(ref source) => {
|
||||
ServerError::ParseParameter(ref source) => {
|
||||
write!(f, "Failed to parse parameter: {}", source)
|
||||
}
|
||||
JsonRpcServerError::MissingParameter(ref source) => {
|
||||
ServerError::MissingParameter(ref source) => {
|
||||
write!(f, "Missing expected parameter: {}", source)
|
||||
}
|
||||
JsonRpcServerError::Stats(ref source) => {
|
||||
ServerError::Network(ref source) => {
|
||||
write!(f, "{}", source)
|
||||
}
|
||||
ServerError::Serialize(ref source) => {
|
||||
write!(f, "Serde serialization failure: {}", source)
|
||||
}
|
||||
ServerError::Stats(ref source) => {
|
||||
write!(f, "{}", source)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<JsonRpcServerError> for JsonRpcError {
|
||||
fn from(err: JsonRpcServerError) -> Self {
|
||||
impl From<ServerError> for JsonRpcError {
|
||||
fn from(err: ServerError) -> Self {
|
||||
match &err {
|
||||
JsonRpcServerError::Stats(source) => JsonRpcError {
|
||||
ServerError::Network(source) => JsonRpcError {
|
||||
code: ErrorCode::ServerError(-32001),
|
||||
message: format!("{}", source),
|
||||
data: None,
|
||||
},
|
||||
JsonRpcServerError::MissingParameter(source) => source.clone(),
|
||||
JsonRpcServerError::ParseParameter(source) => source.clone(),
|
||||
ServerError::Stats(source) => JsonRpcError {
|
||||
code: ErrorCode::ServerError(-32003),
|
||||
message: format!("{}", source),
|
||||
data: None,
|
||||
},
|
||||
ServerError::Serialize(source) => JsonRpcError {
|
||||
code: ErrorCode::ServerError(-32000),
|
||||
message: format!("{}", source),
|
||||
data: None,
|
||||
},
|
||||
ServerError::MissingParameter(source) => source.clone(),
|
||||
ServerError::ParseParameter(source) => source.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,72 +5,378 @@
|
||||
use std::env;
|
||||
use std::result::Result;
|
||||
|
||||
use jsonrpc_core::{IoHandler, Value};
|
||||
use jsonrpc_core::{Error as RpcCoreError, IoHandler, Params, Value};
|
||||
use jsonrpc_http_server::{AccessControlAllowOrigin, DomainsValidation, ServerBuilder};
|
||||
use log::info;
|
||||
use miniserde::json;
|
||||
use peach_network::network;
|
||||
use peach_stats::stats;
|
||||
|
||||
mod error;
|
||||
use crate::error::JsonRpcServerError;
|
||||
mod params;
|
||||
|
||||
use crate::error::ServerError;
|
||||
use crate::params::{Iface, IfaceSsid};
|
||||
|
||||
/// Create JSON-RPC I/O handler, add RPC methods and launch HTTP server.
|
||||
pub fn run() -> Result<(), JsonRpcServerError> {
|
||||
pub fn run() -> Result<(), ServerError> {
|
||||
info!("Starting up.");
|
||||
|
||||
info!("Creating JSON-RPC I/O handler.");
|
||||
let mut io = IoHandler::default();
|
||||
|
||||
io.add_sync_method("ping", |_| Ok(Value::String("success".to_string())));
|
||||
io.add_method("ping", |_| async {
|
||||
Ok(Value::String("success".to_string()))
|
||||
});
|
||||
|
||||
// TODO: add blocks of methods according to provided flags
|
||||
|
||||
/* PEACH-NETWORK RPC METHODS */
|
||||
|
||||
// get - all network rpc methods for querying state
|
||||
|
||||
io.add_method("available_networks", |params: Params| async move {
|
||||
let parsed: Result<Iface, RpcCoreError> = params.parse();
|
||||
match parsed {
|
||||
Ok(i) => {
|
||||
let iface = i.iface;
|
||||
match network::available_networks(&iface).map_err(ServerError::Network)? {
|
||||
Some(list) => {
|
||||
let json_list =
|
||||
serde_json::to_string(&list).map_err(ServerError::Serialize)?;
|
||||
Ok(Value::String(json_list))
|
||||
}
|
||||
// return `Null` if no networks were found
|
||||
None => Ok(Value::Null),
|
||||
}
|
||||
}
|
||||
Err(e) => Err(RpcCoreError::from(ServerError::MissingParameter(e))),
|
||||
}
|
||||
});
|
||||
|
||||
io.add_method("id", |params: Params| async move {
|
||||
let parsed: Result<IfaceSsid, RpcCoreError> = params.parse();
|
||||
match parsed {
|
||||
Ok(i) => {
|
||||
let iface = i.iface;
|
||||
let ssid = i.ssid;
|
||||
match network::id(&iface, &ssid).map_err(ServerError::Network)? {
|
||||
Some(id) => Ok(Value::String(id)),
|
||||
None => Ok(Value::Null),
|
||||
}
|
||||
}
|
||||
Err(e) => Err(RpcCoreError::from(ServerError::MissingParameter(e))),
|
||||
}
|
||||
});
|
||||
|
||||
io.add_method("ip", |params: Params| async move {
|
||||
let parsed: Result<Iface, RpcCoreError> = params.parse();
|
||||
match parsed {
|
||||
Ok(i) => {
|
||||
let iface = i.iface;
|
||||
match network::ip(&iface).map_err(ServerError::Network)? {
|
||||
Some(ip) => Ok(Value::String(ip)),
|
||||
None => Ok(Value::Null),
|
||||
}
|
||||
}
|
||||
Err(e) => Err(RpcCoreError::from(ServerError::MissingParameter(e))),
|
||||
}
|
||||
});
|
||||
|
||||
io.add_method("rssi", |params: Params| async move {
|
||||
let parsed: Result<Iface, RpcCoreError> = params.parse();
|
||||
match parsed {
|
||||
Ok(i) => {
|
||||
let iface = i.iface;
|
||||
match network::rssi(&iface).map_err(ServerError::Network)? {
|
||||
Some(rssi) => Ok(Value::String(rssi)),
|
||||
None => Ok(Value::Null),
|
||||
}
|
||||
}
|
||||
Err(e) => Err(RpcCoreError::from(ServerError::MissingParameter(e))),
|
||||
}
|
||||
});
|
||||
|
||||
io.add_method("rssi_percent", |params: Params| async move {
|
||||
let parsed: Result<Iface, RpcCoreError> = params.parse();
|
||||
match parsed {
|
||||
Ok(i) => {
|
||||
let iface = i.iface;
|
||||
match network::rssi_percent(&iface).map_err(ServerError::Network)? {
|
||||
Some(rssi) => Ok(Value::String(rssi)),
|
||||
None => Ok(Value::Null),
|
||||
}
|
||||
}
|
||||
Err(e) => Err(RpcCoreError::from(ServerError::MissingParameter(e))),
|
||||
}
|
||||
});
|
||||
|
||||
io.add_method("saved_networks", |_| async {
|
||||
let list = network::saved_networks().map_err(ServerError::Network)?;
|
||||
match list {
|
||||
Some(list) => {
|
||||
let json_list = serde_json::to_string(&list).map_err(ServerError::Serialize)?;
|
||||
Ok(Value::String(json_list))
|
||||
}
|
||||
None => Ok(Value::Null),
|
||||
}
|
||||
});
|
||||
|
||||
io.add_method("ssid", |params: Params| async move {
|
||||
let parsed: Result<Iface, RpcCoreError> = params.parse();
|
||||
match parsed {
|
||||
Ok(i) => {
|
||||
let iface = i.iface;
|
||||
match network::ssid(&iface).map_err(ServerError::Network)? {
|
||||
Some(ip) => Ok(Value::String(ip)),
|
||||
None => Ok(Value::Null),
|
||||
}
|
||||
}
|
||||
Err(e) => Err(RpcCoreError::from(ServerError::MissingParameter(e))),
|
||||
}
|
||||
});
|
||||
|
||||
io.add_method("state", |params: Params| async move {
|
||||
let parsed: Result<Iface, RpcCoreError> = params.parse();
|
||||
match parsed {
|
||||
Ok(i) => {
|
||||
let iface = i.iface;
|
||||
match network::state(&iface).map_err(ServerError::Network)? {
|
||||
Some(state) => Ok(Value::String(state)),
|
||||
None => Ok(Value::Null),
|
||||
}
|
||||
}
|
||||
Err(e) => Err(RpcCoreError::from(ServerError::MissingParameter(e))),
|
||||
}
|
||||
});
|
||||
|
||||
io.add_method("status", |params: Params| async move {
|
||||
let parsed: Result<Iface, RpcCoreError> = params.parse();
|
||||
match parsed {
|
||||
Ok(i) => {
|
||||
let iface = i.iface;
|
||||
match network::status(&iface).map_err(ServerError::Network)? {
|
||||
Some(status) => {
|
||||
let json_status =
|
||||
serde_json::to_string(&status).map_err(ServerError::Serialize)?;
|
||||
Ok(Value::String(json_status))
|
||||
}
|
||||
None => Ok(Value::Null),
|
||||
}
|
||||
}
|
||||
Err(e) => Err(RpcCoreError::from(ServerError::MissingParameter(e))),
|
||||
}
|
||||
});
|
||||
|
||||
io.add_method("traffic", |params: Params| async move {
|
||||
let parsed: Result<Iface, RpcCoreError> = params.parse();
|
||||
match parsed {
|
||||
Ok(i) => {
|
||||
let iface = i.iface;
|
||||
match network::traffic(&iface).map_err(ServerError::Network)? {
|
||||
Some(traffic) => {
|
||||
let json_traffic =
|
||||
serde_json::to_string(&traffic).map_err(ServerError::Serialize)?;
|
||||
Ok(Value::String(json_traffic))
|
||||
}
|
||||
None => Ok(Value::Null),
|
||||
}
|
||||
}
|
||||
Err(e) => Err(RpcCoreError::from(ServerError::MissingParameter(e))),
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
// set - all network rpc methods for modifying state
|
||||
|
||||
io.add_method("activate_ap", move |_| {
|
||||
network::activate_ap()?;
|
||||
|
||||
Ok(Value::String("success".to_string()))
|
||||
});
|
||||
|
||||
io.add_method("activate_client", move |_| {
|
||||
network::activate_client()?;
|
||||
|
||||
Ok(Value::String("success".to_string()))
|
||||
});
|
||||
|
||||
io.add_method("add", move |params: Params| {
|
||||
let w: Result<WiFi, Error> = params.parse();
|
||||
match w {
|
||||
Ok(w) => match network::add(&w) {
|
||||
Ok(_) => Ok(Value::String("success".to_string())),
|
||||
Err(e) => Err(Error::from(e)),
|
||||
},
|
||||
Err(e) => Err(Error::from(NetworkError::MissingParams { e })),
|
||||
}
|
||||
});
|
||||
|
||||
io.add_method("check_iface", move |_| {
|
||||
network::check_iface()?;
|
||||
|
||||
Ok(Value::String("success".to_string()))
|
||||
});
|
||||
|
||||
io.add_method("delete", move |params: Params| {
|
||||
let i: Result<IfaceId, Error> = params.parse();
|
||||
match i {
|
||||
Ok(i) => {
|
||||
let id = i.id;
|
||||
let iface = i.iface;
|
||||
match network::delete(&id, &iface) {
|
||||
Ok(_) => Ok(Value::String("success".to_string())),
|
||||
Err(_) => Err(Error::from(NetworkError::Delete { id, iface })),
|
||||
}
|
||||
}
|
||||
Err(e) => Err(Error::from(NetworkError::MissingParams { e })),
|
||||
}
|
||||
});
|
||||
|
||||
io.add_method("disable", move |params: Params| {
|
||||
let i: Result<IfaceId, Error> = params.parse();
|
||||
match i {
|
||||
Ok(i) => {
|
||||
let id = i.id;
|
||||
let iface = i.iface;
|
||||
match network::disable(&id, &iface) {
|
||||
Ok(_) => Ok(Value::String("success".to_string())),
|
||||
Err(_) => Err(Error::from(NetworkError::Disable { id, iface })),
|
||||
}
|
||||
}
|
||||
Err(e) => Err(Error::from(NetworkError::MissingParams { e })),
|
||||
}
|
||||
});
|
||||
|
||||
io.add_method("disconnect", move |params: Params| {
|
||||
let i: Result<Iface, Error> = params.parse();
|
||||
match i {
|
||||
Ok(i) => {
|
||||
let iface = i.iface;
|
||||
match network::disconnect(&iface) {
|
||||
Ok(_) => Ok(Value::String("success".to_string())),
|
||||
Err(_) => Err(Error::from(NetworkError::Disconnect { iface })),
|
||||
}
|
||||
}
|
||||
Err(e) => Err(Error::from(NetworkError::MissingParams { e })),
|
||||
}
|
||||
});
|
||||
|
||||
io.add_method("modify", move |params: Params| {
|
||||
let i: Result<IfaceIdPass, Error> = params.parse();
|
||||
match i {
|
||||
Ok(i) => {
|
||||
let iface = i.iface;
|
||||
let id = i.id;
|
||||
let pass = i.pass;
|
||||
match network::modify(&iface, &id, &pass) {
|
||||
Ok(_) => Ok(Value::String("success".to_string())),
|
||||
Err(_) => Err(Error::from(NetworkError::Modify { iface, id })),
|
||||
}
|
||||
}
|
||||
Err(e) => Err(Error::from(NetworkError::MissingParams { e })),
|
||||
}
|
||||
});
|
||||
|
||||
io.add_method("reassociate", move |params: Params| {
|
||||
let i: Result<Iface, Error> = params.parse();
|
||||
match i {
|
||||
Ok(i) => {
|
||||
let iface = i.iface;
|
||||
match network::reassociate(&iface) {
|
||||
Ok(_) => Ok(Value::String("success".to_string())),
|
||||
Err(_) => Err(Error::from(NetworkError::Reassociate { iface })),
|
||||
}
|
||||
}
|
||||
Err(e) => Err(Error::from(NetworkError::MissingParams { e })),
|
||||
}
|
||||
});
|
||||
|
||||
io.add_method("reconfigure", move |_| match network::reconfigure() {
|
||||
Ok(_) => Ok(Value::String("success".to_string())),
|
||||
Err(_) => Err(Error::from(NetworkError::Reconfigure)),
|
||||
});
|
||||
|
||||
io.add_method("reconnect", move |params: Params| {
|
||||
let i: Result<Iface, Error> = params.parse();
|
||||
match i {
|
||||
Ok(i) => {
|
||||
let iface = i.iface;
|
||||
match network::reconnect(&iface) {
|
||||
Ok(_) => Ok(Value::String("success".to_string())),
|
||||
Err(_) => Err(Error::from(NetworkError::Reconnect { iface })),
|
||||
}
|
||||
}
|
||||
Err(e) => Err(Error::from(NetworkError::MissingParams { e })),
|
||||
}
|
||||
});
|
||||
|
||||
io.add_method("save", move |_| match network::save() {
|
||||
Ok(_) => Ok(Value::String("success".to_string())),
|
||||
Err(_) => Err(Error::from(NetworkError::Save)),
|
||||
});
|
||||
|
||||
io.add_method("connect", move |params: Params| {
|
||||
let i: Result<IfaceId, Error> = params.parse();
|
||||
match i {
|
||||
Ok(i) => {
|
||||
let id = i.id;
|
||||
let iface = i.iface;
|
||||
match network::connect(&id, &iface) {
|
||||
Ok(_) => Ok(Value::String("success".to_string())),
|
||||
Err(_) => Err(Error::from(NetworkError::Connect { id, iface })),
|
||||
}
|
||||
}
|
||||
Err(e) => Err(Error::from(NetworkError::MissingParams { e })),
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
/* PEACH-STATS RPC METHODS */
|
||||
|
||||
io.add_sync_method("cpu_stats", move |_| {
|
||||
io.add_method("cpu_stats", |_| async {
|
||||
info!("Fetching CPU statistics.");
|
||||
let cpu = stats::cpu_stats().map_err(JsonRpcServerError::Stats)?;
|
||||
let json_cpu = json::to_string(&cpu);
|
||||
let cpu = stats::cpu_stats().map_err(ServerError::Stats)?;
|
||||
let json_cpu = serde_json::to_string(&cpu).map_err(ServerError::Serialize)?;
|
||||
|
||||
Ok(Value::String(json_cpu))
|
||||
});
|
||||
|
||||
io.add_sync_method("cpu_stats_percent", move |_| {
|
||||
io.add_method("cpu_stats_percent", |_| async {
|
||||
info!("Fetching CPU statistics as percentages.");
|
||||
let cpu = stats::cpu_stats_percent().map_err(JsonRpcServerError::Stats)?;
|
||||
let json_cpu = json::to_string(&cpu);
|
||||
let cpu = stats::cpu_stats_percent().map_err(ServerError::Stats)?;
|
||||
let json_cpu = serde_json::to_string(&cpu).map_err(ServerError::Serialize)?;
|
||||
|
||||
Ok(Value::String(json_cpu))
|
||||
});
|
||||
|
||||
io.add_sync_method("disk_usage", move |_| {
|
||||
io.add_method("disk_usage", |_| async {
|
||||
info!("Fetching disk usage statistics.");
|
||||
let disks = stats::disk_usage().map_err(JsonRpcServerError::Stats)?;
|
||||
let json_disks = json::to_string(&disks);
|
||||
let disks = stats::disk_usage().map_err(ServerError::Stats)?;
|
||||
let json_disks = serde_json::to_string(&disks).map_err(ServerError::Serialize)?;
|
||||
|
||||
Ok(Value::String(json_disks))
|
||||
});
|
||||
|
||||
io.add_sync_method("load_average", move |_| {
|
||||
io.add_method("load_average", |_| async {
|
||||
info!("Fetching system load average statistics.");
|
||||
let avg = stats::load_average().map_err(JsonRpcServerError::Stats)?;
|
||||
let json_avg = json::to_string(&avg);
|
||||
let avg = stats::load_average().map_err(ServerError::Stats)?;
|
||||
let json_avg = serde_json::to_string(&avg).map_err(ServerError::Serialize)?;
|
||||
|
||||
Ok(Value::String(json_avg))
|
||||
});
|
||||
|
||||
io.add_sync_method("mem_stats", move |_| {
|
||||
io.add_method("mem_stats", |_| async {
|
||||
info!("Fetching current memory statistics.");
|
||||
let mem = stats::mem_stats().map_err(JsonRpcServerError::Stats)?;
|
||||
let json_mem = json::to_string(&mem);
|
||||
let mem = stats::mem_stats().map_err(ServerError::Stats)?;
|
||||
let json_mem = serde_json::to_string(&mem).map_err(ServerError::Serialize)?;
|
||||
|
||||
Ok(Value::String(json_mem))
|
||||
});
|
||||
|
||||
io.add_sync_method("uptime", move |_| {
|
||||
io.add_method("uptime", |_| async {
|
||||
info!("Fetching system uptime.");
|
||||
let uptime = stats::uptime().map_err(JsonRpcServerError::Stats)?;
|
||||
let json_uptime = json::to_string(&uptime);
|
||||
let uptime = stats::uptime().map_err(ServerError::Stats)?;
|
||||
let json_uptime = serde_json::to_string(&uptime).map_err(ServerError::Serialize)?;
|
||||
|
||||
Ok(Value::String(json_uptime))
|
||||
});
|
||||
@ -106,7 +412,7 @@ mod tests {
|
||||
fn rpc_success() {
|
||||
let rpc = {
|
||||
let mut io = IoHandler::new();
|
||||
io.add_sync_method("rpc_success_response", |_| {
|
||||
io.add_method("rpc_success_response", |_| async {
|
||||
Ok(Value::String("success".into()))
|
||||
});
|
||||
test_rpc::Rpc::from(io)
|
||||
@ -119,13 +425,13 @@ mod tests {
|
||||
fn rpc_parse_error() {
|
||||
let rpc = {
|
||||
let mut io = IoHandler::new();
|
||||
io.add_sync_method("rpc_parse_error", |_| {
|
||||
io.add_method("rpc_parse_error", |_| async {
|
||||
let e = JsonRpcError {
|
||||
code: ErrorCode::ParseError,
|
||||
message: String::from("Parse error"),
|
||||
data: None,
|
||||
};
|
||||
Err(JsonRpcError::from(JsonRpcServerError::MissingParameter(e)))
|
||||
Err(JsonRpcError::from(ServerError::MissingParameter(e)))
|
||||
});
|
||||
test_rpc::Rpc::from(io)
|
||||
};
|
||||
|
23
peach-jsonrpc-server/src/params.rs
Normal file
23
peach-jsonrpc-server/src/params.rs
Normal file
@ -0,0 +1,23 @@
|
||||
//! Data structures for parsing JSON-RPC method parameters.
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
/// Network interface name.
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Iface {
|
||||
pub iface: String,
|
||||
}
|
||||
|
||||
/// Network interface name and network identifier.
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct IfaceId {
|
||||
pub iface: String,
|
||||
pub id: String,
|
||||
}
|
||||
|
||||
/// Network interface name and network SSID.
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct IfaceSsid {
|
||||
pub iface: String,
|
||||
pub ssid: String,
|
||||
}
|
Reference in New Issue
Block a user