Use naturalWidth and naturalHeight instead

This commit is contained in:
Edward Shen 2021-10-25 17:31:30 -07:00
parent f5e9b3abd2
commit 6a17a84d3b
Signed by: edward
GPG key ID: 19182661E818369F
10 changed files with 67 additions and 81 deletions

7
Cargo.lock generated
View file

@ -648,12 +648,6 @@ dependencies = [
"unicode-normalization", "unicode-normalization",
] ]
[[package]]
name = "imagesize"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b3b62f4e783e38afa07b51eaaa789be2fba03dbe29a05a1a906eb64feb987d"
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.7.0" version = "1.7.0"
@ -920,7 +914,6 @@ dependencies = [
"getrandom", "getrandom",
"gloo-console", "gloo-console",
"http", "http",
"imagesize",
"js-sys", "js-sys",
"omegaupload-common", "omegaupload-common",
"reqwasm", "reqwasm",

View file

@ -113,8 +113,10 @@ fn handle_download(url: ParsedUrl) -> Result<()> {
.get(EXPIRES) .get(EXPIRES)
.and_then(|v| Expiration::try_from(v).ok()) .and_then(|v| Expiration::try_from(v).ok())
.as_ref() .as_ref()
.map(ToString::to_string) .map_or_else(
.unwrap_or_else(|| "This paste will not expire.".to_string()); || "This paste will not expire.".to_string(),
ToString::to_string,
);
let mut data = res.bytes()?.as_ref().to_vec(); let mut data = res.bytes()?.as_ref().to_vec();

View file

@ -303,7 +303,7 @@ impl TryFrom<web_sys::Headers> for Expiration {
.ok() .ok()
.flatten() .flatten()
.as_deref() .as_deref()
.and_then(|v| Expiration::try_from(v).ok()) .and_then(|v| Self::try_from(v).ok())
.ok_or(ParseHeaderValueError) .ok_or(ParseHeaderValueError)
} }
} }

View file

