Find and replace build_json_response

This commit is contained in:
notplants 2021-11-03 15:03:21 +01:00
commit 2507747f94
25 changed files with 1038 additions and 3903 deletions

865
Cargo.lock generated

File diff suppressed because it is too large Load Diff

1460
peach-buttons/Cargo.lock generated

File diff suppressed because it is too large Load Diff

1603
peach-oled/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -28,13 +28,13 @@ travis-ci = { repository = "peachcloud/peach-stats", branch = "master" }
maintenance = { status = "actively-developed" }
[dependencies]
env_logger = "0.6"
jsonrpc-core = "11"
jsonrpc-http-server = "11"
jsonrpc-test = "11"
env_logger = "0.9"
jsonrpc-core = "18"
jsonrpc-http-server = "18"
log = "0.4"
probes = "0.3"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
snafu = "0.4"
systemstat = "0.1"
miniserde = "0.1.15"
probes = "0.4.1"
systemstat = "0.1.10"
[dev-dependencies]
jsonrpc-test = "18"

View File

@ -14,7 +14,7 @@ System statistics microservice module for PeachCloud. Provides a JSON-RPC wrappe
| `load_average` | Load average statistics | `one`, `five`, `fifteen` |
| `mem_stats` | Memory statistics | `total`, `free`, `used` |
| `ping` | Microservice status | `success` if running |
| `uptime` | System uptime | `secs`, `nanos` |
| `uptime` | System uptime | `secs` |
### Environment
@ -101,7 +101,7 @@ With microservice running, open a second terminal window and use `curl` to call
Server responds with:
`{"jsonrpc":"2.0","result":"{\"secs\":840968,\"nanos\":0}","id":1}`
`{"jsonrpc":"2.0","result":"{\"secs\":840968}","id":1}`
### Licensing

View File

