documentation tidy-up

This commit is contained in:
glyph 2021-11-03 11:52:02 +02:00
parent a48838ad1d
commit 5df88b81ce
14 changed files with 274 additions and 323 deletions

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::error::PeachError;
use peach_lib::{serde_json, serde_yaml}; use peach_lib::{serde_json, serde_yaml};

View File

@ -24,15 +24,12 @@
//! of the template to be rendered. //! of the template to be rendered.
#![feature(proc_macro_hygiene, decl_macro)] #![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 error;
pub mod routes; pub mod routes;
pub mod utils;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
pub mod utils;
mod ws; mod ws;
use std::{env, thread}; use std::{env, thread};

View File

@ -1,20 +1,16 @@
use serde::{Serialize, Deserialize};
use rocket_contrib::json::{Json};
use log::{debug, info}; use log::{debug, info};
use rocket::request::{FlashMessage, Form}; use rocket::request::{FlashMessage, Form, FromForm};
use rocket::response::{Flash, Redirect}; use rocket::response::{Flash, Redirect};
use rocket::{get, post}; use rocket::{get, post};
use rocket::request::FromForm; use rocket_contrib::{json::Json, templates::Template};
use rocket_contrib::templates::Template; use serde::{Deserialize, Serialize};
use peach_lib::password_utils; use peach_lib::password_utils;
use crate::utils::{build_json_response, JsonResponse};
use crate::error::PeachWebError; use crate::error::PeachWebError;
use crate::utils::{build_json_response, JsonResponse};
// HELPERS AND ROUTES FOR /login
/// # helpers and routes for /login
/////////////////////////////////
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub struct LoginContext { pub struct LoginContext {
@ -49,8 +45,7 @@ pub fn login(flash: Option<FlashMessage>) -> Template {
Template::render("login", &context) Template::render("login", &context)
} }
/// # helpers and routes for /logout // HELPERS AND ROUTES FOR /logout
/////////////////////////////////
#[post("/logout")] #[post("/logout")]
pub fn logout() -> Flash<Redirect> { pub fn logout() -> Flash<Redirect> {
@ -68,8 +63,7 @@ pub fn logout() -> Flash<Redirect> {
Flash::success(Redirect::to("/"), "Logged out") Flash::success(Redirect::to("/"), "Logged out")
} }
/// # helpers and routes for /reset_password // HELPERS AND ROUTES FOR /reset_password
//////////////////////////////////////////
#[derive(Debug, Deserialize, FromForm)] #[derive(Debug, Deserialize, FromForm)]
pub struct ResetPasswordForm { 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> { pub fn save_reset_password_form(password_form: ResetPasswordForm) -> Result<(), PeachWebError> {
info!( info!(
"reset password!: {} {} {}", "reset password!: {} {} {}",
@ -133,9 +127,9 @@ pub fn save_reset_password_form(password_form: ResetPasswordForm) -> Result<(),
Ok(()) Ok(())
} }
/// this reset password route is used by a user who is not logged in /// 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 /// and is specifically for users who have forgotten their password.
/// all routes under /public/* are excluded from nginx basic auth via the nginx config /// All routes under /public/* are excluded from nginx basic auth via the nginx config.
#[get("/reset_password")] #[get("/reset_password")]
pub fn reset_password(flash: Option<FlashMessage>) -> Template { pub fn reset_password(flash: Option<FlashMessage>) -> Template {
let mut context = ResetPasswordContext::build(); let mut context = ResetPasswordContext::build();
@ -150,9 +144,9 @@ pub fn reset_password(flash: Option<FlashMessage>) -> Template {
Template::render("password/reset_password", &context) Template::render("password/reset_password", &context)
} }
/// this reset password route is used by a user who is not logged in /// 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 /// and is specifically for users who have forgotten their password.
/// and is excluded from nginx basic auth via the nginx config /// This route is excluded from nginx basic auth via the nginx config.
#[post("/reset_password", data = "<reset_password_form>")] #[post("/reset_password", data = "<reset_password_form>")]
pub fn reset_password_post(reset_password_form: Form<ResetPasswordForm>) -> Template { pub fn reset_password_post(reset_password_form: Form<ResetPasswordForm>) -> Template {
let result = save_reset_password_form(reset_password_form.into_inner()); let result = save_reset_password_form(reset_password_form.into_inner());
@ -178,9 +172,9 @@ 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 /// 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 /// and is specifically for users who have forgotten their password.
/// all routes under /public/* are excluded from nginx basic auth via the nginx config /// All routes under /public/* are excluded from nginx basic auth via the nginx config.
#[post("/public/api/v1/reset_password", data = "<reset_password_form>")] #[post("/public/api/v1/reset_password", data = "<reset_password_form>")]
pub fn reset_password_form_endpoint( pub fn reset_password_form_endpoint(
reset_password_form: Json<ResetPasswordForm>, reset_password_form: Json<ResetPasswordForm>,
@ -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)] #[derive(Debug, Serialize)]
pub struct SendPasswordResetContext { 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")] #[get("/send_password_reset")]
pub fn send_password_reset_page(flash: Option<FlashMessage>) -> Template { pub fn send_password_reset_page(flash: Option<FlashMessage>) -> Template {
let mut context = SendPasswordResetContext::build(); let mut context = SendPasswordResetContext::build();
@ -239,8 +230,9 @@ pub fn send_password_reset_page(flash: Option<FlashMessage>) -> Template {
Template::render("password/send_password_reset", &context) Template::render("password/send_password_reset", &context)
} }
/// this send_password_reset route is used by a user who is not logged in /// 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 /// 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")] #[post("/send_password_reset")]
pub fn send_password_reset_post() -> Template { pub fn send_password_reset_post() -> Template {
info!("++ send password reset post"); 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)] #[derive(Debug, Deserialize, FromForm)]
pub struct PasswordForm { pub struct PasswordForm {
@ -277,7 +268,7 @@ pub struct PasswordForm {
pub new_password2: String, 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> { pub fn save_password_form(password_form: PasswordForm) -> Result<(), PeachWebError> {
info!( info!(
"change password!: {} {} {}", "change password!: {} {} {}",
@ -294,7 +285,7 @@ pub fn save_password_form(password_form: PasswordForm) -> Result<(), PeachWebErr
Ok(()) 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")] #[get("/settings/change_password")]
pub fn change_password(flash: Option<FlashMessage>) -> Template { pub fn change_password(flash: Option<FlashMessage>) -> Template {
let mut context = ChangePasswordContext::build(); let mut context = ChangePasswordContext::build();
@ -310,7 +301,7 @@ pub fn change_password(flash: Option<FlashMessage>) -> Template {
Template::render("password/change_password", &context) 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>")] #[post("/settings/change_password", data = "<password_form>")]
pub fn change_password_post(password_form: Form<PasswordForm>) -> Template { pub fn change_password_post(password_form: Form<PasswordForm>) -> Template {
let result = save_password_form(password_form.into_inner()); let result = save_password_form(password_form.into_inner());
@ -337,6 +328,7 @@ 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>")] #[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>) -> Json<JsonResponse> {
let result = save_password_form(password_form.into_inner()); let result = save_password_form(password_form.into_inner());
@ -352,4 +344,4 @@ pub fn save_password_form_endpoint(password_form: Json<PasswordForm>) -> Json<Js
Json(build_json_response(status, None, Some(msg))) Json(build_json_response(status, None, Some(msg)))
} }
} }
} }

View File

@ -1,27 +1,25 @@
use serde::Serialize;
use rocket_contrib::json::{Json};
use log::{debug, info, warn}; use log::{debug, info, warn};
use rocket::request::{FlashMessage}; use rocket::{
use rocket::response::{Flash, Redirect}; get, post,
use rocket::{get, post}; request::FlashMessage,
use std::io; response::{Flash, Redirect},
use std::process::{Command, Output}; };
use rocket_contrib::templates::Template; use rocket_contrib::{json::Json, templates::Template};
use serde::Serialize;
use std::{
io,
process::{Command, Output},
};
use peach_lib::config_manager::load_peach_config; 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::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}; 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)] #[derive(Debug, Serialize)]
pub struct DeviceContext { pub struct DeviceContext {
pub back: Option<String>, pub back: Option<String>,
@ -165,8 +163,7 @@ pub fn device_stats(flash: Option<FlashMessage>) -> Template {
Template::render("device", &context) 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. /// Executes a system command to reboot the device immediately.
pub fn reboot() -> io::Result<Output> { pub fn reboot() -> io::Result<Output> {
@ -189,7 +186,7 @@ pub fn reboot_cmd() -> Flash<Redirect> {
} }
} }
// reboot the device /// JSON request handler for device reboot.
#[post("/api/v1/device/reboot")] #[post("/api/v1/device/reboot")]
pub fn reboot_device() -> Json<JsonResponse> { pub fn reboot_device() -> Json<JsonResponse> {
match reboot() { match reboot() {
@ -208,17 +205,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. /// Executes a system command to shutdown the device immediately.
pub fn shutdown() -> io::Result<Output> { pub fn shutdown() -> io::Result<Output> {
info ! ("Shutting down the device"); info!("Shutting down the device");
// ideally, we'd like to reboot after 5 seconds to allow time for JSON // 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. // response but this is not possible with the `shutdown` command alone.
// TODO: send "shutting down..." message to `peach-oled` for display // TODO: send "shutting down..." message to `peach-oled` for display
Command::new("sudo").arg("shutdown").arg("now").output() Command::new("sudo").arg("shutdown").arg("now").output()
} }
#[get("/device/shutdown")] #[get("/device/shutdown")]
@ -248,9 +243,7 @@ pub fn shutdown_device() -> Json<JsonResponse> {
} }
} }
// HELPERS AND ROUTES FOR /shutdown
/// # helpers and routes for /shutdown
/////////////////////////////////
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub struct ShutdownContext { pub struct ShutdownContext {
@ -283,4 +276,4 @@ pub fn shutdown_menu(flash: Option<FlashMessage>) -> Template {
context.flash_msg = Some(flash.msg().to_string()); context.flash_msg = Some(flash.msg().to_string());
}; };
Template::render("shutdown", &context) Template::render("shutdown", &context)
} }

View File

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

View File

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

View File

@ -1,16 +1,16 @@
//! Helper routes for pinging services to check that they are active //! Helper routes for pinging services to check that they are active
use rocket_contrib::json::{Json};
use log::{debug, warn}; 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::network_client;
use peach_lib::oled_client; use peach_lib::oled_client;
use peach_lib::stats_client; use peach_lib::stats_client;
use crate::utils::{build_json_response, JsonResponse}; 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")] #[get("/api/v1/ping")]
pub fn ping_pong() -> Json<JsonResponse> { pub fn ping_pong() -> Json<JsonResponse> {
// ping pong // ping pong
@ -19,7 +19,7 @@ pub fn ping_pong() -> Json<JsonResponse> {
Json(build_json_response(status, None, Some(msg))) 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")] #[get("/api/v1/test")]
pub fn test_route() -> Json<JsonResponse> { pub fn test_route() -> Json<JsonResponse> {
let val = is_dns_updater_online().unwrap(); let val = is_dns_updater_online().unwrap();
@ -28,7 +28,7 @@ pub fn test_route() -> Json<JsonResponse> {
Json(build_json_response(status, None, Some(msg))) 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")] #[get("/api/v1/ping/network")]
pub fn ping_network() -> Json<JsonResponse> { pub fn ping_network() -> Json<JsonResponse> {
match network_client::ping() { match network_client::ping() {
@ -47,7 +47,7 @@ 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")] #[get("/api/v1/ping/oled")]
pub fn ping_oled() -> Json<JsonResponse> { pub fn ping_oled() -> Json<JsonResponse> {
match oled_client::ping() { match oled_client::ping() {
@ -66,7 +66,7 @@ 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")] #[get("/api/v1/ping/stats")]
pub fn ping_stats() -> Json<JsonResponse> { pub fn ping_stats() -> Json<JsonResponse> {
match stats_client::ping() { match stats_client::ping() {
@ -83,4 +83,4 @@ pub fn ping_stats() -> Json<JsonResponse> {
Json(build_json_response(status, None, Some(msg))) Json(build_json_response(status, None, Some(msg)))
} }
} }
} }

View File

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

View File

@ -1,19 +1,18 @@
use rocket::{
use rocket::request::{FlashMessage, Form}; get, post,
use rocket::response::{Flash, Redirect}; request::{FlashMessage, Form, FromForm},
use rocket::{get, post, uri}; response::{Flash, Redirect},
use rocket::request::FromForm; uri,
};
use rocket_contrib::templates::Template; use rocket_contrib::templates::Template;
use serde::{Serialize, Deserialize}; use serde::{Deserialize, Serialize};
use peach_lib::config_manager; 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; use crate::error::PeachWebError;
/// # helpers and routes for /settings/configure_admin // HELPERS AND ROUTES FOR /settings/configure_admin
/////////////////////////////////
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub struct ConfigureAdminContext { 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")] #[get("/settings/configure_admin")]
pub fn configure_admin(flash: Option<FlashMessage>) -> Template { pub fn configure_admin(flash: Option<FlashMessage>) -> Template {
let mut context = ConfigureAdminContext::build(); let mut context = ConfigureAdminContext::build();
@ -54,8 +53,7 @@ pub fn configure_admin(flash: Option<FlashMessage>) -> Template {
Template::render("admin/configure_admin", &context) Template::render("admin/configure_admin", &context)
} }
/// # helpers and routes for /settings/admin/add // HELPERS AND ROUTES FOR /settings/admin/add
/////////////////////////////////
#[derive(Debug, Deserialize, FromForm)] #[derive(Debug, Deserialize, FromForm)]
pub struct AddAdminForm { 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)] #[derive(Debug, Deserialize, FromForm)]
pub struct DeleteAdminForm { pub struct DeleteAdminForm {

View File

@ -1,16 +1,18 @@
use rocket_contrib::json::{Json}; use log::info;
use log::{info}; use rocket::{
use rocket::request::{FlashMessage, Form}; get, post,
use rocket::{get, post}; request::{FlashMessage, Form, FromForm},
use rocket::request::FromForm; };
use rocket_contrib::templates::Template; use rocket_contrib::{json::Json, templates::Template};
use serde::{Serialize, Deserialize}; use serde::{Deserialize, Serialize};
use peach_lib::config_manager; 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;
use peach_lib::dyndns_client::{check_is_new_dyndns_domain, get_full_dynamic_domain}; use peach_lib::dyndns_client::{
use peach_lib::dyndns_client::{get_dyndns_subdomain, is_dns_updater_online}; check_is_new_dyndns_domain, get_dyndns_subdomain, get_full_dynamic_domain,
is_dns_updater_online,
};
use peach_lib::error::PeachError; use peach_lib::error::PeachError;
use peach_lib::jsonrpc_client_core::{Error, ErrorKind}; use peach_lib::jsonrpc_client_core::{Error, ErrorKind};
use peach_lib::jsonrpc_core::types::error::ErrorCode; 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::error::PeachWebError;
use crate::utils::{build_json_response, JsonResponse}; use crate::utils::{build_json_response, JsonResponse};
#[derive(Debug, Deserialize, FromForm)] #[derive(Debug, Deserialize, FromForm)]
pub struct DnsForm { pub struct DnsForm {
pub external_domain: String, pub external_domain: String,
@ -164,5 +165,3 @@ pub fn save_dns_configuration_endpoint(dns_form: Json<DnsForm>) -> Json<JsonResp
} }
} }
} }

View File

@ -1,28 +1,26 @@
use std::collections::HashMap;
use rocket_contrib::json;
use rocket_contrib::json::{Json};
use log::{debug, warn}; use log::{debug, warn};
use percent_encoding::percent_decode; use percent_encoding::percent_decode;
use rocket::http::RawStr; use rocket::{
use rocket::request::{FlashMessage, Form}; get,
use rocket::response::{Flash, Redirect}; http::RawStr,
use rocket::{get, post, uri}; post,
use rocket::request::FromForm; request::{FlashMessage, Form, FromForm},
use rocket::UriDisplayQuery; response::{Flash, Redirect},
use rocket_contrib::templates::Template; uri, UriDisplayQuery,
use serde::{Serialize, Deserialize}; };
use rocket_contrib::{json, json::Json, templates::Template};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use peach_lib::network_client; use peach_lib::network_client;
use peach_lib::network_client::{AccessPoint, Networks, Scan}; 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;
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)] #[derive(Debug, Deserialize, FromForm, UriDisplayQuery)]
pub struct Ssid { pub struct Ssid {
@ -35,9 +33,7 @@ pub struct WiFi {
pub pass: String, pub pass: String,
} }
// HELPERS AND ROUTES FOR /network/wifi/usage/reset
/// # helpers and routes for /network/wifi/usage/reset
/////////////////////////////////
#[get("/network/wifi/usage/reset")] #[get("/network/wifi/usage/reset")]
pub fn wifi_usage_reset() -> Flash<Redirect> { pub fn wifi_usage_reset() -> Flash<Redirect> {
@ -122,8 +118,7 @@ pub fn wifi_set_password(wifi: Form<WiFi>) -> Flash<Redirect> {
} }
} }
/// # helpers and routes for /network // HELPERS AND ROUTES FOR /network
/////////////////////////////////
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub struct NetworkContext { pub struct NetworkContext {
@ -295,8 +290,7 @@ pub fn network_home(flash: Option<FlashMessage>) -> Template {
Template::render("network_card", &context) Template::render("network_card", &context)
} }
/// # helpers and routes for /network/ap/activate // HELPERS AND ROUTES FOR /network/ap/activate
/////////////////////////////////
#[get("/network/ap/activate")] #[get("/network/ap/activate")]
pub fn deploy_ap() -> Flash<Redirect> { pub fn deploy_ap() -> Flash<Redirect> {
@ -311,8 +305,7 @@ pub fn deploy_ap() -> Flash<Redirect> {
} }
} }
/// # helpers and routes for /network/wifi // HELPERS AND ROUTES FOR /network/wifi
/////////////////////////////////
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub struct NetworkListContext { pub struct NetworkListContext {
@ -397,9 +390,7 @@ pub fn wifi_list(flash: Option<FlashMessage>) -> Template {
Template::render("network_list", &context) Template::render("network_list", &context)
} }
// HELPERS AND ROUTES FOR /network/wifi<ssid>
/// # helpers and routes for /network/wifi<ssid>
/////////////////////////////////
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub struct NetworkDetailContext { pub struct NetworkDetailContext {
@ -567,9 +558,7 @@ pub fn network_detail(ssid: &RawStr, flash: Option<FlashMessage>) -> Template {
Template::render("network_detail", &context) Template::render("network_detail", &context)
} }
// HELPERS AND ROUTES FOR /network/wifi/activate
/// # helpers and routes for /network/wifi/activate
/////////////////////////////////
#[get("/network/wifi/activate")] #[get("/network/wifi/activate")]
pub fn deploy_client() -> Flash<Redirect> { pub fn deploy_client() -> Flash<Redirect> {
@ -581,8 +570,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")] #[get("/network/wifi/add")]
pub fn network_add_wifi(flash: Option<FlashMessage>) -> Template { pub fn network_add_wifi(flash: Option<FlashMessage>) -> Template {
@ -686,9 +674,7 @@ pub fn add_credentials(wifi: Form<WiFi>) -> Template {
} }
} }
// HELPERS AND ROUTES FOR WIFI USAGE
/// # helpers and routes for /network/wifi/usage
/////////////////////////////////
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub struct NetworkAlertContext { pub struct NetworkAlertContext {
@ -772,9 +758,55 @@ pub fn wifi_usage_alerts(thresholds: Form<Threshold>) -> Flash<Redirect> {
} }
} }
#[post("/api/v1/network/wifi/usage", data = "<thresholds>")]
pub fn update_wifi_alerts(thresholds: Json<Threshold>) -> Json<JsonResponse> {
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<JsonResponse> {
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")] #[post("/api/v1/network/activate_ap")]
pub fn activate_ap() -> Json<JsonResponse> { pub fn activate_ap() -> Json<JsonResponse> {
@ -793,6 +825,8 @@ pub fn activate_ap() -> Json<JsonResponse> {
} }
} }
// HELPERS AND ROUTES FOR WIFI CLIENT MANAGEMENT
#[post("/api/v1/network/activate_client")] #[post("/api/v1/network/activate_client")]
pub fn activate_client() -> Json<JsonResponse> { pub fn activate_client() -> Json<JsonResponse> {
// activate the wireless client // activate the wireless client
@ -810,114 +844,6 @@ pub fn activate_client() -> Json<JsonResponse> {
} }
} }
#[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>")] #[post("/api/v1/network/wifi", data = "<wifi>")]
pub fn add_wifi(wifi: Json<WiFi>) -> Json<JsonResponse> { pub fn add_wifi(wifi: Json<WiFi>) -> Json<JsonResponse> {
// generate and write wifi config to wpa_supplicant // generate and write wifi config to wpa_supplicant
@ -1028,51 +954,112 @@ pub fn modify_password(wifi: Json<WiFi>) -> Json<JsonResponse> {
} }
} }
#[post("/api/v1/network/wifi/usage", data = "<thresholds>")] // HELPERS AND ROUTES FOR NETWORK STATE QUERIES
pub fn update_wifi_alerts(thresholds: Json<Threshold>) -> Json<JsonResponse> {
match monitor::update_store(thresholds.into_inner()) { #[get("/api/v1/network/ip")]
Ok(_) => { pub fn return_ip() -> Json<JsonResponse> {
debug!("WiFi data usage thresholds updated."); // 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 status = "success".to_string();
let msg = "Updated alert threshold and flags.".to_string(); let data = json!(rssi);
Json(build_json_response(status, None, Some(msg))) Json(build_json_response(status, Some(data), None))
} }
Err(_) => { Err(_) => {
warn!("Failed to update WiFi data usage thresholds."); let status = "success".to_string();
let status = "error".to_string(); let msg = "Not currently connected to an access point.".to_string();
let msg = "Failed to update WiFi data usage thresholds.".to_string();
Json(build_json_response(status, None, Some(msg))) Json(build_json_response(status, None, Some(msg)))
} }
} }
} }
#[post("/api/v1/network/wifi/usage/reset")] #[get("/api/v1/network/ssid")]
pub fn reset_data_total() -> Json<JsonResponse> { pub fn return_ssid() -> Json<JsonResponse> {
match monitor::reset_data() { // retrieve ssid for connected network
Ok(_) => { match network_client::ssid("wlan0") {
debug!("Reset network data usage total."); Ok(network) => {
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 status = "success".to_string();
let msg = "Reset network data usage total.".to_string(); let data = json!(network);
Json(build_json_response(status, Some(data), Some(msg))) Json(build_json_response(status, Some(data), None))
} }
Err(_) => { Err(_) => {
warn!("Failed to reset network data usage total."); let status = "success".to_string();
let status = "error".to_string(); let msg = "Not currently connected to an access point.".to_string();
let msg = "Failed to reset network data usage total.".to_string();
Json(build_json_response(status, None, Some(msg))) 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)))
}
}
}

View File

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

View File

@ -1,9 +1,10 @@
pub mod monitor; pub mod monitor;
use rocket_contrib::json::{JsonValue}; use rocket_contrib::json::JsonValue;
use serde::Serialize; use serde::Serialize;
// HELPER FUNCTIONS // HELPER FUNCTIONS
#[derive(Serialize)] #[derive(Serialize)]
pub struct JsonResponse { pub struct JsonResponse {
pub status: String, pub status: String,
@ -21,7 +22,6 @@ pub fn build_json_response(
JsonResponse { status, data, msg } JsonResponse { status, data, msg }
} }
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub struct FlashContext { pub struct FlashContext {
pub flash_name: Option<String>, pub flash_name: Option<String>,

View File

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