Skip to content

Commit e62d4b2

Browse files
committed
feat(config): add configuration values for C4GH S3 and Url storage
1 parent a34e332 commit e62d4b2

File tree

12 files changed

+110
-23
lines changed

12 files changed

+110
-23
lines changed

htsget-actix/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ are exposed in the public API.
5050
This crate has the following features:
5151
* `s3-storage`: used to enable `S3Storage` functionality.
5252
* `url-storage`: used to enable `UrlStorage` functionality.
53-
* `experimental`: used to enable `C4GHStorage` functionality.
53+
* `experimental`: used to enable experimental features like `C4GHStorage`.
5454

5555
## Benchmarks
5656
Benchmarks for this crate written using [Criterion.rs][criterion-rs], and aim to compare the performance of this crate with the

htsget-axum/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ htsget-rs. It also contains the data block server which fetches data from a `Loc
171171
This crate has the following features:
172172
* `s3-storage`: used to enable `S3Storage` functionality.
173173
* `url-storage`: used to enable `UrlStorage` functionality.
174-
* `experimental`: used to enable `C4GHStorage` functionality.
174+
* `experimental`: used to enable experimental features like `C4GHStorage`.
175175

176176
## License
177177

htsget-config/README.md

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ For example, a `resolvers` value of:
193193
[[resolvers]]
194194
regex = '^(example_bucket)/(?P<key>.*)$'
195195
substitution_string = '$key'
196+
196197
[resolvers.storage]
197198
type = 'S3'
198199
# Uses the first capture group in the regex as the bucket.
@@ -275,6 +276,7 @@ regex = '.*'
275276
substitution_string = '$0'
276277

277278
[resolvers.storage]
279+
type = 'S3'
278280
bucket = 'bucket'
279281

280282
[resolvers.allow_guard]
@@ -452,6 +454,7 @@ export HTSGET_RESOLVERS="[{
452454
regex=regex,
453455
substitution_string=substitution_string,
454456
storage={
457+
type=S3,
455458
bucket=bucket
456459
},
457460
allow_guard={
@@ -483,6 +486,7 @@ regex = '.*'
483486
substitution_string = '$0'
484487

485488
[resolvers.storage]
489+
type = 'S3'
486490
bucket = 'bucket'
487491
endpoint = 'http://127.0.0.1:9000'
488492
path_style = true
@@ -504,8 +508,7 @@ serving the data, htsget-rs will decrypt the headers of the Crypt4GH files and r
504508
them. When the client receives byte ranges from htsget-rs and concatenates them, the output bytes will be Crypt4GH encrypted,
505509
and will need to be decrypted before they can be read. All file formats (BAM, CRAM, VCF, and BCF) are supported using Crypt4GH.
506510

507-
To use this feature, an additional config option called `object_type` under `resolvers.storage` is required,
508-
which allows specifying the private and public keys:
511+
To use this feature, additional config under `resolvers.storage` is required to specify the private and public keys:
509512

510513
| Option | Description | Type | Default |
511514
|------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------|---------|
@@ -516,17 +519,17 @@ For example:
516519

517520
```toml
518521
[[resolvers]]
519-
regex = ".*"
520-
substitution_string = "$0"
522+
regex = '.*'
523+
substitution_string = '$0'
521524

