2022-03-28 04:27:07 +00:00
|
|
|
use crate::{
|
2023-07-13 22:42:21 +00:00
|
|
|
config::primitives::{LogFormat, Targets},
|
|
|
|
formats::{AnimationFormat, AudioCodec, ImageFormat, VideoCodec},
|
2022-03-28 04:27:07 +00:00
|
|
|
serde_str::Serde,
|
|
|
|
};
|
2022-03-28 00:10:06 +00:00
|
|
|
use clap::{Parser, Subcommand};
|
|
|
|
use std::{net::SocketAddr, path::PathBuf};
|
|
|
|
use url::Url;
|
|
|
|
|
2022-03-28 04:27:07 +00:00
|
|
|
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,
|
2022-03-29 17:51:16 +00:00
|
|
|
worker_id,
|
2023-06-23 16:20:20 +00:00
|
|
|
client_pool_size,
|
2023-07-17 18:44:31 +00:00
|
|
|
client_timeout,
|
2023-07-22 21:47:59 +00:00
|
|
|
metrics_prometheus_address,
|
2022-09-25 20:17:33 +00:00
|
|
|
media_preprocess_steps,
|
2022-03-28 04:27:07 +00:00
|
|
|
media_max_file_size,
|
2023-07-13 22:42:21 +00:00
|
|
|
media_image_max_width,
|
|
|
|
media_image_max_height,
|
|
|
|
media_image_max_area,
|
|
|
|
media_image_max_file_size,
|
|
|
|
media_image_format,
|
2023-07-17 22:45:26 +00:00
|
|
|
media_image_quality_avif,
|
|
|
|
media_image_quality_jpeg,
|
|
|
|
media_image_quality_jxl,
|
|
|
|
media_image_quality_png,
|
|
|
|
media_image_quality_webp,
|
2023-07-13 22:42:21 +00:00
|
|
|
media_animation_max_width,
|
|
|
|
media_animation_max_height,
|
|
|
|
media_animation_max_area,
|
|
|
|
media_animation_max_file_size,
|
|
|
|
media_animation_max_frame_count,
|
|
|
|
media_animation_format,
|
2023-07-17 22:45:26 +00:00
|
|
|
media_animation_quality_apng,
|
|
|
|
media_animation_quality_avif,
|
|
|
|
media_animation_quality_webp,
|
2023-07-13 22:42:21 +00:00
|
|
|
media_video_enable,
|
|
|
|
media_video_allow_audio,
|
|
|
|
media_video_max_width,
|
|
|
|
media_video_max_height,
|
|
|
|
media_video_max_area,
|
|
|
|
media_video_max_file_size,
|
|
|
|
media_video_max_frame_count,
|
2022-10-01 00:38:11 +00:00
|
|
|
media_video_codec,
|
2023-07-13 22:42:21 +00:00
|
|
|
media_video_audio_codec,
|
2023-07-17 22:45:26 +00:00
|
|
|
media_video_quality_max,
|
|
|
|
media_video_quality_240,
|
|
|
|
media_video_quality_360,
|
|
|
|
media_video_quality_480,
|
|
|
|
media_video_quality_720,
|
|
|
|
media_video_quality_1080,
|
|
|
|
media_video_quality_1440,
|
|
|
|
media_video_quality_2160,
|
2022-03-28 04:27:07 +00:00
|
|
|
media_filters,
|
2023-07-17 19:24:49 +00:00
|
|
|
read_only,
|
2023-07-19 01:32:17 +00:00
|
|
|
max_file_count,
|
2022-03-28 04:27:07 +00:00
|
|
|
store,
|
|
|
|
}) => {
|
2022-03-29 17:51:16 +00:00
|
|
|
let server = Server {
|
|
|
|
address,
|
|
|
|
api_key,
|
|
|
|
worker_id,
|
2023-07-17 19:24:49 +00:00
|
|
|
read_only,
|
2023-07-19 01:32:17 +00:00
|
|
|
max_file_count,
|
2023-07-17 18:44:31 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let client = Client {
|
|
|
|
pool_size: client_pool_size,
|
|
|
|
timeout: client_timeout,
|
2022-03-29 17:51:16 +00:00
|
|
|
};
|
2023-07-13 22:42:21 +00:00
|
|
|
|
2023-07-22 21:47:59 +00:00
|
|
|
let metrics = Metrics {
|
|
|
|
prometheus_address: metrics_prometheus_address,
|
|
|
|
};
|
|
|
|
|
2023-07-17 22:45:26 +00:00
|
|
|
let image_quality = ImageQuality {
|
|
|
|
avif: media_image_quality_avif,
|
|
|
|
jpeg: media_image_quality_jpeg,
|
|
|
|
jxl: media_image_quality_jxl,
|
|
|
|
png: media_image_quality_png,
|
|
|
|
webp: media_image_quality_webp,
|
|
|
|
};
|
|
|
|
|
2023-07-13 22:42:21 +00:00
|
|
|
let image = Image {
|
|
|
|
max_file_size: media_image_max_file_size,
|
|
|
|
max_width: media_image_max_width,
|
|
|
|
max_height: media_image_max_height,
|
|
|
|
max_area: media_image_max_area,
|
|
|
|
format: media_image_format,
|
2023-07-17 22:45:26 +00:00
|
|
|
quality: image_quality.set(),
|
|
|
|
};
|
|
|
|
|
|
|
|
let animation_quality = AnimationQuality {
|
|
|
|
apng: media_animation_quality_apng,
|
|
|
|
avif: media_animation_quality_avif,
|
|
|
|
webp: media_animation_quality_webp,
|
2023-07-13 22:42:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let animation = Animation {
|
|
|
|
max_file_size: media_animation_max_file_size,
|
|
|
|
max_width: media_animation_max_width,
|
|
|
|
max_height: media_animation_max_height,
|
|
|
|
max_area: media_animation_max_area,
|
|
|
|
max_frame_count: media_animation_max_frame_count,
|
|
|
|
format: media_animation_format,
|
2023-07-17 22:45:26 +00:00
|
|
|
quality: animation_quality.set(),
|
|
|
|
};
|
|
|
|
|
|
|
|
let video_quality = VideoQuality {
|
|
|
|
crf_240: media_video_quality_240,
|
|
|
|
crf_360: media_video_quality_360,
|
|
|
|
crf_480: media_video_quality_480,
|
|
|
|
crf_720: media_video_quality_720,
|
|
|
|
crf_1080: media_video_quality_1080,
|
|
|
|
crf_1440: media_video_quality_1440,
|
|
|
|
crf_2160: media_video_quality_2160,
|
|
|
|
crf_max: media_video_quality_max,
|
2023-07-13 22:42:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let video = Video {
|
|
|
|
enable: media_video_enable,
|
|
|
|
allow_audio: media_video_allow_audio,
|
|
|
|
max_file_size: media_video_max_file_size,
|
|
|
|
max_width: media_video_max_width,
|
|
|
|
max_height: media_video_max_height,
|
|
|
|
max_area: media_video_max_area,
|
|
|
|
max_frame_count: media_video_max_frame_count,
|
|
|
|
video_codec: media_video_codec,
|
|
|
|
audio_codec: media_video_audio_codec,
|
2023-07-17 22:45:26 +00:00
|
|
|
quality: video_quality.set(),
|
2023-02-04 23:32:36 +00:00
|
|
|
};
|
2023-07-13 22:42:21 +00:00
|
|
|
|
2022-03-28 04:27:07 +00:00
|
|
|
let media = Media {
|
|
|
|
max_file_size: media_max_file_size,
|
2023-07-13 22:42:21 +00:00
|
|
|
preprocess_steps: media_preprocess_steps,
|
2022-03-28 04:27:07 +00:00
|
|
|
filters: media_filters,
|
2023-07-13 22:42:21 +00:00
|
|
|
image: image.set(),
|
|
|
|
animation: animation.set(),
|
|
|
|
video: video.set(),
|
2022-03-28 04:27:07 +00:00
|
|
|
};
|
|
|
|
let operation = Operation::Run;
|
|
|
|
|
|
|
|
match store {
|
|
|
|
Some(RunStore::Filesystem(RunFilesystem { system, repo })) => {
|
|
|
|
let store = Some(Store::Filesystem(system));
|
|
|
|
Output {
|
|
|
|
config_format: ConfigFormat {
|
|
|
|
server,
|
2023-07-17 18:44:31 +00:00
|
|
|
client,
|
2022-03-28 04:27:07 +00:00
|
|
|
old_db,
|
|
|
|
tracing,
|
2023-07-22 21:47:59 +00:00
|
|
|
metrics,
|
2022-03-28 04:27:07 +00:00
|
|
|
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,
|
2023-07-17 18:44:31 +00:00
|
|
|
client,
|
2022-03-28 04:27:07 +00:00
|
|
|
old_db,
|
|
|
|
tracing,
|
2023-07-22 21:47:59 +00:00
|
|
|
metrics,
|
2022-03-28 04:27:07 +00:00
|
|
|
media,
|
|
|
|
store,
|
|
|
|
repo,
|
|
|
|
},
|
|
|
|
operation,
|
|
|
|
config_file,
|
|
|
|
save_to,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => Output {
|
|
|
|
config_format: ConfigFormat {
|
|
|
|
server,
|
2023-07-17 18:44:31 +00:00
|
|
|
client,
|
2022-03-28 04:27:07 +00:00
|
|
|
old_db,
|
|
|
|
tracing,
|
2023-07-22 21:47:59 +00:00
|
|
|
metrics,
|
2022-03-28 04:27:07 +00:00
|
|
|
media,
|
|
|
|
store: None,
|
|
|
|
repo: None,
|
|
|
|
},
|
|
|
|
operation,
|
|
|
|
config_file,
|
|
|
|
save_to,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
2023-06-20 20:59:08 +00:00
|
|
|
Command::MigrateStore(MigrateStore {
|
|
|
|
skip_missing_files,
|
|
|
|
store,
|
|
|
|
}) => {
|
2022-03-28 04:27:07 +00:00
|
|
|
let server = Server::default();
|
2023-07-17 18:44:31 +00:00
|
|
|
let client = Client::default();
|
2022-03-28 04:27:07 +00:00
|
|
|
let media = Media::default();
|
2023-07-22 21:47:59 +00:00
|
|
|
let metrics = Metrics::default();
|
2022-03-28 04:27:07 +00:00
|
|
|
|
2023-06-20 20:59:08 +00:00
|
|
|
match store {
|
|
|
|
MigrateStoreFrom::Filesystem(MigrateFilesystem { from, to }) => match to {
|
|
|
|
MigrateStoreTo::Filesystem(MigrateFilesystemInner { to, repo }) => Output {
|
2022-03-28 04:27:07 +00:00
|
|
|
config_format: ConfigFormat {
|
|
|
|
server,
|
2023-07-17 18:44:31 +00:00
|
|
|
client,
|
2022-03-28 04:27:07 +00:00
|
|
|
old_db,
|
|
|
|
tracing,
|
2023-07-22 21:47:59 +00:00
|
|
|
metrics,
|
2022-03-28 04:27:07 +00:00
|
|
|
media,
|
|
|
|
store: None,
|
|
|
|
repo,
|
|
|
|
},
|
|
|
|
operation: Operation::MigrateStore {
|
2023-06-20 20:59:08 +00:00
|
|
|
skip_missing_files,
|
2022-03-28 04:27:07 +00:00
|
|
|
from: from.into(),
|
|
|
|
to: to.into(),
|
|
|
|
},
|
|
|
|
config_file,
|
|
|
|
save_to,
|
|
|
|
},
|
2023-06-20 20:59:08 +00:00
|
|
|
MigrateStoreTo::ObjectStorage(MigrateObjectStorageInner { to, repo }) => {
|
2022-03-28 04:27:07 +00:00
|
|
|
Output {
|
|
|
|
config_format: ConfigFormat {
|
|
|
|
server,
|
2023-07-17 18:44:31 +00:00
|
|
|
client,
|
2022-03-28 04:27:07 +00:00
|
|
|
old_db,
|
|
|
|
tracing,
|
2023-07-22 21:47:59 +00:00
|
|
|
metrics,
|
2022-03-28 04:27:07 +00:00
|
|
|
media,
|
|
|
|
store: None,
|
|
|
|
repo,
|
|
|
|
},
|
|
|
|
operation: Operation::MigrateStore {
|
2023-06-20 20:59:08 +00:00
|
|
|
skip_missing_files,
|
2022-03-28 04:27:07 +00:00
|
|
|
from: from.into(),
|
|
|
|
to: to.into(),
|
|
|
|
},
|
|
|
|
config_file,
|
|
|
|
save_to,
|
|
|
|
}
|
|
|
|
}
|
2023-06-20 20:59:08 +00:00
|
|
|
},
|
|
|
|
MigrateStoreFrom::ObjectStorage(MigrateObjectStorage { from, to }) => {
|
|
|
|
match to {
|
|
|
|
MigrateStoreTo::Filesystem(MigrateFilesystemInner { to, repo }) => {
|
|
|
|
Output {
|
|
|
|
config_format: ConfigFormat {
|
|
|
|
server,
|
2023-07-17 18:44:31 +00:00
|
|
|
client,
|
2023-06-20 20:59:08 +00:00
|
|
|
old_db,
|
|
|
|
tracing,
|
2023-07-22 21:47:59 +00:00
|
|
|
metrics,
|
2023-06-20 20:59:08 +00:00
|
|
|
media,
|
|
|
|
store: None,
|
|
|
|
repo,
|
|
|
|
},
|
|
|
|
operation: Operation::MigrateStore {
|
|
|
|
skip_missing_files,
|
|
|
|
from: from.into(),
|
|
|
|
to: to.into(),
|
|
|
|
},
|
|
|
|
config_file,
|
|
|
|
save_to,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MigrateStoreTo::ObjectStorage(MigrateObjectStorageInner {
|
|
|
|
to,
|
2022-03-28 04:27:07 +00:00
|
|
|
repo,
|
2023-06-20 20:59:08 +00:00
|
|
|
}) => Output {
|
|
|
|
config_format: ConfigFormat {
|
|
|
|
server,
|
2023-07-17 18:44:31 +00:00
|
|
|
client,
|
2023-06-20 20:59:08 +00:00
|
|
|
old_db,
|
|
|
|
tracing,
|
2023-07-22 21:47:59 +00:00
|
|
|
metrics,
|
2023-06-20 20:59:08 +00:00
|
|
|
media,
|
|
|
|
store: None,
|
|
|
|
repo,
|
|
|
|
},
|
|
|
|
operation: Operation::MigrateStore {
|
|
|
|
skip_missing_files,
|
|
|
|
from: from.into(),
|
|
|
|
to: to.into(),
|
|
|
|
},
|
|
|
|
config_file,
|
|
|
|
save_to,
|
2022-03-28 04:27:07 +00:00
|
|
|
},
|
2023-06-20 20:59:08 +00:00
|
|
|
}
|
|
|
|
}
|
2022-03-28 04:27:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
2023-06-20 20:59:08 +00:00
|
|
|
skip_missing_files: bool,
|
2022-03-28 04:27:07 +00:00
|
|
|
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,
|
2023-07-17 18:44:31 +00:00
|
|
|
client: Client,
|
2022-03-28 04:27:07 +00:00
|
|
|
old_db: OldDb,
|
|
|
|
tracing: Tracing,
|
2023-07-22 21:47:59 +00:00
|
|
|
metrics: Metrics,
|
2022-03-28 04:27:07 +00:00
|
|
|
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")]
|
2022-03-29 17:51:16 +00:00
|
|
|
worker_id: Option<String>,
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2022-03-28 04:27:07 +00:00
|
|
|
api_key: Option<String>,
|
2023-07-17 19:24:49 +00:00
|
|
|
#[serde(skip_serializing_if = "std::ops::Not::not")]
|
|
|
|
read_only: bool,
|
2023-07-19 01:32:17 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
max_file_count: Option<u32>,
|
2023-07-17 18:44:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Default, serde::Serialize)]
|
|
|
|
#[serde(rename_all = "snake_case")]
|
|
|
|
struct Client {
|
2023-06-23 16:20:20 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2023-07-17 18:44:31 +00:00
|
|
|
pool_size: Option<usize>,
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
timeout: Option<u64>,
|
2022-03-28 04:27:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[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>>,
|
|
|
|
}
|
|
|
|
|
2023-07-22 21:47:59 +00:00
|
|
|
#[derive(Debug, Default, serde::Serialize)]
|
|
|
|
#[serde(rename_all = "snake_case")]
|
|
|
|
struct Metrics {
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
prometheus_address: Option<SocketAddr>,
|
|
|
|
}
|
|
|
|
|
2022-03-28 04:27:07 +00:00
|
|
|
#[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 {
|
2023-07-13 22:42:21 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
max_file_size: Option<usize>,
|
2022-09-25 20:17:33 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
preprocess_steps: Option<String>,
|
2022-03-28 04:27:07 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2023-07-13 22:42:21 +00:00
|
|
|
filters: Option<Vec<String>>,
|
2022-03-28 04:27:07 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2023-07-13 22:42:21 +00:00
|
|
|
image: Option<Image>,
|
2022-03-28 04:27:07 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2023-07-13 22:42:21 +00:00
|
|
|
animation: Option<Animation>,
|
2022-03-28 04:27:07 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2023-07-13 22:42:21 +00:00
|
|
|
video: Option<Video>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Default, serde::Serialize)]
|
|
|
|
#[serde(rename_all = "snake_case")]
|
|
|
|
struct Image {
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
max_width: Option<u16>,
|
2022-03-28 04:27:07 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2023-07-13 22:42:21 +00:00
|
|
|
max_height: Option<u16>,
|
2022-09-25 22:36:07 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2023-07-13 22:42:21 +00:00
|
|
|
max_area: Option<u32>,
|
2023-02-04 23:32:36 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2023-07-13 22:42:21 +00:00
|
|
|
max_file_size: Option<usize>,
|
2022-03-28 04:27:07 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2023-07-13 22:42:21 +00:00
|
|
|
format: Option<ImageFormat>,
|
2023-07-17 22:45:26 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
quality: Option<ImageQuality>,
|
2023-07-13 22:42:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Image {
|
|
|
|
fn set(self) -> Option<Self> {
|
|
|
|
let any_set = self.max_width.is_some()
|
|
|
|
|| self.max_height.is_some()
|
|
|
|
|| self.max_area.is_some()
|
|
|
|
|| self.max_file_size.is_some()
|
2023-07-17 22:45:26 +00:00
|
|
|
|| self.format.is_some()
|
|
|
|
|| self.quality.is_some();
|
|
|
|
|
|
|
|
if any_set {
|
|
|
|
Some(self)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Default, serde::Serialize)]
|
|
|
|
struct ImageQuality {
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
avif: Option<u8>,
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
jpeg: Option<u8>,
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
jxl: Option<u8>,
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
png: Option<u8>,
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
webp: Option<u8>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ImageQuality {
|
|
|
|
fn set(self) -> Option<Self> {
|
|
|
|
let any_set = self.avif.is_some()
|
|
|
|
|| self.jpeg.is_some()
|
|
|
|
|| self.jxl.is_some()
|
|
|
|
|| self.png.is_some()
|
|
|
|
|| self.webp.is_some();
|
2023-07-13 22:42:21 +00:00
|
|
|
|
|
|
|
if any_set {
|
|
|
|
Some(self)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Default, serde::Serialize)]
|
|
|
|
#[serde(rename_all = "snake_case")]
|
|
|
|
struct Animation {
|
2022-09-25 22:36:07 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2023-07-13 22:42:21 +00:00
|
|
|
max_width: Option<u16>,
|
2022-10-01 00:38:11 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2023-07-13 22:42:21 +00:00
|
|
|
max_height: Option<u16>,
|
2022-10-01 00:38:11 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2023-07-13 22:42:21 +00:00
|
|
|
max_area: Option<u32>,
|
2022-03-28 04:27:07 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2023-07-13 22:42:21 +00:00
|
|
|
max_frame_count: Option<u32>,
|
2022-03-28 04:27:07 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2023-07-13 22:42:21 +00:00
|
|
|
max_file_size: Option<usize>,
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
format: Option<AnimationFormat>,
|
2023-07-17 22:45:26 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
quality: Option<AnimationQuality>,
|
2023-07-13 22:42:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Animation {
|
|
|
|
fn set(self) -> Option<Self> {
|
|
|
|
let any_set = self.max_width.is_some()
|
|
|
|
|| self.max_height.is_some()
|
|
|
|
|| self.max_area.is_some()
|
|
|
|
|| self.max_frame_count.is_some()
|
|
|
|
|| self.max_file_size.is_some()
|
2023-07-17 22:45:26 +00:00
|
|
|
|| self.format.is_some()
|
|
|
|
|| self.quality.is_some();
|
|
|
|
|
|
|
|
if any_set {
|
|
|
|
Some(self)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Default, serde::Serialize)]
|
|
|
|
#[serde(rename_all = "snake_case")]
|
|
|
|
struct AnimationQuality {
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
apng: Option<u8>,
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
avif: Option<u8>,
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
webp: Option<u8>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AnimationQuality {
|
|
|
|
fn set(self) -> Option<Self> {
|
|
|
|
let any_set = self.apng.is_some() || self.avif.is_some() || self.webp.is_some();
|
2023-07-13 22:42:21 +00:00
|
|
|
|
|
|
|
if any_set {
|
|
|
|
Some(self)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
2022-03-28 04:27:07 +00:00
|
|
|
}
|
|
|
|
|
2023-02-04 23:32:36 +00:00
|
|
|
#[derive(Debug, Default, serde::Serialize)]
|
|
|
|
#[serde(rename_all = "snake_case")]
|
2023-07-13 22:42:21 +00:00
|
|
|
struct Video {
|
2023-07-17 19:24:49 +00:00
|
|
|
#[serde(skip_serializing_if = "std::ops::Not::not")]
|
|
|
|
enable: bool,
|
|
|
|
#[serde(skip_serializing_if = "std::ops::Not::not")]
|
|
|
|
allow_audio: bool,
|
2023-07-13 22:42:21 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
max_width: Option<u16>,
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
max_height: Option<u16>,
|
2023-02-04 23:32:36 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2023-07-13 22:42:21 +00:00
|
|
|
max_area: Option<u32>,
|
2023-02-04 23:32:36 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2023-07-13 22:42:21 +00:00
|
|
|
max_frame_count: Option<u32>,
|
2023-02-04 23:32:36 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2023-07-13 22:42:21 +00:00
|
|
|
max_file_size: Option<usize>,
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
video_codec: Option<VideoCodec>,
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
audio_codec: Option<AudioCodec>,
|
2023-07-17 22:45:26 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
quality: Option<VideoQuality>,
|
2023-07-13 22:42:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Video {
|
|
|
|
fn set(self) -> Option<Self> {
|
2023-07-17 19:24:49 +00:00
|
|
|
let any_set = self.enable
|
|
|
|
|| self.allow_audio
|
2023-07-13 22:42:21 +00:00
|
|
|
|| self.max_width.is_some()
|
|
|
|
|| self.max_height.is_some()
|
|
|
|
|| self.max_area.is_some()
|
|
|
|
|| self.max_frame_count.is_some()
|
|
|
|
|| self.max_file_size.is_some()
|
|
|
|
|| self.video_codec.is_some()
|
2023-07-17 22:45:26 +00:00
|
|
|
|| self.audio_codec.is_some()
|
|
|
|
|| self.quality.is_some();
|
|
|
|
|
|
|
|
if any_set {
|
|
|
|
Some(self)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Default, serde::Serialize)]
|
|
|
|
#[serde(rename_all = "snake_case")]
|
|
|
|
struct VideoQuality {
|
|
|
|
crf_240: Option<u8>,
|
|
|
|
crf_360: Option<u8>,
|
|
|
|
crf_480: Option<u8>,
|
|
|
|
crf_720: Option<u8>,
|
|
|
|
crf_1080: Option<u8>,
|
|
|
|
crf_1440: Option<u8>,
|
|
|
|
crf_2160: Option<u8>,
|
|
|
|
crf_max: Option<u8>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl VideoQuality {
|
|
|
|
fn set(self) -> Option<Self> {
|
|
|
|
let any_set = self.crf_240.is_some()
|
|
|
|
|| self.crf_360.is_some()
|
|
|
|
|| self.crf_480.is_some()
|
|
|
|
|| self.crf_720.is_some()
|
|
|
|
|| self.crf_1080.is_some()
|
|
|
|
|| self.crf_1440.is_some()
|
|
|
|
|| self.crf_1440.is_some()
|
|
|
|
|| self.crf_2160.is_some()
|
|
|
|
|| self.crf_max.is_some();
|
2023-07-13 22:42:21 +00:00
|
|
|
|
|
|
|
if any_set {
|
|
|
|
Some(self)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
2023-02-04 23:32:36 +00:00
|
|
|
}
|
|
|
|
|
2022-03-28 00:10:06 +00:00
|
|
|
/// Run the pict-rs application
|
|
|
|
#[derive(Debug, Parser)]
|
2022-09-28 23:23:41 +00:00
|
|
|
#[command(author, version, about, long_about = None)]
|
2022-03-28 04:27:07 +00:00
|
|
|
pub(super) struct Args {
|
2022-03-28 00:10:06 +00:00
|
|
|
/// Path to the pict-rs configuration file
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(short, long)]
|
2022-03-28 04:27:07 +00:00
|
|
|
config_file: Option<PathBuf>,
|
|
|
|
|
|
|
|
/// Path to the old pict-rs sled database
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(long)]
|
2022-03-28 04:27:07 +00:00
|
|
|
old_db_path: Option<PathBuf>,
|
2022-03-28 00:10:06 +00:00
|
|
|
|
|
|
|
/// Format of logs printed to stdout
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(long)]
|
2022-03-28 04:27:07 +00:00
|
|
|
log_format: Option<LogFormat>,
|
2022-03-28 00:10:06 +00:00
|
|
|
/// Log levels to print to stdout, respects RUST_LOG formatting
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(long)]
|
2022-03-28 04:27:07 +00:00
|
|
|
log_targets: Option<Targets>,
|
2022-03-28 00:10:06 +00:00
|
|
|
|
|
|
|
/// Address and port to expose tokio-console metrics
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(long)]
|
2022-03-28 04:27:07 +00:00
|
|
|
console_address: Option<SocketAddr>,
|
2022-03-28 00:10:06 +00:00
|
|
|
/// Capacity of the console-subscriber Event Buffer
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(long)]
|
2022-03-28 04:27:07 +00:00
|
|
|
console_buffer_capacity: Option<usize>,
|
2022-03-28 00:10:06 +00:00
|
|
|
|
|
|
|
/// URL to send OpenTelemetry metrics
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(long)]
|
2022-03-28 04:27:07 +00:00
|
|
|
opentelemetry_url: Option<Url>,
|
2022-03-28 00:10:06 +00:00
|
|
|
/// Service Name to use for OpenTelemetry
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(long)]
|
2022-03-28 04:27:07 +00:00
|
|
|
opentelemetry_service_name: Option<String>,
|
2022-03-28 00:10:06 +00:00
|
|
|
/// Log levels to use for OpenTelemetry, respects RUST_LOG formatting
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(long)]
|
2022-03-28 04:27:07 +00:00
|
|
|
opentelemetry_targets: Option<Targets>,
|
2022-03-28 00:10:06 +00:00
|
|
|
|
|
|
|
/// File to save the current configuration for reproducible runs
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(long)]
|
2022-03-28 04:27:07 +00:00
|
|
|
save_to: Option<PathBuf>,
|
2022-03-28 00:10:06 +00:00
|
|
|
|
2022-09-28 23:23:41 +00:00
|
|
|
#[command(subcommand)]
|
2022-03-28 04:27:07 +00:00
|
|
|
command: Command,
|
2022-03-28 00:10:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Subcommand)]
|
2022-03-28 04:27:07 +00:00
|
|
|
enum Command {
|
2022-03-28 00:10:06 +00:00
|
|
|
/// Runs the pict-rs web server
|
|
|
|
Run(Run),
|
|
|
|
|
|
|
|
/// Migrates from one provided media store to another
|
|
|
|
MigrateStore(MigrateStore),
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Parser)]
|
2022-03-28 04:27:07 +00:00
|
|
|
struct Run {
|
2022-03-28 00:10:06 +00:00
|
|
|
/// The address and port to bind the pict-rs web server
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(short, long)]
|
2022-03-28 04:27:07 +00:00
|
|
|
address: Option<SocketAddr>,
|
2022-03-28 00:10:06 +00:00
|
|
|
|
|
|
|
/// The API KEY required to access restricted routes
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(long)]
|
2022-03-28 04:27:07 +00:00
|
|
|
api_key: Option<String>,
|
2022-03-28 00:10:06 +00:00
|
|
|
|
2022-09-25 20:17:33 +00:00
|
|
|
/// ID of this pict-rs node. Doesn't do much yet
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(long)]
|
2022-03-29 17:51:16 +00:00
|
|
|
worker_id: Option<String>,
|
|
|
|
|
2023-06-23 16:20:20 +00:00
|
|
|
/// Number of connections the internel HTTP client should maintain in its pool
|
|
|
|
///
|
|
|
|
/// This number defaults to 100, and the total number is multiplied by the number of cores
|
|
|
|
/// available to the program. This means that running on a 2 core system will result in 200
|
|
|
|
/// pooled connections, and running on a 32 core system will result in 3200 pooled connections.
|
|
|
|
#[arg(long)]
|
|
|
|
client_pool_size: Option<usize>,
|
|
|
|
|
2023-07-17 18:44:31 +00:00
|
|
|
/// How long (in seconds) the internel HTTP client should wait for responses
|
|
|
|
///
|
|
|
|
/// This number defaults to 30
|
|
|
|
#[arg(long)]
|
|
|
|
client_timeout: Option<u64>,
|
|
|
|
|
2023-07-22 21:47:59 +00:00
|
|
|
/// Whether to enable the prometheus scrape endpoint
|
|
|
|
#[arg(long)]
|
|
|
|
metrics_prometheus_address: Option<SocketAddr>,
|
|
|
|
|
2023-07-19 01:32:17 +00:00
|
|
|
/// How many files are allowed to be uploaded per-request
|
|
|
|
///
|
|
|
|
/// This number defaults to 1
|
|
|
|
#[arg(long)]
|
|
|
|
max_file_count: Option<u32>,
|
|
|
|
|
2022-09-25 20:17:33 +00:00
|
|
|
/// Optional pre-processing steps for uploaded media.
|
|
|
|
///
|
|
|
|
/// All still images will be put through these steps before saving
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(long)]
|
2022-09-25 20:17:33 +00:00
|
|
|
media_preprocess_steps: Option<String>,
|
|
|
|
|
2023-07-13 22:42:21 +00:00
|
|
|
/// Which media filters should be enabled on the `process` endpoint
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(long)]
|
2023-07-13 22:42:21 +00:00
|
|
|
media_filters: Option<Vec<String>>,
|
|
|
|
|
|
|
|
/// The maximum size, in megabytes, for all uploaded media
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(long)]
|
2023-07-13 22:42:21 +00:00
|
|
|
media_max_file_size: Option<usize>,
|
|
|
|
|
|
|
|
/// The maximum width, in pixels, for uploaded images
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(long)]
|
2023-07-13 22:42:21 +00:00
|
|
|
media_image_max_width: Option<u16>,
|
|
|
|
/// The maximum height, in pixels, for uploaded images
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(long)]
|
2023-07-13 22:42:21 +00:00
|
|
|
media_image_max_height: Option<u16>,
|
|
|
|
/// The maximum area, in pixels, for uploaded images
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(long)]
|
2023-07-13 22:42:21 +00:00
|
|
|
media_image_max_area: Option<u32>,
|
|
|
|
/// The maximum size, in megabytes, for uploaded images
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(long)]
|
2023-07-13 22:42:21 +00:00
|
|
|
media_image_max_file_size: Option<usize>,
|
|
|
|
/// Enforce a specific format for uploaded images
|
2023-02-04 23:32:36 +00:00
|
|
|
#[arg(long)]
|
2023-07-13 22:42:21 +00:00
|
|
|
media_image_format: Option<ImageFormat>,
|
2023-07-17 22:45:26 +00:00
|
|
|
/// Enforce a specific quality for AVIF images
|
|
|
|
///
|
|
|
|
/// A higher number means better quality, with a minimum value of 0 and a maximum value of 100
|
|
|
|
#[arg(long)]
|
|
|
|
media_image_quality_avif: Option<u8>,
|
|
|
|
/// Enforce a specific compression level for PNG images
|
|
|
|
///
|
|
|
|
/// A higher number means better compression. PNGs will look the same regardless
|
|
|
|
#[arg(long)]
|
|
|
|
media_image_quality_png: Option<u8>,
|
|
|
|
/// Enforce a specific quality for JPEG images
|
|
|
|
///
|
|
|
|
/// A higher number means better quality, with a minimum value of 0 and a maximum value of 100
|
|
|
|
#[arg(long)]
|
|
|
|
media_image_quality_jpeg: Option<u8>,
|
|
|
|
/// Enforce a specific quality for JXL images
|
|
|
|
///
|
|
|
|
/// A higher number means better quality, with a minimum value of 0 and a maximum value of 100
|
|
|
|
#[arg(long)]
|
|
|
|
media_image_quality_jxl: Option<u8>,
|
|
|
|
/// Enforce a specific quality for WEBP images
|
|
|
|
///
|
|
|
|
/// A higher number means better quality, with a minimum value of 0 and a maximum value of 100
|
|
|
|
#[arg(long)]
|
|
|
|
media_image_quality_webp: Option<u8>,
|
2023-07-13 22:42:21 +00:00
|
|
|
|
|
|
|
/// The maximum width, in pixels, for uploaded animations
|
2023-02-04 23:32:36 +00:00
|
|
|
#[arg(long)]
|
2023-07-13 22:42:21 +00:00
|
|
|
media_animation_max_width: Option<u16>,
|
|
|
|
/// The maximum height, in pixels, for uploaded animations
|
|
|
|
#[arg(long)]
|
|
|
|
media_animation_max_height: Option<u16>,
|
|
|
|
/// The maximum area, in pixels, for uploaded animations
|
|
|
|
#[arg(long)]
|
|
|
|
media_animation_max_area: Option<u32>,
|
|
|
|
/// The maximum number of frames allowed for uploaded animations
|
|
|
|
#[arg(long)]
|
|
|
|
media_animation_max_frame_count: Option<u32>,
|
|
|
|
/// The maximum size, in megabytes, for uploaded animations
|
|
|
|
#[arg(long)]
|
|
|
|
media_animation_max_file_size: Option<usize>,
|
|
|
|
/// Enforce a specific format for uploaded animations
|
2023-02-04 23:32:36 +00:00
|
|
|
#[arg(long)]
|
2023-07-13 22:42:21 +00:00
|
|
|
media_animation_format: Option<AnimationFormat>,
|
2023-07-17 22:45:26 +00:00
|
|
|
/// Enforce a specific compression level for APNG animations
|
|
|
|
///
|
|
|
|
/// A higher number means better compression, APNGs will look the same regardless
|
|
|
|
#[arg(long)]
|
|
|
|
media_animation_quality_apng: Option<u8>,
|
|
|
|
/// Enforce a specific quality for AVIF animations
|
|
|
|
///
|
|
|
|
/// A higher number means better quality, with a minimum value of 0 and a maximum value of 100
|
|
|
|
#[arg(long)]
|
|
|
|
media_animation_quality_avif: Option<u8>,
|
|
|
|
/// Enforce a specific quality for WEBP animations
|
|
|
|
///
|
|
|
|
/// A higher number means better quality, with a minimum value of 0 and a maximum value of 100
|
|
|
|
#[arg(long)]
|
|
|
|
media_animation_quality_webp: Option<u8>,
|
2023-07-13 22:42:21 +00:00
|
|
|
|
|
|
|
/// Whether to enable video uploads
|
|
|
|
#[arg(long)]
|
2023-07-17 19:24:49 +00:00
|
|
|
media_video_enable: bool,
|
2023-07-13 22:42:21 +00:00
|
|
|
/// Whether to enable audio in video uploads
|
2023-07-17 19:24:49 +00:00
|
|
|
#[arg(long)]
|
|
|
|
media_video_allow_audio: bool,
|
2023-07-13 22:42:21 +00:00
|
|
|
/// The maximum width, in pixels, for uploaded videos
|
|
|
|
#[arg(long)]
|
|
|
|
media_video_max_width: Option<u16>,
|
|
|
|
/// The maximum height, in pixels, for uploaded videos
|
|
|
|
#[arg(long)]
|
|
|
|
media_video_max_height: Option<u16>,
|
|
|
|
/// The maximum area, in pixels, for uploaded videos
|
|
|
|
#[arg(long)]
|
|
|
|
media_video_max_area: Option<u32>,
|
|
|
|
/// The maximum number of frames allowed for uploaded videos
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(long)]
|
2023-07-13 22:42:21 +00:00
|
|
|
media_video_max_frame_count: Option<u32>,
|
|
|
|
/// The maximum size, in megabytes, for uploaded videos
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(long)]
|
2023-07-13 22:42:21 +00:00
|
|
|
media_video_max_file_size: Option<usize>,
|
2022-10-01 00:38:11 +00:00
|
|
|
/// Enforce a specific video codec for uploaded videos
|
|
|
|
#[arg(long)]
|
|
|
|
media_video_codec: Option<VideoCodec>,
|
|
|
|
/// Enforce a specific audio codec for uploaded videos
|
|
|
|
#[arg(long)]
|
2023-07-13 22:42:21 +00:00
|
|
|
media_video_audio_codec: Option<AudioCodec>,
|
2023-07-17 22:45:26 +00:00
|
|
|
/// Enforce a maximum quality level for uploaded videos
|
|
|
|
///
|
|
|
|
/// This value means different things for different video codecs:
|
|
|
|
/// - it ranges from 0 to 63 for AV1
|
|
|
|
/// - it ranges from 4 to 63 for VP8
|
|
|
|
/// - it ranges from 0 to 63 for VP9
|
|
|
|
/// - it ranges from 0 to 51 for H265
|
|
|
|
/// - it ranges from 0 to 51 for 8bit H264
|
|
|
|
/// - it ranges from 0 to 63 for 10bit H264
|
|
|
|
///
|
|
|
|
/// A lower value (closer to 0) is higher quality, while a higher value (closer to 63) is lower
|
|
|
|
/// quality. Generally acceptable ranges are 15-38, where lower values are preferred for larger
|
|
|
|
/// videos
|
|
|
|
#[arg(long)]
|
|
|
|
media_video_quality_max: Option<u8>,
|
|
|
|
/// Enforce a video quality for video with a smaller dimension less than 240px
|
|
|
|
#[arg(long)]
|
|
|
|
media_video_quality_240: Option<u8>,
|
|
|
|
/// Enforce a video quality for video with a smaller dimension less than 360px
|
|
|
|
#[arg(long)]
|
|
|
|
media_video_quality_360: Option<u8>,
|
|
|
|
/// Enforce a video quality for video with a smaller dimension less than 480px
|
|
|
|
#[arg(long)]
|
|
|
|
media_video_quality_480: Option<u8>,
|
|
|
|
/// Enforce a video quality for video with a smaller dimension less than 720px
|
|
|
|
#[arg(long)]
|
|
|
|
media_video_quality_720: Option<u8>,
|
|
|
|
/// Enforce a video quality for video with a smaller dimension less than 1080px
|
|
|
|
#[arg(long)]
|
|
|
|
media_video_quality_1080: Option<u8>,
|
|
|
|
/// Enforce a video quality for video with a smaller dimension less than 1440px
|
|
|
|
#[arg(long)]
|
|
|
|
media_video_quality_1440: Option<u8>,
|
|
|
|
/// Enforce a video quality for video with a smaller dimension less than 2160px
|
|
|
|
#[arg(long)]
|
|
|
|
media_video_quality_2160: Option<u8>,
|
2022-03-28 00:10:06 +00:00
|
|
|
|
2023-07-17 19:24:49 +00:00
|
|
|
/// Don't permit ingesting media
|
|
|
|
#[arg(long)]
|
|
|
|
read_only: bool,
|
|
|
|
|
2022-09-28 23:23:41 +00:00
|
|
|
#[command(subcommand)]
|
2022-03-28 04:27:07 +00:00
|
|
|
store: Option<RunStore>,
|
2022-03-28 00:10:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Configure the provided storage
|
2022-03-28 04:27:07 +00:00
|
|
|
#[derive(Clone, Debug, Subcommand, serde::Serialize)]
|
|
|
|
#[serde(rename_all = "snake_case")]
|
|
|
|
#[serde(tag = "type")]
|
2023-07-11 18:01:58 +00:00
|
|
|
// allow large enum variant - this is an instantiated-once config
|
|
|
|
#[allow(clippy::large_enum_variant)]
|
2022-03-28 04:27:07 +00:00
|
|
|
enum Store {
|
2022-03-28 00:10:06 +00:00
|
|
|
/// configure filesystem storage
|
|
|
|
Filesystem(Filesystem),
|
|
|
|
|
|
|
|
/// configure object storage
|
|
|
|
ObjectStorage(ObjectStorage),
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Run pict-rs with the provided storage
|
|
|
|
#[derive(Debug, Subcommand)]
|
2023-07-11 18:01:58 +00:00
|
|
|
// allow large enum variant - this is an instantiated-once config
|
|
|
|
#[allow(clippy::large_enum_variant)]
|
2022-03-28 04:27:07 +00:00
|
|
|
enum RunStore {
|
2022-03-28 00:10:06 +00:00
|
|
|
/// Run pict-rs with filesystem storage
|
|
|
|
Filesystem(RunFilesystem),
|
|
|
|
|
|
|
|
/// Run pict-rs with object storage
|
|
|
|
ObjectStorage(RunObjectStorage),
|
|
|
|
}
|
|
|
|
|
2023-06-20 20:59:08 +00:00
|
|
|
#[derive(Debug, Parser)]
|
|
|
|
struct MigrateStore {
|
|
|
|
/// Normally, pict-rs will keep retrying when errors occur during migration. This flag tells
|
|
|
|
/// pict-rs to ignore errors that are caused by files not existing.
|
|
|
|
#[arg(long)]
|
|
|
|
skip_missing_files: bool,
|
|
|
|
|
|
|
|
#[command(subcommand)]
|
|
|
|
store: MigrateStoreFrom,
|
|
|
|
}
|
|
|
|
|
2022-03-28 00:10:06 +00:00
|
|
|
/// Configure the pict-rs storage migration
|
|
|
|
#[derive(Debug, Subcommand)]
|
2023-07-11 18:01:58 +00:00
|
|
|
// allow large enum variant - this is an instantiated-once config
|
|
|
|
#[allow(clippy::large_enum_variant)]
|
2023-06-20 20:59:08 +00:00
|
|
|
enum MigrateStoreFrom {
|
2022-03-28 00:10:06 +00:00
|
|
|
/// Migrate from the provided filesystem storage
|
|
|
|
Filesystem(MigrateFilesystem),
|
|
|
|
|
|
|
|
/// Migrate from the provided object storage
|
|
|
|
ObjectStorage(MigrateObjectStorage),
|
|
|
|
}
|
|
|
|
|
2022-03-28 04:27:07 +00:00
|
|
|
/// Configure the destination storage for pict-rs storage migration
|
|
|
|
#[derive(Debug, Subcommand)]
|
2023-07-11 18:01:58 +00:00
|
|
|
// allow large enum variant - this is an instantiated-once config
|
|
|
|
#[allow(clippy::large_enum_variant)]
|
2023-06-20 20:59:08 +00:00
|
|
|
enum MigrateStoreTo {
|
2022-03-28 04:27:07 +00:00
|
|
|
/// Migrate to the provided filesystem storage
|
|
|
|
Filesystem(MigrateFilesystemInner),
|
|
|
|
|
|
|
|
/// Migrate to the provided object storage
|
|
|
|
ObjectStorage(MigrateObjectStorageInner),
|
|
|
|
}
|
|
|
|
|
2022-03-28 00:10:06 +00:00
|
|
|
/// Migrate pict-rs' storage from the provided filesystem storage
|
|
|
|
#[derive(Debug, Parser)]
|
2022-03-28 04:27:07 +00:00
|
|
|
struct MigrateFilesystem {
|
2022-09-28 23:23:41 +00:00
|
|
|
#[command(flatten)]
|
2023-06-19 20:04:36 +00:00
|
|
|
from: Filesystem,
|
2022-03-28 04:27:07 +00:00
|
|
|
|
2022-09-28 23:23:41 +00:00
|
|
|
#[command(subcommand)]
|
2023-06-20 20:59:08 +00:00
|
|
|
to: MigrateStoreTo,
|
2022-03-28 04:27:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Migrate pict-rs' storage to the provided filesystem storage
|
|
|
|
#[derive(Debug, Parser)]
|
|
|
|
struct MigrateFilesystemInner {
|
2022-09-28 23:23:41 +00:00
|
|
|
#[command(flatten)]
|
2023-06-19 20:04:36 +00:00
|
|
|
to: Filesystem,
|
2022-03-28 00:10:06 +00:00
|
|
|
|
2022-09-28 23:23:41 +00:00
|
|
|
#[command(subcommand)]
|
2022-03-28 04:27:07 +00:00
|
|
|
repo: Option<Repo>,
|
2022-03-28 00:10:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Migrate pict-rs' storage from the provided object storage
|
|
|
|
#[derive(Debug, Parser)]
|
2022-03-28 04:27:07 +00:00
|
|
|
struct MigrateObjectStorage {
|
2022-09-28 23:23:41 +00:00
|
|
|
#[command(flatten)]
|
2022-03-28 04:27:07 +00:00
|
|
|
from: crate::config::primitives::ObjectStorage,
|
2022-03-28 00:10:06 +00:00
|
|
|
|
2022-09-28 23:23:41 +00:00
|
|
|
#[command(subcommand)]
|
2023-06-20 20:59:08 +00:00
|
|
|
to: MigrateStoreTo,
|
2022-03-28 04:27:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Migrate pict-rs' storage to the provided object storage
|
|
|
|
#[derive(Debug, Parser)]
|
|
|
|
struct MigrateObjectStorageInner {
|
2022-09-28 23:23:41 +00:00
|
|
|
#[command(flatten)]
|
2022-03-28 04:27:07 +00:00
|
|
|
to: crate::config::primitives::ObjectStorage,
|
|
|
|
|
2022-09-28 23:23:41 +00:00
|
|
|
#[command(subcommand)]
|
2022-03-28 04:27:07 +00:00
|
|
|
repo: Option<Repo>,
|
2022-03-28 00:10:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Run pict-rs with the provided filesystem storage
|
|
|
|
#[derive(Debug, Parser)]
|
2022-03-28 04:27:07 +00:00
|
|
|
struct RunFilesystem {
|
2022-09-28 23:23:41 +00:00
|
|
|
#[command(flatten)]
|
2022-03-28 04:27:07 +00:00
|
|
|
system: Filesystem,
|
2022-03-28 00:10:06 +00:00
|
|
|
|
2022-09-28 23:23:41 +00:00
|
|
|
#[command(subcommand)]
|
2022-03-28 04:27:07 +00:00
|
|
|
repo: Option<Repo>,
|
2022-03-28 00:10:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Run pict-rs with the provided object storage
|
|
|
|
#[derive(Debug, Parser)]
|
2022-03-28 04:27:07 +00:00
|
|
|
struct RunObjectStorage {
|
2022-09-28 23:23:41 +00:00
|
|
|
#[command(flatten)]
|
2022-03-28 04:27:07 +00:00
|
|
|
storage: ObjectStorage,
|
2022-03-28 00:10:06 +00:00
|
|
|
|
2022-09-28 23:23:41 +00:00
|
|
|
#[command(subcommand)]
|
2022-03-28 04:27:07 +00:00
|
|
|
repo: Option<Repo>,
|
2022-03-28 00:10:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Configuration for data repositories
|
2022-03-28 04:27:07 +00:00
|
|
|
#[derive(Debug, Subcommand, serde::Serialize)]
|
|
|
|
#[serde(rename_all = "snake_case")]
|
|
|
|
#[serde(tag = "type")]
|
|
|
|
enum Repo {
|
2022-03-28 00:10:06 +00:00
|
|
|
/// Run pict-rs with the provided sled-backed data repository
|
|
|
|
Sled(Sled),
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Configuration for filesystem media storage
|
2022-03-28 04:27:07 +00:00
|
|
|
#[derive(Clone, Debug, Parser, serde::Serialize)]
|
|
|
|
#[serde(rename_all = "snake_case")]
|
2023-06-19 20:04:36 +00:00
|
|
|
pub(super) struct Filesystem {
|
2022-03-28 00:10:06 +00:00
|
|
|
/// The path to store uploaded media
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(short, long)]
|
2023-06-19 20:04:36 +00:00
|
|
|
pub(super) path: Option<PathBuf>,
|
2022-03-28 00:10:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Configuration for Object Storage
|
2022-03-28 04:27:07 +00:00
|
|
|
#[derive(Clone, Debug, Parser, serde::Serialize)]
|
|
|
|
#[serde(rename_all = "snake_case")]
|
|
|
|
struct ObjectStorage {
|
2022-09-24 19:18:49 +00:00
|
|
|
/// The base endpoint for the object storage
|
|
|
|
///
|
|
|
|
/// Examples:
|
|
|
|
/// - `http://localhost:9000`
|
|
|
|
/// - `https://s3.dualstack.eu-west-1.amazonaws.com`
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(short, long)]
|
2022-09-24 19:18:49 +00:00
|
|
|
endpoint: Url,
|
|
|
|
|
|
|
|
/// Determines whether to use path style or virtualhost style for accessing objects
|
|
|
|
///
|
|
|
|
/// When this is true, objects will be fetched from {endpoint}/{bucket_name}/{object}
|
|
|
|
/// When false, objects will be fetched from {bucket_name}.{endpoint}/{object}
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(short, long)]
|
2022-09-24 19:18:49 +00:00
|
|
|
use_path_style: bool,
|
|
|
|
|
2022-03-28 00:10:06 +00:00
|
|
|
/// The bucket in which to store media
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(short, long)]
|
2023-07-11 18:01:58 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2022-03-28 04:27:07 +00:00
|
|
|
bucket_name: Option<String>,
|
2022-03-28 00:10:06 +00:00
|
|
|
|
|
|
|
/// The region the bucket is located in
|
2022-09-24 19:18:49 +00:00
|
|
|
///
|
|
|
|
/// For minio deployments, this can just be 'minio'
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(short, long)]
|
2023-07-11 18:01:58 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2022-09-24 19:18:49 +00:00
|
|
|
region: Option<String>,
|
2022-03-28 00:10:06 +00:00
|
|
|
|
|
|
|
/// The Access Key for the user accessing the bucket
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(short, long)]
|
2023-07-11 18:01:58 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2022-03-28 04:27:07 +00:00
|
|
|
access_key: Option<String>,
|
2022-03-28 00:10:06 +00:00
|
|
|
|
|
|
|
/// The secret key for the user accessing the bucket
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(short, long)]
|
2023-07-11 18:01:58 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2022-03-28 04:27:07 +00:00
|
|
|
secret_key: Option<String>,
|
2022-03-28 00:10:06 +00:00
|
|
|
|
|
|
|
/// The session token for accessing the bucket
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(long)]
|
2023-07-11 18:01:58 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2022-03-28 04:27:07 +00:00
|
|
|
session_token: Option<String>,
|
2023-07-11 18:01:58 +00:00
|
|
|
|
|
|
|
/// How long signatures for object storage requests are valid (in seconds)
|
|
|
|
///
|
|
|
|
/// This defaults to 15 seconds
|
|
|
|
#[arg(long)]
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
signature_duration: Option<u64>,
|
|
|
|
|
|
|
|
/// How long a client can wait on an object storage request before giving up (in seconds)
|
|
|
|
///
|
|
|
|
/// This defaults to 30 seconds
|
|
|
|
#[arg(long)]
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
client_timeout: Option<u64>,
|
2022-03-28 00:10:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Configuration for the sled-backed data repository
|
2022-03-28 04:27:07 +00:00
|
|
|
#[derive(Debug, Parser, serde::Serialize)]
|
|
|
|
#[serde(rename_all = "snake_case")]
|
|
|
|
struct Sled {
|
2022-03-28 00:10:06 +00:00
|
|
|
/// The path to store the sled database
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(short, long)]
|
2022-03-28 04:27:07 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
path: Option<PathBuf>,
|
2022-03-28 00:10:06 +00:00
|
|
|
|
|
|
|
/// The cache capacity, in bytes, allowed to sled for in-memory operations
|
2022-09-28 23:23:41 +00:00
|
|
|
#[arg(short, long)]
|
2022-03-28 04:27:07 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
cache_capacity: Option<u64>,
|
2023-07-08 22:35:57 +00:00
|
|
|
|
2023-07-09 00:56:26 +00:00
|
|
|
#[arg(short, long)]
|
2023-07-08 22:35:57 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
export_path: Option<PathBuf>,
|
2022-03-28 00:10:06 +00:00
|
|
|
}
|