From 77c1ccb1c76bb9957393db77163bc85e740e17a7 Mon Sep 17 00:00:00 2001 From: glyph Date: Wed, 23 Mar 2022 09:14:54 +0200 Subject: [PATCH] add form handler and helper for sbot config updates --- peach-web/src/router.rs | 13 +- .../routes/settings/scuttlebutt/configure.rs | 115 ++++++++++++++++-- peach-web/src/utils/sbot.rs | 29 +++++ 3 files changed, 146 insertions(+), 11 deletions(-) diff --git a/peach-web/src/router.rs b/peach-web/src/router.rs index 74d0f44..2809698 100644 --- a/peach-web/src/router.rs +++ b/peach-web/src/router.rs @@ -1,4 +1,3 @@ -use log::debug; use rouille::{router, Request, Response}; use crate::{routes, utils::flash::FlashResponse}; @@ -75,7 +74,16 @@ pub fn mount_peachpub_routes(request: &Request) -> Response { }, (GET) (/settings/scuttlebutt/configure) => { - Response::html(routes::settings::scuttlebutt::configure::build_template()) + Response::html(routes::settings::scuttlebutt::configure::build_template(request)) + .reset_flash() + }, + + (POST) (/settings/scuttlebutt/configure) => { + routes::settings::scuttlebutt::configure::handle_form(request, false) + }, + + (POST) (/settings/scuttlebutt/configure/restart) => { + routes::settings::scuttlebutt::configure::handle_form(request, true) }, (GET) (/settings/admin) => { @@ -133,7 +141,6 @@ pub fn mount_peachpub_routes(request: &Request) -> Response { }, (GET) (/scuttlebutt/profile/{ssb_id: String}) => { - debug!("ssb_id: {}", ssb_id); Response::html(routes::scuttlebutt::profile::build_template(request, Some(ssb_id))) }, diff --git a/peach-web/src/routes/settings/scuttlebutt/configure.rs b/peach-web/src/routes/settings/scuttlebutt/configure.rs index c53c1c8..bc24403 100644 --- a/peach-web/src/routes/settings/scuttlebutt/configure.rs +++ b/peach-web/src/routes/settings/scuttlebutt/configure.rs @@ -1,9 +1,15 @@ +use log::{debug, warn}; use maud::{html, PreEscaped}; use peach_lib::sbot::{SbotConfig, SbotStatus}; +use rouille::{post_input, try_or_400, Request, Response}; -use crate::templates; - -// TODO: flash message implementation for rouille +use crate::{ + templates, + utils::{ + flash::{FlashRequest, FlashResponse}, + sbot, + }, +}; /// Read the status and configuration of the sbot. /// Define fallback values if an error is returned from either read function. @@ -31,7 +37,8 @@ fn read_status_and_config() -> (String, SbotConfig, String, String) { let (ip, port) = match sbot_config.lis.find(':') { Some(index) => { let (ip, port) = sbot_config.lis.split_at(index); - (ip.to_string(), port.to_string()) + // remove the : from the port + (ip.to_string(), port.replace(':', "").to_string()) } // if no ':' separator is found, assume an ip has been configured (without port) None => (sbot_config.lis.to_string(), String::new()), @@ -41,7 +48,10 @@ fn read_status_and_config() -> (String, SbotConfig, String, String) { } /// Scuttlebutt settings menu template builder. -pub fn build_template() -> PreEscaped { +pub fn build_template(request: &Request) -> PreEscaped { + // check for flash cookies; will be (None, None) if no flash cookies are found + let (flash_name, flash_msg) = request.retrieve_flash(); + let (run_on_startup, sbot_config, ip, port) = read_status_and_config(); let menu_template = html! { @@ -152,11 +162,14 @@ pub fn build_template() -> PreEscaped { input type="hidden" id="nounixsock" name="nounixsock" value=(sbot_config.nounixsock); (PreEscaped("")) input id="saveConfig" class="button button-primary center" style="margin-top: 2rem;" type="submit" title="Save configuration parameters to file" value="Save"; - input id="saveRestartConfig" class="button button-primary center" type="submit" title="Save configuration parameters to file and then (re)start the pub" value="Save & Restart" formaction="/settings/scuttlebutt/configure?restart=true"; + input id="saveRestartConfig" class="button button-primary center" type="submit" title="Save configuration parameters to file and then (re)start the pub" value="Save & Restart" formaction="/settings/scuttlebutt/configure/restart"; a id="restoreDefaults" class="button button-warning center" href="/settings/scuttlebutt/configure/default" title="Restore default configuration parameters and save them to file" { "Restore Defaults" } } - (PreEscaped("")) - // TODO: flash message + // render flash message if cookies were found in the request + @if let (Some(name), Some(msg)) = (flash_name, flash_msg) { + (PreEscaped("")) + (templates::flash::build_template(name, msg)) + } } }; @@ -168,3 +181,89 @@ pub fn build_template() -> PreEscaped { // render the base template with the provided body templates::base::build_template(body) } + +/// Parse the sbot configuration values and write to file. +pub fn handle_form(request: &Request, restart: bool) -> Response { + // query the request body for form data + // return a 400 error if the admin_id field is missing + let data = try_or_400!(post_input!(request, { + repo: String, + debugdir: String, + shscap: String, + hmac: String, + hops: u8, + lis_ip: String, + lis_port: String, + wslis: String, + debuglis: String, + localadv: bool, + localdiscov: bool, + enable_ebt: bool, + promisc: bool, + nounixsock: bool, + startup: bool, + repair: bool, + })); + + debug!("ip: {} port: {}", data.lis_ip, data.lis_port); + + // concat the ip and port for listen address + let lis = format!("{}:{}", data.lis_ip, data.lis_port); + + debug!("{}", lis); + + // instantiate `SbotConfig` from form data + let config = SbotConfig { + lis, + hops: data.hops, + repo: data.repo, + debugdir: data.debugdir, + shscap: data.shscap, + localadv: data.localadv, + localdiscov: data.localdiscov, + hmac: data.hmac, + wslis: data.wslis, + debuglis: data.debuglis, + enable_ebt: data.enable_ebt, + promisc: data.promisc, + nounixsock: data.nounixsock, + repair: data.repair, + }; + + match data.startup { + true => { + // TODO: rouille - log integration + //info!("Enabling go-sbot.service"); + if let Err(e) = sbot::systemctl_sbot_cmd("enable") { + warn!("Failed to enable go-sbot.service: {}", e) + } + } + false => { + // TODO: info!("Disabling go-sbot.service"); + if let Err(e) = sbot::systemctl_sbot_cmd("disable") { + warn!("Failed to disable go-sbot.service: {}", e) + } + } + }; + + // write config to file + let (name, msg) = match SbotConfig::write(config) { + Ok(_) => { + // if `restart` query parameter is `true`, attempt sbot process (re)start + if restart { + // returns a tuple of (name, msg) based on the outcome (success or error) + sbot::restart_sbot_process() + } else { + ("success".to_string(), "Updated configuration".to_string()) + } + } + Err(err) => ( + "error".to_string(), + format!("Failed to update configuration: {}", err), + ), + }; + + let (flash_name, flash_msg) = (format!("flash_name={}", name), format!("flash_msg={}", msg)); + + Response::redirect_303("/settings/scuttlebutt/configure").add_flash(flash_name, flash_msg) +} diff --git a/peach-web/src/utils/sbot.rs b/peach-web/src/utils/sbot.rs index d50450b..0390ff7 100644 --- a/peach-web/src/utils/sbot.rs +++ b/peach-web/src/utils/sbot.rs @@ -30,6 +30,35 @@ pub fn systemctl_sbot_cmd(cmd: &str) -> io::Result { .output() } +/// Executes a systemctl stop command followed by start command. +/// Returns a redirect with a flash message stating the output of the restart attempt. +pub fn restart_sbot_process() -> (String, String) { + // TODO: info!("Restarting go-sbot.service"); + match systemctl_sbot_cmd("stop") { + // if stop was successful, try to start the process + Ok(_) => match systemctl_sbot_cmd("start") { + Ok(_) => ( + "success".to_string(), + "Updated configuration and restarted the sbot process".to_string(), + ), + Err(err) => ( + "error".to_string(), + format!( + "Updated configuration but failed to start the sbot process: {}", + err + ), + ), + }, + Err(err) => ( + "error".to_string(), + format!( + "Updated configuration but failed to stop the sbot process: {}", + err + ), + ), + } +} + /// Initialise an sbot client with the given configuration parameters. pub async fn init_sbot_with_config( sbot_config: &Option,