mirror of
https://codeberg.org/Codeberg/pages-server.git
synced 2025-04-25 14:26:58 +00:00
initial commit
This commit is contained in:
commit
363c6a18c4
11 changed files with 589 additions and 0 deletions
82
src/cli.rs
Normal file
82
src/cli.rs
Normal file
|
@ -0,0 +1,82 @@
|
|||
use clap::{App, Arg, ArgGroup, ArgMatches};
|
||||
|
||||
pub fn build_cli() -> App<'static, 'static> {
|
||||
App::new("RS Light")
|
||||
.version("1.0")
|
||||
.author("crapStone <wewr.mc@gmail.com>")
|
||||
.about("Utility to interact with backlight")
|
||||
.arg(
|
||||
Arg::with_name("set")
|
||||
.short("s")
|
||||
.long("set")
|
||||
.value_name("VALUE")
|
||||
.help("Sets brightness to given value")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("inc")
|
||||
.short("i")
|
||||
.long("increase")
|
||||
.value_name("PERCENT")
|
||||
.help("Increases brightness")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("dec")
|
||||
.short("d")
|
||||
.long("decrease")
|
||||
.value_name("PERCENT")
|
||||
.help("Decreases brightness")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("get")
|
||||
.short("g")
|
||||
.long("get")
|
||||
.help("Prints current brightness value"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("zer")
|
||||
.short("z")
|
||||
.long("zero")
|
||||
.help("Sets brightness to lowest value"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("ful")
|
||||
.short("f")
|
||||
.long("full")
|
||||
.help("Sets brightness to highest value"),
|
||||
)
|
||||
.group(ArgGroup::with_name("brightness_control").args(&["set", "inc", "dec", "get", "zer", "ful"]))
|
||||
.arg(
|
||||
Arg::with_name("list")
|
||||
.short("l")
|
||||
.long("list")
|
||||
.help("Lists all available brightness and led controllers")
|
||||
.conflicts_with_all(&["brightness_control"]),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("ctrl_type")
|
||||
.short("t")
|
||||
.long("type")
|
||||
.value_name("controller_type")
|
||||
.takes_value(true)
|
||||
.possible_values(&["raw", "lin", "log"])
|
||||
.default_value("lin")
|
||||
.help("choose controller type")
|
||||
.long_help(
|
||||
r#"You can choose between these controller types:
|
||||
raw: uses the raw values found in the device files
|
||||
lin: uses percentage values (0.0 - 1.0) with a linear curve for the actual brightness
|
||||
log: uses percentage values (0.0 - 1.0) with a logarithmic curve for the actual brightness
|
||||
the perceived brightness for the human eyes should be linear with this controller
|
||||
"#,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a argument parser with [clap](../clap/index.html) and returns a `Box` with the
|
||||
/// [matches](../clap/struct.ArgMatches.html).
|
||||
pub fn parse_args<'a>() -> Box<ArgMatches<'a>> {
|
||||
Box::new(build_cli().get_matches())
|
||||
}
|
204
src/controllers.rs
Normal file
204
src/controllers.rs
Normal file
|
@ -0,0 +1,204 @@
|
|||
use std::collections::HashMap;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::prelude::*;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::exit;
|
||||
|
||||
use exitcode;
|
||||
|
||||
const SYS_PATHS: [&str; 2] = ["/sys/class/backlight", "/sys/class/leds"];
|
||||
|
||||
pub trait Controller {
|
||||
fn get_brightness(&self) -> i32;
|
||||
fn get_max_brightness(&self) -> i32;
|
||||
fn set_brightness(&self, value: i32);
|
||||
|
||||
fn check_brightness_value(&self, value: i32) {
|
||||
if value > self.get_max_brightness() {
|
||||
eprintln!(
|
||||
"brightness value too high: {} > {}",
|
||||
value,
|
||||
self.get_max_brightness()
|
||||
);
|
||||
exit(exitcode::DATAERR);
|
||||
} else if value < 0 {
|
||||
eprintln!("brightness value too low: {}", value);
|
||||
exit(exitcode::DATAERR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RawController {
|
||||
path: Box<PathBuf>,
|
||||
}
|
||||
|
||||
impl RawController {
|
||||
pub fn new(path: Box<PathBuf>) -> Self {
|
||||
Self { path: path }
|
||||
}
|
||||
}
|
||||
|
||||
impl Controller for RawController {
|
||||
fn get_brightness(&self) -> i32 {
|
||||
read_file_to_int(self.path.join("brightness"))
|
||||
}
|
||||
|
||||
fn get_max_brightness(&self) -> i32 {
|
||||
read_file_to_int(self.path.join("max_brightness"))
|
||||
}
|
||||
|
||||
fn set_brightness(&self, value: i32) {
|
||||
self.check_brightness_value(value);
|
||||
|
||||
let path = self.path.join("brightness");
|
||||
|
||||
let mut file = match OpenOptions::new().write(true).read(true).open(&path) {
|
||||
Err(why) => {
|
||||
eprintln!("couldn't open '{}': {:?}", &path.display(), why.kind());
|
||||
exit(exitcode::OSFILE);
|
||||
}
|
||||
Ok(file) => file,
|
||||
};
|
||||
|
||||
match write!(file, "{}", value) {
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
eprintln!(
|
||||
"could not write '{}' to file '{}': {:?}",
|
||||
value,
|
||||
&path.display(),
|
||||
err.kind()
|
||||
);
|
||||
exit(exitcode::OSFILE);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LinController {
|
||||
parent_controller: RawController,
|
||||
}
|
||||
|
||||
impl LinController {
|
||||
pub fn new(path: Box<PathBuf>) -> Self {
|
||||
Self {
|
||||
parent_controller: RawController::new(path),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Controller for LinController {
|
||||
fn get_brightness(&self) -> i32 {
|
||||
((self.parent_controller.get_brightness() as f64
|
||||
/ self.parent_controller.get_max_brightness() as f64)
|
||||
* self.get_max_brightness() as f64) as i32
|
||||
}
|
||||
|
||||
fn get_max_brightness(&self) -> i32 {
|
||||
100
|
||||
}
|
||||
|
||||
fn set_brightness(&self, value: i32) {
|
||||
self.check_brightness_value(value);
|
||||
|
||||
if value > self.get_max_brightness() {
|
||||
eprintln!(
|
||||
"brightness value too high! {} > {}",
|
||||
value,
|
||||
self.get_max_brightness()
|
||||
);
|
||||
exit(exitcode::DATAERR);
|
||||
}
|
||||
|
||||
self.parent_controller.set_brightness(
|
||||
(value * self.parent_controller.get_max_brightness()) / self.get_max_brightness(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LogController {
|
||||
parent_controller: RawController,
|
||||
}
|
||||
|
||||
impl LogController {
|
||||
pub fn new(path: Box<PathBuf>) -> Self {
|
||||
Self {
|
||||
parent_controller: RawController::new(path),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Controller for LogController {
|
||||
fn get_brightness(&self) -> i32 {
|
||||
((self.parent_controller.get_brightness() as f64).log10()
|
||||
/ (self.parent_controller.get_max_brightness() as f64).log10()
|
||||
* self.get_max_brightness() as f64) as i32
|
||||
}
|
||||
|
||||
fn get_max_brightness(&self) -> i32 {
|
||||
100
|
||||
}
|
||||
|
||||
fn set_brightness(&self, value: i32) {
|
||||
self.check_brightness_value(value);
|
||||
|
||||
if value > self.get_max_brightness() {
|
||||
eprintln!(
|
||||
"brightness value too high! {} > {}",
|
||||
value,
|
||||
self.get_max_brightness()
|
||||
);
|
||||
exit(exitcode::DATAERR);
|
||||
}
|
||||
|
||||
self.parent_controller.set_brightness(10f64.powf(
|
||||
(value as f64 / self.get_max_brightness() as f64)
|
||||
* (self.parent_controller.get_max_brightness() as f64).log10(),
|
||||
) as i32)
|
||||
}
|
||||
}
|
||||
|
||||
fn read_file_to_int(path: PathBuf) -> i32 {
|
||||
let mut file = match File::open(&path) {
|
||||
Err(why) => {
|
||||
eprintln!("couldn't open {}: {:?}", path.display(), why.kind());
|
||||
exit(exitcode::OSFILE);
|
||||
}
|
||||
Ok(file) => file,
|
||||
};
|
||||
|
||||
let mut s = String::new();
|
||||
match file.read_to_string(&mut s) {
|
||||
Err(why) => {
|
||||
eprintln!("couldn't read {}: {:?}", path.display(), why.kind());
|
||||
exit(exitcode::OSFILE);
|
||||
}
|
||||
Ok(_) => return s.trim().parse().unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Searches through all paths in `SYS_PATHS` and creates a `HashMap` with the name and absolute path.
|
||||
///
|
||||
/// It returns a `Tuple` of the default backlight name and the `HashMap`.
|
||||
pub fn get_controllers() -> (String, HashMap<String, Box<PathBuf>>) {
|
||||
let mut controllers: HashMap<String, Box<PathBuf>> = HashMap::new();
|
||||
|
||||
let mut default = None;
|
||||
|
||||
for path in SYS_PATHS.iter() {
|
||||
if Path::new(path).exists() {
|
||||
for name in Path::new(path).read_dir().unwrap() {
|
||||
let name = name.unwrap().path();
|
||||
let key = String::from(name.file_name().unwrap().to_str().unwrap());
|
||||
|
||||
if default.is_none() {
|
||||
default = Some(key.clone());
|
||||
}
|
||||
|
||||
controllers.insert(key, Box::new(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(default.unwrap(), controllers)
|
||||
}
|
61
src/main.rs
Normal file
61
src/main.rs
Normal file
|
@ -0,0 +1,61 @@
|
|||
mod cli;
|
||||
mod controllers;
|
||||
|
||||
use std::process::exit;
|
||||
|
||||
use exitcode;
|
||||
|
||||
use controllers::{Controller, LinController, LogController, RawController};
|
||||
|
||||
fn main() {
|
||||
let matches = cli::parse_args();
|
||||
|
||||
let (default_ctrl, ctrls) = controllers::get_controllers();
|
||||
|
||||
let p = ctrls.get(&default_ctrl).unwrap().to_owned();
|
||||
let controller: Box<dyn Controller> = match matches.value_of("ctrl_type") {
|
||||
Some("raw") => Box::new(RawController::new(p)),
|
||||
Some("lin") => Box::new(LinController::new(p)),
|
||||
Some("log") => Box::new(LogController::new(p)),
|
||||
Some(_) | None => panic!(ERROR_MSG),
|
||||
};
|
||||
|
||||
if matches.is_present("list") {
|
||||
for ctrl in ctrls.keys() {
|
||||
println!("{}", ctrl);
|
||||
}
|
||||
exit(exitcode::OK);
|
||||
} else if let Some(value) = matches.value_of("set") {
|
||||
let new_value = value.parse::<i32>().unwrap();
|
||||
controller.set_brightness(new_value);
|
||||
} else if let Some(value) = matches.value_of("inc") {
|
||||
let new_value = controller.get_brightness() + value.parse::<i32>().unwrap();
|
||||
controller.set_brightness(new_value.min(controller.get_max_brightness()));
|
||||
} else if let Some(value) = matches.value_of("dec") {
|
||||
let new_value = controller.get_brightness() - value.parse::<i32>().unwrap();
|
||||
controller.set_brightness(new_value.max(0));
|
||||
} else if matches.is_present("get") {
|
||||
println!("{}", controller.get_brightness());
|
||||
} else if matches.is_present("zer") {
|
||||
controller.set_brightness(0);
|
||||
} else if matches.is_present("ful") {
|
||||
controller.set_brightness(controller.get_max_brightness());
|
||||
} else {
|
||||
panic!(ERROR_MSG);
|
||||
}
|
||||
|
||||
exit(exitcode::OK);
|
||||
}
|
||||
|
||||
// https://xkcd.com/2200/
|
||||
const ERROR_MSG: &str = r#"
|
||||
ERROR!
|
||||
|
||||
If you're seeing this, the code is in what I thought was an unreachable state.
|
||||
|
||||
I could give you advice for what to do. but honestly, why should you trust me?
|
||||
I clearly screwed this up. I'm writing a message that should never appear,
|
||||
yet I know it will probably appear someday.
|
||||
|
||||
On a deep level, I know I'm not up to this task. I'm so sorry.
|
||||
"#;
|
Loading…
Add table
Add a link
Reference in a new issue