Merge pull request 'Add configuration reading and writing for go-sbot' (#79) from sbot_config into main
Reviewed-on: #79
This commit is contained in:
commit
8f49fa55ad
|
@ -6,6 +6,7 @@ edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = "0.4.19"
|
chrono = "0.4.19"
|
||||||
|
dirs = "4.0"
|
||||||
fslock="0.1.6"
|
fslock="0.1.6"
|
||||||
jsonrpc-client-core = "0.5"
|
jsonrpc-client-core = "0.5"
|
||||||
jsonrpc-client-http = "0.5"
|
jsonrpc-client-http = "0.5"
|
||||||
|
@ -16,4 +17,5 @@ regex = "1"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde_yaml = "0.8"
|
serde_yaml = "0.8"
|
||||||
|
toml = "0.5.8"
|
||||||
sha3 = "0.10.0"
|
sha3 = "0.10.0"
|
||||||
|
|
|
@ -7,6 +7,9 @@ use std::{io, str, string};
|
||||||
/// This type represents all possible errors that can occur when interacting with the PeachCloud library.
|
/// This type represents all possible errors that can occur when interacting with the PeachCloud library.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum PeachError {
|
pub enum PeachError {
|
||||||
|
/// Represents a failure to determine the path of the user's home directory.
|
||||||
|
HomeDir,
|
||||||
|
|
||||||
/// Represents all other cases of `std::io::Error`.
|
/// Represents all other cases of `std::io::Error`.
|
||||||
Io(io::Error),
|
Io(io::Error),
|
||||||
|
|
||||||
|
@ -67,6 +70,12 @@ pub enum PeachError {
|
||||||
/// Represents a failure to serialize or deserialize JSON.
|
/// Represents a failure to serialize or deserialize JSON.
|
||||||
SerdeJson(serde_json::error::Error),
|
SerdeJson(serde_json::error::Error),
|
||||||
|
|
||||||
|
/// Represents a failure to deserialize TOML.
|
||||||
|
TomlDeser(toml::de::Error),
|
||||||
|
|
||||||
|
/// Represents a failure to serialize TOML.
|
||||||
|
TomlSer(toml::ser::Error),
|
||||||
|
|
||||||
/// Represents a failure to serialize or deserialize YAML.
|
/// Represents a failure to serialize or deserialize YAML.
|
||||||
SerdeYaml(serde_yaml::Error),
|
SerdeYaml(serde_yaml::Error),
|
||||||
|
|
||||||
|
@ -87,7 +96,7 @@ pub enum PeachError {
|
||||||
Write {
|
Write {
|
||||||
/// The underlying source of the error.
|
/// The underlying source of the error.
|
||||||
source: io::Error,
|
source: io::Error,
|
||||||
/// The file path for the write attemp.
|
/// The file path for the write attempt.
|
||||||
path: String,
|
path: String,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -95,6 +104,7 @@ pub enum PeachError {
|
||||||
impl std::error::Error for PeachError {
|
impl std::error::Error for PeachError {
|
||||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
match *self {
|
match *self {
|
||||||
|
PeachError::HomeDir => None,
|
||||||
PeachError::Io(_) => None,
|
PeachError::Io(_) => None,
|
||||||
PeachError::JsonRpcClientCore(_) => None,
|
PeachError::JsonRpcClientCore(_) => None,
|
||||||
PeachError::JsonRpcCore(_) => None,
|
PeachError::JsonRpcCore(_) => None,
|
||||||
|
@ -111,6 +121,8 @@ impl std::error::Error for PeachError {
|
||||||
PeachError::SerdeJson(_) => None,
|
PeachError::SerdeJson(_) => None,
|
||||||
PeachError::SerdeYaml(_) => None,
|
PeachError::SerdeYaml(_) => None,
|
||||||
PeachError::SsbAdminIdNotFound { .. } => None,
|
PeachError::SsbAdminIdNotFound { .. } => None,
|
||||||
|
PeachError::TomlDeser(_) => None,
|
||||||
|
PeachError::TomlSer(_) => None,
|
||||||
PeachError::Utf8ToStr(_) => None,
|
PeachError::Utf8ToStr(_) => None,
|
||||||
PeachError::Utf8ToString(_) => None,
|
PeachError::Utf8ToString(_) => None,
|
||||||
PeachError::Write { ref source, .. } => Some(source),
|
PeachError::Write { ref source, .. } => Some(source),
|
||||||
|
@ -121,6 +133,12 @@ impl std::error::Error for PeachError {
|
||||||
impl std::fmt::Display for PeachError {
|
impl std::fmt::Display for PeachError {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
|
PeachError::HomeDir => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Unable to determine the path of the user's home directory"
|
||||||
|
)
|
||||||
|
}
|
||||||
PeachError::Io(ref err) => err.fmt(f),
|
PeachError::Io(ref err) => err.fmt(f),
|
||||||
PeachError::JsonRpcClientCore(ref err) => err.fmt(f),
|
PeachError::JsonRpcClientCore(ref err) => err.fmt(f),
|
||||||
PeachError::JsonRpcCore(ref err) => {
|
PeachError::JsonRpcCore(ref err) => {
|
||||||
|
@ -158,6 +176,8 @@ impl std::fmt::Display for PeachError {
|
||||||
PeachError::SsbAdminIdNotFound { ref id } => {
|
PeachError::SsbAdminIdNotFound { ref id } => {
|
||||||
write!(f, "Config error: SSB admin ID `{}` not found", id)
|
write!(f, "Config error: SSB admin ID `{}` not found", id)
|
||||||
}
|
}
|
||||||
|
PeachError::TomlDeser(ref err) => err.fmt(f),
|
||||||
|
PeachError::TomlSer(ref err) => err.fmt(f),
|
||||||
PeachError::Utf8ToStr(ref err) => err.fmt(f),
|
PeachError::Utf8ToStr(ref err) => err.fmt(f),
|
||||||
PeachError::Utf8ToString(ref err) => err.fmt(f),
|
PeachError::Utf8ToString(ref err) => err.fmt(f),
|
||||||
PeachError::Write { ref path, .. } => {
|
PeachError::Write { ref path, .. } => {
|
||||||
|
@ -209,6 +229,18 @@ impl From<serde_yaml::Error> for PeachError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<toml::de::Error> for PeachError {
|
||||||
|
fn from(err: toml::de::Error) -> PeachError {
|
||||||
|
PeachError::TomlDeser(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<toml::ser::Error> for PeachError {
|
||||||
|
fn from(err: toml::ser::Error) -> PeachError {
|
||||||
|
PeachError::TomlSer(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<str::Utf8Error> for PeachError {
|
impl From<str::Utf8Error> for PeachError {
|
||||||
fn from(err: str::Utf8Error) -> PeachError {
|
fn from(err: str::Utf8Error) -> PeachError {
|
||||||
PeachError::Utf8ToStr(err)
|
PeachError::Utf8ToStr(err)
|
||||||
|
|
|
@ -4,7 +4,7 @@ pub mod error;
|
||||||
pub mod network_client;
|
pub mod network_client;
|
||||||
pub mod oled_client;
|
pub mod oled_client;
|
||||||
pub mod password_utils;
|
pub mod password_utils;
|
||||||
pub mod sbot_client;
|
pub mod sbot;
|
||||||
pub mod stats_client;
|
pub mod stats_client;
|
||||||
|
|
||||||
// re-export error types
|
// re-export error types
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use nanorand::{Rng, WyRand};
|
use nanorand::{Rng, WyRand};
|
||||||
use sha3::{Digest, Sha3_256};
|
use sha3::{Digest, Sha3_256};
|
||||||
|
|
||||||
use crate::{config_manager, error::PeachError, sbot_client};
|
use crate::{config_manager, error::PeachError};
|
||||||
|
|
||||||
/// Returns Ok(()) if the supplied password is correct,
|
/// Returns Ok(()) if the supplied password is correct,
|
||||||
/// and returns Err if the supplied password is incorrect.
|
/// and returns Err if the supplied password is incorrect.
|
||||||
|
@ -102,7 +102,8 @@ using this link: http://peach.local/reset_password",
|
||||||
// finally send the message to the admins
|
// finally send the message to the admins
|
||||||
let peach_config = config_manager::load_peach_config()?;
|
let peach_config = config_manager::load_peach_config()?;
|
||||||
for ssb_admin_id in peach_config.ssb_admin_ids {
|
for ssb_admin_id in peach_config.ssb_admin_ids {
|
||||||
sbot_client::private_message(&msg, &ssb_admin_id)?;
|
// TODO: replace with golgi
|
||||||
|
//sbot_client::private_message(&msg, &ssb_admin_id)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,203 @@
|
||||||
|
//! Data types and associated methods for monitoring and configuring go-sbot.
|
||||||
|
|
||||||
|
use std::{fs, fs::File, io::Write, process::Command, str};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::error::PeachError;
|
||||||
|
|
||||||
|
/// go-sbot process status.
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct SbotStatus {
|
||||||
|
/// Current process state.
|
||||||
|
pub state: Option<String>,
|
||||||
|
/// Current process boot state.
|
||||||
|
pub boot_state: Option<String>,
|
||||||
|
/// Current process memory usage in bytes.
|
||||||
|
pub memory: Option<u32>,
|
||||||
|
/// Uptime for the process (if state is `active`).
|
||||||
|
pub uptime: Option<String>,
|
||||||
|
/// Downtime for the process (if state is `inactive`).
|
||||||
|
pub downtime: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Default builder for `SbotStatus`.
|
||||||
|
impl Default for SbotStatus {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
state: None,
|
||||||
|
boot_state: None,
|
||||||
|
memory: None,
|
||||||
|
uptime: None,
|
||||||
|
downtime: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SbotStatus {
|
||||||
|
/// Retrieve statistics for the go-sbot systemd process by querying `systemctl`.
|
||||||
|
pub fn read() -> Result<Self, PeachError> {
|
||||||
|
let mut status = SbotStatus::default();
|
||||||
|
|
||||||
|
let info_output = Command::new("/usr/bin/systemctl")
|
||||||
|
.arg("--user")
|
||||||
|
.arg("show")
|
||||||
|
.arg("go-sbot.service")
|
||||||
|
.arg("--no-page")
|
||||||
|
.output()?;
|
||||||
|
|
||||||
|
let service_info = std::str::from_utf8(&info_output.stdout)?;
|
||||||
|
|
||||||
|
for line in service_info.lines() {
|
||||||
|
if line.starts_with("ActiveState=") {
|
||||||
|
if let Some(state) = line.strip_prefix("ActiveState=") {
|
||||||
|
status.state = Some(state.to_string())
|
||||||
|
}
|
||||||
|
} else if line.starts_with("MemoryCurrent=") {
|
||||||
|
if let Some(memory) = line.strip_prefix("MemoryCurrent=") {
|
||||||
|
status.memory = memory.parse().ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let status_output = Command::new("/usr/bin/systemctl")
|
||||||
|
.arg("--user")
|
||||||
|
.arg("status")
|
||||||
|
.arg("go-sbot.service")
|
||||||
|
.output()?;
|
||||||
|
|
||||||
|
let service_status = str::from_utf8(&status_output.stdout)?;
|
||||||
|
//.map_err(PeachError::Utf8ToStr)?;
|
||||||
|
|
||||||
|
for line in service_status.lines() {
|
||||||
|
// example of the output line we're looking for:
|
||||||
|
// `Loaded: loaded (/home/glyph/.config/systemd/user/go-sbot.service; enabled; vendor
|
||||||
|
// preset: enabled)`
|
||||||
|
if line.contains("Loaded:") {
|
||||||
|
let before_boot_state = line.find(';');
|
||||||
|
let after_boot_state = line.rfind(';');
|
||||||
|
if let (Some(start), Some(end)) = (before_boot_state, after_boot_state) {
|
||||||
|
// extract the enabled / disabled from the `Loaded: ...` line
|
||||||
|
// using the index of the first ';' + 2 and the last ';'
|
||||||
|
status.boot_state = Some(line[start + 2..end].to_string());
|
||||||
|
}
|
||||||
|
// example of the output line we're looking for here:
|
||||||
|
// `Active: active (running) since Mon 2022-01-24 16:22:51 SAST; 4min 14s ago`
|
||||||
|
} else if line.contains("Active:") {
|
||||||
|
let before_time = line.find(';');
|
||||||
|
let after_time = line.find(" ago");
|
||||||
|
if let (Some(start), Some(end)) = (before_time, after_time) {
|
||||||
|
// extract the uptime / downtime from the `Active: ...` line
|
||||||
|
// using the index of ';' + 2 and the index of " ago"
|
||||||
|
let time = Some(&line[start + 2..end]);
|
||||||
|
// if service is active then the `time` reading is uptime
|
||||||
|
if status.state == Some("active".to_string()) {
|
||||||
|
status.uptime = time.map(|t| t.to_string())
|
||||||
|
// if service is inactive then the `time` reading is downtime
|
||||||
|
} else if status.state == Some("inactive".to_string()) {
|
||||||
|
status.downtime = time.map(|t| t.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// go-sbot configuration parameters.
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct SbotConfig {
|
||||||
|
// TODO: maybe define as a Path type?
|
||||||
|
/// Directory path for the log and indexes.
|
||||||
|
pub repo: String,
|
||||||
|
/// Directory path for writing debug output.
|
||||||
|
pub debugdir: String,
|
||||||
|
/// Secret-handshake app-key (aka. network key).
|
||||||
|
pub shscap: String,
|
||||||
|
/// HMAC hash used to sign messages.
|
||||||
|
pub hmac: String,
|
||||||
|
/// Replication hops (1: friends, 2: friends of friends).
|
||||||
|
pub hops: u8,
|
||||||
|
/// Address to listen on.
|
||||||
|
pub lis: String,
|
||||||
|
/// Address to listen on for WebSocket connections.
|
||||||
|
pub wslis: String,
|
||||||
|
/// Address to for metrics and pprof HTTP server.
|
||||||
|
pub debuglis: String,
|
||||||
|
/// Enable sending local UDP broadcasts.
|
||||||
|
pub localadv: bool,
|
||||||
|
/// Enable listening for UDP broadcasts and connecting.
|
||||||
|
pub localdiscov: bool,
|
||||||
|
/// Enable syncing by using epidemic-broadcast-trees (EBT).
|
||||||
|
#[serde(rename(serialize = "enable_ebt", deserialize = "enable-ebt"))]
|
||||||
|
pub enable_ebt: bool,
|
||||||
|
/// Bypass graph auth and fetch remote's feed (useful for pubs that are restoring their data
|
||||||
|
/// from peer; user beware - caveats about).
|
||||||
|
pub promisc: bool,
|
||||||
|
/// Disable the UNIX socket RPC interface.
|
||||||
|
pub nounixsock: bool,
|
||||||
|
/// Attempt to repair the filesystem before starting.
|
||||||
|
pub repair: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Default configuration values for go-sbot.
|
||||||
|
impl Default for SbotConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
repo: ".ssb-go".to_string(),
|
||||||
|
debugdir: "".to_string(),
|
||||||
|
shscap: "1KHLiKZvAvjbY1ziZEHMXawbCEIM6qwjCDm3VYRan/s=".to_string(),
|
||||||
|
hmac: "".to_string(),
|
||||||
|
hops: 1,
|
||||||
|
lis: ":8008".to_string(),
|
||||||
|
wslis: ":8989".to_string(),
|
||||||
|
debuglis: "localhost:6078".to_string(),
|
||||||
|
localadv: false,
|
||||||
|
localdiscov: false,
|
||||||
|
enable_ebt: false,
|
||||||
|
promisc: false,
|
||||||
|
nounixsock: false,
|
||||||
|
repair: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SbotConfig {
|
||||||
|
/// Read the go-sbot `config.toml` file from file and deserialize into `SbotConfig`.
|
||||||
|
pub fn read() -> Result<Self, PeachError> {
|
||||||
|
// determine path of user's home directory
|
||||||
|
let mut config_path = dirs::home_dir().ok_or(PeachError::HomeDir)?;
|
||||||
|
config_path.push(".ssb-go/config.toml");
|
||||||
|
|
||||||
|
let config_contents = fs::read_to_string(config_path)?;
|
||||||
|
|
||||||
|
let config: SbotConfig = toml::from_str(&config_contents)?;
|
||||||
|
|
||||||
|
Ok(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write the given `SbotConfig` to the go-sbot `config.toml` file.
|
||||||
|
pub fn write(config: SbotConfig) -> Result<(), PeachError> {
|
||||||
|
let repo_comment = "# For details about go-sbot configuration, please visit the repo: https://github.com/cryptoscope/ssb\n".to_string();
|
||||||
|
|
||||||
|
// convert the provided `SbotConfig` instance to a string
|
||||||
|
let config_string = toml::to_string(&config)?;
|
||||||
|
|
||||||
|
// determine path of user's home directory
|
||||||
|
let mut config_path = dirs::home_dir().ok_or(PeachError::HomeDir)?;
|
||||||
|
config_path.push(".ssb-go/config.toml");
|
||||||
|
|
||||||
|
// open config file for writing
|
||||||
|
let mut file = File::create(config_path)?;
|
||||||
|
|
||||||
|
// write the repo comment to file
|
||||||
|
write!(file, "{}", repo_comment)?;
|
||||||
|
|
||||||
|
// write the config string to file
|
||||||
|
write!(file, "{}", config_string)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,111 +0,0 @@
|
||||||
//! Interfaces for monitoring and configuring go-sbot using sbotcli.
|
|
||||||
|
|
||||||
use std::process::Command;
|
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::error::PeachError;
|
|
||||||
|
|
||||||
pub fn is_sbot_online() -> Result<bool, PeachError> {
|
|
||||||
let output = Command::new("/usr/bin/systemctl")
|
|
||||||
.arg("status")
|
|
||||||
.arg("peach-go-sbot")
|
|
||||||
.output()?;
|
|
||||||
let status = output.status;
|
|
||||||
// returns true if the service had an exist status of 0 (is running)
|
|
||||||
let is_running = status.success();
|
|
||||||
Ok(is_running)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// currently go-sbotcli determines where the working directory is
|
|
||||||
/// using the home directory of th user that invokes it
|
|
||||||
/// this could be changed to be supplied as CLI arg
|
|
||||||
/// but for now all sbotcli commands must first become peach-go-sbot before running
|
|
||||||
/// the sudoers file is configured to allow this to happen without a password
|
|
||||||
pub fn sbotcli_command() -> Command {
|
|
||||||
let mut command = Command::new("sudo");
|
|
||||||
command
|
|
||||||
.arg("-u")
|
|
||||||
.arg("peach-go-sbot")
|
|
||||||
.arg("/usr/bin/sbotcli");
|
|
||||||
command
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn post(msg: &str) -> Result<(), PeachError> {
|
|
||||||
let mut command = sbotcli_command();
|
|
||||||
let output = command.arg("publish").arg("post").arg(msg).output()?;
|
|
||||||
if output.status.success() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
let stderr = std::str::from_utf8(&output.stderr)?;
|
|
||||||
Err(PeachError::SbotCli {
|
|
||||||
msg: format!("Error making ssb post: {}", stderr),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
struct WhoAmIValue {
|
|
||||||
id: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn whoami() -> Result<String, PeachError> {
|
|
||||||
let mut command = sbotcli_command();
|
|
||||||
let output = command.arg("call").arg("whoami").output()?;
|
|
||||||
let text_output = std::str::from_utf8(&output.stdout)?;
|
|
||||||
let value: WhoAmIValue = serde_json::from_str(text_output)?;
|
|
||||||
let id = value.id;
|
|
||||||
Ok(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_invite(uses: i32) -> Result<String, PeachError> {
|
|
||||||
let mut command = sbotcli_command();
|
|
||||||
let output = command
|
|
||||||
.arg("invite")
|
|
||||||
.arg("create")
|
|
||||||
.arg("--uses")
|
|
||||||
.arg(uses.to_string())
|
|
||||||
.output()?;
|
|
||||||
let text_output = std::str::from_utf8(&output.stdout)?;
|
|
||||||
let output = text_output.replace('\n', "");
|
|
||||||
Ok(output)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_pub_name(new_name: &str) -> Result<(), PeachError> {
|
|
||||||
let pub_ssb_id = whoami()?;
|
|
||||||
let mut command = sbotcli_command();
|
|
||||||
let output = command
|
|
||||||
.arg("publish")
|
|
||||||
.arg("about")
|
|
||||||
.arg("--name")
|
|
||||||
.arg(new_name)
|
|
||||||
.arg(pub_ssb_id)
|
|
||||||
.output()?;
|
|
||||||
if output.status.success() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
let stderr = std::str::from_utf8(&output.stderr)?;
|
|
||||||
Err(PeachError::SbotCli {
|
|
||||||
msg: format!("Error updating pub name: {}", stderr),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn private_message(msg: &str, recipient: &str) -> Result<(), PeachError> {
|
|
||||||
let mut command = sbotcli_command();
|
|
||||||
let output = command
|
|
||||||
.arg("publish")
|
|
||||||
.arg("post")
|
|
||||||
.arg("--recps")
|
|
||||||
.arg(recipient)
|
|
||||||
.arg(msg)
|
|
||||||
.output()?;
|
|
||||||
if output.status.success() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
let stderr = std::str::from_utf8(&output.stderr)?;
|
|
||||||
Err(PeachError::SbotCli {
|
|
||||||
msg: format!("Error sending ssb private message: {}", stderr),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -51,6 +51,8 @@ pub fn mount_peachpub_routes(rocket: Rocket<Build>) -> Rocket<Build> {
|
||||||
routes![
|
routes![
|
||||||
ssb_settings_menu,
|
ssb_settings_menu,
|
||||||
configure_sbot,
|
configure_sbot,
|
||||||
|
configure_sbot_default,
|
||||||
|
configure_sbot_post,
|
||||||
restart_sbot,
|
restart_sbot,
|
||||||
start_sbot,
|
start_sbot,
|
||||||
stop_sbot
|
stop_sbot
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use peach_stats::sbot;
|
use peach_lib::sbot::SbotStatus;
|
||||||
use rocket::{get, request::FlashMessage, State};
|
use rocket::{get, request::FlashMessage, State};
|
||||||
use rocket_dyn_templates::{tera::Context, Template};
|
use rocket_dyn_templates::{tera::Context, Template};
|
||||||
|
|
||||||
|
@ -9,11 +9,11 @@ use crate::RocketConfig;
|
||||||
|
|
||||||
#[get("/")]
|
#[get("/")]
|
||||||
pub fn home(_auth: Authenticated, config: &State<RocketConfig>) -> Template {
|
pub fn home(_auth: Authenticated, config: &State<RocketConfig>) -> Template {
|
||||||
// retrieve go-sbot systemd process stats
|
// retrieve go-sbot systemd process status
|
||||||
let sbot_stats = sbot::sbot_stats().ok();
|
let sbot_status = SbotStatus::read().ok();
|
||||||
|
|
||||||
let mut context = Context::new();
|
let mut context = Context::new();
|
||||||
context.insert("sbot_stats", &sbot_stats);
|
context.insert("sbot_status", &sbot_status);
|
||||||
context.insert("flash_name", &None::<()>);
|
context.insert("flash_name", &None::<()>);
|
||||||
context.insert("flash_msg", &None::<()>);
|
context.insert("flash_msg", &None::<()>);
|
||||||
context.insert("title", &None::<()>);
|
context.insert("title", &None::<()>);
|
||||||
|
|
|
@ -93,11 +93,7 @@ pub struct Post {
|
||||||
|
|
||||||
/// Publish a public Scuttlebutt post. Redirects to profile page of the PeachCloud local identity with a flash message describing the outcome of the action (may be successful or unsuccessful).
|
/// Publish a public Scuttlebutt post. Redirects to profile page of the PeachCloud local identity with a flash message describing the outcome of the action (may be successful or unsuccessful).
|
||||||
#[post("/publish", data = "<post>")]
|
#[post("/publish", data = "<post>")]
|
||||||
pub fn publish(
|
pub fn publish(post: Form<Post>, _auth: Authenticated) -> Flash<Redirect> {
|
||||||
post: Form<Post>,
|
|
||||||
flash: Option<FlashMessage>,
|
|
||||||
_auth: Authenticated,
|
|
||||||
) -> Flash<Redirect> {
|
|
||||||
let post_text = &post.text;
|
let post_text = &post.text;
|
||||||
// perform the sbotcli publish action using post_text
|
// perform the sbotcli publish action using post_text
|
||||||
// if successful, redirect to home profile page and flash "success"
|
// if successful, redirect to home profile page and flash "success"
|
||||||
|
@ -119,11 +115,7 @@ pub struct PublicKey {
|
||||||
|
|
||||||
/// Follow a Scuttlebutt profile specified by the given public key. Redirects to the appropriate profile page with a flash message describing the outcome of the action (may be successful or unsuccessful).
|
/// Follow a Scuttlebutt profile specified by the given public key. Redirects to the appropriate profile page with a flash message describing the outcome of the action (may be successful or unsuccessful).
|
||||||
#[post("/follow", data = "<pub_key>")]
|
#[post("/follow", data = "<pub_key>")]
|
||||||
pub fn follow(
|
pub fn follow(pub_key: Form<PublicKey>, _auth: Authenticated) -> Flash<Redirect> {
|
||||||
pub_key: Form<PublicKey>,
|
|
||||||
flash: Option<FlashMessage>,
|
|
||||||
_auth: Authenticated,
|
|
||||||
) -> Flash<Redirect> {
|
|
||||||
let public_key = &pub_key.key;
|
let public_key = &pub_key.key;
|
||||||
// perform the sbotcli follow action using &pub_key.0
|
// perform the sbotcli follow action using &pub_key.0
|
||||||
// if successful, redirect to profile page with provided public key and flash "success"
|
// if successful, redirect to profile page with provided public key and flash "success"
|
||||||
|
@ -138,11 +130,7 @@ pub fn follow(
|
||||||
|
|
||||||
/// Unfollow a Scuttlebutt profile specified by the given public key. Redirects to the appropriate profile page with a flash message describing the outcome of the action (may be successful or unsuccessful).
|
/// Unfollow a Scuttlebutt profile specified by the given public key. Redirects to the appropriate profile page with a flash message describing the outcome of the action (may be successful or unsuccessful).
|
||||||
#[post("/unfollow", data = "<pub_key>")]
|
#[post("/unfollow", data = "<pub_key>")]
|
||||||
pub fn unfollow(
|
pub fn unfollow(pub_key: Form<PublicKey>, _auth: Authenticated) -> Flash<Redirect> {
|
||||||
pub_key: Form<PublicKey>,
|
|
||||||
flash: Option<FlashMessage>,
|
|
||||||
_auth: Authenticated,
|
|
||||||
) -> Flash<Redirect> {
|
|
||||||
let public_key = &pub_key.key;
|
let public_key = &pub_key.key;
|
||||||
// perform the sbotcli unfollow action using &pub_key.0
|
// perform the sbotcli unfollow action using &pub_key.0
|
||||||
// if successful, redirect to profile page with provided public key and flash "success"
|
// if successful, redirect to profile page with provided public key and flash "success"
|
||||||
|
@ -157,11 +145,7 @@ pub fn unfollow(
|
||||||
|
|
||||||
/// Block a Scuttlebutt profile specified by the given public key. Redirects to the appropriate profile page with a flash message describing the outcome of the action (may be successful or unsuccessful).
|
/// Block a Scuttlebutt profile specified by the given public key. Redirects to the appropriate profile page with a flash message describing the outcome of the action (may be successful or unsuccessful).
|
||||||
#[post("/block", data = "<pub_key>")]
|
#[post("/block", data = "<pub_key>")]
|
||||||
pub fn block(
|
pub fn block(pub_key: Form<PublicKey>, _auth: Authenticated) -> Flash<Redirect> {
|
||||||
pub_key: Form<PublicKey>,
|
|
||||||
flash: Option<FlashMessage>,
|
|
||||||
_auth: Authenticated,
|
|
||||||
) -> Flash<Redirect> {
|
|
||||||
let public_key = &pub_key.key;
|
let public_key = &pub_key.key;
|
||||||
// perform the sbotcli block action using &pub_key.0
|
// perform the sbotcli block action using &pub_key.0
|
||||||
// if successful, redirect to profile page with provided public key and flash "success"
|
// if successful, redirect to profile page with provided public key and flash "success"
|
||||||
|
|
|
@ -3,26 +3,66 @@ use std::{
|
||||||
process::{Command, Output},
|
process::{Command, Output},
|
||||||
};
|
};
|
||||||
|
|
||||||
use log::info;
|
use log::{info, warn};
|
||||||
use peach_stats::sbot;
|
use peach_lib::sbot::{SbotConfig, SbotStatus};
|
||||||
use rocket::{
|
use rocket::{
|
||||||
get,
|
form::{Form, FromForm},
|
||||||
|
get, post,
|
||||||
request::FlashMessage,
|
request::FlashMessage,
|
||||||
response::{Flash, Redirect},
|
response::{Flash, Redirect},
|
||||||
|
serde::Deserialize,
|
||||||
};
|
};
|
||||||
use rocket_dyn_templates::{tera::Context, Template};
|
use rocket_dyn_templates::{tera::Context, Template};
|
||||||
|
|
||||||
use crate::routes::authentication::Authenticated;
|
use crate::routes::authentication::Authenticated;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, FromForm)]
|
||||||
|
pub struct SbotConfigForm {
|
||||||
|
/// Directory path for the log and indexes.
|
||||||
|
repo: String,
|
||||||
|
/// Directory path for writing debug output.
|
||||||
|
debugdir: String,
|
||||||
|
/// Secret-handshake app-key (aka. network key).
|
||||||
|
shscap: String,
|
||||||
|
/// HMAC hash used to sign messages.
|
||||||
|
hmac: String,
|
||||||
|
/// Replication hops (1: friends, 2: friends of friends).
|
||||||
|
hops: u8,
|
||||||
|
/// IP address to listen on.
|
||||||
|
lis_ip: String,
|
||||||
|
/// Port to listen on.
|
||||||
|
lis_port: String,
|
||||||
|
/// Address to listen on for WebSocket connections.
|
||||||
|
wslis: String,
|
||||||
|
/// Address to for metrics and pprof HTTP server.
|
||||||
|
debuglis: String,
|
||||||
|
/// Enable sending local UDP broadcasts.
|
||||||
|
localadv: bool,
|
||||||
|
/// Enable listening for UDP broadcasts and connecting.
|
||||||
|
localdiscov: bool,
|
||||||
|
/// Enable syncing by using epidemic-broadcast-trees (EBT).
|
||||||
|
enable_ebt: bool,
|
||||||
|
/// Bypass graph auth and fetch remote's feed (useful for pubs that are restoring their data
|
||||||
|
/// from peer; user beware - caveats about).
|
||||||
|
promisc: bool,
|
||||||
|
/// Disable the UNIX socket RPC interface.
|
||||||
|
nounixsock: bool,
|
||||||
|
/// Run the go-sbot on system start-up (systemd service enabled).
|
||||||
|
startup: bool,
|
||||||
|
/// Attempt to repair the filesystem before starting.
|
||||||
|
repair: bool,
|
||||||
|
}
|
||||||
|
|
||||||
// HELPERS AND ROUTES FOR /settings/scuttlebutt
|
// HELPERS AND ROUTES FOR /settings/scuttlebutt
|
||||||
|
|
||||||
/// Scuttlebutt settings menu.
|
/// Scuttlebutt settings menu.
|
||||||
#[get("/")]
|
#[get("/")]
|
||||||
pub fn ssb_settings_menu(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
|
pub fn ssb_settings_menu(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
|
||||||
|
// retrieve go-sbot systemd process status
|
||||||
|
let sbot_status = SbotStatus::read().ok();
|
||||||
|
|
||||||
let mut context = Context::new();
|
let mut context = Context::new();
|
||||||
// retrieve go-sbot systemd process stats
|
context.insert("sbot_status", &sbot_status);
|
||||||
let sbot_stats = sbot::sbot_stats().ok();
|
|
||||||
context.insert("sbot_stats", &sbot_stats);
|
|
||||||
context.insert("back", &Some("/settings".to_string()));
|
context.insert("back", &Some("/settings".to_string()));
|
||||||
context.insert("title", &Some("Scuttlebutt Settings".to_string()));
|
context.insert("title", &Some("Scuttlebutt Settings".to_string()));
|
||||||
|
|
||||||
|
@ -37,9 +77,18 @@ pub fn ssb_settings_menu(flash: Option<FlashMessage>, _auth: Authenticated) -> T
|
||||||
/// Sbot configuration page (includes form for updating configuration parameters).
|
/// Sbot configuration page (includes form for updating configuration parameters).
|
||||||
#[get("/configure")]
|
#[get("/configure")]
|
||||||
pub fn configure_sbot(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
|
pub fn configure_sbot(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
|
||||||
|
// retrieve go-sbot systemd process status
|
||||||
|
let sbot_status = SbotStatus::read().ok();
|
||||||
|
let run_on_startup = sbot_status.map(|status| status.boot_state);
|
||||||
|
|
||||||
|
// retrieve sbot config parameters
|
||||||
|
let sbot_config = SbotConfig::read().ok();
|
||||||
|
|
||||||
let mut context = Context::new();
|
let mut context = Context::new();
|
||||||
context.insert("back", &Some("/settings/scuttlebutt".to_string()));
|
context.insert("back", &Some("/settings/scuttlebutt".to_string()));
|
||||||
context.insert("title", &Some("Sbot Configuration".to_string()));
|
context.insert("title", &Some("Sbot Configuration".to_string()));
|
||||||
|
context.insert("sbot_config", &sbot_config);
|
||||||
|
context.insert("run_on_startup", &Some(run_on_startup));
|
||||||
|
|
||||||
if let Some(flash) = flash {
|
if let Some(flash) = flash {
|
||||||
context.insert("flash_name", &Some(flash.kind().to_string()));
|
context.insert("flash_name", &Some(flash.kind().to_string()));
|
||||||
|
@ -49,12 +98,111 @@ pub fn configure_sbot(flash: Option<FlashMessage>, _auth: Authenticated) -> Temp
|
||||||
Template::render("settings/scuttlebutt/configure_sbot", &context.into_json())
|
Template::render("settings/scuttlebutt/configure_sbot", &context.into_json())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: consider using `Contextual` here to collect all submitted form
|
||||||
|
// fields to re-render forms with submitted values on error
|
||||||
|
|
||||||
|
/// Receive the sbot configuration form data and save it to file.
|
||||||
|
#[post("/configure?<restart>", data = "<config>")]
|
||||||
|
pub fn configure_sbot_post(
|
||||||
|
restart: bool,
|
||||||
|
config: Form<SbotConfigForm>,
|
||||||
|
_auth: Authenticated,
|
||||||
|
) -> Flash<Redirect> {
|
||||||
|
// call `into_inner()` to take ownership of the `config` data
|
||||||
|
let owned_config = config.into_inner();
|
||||||
|
|
||||||
|
// concat the ip and port for listen address
|
||||||
|
let lis = format!("{}:{}", owned_config.lis_ip, owned_config.lis_port);
|
||||||
|
|
||||||
|
// instantiate `SbotConfig` from form data
|
||||||
|
let config = SbotConfig {
|
||||||
|
lis,
|
||||||
|
hops: owned_config.hops,
|
||||||
|
repo: owned_config.repo,
|
||||||
|
debugdir: owned_config.debugdir,
|
||||||
|
shscap: owned_config.shscap,
|
||||||
|
localadv: owned_config.localadv,
|
||||||
|
localdiscov: owned_config.localdiscov,
|
||||||
|
hmac: owned_config.hmac,
|
||||||
|
wslis: owned_config.wslis,
|
||||||
|
debuglis: owned_config.debuglis,
|
||||||
|
enable_ebt: owned_config.enable_ebt,
|
||||||
|
promisc: owned_config.promisc,
|
||||||
|
nounixsock: owned_config.nounixsock,
|
||||||
|
repair: owned_config.repair,
|
||||||
|
};
|
||||||
|
|
||||||
|
match owned_config.startup {
|
||||||
|
true => {
|
||||||
|
info!("Enabling go-sbot.service");
|
||||||
|
match systemctl_sbot_cmd("enable") {
|
||||||
|
Err(e) => warn!("Failed to enable go-sbot.service: {}", e),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false => {
|
||||||
|
info!("Disabling go-sbot.service");
|
||||||
|
match systemctl_sbot_cmd("disable") {
|
||||||
|
Err(e) => warn!("Failed to disable go-sbot.service: {}", e),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// write config to file
|
||||||
|
match SbotConfig::write(config) {
|
||||||
|
Ok(_) => {
|
||||||
|
// if `restart` query parameter is `true`, attempt sbot process (re)start
|
||||||
|
if restart {
|
||||||
|
restart_sbot_process(
|
||||||
|
// redirect url
|
||||||
|
"/settings/scuttlebutt/configure",
|
||||||
|
// success flash msg
|
||||||
|
"Updated configuration and restarted the sbot process",
|
||||||
|
// first failed flash msg
|
||||||
|
"Updated configuration but failed to start the sbot process",
|
||||||
|
// second failed flash msg
|
||||||
|
"Updated configuration but failed to stop the sbot process",
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Flash::success(
|
||||||
|
Redirect::to("/settings/scuttlebutt/configure"),
|
||||||
|
"Updated configuration",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => Flash::error(
|
||||||
|
Redirect::to("/settings/scuttlebutt/configure"),
|
||||||
|
format!("Failed to update configuration: {}", e),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set default configuration parameters for the go-sbot and save them to file.
|
||||||
|
#[get("/configure/default")]
|
||||||
|
pub fn configure_sbot_default(_auth: Authenticated) -> Flash<Redirect> {
|
||||||
|
let default_config = SbotConfig::default();
|
||||||
|
|
||||||
|
// write default config to file
|
||||||
|
match SbotConfig::write(default_config) {
|
||||||
|
Ok(_) => Flash::success(
|
||||||
|
Redirect::to("/settings/scuttlebutt/configure"),
|
||||||
|
"Restored default configuration",
|
||||||
|
),
|
||||||
|
Err(e) => Flash::error(
|
||||||
|
Redirect::to("/settings/scuttlebutt/configure"),
|
||||||
|
format!("Failed to restore default configuration: {}", e),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Attempt to start the go-sbot.service process.
|
/// Attempt to start the go-sbot.service process.
|
||||||
/// Redirect to the Scuttlebutt settings menu and communicate the outcome of
|
/// Redirect to the Scuttlebutt settings menu and communicate the outcome of
|
||||||
/// the attempt via a flash message.
|
/// the attempt via a flash message.
|
||||||
#[get("/start")]
|
#[get("/start")]
|
||||||
pub fn start_sbot(_auth: Authenticated) -> Flash<Redirect> {
|
pub fn start_sbot(_auth: Authenticated) -> Flash<Redirect> {
|
||||||
match start_sbot_cmd() {
|
info!("Starting go-sbot.service");
|
||||||
|
match systemctl_sbot_cmd("start") {
|
||||||
Ok(_) => Flash::success(
|
Ok(_) => Flash::success(
|
||||||
Redirect::to("/settings/scuttlebutt"),
|
Redirect::to("/settings/scuttlebutt"),
|
||||||
"Sbot process has been started",
|
"Sbot process has been started",
|
||||||
|
@ -71,7 +219,8 @@ pub fn start_sbot(_auth: Authenticated) -> Flash<Redirect> {
|
||||||
/// the attempt via a flash message.
|
/// the attempt via a flash message.
|
||||||
#[get("/stop")]
|
#[get("/stop")]
|
||||||
pub fn stop_sbot(_auth: Authenticated) -> Flash<Redirect> {
|
pub fn stop_sbot(_auth: Authenticated) -> Flash<Redirect> {
|
||||||
match stop_sbot_cmd() {
|
info!("Stopping go-sbot.service");
|
||||||
|
match systemctl_sbot_cmd("stop") {
|
||||||
Ok(_) => Flash::success(
|
Ok(_) => Flash::success(
|
||||||
Redirect::to("/settings/scuttlebutt"),
|
Redirect::to("/settings/scuttlebutt"),
|
||||||
"Sbot process has been stopped",
|
"Sbot process has been stopped",
|
||||||
|
@ -88,65 +237,43 @@ pub fn stop_sbot(_auth: Authenticated) -> Flash<Redirect> {
|
||||||
/// the attempt via a flash message.
|
/// the attempt via a flash message.
|
||||||
#[get("/restart")]
|
#[get("/restart")]
|
||||||
pub fn restart_sbot(_auth: Authenticated) -> Flash<Redirect> {
|
pub fn restart_sbot(_auth: Authenticated) -> Flash<Redirect> {
|
||||||
// try to stop the process
|
restart_sbot_process(
|
||||||
match stop_sbot_cmd() {
|
"/settings/scuttlebutt",
|
||||||
// if stop was successful, try to start the process
|
"Sbot process has been restarted",
|
||||||
Ok(_) => match start_sbot_cmd() {
|
"Failed to start the sbot process",
|
||||||
Ok(_) => Flash::success(
|
"Failed to stop the sbot process",
|
||||||
Redirect::to("/settings/scuttlebutt"),
|
)
|
||||||
"Sbot process has been restarted",
|
|
||||||
),
|
|
||||||
|
|
||||||
Err(_) => Flash::error(
|
|
||||||
Redirect::to("/settings/scuttlebutt"),
|
|
||||||
"Failed to start the sbot process",
|
|
||||||
),
|
|
||||||
},
|
|
||||||
Err(_) => Flash::error(
|
|
||||||
Redirect::to("/settings/scuttlebutt"),
|
|
||||||
"Failed to stop the sbot process",
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HELPER FUNCTIONS
|
// HELPER FUNCTIONS
|
||||||
|
|
||||||
/// Executes a systemctl disable command for the go-sbot.service process.
|
/// Executes a systemctl command for the go-sbot.service process.
|
||||||
pub fn disable_sbot_cmd() -> io::Result<Output> {
|
pub fn systemctl_sbot_cmd(cmd: &str) -> io::Result<Output> {
|
||||||
info!("Disabling go-sbot.service");
|
|
||||||
Command::new("systemctl")
|
Command::new("systemctl")
|
||||||
.arg("--user")
|
.arg("--user")
|
||||||
.arg("disable")
|
.arg(cmd)
|
||||||
.arg("go-sbot.service")
|
.arg("go-sbot.service")
|
||||||
.output()
|
.output()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes a systemctl enable command for the go-sbot.service process.
|
/// Executes a systemctl stop command followed by start command.
|
||||||
pub fn enable_sbot_cmd() -> io::Result<Output> {
|
/// Returns a redirect with a flash message stating the output of the restart attempt.
|
||||||
info!("Enabling go-sbot.service");
|
fn restart_sbot_process(
|
||||||
Command::new("systemctl")
|
redirect_url: &str,
|
||||||
.arg("--user")
|
success_msg: &str,
|
||||||
.arg("enable")
|
start_failed_msg: &str,
|
||||||
.arg("go-sbot.service")
|
stop_failed_msg: &str,
|
||||||
.output()
|
) -> Flash<Redirect> {
|
||||||
}
|
let url = redirect_url.to_string();
|
||||||
|
|
||||||
/// Executes a systemctl start command for the go-sbot.service process.
|
info!("Restarting go-sbot.service");
|
||||||
pub fn start_sbot_cmd() -> io::Result<Output> {
|
match systemctl_sbot_cmd("stop") {
|
||||||
info!("Starting go-sbot.service");
|
// if stop was successful, try to start the process
|
||||||
Command::new("systemctl")
|
Ok(_) => match systemctl_sbot_cmd("start") {
|
||||||
.arg("--user")
|
Ok(_) => Flash::success(Redirect::to(url), success_msg),
|
||||||
.arg("start")
|
|
||||||
.arg("go-sbot.service")
|
|
||||||
.output()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Executes a systemctl stop command for the go-sbot.service process.
|
Err(e) => Flash::error(Redirect::to(url), format!("{}: {}", start_failed_msg, e)),
|
||||||
pub fn stop_sbot_cmd() -> io::Result<Output> {
|
},
|
||||||
info!("Stopping go-sbot.service");
|
Err(e) => Flash::error(Redirect::to(url), format!("{}: {}", stop_failed_msg, e)),
|
||||||
Command::new("systemctl")
|
}
|
||||||
.arg("--user")
|
|
||||||
.arg("stop")
|
|
||||||
.arg("go-sbot.service")
|
|
||||||
.output()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use peach_lib::{
|
use peach_lib::{
|
||||||
config_manager::load_peach_config, dyndns_client, network_client, oled_client, sbot_client,
|
config_manager::load_peach_config, dyndns_client, network_client, oled_client, sbot::SbotStatus,
|
||||||
};
|
};
|
||||||
use peach_stats::{
|
use peach_stats::{
|
||||||
stats,
|
stats,
|
||||||
|
@ -117,10 +117,11 @@ impl StatusContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
// test if go-sbot is running
|
// test if go-sbot is running
|
||||||
let sbot_is_online_result = sbot_client::is_sbot_online();
|
let sbot_status = SbotStatus::read();
|
||||||
let sbot_is_online: bool = match sbot_is_online_result {
|
let sbot_is_online: bool = match sbot_status {
|
||||||
Ok(val) => val,
|
// return true if state is active
|
||||||
Err(_err) => false,
|
Ok(status) => matches!(status.state == Some("active".to_string()), true),
|
||||||
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
StatusContext {
|
StatusContext {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use peach_stats::sbot;
|
use peach_lib::sbot::{SbotConfig, SbotStatus};
|
||||||
use rocket::{get, State};
|
use rocket::{get, State};
|
||||||
use rocket_dyn_templates::{tera::Context, Template};
|
use rocket_dyn_templates::{tera::Context, Template};
|
||||||
|
|
||||||
|
@ -9,10 +9,14 @@ use crate::RocketConfig;
|
||||||
|
|
||||||
#[get("/scuttlebutt")]
|
#[get("/scuttlebutt")]
|
||||||
pub fn scuttlebutt_status(_auth: Authenticated, config: &State<RocketConfig>) -> Template {
|
pub fn scuttlebutt_status(_auth: Authenticated, config: &State<RocketConfig>) -> Template {
|
||||||
|
// retrieve go-sbot systemd process status
|
||||||
|
let sbot_status = SbotStatus::read().ok();
|
||||||
|
// retrieve go-sbot configuration parameters
|
||||||
|
let sbot_config = SbotConfig::read().ok();
|
||||||
|
|
||||||
let mut context = Context::new();
|
let mut context = Context::new();
|
||||||
// retrieve go-sbot systemd process stats
|
context.insert("sbot_status", &sbot_status);
|
||||||
let sbot_stats = sbot::sbot_stats().ok();
|
context.insert("sbot_config", &sbot_config);
|
||||||
context.insert("sbot_stats", &sbot_stats);
|
|
||||||
context.insert("flash_name", &None::<()>);
|
context.insert("flash_name", &None::<()>);
|
||||||
context.insert("flash_msg", &None::<()>);
|
context.insert("flash_msg", &None::<()>);
|
||||||
context.insert("title", &Some("Scuttlebutt Status"));
|
context.insert("title", &Some("Scuttlebutt Status"));
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
* - HTML
|
* - HTML
|
||||||
* - FLASH MESSAGE
|
* - FLASH MESSAGE
|
||||||
* - FONTS
|
* - FONTS
|
||||||
|
* - FORMS
|
||||||
* - ICONS
|
* - ICONS
|
||||||
* - INPUTS
|
* - INPUTS
|
||||||
* - LABELS
|
* - LABELS
|
||||||
|
@ -596,6 +597,20 @@ html {
|
||||||
color: var(--danger);
|
color: var(--danger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FORMS
|
||||||
|
*/
|
||||||
|
|
||||||
|
form {
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (min-width: 600px) {
|
||||||
|
form {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ICONS
|
* ICONS
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
</a>
|
</a>
|
||||||
<!-- middle -->
|
<!-- middle -->
|
||||||
<a class="middle">
|
<a class="middle">
|
||||||
<div class="circle circle-large {% if sbot_stats.state == "active" %}circle-success{% else %}circle-error{% endif %}"></div>
|
<div class="circle circle-large {% if sbot_status.state == "active" %}circle-success{% else %}circle-error{% endif %}"></div>
|
||||||
</a>
|
</a>
|
||||||
<!-- bottom-left -->
|
<!-- bottom-left -->
|
||||||
<!-- SYSTEM STATUS LINK AND ICON -->
|
<!-- SYSTEM STATUS LINK AND ICON -->
|
||||||
|
|
|
@ -2,21 +2,19 @@
|
||||||
{%- block card %}
|
{%- block card %}
|
||||||
<!-- CHANGE PASSWORD FORM -->
|
<!-- CHANGE PASSWORD FORM -->
|
||||||
<div class="card center">
|
<div class="card center">
|
||||||
<div class="form-container">
|
<form id="changePassword" action="/settings/admin/change_password" method="post">
|
||||||
<form id="changePassword" action="/settings/admin/change_password" method="post">
|
<!-- input for current password -->
|
||||||
<!-- input for current password -->
|
<input id="currentPassword" class="center input" name="current_password" type="password" placeholder="Current password" title="Current password" autofocus>
|
||||||
<input id="currentPassword" class="center input" name="current_password" type="password" placeholder="Current password" title="Current password" autofocus>
|
<!-- input for new password -->
|
||||||
<!-- input for new password -->
|
<input id="newPassword" class="center input" name="new_password1" type="password" placeholder="New password" title="New password">
|
||||||
<input id="newPassword" class="center input" name="new_password1" type="password" placeholder="New password" title="New password">
|
<!-- input for duplicate new password -->
|
||||||
<!-- input for duplicate new password -->
|
<input id="newPasswordDuplicate" class="center input" name="new_password2" type="password" placeholder="Re-enter new password" title="New password duplicate">
|
||||||
<input id="newPasswordDuplicate" class="center input" name="new_password2" type="password" placeholder="Re-enter new password" title="New password duplicate">
|
<div id="buttonDiv">
|
||||||
<div id="buttonDiv">
|
<input id="savePassword" class="button button-primary center" title="Add" type="submit" value="Save">
|
||||||
<input id="savePassword" class="button button-primary center" title="Add" type="submit" value="Save">
|
<a class="button button-secondary center" href="/settings/admin" title="Cancel">Cancel</a>
|
||||||
<a class="button button-secondary center" href="/settings/admin" title="Cancel">Cancel</a>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
</form>
|
<!-- FLASH MESSAGE -->
|
||||||
<!-- FLASH MESSAGE -->
|
{% include "snippets/flash_message" %}
|
||||||
{% include "snippets/flash_message" %}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{%- endblock card -%}
|
{%- endblock card -%}
|
||||||
|
|
|
@ -1,58 +1,85 @@
|
||||||
{%- extends "nav" -%}
|
{%- extends "nav" -%}
|
||||||
{%- block card %}
|
{%- block card %}
|
||||||
|
{# ASSIGN VARIABLES #}
|
||||||
|
{# ---------------- #}
|
||||||
|
{%- if sbot_config.hops -%}
|
||||||
|
{% set hops = sbot_config.hops -%}
|
||||||
|
{%- else -%}
|
||||||
|
{% set hops = "X" -%}
|
||||||
|
{%- endif -%}
|
||||||
|
{%- if sbot_config.lis -%}
|
||||||
|
{%- set listen_addr = sbot_config.lis | split(pat=":") -%}
|
||||||
|
{%- else -%}
|
||||||
|
{%- set listen_addr = ["", ""] -%}
|
||||||
|
{%- endif -%}
|
||||||
<!-- SBOT CONFIGURATION FORM -->
|
<!-- SBOT CONFIGURATION FORM -->
|
||||||
<div class="card center">
|
<div class="card center">
|
||||||
<form>
|
<form id="sbotConfig" class="center" action="/settings/scuttlebutt/configure" method="post">
|
||||||
<div class="center" style="display: flex; flex-direction: column; width: 80%;" title="Number of hops to replicate">
|
<div class="center" style="display: flex; flex-direction: column;" title="Number of hops to replicate">
|
||||||
<label for="hops" class="label-small">HOPS</label>
|
<label for="hops" class="label-small">HOPS</label>
|
||||||
<div id="hops" style="display: flex; justify-content: space-evenly;">
|
<div id="hops" style="display: flex; justify-content: space-evenly;">
|
||||||
<input type="radio" id="hops_0" name="hops" value="0">
|
<input type="radio" id="hops_0" name="hops" value="0"{% if hops == 0 %} checked{% endif %}>
|
||||||
<label for="hops_0">0</label>
|
<label for="hops_0">0</label>
|
||||||
<input type="radio" id="hops_1" name="hops" value="1">
|
<input type="radio" id="hops_1" name="hops" value="1"{% if hops == 1 %} checked{% endif %}>
|
||||||
<label for="hops_1">1</label>
|
<label for="hops_1">1</label>
|
||||||
<input type="radio" id="hops_2" name="hops" value="2">
|
<input type="radio" id="hops_2" name="hops" value="2"{% if hops == 2 %} checked{% endif %}>
|
||||||
<label for="hops_2">2</label>
|
<label for="hops_2">2</label>
|
||||||
<input type="radio" id="hops_3" name="hops" value="3">
|
<input type="radio" id="hops_3" name="hops" value="3"{% if hops == 3 %} checked{% endif %}>
|
||||||
<label for="hops_3">3</label>
|
<label for="hops_3">3</label>
|
||||||
<input type="radio" id="hops_4" name="hops" value="4">
|
<input type="radio" id="hops_4" name="hops" value="4"{% if hops == 4 %} checked{% endif %}>
|
||||||
<label for="hops_4">4</label><br>
|
<label for="hops_4">4</label><br>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<div class="center" style="display: flex; justify-content: space-between; width: 80%;">
|
<div class="center" style="display: flex; justify-content: space-between;">
|
||||||
<div style="display: flex; flex-direction: column; width: 60%;" title="IP address on which the sbot runs">
|
<div style="display: flex; flex-direction: column; width: 60%;" title="IP address on which the sbot runs">
|
||||||
<label for="ip" class="label-small">IP ADDRESS</label>
|
<label for="ip" class="label-small">IP ADDRESS</label>
|
||||||
<input type="text" id="ip" name="ip">
|
<input type="text" id="ip" name="lis_ip" value="{{ listen_addr.0 }}">
|
||||||
</div>
|
</div>
|
||||||
<div style="display: flex; flex-direction: column; width: 20%;" title="Port on which the sbot runs">
|
<div style="display: flex; flex-direction: column; width: 20%;" title="Port on which the sbot runs">
|
||||||
<label for="port" class="label-small">PORT</label>
|
<label for="port" class="label-small">PORT</label>
|
||||||
<input type="text" id="port" name="port">
|
<input type="text" id="port" name="lis_port" value="{{ listen_addr.1 }}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<div class="center" style="display: flex; flex-direction: column; width: 80%;" title="Network key (aka 'caps key') to define the Scuttleverse in which the sbot operates in">
|
<div class="center" style="display: flex; flex-direction: column;" title="Network key (aka 'caps key') to define the Scuttleverse in which the sbot operates in">
|
||||||
<label for="network_key" class="label-small">NETWORK KEY</label>
|
<label for="network_key" class="label-small">NETWORK KEY</label>
|
||||||
<input type="text" id="network_key" name="network_key">
|
<input type="text" id="network_key" name="shscap" value="{{ sbot_config.shscap }}">
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<div class="center" style="display: flex; flex-direction: column; width: 80%;" title="Directory in which the sbot database is saved">
|
<div class="center" style="display: flex; flex-direction: column;" title="Directory in which the sbot database is saved">
|
||||||
<label for="database_dir" class="label-small">DATABASE DIRECTORY</label>
|
<label for="database_dir" class="label-small">DATABASE DIRECTORY</label>
|
||||||
<input type="text" id="database_dir" name="database_dir">
|
<input type="text" id="database_dir" name="repo" value="{{ sbot_config.repo }}">
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<div class="center" style="width: 80%;" title="Broadcast the IP and port of this sbot instance so that local peers can discovery it and attempt to connect">
|
<div class="center">
|
||||||
<input type="checkbox" id="lanBroadcast" name="lan_broadcast">
|
<input type="checkbox" id="lanBroadcast" name="localadv"{% if sbot_config.localadv == true %} checked{% endif %}>
|
||||||
<label for="lanBroadcast">Enable LAN Broadcasting</label><br>
|
<label for="lanBroadcast" title="Broadcast the IP and port of this sbot instance so that local peers can discovery it and attempt to connect">Enable LAN Broadcasting</label><br>
|
||||||
<br>
|
<br>
|
||||||
<input type="checkbox" id="lanDiscovery" name="lan_discovery" title="Listen for the presence of local peers and attempt to connect if found">
|
<input type="checkbox" id="lanDiscovery" name="localdiscov"{% if sbot_config.localdiscov == true %} checked{% endif %}>
|
||||||
<label for="lanDiscovery">Enable LAN Discovery</label><br>
|
<label for="lanDiscovery" title="Listen for the presence of local peers and attempt to connect if found">Enable LAN Discovery</label><br>
|
||||||
<br>
|
<br>
|
||||||
<input type="checkbox" id="startup" name="startup" title="Define whether the pub runs automatically on system startup">
|
<input type="checkbox" id="startup" name="startup"{% if run_on_startup == "enabled" %} checked{% endif %}>
|
||||||
<label for="startup">Run pub on system startup</label><br>
|
<label for="startup" title="Run the pub automatically on system startup">Run pub on system startup</label><br>
|
||||||
|
<br>
|
||||||
|
<input type="checkbox" id="repair" name="repair"{% if sbot_config.repair == true %} checked{% endif %}>
|
||||||
|
<label for="repair" title="Attempt to repair the filesystem before starting the pub">Attempt filesystem repair when pub starts</label><br>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<input class="button button-primary center" type="button" value="Save">
|
<!-- hidden input elements for all other config variables -->
|
||||||
<input class="button button-warning center" type="button" value="Restore Defaults">
|
<input type="hidden" id="debugdir" name="debugdir" value="{{ sbot_config.debugdir }}">
|
||||||
|
<input type="hidden" id="hmac" name="hmac" value="{{ sbot_config.hmac }}">
|
||||||
|
<input type="hidden" id="wslis" name="wslis" value="{{ sbot_config.wslis }}">
|
||||||
|
<input type="hidden" id="debuglis" name="debuglis" value="{{ sbot_config.debuglis }}">
|
||||||
|
<input type="hidden" id="enable_ebt" name="enable_ebt" value="{{ sbot_config.enable_ebt }}">
|
||||||
|
<input type="hidden" id="promisc" name="promisc" value="{{ sbot_config.promisc }}">
|
||||||
|
<input type="hidden" id="nounixsock" name="nounixsock" value="{{ sbot_config.nounixsock }}">
|
||||||
|
<!-- BUTTONS -->
|
||||||
|
<input id="saveConfig" class="button button-primary center" 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">
|
||||||
|
<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</a>
|
||||||
</form>
|
</form>
|
||||||
|
<!-- FLASH MESSAGE -->
|
||||||
|
{% include "snippets/flash_message" %}
|
||||||
</div>
|
</div>
|
||||||
{%- endblock card -%}
|
{%- endblock card -%}
|
||||||
|
|
|
@ -5,14 +5,13 @@
|
||||||
<!-- BUTTONS -->
|
<!-- BUTTONS -->
|
||||||
<div id="settingsButtons">
|
<div id="settingsButtons">
|
||||||
<a id="configureSbot" class="button button-primary center" href="/settings/scuttlebutt/configure" title="Configure Sbot">Configure Sbot</a>
|
<a id="configureSbot" class="button button-primary center" href="/settings/scuttlebutt/configure" title="Configure Sbot">Configure Sbot</a>
|
||||||
{% if sbot_stats.state == "active" %}
|
{% if sbot_status.state == "active" %}
|
||||||
<a id="stop" class="button button-primary center" href="/settings/scuttlebutt/stop" title="Stop Sbot">Stop Sbot</a>
|
<a id="stop" class="button button-primary center" href="/settings/scuttlebutt/stop" title="Stop Sbot">Stop Sbot</a>
|
||||||
<a id="restart" class="button button-primary center" href="/settings/scuttlebutt/restart" title="Restart Sbot">Restart Sbot</a>
|
<a id="restart" class="button button-primary center" href="/settings/scuttlebutt/restart" title="Restart Sbot">Restart Sbot</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a id="start" class="button button-primary center" href="/settings/scuttlebutt/start" title="Start Sbot">Start Sbot</a>
|
<a id="start" class="button button-primary center" href="/settings/scuttlebutt/start" title="Start Sbot">Start Sbot</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a id="checkFilesystem" class="button button-primary center" href="/settings/scuttlebutt/check_fs" title="Check Filesystem">Check Filesystem</a>
|
<a id="checkFilesystem" class="button button-primary center" href="/settings/scuttlebutt/check_fs" title="Check Filesystem">Check Filesystem</a>
|
||||||
<a id="repairFilesystem" class="button button-primary center" href="/settings/scuttlebutt/repair" title="Repair Filesystem">Repair Filesystem</a>
|
|
||||||
<a id="removeFeeds" class="button button-primary center" href="/settings/scuttlebutt/remove_feeds" title="Remove Blocked Feeds">Remove Blocked Feeds</a>
|
<a id="removeFeeds" class="button button-primary center" href="/settings/scuttlebutt/remove_feeds" title="Remove Blocked Feeds">Remove Blocked Feeds</a>
|
||||||
</div>
|
</div>
|
||||||
<!-- FLASH MESSAGE -->
|
<!-- FLASH MESSAGE -->
|
||||||
|
|
|
@ -2,15 +2,15 @@
|
||||||
{%- block card %}
|
{%- block card %}
|
||||||
{# ASSIGN VARIABLES #}
|
{# ASSIGN VARIABLES #}
|
||||||
{# ---------------- #}
|
{# ---------------- #}
|
||||||
{%- if sbot_stats.memory -%}
|
{%- if sbot_status.memory -%}
|
||||||
{% set mem = sbot_stats.memory / 1024 / 1024 | round -%}
|
{% set mem = sbot_status.memory / 1024 / 1024 | round -%}
|
||||||
{%- else -%}
|
{%- else -%}
|
||||||
{% set mem = "X" -%}
|
{% set mem = "X" -%}
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
<!-- SCUTTLEBUTT STATUS -->
|
<!-- SCUTTLEBUTT STATUS -->
|
||||||
<div class="card center">
|
<div class="card center">
|
||||||
<!-- SBOT INFO BOX -->
|
<!-- SBOT INFO BOX -->
|
||||||
<div class="capsule capsule-container {% if sbot_stats.state == "active" %}success-border{% else %}warning-border{% endif %}">
|
<div class="capsule capsule-container {% if sbot_status.state == "active" %}success-border{% else %}warning-border{% endif %}">
|
||||||
<!-- SBOT STATUS GRID -->
|
<!-- SBOT STATUS GRID -->
|
||||||
<div class="two-grid" title="go-sbot process state">
|
<div class="two-grid" title="go-sbot process state">
|
||||||
<!-- top-right config icon -->
|
<!-- top-right config icon -->
|
||||||
|
@ -20,25 +20,25 @@
|
||||||
<!-- left column -->
|
<!-- left column -->
|
||||||
<!-- go-sbot state icon with label -->
|
<!-- go-sbot state icon with label -->
|
||||||
<div class="grid-column-1">
|
<div class="grid-column-1">
|
||||||
<img id="sbotStateIcon" class="center icon {% if sbot_stats.state == "inactive" %}icon-inactive{% endif %}" src="/icons/hermies.svg" alt="Hermies">
|
<img id="sbotStateIcon" class="center icon {% if sbot_status.state == "inactive" %}icon-inactive{% endif %}" src="/icons/hermies.svg" alt="Hermies">
|
||||||
<label id="sbotStateLabel" for="sbotStateIcon" class="center label-small font-gray" style="margin-top: 0.5rem;" title="Sbot state">{{ sbot_stats.state | upper }}</label>
|
<label id="sbotStateLabel" for="sbotStateIcon" class="center label-small font-gray" style="margin-top: 0.5rem;" title="Sbot state">{{ sbot_status.state | upper }}</label>
|
||||||
</div>
|
</div>
|
||||||
<!-- right column -->
|
<!-- right column -->
|
||||||
<!-- go-sbot version and uptime / downtime with labels -->
|
<!-- go-sbot version and uptime / downtime with labels -->
|
||||||
<div class="grid-column-2">
|
<div class="grid-column-2">
|
||||||
<label class="label-small font-gray" for="sbotVersion" title="go-sbot version">VERSION</label>
|
<label class="label-small font-gray" for="sbotVersion" title="go-sbot version">VERSION</label>
|
||||||
<p id="sbotVersion" class="card-text" title="Version">1.1.0-alpha</p>
|
<p id="sbotVersion" class="card-text" title="Version">1.1.0-alpha</p>
|
||||||
{% if sbot_stats.state == "active" %}
|
{% if sbot_status.state == "active" %}
|
||||||
<label class="label-small font-gray" for="sbotUptime" title="go-sbot uptime" style="margin-top: 0.5rem;">UPTIME</label>
|
<label class="label-small font-gray" for="sbotUptime" title="go-sbot uptime" style="margin-top: 0.5rem;">UPTIME</label>
|
||||||
<p id="sbotUptime" class="card-text" title="Uptime">{{ sbot_stats.uptime }}</p>
|
<p id="sbotUptime" class="card-text" title="Uptime">{{ sbot_status.uptime }}</p>
|
||||||
{# render downtime element if downtime is `Some(time)` #}
|
{# render downtime element if downtime is `Some(time)` #}
|
||||||
{# downtime will be `None` if service is stopped and disabled #}
|
{# downtime will be `None` if service is stopped and disabled #}
|
||||||
{%- elif sbot_stats.downtime -%}
|
{%- elif sbot_status.downtime -%}
|
||||||
<label class="label-small font-gray" for="sbotDowntime" title="go-sbot downtime" style="margin-top: 0.5rem;">DOWNTIME</label>
|
<label class="label-small font-gray" for="sbotDowntime" title="go-sbot downtime" style="margin-top: 0.5rem;">DOWNTIME</label>
|
||||||
<p id="sbotDowntime" class="card-text" title="Downtime">{{ sbot_stats.downtime }}</p>
|
<p id="sbotDowntime" class="card-text" title="Downtime">{{ sbot_status.downtime }}</p>
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
<label class="label-small font-gray" for="sbotBootState" title="go-sbot boot state" style="margin-top: 0.5rem;">RUN ON STARTUP</label>
|
<label class="label-small font-gray" for="sbotBootState" title="go-sbot boot state" style="margin-top: 0.5rem;">RUN ON STARTUP</label>
|
||||||
{% if sbot_stats.boot_state == "enabled" %}
|
{% if sbot_status.boot_state == "enabled" %}
|
||||||
<p id="runOnStartup" class="card-text" title="Enabled">Enabled</p>
|
<p id="runOnStartup" class="card-text" title="Enabled">Enabled</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p id="runOnStartup" class="card-text" title="Disabled">Disabled</p>
|
<p id="runOnStartup" class="card-text" title="Disabled">Disabled</p>
|
||||||
|
@ -80,7 +80,7 @@
|
||||||
<div class="stack">
|
<div class="stack">
|
||||||
<img class="icon" title="Hops" src="/icons/orbits.png">
|
<img class="icon" title="Hops" src="/icons/orbits.png">
|
||||||
<div class="flex-grid" style="padding-top: 0.5rem;">
|
<div class="flex-grid" style="padding-top: 0.5rem;">
|
||||||
<label class="label-medium" style="padding-right: 3px;" title="Replication hops">2</label>
|
<label class="label-medium" style="padding-right: 3px;" title="Replication hops">{{ sbot_config.hops }}</label>
|
||||||
</div>
|
</div>
|
||||||
<label class="label-small font-gray">HOPS</label>
|
<label class="label-small font-gray">HOPS</label>
|
||||||
</div>
|
</div>
|
||||||
|
@ -93,10 +93,10 @@
|
||||||
<label class="label-small font-gray">BLOBSTORE</label>
|
<label class="label-small font-gray">BLOBSTORE</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="stack">
|
<div class="stack">
|
||||||
<img class="icon{% if not sbot_stats.memory %} icon-inactive{% endif %}" title="Memory" src="/icons/ram.png">
|
<img class="icon{% if not sbot_status.memory %} icon-inactive{% endif %}" title="Memory" src="/icons/ram.png">
|
||||||
<div class="flex-grid" style="padding-top: 0.5rem;">
|
<div class="flex-grid" style="padding-top: 0.5rem;">
|
||||||
<label class="label-medium{% if sbot_stats.state == "inactive" %} font-gray{% endif %}" style="padding-right: 3px;" title="Memory usage of the go-sbot process in MB">{{ mem }}</label>
|
<label class="label-medium{% if sbot_status.state == "inactive" %} font-gray{% endif %}" style="padding-right: 3px;" title="Memory usage of the go-sbot process in MB">{{ mem }}</label>
|
||||||
<label class="label-small {% if sbot_stats.state == "inactive" %}font-gray{% else %}font-near-black{% endif %}">MB</label>
|
<label class="label-small {% if sbot_status.state == "inactive" %}font-gray{% else %}font-near-black{% endif %}">MB</label>
|
||||||
</div>
|
</div>
|
||||||
<label class="label-small font-gray">MEMORY</label>
|
<label class="label-small font-gray">MEMORY</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue