Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ axum = "0.8.1"
axum-extra = { version = "0.10.0", features = ["typed-header"] }
chrono = "0.4.39"
clap = { version = "4.5.30", features = ["cargo", "derive", "env", "string"] }
derive_more = { version = "2.0.1", features = ["error", "display", "from", "deref"] }
futures = "0.3.31"
opentelemetry = "0.28.0"
opentelemetry-otlp = { version = "0.28.0", features = ["grpc-tonic"] }
Expand Down
56 changes: 10 additions & 46 deletions src/db_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,66 +374,30 @@ impl fmt::Debug for SqliteScanPathService {
}

mod error {
use std::error::Error;
use std::fmt::{self, Display};
use derive_more::{Display, Error, From};

#[derive(Debug)]
#[derive(Debug, Display, Error, From)]
pub enum ConfigurationError {
MissingBeamline(String),
#[display("No configuration available for beamline {_0:?}")]
MissingBeamline(#[error(ignore)] String),
#[display("Error reading configuration: {_0}")]
Db(sqlx::Error),
}

impl Display for ConfigurationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ConfigurationError::MissingBeamline(bl) => {
write!(f, "No configuration available for beamline {bl:?}")
}
ConfigurationError::Db(e) => write!(f, "Error reading configuration: {e}"),
}
}
}

impl Error for ConfigurationError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
ConfigurationError::MissingBeamline(_) => None,
ConfigurationError::Db(e) => Some(e),
}
}
}

impl From<sqlx::Error> for ConfigurationError {
fn from(value: sqlx::Error) -> Self {
Self::Db(value)
}
}

#[derive(Debug)]
#[derive(Debug, Display, From)]
pub enum NewConfigurationError {
#[display("Missing field {_0:?} for new configuration")]
MissingField(String),
#[from]
#[display("Error inserting new configuration: {_0}")]
Db(sqlx::Error),
}
impl Display for NewConfigurationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
NewConfigurationError::MissingField(name) => {
write!(f, "Missing field {name:?} for new configuration")
}
NewConfigurationError::Db(e) => write!(f, "Error inserting new configuration: {e}"),
}
}
}

impl From<&str> for NewConfigurationError {
fn from(value: &str) -> Self {
Self::MissingField(value.into())
}
}
impl From<sqlx::Error> for NewConfigurationError {
fn from(value: sqlx::Error) -> Self {
Self::Db(value)
}
}
}

#[cfg(test)]
Expand Down
40 changes: 8 additions & 32 deletions src/graphql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

use std::any;
use std::borrow::Cow;
use std::error::Error;
use std::fmt::Display;
use std::future::Future;
use std::io::Write;
Expand All @@ -38,6 +37,7 @@ use axum_extra::headers::authorization::Bearer;
use axum_extra::headers::Authorization;
use axum_extra::TypedHeader;
use chrono::{Datelike, Local};
use derive_more::{Display, Error};
use tokio::net::TcpListener;
use tracing::{info, instrument, trace, warn};

Expand Down Expand Up @@ -156,7 +156,8 @@ struct CurrentConfiguration {
}

/// Error to be returned when a path contains non-unicode characters
#[derive(Debug)]
#[derive(Debug, Display, Error)]
#[display("Path contains non-unicode characters")]
struct NonUnicodePath;

/// Try and convert a path to a string (via `OsString`), returning a `NonUnicodePath`
Expand All @@ -167,14 +168,6 @@ fn path_to_string(path: PathBuf) -> Result<String, NonUnicodePath> {
.map_err(|_| NonUnicodePath)
}

impl Display for NonUnicodePath {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("Path contains non-unicode characters")
}
}

impl Error for NonUnicodePath {}

