Added Cloudflare R2 media storage support
Build and Publish / Build and Publish Docker Image (push) Successful in 1m44s

This commit is contained in:
Aleksandr Bogomiakov
2026-08-09 01:05:47 +01:00
parent 9ee5048a43
commit 15c9528f47
14 changed files with 885 additions and 116 deletions
+37 -28
View File
@@ -273,26 +273,28 @@ async fn portal_media_view(
client_token: &str,
) -> cot::Result<PortalMediaView> {
let media_id = media.id.unwrap();
let delivery = crate::uploads::media_delivery_paths(&media.file_type, &media.file_path);
let url = storage
.public_url(
&media.file_path,
&delivery.media_path,
format!("/client/{client_token}/media/{media_id}"),
)
.await
.map_err(crate::uploads::storage_error)?;
let thumbnail_path =
if media.file_type == "photo" && crate::uploads::supports_thumbnail(&media.file_path) {
crate::uploads::thumbnail_db_path(&media.file_path)
} else {
media.file_path.clone()
};
let thumbnail_url = storage
.public_url(
&thumbnail_path,
format!("/client/{client_token}/media/{media_id}/thumbnail"),
)
.await
.map_err(crate::uploads::storage_error)?;
let thumbnail_fallback = format!("/client/{client_token}/media/{media_id}/thumbnail");
let thumbnail_url = if storage.is_r2()
&& storage
.exists(&delivery.thumbnail_path)
.await
.map_err(crate::uploads::storage_error)?
{
storage
.public_url(&delivery.thumbnail_path, thumbnail_fallback)
.await
.map_err(crate::uploads::storage_error)?
} else {
thumbnail_fallback
};
Ok(PortalMediaView {
media,
url,
@@ -858,17 +860,19 @@ async fn portal_media(
.map(str::to_owned);
let storage = crate::uploads::Storage::load(&db).await?;
let display_path =
crate::uploads::media_delivery_paths(&media.file_type, &media.file_path).media_path;
if storage.is_r2() {
let url = storage
.public_url(&media.file_path, String::new())
.public_url(&display_path, String::new())
.await
.map_err(crate::uploads::storage_error)?;
return Redirect::new(url).into_response();
}
match crate::uploads::ranged_local_file_response(
&media.file_path,
crate::uploads::content_type_for_path(&media.file_path),
&display_path,
crate::uploads::content_type_for_path(&display_path),
range.as_deref(),
)
.await
@@ -878,8 +882,8 @@ async fn portal_media(
tracing::warn!(
target: "uploads",
media_id,
db_path = %media.file_path,
resolved_path = %crate::uploads::resolved_display_path(&media.file_path),
db_path = %display_path,
resolved_path = %crate::uploads::resolved_display_path(&display_path),
error = %err,
"portal media file is missing or unreadable"
);
@@ -900,8 +904,7 @@ async fn portal_media_thumbnail(
let media = match query!(Media, $id == media_id).get(&db).await? {
Some(media)
if media.client_id.primary_key().unwrap() == client.id.unwrap()
&& media.status == "active"
&& media.file_type == "photo" =>
&& media.status == "active" =>
{
media
}
@@ -915,16 +918,22 @@ async fn portal_media_thumbnail(
}
}
let storage = crate::uploads::Storage::load(&db).await?;
let display_path = if crate::uploads::supports_thumbnail(&media.file_path) {
match crate::uploads::ensure_thumbnail(&storage, &media.file_path).await {
Ok(path) => path,
Err(error) => {
tracing::warn!(media_id, %error, "failed to create portal media thumbnail");
let display_path = match crate::uploads::ensure_media_delivery_paths(
&storage,
&media.file_type,
&media.file_path,
)
.await
{
Ok(paths) => paths.thumbnail_path,
Err(error) => {
tracing::warn!(media_id, %error, "failed to create portal media thumbnail");
if media.file_type == "photo" {
media.file_path.clone()
} else {
return Html::new("404").into_response();
}
}
} else {
media.file_path.clone()
};
if storage.is_r2() {
let url = storage