Compare commits
7 Commits
main
...
network_rp
Author | SHA1 | Date |
---|---|---|
glyph | 4d08323d77 | |
glyph | df91968762 | |
glyph | 9255abb078 | |
glyph | 1ad956c0c7 | |
glyph | 39c15d0fe5 | |
glyph | fd12e97bc4 | |
glyph | 318fa9768a |
|
@ -2472,15 +2472,17 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "peach-jsonrpc-server"
|
name = "peach-jsonrpc-server"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"env_logger 0.9.0",
|
"env_logger 0.9.0",
|
||||||
"jsonrpc-core 18.0.0",
|
"jsonrpc-core 18.0.0",
|
||||||
"jsonrpc-http-server 18.0.0",
|
"jsonrpc-http-server 18.0.0",
|
||||||
"jsonrpc-test 18.0.0",
|
"jsonrpc-test 18.0.0",
|
||||||
"log 0.4.14",
|
"log 0.4.14",
|
||||||
"miniserde",
|
"peach-network",
|
||||||
"peach-stats",
|
"peach-stats",
|
||||||
|
"serde 1.0.130",
|
||||||
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "peach-jsonrpc-server"
|
name = "peach-jsonrpc-server"
|
||||||
authors = ["Andrew Reid <glyph@mycelial.technology>"]
|
authors = ["Andrew Reid <glyph@mycelial.technology>"]
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "JSON-RPC over HTTP for the PeachCloud system. Provides a JSON-RPC wrapper around the stats, network and oled libraries."
|
description = "JSON-RPC over HTTP for the PeachCloud system. Provides a JSON-RPC wrapper around the stats, network and oled libraries."
|
||||||
homepage = "https://opencollective.com/peachcloud"
|
homepage = "https://opencollective.com/peachcloud"
|
||||||
|
@ -18,8 +18,10 @@ env_logger = "0.9"
|
||||||
jsonrpc-core = "18"
|
jsonrpc-core = "18"
|
||||||
jsonrpc-http-server = "18"
|
jsonrpc-http-server = "18"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
miniserde = "0.1.15"
|
peach-network = { path = "../peach-network", features = ["serde_support"] }
|
||||||
peach-stats = { path = "../peach-stats", features = ["miniserde_support"] }
|
peach-stats = { path = "../peach-stats", features = ["serde_support"] }
|
||||||
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
serde_json = "1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
jsonrpc-test = "18"
|
jsonrpc-test = "18"
|
||||||
|
|
|
@ -1,12 +1,18 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use jsonrpc_core::{Error as JsonRpcError, ErrorCode};
|
use jsonrpc_core::{Error as JsonRpcError, ErrorCode};
|
||||||
|
use peach_network::NetworkError;
|
||||||
use peach_stats::StatsError;
|
use peach_stats::StatsError;
|
||||||
|
use serde_json::Error as SerdeError;
|
||||||
|
|
||||||
/// Custom error type encapsulating all possible errors for a JSON-RPC server
|
/// Custom error type encapsulating all possible errors for a JSON-RPC server
|
||||||
/// and associated methods.
|
/// and associated methods.
|
||||||
#[derive(Debug)]
|
#[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.
|
/// An error returned from the `peach-stats` library.
|
||||||
Stats(StatsError),
|
Stats(StatsError),
|
||||||
/// An expected JSON-RPC method parameter was not provided.
|
/// An expected JSON-RPC method parameter was not provided.
|
||||||
|
@ -15,32 +21,48 @@ pub enum JsonRpcServerError {
|
||||||
ParseParameter(JsonRpcError),
|
ParseParameter(JsonRpcError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for JsonRpcServerError {
|
impl fmt::Display for ServerError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
JsonRpcServerError::ParseParameter(ref source) => {
|
ServerError::ParseParameter(ref source) => {
|
||||||
write!(f, "Failed to parse parameter: {}", source)
|
write!(f, "Failed to parse parameter: {}", source)
|
||||||
}
|
}
|
||||||
JsonRpcServerError::MissingParameter(ref source) => {
|
ServerError::MissingParameter(ref source) => {
|
||||||
write!(f, "Missing expected parameter: {}", 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)
|
write!(f, "{}", source)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<JsonRpcServerError> for JsonRpcError {
|
impl From<ServerError> for JsonRpcError {
|
||||||
fn from(err: JsonRpcServerError) -> Self {
|
fn from(err: ServerError) -> Self {
|
||||||
match &err {
|
match &err {
|
||||||
JsonRpcServerError::Stats(source) => JsonRpcError {
|
ServerError::Network(source) => JsonRpcError {
|
||||||
code: ErrorCode::ServerError(-32001),
|
code: ErrorCode::ServerError(-32001),
|
||||||
message: format!("{}", source),
|
message: format!("{}", source),
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
JsonRpcServerError::MissingParameter(source) => source.clone(),
|
ServerError::Stats(source) => JsonRpcError {
|
||||||
JsonRpcServerError::ParseParameter(source) => source.clone(),
|
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,332 @@
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::result::Result;
|
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 jsonrpc_http_server::{AccessControlAllowOrigin, DomainsValidation, ServerBuilder};
|
||||||
use log::info;
|
use log::info;
|
||||||
use miniserde::json;
|
use peach_network::network;
|
||||||
use peach_stats::stats;
|
use peach_stats::stats;
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
use crate::error::JsonRpcServerError;
|
mod params;
|
||||||
|
|
||||||
|
use crate::error::ServerError;
|
||||||
|
use crate::params::{Iface, IfaceId, IfaceIdPass, IfaceSsid, WiFi, WlanAndAp};
|
||||||
|
|
||||||
/// Create JSON-RPC I/O handler, add RPC methods and launch HTTP server.
|
/// 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!("Starting up.");
|
||||||
|
|
||||||
info!("Creating JSON-RPC I/O handler.");
|
info!("Creating JSON-RPC I/O handler.");
|
||||||
let mut io = IoHandler::default();
|
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
|
// 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) => {
|
||||||
|
match network::available_networks(&i.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) => match network::id(&i.iface, &i.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) => match network::ip(&i.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) => match network::rssi(&i.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) => match network::rssi_percent(&i.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) => match network::ssid(&i.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) => match network::state(&i.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) => match network::status(&i.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) => match network::traffic(&i.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("add", |params: Params| async move {
|
||||||
|
let parsed: Result<WiFi, RpcCoreError> = params.parse();
|
||||||
|
match parsed {
|
||||||
|
Ok(w) => match network::add(&w.iface, &w.ssid, &w.pass) {
|
||||||
|
Ok(_) => Ok(Value::String("success".to_string())),
|
||||||
|
Err(e) => Err(RpcCoreError::from(ServerError::Network(e))),
|
||||||
|
},
|
||||||
|
Err(e) => Err(RpcCoreError::from(ServerError::MissingParameter(e))),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
io.add_method("check_iface", |params: Params| async move {
|
||||||
|
let parsed: Result<WlanAndAp, RpcCoreError> = params.parse();
|
||||||
|
match parsed {
|
||||||
|
Ok(w) => match network::check_iface(&w.wlan_iface, &w.ap_iface) {
|
||||||
|
Ok(_) => Ok(Value::String("success".to_string())),
|
||||||
|
Err(e) => Err(RpcCoreError::from(ServerError::Network(e))),
|
||||||
|
},
|
||||||
|
Err(e) => Err(RpcCoreError::from(ServerError::MissingParameter(e))),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
io.add_method("connect", |params: Params| async move {
|
||||||
|
let parsed: Result<IfaceId, RpcCoreError> = params.parse();
|
||||||
|
match parsed {
|
||||||
|
Ok(i) => match network::connect(&i.id, &i.iface) {
|
||||||
|
Ok(_) => Ok(Value::String("success".to_string())),
|
||||||
|
Err(e) => Err(RpcCoreError::from(ServerError::Network(e))),
|
||||||
|
},
|
||||||
|
Err(e) => Err(RpcCoreError::from(ServerError::MissingParameter(e))),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
io.add_method("delete", |params: Params| async move {
|
||||||
|
let parsed: Result<IfaceId, RpcCoreError> = params.parse();
|
||||||
|
match parsed {
|
||||||
|
Ok(i) => match network::delete(&i.id, &i.iface) {
|
||||||
|
Ok(_) => Ok(Value::String("success".to_string())),
|
||||||
|
Err(e) => Err(RpcCoreError::from(ServerError::Network(e))),
|
||||||
|
},
|
||||||
|
Err(e) => Err(RpcCoreError::from(ServerError::MissingParameter(e))),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
io.add_method("disable", |params: Params| async move {
|
||||||
|
let parsed: Result<IfaceId, RpcCoreError> = params.parse();
|
||||||
|
match parsed {
|
||||||
|
Ok(i) => match network::disable(&i.id, &i.iface) {
|
||||||
|
Ok(_) => Ok(Value::String("success".to_string())),
|
||||||
|
Err(e) => Err(RpcCoreError::from(ServerError::Network(e))),
|
||||||
|
},
|
||||||
|
Err(e) => Err(RpcCoreError::from(ServerError::MissingParameter(e))),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
io.add_method("disconnect", |params: Params| async move {
|
||||||
|
let parsed: Result<Iface, RpcCoreError> = params.parse();
|
||||||
|
match parsed {
|
||||||
|
Ok(i) => match network::disconnect(&i.iface) {
|
||||||
|
Ok(_) => Ok(Value::String("success".to_string())),
|
||||||
|
Err(e) => Err(RpcCoreError::from(ServerError::Network(e))),
|
||||||
|
},
|
||||||
|
Err(e) => Err(RpcCoreError::from(ServerError::MissingParameter(e))),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
io.add_method("modify", |params: Params| async move {
|
||||||
|
let parsed: Result<IfaceIdPass, RpcCoreError> = params.parse();
|
||||||
|
match parsed {
|
||||||
|
Ok(i) => match network::modify(&i.iface, &i.id, &i.pass) {
|
||||||
|
Ok(_) => Ok(Value::String("success".to_string())),
|
||||||
|
Err(e) => Err(RpcCoreError::from(ServerError::Network(e))),
|
||||||
|
},
|
||||||
|
Err(e) => Err(RpcCoreError::from(ServerError::MissingParameter(e))),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
io.add_method("reassociate", |params: Params| async move {
|
||||||
|
let parsed: Result<Iface, RpcCoreError> = params.parse();
|
||||||
|
match parsed {
|
||||||
|
Ok(i) => match network::reassociate(&i.iface) {
|
||||||
|
Ok(_) => Ok(Value::String("success".to_string())),
|
||||||
|
Err(e) => Err(RpcCoreError::from(ServerError::Network(e))),
|
||||||
|
},
|
||||||
|
Err(e) => Err(RpcCoreError::from(ServerError::MissingParameter(e))),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
io.add_method("reconfigure", |_| async {
|
||||||
|
match network::reconfigure() {
|
||||||
|
Ok(_) => Ok(Value::String("success".to_string())),
|
||||||
|
Err(e) => Err(RpcCoreError::from(ServerError::Network(e))),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
io.add_method("reconnect", |params: Params| async move {
|
||||||
|
let parsed: Result<Iface, RpcCoreError> = params.parse();
|
||||||
|
match parsed {
|
||||||
|
Ok(i) => match network::reconnect(&i.iface) {
|
||||||
|
Ok(_) => Ok(Value::String("success".to_string())),
|
||||||
|
Err(e) => Err(RpcCoreError::from(ServerError::Network(e))),
|
||||||
|
},
|
||||||
|
Err(e) => Err(RpcCoreError::from(ServerError::MissingParameter(e))),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
io.add_method("save", |_| async {
|
||||||
|
match network::save() {
|
||||||
|
Ok(_) => Ok(Value::String("success".to_string())),
|
||||||
|
Err(e) => Err(RpcCoreError::from(ServerError::Network(e))),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
io.add_method("start_iface_service", |params: Params| async move {
|
||||||
|
let parsed: Result<Iface, RpcCoreError> = params.parse();
|
||||||
|
match parsed {
|
||||||
|
Ok(i) => match network::start_iface_service(&i.iface) {
|
||||||
|
Ok(_) => Ok(Value::String("success".to_string())),
|
||||||
|
Err(e) => Err(RpcCoreError::from(ServerError::Network(e))),
|
||||||
|
},
|
||||||
|
Err(e) => Err(RpcCoreError::from(ServerError::MissingParameter(e))),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/* PEACH-STATS RPC METHODS */
|
/* PEACH-STATS RPC METHODS */
|
||||||
|
|
||||||
io.add_sync_method("cpu_stats", move |_| {
|
io.add_method("cpu_stats", |_| async {
|
||||||
info!("Fetching CPU statistics.");
|
info!("Fetching CPU statistics.");
|
||||||
let cpu = stats::cpu_stats().map_err(JsonRpcServerError::Stats)?;
|
let cpu = stats::cpu_stats().map_err(ServerError::Stats)?;
|
||||||
let json_cpu = json::to_string(&cpu);
|
let json_cpu = serde_json::to_string(&cpu).map_err(ServerError::Serialize)?;
|
||||||
|
|
||||||
Ok(Value::String(json_cpu))
|
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.");
|
info!("Fetching CPU statistics as percentages.");
|
||||||
let cpu = stats::cpu_stats_percent().map_err(JsonRpcServerError::Stats)?;
|
let cpu = stats::cpu_stats_percent().map_err(ServerError::Stats)?;
|
||||||
let json_cpu = json::to_string(&cpu);
|
let json_cpu = serde_json::to_string(&cpu).map_err(ServerError::Serialize)?;
|
||||||
|
|
||||||
Ok(Value::String(json_cpu))
|
Ok(Value::String(json_cpu))
|
||||||
});
|
});
|
||||||
|
|
||||||
io.add_sync_method("disk_usage", move |_| {
|
io.add_method("disk_usage", |_| async {
|
||||||
info!("Fetching disk usage statistics.");
|
info!("Fetching disk usage statistics.");
|
||||||
let disks = stats::disk_usage().map_err(JsonRpcServerError::Stats)?;
|
let disks = stats::disk_usage().map_err(ServerError::Stats)?;
|
||||||
let json_disks = json::to_string(&disks);
|
let json_disks = serde_json::to_string(&disks).map_err(ServerError::Serialize)?;
|
||||||
|
|
||||||
Ok(Value::String(json_disks))
|
Ok(Value::String(json_disks))
|
||||||
});
|
});
|
||||||
|
|
||||||
io.add_sync_method("load_average", move |_| {
|
io.add_method("load_average", |_| async {
|
||||||
info!("Fetching system load average statistics.");
|
info!("Fetching system load average statistics.");
|
||||||
let avg = stats::load_average().map_err(JsonRpcServerError::Stats)?;
|
let avg = stats::load_average().map_err(ServerError::Stats)?;
|
||||||
let json_avg = json::to_string(&avg);
|
let json_avg = serde_json::to_string(&avg).map_err(ServerError::Serialize)?;
|
||||||
|
|
||||||
Ok(Value::String(json_avg))
|
Ok(Value::String(json_avg))
|
||||||
});
|
});
|
||||||
|
|
||||||
io.add_sync_method("mem_stats", move |_| {
|
io.add_method("mem_stats", |_| async {
|
||||||
info!("Fetching current memory statistics.");
|
info!("Fetching current memory statistics.");
|
||||||
let mem = stats::mem_stats().map_err(JsonRpcServerError::Stats)?;
|
let mem = stats::mem_stats().map_err(ServerError::Stats)?;
|
||||||
let json_mem = json::to_string(&mem);
|
let json_mem = serde_json::to_string(&mem).map_err(ServerError::Serialize)?;
|
||||||
|
|
||||||
Ok(Value::String(json_mem))
|
Ok(Value::String(json_mem))
|
||||||
});
|
});
|
||||||
|
|
||||||
io.add_sync_method("uptime", move |_| {
|
io.add_method("uptime", |_| async {
|
||||||
info!("Fetching system uptime.");
|
info!("Fetching system uptime.");
|
||||||
let uptime = stats::uptime().map_err(JsonRpcServerError::Stats)?;
|
let uptime = stats::uptime().map_err(ServerError::Stats)?;
|
||||||
let json_uptime = json::to_string(&uptime);
|
let json_uptime = serde_json::to_string(&uptime).map_err(ServerError::Serialize)?;
|
||||||
|
|
||||||
Ok(Value::String(json_uptime))
|
Ok(Value::String(json_uptime))
|
||||||
});
|
});
|
||||||
|
@ -106,7 +366,7 @@ mod tests {
|
||||||
fn rpc_success() {
|
fn rpc_success() {
|
||||||
let rpc = {
|
let rpc = {
|
||||||
let mut io = IoHandler::new();
|
let mut io = IoHandler::new();
|
||||||
io.add_sync_method("rpc_success_response", |_| {
|
io.add_method("rpc_success_response", |_| async {
|
||||||
Ok(Value::String("success".into()))
|
Ok(Value::String("success".into()))
|
||||||
});
|
});
|
||||||
test_rpc::Rpc::from(io)
|
test_rpc::Rpc::from(io)
|
||||||
|
@ -119,13 +379,13 @@ mod tests {
|
||||||
fn rpc_parse_error() {
|
fn rpc_parse_error() {
|
||||||
let rpc = {
|
let rpc = {
|
||||||
let mut io = IoHandler::new();
|
let mut io = IoHandler::new();
|
||||||
io.add_sync_method("rpc_parse_error", |_| {
|
io.add_method("rpc_parse_error", |_| async {
|
||||||
let e = JsonRpcError {
|
let e = JsonRpcError {
|
||||||
code: ErrorCode::ParseError,
|
code: ErrorCode::ParseError,
|
||||||
message: String::from("Parse error"),
|
message: String::from("Parse error"),
|
||||||
data: None,
|
data: None,
|
||||||
};
|
};
|
||||||
Err(JsonRpcError::from(JsonRpcServerError::MissingParameter(e)))
|
Err(JsonRpcError::from(ServerError::MissingParameter(e)))
|
||||||
});
|
});
|
||||||
test_rpc::Rpc::from(io)
|
test_rpc::Rpc::from(io)
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,12 +10,51 @@
|
||||||
//!
|
//!
|
||||||
//! | Method | Description | Returns |
|
//! | Method | Description | Returns |
|
||||||
//! | --- | --- | --- |
|
//! | --- | --- | --- |
|
||||||
|
//! | `ping` | Microservice status | `success` if running |
|
||||||
|
//!
|
||||||
|
//! ### Network
|
||||||
|
//!
|
||||||
|
//! Methods for **retrieving data**:
|
||||||
|
//!
|
||||||
|
//! | Method | Description | Returns |
|
||||||
|
//! | --- | --- | --- |
|
||||||
|
//! | `available_networks` | `iface` | List SSID, flags (security), frequency and signal level for all networks in range of given interface |
|
||||||
|
//! | `id` | `iface`, `ssid` | Return ID of given SSID |
|
||||||
|
//! | `ip` | `iface` | Return IP of given network interface |
|
||||||
|
//! | `rssi` | `iface` | Return average signal strength (dBm) for given interface |
|
||||||
|
//! | `rssi_percent` | `iface` | Return average signal strength (%) for given interface |
|
||||||
|
//! | `saved_networks` | | List all networks saved in wpasupplicant config |
|
||||||
|
//! | `ssid` | `iface` | Return SSID of currently-connected network for given interface |
|
||||||
|
//! | `state` | `iface` | Return state of given interface |
|
||||||
|
//! | `status` | `iface` | Return status parameters for given interface |
|
||||||
|
//! | `traffic` | `iface` | Return network traffic for given interface |
|
||||||
|
//!
|
||||||
|
//! Methods for **modifying state**:
|
||||||
|
//!
|
||||||
|
//! | Method | Parameters | Description |
|
||||||
|
//! | --- | --- | --- |
|
||||||
|
//! | `add` | `iface`, `ssid`, `pass` | Add WiFi credentials to `wpa_supplicant-<iface>.conf` |
|
||||||
|
//! | `check_iface` | `wlan_iface`, `ap_iface` | Activate WiFi access point on <ap_iface> if <wlan_iface> is active without a connection |
|
||||||
|
//! | `connect` | `id`, `iface` | Disable other networks and attempt connection with AP represented by given id |
|
||||||
|
//! | `delete` | `id`, `iface` | Remove WiFi credentials for given network id and interface |
|
||||||
|
//! | `disable` | `id`, `iface` | Disable connection with AP represented by given id |
|
||||||
|
//! | `disconnect` | `iface` | Disconnect given interface |
|
||||||
|
//! | `modify` | `id`, `iface`, `pass` | Set a new password for given network id and interface |
|
||||||
|
//! | `reassociate` | `iface` | Reassociate with current AP for given interface |
|
||||||
|
//! | `reconfigure` | | Force wpa_supplicant to re-read its configuration file |
|
||||||
|
//! | `reconnect` | `iface` | Disconnect and reconnect given interface |
|
||||||
|
//! | `save` | | Save configuration changes to `wpa_supplicant-wlan0.conf` |
|
||||||
|
//! | `start_iface_server` | `iface` | Start the `systemd` service for the given interface |
|
||||||
|
//!
|
||||||
|
//! ### System Statistics
|
||||||
|
//!
|
||||||
|
//! | Method | Description | Returns |
|
||||||
|
//! | --- | --- | --- |
|
||||||
//! | `cpu_stats` | CPU statistics | `user`, `system`, `nice`, `idle` |
|
//! | `cpu_stats` | CPU statistics | `user`, `system`, `nice`, `idle` |
|
||||||
//! | `cpu_stats_percent` | CPU statistics as percentages | `user`, `system`, `nice`, `idle` |
|
//! | `cpu_stats_percent` | CPU statistics as percentages | `user`, `system`, `nice`, `idle` |
|
||||||
//! | `disk_usage` | Disk usage statistics (array of disks) | `filesystem`, `one_k_blocks`, `one_k_blocks_used`, `one_k_blocks_free`, `used_percentage`, `mountpoint` |
|
//! | `disk_usage` | Disk usage statistics (array of disks) | `filesystem`, `one_k_blocks`, `one_k_blocks_used`, `one_k_blocks_free`, `used_percentage`, `mountpoint` |
|
||||||
//! | `load_average` | Load average statistics | `one`, `five`, `fifteen` |
|
//! | `load_average` | Load average statistics | `one`, `five`, `fifteen` |
|
||||||
//! | `mem_stats` | Memory statistics | `total`, `free`, `used` |
|
//! | `mem_stats` | Memory statistics | `total`, `free`, `used` |
|
||||||
//! | `ping` | Microservice status | `success` if running |
|
|
||||||
//! | `uptime` | System uptime | `secs` |
|
//! | `uptime` | System uptime | `secs` |
|
||||||
|
|
||||||
use std::process;
|
use std::process;
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
//! Data structures for parsing JSON-RPC method parameters.
|
||||||
|
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
// why do we have multiple structs when we could rather combine them by using
|
||||||
|
// `Option<String>` for some fields? simply because it's easier to handle the
|
||||||
|
// parsed parameters in our json-rpc server methods. we don't have to check
|
||||||
|
// if a given field is `Some` or `None` before passing it into the relevant
|
||||||
|
// function.
|
||||||
|
|
||||||
|
/// 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, network identifier and password.
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct IfaceIdPass {
|
||||||
|
pub iface: String,
|
||||||
|
pub id: String,
|
||||||
|
pub pass: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Network interface name and network SSID.
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct IfaceSsid {
|
||||||
|
pub iface: String,
|
||||||
|
pub ssid: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wireless interface (for which the WiFi credentials will be added), SSID
|
||||||
|
/// and password for a wireless access point.
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct WiFi {
|
||||||
|
pub iface: String,
|
||||||
|
pub ssid: String,
|
||||||
|
pub pass: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wireles network interface and local Access Point network interface (the
|
||||||
|
/// interface on which we deloy or own AP).
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct WlanAndAp {
|
||||||
|
pub wlan_iface: String,
|
||||||
|
pub ap_iface: String,
|
||||||
|
}
|
Loading…
Reference in New Issue