Skip to content

Commit

Permalink
Merge pull request #298 from umccr/feat/encryption-scheme
Browse files Browse the repository at this point in the history
feat: encryption scheme
  • Loading branch information
mmalenic authored Jan 24, 2025
2 parents aa1bc8e + c78087b commit fc84e7e
Show file tree
Hide file tree
Showing 12 changed files with 153 additions and 55 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion htsget-config/src/config/advanced/url.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use reqwest::Client;
use serde::{Deserialize, Serialize};

/// Options for the remote URL server config.
#[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
#[serde(deny_unknown_fields)]
pub struct Url {
#[serde(with = "http_serde::uri")]
Expand Down
11 changes: 11 additions & 0 deletions htsget-config/src/encryption_scheme.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//! Types related to the experimental encryption scheme.
//!
use serde::{Deserialize, Serialize};

/// The file encryption scheme
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum EncryptionScheme {
C4GH,
}
2 changes: 2 additions & 0 deletions htsget-config/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
pub use clap::command;

pub mod config;
#[cfg(feature = "experimental")]
pub mod encryption_scheme;
pub mod error;
pub mod resolver;
pub mod storage;
Expand Down
2 changes: 1 addition & 1 deletion htsget-config/src/storage/url.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use reqwest::Client;
use serde::{Deserialize, Serialize};

/// Remote URL server storage struct.
#[derive(Deserialize, Serialize, Debug, Clone)]
#[derive(Deserialize, Serialize, Debug, Clone, Default)]
#[serde(try_from = "advanced::url::Url", deny_unknown_fields)]
pub struct Url {
#[serde(with = "http_serde::uri")]
Expand Down
53 changes: 39 additions & 14 deletions htsget-config/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,25 @@ use std::fmt::{Debug, Display, Formatter};
use std::io::ErrorKind::Other;
use std::{fmt, io, result};

#[cfg(feature = "experimental")]
use crate::encryption_scheme::EncryptionScheme;
use crate::error::Error;
use crate::error::Error::ParseError;
use http::HeaderMap;
use noodles::core::region::Interval as NoodlesInterval;
use noodles::core::Position;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use tracing::instrument;

use crate::error::Error;
use crate::error::Error::ParseError;

/// The result type returning a `HtsGetError`.
pub type Result<T> = result::Result<T, HtsGetError>;

/// An enumeration with all the possible formats.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all(serialize = "UPPERCASE"), deny_unknown_fields)]
pub enum Format {
#[default]
#[serde(alias = "bam", alias = "BAM")]
Bam,
#[serde(alias = "cram", alias = "CRAM")]
Expand Down Expand Up @@ -111,11 +113,12 @@ impl Display for Format {
}

/// Class component of htsget response.
#[derive(Copy, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
#[derive(Copy, Debug, PartialEq, Eq, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all(serialize = "lowercase"), deny_unknown_fields)]
pub enum Class {
#[serde(alias = "header", alias = "HEADER")]
Header,
#[default]
#[serde(alias = "body", alias = "BODY")]
Body,
}
Expand Down Expand Up @@ -242,6 +245,12 @@ pub enum Fields {
List(HashSet<String>),
}

impl Default for Fields {
fn default() -> Self {
Self::Tagged(TaggedTypeAll::All)
}
}

/// Possible values for the tags parameter.
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
#[serde(untagged, deny_unknown_fields)]
Expand All @@ -252,13 +261,19 @@ pub enum Tags {
List(HashSet<String>),
}

impl Default for Tags {
fn default() -> Self {
Self::Tagged(TaggedTypeAll::All)
}
}

/// The no tags parameter.
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
#[serde(deny_unknown_fields)]
pub struct NoTags(pub Option<HashSet<String>>);

/// A struct containing the information from the HTTP request.
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Default)]
pub struct Request {
path: String,
query: HashMap<String, String>,
Expand Down Expand Up @@ -298,7 +313,7 @@ impl Request {

/// A query contains all the parameters that can be used when requesting
/// a search for either of `reads` or `variants`.
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Default)]
pub struct Query {
id: String,
format: Format,
Expand All @@ -312,6 +327,8 @@ pub struct Query {
no_tags: NoTags,
/// The raw HTTP request information.
request: Request,
#[cfg(feature = "experimental")]
encryption_scheme: Option<EncryptionScheme>,
}

impl Query {
Expand All @@ -320,13 +337,8 @@ impl Query {
Self {
id: id.into(),
format,
class: Class::Body,
reference_name: None,
interval: Interval::default(),
fields: Fields::Tagged(TaggedTypeAll::All),
tags: Tags::Tagged(TaggedTypeAll::All),
no_tags: NoTags(None),
request,
..Default::default()
}
}

Expand Down Expand Up @@ -441,6 +453,19 @@ impl Query {
pub fn request(&self) -> &Request {
&self.request
}

/// Set the encryption scheme.
#[cfg(feature = "experimental")]
pub fn with_encryption_scheme(mut self, encryption_scheme: EncryptionScheme) -> Self {
self.encryption_scheme = Some(encryption_scheme);
self
}

/// Get the encryption scheme
#[cfg(feature = "experimental")]
pub fn encryption_scheme(&self) -> Option<EncryptionScheme> {
self.encryption_scheme
}
}

/// Htsget specific errors.
Expand Down
1 change: 1 addition & 0 deletions htsget-http/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ htsget-test = { version = "0.7.1", path = "../htsget-test", default-features = f
futures = { version = "0.3" }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
tracing = "0.1"
cfg-if = "1"
29 changes: 17 additions & 12 deletions htsget-http/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use std::result;
use std::str::FromStr;

use cfg_if::cfg_if;
pub use error::{HtsGetError, Result};
pub use htsget_config::config::Config;
use htsget_config::types::Format::{Bam, Bcf, Cram, Vcf};
Expand All @@ -10,6 +8,8 @@ pub use post_request::{PostRequest, Region};
use query_builder::QueryBuilder;
pub use service_info::get_service_info_json;
pub use service_info::{Htsget, ServiceInfo, Type};
use std::result;
use std::str::FromStr;

mod error;
mod http_core;
Expand Down Expand Up @@ -57,15 +57,20 @@ pub fn match_format(endpoint: &Endpoint, format: Option<impl Into<String>>) -> R
fn convert_to_query(request: Request, format: Format) -> Result<Query> {
let query = request.query().clone();

Ok(
QueryBuilder::new(request, format)
.with_class(query.get("class"))?
.with_reference_name(query.get("referenceName"))
.with_range(query.get("start"), query.get("end"))?
.with_fields(query.get("fields"))
.with_tags(query.get("tags"), query.get("notags"))?
.build(),
)
let builder = QueryBuilder::new(request, format)
.with_class(query.get("class"))?
.with_reference_name(query.get("referenceName"))
.with_range(query.get("start"), query.get("end"))?
.with_fields(query.get("fields"))
.with_tags(query.get("tags"), query.get("notags"))?;

cfg_if! {
if #[cfg(feature = "experimental")] {
Ok(builder.with_encryption_scheme(query.get("encryptionScheme"))?.build())
} else {
Ok(builder.build())
}
}
}

fn merge_responses(responses: Vec<Response>) -> Option<Response> {
Expand Down
25 changes: 23 additions & 2 deletions htsget-http/src/query_builder.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std::collections::HashSet;

use tracing::instrument;

#[cfg(feature = "experimental")]
use htsget_config::encryption_scheme::EncryptionScheme;
use htsget_config::types::{Class, Fields, Format, Query, Request, Tags};
use tracing::instrument;

use crate::error::{HtsGetError, Result};

Expand Down Expand Up @@ -163,6 +164,26 @@ impl QueryBuilder {

Ok(self)
}

/// Set the encryption scheme.
#[cfg(feature = "experimental")]
pub fn with_encryption_scheme(
mut self,
encryption_scheme: Option<impl Into<String>>,
) -> Result<Self> {
if let Some(scheme) = encryption_scheme {
let scheme = match scheme.into().as_str() {
"c4gh" => Ok(EncryptionScheme::C4GH),
scheme => Err(HtsGetError::UnsupportedFormat(format!(
"invalid encryption scheme `{scheme}`"
))),
}?;

self.query = self.query.with_encryption_scheme(scheme);
}

Ok(self)
}
}

#[cfg(test)]
Expand Down
6 changes: 3 additions & 3 deletions htsget-search/src/from_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,21 +51,21 @@ impl HtsGet for HtsGetFromStorage {
#[async_trait]
impl ResolveResponse for HtsGetFromStorage {
async fn from_file(file_storage: &storage::file::File, query: &Query) -> Result<Response> {
let storage = Storage::from_file(file_storage).await?;
let storage = Storage::from_file(file_storage, query).await?;
let searcher = HtsGetFromStorage::new(storage);
searcher.search(query.clone()).await
}

#[cfg(feature = "aws")]
async fn from_s3(s3_storage: &storage::s3::S3, query: &Query) -> Result<Response> {
let storage = Storage::from_s3(s3_storage).await;
let storage = Storage::from_s3(s3_storage, query).await;
let searcher = HtsGetFromStorage::new(storage?);
searcher.search(query.clone()).await
}

#[cfg(feature = "url")]
async fn from_url(url_storage_config: &storage::url::Url, query: &Query) -> Result<Response> {
let storage = Storage::from_url(url_storage_config).await;
let storage = Storage::from_url(url_storage_config, query).await;
let searcher = HtsGetFromStorage::new(storage?);
searcher.search(query.clone()).await
}
Expand Down
10 changes: 7 additions & 3 deletions htsget-storage/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ pub type Result<T> = core::result::Result<T, StorageError>;
/// Storage error type.
#[derive(Error, Debug)]
pub enum StorageError {
#[error("wrong key derived from ID: `{0}`")]
#[error("wrong key derived from ID: {0}")]
InvalidKey(String),

#[error("key not found in storage: `{0}`")]
#[error("key not found in storage: {0}")]
KeyNotFound(String),

#[error("{0}: {1}")]
Expand All @@ -34,14 +34,17 @@ pub enum StorageError {
#[error("invalid address: {0}")]
InvalidAddress(AddrParseError),

#[error("unsupported format: {0}")]
UnsupportedFormat(String),

#[error("internal error: {0}")]
InternalError(String),

#[error("response error: {0}")]
ResponseError(String),

#[cfg(feature = "aws")]
#[error("aws error: {0}, with key: `{1}`")]
#[error("aws error: {0}, with key: {1}")]
AwsS3Error(String, String),

#[error("parsing url: {0}")]
Expand All @@ -56,6 +59,7 @@ impl From<StorageError> for HtsGetError {
| StorageError::InvalidKey(_)
| StorageError::ResponseError(_)) => Self::NotFound(err.to_string()),
err @ StorageError::IoError(_, _) => Self::IoError(err.to_string()),
err @ StorageError::UnsupportedFormat(_) => Self::UnsupportedFormat(err.to_string()),
err @ (StorageError::ServerError(_)
| StorageError::InvalidUri(_)
| StorageError::InvalidAddress(_)
Expand Down
Loading

0 comments on commit fc84e7e

Please sign in to comment.