mirror of
https://github.com/shadowsocks/shadowsocks-rust.git
synced 2026-02-09 01:59:16 +08:00
"log" and "runtime" specific options configurable in file (#702)
This commit is contained in:
3
Cargo.lock
generated
3
Cargo.lock
generated
@@ -1679,15 +1679,18 @@ dependencies = [
|
||||
"futures",
|
||||
"ipnet",
|
||||
"jemallocator",
|
||||
"json5",
|
||||
"log",
|
||||
"log4rs",
|
||||
"mimalloc",
|
||||
"qrcode",
|
||||
"rpassword",
|
||||
"rpmalloc",
|
||||
"serde",
|
||||
"shadowsocks-service",
|
||||
"snmalloc-rs",
|
||||
"tcmalloc",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"xdg",
|
||||
]
|
||||
|
||||
@@ -130,6 +130,9 @@ replay-attack-detect = ["shadowsocks-service/replay-attack-detect"]
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
log4rs = { version = "1.0", optional = true }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
json5 = "0.4"
|
||||
thiserror = "1.0"
|
||||
|
||||
clap = { version = "2", features = ["wrap_help", "suggestions"] }
|
||||
cfg-if = "1"
|
||||
|
||||
24
README.md
24
README.md
@@ -585,16 +585,34 @@ Example configuration:
|
||||
"max_server_rtt": 5,
|
||||
// Interval seconds between each check
|
||||
"check_interval": 10,
|
||||
},
|
||||
|
||||
// Service configurations
|
||||
// Logger configuration
|
||||
"log": {
|
||||
// Equivalent to `-v` command line option
|
||||
"level": 1,
|
||||
"format": {
|
||||
// Euiqvalent to `--log-without-time`
|
||||
"without_time": false,
|
||||
},
|
||||
// Equivalent to `--log-config`
|
||||
// More detail could be found in https://crates.io/crates/log4rs
|
||||
"config_path": "/path/to/log4rs/config.yaml"
|
||||
},
|
||||
// Runtime configuration
|
||||
"runtime": {
|
||||
// single_thread or multi_thread
|
||||
"mode": "multi_thread",
|
||||
// Worker threads that are used in multi-thread runtime
|
||||
"worker_count": 10
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
- `SS_LOG_VERBOSE_LEVEL`: Logging level for binaries (`sslocal`, `ssserver` and `ssmanager`). It is valid only when command line argument `-v` is not applied. Example: `SS_LOG_VERBOSE_LEVEL=1`
|
||||
- `SS_LOG_WITHOUT_TIME`: Logging format for binaries (`sslocal`, `ssserver` and `ssmanager`). It is valid only when command line argument `--log-without-time` is not applied. Example `SS_LOG_WITHOUT_TIME=1`
|
||||
- `SS_SERVER_PASSWORD`: A default password for servers that created from command line argument (`--server-addr`)
|
||||
- `SS_SERVER_${SERVER_ADDR}_PASSWORD`: A default password for server with address `$SERVER_ADDR` that created from command line argument (`--server-addr`)
|
||||
|
||||
## Supported Ciphers
|
||||
|
||||
|
||||
251
src/config.rs
251
src/config.rs
@@ -1,9 +1,17 @@
|
||||
//! Common configuration utilities
|
||||
|
||||
use std::{
|
||||
env,
|
||||
fs::OpenOptions,
|
||||
io::{self, Read},
|
||||
path::{Path, PathBuf},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use clap::{ArgMatches, ErrorKind as ClapErrorKind};
|
||||
use directories::ProjectDirs;
|
||||
#[cfg(unix)]
|
||||
use std::path::Path;
|
||||
use std::{env, path::PathBuf};
|
||||
use serde::Deserialize;
|
||||
|
||||
/// Default configuration file path
|
||||
pub fn get_default_config_path() -> Option<PathBuf> {
|
||||
@@ -59,3 +67,240 @@ pub fn get_default_config_path() -> Option<PathBuf> {
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Error while reading `Config`
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum ConfigError {
|
||||
/// Input/Output error
|
||||
#[error("{0}")]
|
||||
IoError(#[from] io::Error),
|
||||
/// JSON parsing error
|
||||
#[error("{0}")]
|
||||
JsonError(#[from] json5::Error),
|
||||
/// Invalid value
|
||||
#[error("Invalid value: {0}")]
|
||||
InvalidValue(String),
|
||||
}
|
||||
|
||||
/// Configuration Options for shadowsocks service runnables
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Config {
|
||||
/// Logger configuration
|
||||
#[cfg(feature = "logging")]
|
||||
pub log: LogConfig,
|
||||
|
||||
/// Runtime configuration
|
||||
pub runtime: RuntimeConfig,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Load `Config` from file
|
||||
pub fn load_from_file<P: AsRef<Path>>(filename: &P) -> Result<Config, ConfigError> {
|
||||
let filename = filename.as_ref();
|
||||
|
||||
let mut reader = OpenOptions::new().read(true).open(filename)?;
|
||||
let mut content = String::new();
|
||||
reader.read_to_string(&mut content)?;
|
||||
|
||||
Config::load_from_str(&content)
|
||||
}
|
||||
|
||||
/// Load `Config` from string
|
||||
pub fn load_from_str(s: &str) -> Result<Config, ConfigError> {
|
||||
let ssconfig = json5::from_str(s)?;
|
||||
Config::load_from_ssconfig(ssconfig)
|
||||
}
|
||||
|
||||
fn load_from_ssconfig(ssconfig: SSConfig) -> Result<Config, ConfigError> {
|
||||
let mut config = Config::default();
|
||||
|
||||
#[cfg(feature = "logging")]
|
||||
if let Some(log) = ssconfig.log {
|
||||
let mut nlog = LogConfig::default();
|
||||
if let Some(level) = log.level {
|
||||
nlog.level = level;
|
||||
}
|
||||
|
||||
if let Some(format) = log.format {
|
||||
let mut nformat = LogFormatConfig::default();
|
||||
if let Some(without_time) = format.without_time {
|
||||
nformat.without_time = without_time;
|
||||
}
|
||||
nlog.format = nformat;
|
||||
}
|
||||
|
||||
if let Some(config_path) = log.config_path {
|
||||
nlog.config_path = Some(PathBuf::from(config_path));
|
||||
}
|
||||
|
||||
config.log = nlog;
|
||||
}
|
||||
|
||||
if let Some(runtime) = ssconfig.runtime {
|
||||
let mut nruntime = RuntimeConfig::default();
|
||||
|
||||
#[cfg(feature = "multi-threaded")]
|
||||
if let Some(worker_count) = runtime.worker_count {
|
||||
nruntime.worker_count = Some(worker_count);
|
||||
}
|
||||
|
||||
if let Some(mode) = runtime.mode {
|
||||
match mode.parse::<RuntimeMode>() {
|
||||
Ok(m) => nruntime.mode = m,
|
||||
Err(..) => return Err(ConfigError::InvalidValue(mode)),
|
||||
}
|
||||
}
|
||||
|
||||
config.runtime = nruntime;
|
||||
}
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
/// Set by command line options
|
||||
pub fn set_options(&mut self, matches: &ArgMatches<'_>) {
|
||||
#[cfg(feature = "logging")]
|
||||
{
|
||||
let debug_level = matches.occurrences_of("VERBOSE");
|
||||
if debug_level > 0 {
|
||||
self.log.level = debug_level as u32;
|
||||
}
|
||||
|
||||
if matches.is_present("LOG_WITHOUT_TIME") {
|
||||
self.log.format.without_time = true;
|
||||
}
|
||||
|
||||
if let Some(log_config) = matches.value_of("LOG_CONFIG") {
|
||||
self.log.config_path = Some(log_config.into());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "multi-threaded")]
|
||||
if matches.is_present("SINGLE_THREADED") {
|
||||
self.runtime.mode = RuntimeMode::SingleThread;
|
||||
}
|
||||
|
||||
#[cfg(feature = "multi-threaded")]
|
||||
match clap::value_t!(matches.value_of("WORKER_THREADS"), usize) {
|
||||
Ok(worker_count) => self.runtime.worker_count = Some(worker_count),
|
||||
Err(ref err) if err.kind == ClapErrorKind::ArgumentNotFound => {}
|
||||
Err(err) => err.exit(),
|
||||
}
|
||||
|
||||
let _ = matches;
|
||||
}
|
||||
}
|
||||
|
||||
/// Logger configuration
|
||||
#[cfg(feature = "logging")]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LogConfig {
|
||||
/// Default logger log level, [0, 3]
|
||||
pub level: u32,
|
||||
/// Default logger format configuration
|
||||
pub format: LogFormatConfig,
|
||||
/// Logging configuration file path
|
||||
pub config_path: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "logging")]
|
||||
impl Default for LogConfig {
|
||||
fn default() -> LogConfig {
|
||||
LogConfig {
|
||||
level: 0,
|
||||
format: LogFormatConfig::default(),
|
||||
config_path: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Logger format configuration
|
||||
#[cfg(feature = "logging")]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LogFormatConfig {
|
||||
pub without_time: bool,
|
||||
}
|
||||
|
||||
#[cfg(feature = "logging")]
|
||||
impl Default for LogFormatConfig {
|
||||
fn default() -> LogFormatConfig {
|
||||
LogFormatConfig { without_time: false }
|
||||
}
|
||||
}
|
||||
|
||||
/// Runtime mode (Tokio)
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum RuntimeMode {
|
||||
/// Single-Thread Runtime
|
||||
SingleThread,
|
||||
/// Multi-Thread Runtime
|
||||
#[cfg(feature = "multi-threaded")]
|
||||
MultiThread,
|
||||
}
|
||||
|
||||
impl Default for RuntimeMode {
|
||||
fn default() -> RuntimeMode {
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "multi-threaded")] {
|
||||
RuntimeMode::MultiThread
|
||||
} else {
|
||||
RuntimeMode::SingleThread
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse `RuntimeMode` from string error
|
||||
#[derive(Debug)]
|
||||
pub struct RuntimeModeError;
|
||||
|
||||
impl FromStr for RuntimeMode {
|
||||
type Err = RuntimeModeError;
|
||||
|
||||
fn from_str(s: &str) -> Result<RuntimeMode, Self::Err> {
|
||||
match s {
|
||||
"single_thread" => Ok(RuntimeMode::SingleThread),
|
||||
#[cfg(feature = "multi-threaded")]
|
||||
"multi_thread" => Ok(RuntimeMode::MultiThread),
|
||||
_ => Err(RuntimeModeError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Runtime configuration
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct RuntimeConfig {
|
||||
/// Multithread runtime worker count, CPU count if not configured
|
||||
#[cfg(feature = "multi-threaded")]
|
||||
pub worker_count: Option<usize>,
|
||||
/// Runtime Mode, single-thread, multi-thread
|
||||
pub mode: RuntimeMode,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct SSConfig {
|
||||
#[cfg(feature = "logging")]
|
||||
log: Option<SSLogConfig>,
|
||||
runtime: Option<SSRuntimeConfig>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "logging")]
|
||||
#[derive(Deserialize)]
|
||||
struct SSLogConfig {
|
||||
level: Option<u32>,
|
||||
format: Option<SSLogFormat>,
|
||||
config_path: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "logging")]
|
||||
#[derive(Deserialize)]
|
||||
struct SSLogFormat {
|
||||
without_time: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct SSRuntimeConfig {
|
||||
#[cfg(feature = "multi-threaded")]
|
||||
worker_count: Option<usize>,
|
||||
mode: Option<String>,
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
//! Logging facilities
|
||||
|
||||
use std::{env, path::Path};
|
||||
use std::path::Path;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use log::LevelFilter;
|
||||
use log4rs::{
|
||||
append::console::{ConsoleAppender, Target},
|
||||
@@ -10,6 +9,8 @@ use log4rs::{
|
||||
encode::pattern::PatternEncoder,
|
||||
};
|
||||
|
||||
use crate::config::LogConfig;
|
||||
|
||||
/// Initialize logger ([log4rs](https://crates.io/crates/log4rs)) from yaml configuration file
|
||||
pub fn init_with_file<P>(path: P)
|
||||
where
|
||||
@@ -19,25 +20,9 @@ where
|
||||
}
|
||||
|
||||
/// Initialize logger with default configuration
|
||||
pub fn init_with_config(bin_name: &str, matches: &ArgMatches) {
|
||||
let mut debug_level = matches.occurrences_of("VERBOSE");
|
||||
if debug_level == 0 {
|
||||
// Override by SS_LOG_VERBOSE_LEVEL
|
||||
if let Ok(verbose_level) = env::var("SS_LOG_VERBOSE_LEVEL") {
|
||||
if let Ok(verbose_level) = verbose_level.parse::<u64>() {
|
||||
debug_level = verbose_level;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut without_time = matches.is_present("LOG_WITHOUT_TIME");
|
||||
if !without_time {
|
||||
if let Ok(log_without_time) = env::var("SS_LOG_WITHOUT_TIME") {
|
||||
if let Ok(log_without_time) = log_without_time.parse::<u32>() {
|
||||
without_time = log_without_time != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn init_with_config(bin_name: &str, config: &LogConfig) {
|
||||
let debug_level = config.level;
|
||||
let without_time = config.format.without_time;
|
||||
|
||||
let mut pattern = String::new();
|
||||
if !without_time {
|
||||
@@ -92,3 +77,8 @@ pub fn init_with_config(bin_name: &str, matches: &ArgMatches) {
|
||||
|
||||
log4rs::init_config(config).expect("logging");
|
||||
}
|
||||
|
||||
/// Init a default logger
|
||||
pub fn init_with_default(bin_name: &str) {
|
||||
init_with_config(bin_name, &LogConfig::default());
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::{net::IpAddr, path::PathBuf, process, time::Duration};
|
||||
|
||||
use clap::{clap_app, App, Arg, ArgMatches, ErrorKind as ClapErrorKind};
|
||||
use futures::future::{self, Either};
|
||||
use log::info;
|
||||
use log::{info, trace};
|
||||
use tokio::{self, runtime::Builder};
|
||||
|
||||
#[cfg(feature = "local-redir")]
|
||||
@@ -25,7 +25,11 @@ use shadowsocks_service::{
|
||||
|
||||
#[cfg(feature = "logging")]
|
||||
use crate::logging;
|
||||
use crate::{monitor, validator};
|
||||
use crate::{
|
||||
config::{Config as ServiceConfig, RuntimeMode},
|
||||
monitor,
|
||||
validator,
|
||||
};
|
||||
|
||||
/// Defines command line options
|
||||
pub fn define_command_line_options<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
|
||||
@@ -189,22 +193,12 @@ pub fn define_command_line_options<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
|
||||
/// Program entrance `main`
|
||||
pub fn main(matches: &ArgMatches<'_>) {
|
||||
let (config, runtime) = {
|
||||
#[cfg(feature = "logging")]
|
||||
match matches.value_of("LOG_CONFIG") {
|
||||
Some(path) => {
|
||||
logging::init_with_file(path);
|
||||
}
|
||||
None => {
|
||||
logging::init_with_config("sslocal", matches);
|
||||
}
|
||||
}
|
||||
|
||||
let config_path_opt = matches.value_of("CONFIG").map(PathBuf::from).or_else(|| {
|
||||
if !matches.is_present("SERVER_CONFIG") {
|
||||
match crate::config::get_default_config_path() {
|
||||
None => None,
|
||||
Some(p) => {
|
||||
info!("loading default config from {:?}", p);
|
||||
println!("loading default config {:?}", p);
|
||||
Some(p)
|
||||
}
|
||||
}
|
||||
@@ -213,6 +207,30 @@ pub fn main(matches: &ArgMatches<'_>) {
|
||||
}
|
||||
});
|
||||
|
||||
let mut service_config = match config_path_opt {
|
||||
Some(ref config_path) => match ServiceConfig::load_from_file(config_path) {
|
||||
Ok(c) => c,
|
||||
Err(err) => {
|
||||
eprintln!("loading config {:?}, {}", config_path, err);
|
||||
process::exit(crate::EXIT_CODE_LOAD_CONFIG_FAILURE);
|
||||
}
|
||||
},
|
||||
None => ServiceConfig::default(),
|
||||
};
|
||||
service_config.set_options(&matches);
|
||||
|
||||
#[cfg(feature = "logging")]
|
||||
match service_config.log.config_path {
|
||||
Some(ref path) => {
|
||||
logging::init_with_file(path);
|
||||
}
|
||||
None => {
|
||||
logging::init_with_config("sslocal", &service_config.log);
|
||||
}
|
||||
}
|
||||
|
||||
trace!("{:?}", service_config);
|
||||
|
||||
let mut config = match config_path_opt {
|
||||
Some(cpath) => match Config::load_from_file(&cpath, ConfigType::Local) {
|
||||
Ok(cfg) => cfg,
|
||||
@@ -563,22 +581,18 @@ pub fn main(matches: &ArgMatches<'_>) {
|
||||
|
||||
info!("shadowsocks local {} build {}", crate::VERSION, crate::BUILD_TIME);
|
||||
|
||||
#[cfg(feature = "multi-threaded")]
|
||||
let mut builder = if matches.is_present("SINGLE_THREADED") {
|
||||
Builder::new_current_thread()
|
||||
} else {
|
||||
let mut builder = Builder::new_multi_thread();
|
||||
match clap::value_t!(matches.value_of("WORKER_THREADS"), usize) {
|
||||
Ok(worker_threads) => {
|
||||
let mut builder = match service_config.runtime.mode {
|
||||
RuntimeMode::SingleThread => Builder::new_current_thread(),
|
||||
#[cfg(feature = "multi-threaded")]
|
||||
RuntimeMode::MultiThread => {
|
||||
let mut builder = Builder::new_multi_thread();
|
||||
if let Some(worker_threads) = service_config.runtime.worker_count {
|
||||
builder.worker_threads(worker_threads);
|
||||
}
|
||||
Err(ref err) if err.kind == ClapErrorKind::ArgumentNotFound => {}
|
||||
Err(err) => err.exit(),
|
||||
|
||||
builder
|
||||
}
|
||||
builder
|
||||
};
|
||||
#[cfg(not(feature = "multi-threaded"))]
|
||||
let mut builder = Builder::new_current_thread();
|
||||
|
||||
let runtime = builder.enable_all().build().expect("create tokio Runtime");
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::{net::IpAddr, path::PathBuf, process, time::Duration};
|
||||
|
||||
use clap::{clap_app, App, Arg, ArgMatches, ErrorKind as ClapErrorKind};
|
||||
use futures::future::{self, Either};
|
||||
use log::info;
|
||||
use log::{info, trace};
|
||||
use tokio::{self, runtime::Builder};
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -22,7 +22,11 @@ use shadowsocks_service::{
|
||||
|
||||
#[cfg(feature = "logging")]
|
||||
use crate::logging;
|
||||
use crate::{monitor, validator};
|
||||
use crate::{
|
||||
config::{Config as ServiceConfig, RuntimeMode},
|
||||
monitor,
|
||||
validator,
|
||||
};
|
||||
|
||||
/// Defines command line options
|
||||
pub fn define_command_line_options<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
|
||||
@@ -117,22 +121,12 @@ pub fn define_command_line_options<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
|
||||
/// Program entrance `main`
|
||||
pub fn main(matches: &ArgMatches<'_>) {
|
||||
let (config, runtime) = {
|
||||
#[cfg(feature = "logging")]
|
||||
match matches.value_of("LOG_CONFIG") {
|
||||
Some(path) => {
|
||||
logging::init_with_file(path);
|
||||
}
|
||||
None => {
|
||||
logging::init_with_config("ssmanager", matches);
|
||||
}
|
||||
}
|
||||
|
||||
let config_path_opt = matches.value_of("CONFIG").map(PathBuf::from).or_else(|| {
|
||||
if !matches.is_present("SERVER_CONFIG") {
|
||||
match crate::config::get_default_config_path() {
|
||||
None => None,
|
||||
Some(p) => {
|
||||
info!("loading default config from {:?}", p);
|
||||
println!("loading default config {:?}", p);
|
||||
Some(p)
|
||||
}
|
||||
}
|
||||
@@ -141,6 +135,30 @@ pub fn main(matches: &ArgMatches<'_>) {
|
||||
}
|
||||
});
|
||||
|
||||
let mut service_config = match config_path_opt {
|
||||
Some(ref config_path) => match ServiceConfig::load_from_file(config_path) {
|
||||
Ok(c) => c,
|
||||
Err(err) => {
|
||||
eprintln!("loading config {:?}, {}", config_path, err);
|
||||
process::exit(crate::EXIT_CODE_LOAD_CONFIG_FAILURE);
|
||||
}
|
||||
},
|
||||
None => ServiceConfig::default(),
|
||||
};
|
||||
service_config.set_options(&matches);
|
||||
|
||||
#[cfg(feature = "logging")]
|
||||
match service_config.log.config_path {
|
||||
Some(ref path) => {
|
||||
logging::init_with_file(path);
|
||||
}
|
||||
None => {
|
||||
logging::init_with_config("sslocal", &service_config.log);
|
||||
}
|
||||
}
|
||||
|
||||
trace!("{:?}", service_config);
|
||||
|
||||
let mut config = match config_path_opt {
|
||||
Some(cpath) => match Config::load_from_file(&cpath, ConfigType::Manager) {
|
||||
Ok(cfg) => cfg,
|
||||
@@ -336,18 +354,18 @@ pub fn main(matches: &ArgMatches<'_>) {
|
||||
|
||||
info!("shadowsocks manager {} build {}", crate::VERSION, crate::BUILD_TIME);
|
||||
|
||||
#[cfg(feature = "multi-threaded")]
|
||||
let mut builder = if matches.is_present("SINGLE_THREADED") {
|
||||
Builder::new_current_thread()
|
||||
} else {
|
||||
let mut builder = Builder::new_multi_thread();
|
||||
if let Some(worker_threads) = matches.value_of("WORKER_THREADS") {
|
||||
builder.worker_threads(worker_threads.parse::<usize>().expect("worker-threads"));
|
||||
let mut builder = match service_config.runtime.mode {
|
||||
RuntimeMode::SingleThread => Builder::new_current_thread(),
|
||||
#[cfg(feature = "multi-threaded")]
|
||||
RuntimeMode::MultiThread => {
|
||||
let mut builder = Builder::new_multi_thread();
|
||||
if let Some(worker_threads) = service_config.runtime.worker_count {
|
||||
builder.worker_threads(worker_threads);
|
||||
}
|
||||
|
||||
builder
|
||||
}
|
||||
builder
|
||||
};
|
||||
#[cfg(not(feature = "multi-threaded"))]
|
||||
let mut builder = Builder::new_current_thread();
|
||||
|
||||
let runtime = builder.enable_all().build().expect("create tokio Runtime");
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::{net::IpAddr, path::PathBuf, process, time::Duration};
|
||||
|
||||
use clap::{clap_app, App, Arg, ArgMatches, ErrorKind as ClapErrorKind};
|
||||
use futures::future::{self, Either};
|
||||
use log::info;
|
||||
use log::{info, trace};
|
||||
use tokio::{self, runtime::Builder};
|
||||
|
||||
use shadowsocks_service::{
|
||||
@@ -20,7 +20,11 @@ use shadowsocks_service::{
|
||||
|
||||
#[cfg(feature = "logging")]
|
||||
use crate::logging;
|
||||
use crate::{monitor, validator};
|
||||
use crate::{
|
||||
config::{Config as ServiceConfig, RuntimeMode},
|
||||
monitor,
|
||||
validator,
|
||||
};
|
||||
|
||||
/// Defines command line options
|
||||
pub fn define_command_line_options<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
|
||||
@@ -110,22 +114,12 @@ pub fn define_command_line_options<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
|
||||
/// Program entrance `main`
|
||||
pub fn main(matches: &ArgMatches<'_>) {
|
||||
let (config, runtime) = {
|
||||
#[cfg(feature = "logging")]
|
||||
match matches.value_of("LOG_CONFIG") {
|
||||
Some(path) => {
|
||||
logging::init_with_file(path);
|
||||
}
|
||||
None => {
|
||||
logging::init_with_config("ssserver", matches);
|
||||
}
|
||||
}
|
||||
|
||||
let config_path_opt = matches.value_of("CONFIG").map(PathBuf::from).or_else(|| {
|
||||
if !matches.is_present("SERVER_CONFIG") {
|
||||
match crate::config::get_default_config_path() {
|
||||
None => None,
|
||||
Some(p) => {
|
||||
info!("loading default config from {:?}", p);
|
||||
println!("loading default config {:?}", p);
|
||||
Some(p)
|
||||
}
|
||||
}
|
||||
@@ -134,6 +128,30 @@ pub fn main(matches: &ArgMatches<'_>) {
|
||||
}
|
||||
});
|
||||
|
||||
let mut service_config = match config_path_opt {
|
||||
Some(ref config_path) => match ServiceConfig::load_from_file(config_path) {
|
||||
Ok(c) => c,
|
||||
Err(err) => {
|
||||
eprintln!("loading config {:?}, {}", config_path, err);
|
||||
process::exit(crate::EXIT_CODE_LOAD_CONFIG_FAILURE);
|
||||
}
|
||||
},
|
||||
None => ServiceConfig::default(),
|
||||
};
|
||||
service_config.set_options(&matches);
|
||||
|
||||
#[cfg(feature = "logging")]
|
||||
match service_config.log.config_path {
|
||||
Some(ref path) => {
|
||||
logging::init_with_file(path);
|
||||
}
|
||||
None => {
|
||||
logging::init_with_config("sslocal", &service_config.log);
|
||||
}
|
||||
}
|
||||
|
||||
trace!("{:?}", service_config);
|
||||
|
||||
let mut config = match config_path_opt {
|
||||
Some(cpath) => match Config::load_from_file(&cpath, ConfigType::Server) {
|
||||
Ok(cfg) => cfg,
|
||||
@@ -324,24 +342,18 @@ pub fn main(matches: &ArgMatches<'_>) {
|
||||
|
||||
info!("shadowsocks server {} build {}", crate::VERSION, crate::BUILD_TIME);
|
||||
|
||||
#[cfg(feature = "multi-threaded")]
|
||||
let mut builder = if matches.is_present("SINGLE_THREADED") {
|
||||
Builder::new_current_thread()
|
||||
} else {
|
||||
let mut builder = Builder::new_multi_thread();
|
||||
|
||||
match clap::value_t!(matches.value_of("WORKER_THREADS"), usize) {
|
||||
Ok(worker_threads) => {
|
||||
let mut builder = match service_config.runtime.mode {
|
||||
RuntimeMode::SingleThread => Builder::new_current_thread(),
|
||||
#[cfg(feature = "multi-threaded")]
|
||||
RuntimeMode::MultiThread => {
|
||||
let mut builder = Builder::new_multi_thread();
|
||||
if let Some(worker_threads) = service_config.runtime.worker_count {
|
||||
builder.worker_threads(worker_threads);
|
||||
}
|
||||
Err(ref err) if err.kind == ClapErrorKind::ArgumentNotFound => {}
|
||||
Err(err) => err.exit(),
|
||||
}
|
||||
|
||||
builder
|
||||
builder
|
||||
}
|
||||
};
|
||||
#[cfg(not(feature = "multi-threaded"))]
|
||||
let mut builder = Builder::new_current_thread();
|
||||
|
||||
let runtime = builder.enable_all().build().expect("create tokio Runtime");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user