summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlittleblack111 <littleblack11111@gmail.com>2025-09-20 21:39:52 +0800
committerlittleblack111 <littleblack11111@gmail.com>2025-09-20 23:34:16 +0800
commit9c06520622ccc9662fd97a8e0457bc03b4dc4db6 (patch)
tree57b546735c9a953360af89220ff12b9ecabb0371
parent002be6a430d92be930b0e2164f373672c8b7ae83 (diff)
wip
-rw-r--r--src/client/connector.rs4
-rw-r--r--src/client/connector/httpconnector.rs7
-rw-r--r--src/executor.rs10
-rw-r--r--src/server/servers/tcpserver/tasks.rs4
-rw-r--r--src/tasks.rs136
-rw-r--r--src/tasks/client.rs146
-rw-r--r--src/tasks/server.rs0
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