use crate::{
config::primitives::{AudioCodec, ImageFormat, LogFormat, Targets, VideoCodec},
serde_str::Serde,
};
use clap::{Parser, Subcommand};
use std::{net::SocketAddr, path::PathBuf};
use url::Url;
impl Args {
pub(super) fn into_output(self) -> Output {
let Args {
config_file,
old_db_path,
log_format,
log_targets,
console_address,
console_buffer_capacity,
opentelemetry_url,
opentelemetry_service_name,
opentelemetry_targets,
save_to,
command,
} = self;
let old_db = OldDb { path: old_db_path };
let tracing = Tracing {
logging: Logging {
format: log_format,
targets: log_targets.map(Serde::new),
},
console: Console {
address: console_address,
buffer_capacity: console_buffer_capacity,
},
opentelemetry: OpenTelemetry {
url: opentelemetry_url,
service_name: opentelemetry_service_name,
targets: opentelemetry_targets.map(Serde::new),
},
};
match command {
Command::Run(Run {
address,
api_key,
worker_id,
media_preprocess_steps,
media_skip_validate_imports,
media_max_width,
media_max_height,
media_max_area,
media_max_file_size,
media_max_frame_count,
media_enable_silent_video,
media_enable_full_video,
media_video_codec,
media_audio_codec,
media_filters,
media_format,
media_cache_duration,
store,
}) => {
let server = Server {
address,
api_key,
worker_id,
};
let media = Media {
preprocess_steps: media_preprocess_steps,
skip_validate_imports: media_skip_validate_imports,
max_width: media_max_width,
max_height: media_max_height,
max_area: media_max_area,
max_file_size: media_max_file_size,
max_frame_count: media_max_frame_count,
enable_silent_video: media_enable_silent_video,
enable_full_video: media_enable_full_video,
video_codec: media_video_codec,
audio_codec: media_audio_codec,
filters: media_filters,
format: media_format,
cache_duration: media_cache_duration,
};
let operation = Operation::Run;
match store {
Some(RunStore::Filesystem(RunFilesystem { system, repo })) => {
let store = Some(Store::Filesystem(system));
Output {
config_format: ConfigFormat {
server,
old_db,
tracing,
media,
store,
repo,
},
operation,
config_file,
save_to,
}
}
Some(RunStore::ObjectStorage(RunObjectStorage { storage, repo })) => {
let store = Some(Store::ObjectStorage(storage));
Output {
config_format: ConfigFormat {
server,
old_db,
tracing,
media,
store,
repo,
},
operation,
config_file,
save_to,
}
}
None => Output {
config_format: ConfigFormat {
server,
old_db,
tracing,
media,
store: None,
repo: None,
},
operation,
config_file,
save_to,
},
}
}
Command::MigrateStore(migrate_store) => {
let server = Server::default();
let media = Media::default();
match migrate_store {
MigrateStore::Filesystem(MigrateFilesystem { from, to }) => match to {
MigrateStoreInner::Filesystem(MigrateFilesystemInner { to, repo }) => {
Output {
config_format: ConfigFormat {
server,
old_db,
tracing,
media,
store: None,
repo,
},
operation: Operation::MigrateStore {
from: from.into(),
to: to.into(),
},
config_file,
save_to,
}
}
MigrateStoreInner::ObjectStorage(MigrateObjectStorageInner {
to,
repo,
}) => Output {
config_format: ConfigFormat {
server,
old_db,
tracing,
media,
store: None,
repo,
},
operation: Operation::MigrateStore {
from: from.into(),
to: to.into(),
},
config_file,
save_to,
},
},
MigrateStore::ObjectStorage(MigrateObjectStorage { from, to }) => match to {
MigrateStoreInner::Filesystem(MigrateFilesystemInner { to, repo }) => {
Output {
config_format: ConfigFormat {
server,
old_db,
tracing,
media,
store: None,
repo,
},
operation: Operation::MigrateStore {
from: from.into(),
to: to.into(),
},
config_file,
save_to,
}
}
MigrateStoreInner::ObjectStorage(MigrateObjectStorageInner {
to,
repo,
}) => Output {
config_format: ConfigFormat {
server,
old_db,
tracing,
media,
store: None,
repo,
},
operation: Operation::MigrateStore {
from: from.into(),
to: to.into(),
},
config_file,
save_to,
},
},
}
}
}
}
}
pub(super) struct Output {
pub(super) config_format: ConfigFormat,
pub(super) operation: Operation,
pub(super) save_to: Option<PathBuf>,
pub(super) config_file: Option<PathBuf>,
}
#[allow(clippy::large_enum_variant)]
#[derive(Clone)]
pub(crate) enum Operation {
Run,
MigrateStore {
from: crate::config::primitives::Store,
to: crate::config::primitives::Store,
},
}
#[derive(Debug, Default, serde::Serialize)]
#[serde(rename_all = "snake_case")]
pub(super) struct ConfigFormat {
server: Server,
old_db: OldDb,
tracing: Tracing,
media: Media,
#[serde(skip_serializing_if = "Option::is_none")]
repo: Option<Repo>,
#[serde(skip_serializing_if = "Option::is_none")]
store: Option<Store>,
}
#[derive(Debug, Default, serde::Serialize)]
#[serde(rename_all = "snake_case")]
struct Server {
#[serde(skip_serializing_if = "Option::is_none")]
address: Option<SocketAddr>,
#[serde(skip_serializing_if = "Option::is_none")]
worker_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
api_key: Option<String>,
}
#[derive(Debug, Default, serde::Serialize)]
#[serde(rename_all = "snake_case")]
struct Tracing {
logging: Logging,
console: Console,
opentelemetry: OpenTelemetry,
}
#[derive(Debug, Default, serde::Serialize)]
#[serde(rename_all = "snake_case")]
struct Logging {
#[serde(skip_serializing_if = "Option::is_none")]
format: Option<LogFormat>,
#[serde(skip_serializing_if = "Option::is_none")]
targets: Option<Serde<Targets>>,
}
#[derive(Debug, Default, serde::Serialize)]
#[serde(rename_all = "snake_case")]
struct Console {
#[serde(skip_serializing_if = "Option::is_none")]
address: Option<SocketAddr>,
#[serde(skip_serializing_if = "Option::is_none")]
buffer_capacity: Option<usize>,
}
#[derive(Debug, Default, serde::Serialize)]
#[serde(rename_all = "snake_case")]
struct OpenTelemetry {
#[serde(skip_serializing_if = "Option::is_none")]
url: Option<Url>,
#[serde(skip_serializing_if = "Option::is_none")]
service_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
targets: Option<Serde<Targets>>,
}
#[derive(Debug, Default, serde::Serialize)]
#[serde(rename_all = "snake_case")]
struct OldDb {
#[serde(skip_serializing_if = "Option::is_none")]
path: Option<PathBuf>,
}
#[derive(Debug, Default, serde::Serialize)]
#[serde(rename_all = "snake_case")]
struct Media {
#[serde(skip_serializing_if = "Option::is_none")]
preprocess_steps: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
max_width: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
max_height: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
max_area: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
max_file_size: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
max_frame_count: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
enable_silent_video: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
enable_full_video: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
video_codec: Option<VideoCodec>,
#[serde(skip_serializing_if = "Option::is_none")]
audio_codec: Option<AudioCodec>,
#[serde(skip_serializing_if = "Option::is_none")]
filters: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
format: Option<ImageFormat>,
#[serde(skip_serializing_if = "Option::is_none")]
skip_validate_imports: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
cache_duration: Option<i64>,
}
#[derive(Debug, Parser)]
#[command(author, version, about, long_about = None)]
pub(super) struct Args {
#[arg(short, long)]
config_file: Option<PathBuf>,
#[arg(long)]
old_db_path: Option<PathBuf>,
#[arg(long)]
log_format: Option<LogFormat>,
#[arg(long)]
log_targets: Option<Targets>,
#[arg(long)]
console_address: Option<SocketAddr>,
#[arg(long)]
console_buffer_capacity: Option<usize>,
#[arg(long)]
opentelemetry_url: Option<Url>,
#[arg(long)]
opentelemetry_service_name: Option<String>,
#[arg(long)]
opentelemetry_targets: Option<Targets>,
#[arg(long)]
save_to: Option<PathBuf>,
#[command(subcommand)]
command: Command,
}
#[derive(Debug, Subcommand)]
enum Command {
Run(Run),
#[command(flatten)]
MigrateStore(MigrateStore),
}
#[derive(Debug, Parser)]
struct Run {
#[arg(short, long)]
address: Option<SocketAddr>,
#[arg(long)]
api_key: Option<String>,
#[arg(long)]
worker_id: Option<String>,
#[arg(long)]
media_preprocess_steps: Option<String>,
#[arg(long)]
media_skip_validate_imports: Option<bool>,
#[arg(long)]
media_max_width: Option<usize>,
#[arg(long)]
media_max_height: Option<usize>,
#[arg(long)]
media_max_area: Option<usize>,
#[arg(long)]
media_max_file_size: Option<usize>,
#[arg(long)]
media_max_frame_count: Option<usize>,
#[arg(long)]
media_enable_silent_video: Option<bool>,
#[arg(long)]
media_enable_full_video: Option<bool>,
#[arg(long)]
media_video_codec: Option<VideoCodec>,
#[arg(long)]
media_audio_codec: Option<AudioCodec>,
#[arg(long)]
media_filters: Option<Vec<String>>,
#[arg(long)]
media_format: Option<ImageFormat>,
#[arg(long)]
media_cache_duration: Option<i64>,
#[command(subcommand)]
store: Option<RunStore>,
}
#[derive(Clone, Debug, Subcommand, serde::Serialize)]
#[serde(rename_all = "snake_case")]
#[serde(tag = "type")]
enum Store {
Filesystem(Filesystem),
ObjectStorage(ObjectStorage),
}
#[derive(Debug, Subcommand)]
enum RunStore {
Filesystem(RunFilesystem),
ObjectStorage(RunObjectStorage),
}
#[derive(Debug, Subcommand)]
enum MigrateStore {
Filesystem(MigrateFilesystem),
ObjectStorage(MigrateObjectStorage),
}
#[derive(Debug, Subcommand)]
enum MigrateStoreInner {
Filesystem(MigrateFilesystemInner),
ObjectStorage(MigrateObjectStorageInner),
}
#[derive(Debug, Parser)]
struct MigrateFilesystem {
#[command(flatten)]
from: crate::config::primitives::Filesystem,
#[command(subcommand)]
to: MigrateStoreInner,
}
#[derive(Debug, Parser)]
struct MigrateFilesystemInner {
#[command(flatten)]
to: crate::config::primitives::Filesystem,
#[command(subcommand)]
repo: Option<Repo>,
}
#[derive(Debug, Parser)]
struct MigrateObjectStorage {
#[command(flatten)]
from: crate::config::primitives::ObjectStorage,
#[command(subcommand)]
to: MigrateStoreInner,
}
#[derive(Debug, Parser)]
struct MigrateObjectStorageInner {
#[command(flatten)]
to: crate::config::primitives::ObjectStorage,
#[command(subcommand)]
repo: Option<Repo>,
}
#[derive(Debug, Parser)]
struct RunFilesystem {
#[command(flatten)]
system: Filesystem,
#[command(subcommand)]
repo: Option<Repo>,
}
#[derive(Debug, Parser)]
struct RunObjectStorage {
#[command(flatten)]
storage: ObjectStorage,
#[command(subcommand)]
repo: Option<Repo>,
}
#[derive(Debug, Subcommand, serde::Serialize)]
#[serde(rename_all = "snake_case")]
#[serde(tag = "type")]
enum Repo {
Sled(Sled),
}
#[derive(Clone, Debug, Parser, serde::Serialize)]
#[serde(rename_all = "snake_case")]
struct Filesystem {
#[arg(short, long)]
path: Option<PathBuf>,
}
#[derive(Clone, Debug, Parser, serde::Serialize)]
#[serde(rename_all = "snake_case")]
struct ObjectStorage {
#[arg(short, long)]
endpoint: Url,
#[arg(short, long)]
use_path_style: bool,
#[arg(short, long)]
bucket_name: Option<String>,
#[arg(short, long)]
region: Option<String>,
#[arg(short, long)]
access_key: Option<String>,
#[arg(short, long)]
secret_key: Option<String>,
#[arg(long)]
session_token: Option<String>,
}
#[derive(Debug, Parser, serde::Serialize)]
#[serde(rename_all = "snake_case")]
struct Sled {
#[arg(short, long)]
#[serde(skip_serializing_if = "Option::is_none")]
path: Option<PathBuf>,
#[arg(short, long)]
#[serde(skip_serializing_if = "Option::is_none")]
cache_capacity: Option<u64>,
}