diff --git a/peach-web/src/error.rs b/peach-web/src/error.rs index e140586..a24d253 100644 --- a/peach-web/src/error.rs +++ b/peach-web/src/error.rs @@ -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}; diff --git a/peach-web/src/lib.rs b/peach-web/src/lib.rs index a6e4cf0..a692239 100644 --- a/peach-web/src/lib.rs +++ b/peach-web/src/lib.rs @@ -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}; diff --git a/peach-web/src/routes/authentication.rs b/peach-web/src/routes/authentication.rs index 7b69cf5..3e59d9c 100644 --- a/peach-web/src/routes/authentication.rs +++ b/peach-web/src/routes/authentication.rs @@ -1,20 +1,16 @@ -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_contrib::templates::Template; +use rocket_contrib::{json::Json, templates::Template}; +use 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 +45,7 @@ pub fn login(flash: Option) -> Template { Template::render("login", &context) } -/// # helpers and routes for /logout -///////////////////////////////// +// HELPERS AND ROUTES FOR /logout #[post("/logout")] pub fn logout() -> Flash { @@ -68,8 +63,7 @@ pub fn logout() -> Flash { 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 +110,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 +127,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) -> Template { let mut context = ResetPasswordContext::build(); @@ -150,9 +144,9 @@ pub fn reset_password(flash: Option) -> 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 = "")] pub fn reset_password_post(reset_password_form: Form) -> Template { let result = save_reset_password_form(reset_password_form.into_inner()); @@ -178,9 +172,9 @@ pub fn reset_password_post(reset_password_form: Form) -> 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 = "")] pub fn reset_password_form_endpoint( reset_password_form: Json, @@ -200,10 +194,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 +215,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) -> Template { let mut context = SendPasswordResetContext::build(); @@ -239,8 +230,9 @@ pub fn send_password_reset_page(flash: Option) -> 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 +259,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 +268,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 +285,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) -> Template { let mut context = ChangePasswordContext::build(); @@ -310,7 +301,7 @@ pub fn change_password(flash: Option) -> 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 = "")] pub fn change_password_post(password_form: Form) -> Template { let result = save_password_form(password_form.into_inner()); @@ -337,6 +328,7 @@ pub fn change_password_post(password_form: Form) -> Template { } } +/// JSON change password form request handler. #[post("/api/v1/settings/change_password", data = "")] pub fn save_password_form_endpoint(password_form: Json) -> Json { let result = save_password_form(password_form.into_inner()); @@ -352,4 +344,4 @@ pub fn save_password_form_endpoint(password_form: Json) -> Json, @@ -165,8 +163,7 @@ pub fn device_stats(flash: Option) -> 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 { @@ -189,7 +186,7 @@ pub fn reboot_cmd() -> Flash { } } -// reboot the device +/// JSON request handler for device reboot. #[post("/api/v1/device/reboot")] pub fn reboot_device() -> Json { match reboot() { @@ -208,17 +205,15 @@ pub fn reboot_device() -> Json { } } - -/// # 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 { -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")] @@ -248,9 +243,7 @@ pub fn shutdown_device() -> Json { } } - -/// # helpers and routes for /shutdown -///////////////////////////////// +// HELPERS AND ROUTES FOR /shutdown #[derive(Debug, Serialize)] pub struct ShutdownContext { @@ -283,4 +276,4 @@ pub fn shutdown_menu(flash: Option) -> Template { context.flash_msg = Some(flash.msg().to_string()); }; Template::render("shutdown", &context) -} \ No newline at end of file +} diff --git a/peach-web/src/routes/helpers.rs b/peach-web/src/routes/helpers.rs index 75ca8e7..11fa1b2 100644 --- a/peach-web/src/routes/helpers.rs +++ b/peach-web/src/routes/helpers.rs @@ -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("/", rank = 2)] pub fn files(file: PathBuf) -> Option { 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, @@ -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) } - diff --git a/peach-web/src/routes/index.rs b/peach-web/src/routes/index.rs index ea29588..5d57d2d 100644 --- a/peach-web/src/routes/index.rs +++ b/peach-web/src/routes/index.rs @@ -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) -> Template { }; Template::render("help", &context) } - - diff --git a/peach-web/src/routes/ping.rs b/peach-web/src/routes/ping.rs index 8163b60..2eac821 100644 --- a/peach-web/src/routes/ping.rs +++ b/peach-web/src/routes/ping.rs @@ -1,16 +1,16 @@ //! 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 { // ping pong @@ -19,7 +19,7 @@ pub fn ping_pong() -> Json { 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 { let val = is_dns_updater_online().unwrap(); @@ -28,7 +28,7 @@ pub fn test_route() -> Json { 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 { match network_client::ping() { @@ -47,7 +47,7 @@ pub fn ping_network() -> Json { } } -// 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 { match oled_client::ping() { @@ -66,7 +66,7 @@ pub fn ping_oled() -> Json { } } -// 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 { match stats_client::ping() { @@ -83,4 +83,4 @@ pub fn ping_stats() -> Json { Json(build_json_response(status, None, Some(msg))) } } -} \ No newline at end of file +} diff --git a/peach-web/src/routes/scuttlebutt.rs b/peach-web/src/routes/scuttlebutt.rs index 9dc5e9e..a68095c 100644 --- a/peach-web/src/routes/scuttlebutt.rs +++ b/peach-web/src/routes/scuttlebutt.rs @@ -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) -> 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) -> 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) -> Template { context.flash_msg = Some(flash.msg().to_string()); }; Template::render("profile", &context) -} \ No newline at end of file +} diff --git a/peach-web/src/routes/settings/admin.rs b/peach-web/src/routes/settings/admin.rs index 2a7ff1b..0e0f4b2 100644 --- a/peach-web/src/routes/settings/admin.rs +++ b/peach-web/src/routes/settings/admin.rs @@ -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 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) -> Template { let mut context = ConfigureAdminContext::build(); @@ -54,8 +53,7 @@ pub fn configure_admin(flash: Option) -> 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) -> Flash { } } -/// # helpers and routes for /settings/admin/delete -///////////////////////////////// +// HELPERS AND ROUTES FOR /settings/admin/delete #[derive(Debug, Deserialize, FromForm)] pub struct DeleteAdminForm { diff --git a/peach-web/src/routes/settings/dns.rs b/peach-web/src/routes/settings/dns.rs index 9e63428..4e212c4 100644 --- a/peach-web/src/routes/settings/dns.rs +++ b/peach-web/src/routes/settings/dns.rs @@ -1,16 +1,18 @@ -use rocket_contrib::json::{Json}; -use log::{info}; -use rocket::request::{FlashMessage, Form}; -use rocket::{get, post}; -use rocket::request::FromForm; -use rocket_contrib::templates::Template; -use serde::{Serialize, Deserialize}; +use log::info; +use rocket::{ + get, post, + request::{FlashMessage, Form, FromForm}, +}; +use rocket_contrib::{json::Json, templates::Template}; +use 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 +20,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, @@ -164,5 +165,3 @@ pub fn save_dns_configuration_endpoint(dns_form: Json) -> Json Flash { @@ -122,8 +118,7 @@ pub fn wifi_set_password(wifi: Form) -> Flash { } } -/// # helpers and routes for /network -///////////////////////////////// +// HELPERS AND ROUTES FOR /network #[derive(Debug, Serialize)] pub struct NetworkContext { @@ -295,8 +290,7 @@ pub fn network_home(flash: Option) -> 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 { @@ -311,8 +305,7 @@ pub fn deploy_ap() -> Flash { } } -/// # helpers and routes for /network/wifi -///////////////////////////////// +// HELPERS AND ROUTES FOR /network/wifi #[derive(Debug, Serialize)] pub struct NetworkListContext { @@ -397,9 +390,7 @@ pub fn wifi_list(flash: Option) -> Template { Template::render("network_list", &context) } - -/// # helpers and routes for /network/wifi -///////////////////////////////// +// HELPERS AND ROUTES FOR /network/wifi #[derive(Debug, Serialize)] pub struct NetworkDetailContext { @@ -567,9 +558,7 @@ pub fn network_detail(ssid: &RawStr, flash: Option) -> 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 { @@ -581,8 +570,7 @@ pub fn deploy_client() -> Flash { } } -/// # 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) -> Template { @@ -686,9 +674,7 @@ pub fn add_credentials(wifi: Form) -> Template { } } - -/// # helpers and routes for /network/wifi/usage -///////////////////////////////// +// HELPERS AND ROUTES FOR WIFI USAGE #[derive(Debug, Serialize)] pub struct NetworkAlertContext { @@ -772,9 +758,55 @@ pub fn wifi_usage_alerts(thresholds: Form) -> Flash { } } +#[post("/api/v1/network/wifi/usage", data = "")] +pub fn update_wifi_alerts(thresholds: Json) -> Json { + match monitor::update_store(thresholds.into_inner()) { + Ok(_) => { + debug!("WiFi data usage thresholds updated."); + let status = "success".to_string(); + let msg = "Updated alert threshold and flags.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + Err(_) => { + warn!("Failed to update WiFi data usage thresholds."); + let status = "error".to_string(); + let msg = "Failed to update WiFi data usage thresholds.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + } +} -/// # helpers and routes for /network/activate_ap -////////////////////////////////// +#[post("/api/v1/network/wifi/usage/reset")] +pub fn reset_data_total() -> Json { + match monitor::reset_data() { + Ok(_) => { + debug!("Reset network data usage total."); + let traffic = match network_client::traffic("wlan0") { + Ok(t) => t, + Err(_) => Traffic { + received: 0, + transmitted: 0, + rx_unit: None, + tx_unit: None, + }, + }; + // current wifi traffic values as bytes + let current_traffic = traffic.received + traffic.transmitted; + let data = json!(current_traffic); + let status = "success".to_string(); + let msg = "Reset network data usage total.".to_string(); + Json(build_json_response(status, Some(data), Some(msg))) + } + Err(_) => { + warn!("Failed to reset network data usage total."); + let status = "error".to_string(); + let msg = "Failed to reset network data usage total.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + } +} + +// HELPERS AND ROUTES FOR ACCESS POINT ACTIVATION #[post("/api/v1/network/activate_ap")] pub fn activate_ap() -> Json { @@ -793,6 +825,8 @@ pub fn activate_ap() -> Json { } } +// HELPERS AND ROUTES FOR WIFI CLIENT MANAGEMENT + #[post("/api/v1/network/activate_client")] pub fn activate_client() -> Json { // activate the wireless client @@ -810,114 +844,6 @@ pub fn activate_client() -> Json { } } -#[get("/api/v1/network/ip")] -pub fn return_ip() -> Json { - // 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 { - // 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 { - // 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 { - // 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 { - // 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 { - // 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 = "")] pub fn add_wifi(wifi: Json) -> Json { // generate and write wifi config to wpa_supplicant @@ -1028,51 +954,112 @@ pub fn modify_password(wifi: Json) -> Json { } } -#[post("/api/v1/network/wifi/usage", data = "")] -pub fn update_wifi_alerts(thresholds: Json) -> Json { - match monitor::update_store(thresholds.into_inner()) { - Ok(_) => { - debug!("WiFi data usage thresholds updated."); +// HELPERS AND ROUTES FOR NETWORK STATE QUERIES + +#[get("/api/v1/network/ip")] +pub fn return_ip() -> Json { + // 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 { + // retrieve rssi for connected network + match network_client::rssi("wlan0") { + Ok(rssi) => { let status = "success".to_string(); - let msg = "Updated alert threshold and flags.".to_string(); - Json(build_json_response(status, None, Some(msg))) + let data = json!(rssi); + Json(build_json_response(status, Some(data), None)) } Err(_) => { - warn!("Failed to update WiFi data usage thresholds."); - let status = "error".to_string(); - let msg = "Failed to update WiFi data usage thresholds.".to_string(); + let status = "success".to_string(); + let msg = "Not currently connected to an access point.".to_string(); Json(build_json_response(status, None, Some(msg))) } } } -#[post("/api/v1/network/wifi/usage/reset")] -pub fn reset_data_total() -> Json { - match monitor::reset_data() { - Ok(_) => { - debug!("Reset network data usage total."); - let traffic = match network_client::traffic("wlan0") { - Ok(t) => t, - Err(_) => Traffic { - received: 0, - transmitted: 0, - rx_unit: None, - tx_unit: None, - }, - }; - // current wifi traffic values as bytes - let current_traffic = traffic.received + traffic.transmitted; - let data = json!(current_traffic); +#[get("/api/v1/network/ssid")] +pub fn return_ssid() -> Json { + // retrieve ssid for connected network + match network_client::ssid("wlan0") { + Ok(network) => { let status = "success".to_string(); - let msg = "Reset network data usage total.".to_string(); - Json(build_json_response(status, Some(data), Some(msg))) + let data = json!(network); + Json(build_json_response(status, Some(data), None)) } Err(_) => { - warn!("Failed to reset network data usage total."); - let status = "error".to_string(); - let msg = "Failed to reset network data usage total.".to_string(); + 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 { + // 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 { + // 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 { + // 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))) + } + } +} diff --git a/peach-web/src/tests.rs b/peach-web/src/tests.rs index a088f8a..a6402ae 100644 --- a/peach-web/src/tests.rs +++ b/peach-web/src/tests.rs @@ -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; diff --git a/peach-web/src/utils.rs b/peach-web/src/utils.rs index 12cff38..aee2f14 100644 --- a/peach-web/src/utils.rs +++ b/peach-web/src/utils.rs @@ -1,9 +1,10 @@ pub mod monitor; -use rocket_contrib::json::{JsonValue}; +use rocket_contrib::json::JsonValue; use serde::Serialize; // HELPER FUNCTIONS + #[derive(Serialize)] pub struct JsonResponse { pub status: String, @@ -21,7 +22,6 @@ pub fn build_json_response( JsonResponse { status, data, msg } } - #[derive(Debug, Serialize)] pub struct FlashContext { pub flash_name: Option, diff --git a/peach-web/src/ws.rs b/peach-web/src/ws.rs index 50591a0..fb83b89 100644 --- a/peach-web/src/ws.rs +++ b/peach-web/src/ws.rs @@ -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()