#[Object]
/// The path to a visit directory and the components used to build it
impl VisitPath {
Expand Down Expand Up @@ -556,12 +549,14 @@ where
/// Name of subdirectory within visit directory where data should be written.
/// Can be nested (eg foo/bar) but cannot include links to parent directories (eg ../foo).
// Derived Default is OK without validation as empty path is a valid subdirectory
#[derive(Debug, Default)]
#[derive(Debug, Display, Default)]
pub struct Subdirectory(String);

#[derive(Debug)]
#[derive(Debug, Display, Error)]
pub enum InvalidSubdirectory {
InvalidComponent(usize),
#[display("Segment {_0} of path is not valid for a subdirectory")]
InvalidComponent(#[error(ignore)] usize),
#[display("Subdirectory cannot be absolute")]
AbsolutePath,
}

Expand Down Expand Up @@ -596,25 +591,6 @@ impl ScalarType for Subdirectory {
}
}

impl Display for InvalidSubdirectory {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
InvalidSubdirectory::InvalidComponent(s) => {
write!(f, "Segment {s} of path is not valid for a subdirectory")
}
InvalidSubdirectory::AbsolutePath => f.write_str("Subdirectory cannot be absolute"),
}
}
}

impl Error for InvalidSubdirectory {}

impl Display for Subdirectory {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}

/// Detector name
#[derive(Debug)]
pub struct Detector(String);
Expand Down
32 changes: 5 additions & 27 deletions src/graphql/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fmt::Display;
use std::str::FromStr;

use axum_extra::headers::authorization::Bearer;
use axum_extra::headers::Authorization;
use derive_more::{Display, Error, From};
use serde::{Deserialize, Serialize};
use tracing::info;

Expand Down Expand Up @@ -162,38 +162,16 @@ impl PolicyCheck {
}
}

#[derive(Debug)]
#[derive(Debug, Display, Error, From)]
pub enum AuthError {
#[display("Invalid authorization configuration")]
ServerError(reqwest::Error),
#[display("Authentication failed")]
Failed,
#[display("No authentication token was provided")]
Missing,
}

impl Display for AuthError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AuthError::ServerError(_) => write!(f, "Invalid authorization configuration"),
AuthError::Failed => write!(f, "Authentication failed"),
AuthError::Missing => f.write_str("No authentication token was provided"),
}
}
}

impl std::error::Error for AuthError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
AuthError::ServerError(e) => Some(e),
_ => None,
}
}
}

impl From<reqwest::Error> for AuthError {
fn from(value: reqwest::Error) -> Self {
Self::ServerError(value)
}
}

#[cfg(test)]
mod tests {
use std::str::FromStr as _;
Expand Down
25 changes: 6 additions & 19 deletions src/numtracker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
// limitations under the License.

use std::collections::HashMap;
use std::fmt::{self, Display};
use std::io::Error;
use std::path::{Path, PathBuf};

use derive_more::{Display, Error};
#[cfg(test)]
pub use tests::TempTracker;
use tokio::fs as async_fs;
Expand Down Expand Up @@ -162,32 +162,26 @@ impl GdaNumTracker<'_, '_> {
}

/// Error returned when an extension would result in directory traversal - eg '.foo/../../bar'
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Display, Error, Clone, Copy)]
#[display("Extension is not valid")]
pub struct InvalidExtension;

impl Display for InvalidExtension {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Extension is not valid")
}
}

impl std::error::Error for InvalidExtension {}

#[cfg(test)]
mod tests {
use std::ops::Deref;
use std::path::Path;
use std::time::Duration;
use std::{fs, io};

use derive_more::Deref;
use rstest::{fixture, rstest};
use tempfile::{tempdir, TempDir};
use tokio::time::timeout;

use super::{InvalidExtension, NumTracker};

/// Wrapper around a NumTracker to ensure the tempdir is not dropped while it is still required
pub struct TempTracker(pub NumTracker, pub TempDir);
#[derive(Deref)]
pub struct TempTracker(#[deref] pub NumTracker, pub TempDir);
impl TempTracker {
pub fn new<F>(init: F) -> Self
where
Expand All @@ -198,13 +192,6 @@ mod tests {
Self(NumTracker::for_root_directory(Some(&root)).unwrap(), root)
}
}
impl Deref for TempTracker {
type Target = NumTracker;

fn deref(&self) -> &Self::Target {
&self.0
}
}

#[rstest::fixture]
fn root() -> TempDir {
Expand Down
Loading