feat: serve legacy void.cat uploads

This commit is contained in:
kieran 2024-12-16 13:34:30 +00:00
parent 961a6910ac
commit b0571efcb3
No known key found for this signature in database
GPG Key ID: DE71CEB3925BE941
7 changed files with 66 additions and 58 deletions

View File

@ -28,4 +28,7 @@ vit_model:
# plausible_url: "https://plausible.com/" # plausible_url: "https://plausible.com/"
# Support legacy void # Support legacy void
# void_cat_database: "postgres://postgres:postgres@localhost:41911/void" # void_cat_database: "postgres://postgres:postgres@localhost:41911/void"
# Legacy file path for void.cat uploads
# void_cat_files: "/my/void.cat/data"

View File

@ -6,7 +6,8 @@ use nostr::bitcoin::base58;
use route96::db::{Database, FileUpload}; use route96::db::{Database, FileUpload};
use route96::filesystem::FileStore; use route96::filesystem::FileStore;
use route96::settings::Settings; use route96::settings::Settings;
use route96::void_db::{VoidCatDb, VoidFile}; use route96::void_db::VoidCatDb;
use route96::void_file::VoidFile;
use std::path::PathBuf; use std::path::PathBuf;
use tokio::io::{AsyncWriteExt, BufWriter}; use tokio::io::{AsyncWriteExt, BufWriter};
@ -54,7 +55,7 @@ async fn main() -> Result<(), Error> {
let mut page = 0; let mut page = 0;
loop { loop {
let files = db_void.list_files(page).await?; let files = db_void.list_files(page).await?;
if files.len() == 0 { if files.is_empty() {
break; break;
} }
for f in files { for f in files {
@ -73,7 +74,7 @@ async fn main() -> Result<(), Error> {
let mut page = 0; let mut page = 0;
loop { loop {
let files = db_void.list_files(page).await?; let files = db_void.list_files(page).await?;
if files.len() == 0 { if files.is_empty() {
break; break;
} }
for f in files { for f in files {
@ -99,7 +100,9 @@ async fn migrate_file(
let id_vec = hex::decode(&f.digest)?; let id_vec = hex::decode(&f.digest)?;
// copy file // copy file
let src_path = PathBuf::new().join(&args.data_path).join(f.map_to_path()); let src_path = PathBuf::new()
.join(&args.data_path)
.join(VoidFile::map_to_path(&f.id));
let dst_path = fs.map_path(&id_vec); let dst_path = fs.map_path(&id_vec);
if src_path.exists() && !dst_path.exists() { if src_path.exists() && !dst_path.exists() {
info!( info!(

View File

@ -10,4 +10,5 @@ pub mod routes;
pub mod settings; pub mod settings;
#[cfg(any(feature = "void-cat-redirects", feature = "bin-void-cat-migrate"))] #[cfg(any(feature = "void-cat-redirects", feature = "bin-void-cat-migrate"))]
pub mod void_db; pub mod void_db;
pub mod void_file;
pub mod webhook; pub mod webhook;

View File

@ -6,16 +6,13 @@ pub use crate::routes::blossom::blossom_routes;
#[cfg(feature = "nip96")] #[cfg(feature = "nip96")]
pub use crate::routes::nip96::nip96_routes; pub use crate::routes::nip96::nip96_routes;
use crate::settings::Settings; use crate::settings::Settings;
#[cfg(feature = "void-cat-redirects")] use crate::void_file::VoidFile;
use crate::void_db::VoidCatDb;
use anyhow::Error; use anyhow::Error;
use http_range_header::{parse_range_header, EndPosition, StartPosition}; use http_range_header::{parse_range_header, EndPosition, StartPosition};
use log::warn; use log::warn;
use nostr::Event; use nostr::Event;
use rocket::fs::NamedFile; use rocket::fs::NamedFile;
use rocket::http::{ContentType, Header, Status}; use rocket::http::{ContentType, Header, Status};
#[cfg(feature = "void-cat-redirects")]
use rocket::response::Redirect;
use rocket::response::Responder; use rocket::response::Responder;
use rocket::serde::Serialize; use rocket::serde::Serialize;
use rocket::{Request, Response, State}; use rocket::{Request, Response, State};
@ -355,25 +352,24 @@ pub async fn head_blob(sha256: &str, fs: &State<FileStore>) -> Status {
} }
} }
#[cfg(feature = "void-cat-redirects")] /// Legacy URL redirect for void.cat uploads
#[rocket::get("/d/<id>")] #[rocket::get("/d/<id>")]
pub async fn void_cat_redirect( pub async fn void_cat_redirect(id: &str, settings: &State<Settings>) -> Option<NamedFile> {
id: &str,
settings: &State<Settings>,
vdb: &State<VoidCatDb>,
) -> Option<Redirect> {
let id = if id.contains(".") { let id = if id.contains(".") {
id.split('.').next().unwrap() id.split('.').next().unwrap()
} else { } else {
id id
}; };
let uuid = if let Some(base) = &settings.void_cat_files {
uuid::Uuid::from_slice_le(nostr::bitcoin::base58::decode(id).unwrap().as_slice()).unwrap(); let uuid =
if let Ok(Some(d)) = vdb.get_digest(&uuid).await { uuid::Uuid::from_slice_le(nostr::bitcoin::base58::decode(id).unwrap().as_slice())
Some(Redirect::permanent(format!( .unwrap();
"{}/{}", let f = base.join(VoidFile::map_to_path(&uuid));
&settings.public_url, &d if let Ok(f) = NamedFile::open(f).await {
))) Some(f)
} else {
None
}
} else { } else {
None None
} }

View File

@ -32,6 +32,9 @@ pub struct Settings {
#[cfg(feature = "void-cat-redirects")] #[cfg(feature = "void-cat-redirects")]
pub void_cat_database: Option<String>, pub void_cat_database: Option<String>,
/// Path to void.cat uploads (files-v2)
pub void_cat_files: Option<PathBuf>,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]

View File

@ -1,42 +1,7 @@
use chrono::{DateTime, Utc}; use crate::void_file::VoidFile;
use sqlx::FromRow;
use sqlx_postgres::{PgPool, PgPoolOptions}; use sqlx_postgres::{PgPool, PgPoolOptions};
use std::path::PathBuf;
use uuid::Uuid; use uuid::Uuid;
#[derive(FromRow)]
pub struct VoidFile {
#[sqlx(rename = "Id")]
pub id: Uuid,
#[sqlx(rename = "Name")]
pub name: Option<String>,
#[sqlx(rename = "Size")]
pub size: i64,
#[sqlx(rename = "Uploaded")]
pub uploaded: DateTime<Utc>,
#[sqlx(rename = "Description")]
pub description: Option<String>,
#[sqlx(rename = "MimeType")]
pub mime_type: String,
#[sqlx(rename = "Digest")]
pub digest: String,
#[sqlx(rename = "MediaDimensions")]
pub media_dimensions: Option<String>,
#[sqlx(rename = "Email")]
pub email: String,
}
impl VoidFile {
pub fn map_to_path(&self) -> PathBuf {
let id_str = self.id.as_hyphenated().to_string();
PathBuf::new()
.join("files-v2/")
.join(&id_str[..2])
.join(&id_str[2..4])
.join(&id_str)
}
}
pub struct VoidCatDb { pub struct VoidCatDb {
pub pool: PgPool, pub pool: PgPool,
} }

37
src/void_file.rs Normal file
View File

@ -0,0 +1,37 @@
use chrono::{DateTime, Utc};
use sqlx::FromRow;
use std::path::PathBuf;
use uuid::Uuid;
#[derive(FromRow)]
pub struct VoidFile {
#[sqlx(rename = "Id")]
pub id: Uuid,
#[sqlx(rename = "Name")]
pub name: Option<String>,
#[sqlx(rename = "Size")]
pub size: i64,
#[sqlx(rename = "Uploaded")]
pub uploaded: DateTime<Utc>,
#[sqlx(rename = "Description")]
pub description: Option<String>,
#[sqlx(rename = "MimeType")]
pub mime_type: String,
#[sqlx(rename = "Digest")]
pub digest: String,
#[sqlx(rename = "MediaDimensions")]
pub media_dimensions: Option<String>,
#[sqlx(rename = "Email")]
pub email: String,
}
impl VoidFile {
pub fn map_to_path(id: &Uuid) -> PathBuf {
let id_str = id.as_hyphenated().to_string();
PathBuf::new()
.join("files-v2/")
.join(&id_str[..2])
.join(&id_str[2..4])
.join(&id_str)
}
}