Compare commits
4 Commits
7d5d6bcc1f
...
6028e07bde
Author | SHA1 | Date |
---|---|---|
glyph | 6028e07bde | |
glyph | ebc7b9d417 | |
glyph | b8ff944377 | |
glyph | 8cbb295c3a |
|
@ -49,10 +49,6 @@ pub fn mount_peachpub_routes(
|
|||
Response::html(routes::guide::build_template())
|
||||
},
|
||||
|
||||
(GET) (/power) => {
|
||||
Response::html(routes::power::menu::build_template())
|
||||
},
|
||||
|
||||
(POST) (/scuttlebutt/block) => {
|
||||
routes::scuttlebutt::block::handle_form(request)
|
||||
},
|
||||
|
@ -170,6 +166,18 @@ pub fn mount_peachpub_routes(
|
|||
routes::settings::admin::delete::handle_form(request)
|
||||
},
|
||||
|
||||
(GET) (/settings/power) => {
|
||||
Response::html(routes::settings::power::menu::build_template(request))
|
||||
},
|
||||
|
||||
(GET) (/settings/power/reboot) => {
|
||||
routes::settings::power::reboot::handle_reboot()
|
||||
},
|
||||
|
||||
(GET) (/settings/power/shutdown) => {
|
||||
routes::settings::power::shutdown::handle_shutdown()
|
||||
},
|
||||
|
||||
(GET) (/settings/scuttlebutt) => {
|
||||
Response::html(routes::settings::scuttlebutt::menu::build_template(request))
|
||||
.reset_flash()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use maud::{html, PreEscaped};
|
||||
use peach_lib::sbot::SbotStatus;
|
||||
|
||||
use crate::{templates, utils::theme};
|
||||
use crate::{templates, utils::theme, SERVER_CONFIG};
|
||||
|
||||
/// Read the state of the go-sbot process and define status-related
|
||||
/// elements accordingly.
|
||||
|
@ -24,9 +24,23 @@ fn render_status_elements<'a>() -> (&'a str, &'a str, &'a str) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Render the URL for the status element (icon / link).
|
||||
///
|
||||
/// If the application is running in standalone mode then the element links
|
||||
/// directly to the Scuttlebutt status page. If not, it links to the device
|
||||
/// status page.
|
||||
fn render_status_url<'a>() -> &'a str {
|
||||
if SERVER_CONFIG.standalone_mode {
|
||||
"/status/scuttlebutt"
|
||||
} else {
|
||||
"/status"
|
||||
}
|
||||
}
|
||||
|
||||
/// Home template builder.
|
||||
pub fn build_template() -> PreEscaped<String> {
|
||||
let (circle_color, center_circle_text, circle_border) = render_status_elements();
|
||||
let status_url = render_status_url();
|
||||
|
||||
// render the home template html
|
||||
let home_template = html! {
|
||||
|
@ -63,7 +77,7 @@ pub fn build_template() -> PreEscaped<String> {
|
|||
}
|
||||
(PreEscaped("<!-- bottom-left -->"))
|
||||
(PreEscaped("<!-- SYSTEM STATUS LINK AND ICON -->"))
|
||||
a class="bottom-left" href="/status/scuttlebutt" title="Status" {
|
||||
a class="bottom-left" href=(status_url) title="Status" {
|
||||
div class={ "circle circle-small border-circle-small " (circle_border) } {
|
||||
img class="icon-medium" src="/icons/heart-pulse.svg";
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ pub mod authentication;
|
|||
//pub mod index;
|
||||
pub mod guide;
|
||||
pub mod home;
|
||||
pub mod power;
|
||||
pub mod scuttlebutt;
|
||||
pub mod settings;
|
||||
pub mod status;
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
pub mod menu;
|
|
@ -11,8 +11,10 @@ pub fn build_template() -> PreEscaped<String> {
|
|||
div class="card center" {
|
||||
(PreEscaped("<!-- BUTTONS -->"))
|
||||
div id="settingsButtons" {
|
||||
// render the network settings button if we're not in standalone mode
|
||||
// render the network settings and power menu buttons if we're
|
||||
// not in standalone mode
|
||||
@if !SERVER_CONFIG.standalone_mode {
|
||||
a id="power" class="button button-primary center" href="/settings/power" title="Power Menu" { "Power" }
|
||||
a id="network" class="button button-primary center" href="/settings/network" title="Network Settings" { "Network" }
|
||||
}
|
||||
a id="scuttlebutt" class="button button-primary center" href="/settings/scuttlebutt" title="Scuttlebutt Settings" { "Scuttlebutt" }
|
||||
|
|
|
@ -2,5 +2,6 @@ pub mod admin;
|
|||
//pub mod dns;
|
||||
pub mod menu;
|
||||
pub mod network;
|
||||
pub mod power;
|
||||
pub mod scuttlebutt;
|
||||
pub mod theme;
|
||||
|
|
|
@ -1,8 +1,17 @@
|
|||
use maud::{html, PreEscaped};
|
||||
use rouille::Request;
|
||||
|
||||
use crate::{templates, utils::theme};
|
||||
use crate::{
|
||||
templates,
|
||||
utils::{flash::FlashRequest, theme},
|
||||
};
|
||||
|
||||
/// Power menu template builder.
|
||||
///
|
||||
/// Presents options for rebooting or shutting down the device.
|
||||
pub fn build_template(request: &Request) -> PreEscaped<String> {
|
||||
let (flash_name, flash_msg) = request.retrieve_flash();
|
||||
|
||||
pub fn build_template() -> PreEscaped<String> {
|
||||
let power_menu_template = html! {
|
||||
(PreEscaped("<!-- POWER MENU -->"))
|
||||
div class="card center" {
|
||||
|
@ -10,7 +19,11 @@ pub fn build_template() -> PreEscaped<String> {
|
|||
div id="buttons" {
|
||||
a id="rebootBtn" class="button button-primary center" href="/reboot" title="Reboot Device" { "Reboot" }
|
||||
a id="shutdownBtn" class="button button-warning center" href="/shutdown" title="Shutdown Device" { "Shutdown" }
|
||||
a id="cancelBtn" class="button button-secondary center" href="/" title="Cancel" { "Cancel" }
|
||||
a id="cancelBtn" class="button button-secondary center" href="/settings" title="Cancel" { "Cancel" }
|
||||
}
|
||||
@if let (Some(name), Some(msg)) = (flash_name, flash_msg) {
|
||||
(PreEscaped("<!-- FLASH MESSAGE -->"))
|
||||
(templates::flash::build_template(name, msg))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
pub mod menu;
|
||||
pub mod reboot;
|
||||
pub mod shutdown;
|
|
@ -0,0 +1,36 @@
|
|||
use log::info;
|
||||
use rouille::Response;
|
||||
|
||||
use std::{
|
||||
io::Result,
|
||||
process::{Command, Output},
|
||||
};
|
||||
|
||||
use crate::utils::flash::FlashResponse;
|
||||
|
||||
/// Executes a system command to reboot the device immediately.
|
||||
fn reboot() -> Result<Output> {
|
||||
info!("Rebooting 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 "rebooting..." message to `peach-oled` for display
|
||||
Command::new("sudo")
|
||||
.arg("shutdown")
|
||||
.arg("-r")
|
||||
.arg("now")
|
||||
.output()
|
||||
}
|
||||
|
||||
pub fn handle_reboot() -> Response {
|
||||
let (name, msg) = match reboot() {
|
||||
Ok(_) => ("success".to_string(), "Rebooting the device".to_string()),
|
||||
Err(err) => (
|
||||
"error".to_string(),
|
||||
format!("Failed to reboot the device: {}", err),
|
||||
),
|
||||
};
|
||||
|
||||
let (flash_name, flash_msg) = (format!("flash_name={}", name), format!("flash_msg={}", msg));
|
||||
|
||||
Response::redirect_303("/power").add_flash(flash_name, flash_msg)
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
use log::info;
|
||||
use rouille::Response;
|
||||
|
||||
use std::{
|
||||
io::Result,
|
||||
process::{Command, Output},
|
||||
};
|
||||
|
||||
use crate::utils::flash::FlashResponse;
|
||||
|
||||
/// Executes a system command to shutdown the device immediately.
|
||||
fn shutdown() -> Result<Output> {
|
||||
info!("Shutting down the device");
|
||||
// ideally, we'd like to shutdown 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()
|
||||
}
|
||||
|
||||
pub fn handle_shutdown() -> Response {
|
||||
let (name, msg) = match shutdown() {
|
||||
Ok(_) => (
|
||||
"success".to_string(),
|
||||
"Shutting down the device".to_string(),
|
||||
),
|
||||
Err(err) => (
|
||||
"error".to_string(),
|
||||
format!("Failed to shutdown the device: {}", err),
|
||||
),
|
||||
};
|
||||
|
||||
let (flash_name, flash_msg) = (format!("flash_name={}", name), format!("flash_msg={}", msg));
|
||||
|
||||
Response::redirect_303("/power").add_flash(flash_name, flash_msg)
|
||||
}
|
|
@ -27,8 +27,7 @@ fn retrieve_networking_state() -> Option<String> {
|
|||
service_info
|
||||
.lines()
|
||||
.find(|line| line.starts_with("ActiveState="))
|
||||
.map(|line| line.strip_prefix("ActiveState="))
|
||||
.flatten()
|
||||
.and_then(|line| line.strip_prefix("ActiveState="))
|
||||
.map(|state| state.to_string())
|
||||
}
|
||||
|
||||
|
@ -36,7 +35,7 @@ fn retrieve_networking_state() -> Option<String> {
|
|||
fn retrieve_sbot_state() -> Option<String> {
|
||||
// retrieve the name of the go-sbot service or set default
|
||||
let go_sbot_service = config_manager::get_config_value("GO_SBOT_SERVICE")
|
||||
.unwrap_or("go-sbot.service".to_string());
|
||||
.unwrap_or_else(|_| "go-sbot.service".to_string());
|
||||
|
||||
let sbot_service_output = Command::new("systemctl")
|
||||
.arg("show")
|
||||
|
@ -51,8 +50,7 @@ fn retrieve_sbot_state() -> Option<String> {
|
|||
service_info
|
||||
.lines()
|
||||
.find(|line| line.starts_with("ActiveState="))
|
||||
.map(|line| line.strip_prefix("ActiveState="))
|
||||
.flatten()
|
||||
.and_then(|line| line.strip_prefix("ActiveState="))
|
||||
.map(|state| state.to_string())
|
||||
}
|
||||
|
||||
|
@ -67,7 +65,7 @@ fn retrieve_device_status_data() -> (Option<u64>, String) {
|
|||
(uptime, oled_ping)
|
||||
}
|
||||
|
||||
fn retrieve_device_usage_data<'a>() -> (Option<CpuStatPercentages>, Option<MemStat>) {
|
||||
fn retrieve_device_usage_data() -> (Option<CpuStatPercentages>, Option<MemStat>) {
|
||||
// convert result to Option<CpuStatPercentages>, discard any error
|
||||
let cpu_stat_percent = stats::cpu_stats_percent().ok();
|
||||
let mem_stats = stats::mem_stats().ok();
|
||||
|
@ -381,387 +379,3 @@ pub fn build_template() -> PreEscaped<String> {
|
|||
|
||||
templates::base::build_template(body, theme)
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
{%- extends "nav" -%}
|
||||
{%- block card -%}
|
||||
{# ASSIGN VARIABLES #}
|
||||
{# ---------------- #}
|
||||
{%- if mem_stats -%}
|
||||
{% set mem_usage_percent = mem_stats.used / mem_stats.total * 100 | round -%}
|
||||
{% set mem_used = mem_stats.used / 1024 | round -%}
|
||||
{% set mem_free = mem_stats.free / 1024 | round -%}
|
||||
{% set mem_total = mem_stats.total / 1024 | round -%}
|
||||
{% endif -%}
|
||||
{% if cpu_stat_percent -%}
|
||||
{% set cpu_usage_percent = cpu_stat_percent.nice + cpu_stat_percent.system + cpu_stat_percent.user | round -%}
|
||||
{%- endif -%}
|
||||
{%- if disk_stats -%}
|
||||
{%- for disk in disk_stats -%}
|
||||
{%- set_global disk_usage_percent = disk.used_percentage -%}
|
||||
{# Calculate free disk space in megabytes #}
|
||||
{%- set_global disk_free = disk.one_k_blocks_free / 1024 | round -%}
|
||||
{%- endfor -%}
|
||||
{%- endif -%}
|
||||
<!-- DEVICE STATUS VIEW -->
|
||||
<div class="card center">
|
||||
<div class="card-container">
|
||||
{# Display microservice status for network, oled & stats #}
|
||||
<div class="three-grid" style="padding-top: 1rem;">
|
||||
<!-- PEACH-NETWORK STATUS STACK -->
|
||||
<div class="stack capsule{% if network_ping == "ONLINE" %} border-success{% else %} border-warning{% endif %}">
|
||||
<img id="networkIcon" class="icon{% if network_ping == "OFFLINE" %} icon-inactive{% endif %} icon-medium" alt="Network" title="Network microservice status" src="icons/wifi.svg">
|
||||
<div class="stack" style="padding-top: 0.5rem;">
|
||||
<label class="label-small font-near-black">Networking</label>
|
||||
<label class="label-small font-near-black">{{ network_ping }}</label>
|
||||
</div>
|
||||
</div>
|
||||
<!-- PEACH-OLED STATUS STACK -->
|
||||
<div class="stack capsule{% if oled_ping == "ONLINE" %} border-success{% else %} border-warning{% endif %}">
|
||||
<img id="oledIcon" class="icon{% if oled_ping == "OFFLINE" %} icon-inactive{% endif %} icon-medium" alt="Display" title="OLED display microservice status" src="icons/lcd.svg">
|
||||
<div class="stack" style="padding-top: 0.5rem;">
|
||||
<label class="label-small font-near-black">Display</label>
|
||||
<label class="label-small font-near-black">{{ oled_ping }}</label>
|
||||
</div>
|
||||
</div>
|
||||
<!-- PEACH-STATS STATUS STACK -->
|
||||
<div class="stack capsule{% if stats_ping == "ONLINE" %} border-success{% else %} border-warning{% endif %}">
|
||||
<img id="statsIcon" class="icon{% if stats_ping == "OFFLINE" %} icon-inactive{% endif %} icon-medium" alt="Stats" title="System statistics microservice status" src="icons/chart.svg">
|
||||
<div class="stack" style="padding-top: 0.5rem;">
|
||||
<label class="label-small font-near-black">Statistics</label>
|
||||
<label class="label-small font-near-black">{{ stats_ping }}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="three-grid" style="padding-bottom: 1rem; margin-top: 0px;">
|
||||
<!-- DYNDNS STATUS STACK -->
|
||||
<div class="stack capsule{% if dyndns_is_online %} border-success{% else %} border-warning{% endif %}">
|
||||
<img id="networkIcon" class="icon{% if dyndns_is_online != true %} icon-inactive {% endif %} icon-medium" alt="Dyndns" title="Dyndns status" src="icons/wifi.svg">
|
||||
<div class="stack" style="padding-top: 0.5rem;">
|
||||
<label class="label-small font-near-black">Dyn DNS</label>
|
||||
<label class="label-small font-near-black">{% if dyndns_is_online %} ONLINE {% else %} OFFLINE {% endif %} </label>
|
||||
</div>
|
||||
</div>
|
||||
<!-- CONFIG STATUS STACK -->
|
||||
<div class="stack capsule{% if config_is_valid %} border-success{% else %} border-warning{% endif %}">
|
||||
<img id="networkIcon" class="icon{% if config_is_valid != true %} icon-inactive {% endif %} icon-medium" alt="Config" title="Config status" src="icons/wifi.svg">
|
||||
<div class="stack" style="padding-top: 0.5rem;">
|
||||
<label class="label-small font-near-black">Config</label>
|
||||
<label class="label-small font-near-black">{% if config_is_valid %} LOADED {% else %} INVALID {% endif %} </label>
|
||||
</div>
|
||||
</div>
|
||||
<!-- SBOT STATUS STACK -->
|
||||
<div class="stack capsule{% if sbot_is_online %} border-success{% else %} border-warning{% endif %}">
|
||||
<img id="networkIcon" class="icon{% if sbot_is_online != true %} icon-inactive {% endif %} icon-medium" alt="Sbot" title="Sbot status" src="icons/wifi.svg">
|
||||
<div class="stack" style="padding-top: 0.5rem;">
|
||||
<label class="label-small font-near-black">Sbot</label>
|
||||
<label class="label-small font-near-black">{% if sbot_is_online %} ONLINE {% else %} OFFLINE {% endif %} </label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{# Display CPU usage meter #}
|
||||
{%- if cpu_stat_percent -%}
|
||||
<div class="flex-grid">
|
||||
<span class="card-text">CPU</span>
|
||||
<span class="label-small push-right">{{ cpu_usage_percent }}%</span>
|
||||
</div>
|
||||
<meter value="{{ cpu_usage_percent }}" min="0" max="100" title="CPU usage">
|
||||
<div class="meter-gauge">
|
||||
<span style="width: {{ cpu_usage_percent }}%;">CPU Usage</span>
|
||||
</div>
|
||||
</meter>
|
||||
{%- else -%}
|
||||
<p class="card-text">CPU usage data unavailable</p>
|
||||
{% endif -%}
|
||||
{# Display memory usage meter #}
|
||||
{%- if mem_stats %}
|
||||
<div class="flex-grid">
|
||||
<span class="card-text">Memory</span>
|
||||
<span class="label-small push-right">{{ mem_usage_percent }}% ({{ mem_free }} MB free)</span>
|
||||
</div>
|
||||
<meter value="{{ mem_used }}" min="0" max="{{ mem_total }}" title="Memory usage">
|
||||
<div class="meter-gauge">
|
||||
<span style="width: {{ mem_usage_percent }}%;">Memory Usage</span>
|
||||
</div>
|
||||
</meter>
|
||||
{%- else -%}
|
||||
<p class="card-text">Memory usage data unavailable</p>
|
||||
{% endif -%}
|
||||
{# Display disk usage meter #}
|
||||
{%- if disk_stats %}
|
||||
<div class="flex-grid">
|
||||
<span class="card-text">Disk</span>
|
||||
<span class="label-small push-right">{{ disk_usage_percent }}% ({% if disk_free > 1024 %}{{ disk_free / 1024 | round }} GB{% else %}{{ disk_free }} MB{% endif %} free)</span>
|
||||
</div>
|
||||
<meter value="{{ disk_usage_percent }}" min="0" max="100" title="Disk usage">
|
||||
<div class="meter-gauge">
|
||||
<span style="width: {{ disk_usage_percent }}%;">Disk Usage</span>
|
||||
</div>
|
||||
</meter>
|
||||
{%- else -%}
|
||||
<p class="card-text">Disk usage data unavailable</p>
|
||||
{%- endif %}
|
||||
{# Display system uptime in minutes #}
|
||||
{%- if uptime and uptime < 60 %}
|
||||
<p class="capsule center-text">Uptime: {{ uptime }} minutes</p>
|
||||
{# Display system uptime in hours & minutes #}
|
||||
{%- elif uptime and uptime > 60 -%}
|
||||
<p class="capsule center-text">Uptime: {{ uptime / 60 | round(method="floor") }} hours, {{ uptime % 60 }} minutes</p>
|
||||
{%- else -%}
|
||||
<p class="card-text">Uptime data unavailable</p>
|
||||
{%- endif %}
|
||||
<!-- FLASH MESSAGE -->
|
||||
<!-- check for flash message and display accordingly -->
|
||||
{%- if flash_msg and flash_name == "success" -%}
|
||||
<!-- display success message -->
|
||||
<div class="capsule center-text flash-message font-success">{{ flash_msg }}.</div>
|
||||
{%- elif flash_msg and flash_name == "error" -%}
|
||||
<!-- display error message -->
|
||||
<div class="capsule center-text flash-message font-failure">{{ flash_msg }}.</div>
|
||||
{%- endif %}
|
||||
</div>
|
||||
</div>
|
||||
{%- endblock card %}
|
||||
|
||||
// CONTEXT
|
||||
|
||||
use log::info;
|
||||
use rocket::{
|
||||
get,
|
||||
request::FlashMessage,
|
||||
response::{Flash, Redirect},
|
||||
};
|
||||
use rocket_dyn_templates::Template;
|
||||
use serde::Serialize;
|
||||
use std::{
|
||||
io,
|
||||
process::{Command, Output},
|
||||
};
|
||||
|
||||
use peach_lib::{
|
||||
config_manager::load_peach_config, dyndns_client, network_client, oled_client, sbot::SbotStatus,
|
||||
};
|
||||
use peach_stats::{
|
||||
stats,
|
||||
stats::{CpuStatPercentages, DiskUsage, LoadAverage, MemStat},
|
||||
};
|
||||
|
||||
use crate::routes::authentication::Authenticated;
|
||||
|
||||
// HELPERS AND ROUTES FOR /status
|
||||
|
||||
/// System statistics data.
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct StatusContext {
|
||||
pub back: Option<String>,
|
||||
pub cpu_stat_percent: Option<CpuStatPercentages>,
|
||||
pub disk_stats: Vec<DiskUsage>,
|
||||
pub flash_name: Option<String>,
|
||||
pub flash_msg: Option<String>,
|
||||
pub load_average: Option<LoadAverage>,
|
||||
pub mem_stats: Option<MemStat>,
|
||||
pub network_ping: String,
|
||||
pub oled_ping: String,
|
||||
pub dyndns_enabled: bool,
|
||||
pub dyndns_is_online: bool,
|
||||
pub config_is_valid: bool,
|
||||
pub sbot_is_online: bool,
|
||||
pub title: Option<String>,
|
||||
pub uptime: Option<i32>,
|
||||
}
|
||||
|
||||
impl StatusContext {
|
||||
pub fn build() -> StatusContext {
|
||||
// convert result to Option<CpuStatPercentages>, discard any error
|
||||
let cpu_stat_percent = stats::cpu_stats_percent().ok();
|
||||
let load_average = stats::load_average().ok();
|
||||
let mem_stats = stats::mem_stats().ok();
|
||||
// TODO: add `wpa_supplicant_status` to peach_network to replace this ping call
|
||||
// instead of: "is the network json-rpc server running?", we want to ask:
|
||||
// "is the wpa_supplicant systemd service functioning correctly?"
|
||||
let network_ping = match network_client::ping() {
|
||||
Ok(_) => "ONLINE".to_string(),
|
||||
Err(_) => "OFFLINE".to_string(),
|
||||
};
|
||||
let oled_ping = match oled_client::ping() {
|
||||
Ok(_) => "ONLINE".to_string(),
|
||||
Err(_) => "OFFLINE".to_string(),
|
||||
};
|
||||
|
||||
let uptime = match stats::uptime() {
|
||||
Ok(secs) => {
|
||||
let uptime_mins = secs / 60;
|
||||
uptime_mins.to_string()
|
||||
}
|
||||
Err(_) => "Unavailable".to_string(),
|
||||
};
|
||||
|
||||
// parse the uptime string to a signed integer (for math)
|
||||
let uptime_parsed = uptime.parse::<i32>().ok();
|
||||
|
||||
// serialize disk usage data into Vec<DiskUsage>
|
||||
let disk_usage_stats = match stats::disk_usage() {
|
||||
Ok(disks) => disks,
|
||||
Err(_) => Vec::new(),
|
||||
};
|
||||
|
||||
let mut disk_stats = Vec::new();
|
||||
// select only the partition we're interested in: /dev/mmcblk0p2 ("/")
|
||||
for disk in disk_usage_stats {
|
||||
if disk.mountpoint == "/" {
|
||||
disk_stats.push(disk);
|
||||
}
|
||||
}
|
||||
|
||||
// dyndns_is_online & config_is_valid
|
||||
let dyndns_enabled: bool;
|
||||
let dyndns_is_online: bool;
|
||||
let config_is_valid: bool;
|
||||
let load_peach_config_result = load_peach_config();
|
||||
match load_peach_config_result {
|
||||
Ok(peach_config) => {
|
||||
dyndns_enabled = peach_config.dyn_enabled;
|
||||
config_is_valid = true;
|
||||
if dyndns_enabled {
|
||||
let is_dyndns_online_result = dyndns_client::is_dns_updater_online();
|
||||
match is_dyndns_online_result {
|
||||
Ok(is_online) => {
|
||||
dyndns_is_online = is_online;
|
||||
}
|
||||
Err(_err) => {
|
||||
dyndns_is_online = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dyndns_is_online = false;
|
||||
}
|
||||
}
|
||||
Err(_err) => {
|
||||
dyndns_enabled = false;
|
||||
dyndns_is_online = false;
|
||||
config_is_valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
// test if go-sbot is running
|
||||
let sbot_status = SbotStatus::read();
|
||||
let sbot_is_online: bool = match sbot_status {
|
||||
// return true if state is active
|
||||
Ok(status) => matches!(status.state == Some("active".to_string()), true),
|
||||
_ => false,
|
||||
};
|
||||
|
||||
StatusContext {
|
||||
back: None,
|
||||
cpu_stat_percent,
|
||||
disk_stats,
|
||||
flash_name: None,
|
||||
flash_msg: None,
|
||||
load_average,
|
||||
mem_stats,
|
||||
network_ping,
|
||||
oled_ping,
|
||||
dyndns_enabled,
|
||||
dyndns_is_online,
|
||||
config_is_valid,
|
||||
sbot_is_online,
|
||||
title: None,
|
||||
uptime: uptime_parsed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/")]
|
||||
pub fn device_status(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
|
||||
// assign context through context_builder call
|
||||
let mut context = StatusContext::build();
|
||||
context.back = Some("/".to_string());
|
||||
context.title = Some("Device Status".to_string());
|
||||
// check to see if there is a flash message to display
|
||||
if let Some(flash) = flash {
|
||||
// add flash message contents to the context object
|
||||
context.flash_name = Some(flash.kind().to_string());
|
||||
context.flash_msg = Some(flash.message().to_string());
|
||||
};
|
||||
// template_dir is set in Rocket.toml
|
||||
Template::render("status/device", &context)
|
||||
}
|
||||
|
||||
// HELPERS AND ROUTES FOR /power/reboot
|
||||
|
||||
/// Executes a system command to reboot the device immediately.
|
||||
pub fn reboot() -> io::Result<Output> {
|
||||
info!("Rebooting 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 "rebooting..." message to `peach-oled` for display
|
||||
Command::new("sudo")
|
||||
.arg("shutdown")
|
||||
.arg("-r")
|
||||
.arg("now")
|
||||
.output()
|
||||
}
|
||||
|
||||
#[get("/power/reboot")]
|
||||
pub fn reboot_cmd(_auth: Authenticated) -> Flash<Redirect> {
|
||||
match reboot() {
|
||||
Ok(_) => Flash::success(Redirect::to("/power"), "Rebooting the device"),
|
||||
Err(_) => Flash::error(Redirect::to("/power"), "Failed to reboot the device"),
|
||||
}
|
||||
}
|
||||
|
||||
// HELPERS AND ROUTES FOR /power/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()
|
||||
}
|
||||
|
||||
#[get("/power/shutdown")]
|
||||
pub fn shutdown_cmd(_auth: Authenticated) -> Flash<Redirect> {
|
||||
match shutdown() {
|
||||
Ok(_) => Flash::success(Redirect::to("/power"), "Shutting down the device"),
|
||||
Err(_) => Flash::error(Redirect::to("/power"), "Failed to shutdown the device"),
|
||||
}
|
||||
}
|
||||
|
||||
// HELPERS AND ROUTES FOR /power
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct PowerContext {
|
||||
pub back: Option<String>,
|
||||
pub flash_name: Option<String>,
|
||||
pub flash_msg: Option<String>,
|
||||
pub title: Option<String>,
|
||||
}
|
||||
|
||||
impl PowerContext {
|
||||
pub fn build() -> PowerContext {
|
||||
PowerContext {
|
||||
back: None,
|
||||
flash_name: None,
|
||||
flash_msg: None,
|
||||
title: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/power")]
|
||||
pub fn power_menu(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
|
||||
let mut context = PowerContext::build();
|
||||
context.back = Some("/".to_string());
|
||||
context.title = Some("Power Menu".to_string());
|
||||
// check to see if there is a flash message to display
|
||||
if let Some(flash) = flash {
|
||||
// add flash message contents to the context object
|
||||
context.flash_name = Some(flash.kind().to_string());
|
||||
context.flash_msg = Some(flash.message().to_string());
|
||||
};
|
||||
Template::render("power", &context)
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -14,7 +14,7 @@ pub fn build_template(
|
|||
let theme = theme::get_theme();
|
||||
|
||||
// conditionally render the hermies icon and theme-switcher icon with correct link
|
||||
let (hermies, switcher) = match theme.as_str() {
|
||||
let (hermies, theme_switcher) = match theme.as_str() {
|
||||
// if we're using the dark theme, render light icons and "light" query param
|
||||
"dark" => (
|
||||
"/icons/hermies_hex_light.svg",
|
||||
|
@ -56,8 +56,7 @@ pub fn build_template(
|
|||
a class="nav-item" href="/" {
|
||||
img class="icon nav-icon-left" src="/icons/peach-icon.png" alt="PeachCloud" title="Home";
|
||||
}
|
||||
// render the pre-defined theme-switcher icon
|
||||
(switcher)
|
||||
(theme_switcher)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue