use ::url::Url;
use bevy::prelude::{Event, Message};
use ehttp::multipart::MultipartBuilder;
use nostr::NostrSigner;
use nostr::nips::nip96;
use nostr_sdk::prelude::*;
use std::io::Cursor;
use std::sync::Arc;
#[derive(Debug, Clone)]
pub enum FileUploadError {
ServerError,
ServerConfigError,
UploadError,
}
#[derive(Event)]
pub struct FileUploadReqEvent {
pub file_data: Vec<u8>,
pub id: String,
}
#[derive(Message)]
pub struct FileUploadSuccess {
pub url: Url,
pub id: String,
}
pub async fn upload_file(
data: Vec<u8>,
srv_url: Option<Url>,
signer: Arc<dyn NostrSigner>,
) -> Result<Url, FileUploadError> {
let server_url =
srv_url.unwrap_or(Url::parse("https://nostr.build").unwrap());
let config_url = nip96::get_server_config_url(&server_url)
.map_err(|_| FileUploadError::ServerConfigError)?;
let Ok(resp) = ehttp::fetch_async(ehttp::Request::get(config_url)).await
else {
return Err(FileUploadError::ServerConfigError);
};
let Ok(config) = resp.json::<nip96::ServerConfig>() else {
return Err(FileUploadError::ServerConfigError);
};
let upload_req = nip96::UploadRequest::new(&signer, &config, &data)
.await
.map_err(|_| FileUploadError::ServerError)?;
let mut request = ehttp::Request::multipart(
upload_req.url,
MultipartBuilder::new()
.add_stream(&mut Cursor::new(data), "file", Some("file"), None)
.unwrap(),
);
request
.headers
.insert("Authorization", upload_req.authorization);
let Ok(resp) = ehttp::fetch_async(request).await else {
return Err(FileUploadError::UploadError);
};
let Ok(upload_resp) = resp.json::<nip96::UploadResponse>() else {
return Err(FileUploadError::UploadError);
};
match upload_resp.status {
nip96::UploadResponseStatus::Success => {
let url = upload_resp
.download_url()
.map_err(|_| FileUploadError::UploadError)?;
Ok(url.clone())
}
nip96::UploadResponseStatus::Error => Err(FileUploadError::UploadError),
}
}