522525
[resolvers.storage]
523-
object_type = { private_key = "data/c4gh/keys/bob.sec", recipient_public_key = "data/c4gh/keys/alice.pub" } # pragma: allowlist secret
526+
type = 'Local'
527+
private_key = 'data/c4gh/keys/bob.sec' # pragma: allowlist secret
528+
recipient_public_key = 'data/c4gh/keys/alice.pub'
524529
```
525530

526531
The htsget-rs server expects the Crypt4GH file to end with `.c4gh`, and the index file to be unencrypted. See the [`data/c4gh`][data-c4gh] for examples of file structure.
527-
528-
> [!NOTE]
529-
> This option is currently only supported for `LocalStorage`. The `object_type` will not have an effect if using `S3Storage` or `UrlStorage`.
532+
Any of the storage types are supported, i.e. `Local`, `S3`, or `Url`.
530533

531534
### As a library
532535

@@ -541,7 +544,7 @@ regex, and changing it by using a substitution string.
541544
This crate has the following features:
542545
* `s3-storage`: used to enable `S3Storage` functionality.
543546
* `url-storage`: used to enable `UrlStorage` functionality.
544-
* `experimental`: used to enable `C4GHStorage` functionality.
547+
* `experimental`: used to enable experimental features like `C4GHStorage`.
545548

546549
## License
547550

htsget-config/src/resolver.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ mod tests {
499499
#[cfg(feature = "s3-storage")]
500500
#[tokio::test]
501501
async fn resolver_resolve_s3_request_tagged() {
502-
let s3_storage = S3Storage::new("id".to_string(), None, false);
502+
let s3_storage = S3Storage::new("id".to_string(), None, false, Default::default());
503503
let resolver = Resolver::new(
504504
Storage::S3(s3_storage),
505505
"(id)-1",
@@ -538,6 +538,7 @@ mod tests {
538538
}),
539539
true,
540540
vec![],
541+
Default::default(),
541542
client,
542543
);
543544

@@ -692,7 +693,8 @@ mod tests {
692693
Interval::new(Some(100), Some(1000)),
693694
);
694695
let resolver = config.resolvers().first().unwrap();
695-
let expected_storage = S3Storage::new("bucket".to_string(), None, false);
696+
let expected_storage =
697+
S3Storage::new("bucket".to_string(), None, false, Default::default());
696698

697699
assert_eq!(resolver.regex().to_string(), "regex");
698700
assert_eq!(resolver.substitution_string(), "substitution_string");

htsget-config/src/storage/object/c4gh.rs

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,16 @@ impl From<Crypt4GHError> for Error {
6464
#[cfg(test)]
6565
mod tests {
6666
use crate::config::tests::test_config_from_file;
67+
use crate::config::Config;
6768
use crate::storage::Storage;
6869
use std::fs::copy;
6970
use std::path::PathBuf;
7071
use tempfile::TempDir;
7172

72-
#[test]
73-
fn config_storage_c4gh() {
73+
fn test_c4gh_storage_config<F>(storage_config: &str, test_fn: F)
74+
where
75+
F: Fn(Config),
76+
{
7477
let tmp = TempDir::new().unwrap();
7578
let private_key = tmp.path().join("bob.sec");
7679
let recipient_public_key = tmp.path().join("alice.pub");
@@ -94,18 +97,62 @@ mod tests {
9497
regex = "regex"
9598
9699
[resolvers.storage]
97-
type = "Local"
100+
{}
98101
private_key = "{}"
99102
recipient_public_key = "{}"
100103
"#,
104+
storage_config,
101105
private_key.to_string_lossy(),
102106
recipient_public_key.to_string_lossy()
103107
),
104108
|config| {
105109
println!("{:?}", config.resolvers().first().unwrap().storage());
106-
assert!(matches!(
110+
test_fn(config);
111+
},
112+
);
113+
}
114+
115+
#[test]
116+
fn config_local_storage_c4gh() {
117+
test_c4gh_storage_config(r#"type = "Local""#, |config| {
118+
assert!(matches!(
107119
config.resolvers().first().unwrap().storage(),
108120
Storage::Local(local_storage) if local_storage.object_type().keys().is_some()
121+
));
122+
});
123+
}
124+
125+
#[cfg(feature = "s3-storage")]
126+
#[test]
127+
fn config_s3_storage_c4gh() {
128+
test_c4gh_storage_config(
129+
r#"
130+
type = "S3"
131+
bucket = "bucket"
132+
"#,
133+
|config| {
134+
assert!(matches!(
135+
config.resolvers().first().unwrap().storage(),
136+
Storage::S3(s3_storage) if s3_storage.object_type().keys().is_some()
137+
));
138+
},
139+
);
140+
}
141+
142+
#[cfg(feature = "url-storage")]
143+
#[test]
144+
fn config_url_storage_c4gh() {
145+
test_c4gh_storage_config(
146+
r#"
147+
type = "Url"
148+
url = "https://example.com/"
149+
response_url = "https://example.com/"
150+
forward_headers = false
151+
"#,
152+
|config| {
153+
assert!(matches!(
154+
config.resolvers().first().unwrap().storage(),
155+
Storage::Url(url_storage) if url_storage.object_type().keys().is_some()
109156
));
110157
},
111158
);

htsget-config/src/storage/s3.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::storage::object::ObjectType;
12
use serde::{Deserialize, Serialize};
23

34
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq)]
@@ -6,15 +7,23 @@ pub struct S3Storage {
67
pub(crate) bucket: String,
78
pub(crate) endpoint: Option<String>,
89
pub(crate) path_style: bool,
10+
#[serde(flatten)]
11+
pub(crate) object_type: ObjectType,
912
}
1013

1114
impl S3Storage {
1215
/// Create a new S3 storage.
13-
pub fn new(bucket: String, endpoint: Option<String>, path_style: bool) -> Self {
16+
pub fn new(
17+
bucket: String,
18+
endpoint: Option<String>,
19+
path_style: bool,
20+
object_type: ObjectType,
21+
) -> Self {
1422
Self {
1523
bucket,
1624
endpoint,
1725
path_style,
26+
object_type,
1827
}
1928
}
2029

@@ -32,6 +41,11 @@ impl S3Storage {
3241
pub fn path_style(self) -> bool {
3342
self.path_style
3443
}
44+
45+
/// Get the object type.
46+
pub fn object_type(&self) -> &ObjectType {
47+
&self.object_type
48+
}
3549
}
3650

3751
#[cfg(test)]

htsget-config/src/storage/url.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use serde_with::with_prefix;
88
use crate::error::Error::ParseError;
99
use crate::error::{Error, Result};
1010
use crate::storage::local::default_authority;
11+
use crate::storage::object::ObjectType;
1112
use crate::tls::client::TlsClientConfig;
1213

1314
fn default_url() -> ValidatedUrl {
@@ -28,6 +29,8 @@ pub struct UrlStorage {
2829
header_blacklist: Vec<String>,
2930
#[serde(skip_serializing)]
3031
tls: TlsClientConfig,
32+
#[serde(flatten)]
33+
object_type: ObjectType,
3134
}
3235

3336
#[derive(Deserialize, Debug, Clone)]
@@ -37,6 +40,7 @@ pub struct UrlStorageClient {
3740
response_url: ValidatedUrl,
3841
forward_headers: bool,
3942
header_blacklist: Vec<String>,
43+
object_type: ObjectType,
4044
client: Client,
4145
}
4246

@@ -66,6 +70,7 @@ impl TryFrom<UrlStorage> for UrlStorageClient {
6670
storage.response_url,
6771
storage.forward_headers,
6872
storage.header_blacklist,
73+
storage.object_type,
6974
client,
7075
))
7176
}
@@ -78,13 +83,15 @@ impl UrlStorageClient {
7883
response_url: ValidatedUrl,
7984
forward_headers: bool,
8085
header_blacklist: Vec<String>,
86+
object_type: ObjectType,
8187
client: Client,
8288
) -> Self {
8389
Self {
8490
url,
8591
response_url,
8692
forward_headers,
8793
header_blacklist,
94+
object_type,
8895
client,
8996
}
9097
}
@@ -113,6 +120,11 @@ impl UrlStorageClient {
113120
pub fn client_cloned(&self) -> Client {
114121
self.client.clone()
115122
}
123+
124+
/// Get the object type.
125+
pub fn object_type(&self) -> &ObjectType {
126+
&self.object_type
127+
}
116128
}
117129

118130
/// A wrapper around `http::Uri` type which implements serialize and deserialize.
@@ -154,6 +166,7 @@ impl UrlStorage {
154166
forward_headers: bool,
155167
header_blacklist: Vec<String>,
156168
tls: TlsClientConfig,
169+
object_type: ObjectType,
157170
) -> Self {
158171
Self {
159172
url: ValidatedUrl(Url { inner: url }),
@@ -163,6 +176,7 @@ impl UrlStorage {
163176
forward_headers,
164177
header_blacklist,
165178
tls,
179+
object_type,
166180
}
167181
}
168182

@@ -186,6 +200,11 @@ impl UrlStorage {
186200
pub fn tls(&self) -> &TlsClientConfig {
187201
&self.tls
188202
}
203+
204+
/// Get the object type.
205+
pub fn object_type(&self) -> &ObjectType {
206+
&self.object_type
207+
}
189208
}
190209

191210
impl Default for UrlStorage {
@@ -196,6 +215,7 @@ impl Default for UrlStorage {
196215
forward_headers: true,
197216
header_blacklist: vec![],
198217
tls: TlsClientConfig::default(),
218+
object_type: Default::default(),
199219
}
200220
}
201221
}
@@ -221,6 +241,7 @@ mod tests {
221241
true,
222242
vec![],
223243
client_config,
244+
Default::default(),
224245
));
225246

226247
assert!(url_storage.is_ok());

htsget-http/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ These functions take query and endpoint information, and process it using [htsge
3838
This crate has the following features:
3939
* `s3-storage`: used to enable `S3Storage` functionality.
4040
* `url-storage`: used to enable `UrlStorage` functionality.
41-
* `experimental`: used to enable `C4GHStorage` functionality.
41+
* `experimental`: used to enable experimental features like `C4GHStorage`.
4242

4343
[warp]: https://github.com/seanmonstar/warp
4444
[htsget-search]: ../htsget-search

htsget-lambda/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ library code, and it instead uses `htsget-axum`. Please use that crate for funct
4646
This crate has the following features:
4747
* `s3-storage`: used to enable `S3Storage` functionality.
4848
* `url-storage`: used to enable `UrlStorage` functionality.
49-
* `experimental`: used to enable `C4GHStorage` functionality.
49+
* `experimental`: used to enable experimental features like `C4GHStorage`.
5050

5151
## License
5252

htsget-search/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ used to process requests.
5959
This crate has the following features:
6060
* `s3-storage`: used to enable `S3Storage` functionality.
6161
* `url-storage`: used to enable `UrlStorage` functionality.
62-
* `experimental`: used to enable `C4GHStorage` functionality.
62+
* `experimental`: used to enable experimental features like `C4GHStorage`.
6363

6464
## Minimising Byte Ranges
6565

0 commit comments

Comments
 (0)