diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/client/connector.rs | 4 | ||||
| -rw-r--r-- | src/client/connector/httpconnector.rs | 7 | ||||
| -rw-r--r-- | src/executor.rs | 10 | ||||
| -rw-r--r-- | src/server/servers/tcpserver/tasks.rs | 4 | ||||
| -rw-r--r-- | src/tasks.rs | 136 | ||||
| -rw-r--r-- | src/tasks/client.rs | 146 | ||||
| -rw-r--r-- | src/tasks/server.rs | 0 |
7 files changed, 165 insertions, 142 deletions
diff --git a/src/client/connector.rs b/src/client/connector.rs index f57e388..f48b039 100644 --- a/src/client/connector.rs +++ b/src/client/connector.rs @@ -7,7 +7,7 @@ use std::{ }; use crate::client::Client; -use remote_control_rs::{executor::Executor, tasks::NETWORK_T}; +use remote_control_rs::{executor::Executor, tasks::client::NETWORK_T}; pub type Result<T: Display, E: Debug> = result::Result<T, E>; @@ -28,7 +28,7 @@ pub trait Connection { fn get_ip(&self) -> Option<IpAddr>; fn force_network(&mut self) { - _ = Executor::new(&NETWORK_T, ["true"]); + _ = Executor::new(NETWORK_T.as_ref(), ["true"]); } fn init<'a>(&self, c: &Client<'a, Self>) -> std::result::Result<(), Self::Err> diff --git a/src/client/connector/httpconnector.rs b/src/client/connector/httpconnector.rs index 60405f4..eb5ebe3 100644 --- a/src/client/connector/httpconnector.rs +++ b/src/client/connector/httpconnector.rs @@ -1,5 +1,6 @@ use crate::connector::Connection; -use remote_control_rs::{executor::Executor, tasks::NETWORK_T}; +use remote_control_rs::executor::Executor; +use remote_control_rs::tasks::client::{NETWORK_T, Name}; use reqwest::{ Error, StatusCode, Url, blocking::{Client, RequestBuilder}, @@ -25,7 +26,7 @@ impl From<reqwest::Error> for HTTPConnectorError { } pub struct HTTPConnector { - network_enforcer: Executor<'static, 'static>, + network_enforcer: Executor<'static, 'static, Name>, pull_url: Url, ntfy_url: Url, ip_getter_url: Url, @@ -36,7 +37,7 @@ pub struct HTTPConnector { impl HTTPConnector { pub fn new(pull_url: &str, ntfy_url: &str, ip_getter_url: &str) -> result::Result<Self, HTTPConnectorError> { Ok(Self { - network_enforcer: Executor::new(&NETWORK_T, ["true"]).unwrap(), // .unwrap() should never panic + network_enforcer: Executor::new(NETWORK_T.as_ref(), ["true"]).unwrap(), // .unwrap() should never panic prev: String::new(), pull_url: Url::parse(pull_url)?, ntfy_url: Url::parse(ntfy_url)?, diff --git a/src/executor.rs b/src/executor.rs index 9f66ec3..df59734 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -1,13 +1,13 @@ use crate::tasks::{CompletedTask, IntoTaskErr, Task, TaskOutput}; -pub struct Executor<'a, 't> { - task: &'t Task, +pub struct Executor<'a, 't, N: Copy> { + task: &'t Task<N>, args: Box<[&'a str]>, - complete_task: Option<CompletedTask>, + complete_task: Option<CompletedTask<N>>, } -impl<'a, 't> Executor<'a, 't> { - pub fn new(task: &'t Task, args: impl IntoIterator<Item = &'a str>) -> Result<Self, IntoTaskErr> { +impl<'a, 't, N: Copy> Executor<'a, 't, N> { + pub fn new(task: &'t Task<N>, args: impl IntoIterator<Item = &'a str>) -> Result<Self, IntoTaskErr> { Ok(Self { task: task, args: args.into_iter().collect(), complete_task: None }) } diff --git a/src/server/servers/tcpserver/tasks.rs b/src/server/servers/tcpserver/tasks.rs index 23e6f9e..5052dfe 100644 --- a/src/server/servers/tcpserver/tasks.rs +++ b/src/server/servers/tcpserver/tasks.rs @@ -1,4 +1,4 @@ -use remote_control_rs::tasks::{CompletedTask, Name}; +use remote_control_rs::tasks::{CompletedTask, client::Name}; use serde::Deserialize; #[derive(Deserialize)] @@ -15,6 +15,6 @@ pub enum Request { #[derive(Deserialize)] pub enum TaskType { - Completed(CompletedTask), + Completed(CompletedTask<Name>), Pending(Name), } diff --git a/src/tasks.rs b/src/tasks.rs index b979d4f..3e76ce4 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -1,145 +1,21 @@ -use std::fmt::Display; - use serde::Deserialize; pub type TaskOutput = Result<String, String>; +pub mod client; +pub mod server; -pub struct Task { - pub name: Name, +pub struct Task<N> { + pub name: N, pub exec: fn(&[&str]) -> TaskOutput, } #[derive(Deserialize)] -pub struct CompletedTask { - pub name: Name, +pub struct CompletedTask<N> { + pub name: N, pub output: Option<TaskOutput>, } -#[derive(Debug, Deserialize, Clone, Copy)] -pub enum Name { - Nop, - Exec, - Network, -} - -impl Display for Name { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{:?}", self) - } -} - -pub const TASKS: &[Task] = &[Task { name: Name::Nop, exec: no_op }, Task { name: Name::Exec, exec: exec }, NETWORK_T]; - -pub const NETWORK_T: Task = Task { name: Name::Network, exec: network }; - -fn no_op(_: &[&str]) -> Result<String, String> { - Ok("".to_string()) -} - -fn exec(cmds: &[&str]) -> 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]).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: &[&str]) -> Result<String, String> { - use std::process::{Command, Stdio}; - let switch: bool = switch[0].parse::<bool>().map_err(|e| 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(); - if let Err(e) = e.read_to_string(&mut reason) { - 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(); - if let Err(e) = o.read_to_string(&mut output) { - 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(); - if let Err(e) = e.read_to_string(&mut reason) { - 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), } - -impl TryFrom<&str> for &'static Task { - type Error = IntoTaskErr; - - fn try_from(value: &str) -> Result<Self, Self::Error> { - for task in TASKS { - if task.name.to_string() == value { - return Ok(task); - } - } - Err(IntoTaskErr::NotFound(value.to_string())) - } -} diff --git a/src/tasks/client.rs b/src/tasks/client.rs new file mode 100644 index 0000000..274eee2 --- /dev/null +++ b/src/tasks/client.rs @@ -0,0 +1,146 @@ +use std::fmt::Display; + +use crate::tasks::{IntoTaskErr, Task as BaseTask}; +use serde::Deserialize; + +pub struct Task(pub BaseTask<Name>); + +#[derive(Debug, Deserialize, Clone, Copy)] +pub enum Name { + Nop, + Exec, + Network, +} + +impl Display for Name { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:?}", self) + } +} + +pub const TASKS: &[Task] = &[ + Task(BaseTask { name: Name::Nop, exec: no_op }), + Task(BaseTask { name: Name::Exec, exec: exec }), + // assuming NETWORK_T was a BaseTask<Name>; wrap it as well + NETWORK_T, +]; +pub const NETWORK_T: Task = Task(BaseTask { name: Name::Network, exec: network }); + +fn no_op(_: &[&str]) -> Result<String, String> { + Ok("".to_string()) +} + +fn exec(cmds: &[&str]) -> 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]).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: &[&str]) -> Result<String, String> { + use std::process::{Command, Stdio}; + let switch: bool = switch[0].parse::<bool>().map_err(|e| 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(); + if let Err(e) = e.read_to_string(&mut reason) { + 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(); + if let Err(e) = o.read_to_string(&mut output) { + 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(); + if let Err(e) = e.read_to_string(&mut reason) { + 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()) +} + +impl TryFrom<&str> for &'static Task { + type Error = IntoTaskErr; + + fn try_from(value: &str) -> Result<Self, Self::Error> { + for task in TASKS { + if task.0.name.to_string() == value { + return Ok(task); + } + } + Err(IntoTaskErr::NotFound(value.to_string())) + } +} + +impl From<Task> for BaseTask<Name> { + fn from(value: Task) -> Self { + value.0 + } +} + +impl AsRef<BaseTask<Name>> for Task { + fn as_ref(&self) -> &BaseTask<Name> { + &self.0 + } +} diff --git a/src/tasks/server.rs b/src/tasks/server.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/tasks/server.rs |
