mirror of
https://git.asonix.dog/asonix/pict-rs
synced 2024-12-22 19:31:35 +00:00
Add error codes
This commit is contained in:
parent
3c09aad5e8
commit
ba3a23ed43
15 changed files with 380 additions and 46 deletions
68
src/error.rs
68
src/error.rs
|
@ -1,6 +1,8 @@
|
||||||
use actix_web::{http::StatusCode, HttpResponse, ResponseError};
|
use actix_web::{http::StatusCode, HttpResponse, ResponseError};
|
||||||
use color_eyre::Report;
|
use color_eyre::Report;
|
||||||
|
|
||||||
|
use crate::error_code::ErrorCode;
|
||||||
|
|
||||||
pub(crate) struct Error {
|
pub(crate) struct Error {
|
||||||
inner: color_eyre::Report,
|
inner: color_eyre::Report,
|
||||||
}
|
}
|
||||||
|
@ -13,6 +15,12 @@ impl Error {
|
||||||
pub(crate) fn root_cause(&self) -> &(dyn std::error::Error + 'static) {
|
pub(crate) fn root_cause(&self) -> &(dyn std::error::Error + 'static) {
|
||||||
self.inner.root_cause()
|
self.inner.root_cause()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn error_code(&self) -> ErrorCode {
|
||||||
|
self.kind()
|
||||||
|
.map(|e| e.error_code())
|
||||||
|
.unwrap_or(ErrorCode::UNKNOWN_ERROR)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for Error {
|
impl std::fmt::Debug for Error {
|
||||||
|
@ -55,21 +63,12 @@ pub(crate) enum UploadError {
|
||||||
#[error("Error in old repo")]
|
#[error("Error in old repo")]
|
||||||
OldRepo(#[from] crate::repo_04::RepoError),
|
OldRepo(#[from] crate::repo_04::RepoError),
|
||||||
|
|
||||||
#[error("Error parsing string")]
|
|
||||||
ParseString(#[from] std::string::FromUtf8Error),
|
|
||||||
|
|
||||||
#[error("Error interacting with filesystem")]
|
#[error("Error interacting with filesystem")]
|
||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
|
|
||||||
#[error("Error validating upload")]
|
#[error("Error validating upload")]
|
||||||
Validation(#[from] crate::validate::ValidationError),
|
Validation(#[from] crate::validate::ValidationError),
|
||||||
|
|
||||||
#[error("Error generating path")]
|
|
||||||
PathGenerator(#[from] storage_path_generator::PathError),
|
|
||||||
|
|
||||||
#[error("Error stripping prefix")]
|
|
||||||
StripPrefix(#[from] std::path::StripPrefixError),
|
|
||||||
|
|
||||||
#[error("Error in store")]
|
#[error("Error in store")]
|
||||||
Store(#[source] crate::store::StoreError),
|
Store(#[source] crate::store::StoreError),
|
||||||
|
|
||||||
|
@ -127,11 +126,8 @@ pub(crate) enum UploadError {
|
||||||
#[error("Tried to save an image with an already-taken name")]
|
#[error("Tried to save an image with an already-taken name")]
|
||||||
DuplicateAlias,
|
DuplicateAlias,
|
||||||
|
|
||||||
#[error("Error in json")]
|
#[error("Failed to serialize job")]
|
||||||
Json(#[from] serde_json::Error),
|
PushJob(#[source] serde_json::Error),
|
||||||
|
|
||||||
#[error("Error in cbor")]
|
|
||||||
Cbor(#[from] serde_cbor::Error),
|
|
||||||
|
|
||||||
#[error("Range header not satisfiable")]
|
#[error("Range header not satisfiable")]
|
||||||
Range,
|
Range,
|
||||||
|
@ -143,6 +139,41 @@ pub(crate) enum UploadError {
|
||||||
Timeout(#[from] crate::stream::TimeoutError),
|
Timeout(#[from] crate::stream::TimeoutError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl UploadError {
|
||||||
|
const fn error_code(&self) -> ErrorCode {
|
||||||
|
match self {
|
||||||
|
Self::Upload(_) => ErrorCode::FILE_UPLOAD_ERROR,
|
||||||
|
Self::Repo(e) => e.error_code(),
|
||||||
|
Self::OldRepo(_) => ErrorCode::OLD_REPO_ERROR,
|
||||||
|
Self::Io(_) => ErrorCode::IO_ERROR,
|
||||||
|
Self::Validation(e) => e.error_code(),
|
||||||
|
Self::Store(e) => e.error_code(),
|
||||||
|
Self::Ffmpeg(e) => e.error_code(),
|
||||||
|
Self::Magick(e) => e.error_code(),
|
||||||
|
Self::Exiftool(e) => e.error_code(),
|
||||||
|
Self::BuildClient(_) | Self::RequestMiddleware(_) | Self::Request(_) => {
|
||||||
|
ErrorCode::HTTP_CLIENT_ERROR
|
||||||
|
}
|
||||||
|
Self::Download(_) => ErrorCode::DOWNLOAD_FILE_ERROR,
|
||||||
|
Self::ReadOnly => ErrorCode::READ_ONLY,
|
||||||
|
Self::InvalidProcessExtension => ErrorCode::INVALID_FILE_EXTENSION,
|
||||||
|
Self::ParsePath => ErrorCode::INVALID_PROCESS_PATH,
|
||||||
|
Self::Semaphore => ErrorCode::PROCESS_SEMAPHORE_CLOSED,
|
||||||
|
Self::Canceled => ErrorCode::PANIC,
|
||||||
|
Self::NoFiles => ErrorCode::VALIDATE_NO_FILES,
|
||||||
|
Self::MissingAlias => ErrorCode::ALIAS_NOT_FOUND,
|
||||||
|
Self::MissingIdentifier => ErrorCode::LOST_FILE,
|
||||||
|
Self::InvalidToken => ErrorCode::INVALID_DELETE_TOKEN,
|
||||||
|
Self::UnsupportedProcessExtension => ErrorCode::INVALID_FILE_EXTENSION,
|
||||||
|
Self::DuplicateAlias => ErrorCode::DUPLICATE_ALIAS,
|
||||||
|
Self::PushJob(_) => todo!(),
|
||||||
|
Self::Range => ErrorCode::RANGE_NOT_SATISFIABLE,
|
||||||
|
Self::Limit(_) => ErrorCode::VALIDATE_FILE_SIZE,
|
||||||
|
Self::Timeout(_) => ErrorCode::STREAM_TOO_SLOW,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<actix_web::error::BlockingError> for UploadError {
|
impl From<actix_web::error::BlockingError> for UploadError {
|
||||||
fn from(_: actix_web::error::BlockingError) -> Self {
|
fn from(_: actix_web::error::BlockingError) -> Self {
|
||||||
UploadError::Canceled
|
UploadError::Canceled
|
||||||
|
@ -196,8 +227,13 @@ impl ResponseError for Error {
|
||||||
HttpResponse::build(self.status_code())
|
HttpResponse::build(self.status_code())
|
||||||
.content_type("application/json")
|
.content_type("application/json")
|
||||||
.body(
|
.body(
|
||||||
serde_json::to_string(&serde_json::json!({ "msg": self.root_cause().to_string() }))
|
serde_json::to_string(&serde_json::json!({
|
||||||
.unwrap_or_else(|_| r#"{"msg":"Request failed"}"#.to_string()),
|
"msg": self.root_cause().to_string(),
|
||||||
|
"code": self.error_code()
|
||||||
|
}))
|
||||||
|
.unwrap_or_else(|_| {
|
||||||
|
r#"{"msg":"Request failed","code":"unknown-error"}"#.to_string()
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
137
src/error_code.rs
Normal file
137
src/error_code.rs
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
#[derive(Debug, serde::Serialize)]
|
||||||
|
#[serde(transparent)]
|
||||||
|
pub(crate) struct ErrorCode {
|
||||||
|
code: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(transparent)]
|
||||||
|
pub(crate) struct OwnedErrorCode {
|
||||||
|
code: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ErrorCode {
|
||||||
|
pub(crate) fn into_owned(self) -> OwnedErrorCode {
|
||||||
|
OwnedErrorCode {
|
||||||
|
code: self.code.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) const COMMAND_TIMEOUT: ErrorCode = ErrorCode {
|
||||||
|
code: "command-timeout",
|
||||||
|
};
|
||||||
|
pub(crate) const COMMAND_ERROR: ErrorCode = ErrorCode {
|
||||||
|
code: "command-error",
|
||||||
|
};
|
||||||
|
pub(crate) const COMMAND_FAILURE: ErrorCode = ErrorCode {
|
||||||
|
code: "command-failure",
|
||||||
|
};
|
||||||
|
pub(crate) const OLD_REPO_ERROR: ErrorCode = ErrorCode {
|
||||||
|
code: "old-repo-error",
|
||||||
|
};
|
||||||
|
pub(crate) const NOT_FOUND: ErrorCode = ErrorCode { code: "not-found" };
|
||||||
|
pub(crate) const FILE_IO_ERROR: ErrorCode = ErrorCode {
|
||||||
|
code: "file-io-error",
|
||||||
|
};
|
||||||
|
pub(crate) const PARSE_PATH_ERROR: ErrorCode = ErrorCode {
|
||||||
|
code: "parse-path-error",
|
||||||
|
};
|
||||||
|
pub(crate) const FILE_EXISTS: ErrorCode = ErrorCode {
|
||||||
|
code: "file-exists",
|
||||||
|
};
|
||||||
|
pub(crate) const FORMAT_FILE_ID_ERROR: ErrorCode = ErrorCode {
|
||||||
|
code: "format-file-id-error",
|
||||||
|
};
|
||||||
|
pub(crate) const OBJECT_REQUEST_ERROR: ErrorCode = ErrorCode {
|
||||||
|
code: "object-request-error",
|
||||||
|
};
|
||||||
|
pub(crate) const OBJECT_IO_ERROR: ErrorCode = ErrorCode {
|
||||||
|
code: "object-io-error",
|
||||||
|
};
|
||||||
|
pub(crate) const PARSE_OBJECT_ID_ERROR: ErrorCode = ErrorCode {
|
||||||
|
code: "parse-object-id-error",
|
||||||
|
};
|
||||||
|
pub(crate) const PANIC: ErrorCode = ErrorCode { code: "panic" };
|
||||||
|
pub(crate) const ALREADY_CLAIMED: ErrorCode = ErrorCode {
|
||||||
|
code: "already-claimed",
|
||||||
|
};
|
||||||
|
pub(crate) const SLED_ERROR: ErrorCode = ErrorCode { code: "sled-error" };
|
||||||
|
pub(crate) const EXTRACT_DETAILS: ErrorCode = ErrorCode {
|
||||||
|
code: "extract-details",
|
||||||
|
};
|
||||||
|
pub(crate) const EXTRACT_UPLOAD_RESULT: ErrorCode = ErrorCode {
|
||||||
|
code: "extract-upload-result",
|
||||||
|
};
|
||||||
|
pub(crate) const CONFLICTED_RECORD: ErrorCode = ErrorCode {
|
||||||
|
code: "conflicted-record",
|
||||||
|
};
|
||||||
|
pub(crate) const COMMAND_NOT_FOUND: ErrorCode = ErrorCode {
|
||||||
|
code: "command-not-found",
|
||||||
|
};
|
||||||
|
pub(crate) const COMMAND_PERMISSION_DENIED: ErrorCode = ErrorCode {
|
||||||
|
code: "command-permission-denied",
|
||||||
|
};
|
||||||
|
pub(crate) const FILE_UPLOAD_ERROR: ErrorCode = ErrorCode {
|
||||||
|
code: "file-upload-error",
|
||||||
|
};
|
||||||
|
pub(crate) const IO_ERROR: ErrorCode = ErrorCode { code: "io-error" };
|
||||||
|
pub(crate) const VALIDATE_WIDTH: ErrorCode = ErrorCode {
|
||||||
|
code: "validate-width",
|
||||||
|
};
|
||||||
|
pub(crate) const VALIDATE_HEIGHT: ErrorCode = ErrorCode {
|
||||||
|
code: "validate-height",
|
||||||
|
};
|
||||||
|
pub(crate) const VALIDATE_AREA: ErrorCode = ErrorCode {
|
||||||
|
code: "validate-area",
|
||||||
|
};
|
||||||
|
pub(crate) const VALIDATE_FRAMES: ErrorCode = ErrorCode {
|
||||||
|
code: "validate-frames",
|
||||||
|
};
|
||||||
|
pub(crate) const VALIDATE_FILE_EMPTY: ErrorCode = ErrorCode {
|
||||||
|
code: "validate-file-empty",
|
||||||
|
};
|
||||||
|
pub(crate) const VALIDATE_FILE_SIZE: ErrorCode = ErrorCode {
|
||||||
|
code: "validate-file-size",
|
||||||
|
};
|
||||||
|
pub(crate) const VIDEO_DISABLED: ErrorCode = ErrorCode {
|
||||||
|
code: "video-disabled",
|
||||||
|
};
|
||||||
|
pub(crate) const HTTP_CLIENT_ERROR: ErrorCode = ErrorCode {
|
||||||
|
code: "http-client-error",
|
||||||
|
};
|
||||||
|
pub(crate) const DOWNLOAD_FILE_ERROR: ErrorCode = ErrorCode {
|
||||||
|
code: "download-file-error",
|
||||||
|
};
|
||||||
|
pub(crate) const READ_ONLY: ErrorCode = ErrorCode { code: "read-only" };
|
||||||
|
pub(crate) const INVALID_FILE_EXTENSION: ErrorCode = ErrorCode {
|
||||||
|
code: "invalid-file-extension",
|
||||||
|
};
|
||||||
|
pub(crate) const INVALID_PROCESS_PATH: ErrorCode = ErrorCode {
|
||||||
|
code: "invalid-process-path",
|
||||||
|
};
|
||||||
|
pub(crate) const PROCESS_SEMAPHORE_CLOSED: ErrorCode = ErrorCode {
|
||||||
|
code: "process-semaphore-closed",
|
||||||
|
};
|
||||||
|
pub(crate) const VALIDATE_NO_FILES: ErrorCode = ErrorCode {
|
||||||
|
code: "validate-no-files",
|
||||||
|
};
|
||||||
|
pub(crate) const ALIAS_NOT_FOUND: ErrorCode = ErrorCode {
|
||||||
|
code: "alias-not-found",
|
||||||
|
};
|
||||||
|
pub(crate) const LOST_FILE: ErrorCode = ErrorCode { code: "lost-file" };
|
||||||
|
pub(crate) const INVALID_DELETE_TOKEN: ErrorCode = ErrorCode {
|
||||||
|
code: "invalid-delete-token",
|
||||||
|
};
|
||||||
|
pub(crate) const DUPLICATE_ALIAS: ErrorCode = ErrorCode {
|
||||||
|
code: "duplicate-alias",
|
||||||
|
};
|
||||||
|
pub(crate) const RANGE_NOT_SATISFIABLE: ErrorCode = ErrorCode {
|
||||||
|
code: "range-not-satisfiable",
|
||||||
|
};
|
||||||
|
pub(crate) const STREAM_TOO_SLOW: ErrorCode = ErrorCode {
|
||||||
|
code: "stream-too-slow",
|
||||||
|
};
|
||||||
|
pub(crate) const UNKNOWN_ERROR: ErrorCode = ErrorCode {
|
||||||
|
code: "unknown-error",
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,4 +1,7 @@
|
||||||
use crate::process::{Process, ProcessError};
|
use crate::{
|
||||||
|
error_code::ErrorCode,
|
||||||
|
process::{Process, ProcessError},
|
||||||
|
};
|
||||||
use actix_web::web::Bytes;
|
use actix_web::web::Bytes;
|
||||||
use tokio::io::{AsyncRead, AsyncReadExt};
|
use tokio::io::{AsyncRead, AsyncReadExt};
|
||||||
|
|
||||||
|
@ -24,6 +27,13 @@ impl From<ProcessError> for ExifError {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExifError {
|
impl ExifError {
|
||||||
|
pub(crate) const fn error_code(&self) -> ErrorCode {
|
||||||
|
match self {
|
||||||
|
Self::Process(e) => e.error_code(),
|
||||||
|
Self::Read(_) => ErrorCode::COMMAND_ERROR,
|
||||||
|
Self::CommandFailed(_) => ErrorCode::COMMAND_FAILURE,
|
||||||
|
}
|
||||||
|
}
|
||||||
pub(crate) fn is_client_error(&self) -> bool {
|
pub(crate) fn is_client_error(&self) -> bool {
|
||||||
// if exiftool bails we probably have bad input
|
// if exiftool bails we probably have bad input
|
||||||
matches!(
|
matches!(
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
|
error_code::ErrorCode,
|
||||||
formats::InternalVideoFormat,
|
formats::InternalVideoFormat,
|
||||||
process::{Process, ProcessError},
|
process::{Process, ProcessError},
|
||||||
store::{Store, StoreError},
|
store::{Store, StoreError},
|
||||||
|
@ -63,6 +64,24 @@ impl From<ProcessError> for FfMpegError {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FfMpegError {
|
impl FfMpegError {
|
||||||
|
pub(crate) const fn error_code(&self) -> ErrorCode {
|
||||||
|
match self {
|
||||||
|
Self::CommandFailed(_) => ErrorCode::COMMAND_FAILURE,
|
||||||
|
Self::Store(s) => s.error_code(),
|
||||||
|
Self::Process(e) => e.error_code(),
|
||||||
|
Self::Read(_)
|
||||||
|
| Self::Write(_)
|
||||||
|
| Self::Json(_)
|
||||||
|
| Self::CreateDir(_)
|
||||||
|
| Self::ReadFile(_)
|
||||||
|
| Self::OpenFile(_)
|
||||||
|
| Self::CreateFile(_)
|
||||||
|
| Self::CloseFile(_)
|
||||||
|
| Self::RemoveFile(_)
|
||||||
|
| Self::Path => ErrorCode::COMMAND_ERROR,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn is_client_error(&self) -> bool {
|
pub(crate) fn is_client_error(&self) -> bool {
|
||||||
// Failing validation or ffmpeg bailing probably means bad input
|
// Failing validation or ffmpeg bailing probably means bad input
|
||||||
matches!(
|
matches!(
|
||||||
|
|
|
@ -6,6 +6,7 @@ mod details;
|
||||||
mod discover;
|
mod discover;
|
||||||
mod either;
|
mod either;
|
||||||
mod error;
|
mod error;
|
||||||
|
mod error_code;
|
||||||
mod exiftool;
|
mod exiftool;
|
||||||
mod ffmpeg;
|
mod ffmpeg;
|
||||||
mod file;
|
mod file;
|
||||||
|
@ -450,11 +451,11 @@ async fn claim_upload<S: Store + 'static>(
|
||||||
}]
|
}]
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
UploadResult::Failure { message } => Ok(HttpResponse::UnprocessableEntity().json(
|
UploadResult::Failure { message, code } => Ok(HttpResponse::UnprocessableEntity()
|
||||||
&serde_json::json!({
|
.json(&serde_json::json!({
|
||||||
"msg": message,
|
"msg": message,
|
||||||
}),
|
"code": code,
|
||||||
)),
|
}))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_) => Ok(HttpResponse::NoContent().finish()),
|
Err(_) => Ok(HttpResponse::NoContent().finish()),
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
|
error_code::ErrorCode,
|
||||||
formats::ProcessableFormat,
|
formats::ProcessableFormat,
|
||||||
process::{Process, ProcessError},
|
process::{Process, ProcessError},
|
||||||
store::Store,
|
store::Store,
|
||||||
|
@ -57,6 +58,24 @@ impl From<ProcessError> for MagickError {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MagickError {
|
impl MagickError {
|
||||||
|
pub(crate) const fn error_code(&self) -> ErrorCode {
|
||||||
|
match self {
|
||||||
|
Self::CommandFailed(_) => ErrorCode::COMMAND_FAILURE,
|
||||||
|
Self::Store(e) => e.error_code(),
|
||||||
|
Self::Process(e) => e.error_code(),
|
||||||
|
Self::Json(_)
|
||||||
|
| Self::Read(_)
|
||||||
|
| Self::Write(_)
|
||||||
|
| Self::CreateFile(_)
|
||||||
|
| Self::CreateDir(_)
|
||||||
|
| Self::CloseFile(_)
|
||||||
|
| Self::RemoveFile(_)
|
||||||
|
| Self::Discover(_)
|
||||||
|
| Self::Empty
|
||||||
|
| Self::Path => ErrorCode::COMMAND_ERROR,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn is_client_error(&self) -> bool {
|
pub(crate) fn is_client_error(&self) -> bool {
|
||||||
// Failing validation or imagemagick bailing probably means bad input
|
// Failing validation or imagemagick bailing probably means bad input
|
||||||
matches!(
|
matches!(
|
||||||
|
|
|
@ -14,6 +14,8 @@ use tokio::{
|
||||||
};
|
};
|
||||||
use tracing::{Instrument, Span};
|
use tracing::{Instrument, Span};
|
||||||
|
|
||||||
|
use crate::error_code::ErrorCode;
|
||||||
|
|
||||||
struct MetricsGuard {
|
struct MetricsGuard {
|
||||||
start: Instant,
|
start: Instant,
|
||||||
armed: bool,
|
armed: bool,
|
||||||
|
@ -100,6 +102,18 @@ pub(crate) enum ProcessError {
|
||||||
Other(#[source] std::io::Error),
|
Other(#[source] std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ProcessError {
|
||||||
|
pub(crate) const fn error_code(&self) -> ErrorCode {
|
||||||
|
match self {
|
||||||
|
Self::NotFound(_) => ErrorCode::COMMAND_NOT_FOUND,
|
||||||
|
Self::PermissionDenied(_) => ErrorCode::COMMAND_PERMISSION_DENIED,
|
||||||
|
Self::LimitReached | Self::Other(_) => ErrorCode::COMMAND_ERROR,
|
||||||
|
Self::Timeout(_) => ErrorCode::COMMAND_TIMEOUT,
|
||||||
|
Self::Status(_, _) => ErrorCode::COMMAND_FAILURE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Process {
|
impl Process {
|
||||||
pub(crate) fn run(command: &str, args: &[&str], timeout: u64) -> Result<Self, ProcessError> {
|
pub(crate) fn run(command: &str, args: &[&str], timeout: u64) -> Result<Self, ProcessError> {
|
||||||
let res = tracing::trace_span!(parent: None, "Create command", %command)
|
let res = tracing::trace_span!(parent: None, "Create command", %command)
|
||||||
|
|
25
src/queue.rs
25
src/queue.rs
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
concurrent_processor::ProcessMap,
|
concurrent_processor::ProcessMap,
|
||||||
config::Configuration,
|
config::Configuration,
|
||||||
error::Error,
|
error::{Error, UploadError},
|
||||||
formats::InputProcessableFormat,
|
formats::InputProcessableFormat,
|
||||||
repo::{Alias, DeleteToken, FullRepo, Hash, JobId, UploadId},
|
repo::{Alias, DeleteToken, FullRepo, Hash, JobId, UploadId},
|
||||||
serde_str::Serde,
|
serde_str::Serde,
|
||||||
|
@ -94,13 +94,14 @@ pub(crate) async fn cleanup_alias(
|
||||||
let job = serde_json::to_vec(&Cleanup::Alias {
|
let job = serde_json::to_vec(&Cleanup::Alias {
|
||||||
alias: Serde::new(alias),
|
alias: Serde::new(alias),
|
||||||
token: Serde::new(token),
|
token: Serde::new(token),
|
||||||
})?;
|
})
|
||||||
|
.map_err(UploadError::PushJob)?;
|
||||||
repo.push(CLEANUP_QUEUE, job.into()).await?;
|
repo.push(CLEANUP_QUEUE, job.into()).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn cleanup_hash(repo: &Arc<dyn FullRepo>, hash: Hash) -> Result<(), Error> {
|
pub(crate) async fn cleanup_hash(repo: &Arc<dyn FullRepo>, hash: Hash) -> Result<(), Error> {
|
||||||
let job = serde_json::to_vec(&Cleanup::Hash { hash })?;
|
let job = serde_json::to_vec(&Cleanup::Hash { hash }).map_err(UploadError::PushJob)?;
|
||||||
repo.push(CLEANUP_QUEUE, job.into()).await?;
|
repo.push(CLEANUP_QUEUE, job.into()).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -111,7 +112,8 @@ pub(crate) async fn cleanup_identifier<I: Identifier>(
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let job = serde_json::to_vec(&Cleanup::Identifier {
|
let job = serde_json::to_vec(&Cleanup::Identifier {
|
||||||
identifier: Base64Bytes(identifier.to_bytes()?),
|
identifier: Base64Bytes(identifier.to_bytes()?),
|
||||||
})?;
|
})
|
||||||
|
.map_err(UploadError::PushJob)?;
|
||||||
repo.push(CLEANUP_QUEUE, job.into()).await?;
|
repo.push(CLEANUP_QUEUE, job.into()).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -121,25 +123,26 @@ async fn cleanup_variants(
|
||||||
hash: Hash,
|
hash: Hash,
|
||||||
variant: Option<String>,
|
variant: Option<String>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let job = serde_json::to_vec(&Cleanup::Variant { hash, variant })?;
|
let job =
|
||||||
|
serde_json::to_vec(&Cleanup::Variant { hash, variant }).map_err(UploadError::PushJob)?;
|
||||||
repo.push(CLEANUP_QUEUE, job.into()).await?;
|
repo.push(CLEANUP_QUEUE, job.into()).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn cleanup_outdated_proxies(repo: &Arc<dyn FullRepo>) -> Result<(), Error> {
|
pub(crate) async fn cleanup_outdated_proxies(repo: &Arc<dyn FullRepo>) -> Result<(), Error> {
|
||||||
let job = serde_json::to_vec(&Cleanup::OutdatedProxies)?;
|
let job = serde_json::to_vec(&Cleanup::OutdatedProxies).map_err(UploadError::PushJob)?;
|
||||||
repo.push(CLEANUP_QUEUE, job.into()).await?;
|
repo.push(CLEANUP_QUEUE, job.into()).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn cleanup_outdated_variants(repo: &Arc<dyn FullRepo>) -> Result<(), Error> {
|
pub(crate) async fn cleanup_outdated_variants(repo: &Arc<dyn FullRepo>) -> Result<(), Error> {
|
||||||
let job = serde_json::to_vec(&Cleanup::OutdatedVariants)?;
|
let job = serde_json::to_vec(&Cleanup::OutdatedVariants).map_err(UploadError::PushJob)?;
|
||||||
repo.push(CLEANUP_QUEUE, job.into()).await?;
|
repo.push(CLEANUP_QUEUE, job.into()).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn cleanup_all_variants(repo: &Arc<dyn FullRepo>) -> Result<(), Error> {
|
pub(crate) async fn cleanup_all_variants(repo: &Arc<dyn FullRepo>) -> Result<(), Error> {
|
||||||
let job = serde_json::to_vec(&Cleanup::AllVariants)?;
|
let job = serde_json::to_vec(&Cleanup::AllVariants).map_err(UploadError::PushJob)?;
|
||||||
repo.push(CLEANUP_QUEUE, job.into()).await?;
|
repo.push(CLEANUP_QUEUE, job.into()).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -154,7 +157,8 @@ pub(crate) async fn queue_ingest(
|
||||||
identifier: Base64Bytes(identifier),
|
identifier: Base64Bytes(identifier),
|
||||||
declared_alias: declared_alias.map(Serde::new),
|
declared_alias: declared_alias.map(Serde::new),
|
||||||
upload_id: Serde::new(upload_id),
|
upload_id: Serde::new(upload_id),
|
||||||
})?;
|
})
|
||||||
|
.map_err(UploadError::PushJob)?;
|
||||||
repo.push(PROCESS_QUEUE, job.into()).await?;
|
repo.push(PROCESS_QUEUE, job.into()).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -171,7 +175,8 @@ pub(crate) async fn queue_generate(
|
||||||
source: Serde::new(source),
|
source: Serde::new(source),
|
||||||
process_path,
|
process_path,
|
||||||
process_args,
|
process_args,
|
||||||
})?;
|
})
|
||||||
|
.map_err(UploadError::PushJob)?;
|
||||||
repo.push(PROCESS_QUEUE, job.into()).await?;
|
repo.push(PROCESS_QUEUE, job.into()).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,6 +117,7 @@ where
|
||||||
|
|
||||||
UploadResult::Failure {
|
UploadResult::Failure {
|
||||||
message: e.root_cause().to_string(),
|
message: e.root_cause().to_string(),
|
||||||
|
code: e.error_code().into_owned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
22
src/repo.rs
22
src/repo.rs
|
@ -1,6 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
config,
|
config,
|
||||||
details::Details,
|
details::Details,
|
||||||
|
error_code::{ErrorCode, OwnedErrorCode},
|
||||||
store::{Identifier, StoreError},
|
store::{Identifier, StoreError},
|
||||||
stream::LocalBoxStream,
|
stream::LocalBoxStream,
|
||||||
};
|
};
|
||||||
|
@ -52,9 +53,16 @@ pub(crate) struct UploadId {
|
||||||
id: Uuid,
|
id: Uuid,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub(crate) enum UploadResult {
|
pub(crate) enum UploadResult {
|
||||||
Success { alias: Alias, token: DeleteToken },
|
Success {
|
||||||
Failure { message: String },
|
alias: Alias,
|
||||||
|
token: DeleteToken,
|
||||||
|
},
|
||||||
|
Failure {
|
||||||
|
message: String,
|
||||||
|
code: OwnedErrorCode,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
@ -69,6 +77,16 @@ pub(crate) enum RepoError {
|
||||||
Canceled,
|
Canceled,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RepoError {
|
||||||
|
pub(crate) const fn error_code(&self) -> ErrorCode {
|
||||||
|
match self {
|
||||||
|
Self::SledError(e) => e.error_code(),
|
||||||
|
Self::AlreadyClaimed => ErrorCode::ALREADY_CLAIMED,
|
||||||
|
Self::Canceled => ErrorCode::PANIC,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
pub(crate) trait FullRepo:
|
pub(crate) trait FullRepo:
|
||||||
UploadRepo
|
UploadRepo
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
details::HumanDate,
|
details::HumanDate,
|
||||||
|
error_code::{ErrorCode, OwnedErrorCode},
|
||||||
serde_str::Serde,
|
serde_str::Serde,
|
||||||
store::StoreError,
|
store::StoreError,
|
||||||
stream::{from_iterator, LocalBoxStream},
|
stream::{from_iterator, LocalBoxStream},
|
||||||
|
@ -46,7 +47,10 @@ pub(crate) enum SledError {
|
||||||
Sled(#[from] sled::Error),
|
Sled(#[from] sled::Error),
|
||||||
|
|
||||||
#[error("Invalid details json")]
|
#[error("Invalid details json")]
|
||||||
Details(#[from] serde_json::Error),
|
Details(serde_json::Error),
|
||||||
|
|
||||||
|
#[error("Invalid upload result json")]
|
||||||
|
UploadResult(serde_json::Error),
|
||||||
|
|
||||||
#[error("Error parsing variant key")]
|
#[error("Error parsing variant key")]
|
||||||
VariantKey(#[from] VariantKeyError),
|
VariantKey(#[from] VariantKeyError),
|
||||||
|
@ -58,6 +62,18 @@ pub(crate) enum SledError {
|
||||||
Conflict,
|
Conflict,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SledError {
|
||||||
|
pub(super) const fn error_code(&self) -> ErrorCode {
|
||||||
|
match self {
|
||||||
|
Self::Sled(_) | Self::VariantKey(_) => ErrorCode::SLED_ERROR,
|
||||||
|
Self::Details(_) => ErrorCode::EXTRACT_DETAILS,
|
||||||
|
Self::UploadResult(_) => ErrorCode::EXTRACT_UPLOAD_RESULT,
|
||||||
|
Self::Panic => ErrorCode::PANIC,
|
||||||
|
Self::Conflict => ErrorCode::CONFLICTED_RECORD,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct SledRepo {
|
pub(crate) struct SledRepo {
|
||||||
healthz_count: Arc<AtomicU64>,
|
healthz_count: Arc<AtomicU64>,
|
||||||
|
@ -442,6 +458,7 @@ enum InnerUploadResult {
|
||||||
},
|
},
|
||||||
Failure {
|
Failure {
|
||||||
message: String,
|
message: String,
|
||||||
|
code: OwnedErrorCode,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,7 +469,7 @@ impl From<UploadResult> for InnerUploadResult {
|
||||||
alias: Serde::new(alias),
|
alias: Serde::new(alias),
|
||||||
token: Serde::new(token),
|
token: Serde::new(token),
|
||||||
},
|
},
|
||||||
UploadResult::Failure { message } => InnerUploadResult::Failure { message },
|
UploadResult::Failure { message, code } => InnerUploadResult::Failure { message, code },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -464,7 +481,7 @@ impl From<InnerUploadResult> for UploadResult {
|
||||||
alias: Serde::into_inner(alias),
|
alias: Serde::into_inner(alias),
|
||||||
token: Serde::into_inner(token),
|
token: Serde::into_inner(token),
|
||||||
},
|
},
|
||||||
InnerUploadResult::Failure { message } => UploadResult::Failure { message },
|
InnerUploadResult::Failure { message, code } => UploadResult::Failure { message, code },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -538,7 +555,7 @@ impl UploadRepo for SledRepo {
|
||||||
if let Some(bytes) = opt {
|
if let Some(bytes) = opt {
|
||||||
if bytes != b"1" {
|
if bytes != b"1" {
|
||||||
let result: InnerUploadResult =
|
let result: InnerUploadResult =
|
||||||
serde_json::from_slice(&bytes).map_err(SledError::from)?;
|
serde_json::from_slice(&bytes).map_err(SledError::UploadResult)?;
|
||||||
return Ok(result.into());
|
return Ok(result.into());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -553,7 +570,7 @@ impl UploadRepo for SledRepo {
|
||||||
sled::Event::Insert { value, .. } => {
|
sled::Event::Insert { value, .. } => {
|
||||||
if value != b"1" {
|
if value != b"1" {
|
||||||
let result: InnerUploadResult =
|
let result: InnerUploadResult =
|
||||||
serde_json::from_slice(&value).map_err(SledError::from)?;
|
serde_json::from_slice(&value).map_err(SledError::UploadResult)?;
|
||||||
return Ok(result.into());
|
return Ok(result.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -576,7 +593,7 @@ impl UploadRepo for SledRepo {
|
||||||
result: UploadResult,
|
result: UploadResult,
|
||||||
) -> Result<(), RepoError> {
|
) -> Result<(), RepoError> {
|
||||||
let result: InnerUploadResult = result.into();
|
let result: InnerUploadResult = result.into();
|
||||||
let result = serde_json::to_vec(&result).map_err(SledError::from)?;
|
let result = serde_json::to_vec(&result).map_err(SledError::UploadResult)?;
|
||||||
|
|
||||||
b!(self.uploads, uploads.insert(upload_id.as_bytes(), result));
|
b!(self.uploads, uploads.insert(upload_id.as_bytes(), result));
|
||||||
|
|
||||||
|
@ -940,7 +957,7 @@ impl DetailsRepo for SledRepo {
|
||||||
) -> Result<(), StoreError> {
|
) -> Result<(), StoreError> {
|
||||||
let key = identifier.to_bytes()?;
|
let key = identifier.to_bytes()?;
|
||||||
let details = serde_json::to_vec(&details.inner)
|
let details = serde_json::to_vec(&details.inner)
|
||||||
.map_err(SledError::from)
|
.map_err(SledError::Details)
|
||||||
.map_err(RepoError::from)?;
|
.map_err(RepoError::from)?;
|
||||||
|
|
||||||
b!(
|
b!(
|
||||||
|
@ -959,7 +976,7 @@ impl DetailsRepo for SledRepo {
|
||||||
|
|
||||||
opt.map(|ivec| serde_json::from_slice(&ivec).map(|inner| Details { inner }))
|
opt.map(|ivec| serde_json::from_slice(&ivec).map(|inner| Details { inner }))
|
||||||
.transpose()
|
.transpose()
|
||||||
.map_err(SledError::from)
|
.map_err(SledError::Details)
|
||||||
.map_err(RepoError::from)
|
.map_err(RepoError::from)
|
||||||
.map_err(StoreError::from)
|
.map_err(StoreError::from)
|
||||||
}
|
}
|
||||||
|
|
11
src/store.rs
11
src/store.rs
|
@ -4,6 +4,8 @@ use futures_core::Stream;
|
||||||
use std::{fmt::Debug, sync::Arc};
|
use std::{fmt::Debug, sync::Arc};
|
||||||
use tokio::io::{AsyncRead, AsyncWrite};
|
use tokio::io::{AsyncRead, AsyncWrite};
|
||||||
|
|
||||||
|
use crate::error_code::ErrorCode;
|
||||||
|
|
||||||
pub(crate) mod file_store;
|
pub(crate) mod file_store;
|
||||||
pub(crate) mod object_store;
|
pub(crate) mod object_store;
|
||||||
|
|
||||||
|
@ -29,6 +31,15 @@ pub(crate) enum StoreError {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StoreError {
|
impl StoreError {
|
||||||
|
pub(crate) const fn error_code(&self) -> ErrorCode {
|
||||||
|
match self {
|
||||||
|
Self::FileStore(e) => e.error_code(),
|
||||||
|
Self::ObjectStore(e) => e.error_code(),
|
||||||
|
Self::Repo(e) => e.error_code(),
|
||||||
|
Self::Repo04(_) => ErrorCode::OLD_REPO_ERROR,
|
||||||
|
Self::FileNotFound(_) | Self::ObjectNotFound(_) => ErrorCode::NOT_FOUND,
|
||||||
|
}
|
||||||
|
}
|
||||||
pub(crate) const fn is_not_found(&self) -> bool {
|
pub(crate) const fn is_not_found(&self) -> bool {
|
||||||
matches!(self, Self::FileNotFound(_)) || matches!(self, Self::ObjectNotFound(_))
|
matches!(self, Self::FileNotFound(_)) || matches!(self, Self::ObjectNotFound(_))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
|
error_code::ErrorCode,
|
||||||
file::File,
|
file::File,
|
||||||
repo::{Repo, SettingsRepo},
|
repo::{Repo, SettingsRepo},
|
||||||
store::Store,
|
store::Store,
|
||||||
|
@ -32,16 +33,27 @@ pub(crate) enum FileError {
|
||||||
#[error("Failed to generate path")]
|
#[error("Failed to generate path")]
|
||||||
PathGenerator(#[from] storage_path_generator::PathError),
|
PathGenerator(#[from] storage_path_generator::PathError),
|
||||||
|
|
||||||
#[error("Error formatting file store identifier")]
|
#[error("Error formatting file store ID")]
|
||||||
IdError,
|
IdError,
|
||||||
|
|
||||||
#[error("Mailformed file store identifier")]
|
#[error("Malformed file store ID")]
|
||||||
PrefixError,
|
PrefixError,
|
||||||
|
|
||||||
#[error("Tried to save over existing file")]
|
#[error("Tried to save over existing file")]
|
||||||
FileExists,
|
FileExists,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FileError {
|
||||||
|
pub(super) const fn error_code(&self) -> ErrorCode {
|
||||||
|
match self {
|
||||||
|
Self::Io(_) => ErrorCode::FILE_IO_ERROR,
|
||||||
|
Self::PathGenerator(_) => ErrorCode::PARSE_PATH_ERROR,
|
||||||
|
Self::FileExists => ErrorCode::FILE_EXISTS,
|
||||||
|
Self::IdError | Self::PrefixError => ErrorCode::FORMAT_FILE_ID_ERROR,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct FileStore {
|
pub(crate) struct FileStore {
|
||||||
path_gen: Generator,
|
path_gen: Generator,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
bytes_stream::BytesStream,
|
bytes_stream::BytesStream,
|
||||||
|
error_code::ErrorCode,
|
||||||
repo::{Repo, SettingsRepo},
|
repo::{Repo, SettingsRepo},
|
||||||
store::Store,
|
store::Store,
|
||||||
stream::{IntoStreamer, StreamMap},
|
stream::{IntoStreamer, StreamMap},
|
||||||
|
@ -67,21 +68,39 @@ pub(crate) enum ObjectError {
|
||||||
Etag,
|
Etag,
|
||||||
|
|
||||||
#[error("Task cancelled")]
|
#[error("Task cancelled")]
|
||||||
Cancelled,
|
Canceled,
|
||||||
|
|
||||||
#[error("Invalid status: {0}\n{1}")]
|
#[error("Invalid status: {0}\n{1}")]
|
||||||
Status(StatusCode, String),
|
Status(StatusCode, String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ObjectError {
|
||||||
|
pub(super) const fn error_code(&self) -> ErrorCode {
|
||||||
|
match self {
|
||||||
|
Self::PathGenerator(_) => ErrorCode::PARSE_PATH_ERROR,
|
||||||
|
Self::S3(_)
|
||||||
|
| Self::RequestMiddleware(_)
|
||||||
|
| Self::Request(_)
|
||||||
|
| Self::Xml(_)
|
||||||
|
| Self::Length
|
||||||
|
| Self::Etag
|
||||||
|
| Self::Status(_, _) => ErrorCode::OBJECT_REQUEST_ERROR,
|
||||||
|
Self::IO(_) => ErrorCode::OBJECT_IO_ERROR,
|
||||||
|
Self::Utf8(_) => ErrorCode::PARSE_OBJECT_ID_ERROR,
|
||||||
|
Self::Canceled => ErrorCode::PANIC,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<JoinError> for ObjectError {
|
impl From<JoinError> for ObjectError {
|
||||||
fn from(_: JoinError) -> Self {
|
fn from(_: JoinError) -> Self {
|
||||||
Self::Cancelled
|
Self::Canceled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<BlockingError> for ObjectError {
|
impl From<BlockingError> for ObjectError {
|
||||||
fn from(_: BlockingError) -> Self {
|
fn from(_: BlockingError) -> Self {
|
||||||
Self::Cancelled
|
Self::Canceled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ use crate::{
|
||||||
discover::Discovery,
|
discover::Discovery,
|
||||||
either::Either,
|
either::Either,
|
||||||
error::Error,
|
error::Error,
|
||||||
|
error_code::ErrorCode,
|
||||||
formats::{
|
formats::{
|
||||||
AnimationFormat, AnimationOutput, ImageInput, ImageOutput, InputFile, InputVideoFormat,
|
AnimationFormat, AnimationOutput, ImageInput, ImageOutput, InputFile, InputVideoFormat,
|
||||||
InternalFormat, Validations,
|
InternalFormat, Validations,
|
||||||
|
@ -38,6 +39,20 @@ pub(crate) enum ValidationError {
|
||||||
VideoDisabled,
|
VideoDisabled,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ValidationError {
|
||||||
|
pub(crate) const fn error_code(&self) -> ErrorCode {
|
||||||
|
match self {
|
||||||
|
Self::Width => ErrorCode::VALIDATE_WIDTH,
|
||||||
|
Self::Height => ErrorCode::VALIDATE_HEIGHT,
|
||||||
|
Self::Area => ErrorCode::VALIDATE_AREA,
|
||||||
|
Self::Frames => ErrorCode::VALIDATE_FRAMES,
|
||||||
|
Self::Empty => ErrorCode::VALIDATE_FILE_EMPTY,
|
||||||
|
Self::Filesize => ErrorCode::VALIDATE_FILE_SIZE,
|
||||||
|
Self::VideoDisabled => ErrorCode::VIDEO_DISABLED,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const MEGABYTES: usize = 1024 * 1024;
|
const MEGABYTES: usize = 1024 * 1024;
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
|
|
Loading…
Reference in a new issue