use std::{ffi::OsString, path::PathBuf};
use structopt::StructOpt;
use crate::{
info_storages::AvailableInfoStores,
notifiers::{Format, Hook},
protocol::extensions::Extensions,
};
use crate::storages::AvailableStores;
#[derive(StructOpt, Debug, Clone)]
pub struct StorageOptions {
#[structopt(long, short, default_value = "file-storage", env = "RUSTUS_STORAGE")]
pub storage: AvailableStores,
#[structopt(long, env = "RUSTUS_DATA_DIR", default_value = "./data")]
pub data_dir: PathBuf,
#[structopt(long, env = "RUSTUS_DIR_STRUCTURE", default_value = "")]
pub dir_structure: String,
#[structopt(long, env = "RUSTUS_FORCE_FSYNC")]
pub force_fsync: bool,
}
#[derive(StructOpt, Debug, Clone)]
pub struct InfoStoreOptions {
#[structopt(
long,
short,
default_value = "file-info-storage",
env = "RUSTUS_INFO_STORAGE"
)]
pub info_storage: AvailableInfoStores,
#[structopt(long, default_value = "./data", env = "RUSTUS_INFO_DIR")]
pub info_dir: PathBuf,
#[cfg(any(feature = "redis_info_storage", feature = "db_info_storage"))]
#[structopt(
long,
required_if("info-storage", "db-info-storage"),
required_if("info-storage", "redis-info-storage"),
env = "RUSTUS_INFO_DB_DSN"
)]
pub info_db_dsn: Option<String>,
}
#[derive(StructOpt, Debug, Clone)]
#[allow(clippy::struct_excessive_bools)]
pub struct NotificationsOptions {
#[structopt(long, default_value = "default", env = "RUSTUS_HOOKS_FORMAT")]
pub hooks_format: Format,
#[structopt(
long,
default_value = "pre-create,post-create,post-receive,pre-terminate,post-terminate,post-finish",
env = "RUSTUS_HOOKS",
use_delimiter = true
)]
pub hooks: Vec<Hook>,
#[structopt(long, env = "RUSTUS_BEHIND_PROXY")]
pub behind_proxy: bool,
#[cfg(feature = "http_notifier")]
#[structopt(long, env = "RUSTUS_HOOKS_HTTP_URLS", use_delimiter = true)]
pub hooks_http_urls: Vec<String>,
#[cfg(feature = "http_notifier")]
#[structopt(long, env = "RUSTUS_HOOKS_HTTP_PROXY_HEADERS", use_delimiter = true)]
pub hooks_http_proxy_headers: Vec<String>,
#[cfg(feature = "amqp_notifier")]
#[structopt(long, env = "RUSTUS_HOOKS_AMQP_URL")]
pub hooks_amqp_url: Option<String>,
#[cfg(feature = "amqp_notifier")]
#[structopt(long, env = "RUSTUS_HOOKS_AMQP_DECLARE_EXCHANGE")]
pub hooks_amqp_declare_exchange: bool,
#[cfg(feature = "amqp_notifier")]
#[structopt(long, env = "RUSTUS_HOOKS_AMQP_DECLARE_QUEUES")]
pub hooks_amqp_declare_queues: bool,
#[cfg(feature = "amqp_notifier")]
#[structopt(long, env = "RUSTUS_HOOKS_AMQP_DURABLE_EXCHANGE")]
pub hooks_amqp_durable_exchange: bool,
#[cfg(feature = "amqp_notifier")]
#[structopt(long, env = "RUSTUS_HOOKS_AMQP_DURABLE_QUEUES")]
pub hooks_amqp_durable_queues: bool,
#[cfg(feature = "amqp_notifier")]
#[structopt(long, env = "RUSTUS_HOOKS_AMQP_CELERY")]
pub hooks_amqp_celery: bool,
#[cfg(feature = "amqp_notifier")]
#[structopt(long, env = "RUSTUS_HOOKS_AMQP_EXCHANGE", default_value = "rustus")]
pub hooks_amqp_exchange: String,
#[cfg(feature = "amqp_notifier")]
#[structopt(long, env = "RUSTUS_HOOKS_AMQP_EXCHANGE_KIND", default_value = "topic")]
pub hooks_amqp_exchange_kind: String,
#[cfg(feature = "amqp_notifier")]
#[structopt(long, env = "RUSTUS_HOOKS_AMQP_ROUTING_KEY")]
pub hooks_amqp_routing_key: Option<String>,
#[cfg(feature = "amqp_notifier")]
#[structopt(
long,
env = "RUSTUS_HOOKS_AMQP_QUEUES_PREFIX",
default_value = "rustus"
)]
pub hooks_amqp_queues_prefix: String,
#[structopt(long, env = "RUSTUS_HOOKS_DIR")]
pub hooks_dir: Option<PathBuf>,
#[structopt(long, env = "RUSTUS_HOOKS_FILE")]
pub hooks_file: Option<String>,
}
#[derive(Debug, StructOpt, Clone)]
#[structopt(name = "Rustus")]
pub struct RustusConf {
#[structopt(short, long, default_value = "0.0.0.0", env = "RUSTUS_SERVER_HOST")]
pub host: String,
#[structopt(short, long, default_value = "1081", env = "RUSTUS_SERVER_PORT")]
pub port: u16,
#[structopt(long, default_value = "/files", env = "RUSTUS_URL")]
pub url: String,
#[structopt(long, env = "RUSTUS_CORS", use_delimiter = true)]
pub cors: Vec<String>,
#[structopt(
long,
short = "mbs",
default_value = "262144",
env = "RUSTUS_MAX_BODY_SIZE"
)]
pub max_body_size: usize,
#[structopt(long, default_value = "INFO", env = "RUSTUS_LOG_LEVEL")]
pub log_level: log::LevelFilter,
#[structopt(long, short, env = "RUSTUS_WORKERS")]
pub workers: Option<usize>,
#[structopt(
long,
default_value = "getting,creation,termination,creation-with-upload,creation-defer-length,concatenation,checksum",
env = "RUSTUS_TUS_EXTENSIONS",
use_delimiter = true
)]
pub tus_extensions: Vec<Extensions>,
#[structopt(long, env = "RUSTUS_REMOVE_PARTS")]
pub remove_parts: bool,
#[structopt(flatten)]
pub storage_opts: StorageOptions,
#[structopt(flatten)]
pub info_storage_opts: InfoStoreOptions,
#[structopt(flatten)]
pub notification_opts: NotificationsOptions,
}
#[cfg_attr(coverage, no_coverage)]
impl RustusConf {
pub fn from_args() -> RustusConf {
<RustusConf as StructOpt>::from_args()
}
pub fn from_iter<I>(iter: I) -> RustusConf
where
I: IntoIterator,
I::Item: Into<OsString> + Clone,
{
<RustusConf as StructOpt>::from_iter(iter)
}
pub fn base_url(&self) -> String {
let stripped_prefix = self.url.strip_prefix('/').unwrap_or(self.url.as_str());
String::from(stripped_prefix.strip_suffix('/').unwrap_or(stripped_prefix))
}
#[cfg(test)]
pub fn file_url(&self, file_id: &str) -> String {
format!("/{}/{}/", self.base_url(), file_id)
}
#[cfg(test)]
pub fn test_url(&self) -> String {
format!("/{}/", self.base_url())
}
pub fn hook_is_active(&self, hook: Hook) -> bool {
self.notification_opts.hooks.contains(&hook)
}
pub fn extensions_vec(&self) -> Vec<Extensions> {
let mut ext = self.tus_extensions.clone();
if ext.contains(&Extensions::CreationWithUpload) && !ext.contains(&Extensions::Creation) {
ext.push(Extensions::Creation);
}
if ext.contains(&Extensions::CreationDeferLength) && !ext.contains(&Extensions::Creation) {
ext.push(Extensions::Creation);
}
ext.sort();
ext
}
}