mirror of
https://gitlab.com/famedly/conduit.git
synced 2025-09-15 18:57:03 +00:00
feat(service/media): add S3 support
This commit is contained in:
parent
30d578a81a
commit
6541402609
5 changed files with 143 additions and 3 deletions
|
@ -242,6 +242,32 @@ impl From<IncompleteConfig> for Config {
|
|||
}),
|
||||
directory_structure,
|
||||
},
|
||||
IncompleteMediaBackendConfig::S3 {
|
||||
endpoint,
|
||||
bucket,
|
||||
region,
|
||||
key,
|
||||
secret,
|
||||
duration,
|
||||
bucket_use_path,
|
||||
} => {
|
||||
let path_style = if bucket_use_path {
|
||||
rusty_s3::UrlStyle::Path
|
||||
} else {
|
||||
rusty_s3::UrlStyle::VirtualHost
|
||||
};
|
||||
|
||||
let bucket = rusty_s3::Bucket::new(endpoint, path_style, bucket, region)
|
||||
.expect("Invalid S3 config");
|
||||
|
||||
let credentials = rusty_s3::Credentials::new(key, secret);
|
||||
|
||||
MediaBackendConfig::S3 {
|
||||
bucket: bucket,
|
||||
credentials: credentials,
|
||||
duration: Duration::from_secs(duration),
|
||||
}
|
||||
}
|
||||
},
|
||||
retention: media.retention.into(),
|
||||
};
|
||||
|
@ -481,6 +507,17 @@ pub enum IncompleteMediaBackendConfig {
|
|||
#[serde(default)]
|
||||
directory_structure: DirectoryStructure,
|
||||
},
|
||||
S3 {
|
||||
endpoint: Url,
|
||||
bucket: String,
|
||||
region: String,
|
||||
key: String,
|
||||
secret: String,
|
||||
#[serde(default = "default_s3_duration")]
|
||||
duration: u64,
|
||||
#[serde(default = "false_fn")]
|
||||
bucket_use_path: bool,
|
||||
},
|
||||
}
|
||||
|
||||
impl Default for IncompleteMediaBackendConfig {
|
||||
|
@ -498,6 +535,11 @@ pub enum MediaBackendConfig {
|
|||
path: String,
|
||||
directory_structure: DirectoryStructure,
|
||||
},
|
||||
S3 {
|
||||
bucket: rusty_s3::Bucket,
|
||||
credentials: rusty_s3::Credentials,
|
||||
duration: Duration,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
|
@ -727,3 +769,7 @@ fn default_openid_token_ttl() -> u64 {
|
|||
pub fn default_default_room_version() -> RoomVersionId {
|
||||
RoomVersionId::V10
|
||||
}
|
||||
|
||||
fn default_s3_duration() -> u64 {
|
||||
30
|
||||
}
|
||||
|
|
|
@ -230,8 +230,6 @@ impl Service {
|
|||
shutdown: AtomicBool::new(false),
|
||||
};
|
||||
|
||||
// Remove this exception once other media backends are added
|
||||
#[allow(irrefutable_let_patterns)]
|
||||
if let MediaBackendConfig::FileSystem { path, .. } = &s.config.media.backend {
|
||||
fs::create_dir_all(path)?;
|
||||
}
|
||||
|
|
|
@ -8,8 +8,9 @@ use ruma::{
|
|||
http_headers::{ContentDisposition, ContentDispositionType},
|
||||
OwnedServerName, ServerName, UserId,
|
||||
};
|
||||
use rusty_s3::S3Action;
|
||||
use sha2::{digest::Output, Digest, Sha256};
|
||||
use tracing::{error, info};
|
||||
use tracing::{error, info, warn};
|
||||
|
||||
use crate::{
|
||||
config::{DirectoryStructure, MediaBackendConfig},
|
||||
|
@ -615,6 +616,25 @@ impl Service {
|
|||
|
||||
file
|
||||
}
|
||||
MediaBackendConfig::S3 {
|
||||
bucket,
|
||||
credentials,
|
||||
duration,
|
||||
} => {
|
||||
let url = bucket
|
||||
.get_object(Some(credentials), &hex::encode(sha256_digest))
|
||||
.sign(*duration);
|
||||
|
||||
let client = services().globals.default_client();
|
||||
let resp = client.get(url).send().await?;
|
||||
|
||||
if !resp.status().is_success() {
|
||||
warn!("S3 request error:\n{}", resp.text().await?);
|
||||
return Err(Error::bad_database("Cannot read media file"));
|
||||
}
|
||||
|
||||
resp.bytes().await?.to_vec()
|
||||
}
|
||||
};
|
||||
|
||||
if let Some((server_name, media_id)) = original_file_id {
|
||||
|
@ -643,6 +663,23 @@ pub async fn create_file(sha256_hex: &str, file: &[u8]) -> Result<()> {
|
|||
let mut f = File::create(path).await?;
|
||||
f.write_all(file).await?;
|
||||
}
|
||||
MediaBackendConfig::S3 {
|
||||
bucket,
|
||||
credentials,
|
||||
duration,
|
||||
} => {
|
||||
let url = bucket
|
||||
.put_object(Some(credentials), sha256_hex)
|
||||
.sign(*duration);
|
||||
|
||||
let client = services().globals.default_client();
|
||||
let resp = client.put(url).body(file.to_vec()).send().await?;
|
||||
|
||||
if !resp.status().is_success() {
|
||||
warn!("S3 request error:\n{}", resp.text().await?);
|
||||
return Err(Error::bad_database("Cannot write media file"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -713,6 +750,23 @@ async fn delete_file(sha256_hex: &str) -> Result<()> {
|
|||
}
|
||||
}
|
||||
}
|
||||
MediaBackendConfig::S3 {
|
||||
bucket,
|
||||
credentials,
|
||||
duration,
|
||||
} => {
|
||||
let url = bucket
|
||||
.delete_object(Some(credentials), sha256_hex)
|
||||
.sign(*duration);
|
||||
|
||||
let client = services().globals.default_client();
|
||||
let resp = client.delete(url).send().await?;
|
||||
|
||||
if !resp.status().is_success() {
|
||||
warn!("S3 request error:\n{}", resp.text().await?);
|
||||
return Err(Error::bad_database("Cannot delete media file"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue