Skip to content

Commit

Permalink
refactor: v2.0, cmd refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
fengyc committed Dec 8, 2024
1 parent 6b76ec2 commit bcdf513
Show file tree
Hide file tree
Showing 13 changed files with 953 additions and 559 deletions.
485 changes: 432 additions & 53 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ Default ports:
ws 0.0.0.0:8422 # standalone websocket api
http 0.0.0.0:8421 # web UI and websocket (/ws)

To get the full command list, please send a `help xx` request.

| Command | Description | Response/Usage |
| :- | :-: | :-: |
| get firmware_version | firmware version | firmware_version: [string] |
Expand Down
3 changes: 2 additions & 1 deletion pisugar-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pisugar-core"
version = "1.7.8"
version = "2.0.0"
authors = ["PiSugare"]
edition = "2018"
license = "gplv3"
Expand All @@ -17,3 +17,4 @@ serde_json = "1.0"
hyper = {version ="0.14.10", features = ["full"]}
anyhow = "1"
rsntp = "4.0.0"
clap = "4.5.23"
1 change: 0 additions & 1 deletion pisugar-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use std::fmt;
use std::fmt::{Display, Formatter};

use std::io;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::{Command, ExitStatus};
use std::thread;
Expand Down
28 changes: 23 additions & 5 deletions pisugar-core/src/model.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use std::convert::TryFrom;
use std::fmt;
use std::str::FromStr;

use clap::builder::PossibleValue;
use clap::ValueEnum;

use crate::ip5312::IP5312Battery;
use crate::pisugar3::{PiSugar3Battery, PiSugar3RTC, I2C_ADDR_P3};
Expand Down Expand Up @@ -88,11 +91,11 @@ impl fmt::Display for Model {
}
}

