summaryrefslogtreecommitdiff
path: root/src/tasks.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tasks.rs')
-rw-r--r--src/tasks.rs171
1 files changed, 171 insertions, 0 deletions
diff --git a/src/tasks.rs b/src/tasks.rs
new file mode 100644
index 0000000..3d9d940
--- /dev/null
+++ b/src/tasks.rs
@@ -0,0 +1,171 @@
+pub struct Task {
+ pub name: &'static str,
+ pub exec: fn(&[String]) -> Result<String, String>,
+}
+
+impl PartialEq for &Task {
+ fn eq(&self, other: &Self) -> bool {
+ self.name == other.name
+ }
+}
+
+pub const TASKS: &[Task] = &[
+ Task {
+ name: "nop",
+ exec: no_op,
+ },
+ Task {
+ name: "exec",
+ exec: exec,
+ },
+ Task {
+ name: "network",
+ exec: network,
+ },
+];
+
+fn no_op(_: &[String]) -> Result<String, String> {
+ Ok("".to_string())
+}
+
+fn exec(cmds: &[String]) -> Result<String, String> {
+ use std::process::Command;
+ // TODO: fmt and add exit code, and add support for both stdout and stderr, and support for no output
+ match Command::new(cmds[0].as_str()).args(&cmds[1..]).output() {
+ Ok(o) => {
+ if o.status.success() {
+ Ok(String::from_utf8_lossy(&o.stdout).to_string())
+ } else {
+ Err(String::from_utf8_lossy(&o.stderr).to_string())
+ }
+ }
+ Err(e) => Err(e.to_string()),
+ }
+}
+
+fn network(switch: &[String]) -> Result<String, String> {
+ use std::process::{Command, Stdio};
+ let switch: bool = match switch[0].parse() {
+ Ok(s) => s,
+ Err(e) => return Err(e.to_string()),
+ };
+
+ // TODO: windows and linux
+
+ // todo let .. = Command::new('networksetup')
+ #[cfg(target_os = "macos")]
+ {
+ use std::io::Read;
+ match Command::new("networksetup")
+ .arg("-listallhardwareports")
+ .stdout(Stdio::piped())
+ .spawn()
+ {
+ Ok(devs) => {
+ match Command::new("awk")
+ .arg(r#"/Wi-Fi|AirPort/{getline; print $2}"#)
+ .stdin(Stdio::from(match devs.stdout {
+ Some(s) => s,
+ None => match devs.stderr {
+ Some(mut e) => {
+ let mut reason = String::new();
+ match e.read_to_string(&mut reason) {
+ Ok(_) => {}
+ Err(e) => return Err(format!("networksetup failed to list hardware: {e}"))
+ }
+ return Err(format!(
+ "networksetup failed to list hardware: {reason}"
+ ));
+ }
+ None => Err("networksetup failed to list hardware".to_string())?,
+ },
+ }))
+ .stdout(Stdio::piped())
+ .spawn()
+ {
+ Ok(dev) => match Command::new("networksetup").arg("-setairportpower").arg(
+ match dev.stdout {
+ Some(mut o) => {
+ let mut output = String::new();
+ match o.read_to_string(&mut output) {
+ Ok(_) => (),
+ Err(e) => return Err(format!("awk failed to get device from networksetup list hardware: {e}"))
+ };
+ output
+ }
+ None => match dev.stderr {
+ Some(mut e) => {
+ let mut reason = String::new();
+ match e.read_to_string(&mut reason) {
+ Ok(_) => {}
+ Err(e) => return Err(format!("awk failed to get device from networksetup list hardware: {e}"))
+ }
+ return Err(format!("awk failed to get device from networksetup list hardware: {reason}"));
+ }
+ None => Err("awk failed to get device from networksetup list hardware".to_string())?,
+ },
+ },
+ ).arg(if switch { "on" } else { "off" }).output() {
+ Ok(o) => {
+ if o.status.success() {
+ Ok(String::from_utf8_lossy(&o.stdout)
+ .to_string())
+ } else {
+ Err(String::from_utf8_lossy(&o.stderr)
+ .to_string())
+ }
+ }
+ Err(e) => Err(e.to_string()),
+ },
+ Err(e) => Err(e.to_string()),
+ }
+ }
+ Err(e) => Err(e.to_string()),
+ }
+ }
+
+ #[cfg(not(target_os = "macos"))]
+ Err("not implemented".to_string())
+}
+
+#[derive(Debug)]
+pub enum IntoTaskErr {
+ NotFound(String),
+}
+
+pub trait IntoTask {
+ fn into_task<'a>(self) -> Result<&'a Task, IntoTaskErr>;
+}
+
+impl IntoTask for String {
+ fn into_task<'a>(self) -> Result<&'a Task, IntoTaskErr> {
+ for task in TASKS {
+ if task.name == self {
+ return Ok(task);
+ }
+ }
+ Err(IntoTaskErr::NotFound(self))
+ }
+}
+
+impl IntoTask for &str {
+ fn into_task<'a>(self) -> Result<&'a Task, IntoTaskErr> {
+ for task in TASKS {
+ if task.name == self {
+ return Ok(task);
+ }
+ }
+ Err(IntoTaskErr::NotFound(self.to_string()))
+ }
+}
+
+impl IntoTask for &Task {
+ fn into_task<'a>(self) -> Result<&'a Task, IntoTaskErr> {
+ for task in TASKS {
+ if task == self {
+ return Ok(task);
+ }
+ }
+ Err(IntoTaskErr::NotFound(self.name.to_string()))
+ }
+}