From 9c06520622ccc9662fd97a8e0457bc03b4dc4db6 Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Sat, 20 Sep 2025 21:39:52 +0800 Subject: wip --- src/client/connector.rs | 4 +- src/client/connector/httpconnector.rs | 7 +- src/executor.rs | 10 +-- src/server/servers/tcpserver/tasks.rs | 4 +- src/tasks.rs | 136 ++----------------------------- src/tasks/client.rs | 146 ++++++++++++++++++++++++++++++++++ src/tasks/server.rs | 0 7 files changed, 165 insertions(+), 142 deletions(-) create mode 100644 src/tasks/client.rs create mode 100644 src/tasks/server.rs 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 = result::Result; @@ -28,7 +28,7 @@ pub trait Connection { fn get_ip(&self) -> Option; 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 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 { 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, args: Box<[&'a str]>, - complete_task: Option, + complete_task: Option>, } -impl<'a, 't> Executor<'a, 't> { - pub fn new(task: &'t Task, args: impl IntoIterator) -> Result { +impl<'a, 't, N: Copy> Executor<'a, 't, N> { + pub fn new(task: &'t Task, args: impl IntoIterator) -> Result { 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), 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; +pub mod client; +pub mod server; -pub struct Task { - pub name: Name, +pub struct Task { + pub name: N, pub exec: fn(&[&str]) -> TaskOutput, } #[derive(Deserialize)] -pub struct CompletedTask { - pub name: Name, +pub struct CompletedTask { + pub name: N, pub output: Option, } -#[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 { - Ok("".to_string()) -} - -fn exec(cmds: &[&str]) -> Result { - 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 { - use std::process::{Command, Stdio}; - let switch: bool = switch[0].parse::().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 { - 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); + +#[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; wrap it as well + NETWORK_T, +]; +pub const NETWORK_T: Task = Task(BaseTask { name: Name::Network, exec: network }); + +fn no_op(_: &[&str]) -> Result { + Ok("".to_string()) +} + +fn exec(cmds: &[&str]) -> Result { + 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 { + use std::process::{Command, Stdio}; + let switch: bool = switch[0].parse::().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 { + for task in TASKS { + if task.0.name.to_string() == value { + return Ok(task); + } + } + Err(IntoTaskErr::NotFound(value.to_string())) + } +} + +impl From for BaseTask { + fn from(value: Task) -> Self { + value.0 + } +} + +impl AsRef> for Task { + fn as_ref(&self) -> &BaseTask { + &self.0 + } +} diff --git a/src/tasks/server.rs b/src/tasks/server.rs new file mode 100644 index 0000000..e69de29 -- cgit v1.2.3