impl TryFrom<&str> for Model {
type Error = ();
impl FromStr for Model {
type Err = ();

fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
match value {
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
match s {
PISUGAR_2_4LEDS => Ok(Model::PiSugar_2_4LEDs),
PISUGAR_2_2LEDS => Ok(Model::PiSugar_2_2LEDs),
PISUGAR_2_PRO => Ok(Model::PiSugar_2_Pro),
Expand All @@ -101,3 +104,18 @@ impl TryFrom<&str> for Model {
}
}
}

impl ValueEnum for Model {
fn value_variants<'a>() -> &'a [Self] {
&[Model::PiSugar_2_4LEDs, Model::PiSugar_2_2LEDs, Model::PiSugar_2_Pro, Model::PiSugar_3]
}

fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
Some(match self {
Model::PiSugar_2_4LEDs => PossibleValue::new(PISUGAR_2_4LEDS),
Model::PiSugar_2_2LEDs => PossibleValue::new(PISUGAR_2_2LEDS),
Model::PiSugar_2_Pro => PossibleValue::new(PISUGAR_2_PRO),
Model::PiSugar_3 => PossibleValue::new(PISUGAR_3),
})
}
}
2 changes: 1 addition & 1 deletion pisugar-poweroff/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pisugar-poweroff"
version = "1.7.8"
version = "2.0.0"
authors = ["PiSugar"]
edition = "2018"
description = "PiSugar Poweroff"
Expand Down
3 changes: 1 addition & 2 deletions pisugar-poweroff/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use std::time::Duration;
use clap::{Arg, Command};
use env_logger::Env;
use pisugar_core::{Model, PiSugarConfig, PiSugarCore, Result};
use std::convert::TryInto;

fn shutdown(config: PiSugarConfig, model: Model, retries: u32) -> Result<()> {
for _ in 0..retries {
Expand Down Expand Up @@ -79,7 +78,7 @@ fn main() {
)
.get_matches();

let model: Model = matches.value_of("model").unwrap().try_into().unwrap();
let model: Model = matches.value_of("model").unwrap().parse().unwrap();
let log_level = matches.value_of("log").unwrap();
let countdown: u64 = matches.value_of("countdown").unwrap().parse().unwrap();
let retries: u32 = matches.value_of("retries").unwrap().parse().unwrap();
Expand Down
2 changes: 1 addition & 1 deletion pisugar-programmer/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pisugar-programmer"
version = "1.7.8"
version = "2.0.0"
authors = ["PiSugar"]
edition = "2018"
description = "PiSugar Firmware Programmer (for PiSugar 3)"
Expand Down
9 changes: 7 additions & 2 deletions pisugar-server/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pisugar-server"
version = "1.7.8"
version = "2.0.0"
authors = ["PiSugar"]
edition = "2018"
description = "PiSugar Power Manager"
Expand All @@ -16,7 +16,7 @@ syslog = "6"
rand = "0.8"
base64 = "0.13"
libc = "0.2"
clap = "3"
clap = { version = "4", features = ["derive"] }
bytes = "1"
ctrlc = "3.1.4"
lazy_static = "1.4"
Expand All @@ -34,10 +34,15 @@ hyper-tungstenite = "0.8"
websocket-codec = "0.5"
digest_auth = "0.3.0"
pisugar-core = { path = "../pisugar-core" }
shlex = "1.3.0"
enum-variants-strings = "0.3.0"

[[bin]]
name = "pisugar-server"

[dev-dependencies]
rstest = "0.23.0"

[package.metadata.deb]
license-file = ["../LICENSE", "0"]
copyright = "2020, PiSugar team"
Expand Down
207 changes: 207 additions & 0 deletions pisugar-server/src/cmds.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
use std::str::FromStr;

use anyhow::anyhow;
use anyhow::Error as AnyError;
use chrono::{DateTime, FixedOffset};
use clap::{builder::PossibleValue, ArgAction, Args, Parser, Subcommand};
use enum_variants_strings::EnumVariantsStrings;

#[derive(Debug, Parser, PartialEq)]
#[command(multicall = true)]
#[clap(rename_all = "snake_case")]
pub enum Cmds {
#[command(subcommand)]
Get(GetCmds),

SetBatteryChargingRange {
#[arg(value_delimiter = ',')]
range: Vec<f32>,
},

SetBatteryInputProtect(BoolArg),

SetBatteryOutput(BoolArg),

SetFullChargeDuration {
seconds: u64,
},

SetAllowCharging(BoolArg),

RtcClearFlag,

RtcPi2rtc,

RtcRtc2pi,

RtcWeb,

RtcAlarmSet {
datetime: DateTime<FixedOffset>,
weekdays: u8,
},

RtcAlarmDisable,

RtcAdjustPpm {
ppm: f64,
},

SetSafeShutdownLevel {
level: f64,
},

SetSafeShutdownDelay {
delay: f64,
},

RtcTestWake,

SetButtonEnable {
mode: ButtonMode,
enable: bool,
},

SetButtonShell {
mode: ButtonMode,
shell: Vec<String>,
},

SetAutoPowerOn(BoolArg),

SetAuth {
username: Option<String>,
password: Option<String>,
},

ForceShutdown,

SetAntiMistouch(BoolArg),

SetSoftPoweroff(BoolArg),

SetSoftPoweroffShell {
shell: Vec<String>,
},

SetInputProtect(BoolArg),
}

impl FromStr for Cmds {
type Err = AnyError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut args = shlex::split(s).ok_or(anyhow!("Invalid args"))?;
if args.as_slice()[1..].iter().any(|a| a.starts_with("-")) {
args.insert(1, "--".to_string());
}
Ok(Self::try_parse_from(args)?)
}
}

#[derive(Debug, Subcommand, PartialEq, Eq)]
#[clap(rename_all = "snake_case")]
pub enum GetCmds {
Version,
Model,
FirmwareVersion,
Battery,
BatteryI,
BatteryV,
BatteryLedAmount,
BatteryPowerPlugged,
BatteryAllowCharging,
BatteryChargingRange,
BatteryCharging,
BatteryInputProtectEnabled,
BatteryOutputEnabled,
FullChargeDuration,
SystemTime,
RtcTime,
RtcTimeList,
RtcAlarmFlag,
RtcAlarmTime,
RtcAlarmTimeList,
RtcAlarmEnabled,
RtcAdjustPpm,
AlarmRepeat,
SafeShutdownLevel,
SafeShutdownDelay,
ButtonEnable { mode: ButtonMode },
ButtonShell { mode: ButtonMode },
AutoPowerOn,
AuthUsername,
AntiMistouch,
SoftPoweroff,
SoftPoweroffShell,
Temperature,
InputProtect,
}

#[derive(Debug, EnumVariantsStrings, PartialEq, Eq, Clone, Copy)]
pub enum ButtonMode {
Single,
Double,
Long,
}

impl clap::ValueEnum for ButtonMode {
fn value_variants<'a>() -> &'a [Self] {
&[Self::Single, Self::Double, Self::Long]
}

fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
Some(PossibleValue::new(self.to_str()))
}
}

#[derive(Debug, Args, PartialEq)]
pub struct BatteryRangeArgs {
pub min: f32,
pub max: f32,
}

#[derive(Debug, Args, PartialEq)]
pub struct BoolArg {
#[arg(action = ArgAction::Set)]
pub enable: bool,
}

#[cfg(test)]
mod tests {

use anyhow::Result;
use rstest::rstest;

use super::*;

#[rstest]
#[case("get version", Cmds::Get(GetCmds::Version))]
#[case("get model", Cmds::Get(GetCmds::Model))]
#[case("get firmware_version", Cmds::Get(GetCmds::FirmwareVersion))]
#[case("get button_enable single", Cmds::Get(GetCmds::ButtonEnable{ mode: ButtonMode::Single }))]
#[case("get button_shell long", Cmds::Get(GetCmds::ButtonShell { mode: ButtonMode::Long } ))]
#[case("set_battery_charging_range 30.0,80.0", Cmds::SetBatteryChargingRange{ range: vec![30.0, 80.0]})]
#[case("set_battery_output true", Cmds::SetBatteryOutput(BoolArg{ enable: true }))]
#[case("set_battery_output false", Cmds::SetBatteryOutput(BoolArg { enable: false }))]
#[case("set_button_shell single echo hello", Cmds::SetButtonShell { mode: ButtonMode::Single, shell: vec!["echo".to_string(), "hello".to_string()] })]
#[case("set_soft_poweroff_shell shutdown -a", Cmds::SetSoftPoweroffShell { shell: vec!["shutdown".to_string(), "-a".to_string()] })]
#[case("set_soft_poweroff_shell bash \"shutdown -a\"", Cmds::SetSoftPoweroffShell { shell: vec!["bash".to_string(), "shutdown -a".to_string()] })]
fn test_cmds(#[case] repl: &str, #[case] cmd: Cmds) -> Result<()> {
assert!(cmd == Cmds::from_str(repl)?);
Ok(())
}

#[rstest]
fn test_help() {
let h = Cmds::from_str("help");
assert!(format!("{:?}", h).contains("help"));
}

#[rstest]
fn test_help_get() {
let h = Cmds::from_str("help get");
println!("{:?}", h);
assert!(format!("{:?}", h).contains("version"));
}
}
Loading

0 comments on commit bcdf513

Please sign in to comment.