@ -1,67 +1,69 @@
use std::{error, io};
use std::{error, fmt, io};
use jsonrpc_core::{types::error::Error, ErrorCode};
use probes::ProbeError;
use serde_json::Error as SerdeError;
use snafu::Snafu;
pub type BoxError = Box<dyn error::Error>;
#[derive(Debug, Snafu)]
#[snafu(visibility(pub(crate)))]
#[derive(Debug)]
pub enum StatError {
#[snafu(display("Failed to retrieve CPU statistics: {}", source))]
ReadCpuStat { source: ProbeError },
CpuStat { source: ProbeError },
DiskUsage { source: ProbeError },
LoadAvg { source: ProbeError },
MemStat { source: ProbeError },
Uptime { source: io::Error },
}
#[snafu(display("Failed to retrieve disk usage statistics: {}", source))]
ReadDiskUsage { source: ProbeError },
impl error::Error for StatError {}
#[snafu(display("Failed to retrieve load average statistics: {}", source))]
ReadLoadAvg { source: ProbeError },
#[snafu(display("Failed to retrieve memory statistics: {}", source))]
ReadMemStat { source: ProbeError },
#[snafu(display("Failed to retrieve system uptime: {}", source))]
ReadUptime { source: io::Error },
#[snafu(display("JSON serialization failed: {}", source))]
SerdeSerialize { source: SerdeError },
impl fmt::Display for StatError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
StatError::CpuStat { ref source } => {
write!(f, "Failed to retrieve CPU statistics: {}", source)
}
StatError::DiskUsage { ref source } => {
write!(f, "Failed to retrieve disk usage statistics: {}", source)
}
StatError::LoadAvg { ref source } => {
write!(f, "Failed to retrieve load average statistics: {}", source)
}
StatError::MemStat { ref source } => {
write!(f, "Failed to retrieve memory statistics: {}", source)
}
StatError::Uptime { ref source } => {
write!(f, "Failed to retrieve system uptime: {}", source)
}
}
}
}
impl From<StatError> for Error {
fn from(err: StatError) -> Self {
match &err {
StatError::ReadCpuStat { source } => Error {
StatError::CpuStat { source } => Error {
code: ErrorCode::ServerError(-32001),
message: format!("Failed to retrieve CPU statistics: {}", source),
data: None,
},
StatError::ReadDiskUsage { source } => Error {
StatError::DiskUsage { source } => Error {
code: ErrorCode::ServerError(-32001),
message: format!("Failed to retrieve disk usage statistics: {}", source),
data: None,
},
StatError::ReadLoadAvg { source } => Error {
StatError::LoadAvg { source } => Error {
code: ErrorCode::ServerError(-32001),
message: format!("Failed to retrieve load average statistics: {}", source),
data: None,
},
StatError::ReadMemStat { source } => Error {
StatError::MemStat { source } => Error {
code: ErrorCode::ServerError(-32001),
message: format!("Failed to retrieve memory statistics: {}", source),
data: None,
},
StatError::ReadUptime { source } => Error {
StatError::Uptime { source } => Error {
code: ErrorCode::ServerError(-32001),
message: format!("Failed to retrieve system uptime: {}", source),
data: None,
},
StatError::SerdeSerialize { source } => Error {
code: ErrorCode::ServerError(-32002),
message: format!("JSON serialization failed: {}", source),
data: None,
},
}
}
}

View File

@ -6,56 +6,56 @@ use std::{env, result::Result};
use jsonrpc_core::{IoHandler, Value};
use jsonrpc_http_server::{AccessControlAllowOrigin, DomainsValidation, ServerBuilder};
#[allow(unused_imports)]
use jsonrpc_test as test;
use log::info;
use crate::error::BoxError;
use crate::error::StatError;
pub fn run() -> Result<(), BoxError> {
pub fn run() -> Result<(), StatError> {
info!("Starting up.");
info!("Creating JSON-RPC I/O handler.");
let mut io = IoHandler::default();
io.add_method("cpu_stats", move |_| {
io.add_method("cpu_stats", move |_| async {
info!("Fetching CPU statistics.");
let stats = stats::cpu_stats()?;
Ok(Value::String(stats))
});
io.add_method("cpu_stats_percent", move |_| {
io.add_method("cpu_stats_percent", move |_| async {
info!("Fetching CPU statistics as percentages.");
let stats = stats::cpu_stats_percent()?;
Ok(Value::String(stats))
});
io.add_method("disk_usage", move |_| {
io.add_method("disk_usage", move |_| async {
info!("Fetching disk usage statistics.");
let disks = stats::disk_usage()?;
Ok(Value::String(disks))
});
io.add_method("load_average", move |_| {
io.add_method("load_average", move |_| async {
info!("Fetching system load average statistics.");
let avg = stats::load_average()?;
Ok(Value::String(avg))
});
io.add_method("mem_stats", move |_| {
io.add_method("mem_stats", move |_| async {
info!("Fetching current memory statistics.");
let mem = stats::mem_stats()?;
Ok(Value::String(mem))
});
io.add_method("ping", |_| Ok(Value::String("success".to_string())));
io.add_method("ping", |_| async {
Ok(Value::String("success".to_string()))
});
io.add_method("uptime", move |_| {
io.add_method("uptime", move |_| async {
info!("Fetching system uptime.");
let uptime = stats::uptime()?;
@ -85,16 +85,17 @@ pub fn run() -> Result<(), BoxError> {
#[cfg(test)]
mod tests {
use super::*;
use jsonrpc_test as test_rpc;
// test to ensure correct success response
#[test]
fn rpc_success() {
let rpc = {
let mut io = IoHandler::new();
io.add_method("rpc_success_response", |_| {
io.add_method("rpc_success_response", |_| async {
Ok(Value::String("success".into()))
});
test::Rpc::from(io)
test_rpc::Rpc::from(io)
};
assert_eq!(rpc.request("rpc_success_response", &()), r#""success""#);

View File

@ -1,14 +1,14 @@
use std::result::Result;
use miniserde::json;
use probes::{cpu, disk_usage, load, memory};
use snafu::ResultExt;
use systemstat::{Platform, System};
use crate::error::*;
use crate::error::StatError;
use crate::structs::{CpuStat, CpuStatPercentages, DiskUsage, LoadAverage, MemStat};
pub fn cpu_stats() -> Result<String, StatError> {
let cpu_stats = cpu::proc::read().context(ReadCpuStat)?;
let cpu_stats = cpu::proc::read().map_err(|source| StatError::CpuStat { source })?;
let s = cpu_stats.stat;
let cpu = CpuStat {
user: s.user,
@ -16,13 +16,13 @@ pub fn cpu_stats() -> Result<String, StatError> {
nice: s.nice,
idle: s.idle,
};
let json_cpu = serde_json::to_string(&cpu).context(SerdeSerialize)?;
let json_cpu = json::to_string(&cpu);
Ok(json_cpu)
}
pub fn cpu_stats_percent() -> Result<String, StatError> {
let cpu_stats = cpu::proc::read().context(ReadCpuStat)?;
let cpu_stats = cpu::proc::read().map_err(|source| StatError::CpuStat { source })?;
let s = cpu_stats.stat.in_percentages();
let cpu = CpuStatPercentages {
user: s.user,
@ -30,13 +30,13 @@ pub fn cpu_stats_percent() -> Result<String, StatError> {
nice: s.nice,
idle: s.idle,
};
let json_cpu = serde_json::to_string(&cpu).context(SerdeSerialize)?;
let json_cpu = json::to_string(&cpu);
Ok(json_cpu)
}
pub fn disk_usage() -> Result<String, StatError> {
let disks = disk_usage::read().context(ReadDiskUsage)?;
let disks = disk_usage::read().map_err(|source| StatError::DiskUsage { source })?;
let mut disk_usages = Vec::new();
for d in disks {
let disk = DiskUsage {
@ -49,39 +49,42 @@ pub fn disk_usage() -> Result<String, StatError> {
};
disk_usages.push(disk);
}
let json_disks = serde_json::to_string(&disk_usages).context(SerdeSerialize)?;
let json_disks = json::to_string(&disk_usages);
Ok(json_disks)
}
pub fn load_average() -> Result<String, StatError> {
let l = load::read().context(ReadLoadAvg)?;
let l = load::read().map_err(|source| StatError::LoadAvg { source })?;
let load_avg = LoadAverage {
one: l.one,
five: l.five,
fifteen: l.fifteen,
};
let json_load_avg = serde_json::to_string(&load_avg).context(SerdeSerialize)?;
let json_load_avg = json::to_string(&load_avg);
Ok(json_load_avg)
}
pub fn mem_stats() -> Result<String, StatError> {
let m = memory::read().context(ReadMemStat)?;
let m = memory::read().map_err(|source| StatError::MemStat { source })?;
let mem = MemStat {
total: m.total(),
free: m.free(),
used: m.used(),
};
let json_mem = serde_json::to_string(&mem).context(SerdeSerialize)?;
let json_mem = json::to_string(&mem);
Ok(json_mem)
}
pub fn uptime() -> Result<String, StatError> {
let sys = System::new();
let uptime = sys.uptime().context(ReadUptime)?;
let json_uptime = serde_json::to_string(&uptime).context(SerdeSerialize)?;
let uptime = sys
.uptime()
.map_err(|source| StatError::Uptime { source })?;
let uptime_secs = uptime.as_secs();
let json_uptime = json::to_string(&uptime_secs);
Ok(json_uptime)
}

View File

@ -1,4 +1,4 @@
use serde::Serialize;
use miniserde::Serialize;
#[derive(Debug, Serialize)]
pub struct CpuStat {

View File

@ -40,7 +40,7 @@ log = "0.4"
nest = "1.0.0"
peach-lib = { path = "../peach-lib" }
percent-encoding = "2.1.0"
rocket = "0.5.0-rc.1"
rocket = { version = "0.5.0-rc.1", features = ["json"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
snafu = "0.6"
@ -53,4 +53,4 @@ openssl = { version = "0.10", features = ["vendored"] }
[dependencies.rocket_contrib]
version = "0.4.10"
default-features = false
features = ["json", "tera_templates"]
features = ["tera_templates"]

View File

@ -1,4 +1,4 @@
//!! different types of PeachWebError
//! Custom error type representing all possible error variants for peach-web.
use peach_lib::error::PeachError;
use peach_lib::{serde_json, serde_yaml};

View File

@ -24,15 +24,12 @@
//! of the template to be rendered.
#![feature(proc_macro_hygiene, decl_macro)]
// this is to ignore a clippy warning that suggests
// to replace code with the same code that is already there (possibly a bug)
#![allow(clippy::nonstandard_macro_braces)]
pub mod error;
pub mod routes;
pub mod utils;
#[cfg(test)]
mod tests;
pub mod utils;
mod ws;
use std::{env, thread};

View File

@ -1,20 +1,17 @@
use serde::{Serialize, Deserialize};
use rocket_contrib::json::{Json};
use log::{debug, info};
use rocket::request::{FlashMessage, Form};
use rocket::request::{FlashMessage, Form, FromForm};
use rocket::response::{Flash, Redirect};
use rocket::{get, post};
use rocket::request::FromForm;
use rocket::serde::json::Json;
use rocket_contrib::templates::Template;
use rocket::serde::{Deserialize, Serialize};
use peach_lib::password_utils;
use crate::utils::{build_json_response, JsonResponse};
use crate::error::PeachWebError;
use crate::utils::{build_json_response, JsonResponse};
/// # helpers and routes for /login
/////////////////////////////////
// HELPERS AND ROUTES FOR /login
#[derive(Debug, Serialize)]
pub struct LoginContext {
@ -49,8 +46,7 @@ pub fn login(flash: Option<FlashMessage>) -> Template {
Template::render("login", &context)
}
/// # helpers and routes for /logout
/////////////////////////////////
// HELPERS AND ROUTES FOR /logout
#[post("/logout")]
pub fn logout() -> Flash<Redirect> {
@ -68,8 +64,7 @@ pub fn logout() -> Flash<Redirect> {
Flash::success(Redirect::to("/"), "Logged out")
}
/// # helpers and routes for /reset_password
//////////////////////////////////////////
// HELPERS AND ROUTES FOR /reset_password
#[derive(Debug, Deserialize, FromForm)]
pub struct ResetPasswordForm {
@ -116,7 +111,7 @@ impl ChangePasswordContext {
}
}
/// this function is publicly exposed for users who have forgotten their password
/// Verify, validate and save the submitted password. This function is publicly exposed for users who have forgotten their password.
pub fn save_reset_password_form(password_form: ResetPasswordForm) -> Result<(), PeachWebError> {
info!(
"reset password!: {} {} {}",
@ -133,9 +128,9 @@ pub fn save_reset_password_form(password_form: ResetPasswordForm) -> Result<(),
Ok(())
}
/// this reset password route is used by a user who is not logged in
/// and is specifically for users who have forgotten their password
/// all routes under /public/* are excluded from nginx basic auth via the nginx config
/// Password reset request handler. This route is used by a user who is not logged in
/// and is specifically for users who have forgotten their password.
/// All routes under /public/* are excluded from nginx basic auth via the nginx config.
#[get("/reset_password")]
pub fn reset_password(flash: Option<FlashMessage>) -> Template {
let mut context = ResetPasswordContext::build();
@ -150,9 +145,9 @@ pub fn reset_password(flash: Option<FlashMessage>) -> Template {
Template::render("password/reset_password", &context)
}
/// this reset password route is used by a user who is not logged in
/// and is specifically for users who have forgotten their password
/// and is excluded from nginx basic auth via the nginx config
/// Password reset form request handler. This route is used by a user who is not logged in
/// and is specifically for users who have forgotten their password.
/// This route is excluded from nginx basic auth via the nginx config.
#[post("/reset_password", data = "<reset_password_form>")]
pub fn reset_password_post(reset_password_form: Form<ResetPasswordForm>) -> Template {
let result = save_reset_password_form(reset_password_form.into_inner());
@ -178,13 +173,13 @@ pub fn reset_password_post(reset_password_form: Form<ResetPasswordForm>) -> Temp
}
}
/// this reset password route is used by a user who is not logged in
/// and is specifically for users who have forgotten their password
/// all routes under /public/* are excluded from nginx basic auth via the nginx config
/// JSON password reset form request handler. This route is used by a user who is not logged in
/// and is specifically for users who have forgotten their password.
/// All routes under /public/* are excluded from nginx basic auth via the nginx config.
#[post("/public/api/v1/reset_password", data = "<reset_password_form>")]
pub fn reset_password_form_endpoint(
reset_password_form: Json<ResetPasswordForm>,
) -> Json<JsonResponse> {
) -> Value {
let result = save_reset_password_form(reset_password_form.into_inner());
match result {
Ok(_) => {
@ -200,10 +195,7 @@ pub fn reset_password_form_endpoint(
}
}
/// # helpers and routes for /send_password_reset
////////////////////////////////////////////////
// HELPERS AND ROUTES FOR /send_password_reset
#[derive(Debug, Serialize)]
pub struct SendPasswordResetContext {
@ -224,7 +216,7 @@ impl SendPasswordResetContext {
}
}
/// this route is used by a user who is not logged in to send a new password reset link
/// Password reset request handler. This route is used by a user who is not logged in to send a new password reset link.
#[get("/send_password_reset")]
pub fn send_password_reset_page(flash: Option<FlashMessage>) -> Template {
let mut context = SendPasswordResetContext::build();
@ -239,8 +231,9 @@ pub fn send_password_reset_page(flash: Option<FlashMessage>) -> Template {
Template::render("password/send_password_reset", &context)
}
/// this send_password_reset route is used by a user who is not logged in
/// and is specifically for users who have forgotten their password
/// Send password reset request handler. This route is used by a user who is not logged in
/// and is specifically for users who have forgotten their password. A successful request results
/// in a Scuttlebutt private message being sent to the account of the device admin.
#[post("/send_password_reset")]
pub fn send_password_reset_post() -> Template {
info!("++ send password reset post");
@ -267,8 +260,7 @@ pub fn send_password_reset_post() -> Template {
}
}
/// # helpers and routes for /settings/change_password
//////////////////////////////////////////
// HELPERS AND ROUTES FOR /settings/change_password
#[derive(Debug, Deserialize, FromForm)]
pub struct PasswordForm {
@ -277,7 +269,7 @@ pub struct PasswordForm {
pub new_password2: String,
}
/// this function is for use by a user who is already logged in to change their password
/// Password save form request handler. This function is for use by a user who is already logged in to change their password.
pub fn save_password_form(password_form: PasswordForm) -> Result<(), PeachWebError> {
info!(
"change password!: {} {} {}",
@ -294,7 +286,7 @@ pub fn save_password_form(password_form: PasswordForm) -> Result<(), PeachWebErr
Ok(())
}
/// this change password route is used by a user who is already logged in
/// Change password request handler. This is used by a user who is already logged in.
#[get("/settings/change_password")]
pub fn change_password(flash: Option<FlashMessage>) -> Template {
let mut context = ChangePasswordContext::build();
@ -310,7 +302,7 @@ pub fn change_password(flash: Option<FlashMessage>) -> Template {
Template::render("password/change_password", &context)
}
/// this change password route is used by a user who is already logged in
/// Change password form request handler. This route is used by a user who is already logged in.
#[post("/settings/change_password", data = "<password_form>")]
pub fn change_password_post(password_form: Form<PasswordForm>) -> Template {
let result = save_password_form(password_form.into_inner());
@ -337,8 +329,9 @@ pub fn change_password_post(password_form: Form<PasswordForm>) -> Template {
}
}
/// JSON change password form request handler.
#[post("/api/v1/settings/change_password", data = "<password_form>")]
pub fn save_password_form_endpoint(password_form: Json<PasswordForm>) -> Json<JsonResponse> {
pub fn save_password_form_endpoint(password_form: Json<PasswordForm>) -> Value {
let result = save_password_form(password_form.into_inner());
match result {
Ok(_) => {
@ -352,4 +345,4 @@ pub fn save_password_form_endpoint(password_form: Json<PasswordForm>) -> Json<Js
Json(build_json_response(status, None, Some(msg)))
}
}
}
}

View File

@ -1,27 +1,26 @@
use serde::Serialize;
use rocket_contrib::json::{Json};
use log::{debug, info, warn};
use rocket::request::{FlashMessage};
use rocket::response::{Flash, Redirect};
use rocket::{get, post};
use std::io;
use std::process::{Command, Output};
use rocket::{
get, post,
request::FlashMessage,
response::{Flash, Redirect},
};
use rocket::serde::json::Json;
use rocket_contrib::templates::Template;
use serde::Serialize;
use std::{
io,
process::{Command, Output},
};
use peach_lib::config_manager::load_peach_config;
use peach_lib::dyndns_client;
use peach_lib::network_client;
use peach_lib::oled_client;
use peach_lib::sbot_client;
use peach_lib::stats_client;
use peach_lib::stats_client::{CpuStatPercentages, DiskUsage, LoadAverage, MemStat};
use peach_lib::{dyndns_client, network_client, oled_client, sbot_client, stats_client};
use crate::utils::{build_json_response, JsonResponse};
/// # helpers and routes for /device
/////////////////////////////////
// HELPERS AND ROUTES FOR /device
// used in /device for system statistics
/// System statistics data.
#[derive(Debug, Serialize)]
pub struct DeviceContext {
pub back: Option<String>,
@ -165,8 +164,7 @@ pub fn device_stats(flash: Option<FlashMessage>) -> Template {
Template::render("device", &context)
}
/// # helpers and routes for /device/reboot
/////////////////////////////////
// HELPERS AND ROUTES FOR /device/reboot
/// Executes a system command to reboot the device immediately.
pub fn reboot() -> io::Result<Output> {
@ -189,9 +187,9 @@ pub fn reboot_cmd() -> Flash<Redirect> {
}
}
// reboot the device
/// JSON request handler for device reboot.
#[post("/api/v1/device/reboot")]
pub fn reboot_device() -> Json<JsonResponse> {
pub fn reboot_device() -> Value {
match reboot() {
Ok(_) => {
debug!("Going down for reboot...");
@ -208,17 +206,15 @@ pub fn reboot_device() -> Json<JsonResponse> {
}
}
/// # helpers and routes for /device/shutdown
/////////////////////////////////
// HELPERS AND ROUTES FOR /device/shutdown
/// Executes a system command to shutdown the device immediately.
pub fn shutdown() -> io::Result<Output> {
info ! ("Shutting down the device");
// ideally, we'd like to reboot after 5 seconds to allow time for JSON
// response but this is not possible with the `shutdown` command alone.
// TODO: send "shutting down..." message to `peach-oled` for display
Command::new("sudo").arg("shutdown").arg("now").output()
info!("Shutting down the device");
// ideally, we'd like to reboot after 5 seconds to allow time for JSON
// response but this is not possible with the `shutdown` command alone.
// TODO: send "shutting down..." message to `peach-oled` for display
Command::new("sudo").arg("shutdown").arg("now").output()
}
#[get("/device/shutdown")]
@ -231,7 +227,7 @@ pub fn shutdown_cmd() -> Flash<Redirect> {
// shutdown the device
#[post("/api/v1/device/shutdown")]
pub fn shutdown_device() -> Json<JsonResponse> {
pub fn shutdown_device() -> Value {
match shutdown() {
Ok(_) => {
debug!("Going down for shutdown...");
@ -248,9 +244,7 @@ pub fn shutdown_device() -> Json<JsonResponse> {
}
}
/// # helpers and routes for /shutdown
/////////////////////////////////
// HELPERS AND ROUTES FOR /shutdown
#[derive(Debug, Serialize)]
pub struct ShutdownContext {
@ -283,4 +277,4 @@ pub fn shutdown_menu(flash: Option<FlashMessage>) -> Template {
context.flash_msg = Some(flash.msg().to_string());
};
Template::render("shutdown", &context)
}
}

View File

@ -1,18 +1,16 @@
use std::path::{Path, PathBuf};
use log::{debug};
use rocket::response::{NamedFile};
use rocket::{catch, get};
use log::debug;
use rocket::{catch, get, response::NamedFile};
use rocket_contrib::templates::Template;
use serde::Serialize;
use std::path::{Path, PathBuf};
#[get("/<file..>", rank = 2)]
pub fn files(file: PathBuf) -> Option<NamedFile> {
NamedFile::open(Path::new("static/").join(file)).ok()
}
/// # helpers and routes for /404
/////////////////////////////////
// HELPERS AND ROUTES FOR 404 ERROR
#[derive(Debug, Serialize)]
pub struct ErrorContext {
pub back: Option<String>,
@ -44,8 +42,7 @@ pub fn not_found() -> Template {
Template::render("not_found", context)
}
/// # helpers and routes for 500
/////////////////////////////////
// HELPERS AND ROUTES FOR 500 ERROR
#[catch(500)]
pub fn internal_error() -> Template {
@ -58,4 +55,3 @@ pub fn internal_error() -> Template {
Template::render("internal_error", context)
}

View File

@ -1,11 +1,8 @@
use rocket::request::{FlashMessage};
use rocket::{get};
use rocket::{get, request::FlashMessage};
use rocket_contrib::templates::Template;
use serde::Serialize;
/// # helpers and routes for / (home page)
/////////////////////////////////////
// HELPERS AND ROUTES FOR / (HOME PAGE)
#[derive(Debug, Serialize)]
pub struct HomeContext {
@ -34,8 +31,7 @@ pub fn index() -> Template {
Template::render("index", &context)
}
/// # helpers and routes for /help
/////////////////////////////////
// HELPERS AND ROUTES FOR /help
#[derive(Debug, Serialize)]
pub struct HelpContext {
@ -69,5 +65,3 @@ pub fn help(flash: Option<FlashMessage>) -> Template {
};
Template::render("help", &context)
}

View File

@ -1,36 +1,36 @@
//! Helper routes for pinging services to check that they are active
use rocket_contrib::json::{Json};
use log::{debug, warn};
use rocket::{get};
use rocket::get;
use rocket_contrib::json::Json;
use peach_lib::dyndns_client::{is_dns_updater_online};
use peach_lib::dyndns_client::is_dns_updater_online;
use peach_lib::network_client;
use peach_lib::oled_client;
use peach_lib::stats_client;
use crate::utils::{build_json_response, JsonResponse};
// status route: useful for checking connectivity from web client
/// Status route: useful for checking connectivity from web client.
#[get("/api/v1/ping")]
pub fn ping_pong() -> Json<JsonResponse> {
pub fn ping_pong() -> Value {
// ping pong
let status = "success".to_string();
let msg = "pong!".to_string();
Json(build_json_response(status, None, Some(msg)))
}
// test route: useful for ad hoc testing
/// Test route: useful for ad hoc testing.
#[get("/api/v1/test")]
pub fn test_route() -> Json<JsonResponse> {
pub fn test_route() -> Value {
let val = is_dns_updater_online().unwrap();
let status = "success".to_string();
let msg = val.to_string();
Json(build_json_response(status, None, Some(msg)))
}
// status route: check availability of `peach-network` microservice
/// Status route: check availability of `peach-network` microservice.
#[get("/api/v1/ping/network")]
pub fn ping_network() -> Json<JsonResponse> {
pub fn ping_network() -> Value {
match network_client::ping() {
Ok(_) => {
debug!("peach-network responded successfully");
@ -47,9 +47,9 @@ pub fn ping_network() -> Json<JsonResponse> {
}
}
// status route: check availability of `peach-oled` microservice
/// Status route: check availability of `peach-oled` microservice.
#[get("/api/v1/ping/oled")]
pub fn ping_oled() -> Json<JsonResponse> {
pub fn ping_oled() -> Value {
match oled_client::ping() {
Ok(_) => {
debug!("peach-oled responded successfully");
@ -66,9 +66,9 @@ pub fn ping_oled() -> Json<JsonResponse> {
}
}
// status route: check availability of `peach-stats` microservice
/// Status route: check availability of `peach-stats` microservice.
#[get("/api/v1/ping/stats")]
pub fn ping_stats() -> Json<JsonResponse> {
pub fn ping_stats() -> Value {
match stats_client::ping() {
Ok(_) => {
debug!("peach-stats responded successfully");
@ -83,4 +83,4 @@ pub fn ping_stats() -> Json<JsonResponse> {
Json(build_json_response(status, None, Some(msg)))
}
}
}
}

View File

@ -1,11 +1,10 @@
//! Routes for scuttlebutt related functionality.
use rocket::request::{FlashMessage};
use rocket::{get};
//! Routes for ScuttleButt related functionality.
use rocket::{get, request::FlashMessage};
use rocket_contrib::templates::Template;
use serde::Serialize;
/// # helpers and routes for /messages
/////////////////////////////////
// HELPERS AND ROUTES FOR /messages
#[derive(Debug, Serialize)]
pub struct MessageContext {
@ -40,8 +39,7 @@ pub fn messages(flash: Option<FlashMessage>) -> Template {
Template::render("messages", &context)
}
/// # helpers and routes for /peers
/////////////////////////////////
// HELPERS AND ROUTES FOR /peers
#[derive(Debug, Serialize)]
pub struct PeerContext {
@ -76,9 +74,7 @@ pub fn peers(flash: Option<FlashMessage>) -> Template {
Template::render("peers", &context)
}
/// # helpers and routes for /profile
/////////////////////////////////
// HELPERS AND ROUTES FOR /profile
#[derive(Debug, Serialize)]
pub struct ProfileContext {
@ -111,4 +107,4 @@ pub fn profile(flash: Option<FlashMessage>) -> Template {
context.flash_msg = Some(flash.msg().to_string());
};
Template::render("profile", &context)
}
}

View File

@ -1,19 +1,18 @@
use rocket::request::{FlashMessage, Form};
use rocket::response::{Flash, Redirect};
use rocket::{get, post, uri};
use rocket::request::FromForm;
use rocket::{
get, post,
request::{FlashMessage, Form, FromForm},
response::{Flash, Redirect},
uri,
};
use rocket_contrib::templates::Template;
use serde::{Serialize, Deserialize};
use rocket::serde::{Deserialize, Serialize};
use peach_lib::config_manager;
use peach_lib::config_manager::{load_peach_config};
use peach_lib::config_manager::load_peach_config;
use crate::error::PeachWebError;
/// # helpers and routes for /settings/configure_admin
/////////////////////////////////
// HELPERS AND ROUTES FOR /settings/configure_admin
#[derive(Debug, Serialize)]
pub struct ConfigureAdminContext {
@ -38,7 +37,7 @@ impl ConfigureAdminContext {
}
}
/// this is a route for viewing and deleting currently configured admin
/// View and delete currently configured admin.
#[get("/settings/configure_admin")]
pub fn configure_admin(flash: Option<FlashMessage>) -> Template {
let mut context = ConfigureAdminContext::build();
@ -54,8 +53,7 @@ pub fn configure_admin(flash: Option<FlashMessage>) -> Template {
Template::render("admin/configure_admin", &context)
}
/// # helpers and routes for /settings/admin/add
/////////////////////////////////
// HELPERS AND ROUTES FOR /settings/admin/add
#[derive(Debug, Deserialize, FromForm)]
pub struct AddAdminForm {
@ -112,8 +110,7 @@ pub fn add_admin_post(add_admin_form: Form<AddAdminForm>) -> Flash<Redirect> {
}
}
/// # helpers and routes for /settings/admin/delete
/////////////////////////////////
// HELPERS AND ROUTES FOR /settings/admin/delete
#[derive(Debug, Deserialize, FromForm)]
pub struct DeleteAdminForm {

View File

@ -1,16 +1,19 @@
use rocket_contrib::json::{Json};
use log::{info};
use rocket::request::{FlashMessage, Form};
use rocket::{get, post};
use rocket::request::FromForm;
use log::info;
use rocket::{
get, post,
request::{FlashMessage, Form, FromForm},
};
use rocket::serde::json::Json;
use rocket_contrib::templates::Template;
use serde::{Serialize, Deserialize};
use rocket::serde::{Deserialize, Serialize};
use peach_lib::config_manager;
use peach_lib::config_manager::{load_peach_config};
use peach_lib::config_manager::load_peach_config;
use peach_lib::dyndns_client;
use peach_lib::dyndns_client::{check_is_new_dyndns_domain, get_full_dynamic_domain};
use peach_lib::dyndns_client::{get_dyndns_subdomain, is_dns_updater_online};
use peach_lib::dyndns_client::{
check_is_new_dyndns_domain, get_dyndns_subdomain, get_full_dynamic_domain,
is_dns_updater_online,
};
use peach_lib::error::PeachError;
use peach_lib::jsonrpc_client_core::{Error, ErrorKind};
use peach_lib::jsonrpc_core::types::error::ErrorCode;
@ -18,7 +21,6 @@ use peach_lib::jsonrpc_core::types::error::ErrorCode;
use crate::error::PeachWebError;
use crate::utils::{build_json_response, JsonResponse};
#[derive(Debug, Deserialize, FromForm)]
pub struct DnsForm {
pub external_domain: String,
@ -149,7 +151,7 @@ pub fn configure_dns_post(dns: Form<DnsForm>) -> Template {
}
#[post("/api/v1/dns/configure", data = "<dns_form>")]
pub fn save_dns_configuration_endpoint(dns_form: Json<DnsForm>) -> Json<JsonResponse> {
pub fn save_dns_configuration_endpoint(dns_form: Json<DnsForm>) -> Value {
let result = save_dns_configuration(dns_form.into_inner());
match result {
Ok(_) => {
@ -164,5 +166,3 @@ pub fn save_dns_configuration_endpoint(dns_form: Json<DnsForm>) -> Json<JsonResp
}
}
}

View File

@ -1,28 +1,27 @@
use std::collections::HashMap;
use rocket_contrib::json;
use rocket_contrib::json::{Json};
use log::{debug, warn};
use percent_encoding::percent_decode;
use rocket::http::RawStr;
use rocket::request::{FlashMessage, Form};
use rocket::response::{Flash, Redirect};
use rocket::{get, post, uri};
use rocket::request::FromForm;
use rocket::UriDisplayQuery;
use rocket_contrib::templates::Template;
use serde::{Serialize, Deserialize};
use rocket::{
get,
http::RawStr,
post,
request::{FlashMessage, Form, FromForm},
response::{Flash, Redirect},
uri, UriDisplayQuery,
};
use rocket::serde::json::{json, Json};
use rocket_contrib::{templates::Template};
use rocket::serde::{Deserialize, Serialize};
use std::collections::HashMap;
use peach_lib::network_client;
use peach_lib::network_client::{AccessPoint, Networks, Scan};
use peach_lib::stats_client::{Traffic};
use peach_lib::stats_client::Traffic;
use crate::utils::{build_json_response, JsonResponse};
use crate::utils::monitor;
use crate::utils::monitor::{Threshold, Data, Alert};
use crate::utils::monitor::{Alert, Data, Threshold};
use crate::utils::{build_json_response, JsonResponse};
/// # structs used by network routes
////////////////////////////////////
// STRUCTS USED BY NETWORK ROUTES
#[derive(Debug, Deserialize, FromForm, UriDisplayQuery)]
pub struct Ssid {
@ -35,9 +34,7 @@ pub struct WiFi {
pub pass: String,
}
/// # helpers and routes for /network/wifi/usage/reset
/////////////////////////////////
// HELPERS AND ROUTES FOR /network/wifi/usage/reset
#[get("/network/wifi/usage/reset")]
pub fn wifi_usage_reset() -> Flash<Redirect> {
@ -122,8 +119,7 @@ pub fn wifi_set_password(wifi: Form<WiFi>) -> Flash<Redirect> {
}
}
/// # helpers and routes for /network
/////////////////////////////////
// HELPERS AND ROUTES FOR /network
#[derive(Debug, Serialize)]
pub struct NetworkContext {
@ -295,8 +291,7 @@ pub fn network_home(flash: Option<FlashMessage>) -> Template {
Template::render("network_card", &context)
}
/// # helpers and routes for /network/ap/activate
/////////////////////////////////
// HELPERS AND ROUTES FOR /network/ap/activate
#[get("/network/ap/activate")]
pub fn deploy_ap() -> Flash<Redirect> {
@ -311,8 +306,7 @@ pub fn deploy_ap() -> Flash<Redirect> {
}
}
/// # helpers and routes for /network/wifi
/////////////////////////////////
// HELPERS AND ROUTES FOR /network/wifi
#[derive(Debug, Serialize)]
pub struct NetworkListContext {
@ -397,9 +391,7 @@ pub fn wifi_list(flash: Option<FlashMessage>) -> Template {
Template::render("network_list", &context)
}
/// # helpers and routes for /network/wifi<ssid>
/////////////////////////////////
// HELPERS AND ROUTES FOR /network/wifi<ssid>
#[derive(Debug, Serialize)]
pub struct NetworkDetailContext {
@ -567,9 +559,7 @@ pub fn network_detail(ssid: &RawStr, flash: Option<FlashMessage>) -> Template {
Template::render("network_detail", &context)
}
/// # helpers and routes for /network/wifi/activate
/////////////////////////////////
// HELPERS AND ROUTES FOR /network/wifi/activate
#[get("/network/wifi/activate")]
pub fn deploy_client() -> Flash<Redirect> {
@ -581,8 +571,7 @@ pub fn deploy_client() -> Flash<Redirect> {
}
}
/// # helpers and routes for /network/wifi/add
/////////////////////////////////
// HELPERS AND ROUTES FOR /network/wifi/add
#[get("/network/wifi/add")]
pub fn network_add_wifi(flash: Option<FlashMessage>) -> Template {
@ -686,9 +675,7 @@ pub fn add_credentials(wifi: Form<WiFi>) -> Template {
}
}
/// # helpers and routes for /network/wifi/usage
/////////////////////////////////
// HELPERS AND ROUTES FOR WIFI USAGE
#[derive(Debug, Serialize)]
pub struct NetworkAlertContext {
@ -772,264 +759,8 @@ pub fn wifi_usage_alerts(thresholds: Form<Threshold>) -> Flash<Redirect> {
}
}
/// # helpers and routes for /network/activate_ap
//////////////////////////////////
#[post("/api/v1/network/activate_ap")]
pub fn activate_ap() -> Json<JsonResponse> {
// activate the wireless access point
debug!("Activating WiFi access point.");
match network_client::activate_ap() {
Ok(_) => {
let status = "success".to_string();
Json(build_json_response(status, None, None))
}
Err(_) => {
let status = "error".to_string();
let msg = "Failed to activate WiFi access point.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
}
}
#[post("/api/v1/network/activate_client")]
pub fn activate_client() -> Json<JsonResponse> {
// activate the wireless client
debug!("Activating WiFi client mode.");
match network_client::activate_client() {
Ok(_) => {
let status = "success".to_string();
Json(build_json_response(status, None, None))
}
Err(_) => {
let status = "error".to_string();
let msg = "Failed to activate WiFi client mode.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
}
}
#[get("/api/v1/network/ip")]
pub fn return_ip() -> Json<JsonResponse> {
// retrieve ip for wlan0 or set to x.x.x.x if not found
let wlan_ip = match network_client::ip("wlan0") {
Ok(ip) => ip,
Err(_) => "x.x.x.x".to_string(),
};
// retrieve ip for ap0 or set to x.x.x.x if not found
let ap_ip = match network_client::ip("ap0") {
Ok(ip) => ip,
Err(_) => "x.x.x.x".to_string(),
};
let data = json!({
"wlan0": wlan_ip,
"ap0": ap_ip
});
let status = "success".to_string();
Json(build_json_response(status, Some(data), None))
}
#[get("/api/v1/network/rssi")]
pub fn return_rssi() -> Json<JsonResponse> {
// retrieve rssi for connected network
match network_client::rssi("wlan0") {
Ok(rssi) => {
let status = "success".to_string();
let data = json!(rssi);
Json(build_json_response(status, Some(data), None))
}
Err(_) => {
let status = "success".to_string();
let msg = "Not currently connected to an access point.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
}
}
#[get("/api/v1/network/ssid")]
pub fn return_ssid() -> Json<JsonResponse> {
// retrieve ssid for connected network
match network_client::ssid("wlan0") {
Ok(network) => {
let status = "success".to_string();
let data = json!(network);
Json(build_json_response(status, Some(data), None))
}
Err(_) => {
let status = "success".to_string();
let msg = "Not currently connected to an access point.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
}
}
#[get("/api/v1/network/state")]
pub fn return_state() -> Json<JsonResponse> {
// retrieve state of wlan0 or set to x.x.x.x if not found
let wlan_state = match network_client::state("wlan0") {
Ok(state) => state,
Err(_) => "unavailable".to_string(),
};
// retrieve state for ap0 or set to x.x.x.x if not found
let ap_state = match network_client::state("ap0") {
Ok(state) => state,
Err(_) => "unavailable".to_string(),
};
let data = json!({
"wlan0": wlan_state,
"ap0": ap_state
});
let status = "success".to_string();
Json(build_json_response(status, Some(data), None))
}
#[get("/api/v1/network/status")]
pub fn return_status() -> Json<JsonResponse> {
// retrieve status info for wlan0 interface
match network_client::status("wlan0") {
Ok(network) => {
let status = "success".to_string();
let data = json!(network);
Json(build_json_response(status, Some(data), None))
}
Err(_) => {
let status = "success".to_string();
let msg = "Not currently connected to an access point.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
}
}
#[get("/api/v1/network/wifi")]
pub fn scan_networks() -> Json<JsonResponse> {
// retrieve scan results for access-points within range of wlan0
match network_client::available_networks("wlan0") {
Ok(networks) => {
let status = "success".to_string();
let data = json!(networks);
Json(build_json_response(status, Some(data), None))
}
Err(_) => {
let status = "success".to_string();
let msg = "Unable to scan for networks. Interface may be deactivated.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
}
}
#[post("/api/v1/network/wifi", data = "<wifi>")]
pub fn add_wifi(wifi: Json<WiFi>) -> Json<JsonResponse> {
// generate and write wifi config to wpa_supplicant
match network_client::add(&wifi.ssid, &wifi.pass) {
Ok(_) => {
debug!("Added WiFi credentials.");
// force reread of wpa_supplicant.conf file with new credentials
match network_client::reconfigure() {
Ok(_) => debug!("Successfully reconfigured wpa_supplicant."),
Err(_) => warn!("Failed to reconfigure wpa_supplicant."),
}
// json response for successful update
let status = "success".to_string();
let msg = "WiFi credentials added.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
Err(_) => {
debug!("Failed to add WiFi credentials.");
// json response for failed update
let status = "error".to_string();
let msg = "Failed to add WiFi credentials.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
}
}
#[post("/api/v1/network/wifi/connect", data = "<ssid>")]
pub fn connect_ap(ssid: Json<Ssid>) -> Json<JsonResponse> {
// retrieve the id for the given network ssid
match network_client::id("wlan0", &ssid.ssid) {
// attempt connection with the given network
Ok(id) => match network_client::connect(&id, "wlan0") {
Ok(_) => {
let status = "success".to_string();
let msg = "Connected to chosen network.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
Err(_) => {
let status = "error".to_string();
let msg = "Failed to connect to chosen network.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
},
Err(_) => {
let status = "error".to_string();
let msg = "Failed to retrieve the network ID.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
}
}
#[post("/api/v1/network/wifi/disconnect", data = "<ssid>")]
pub fn disconnect_ap(ssid: Json<Ssid>) -> Json<JsonResponse> {
// attempt to disable the current network for wlan0 interface
match network_client::disable("wlan0", &ssid.ssid) {
Ok(_) => {
let status = "success".to_string();
let msg = "Disconnected from WiFi network.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
Err(_) => {
let status = "error".to_string();
let msg = "Failed to disconnect from WiFi network.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
}
}
#[post("/api/v1/network/wifi/forget", data = "<network>")]
pub fn forget_ap(network: Json<Ssid>) -> Json<JsonResponse> {
let ssid = &network.ssid;
match network_client::forget("wlan0", ssid) {
Ok(_) => {
debug!("Removed WiFi credentials for chosen network.");
let status = "success".to_string();
let msg = "WiFi network credentials removed.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
Err(_) => {
warn!("Failed to remove WiFi credentials.");
let status = "error".to_string();
let msg = "Failed to remove WiFi network credentials.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
}
}
#[post("/api/v1/network/wifi/modify", data = "<wifi>")]
pub fn modify_password(wifi: Json<WiFi>) -> Json<JsonResponse> {
let ssid = &wifi.ssid;
let pass = &wifi.pass;
// we are using a helper function (`update`) to delete the old
// credentials and add the new ones. this is because the wpa_cli method
// for updating the password does not work.
match network_client::update("wlan0", ssid, pass) {
Ok(_) => {
debug!("WiFi password updated for chosen network.");
let status = "success".to_string();
let msg = "WiFi password updated.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
Err(_) => {
warn!("Failed to update WiFi password.");
let status = "error".to_string();
let msg = "Failed to update WiFi password.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
}
}
#[post("/api/v1/network/wifi/usage", data = "<thresholds>")]
pub fn update_wifi_alerts(thresholds: Json<Threshold>) -> Json<JsonResponse> {
pub fn update_wifi_alerts(thresholds: Json<Threshold>) -> Value {
match monitor::update_store(thresholds.into_inner()) {
Ok(_) => {
debug!("WiFi data usage thresholds updated.");
@ -1047,7 +778,7 @@ pub fn update_wifi_alerts(thresholds: Json<Threshold>) -> Json<JsonResponse> {
}
#[post("/api/v1/network/wifi/usage/reset")]
pub fn reset_data_total() -> Json<JsonResponse> {
pub fn reset_data_total() -> Value {
match monitor::reset_data() {
Ok(_) => {
debug!("Reset network data usage total.");
@ -1076,3 +807,260 @@ pub fn reset_data_total() -> Json<JsonResponse> {
}
}
// HELPERS AND ROUTES FOR ACCESS POINT ACTIVATION
#[post("/api/v1/network/activate_ap")]
pub fn activate_ap() -> Value {
// activate the wireless access point
debug!("Activating WiFi access point.");
match network_client::activate_ap() {
Ok(_) => {
let status = "success".to_string();
Json(build_json_response(status, None, None))
}
Err(_) => {
let status = "error".to_string();
let msg = "Failed to activate WiFi access point.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
}
}
// HELPERS AND ROUTES FOR WIFI CLIENT MANAGEMENT
#[post("/api/v1/network/activate_client")]
pub fn activate_client() -> Value {
// activate the wireless client
debug!("Activating WiFi client mode.");
match network_client::activate_client() {
Ok(_) => {
let status = "success".to_string();
Json(build_json_response(status, None, None))
}
Err(_) => {
let status = "error".to_string();
let msg = "Failed to activate WiFi client mode.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
}
}
#[post("/api/v1/network/wifi", data = "<wifi>")]
pub fn add_wifi(wifi: Json<WiFi>) -> Value {
// generate and write wifi config to wpa_supplicant
match network_client::add(&wifi.ssid, &wifi.pass) {
Ok(_) => {
debug!("Added WiFi credentials.");
// force reread of wpa_supplicant.conf file with new credentials
match network_client::reconfigure() {
Ok(_) => debug!("Successfully reconfigured wpa_supplicant."),
Err(_) => warn!("Failed to reconfigure wpa_supplicant."),
}
// json response for successful update
let status = "success".to_string();
let msg = "WiFi credentials added.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
Err(_) => {
debug!("Failed to add WiFi credentials.");
// json response for failed update
let status = "error".to_string();
let msg = "Failed to add WiFi credentials.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
}
}
#[post("/api/v1/network/wifi/connect", data = "<ssid>")]
pub fn connect_ap(ssid: Json<Ssid>) -> Value {
// retrieve the id for the given network ssid
match network_client::id("wlan0", &ssid.ssid) {
// attempt connection with the given network
Ok(id) => match network_client::connect(&id, "wlan0") {
Ok(_) => {
let status = "success".to_string();
let msg = "Connected to chosen network.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
Err(_) => {
let status = "error".to_string();
let msg = "Failed to connect to chosen network.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
},
Err(_) => {
let status = "error".to_string();
let msg = "Failed to retrieve the network ID.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
}
}
#[post("/api/v1/network/wifi/disconnect", data = "<ssid>")]
pub fn disconnect_ap(ssid: Json<Ssid>) -> Value {
// attempt to disable the current network for wlan0 interface
match network_client::disable("wlan0", &ssid.ssid) {
Ok(_) => {
let status = "success".to_string();
let msg = "Disconnected from WiFi network.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
Err(_) => {
let status = "error".to_string();
let msg = "Failed to disconnect from WiFi network.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
}
}
#[post("/api/v1/network/wifi/forget", data = "<network>")]
pub fn forget_ap(network: Json<Ssid>) -> Value {
let ssid = &network.ssid;
match network_client::forget("wlan0", ssid) {
Ok(_) => {
debug!("Removed WiFi credentials for chosen network.");
let status = "success".to_string();
let msg = "WiFi network credentials removed.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
Err(_) => {
warn!("Failed to remove WiFi credentials.");
let status = "error".to_string();
let msg = "Failed to remove WiFi network credentials.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
}
}
#[post("/api/v1/network/wifi/modify", data = "<wifi>")]
pub fn modify_password(wifi: Json<WiFi>) -> Value {
let ssid = &wifi.ssid;
let pass = &wifi.pass;
// we are using a helper function (`update`) to delete the old
// credentials and add the new ones. this is because the wpa_cli method
// for updating the password does not work.
match network_client::update("wlan0", ssid, pass) {
Ok(_) => {
debug!("WiFi password updated for chosen network.");
let status = "success".to_string();
let msg = "WiFi password updated.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
Err(_) => {
warn!("Failed to update WiFi password.");
let status = "error".to_string();
let msg = "Failed to update WiFi password.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
}
}
// HELPERS AND ROUTES FOR NETWORK STATE QUERIES
#[get("/api/v1/network/ip")]
pub fn return_ip() -> Value {
// retrieve ip for wlan0 or set to x.x.x.x if not found
let wlan_ip = match network_client::ip("wlan0") {
Ok(ip) => ip,
Err(_) => "x.x.x.x".to_string(),
};
// retrieve ip for ap0 or set to x.x.x.x if not found
let ap_ip = match network_client::ip("ap0") {
Ok(ip) => ip,
Err(_) => "x.x.x.x".to_string(),
};
let data = json!({
"wlan0": wlan_ip,
"ap0": ap_ip
});
let status = "success".to_string();
Json(build_json_response(status, Some(data), None))
}
#[get("/api/v1/network/rssi")]
pub fn return_rssi() -> Value {
// retrieve rssi for connected network
match network_client::rssi("wlan0") {
Ok(rssi) => {
let status = "success".to_string();
let data = json!(rssi);
Json(build_json_response(status, Some(data), None))
}
Err(_) => {
let status = "success".to_string();
let msg = "Not currently connected to an access point.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
}
}
#[get("/api/v1/network/ssid")]
pub fn return_ssid() -> Value {
// retrieve ssid for connected network
match network_client::ssid("wlan0") {
Ok(network) => {
let status = "success".to_string();
let data = json!(network);
Json(build_json_response(status, Some(data), None))
}
Err(_) => {
let status = "success".to_string();
let msg = "Not currently connected to an access point.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
}
}
#[get("/api/v1/network/state")]
pub fn return_state() -> Value {
// retrieve state of wlan0 or set to x.x.x.x if not found
let wlan_state = match network_client::state("wlan0") {
Ok(state) => state,
Err(_) => "unavailable".to_string(),
};
// retrieve state for ap0 or set to x.x.x.x if not found
let ap_state = match network_client::state("ap0") {
Ok(state) => state,
Err(_) => "unavailable".to_string(),
};
let data = json!({
"wlan0": wlan_state,
"ap0": ap_state
});
let status = "success".to_string();
Json(build_json_response(status, Some(data), None))
}
#[get("/api/v1/network/status")]
pub fn return_status() -> Value {
// retrieve status info for wlan0 interface
match network_client::status("wlan0") {
Ok(network) => {
let status = "success".to_string();
let data = json!(network);
Json(build_json_response(status, Some(data), None))
}
Err(_) => {
let status = "success".to_string();
let msg = "Not currently connected to an access point.".to_string();
Json(build_json_response(status, None, Some(msg)))
}
}
}
#[get("/api/v1/network/wifi")]
pub fn scan_networks() -> JsonResponse {
// retrieve scan results for access-points within range of wlan0
match network_client::available_networks("wlan0") {
Ok(networks) => {
let status = "success".to_string();
let data = json!(networks);
build_json_response(status, Some(data), None)
}
Err(_) => {
let status = "success".to_string();
let msg = "Unable to scan for networks. Interface may be deactivated.".to_string();
build_json_response(status, None, Some(msg))
}
}
}

View File

@ -5,7 +5,7 @@ use rocket::http::{ContentType, Status};
use rocket::local::Client;
use rocket_contrib::json;
use crate::utils::{build_json_response};
use crate::utils::build_json_response;
use super::rocket;

View File

@ -1,27 +1,27 @@
pub mod monitor;
use rocket_contrib::json::{JsonValue};
use serde::Serialize;
use rocket::serde::json::{Json, Value, json};
use rocket::serde::{Serialize, Deserialize};
// HELPER FUNCTIONS
#[derive(Serialize)]
#[derive(Serialize, Deserialize)]
pub struct JsonResponse {
pub status: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<JsonValue>,
pub data: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub msg: Option<String>,
}
pub fn build_json_response(
status: String,
data: Option<JsonValue>,
data: Option<Value>,
msg: Option<String>,
) -> JsonResponse {
JsonResponse { status, data, msg }
) -> Value {
json!({ "status": status, "data": data, "msg": msg })
}
#[derive(Debug, Serialize)]
pub struct FlashContext {
pub flash_name: Option<String>,

View File

@ -4,7 +4,7 @@ use std::convert::TryInto;
use nest::{Error, Store, Value};
use rocket::request::FromForm;
use serde::{Deserialize, Serialize};
use rocket::serde::{Deserialize, Serialize};
use serde_json::json;
/// Network traffic data total

View File

@ -9,12 +9,12 @@ use websocket::sync::Server;
use websocket::{Message, OwnedMessage};
pub fn websocket_server(address: String) -> io::Result<()> {
// Start listening for WebSocket connections
// start listening for WebSocket connections
let ws_server = Server::bind(address)?;
info!("Listening for WebSocket connections.");
for connection in ws_server.filter_map(Result::ok) {
// Spawn a new thread for each connection.
// spawn a new thread for each connection
thread::spawn(move || {
if !connection
.protocols()