feat(sswinservice): Running ssservice as a Windows Service

ref #1292

https://learn.microsoft.com/en-us/windows/win32/services/about-services
This commit is contained in:
zonyitoo
2023-09-19 00:29:35 +08:00
parent c0ba7f044d
commit 268e520a72
6 changed files with 399 additions and 65 deletions
+25 -11
View File
@@ -1,11 +1,14 @@
//! Local server launchers
use std::{net::IpAddr, path::PathBuf, process::ExitCode, time::Duration};
use std::{future::Future, net::IpAddr, path::PathBuf, process::ExitCode, time::Duration};
use clap::{builder::PossibleValuesParser, Arg, ArgAction, ArgGroup, ArgMatches, Command, ValueHint};
use futures::future::{self, Either};
use log::{info, trace};
use tokio::{self, runtime::Builder};
use tokio::{
self,
runtime::{Builder, Runtime},
};
#[cfg(feature = "local-redir")]
use shadowsocks_service::config::RedirType;
@@ -496,8 +499,8 @@ pub fn define_command_line_options(mut app: Command) -> Command {
app
}
/// Program entrance `main`
pub fn main(matches: &ArgMatches) -> ExitCode {
/// Create `Runtime` and `main` entry
pub fn create(matches: &ArgMatches) -> Result<(Runtime, impl Future<Output = ExitCode>), ExitCode> {
let (config, runtime) = {
let config_path_opt = matches.get_one::<PathBuf>("CONFIG").cloned().or_else(|| {
if !matches.contains_id("SERVER_CONFIG") {
@@ -518,7 +521,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
Ok(c) => c,
Err(err) => {
eprintln!("loading config {config_path:?}, {err}");
return crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into();
return Err(crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into());
}
},
None => ServiceConfig::default(),
@@ -542,7 +545,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
Ok(cfg) => cfg,
Err(err) => {
eprintln!("loading config {cpath:?}, {err}");
return crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into();
return Err(crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into());
}
},
None => Config::new(ConfigType::Local),
@@ -781,7 +784,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
Ok(acl) => acl,
Err(err) => {
eprintln!("loading ACL \"{acl_file}\", {err}");
return crate::EXIT_CODE_LOAD_ACL_FAILURE.into();
return Err(crate::EXIT_CODE_LOAD_ACL_FAILURE.into());
}
};
config.acl = Some(acl);
@@ -831,12 +834,12 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
"missing `local_address`, consider specifying it by --local-addr command line option, \
or \"local_address\" and \"local_port\" in configuration file"
);
return crate::EXIT_CODE_INSUFFICIENT_PARAMS.into();
return Err(crate::EXIT_CODE_INSUFFICIENT_PARAMS.into());
}
if let Err(err) = config.check_integrity() {
eprintln!("config integrity check failed, {err}");
return crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into();
return Err(crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into());
}
#[cfg(unix)]
@@ -870,7 +873,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
(config, runtime)
};
runtime.block_on(async move {
let main_fut = async move {
let config_path = config.config_path.clone();
let instance = Server::new(config).await.expect("create local");
@@ -899,7 +902,18 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
// The abort signal future resolved. Means we should just exit.
Either::Right(_) => ExitCode::SUCCESS,
}
})
};
Ok((runtime, main_fut))
}
/// Program entrance `main`
#[inline]
pub fn main(matches: &ArgMatches) -> ExitCode {
match create(matches) {
Ok((runtime, main_fut)) => runtime.block_on(main_fut),
Err(code) => code,
}
}
#[cfg(unix)]
+25 -11
View File
@@ -1,11 +1,14 @@
//! Server Manager launchers
use std::{net::IpAddr, path::PathBuf, process::ExitCode, time::Duration};
use std::{future::Future, net::IpAddr, path::PathBuf, process::ExitCode, time::Duration};
use clap::{builder::PossibleValuesParser, Arg, ArgAction, ArgGroup, ArgMatches, Command, ValueHint};
use futures::future::{self, Either};
use log::{info, trace};
use tokio::{self, runtime::Builder};
use tokio::{
self,
runtime::{Builder, Runtime},
};
#[cfg(unix)]
use shadowsocks_service::config::ManagerServerMode;
@@ -256,8 +259,8 @@ pub fn define_command_line_options(mut app: Command) -> Command {
app
}
/// Program entrance `main`
pub fn main(matches: &ArgMatches) -> ExitCode {
/// Create `Runtime` and `main` entry
pub fn create(matches: &ArgMatches) -> Result<(Runtime, impl Future<Output = ExitCode>), ExitCode> {
let (config, runtime) = {
let config_path_opt = matches.get_one::<PathBuf>("CONFIG").cloned().or_else(|| {
if !matches.contains_id("SERVER_CONFIG") {
@@ -278,7 +281,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
Ok(c) => c,
Err(err) => {
eprintln!("loading config {config_path:?}, {err}");
return crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into();
return Err(crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into());
}
},
None => ServiceConfig::default(),
@@ -302,7 +305,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
Ok(cfg) => cfg,
Err(err) => {
eprintln!("loading config {cpath:?}, {err}");
return crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into();
return Err(crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into());
}
},
None => Config::new(ConfigType::Manager),
@@ -409,7 +412,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
Ok(acl) => acl,
Err(err) => {
eprintln!("loading ACL \"{acl_file}\", {err}");
return crate::EXIT_CODE_LOAD_ACL_FAILURE.into();
return Err(crate::EXIT_CODE_LOAD_ACL_FAILURE.into());
}
};
config.acl = Some(acl);
@@ -459,12 +462,12 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
"missing `manager_address`, consider specifying it by --manager-address command line option, \
or \"manager_address\" and \"manager_port\" keys in configuration file"
);
return crate::EXIT_CODE_INSUFFICIENT_PARAMS.into();
return Err(crate::EXIT_CODE_INSUFFICIENT_PARAMS.into());
}
if let Err(err) = config.check_integrity() {
eprintln!("config integrity check failed, {err}");
return crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into();
return Err(crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into());
}
#[cfg(unix)]
@@ -503,7 +506,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
(config, runtime)
};
runtime.block_on(async move {
let main_fut = async move {
let abort_signal = monitor::create_signal_monitor();
let server = run_manager(config);
@@ -524,7 +527,18 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
// The abort signal future resolved. Means we should just exit.
Either::Right(_) => ExitCode::SUCCESS,
}
})
};
Ok((runtime, main_fut))
}
/// Program entrance `main`
#[inline]
pub fn main(matches: &ArgMatches) -> ExitCode {
match create(matches) {
Ok((runtime, main_fut)) => runtime.block_on(main_fut),
Err(code) => code,
}
}
#[cfg(test)]
+25 -11
View File
@@ -1,11 +1,14 @@
//! Server launchers
use std::{net::IpAddr, path::PathBuf, process::ExitCode, time::Duration};
use std::{future::Future, net::IpAddr, path::PathBuf, process::ExitCode, time::Duration};
use clap::{builder::PossibleValuesParser, Arg, ArgAction, ArgGroup, ArgMatches, Command, ValueHint};
use futures::future::{self, Either};
use log::{info, trace};
use tokio::{self, runtime::Builder};
use tokio::{
self,
runtime::{Builder, Runtime},
};
use shadowsocks_service::{
acl::AccessControl,
@@ -268,8 +271,8 @@ pub fn define_command_line_options(mut app: Command) -> Command {
app
}
/// Program entrance `main`
pub fn main(matches: &ArgMatches) -> ExitCode {
/// Create `Runtime` and `main` entry
pub fn create(matches: &ArgMatches) -> Result<(Runtime, impl Future<Output = ExitCode>), ExitCode> {
let (config, runtime) = {
let config_path_opt = matches.get_one::<PathBuf>("CONFIG").cloned().or_else(|| {
if !matches.contains_id("SERVER_CONFIG") {
@@ -290,7 +293,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
Ok(c) => c,
Err(err) => {
eprintln!("loading config {config_path:?}, {err}");
return crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into();
return Err(crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into());
}
},
None => ServiceConfig::default(),
@@ -314,7 +317,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
Ok(cfg) => cfg,
Err(err) => {
eprintln!("loading config {cpath:?}, {err}");
return crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into();
return Err(crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into());
}
},
None => Config::new(ConfigType::Server),
@@ -428,7 +431,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
Ok(acl) => acl,
Err(err) => {
eprintln!("loading ACL \"{acl_file}\", {err}");
return crate::EXIT_CODE_LOAD_ACL_FAILURE.into();
return Err(crate::EXIT_CODE_LOAD_ACL_FAILURE.into());
}
};
config.acl = Some(acl);
@@ -479,12 +482,12 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
--server-addr, --encrypt-method, --password command line option, \
or configuration file, check more details in https://shadowsocks.org/guide/configs.html"
);
return crate::EXIT_CODE_INSUFFICIENT_PARAMS.into();
return Err(crate::EXIT_CODE_INSUFFICIENT_PARAMS.into());
}
if let Err(err) = config.check_integrity() {
eprintln!("config integrity check failed, {err}");
return crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into();
return Err(crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into());
}
#[cfg(unix)]
@@ -523,7 +526,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
(config, runtime)
};
runtime.block_on(async move {
let main_fut = async move {
let abort_signal = monitor::create_signal_monitor();
let server = run_server(config);
@@ -544,7 +547,18 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
// The abort signal future resolved. Means we should just exit.
Either::Right(_) => ExitCode::SUCCESS,
}
})
};
Ok((runtime, main_fut))
}
/// Program entrance `main`
#[inline]
pub fn main(matches: &ArgMatches) -> ExitCode {
match create(matches) {
Ok((runtime, main_fut)) => runtime.block_on(main_fut),
Err(code) => code,
}
}
#[cfg(test)]