@ -48,7 +48,7 @@ async fn main() -> Result<()> {
], ],
)?); )?);
set_up_expirations(Arc::clone(&db)); set_up_expirations(&db);
axum::Server::bind(&"0.0.0.0:8081".parse()?) axum::Server::bind(&"0.0.0.0:8081".parse()?)
.serve( .serve(
@ -68,7 +68,7 @@ async fn main() -> Result<()> {
Ok(()) Ok(())
} }
fn set_up_expirations(db: Arc<DB>) { fn set_up_expirations(db: &Arc<DB>) {
let mut corrupted = 0; let mut corrupted = 0;
let mut expired = 0; let mut expired = 0;
let mut pending = 0; let mut pending = 0;
@ -77,7 +77,7 @@ fn set_up_expirations(db: Arc<DB>) {
let meta_cf = db.cf_handle(META_CF_NAME).unwrap(); let meta_cf = db.cf_handle(META_CF_NAME).unwrap();
let db_ref = Arc::clone(&db); let db_ref = Arc::clone(db);
let delete_entry = move |key: &[u8]| { let delete_entry = move |key: &[u8]| {
let blob_cf = db_ref.cf_handle(BLOB_CF_NAME).unwrap(); let blob_cf = db_ref.cf_handle(BLOB_CF_NAME).unwrap();
@ -91,7 +91,7 @@ fn set_up_expirations(db: Arc<DB>) {
}; };
for (key, value) in db.iterator_cf(meta_cf, IteratorMode::Start) { for (key, value) in db.iterator_cf(meta_cf, IteratorMode::Start) {
let expires = if let Ok(value) = bincode::deserialize::<Expiration>(&value) { let expiration = if let Ok(value) = bincode::deserialize::<Expiration>(&value) {
value value
} else { } else {
corrupted += 1; corrupted += 1;
@ -99,7 +99,7 @@ fn set_up_expirations(db: Arc<DB>) {
continue; continue;
}; };
let expiration_time = match expires { let expiration_time = match expiration {
Expiration::BurnAfterReading => { Expiration::BurnAfterReading => {
panic!("Got burn after reading expiration time? Invariant violated"); panic!("Got burn after reading expiration time? Invariant violated");
} }
@ -107,16 +107,16 @@ fn set_up_expirations(db: Arc<DB>) {
}; };
let sleep_duration = (expiration_time - Utc::now()).to_std().unwrap_or_default(); let sleep_duration = (expiration_time - Utc::now()).to_std().unwrap_or_default();
if sleep_duration != Duration::default() { if sleep_duration == Duration::default() {
expired += 1;
delete_entry(&key);
} else {
pending += 1; pending += 1;
let delete_entry_ref = delete_entry.clone(); let delete_entry_ref = delete_entry.clone();
task::spawn_blocking(move || async move { task::spawn_blocking(move || async move {
tokio::time::sleep(sleep_duration).await; tokio::time::sleep(sleep_duration).await;
delete_entry_ref(&key); delete_entry_ref(&key);
}); });
} else {
expired += 1;
delete_entry(&key);
} }
} }
@ -125,6 +125,7 @@ fn set_up_expirations(db: Arc<DB>) {
} else { } else {
warn!("Found {} corrupted pastes.", corrupted); warn!("Found {} corrupted pastes.", corrupted);
} }
info!("Found {} expired pastes.", expired); info!("Found {} expired pastes.", expired);
info!("Found {} active pastes.", pending); info!("Found {} active pastes.", pending);
info!("Cleanup timers have been initialized."); info!("Cleanup timers have been initialized.");

View file

@ -17,7 +17,6 @@ console_error_panic_hook = "0.1"
gloo-console = "0.1" gloo-console = "0.1"
http = "0.2" http = "0.2"
js-sys = "0.3" js-sys = "0.3"
imagesize = "0.9"
reqwasm = "0.2" reqwasm = "0.2"
tree_magic_mini = { version = "3", features = ["with-gpl-data"] } tree_magic_mini = { version = "3", features = ["with-gpl-data"] }
wasm-bindgen = "0.2" wasm-bindgen = "0.2"

View file

@ -11,7 +11,7 @@ use web_sys::Blob;
pub enum DecryptedData { pub enum DecryptedData {
String(Arc<String>), String(Arc<String>),
Blob(Arc<Blob>), Blob(Arc<Blob>),
Image(Arc<Blob>, (usize, usize), usize), Image(Arc<Blob>, usize),
Audio(Arc<Blob>), Audio(Arc<Blob>),
Video(Arc<Blob>), Video(Arc<Blob>),
} }
@ -69,33 +69,19 @@ pub fn decrypt(
Arc::new(Blob::new_with_u8_array_sequence(blob_chunks.dyn_ref().unwrap()).unwrap()); Arc::new(Blob::new_with_u8_array_sequence(blob_chunks.dyn_ref().unwrap()).unwrap());
log!(format!("Blob conversion completed in {}ms", now() - start)); log!(format!("Blob conversion completed in {}ms", now() - start));
log!("Image introspection started");
let start = now();
let dimensions = imagesize::blob_size(&container).ok();
log!(format!(
"Image introspection completed in {}ms",
now() - start
));
if let Some(dimensions) = dimensions {
Ok(DecryptedData::Image(
blob,
(dimensions.width, dimensions.height),
container.len(),
))
} else {
let mime_type = tree_magic_mini::from_u8(container); let mime_type = tree_magic_mini::from_u8(container);
log!(mime_type);
if mime_type.starts_with("audio/") { if mime_type.starts_with("image/") || mime_type == "application/x-riff" {
Ok(DecryptedData::Image(blob, container.len()))
} else if mime_type.starts_with("audio/") {
Ok(DecryptedData::Audio(blob)) Ok(DecryptedData::Audio(blob))
} else if mime_type.starts_with("video/") || mime_type.ends_with("x-matroska") { } else if mime_type.starts_with("video/") || mime_type == "application/x-matroska" {
Ok(DecryptedData::Video(blob)) Ok(DecryptedData::Video(blob))
} else { } else {
Ok(DecryptedData::Blob(blob)) Ok(DecryptedData::Blob(blob))
} }
} }
} }
}
#[derive(Debug)] #[derive(Debug)]
pub enum PasteCompleteConstructionError { pub enum PasteCompleteConstructionError {

View file

@ -17,7 +17,7 @@ impl<State: IdbObjectState> IdbObject<State> {
impl From<IdbObject<Ready>> for Object { impl From<IdbObject<Ready>> for Object {
fn from(db_object: IdbObject<Ready>) -> Self { fn from(db_object: IdbObject<Ready>) -> Self {
match Object::from_entries(db_object.as_ref()) { match Self::from_entries(db_object.as_ref()) {
Ok(o) => o, Ok(o) => o,
// SAFETY: IdbObject maintains the invariant that it can eventually // SAFETY: IdbObject maintains the invariant that it can eventually
// be constructed into a JS object. // be constructed into a JS object.
@ -52,6 +52,12 @@ impl IdbObject<NeedsType> {
} }
} }
impl Default for IdbObject<NeedsType> {
fn default() -> Self {
Self::new()
}
}
impl IdbObject<NeedsExpiration> { impl IdbObject<NeedsExpiration> {
pub fn expiration_text(self, expires: &str) -> IdbObject<NeedsData> { pub fn expiration_text(self, expires: &str) -> IdbObject<NeedsData> {
self.add_tuple("expiration", &JsString::from(expires)) self.add_tuple("expiration", &JsString::from(expires))

View file

@ -74,21 +74,19 @@ fn main() {
.split_once('#') .split_once('#')
.map(|(_, fragment)| PartialParsedUrl::from(fragment)) .map(|(_, fragment)| PartialParsedUrl::from(fragment))
.unwrap_or_default(); .unwrap_or_default();
let key = match partial_parsed_url.decryption_key { let key = if let Some(key) = partial_parsed_url.decryption_key {
Some(key) => key, key
None => { } else {
error!("Key is missing in url; bailing."); error!("Key is missing in url; bailing.");
render_message("Invalid paste link: Missing decryption key.".into()); render_message("Invalid paste link: Missing decryption key.".into());
return; return;
}
}; };
let nonce = match partial_parsed_url.nonce { let nonce = if let Some(nonce) = partial_parsed_url.nonce {
Some(nonce) => nonce, nonce
None => { } else {
error!("Nonce is missing in url; bailing."); error!("Nonce is missing in url; bailing.");
render_message("Invalid paste link: Missing nonce.".into()); render_message("Invalid paste link: Missing nonce.".into());
return; return;
}
}; };
(key, nonce, partial_parsed_url.needs_password) (key, nonce, partial_parsed_url.needs_password)
}; };
@ -175,20 +173,15 @@ async fn fetch_resources(
DecryptedData::Blob(blob) => { DecryptedData::Blob(blob) => {
IdbObject::new().blob().expiration_text(&expires).data(blob) IdbObject::new().blob().expiration_text(&expires).data(blob)
} }
DecryptedData::Image(blob, (width, height), size) => IdbObject::new() DecryptedData::Image(blob, size) => IdbObject::new()
.image() .image()
.expiration_text(&expires) .expiration_text(&expires)
.data(blob) .data(blob)
.extra("width", *width)
.extra("height", *height)
.extra( .extra(
"button", "file_size",
&format!( Byte::from_bytes(*size as u128)
"Download {} \u{2014} {} by {}", .get_appropriate_unit(true)
Byte::from_bytes(*size as u128).get_appropriate_unit(true), .to_string(),
width,
height,
),
), ),
DecryptedData::Audio(blob) => IdbObject::new() DecryptedData::Audio(blob) => IdbObject::new()
.audio() .audio()
@ -233,7 +226,7 @@ async fn fetch_resources(
)); ));
let on_upgrade = Closure::wrap(Box::new(move |event: Event| { let on_upgrade = Closure::wrap(Box::new(move |event: Event| {
let db = as_idb_db(&event); let db = as_idb_db(&event);
let _ = db.create_object_store("decrypted data").unwrap(); let _obj_store = db.create_object_store("decrypted data").unwrap();
}) as Box<dyn FnMut(Event)>); }) as Box<dyn FnMut(Event)>);
db_open_req.set_onupgradeneeded(Some(on_upgrade.into_js_value().unchecked_ref())); db_open_req.set_onupgradeneeded(Some(on_upgrade.into_js_value().unchecked_ref()));
} }
@ -244,7 +237,7 @@ async fn fetch_resources(
render_message("Invalid paste URL.".into()); render_message("Invalid paste URL.".into());
} }
Ok(err) => { Ok(err) => {
render_message(format!("{}", err.status_text()).into()); render_message(err.status_text().into());
} }
Err(err) => { Err(err) => {
render_message(format!("{}", err).into()); render_message(format!("{}", err).into());

View file

@ -117,8 +117,12 @@ function createBlobPasteUi(data) {
bodyEle.appendChild(mainEle); bodyEle.appendChild(mainEle);
} }
function createImagePasteUi({ expiration, data, button }) { function createImagePasteUi({ expiration, data, file_size }) {
createMultiMediaPasteUi("img", expiration, data, button); createMultiMediaPasteUi("img", expiration, data, (downloadEle, imgEle) => {
imgEle.onload = () => {
downloadEle.textContent = "Download " + file_size + " \u2014 " + imgEle.naturalWidth + " by " + imgEle.naturalHeight;
}
});
} }
function createAudioPasteUi({ expiration, data }) { function createAudioPasteUi({ expiration, data }) {
@ -129,7 +133,7 @@ function createVideoPasteUi({ expiration, data }) {
createMultiMediaPasteUi("video", expiration, data, "Download"); createMultiMediaPasteUi("video", expiration, data, "Download");
} }
function createMultiMediaPasteUi(tag, expiration, data, downloadMessage) { function createMultiMediaPasteUi(tag, expiration, data, on_create?) {
let bodyEle = document.getElementsByTagName("body")[0]; let bodyEle = document.getElementsByTagName("body")[0];
bodyEle.textContent = ''; bodyEle.textContent = '';
@ -144,19 +148,24 @@ function createMultiMediaPasteUi(tag, expiration, data, downloadMessage) {
expirationEle.textContent = expiration; expirationEle.textContent = expiration;
mainEle.appendChild(expirationEle); mainEle.appendChild(expirationEle);
let videoEle = document.createElement(tag); let mediaEle = document.createElement(tag);
videoEle.src = downloadLink; mediaEle.src = downloadLink;
videoEle.controls = true; mediaEle.controls = true;
mainEle.appendChild(videoEle); mainEle.appendChild(mediaEle);
let downloadEle = document.createElement("a"); let downloadEle = document.createElement("a");
downloadEle.href = downloadLink; downloadEle.href = downloadLink;
downloadEle.download = window.location.pathname; downloadEle.download = window.location.pathname;
downloadEle.classList.add("hljs-meta"); downloadEle.classList.add("hljs-meta");
downloadEle.textContent = downloadMessage;
mainEle.appendChild(downloadEle); mainEle.appendChild(downloadEle);
bodyEle.appendChild(mainEle); bodyEle.appendChild(mainEle);
if (on_create instanceof Function) {
on_create(downloadEle, mediaEle);
} else {
downloadEle.textContent = on_create;
}
} }
function renderMessage(message) { function renderMessage(message) {

View file

@ -1,6 +1,3 @@
use js_sys::Function;
use wasm_bindgen::closure::WasmClosure;
use wasm_bindgen::prelude::Closure;
use wasm_bindgen::JsCast; use wasm_bindgen::JsCast;
use web_sys::{Event, IdbDatabase, IdbOpenDbRequest}; use web_sys::{Event, IdbDatabase, IdbOpenDbRequest};