Use naturalWidth and naturalHeight instead
This commit is contained in:
parent
f5e9b3abd2
commit
6a17a84d3b
10 changed files with 67 additions and 81 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -648,12 +648,6 @@ dependencies = [
|
|||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "imagesize"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b3b62f4e783e38afa07b51eaaa789be2fba03dbe29a05a1a906eb64feb987d"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.7.0"
|
||||
|
@ -920,7 +914,6 @@ dependencies = [
|
|||
"getrandom",
|
||||
"gloo-console",
|
||||
"http",
|
||||
"imagesize",
|
||||
"js-sys",
|
||||
"omegaupload-common",
|
||||
"reqwasm",
|
||||
|
|
|
@ -113,8 +113,10 @@ fn handle_download(url: ParsedUrl) -> Result<()> {
|
|||
.get(EXPIRES)
|
||||
.and_then(|v| Expiration::try_from(v).ok())
|
||||
.as_ref()
|
||||
.map(ToString::to_string)
|
||||
.unwrap_or_else(|| "This paste will not expire.".to_string());
|
||||
.map_or_else(
|
||||
|| "This paste will not expire.".to_string(),
|
||||
ToString::to_string,
|
||||
);
|
||||
|
||||
let mut data = res.bytes()?.as_ref().to_vec();
|
||||
|
||||
|
|
|
@ -303,7 +303,7 @@ impl TryFrom<web_sys::Headers> for Expiration {
|
|||
.ok()
|
||||
.flatten()
|
||||
.as_deref()
|
||||
.and_then(|v| Expiration::try_from(v).ok())
|
||||
.and_then(|v| Self::try_from(v).ok())
|
||||
.ok_or(ParseHeaderValueError)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()?)
|
||||
.serve(
|
||||
|
@ -68,7 +68,7 @@ async fn main() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn set_up_expirations(db: Arc<DB>) {
|
||||
fn set_up_expirations(db: &Arc<DB>) {
|
||||
let mut corrupted = 0;
|
||||
let mut expired = 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 db_ref = Arc::clone(&db);
|
||||
let db_ref = Arc::clone(db);
|
||||
|
||||
let delete_entry = move |key: &[u8]| {
|
||||
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) {
|
||||
let expires = if let Ok(value) = bincode::deserialize::<Expiration>(&value) {
|
||||
let expiration = if let Ok(value) = bincode::deserialize::<Expiration>(&value) {
|
||||
value
|
||||
} else {
|
||||
corrupted += 1;
|
||||
|
@ -99,7 +99,7 @@ fn set_up_expirations(db: Arc<DB>) {
|
|||
continue;
|
||||
};
|
||||
|
||||
let expiration_time = match expires {
|
||||
let expiration_time = match expiration {
|
||||
Expiration::BurnAfterReading => {
|
||||
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();
|
||||
if sleep_duration != Duration::default() {
|
||||
if sleep_duration == Duration::default() {
|
||||
expired += 1;
|
||||
delete_entry(&key);
|
||||
} else {
|
||||
pending += 1;
|
||||
let delete_entry_ref = delete_entry.clone();
|
||||
task::spawn_blocking(move || async move {
|
||||
tokio::time::sleep(sleep_duration).await;
|
||||
delete_entry_ref(&key);
|
||||
});
|
||||
} else {
|
||||
expired += 1;
|
||||
delete_entry(&key);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,6 +125,7 @@ fn set_up_expirations(db: Arc<DB>) {
|
|||
} else {
|
||||
warn!("Found {} corrupted pastes.", corrupted);
|
||||
}
|
||||
|
||||
info!("Found {} expired pastes.", expired);
|
||||
info!("Found {} active pastes.", pending);
|
||||
info!("Cleanup timers have been initialized.");
|
||||
|
|
|
@ -17,7 +17,6 @@ console_error_panic_hook = "0.1"
|
|||
gloo-console = "0.1"
|
||||
http = "0.2"
|
||||
js-sys = "0.3"
|
||||
imagesize = "0.9"
|
||||
reqwasm = "0.2"
|
||||
tree_magic_mini = { version = "3", features = ["with-gpl-data"] }
|
||||
wasm-bindgen = "0.2"
|
||||
|
|
|
@ -11,7 +11,7 @@ use web_sys::Blob;
|
|||
pub enum DecryptedData {
|
||||
String(Arc<String>),
|
||||
Blob(Arc<Blob>),
|
||||
Image(Arc<Blob>, (usize, usize), usize),
|
||||
Image(Arc<Blob>, usize),
|
||||
Audio(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());
|
||||
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);
|
||||
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))
|
||||
} 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))
|
||||
} else {
|
||||
Ok(DecryptedData::Blob(blob))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PasteCompleteConstructionError {
|
||||
|
|
|
@ -17,7 +17,7 @@ impl<State: IdbObjectState> IdbObject<State> {
|
|||
|
||||
impl From<IdbObject<Ready>> for Object {
|
||||
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,
|
||||
// SAFETY: IdbObject maintains the invariant that it can eventually
|
||||
// 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> {
|
||||
pub fn expiration_text(self, expires: &str) -> IdbObject<NeedsData> {
|
||||
self.add_tuple("expiration", &JsString::from(expires))
|
||||
|
|
|
@ -74,21 +74,19 @@ fn main() {
|
|||
.split_once('#')
|
||||
.map(|(_, fragment)| PartialParsedUrl::from(fragment))
|
||||
.unwrap_or_default();
|
||||
let key = match partial_parsed_url.decryption_key {
|
||||
Some(key) => key,
|
||||
None => {
|
||||
let key = if let Some(key) = partial_parsed_url.decryption_key {
|
||||
key
|
||||
} else {
|
||||
error!("Key is missing in url; bailing.");
|
||||
render_message("Invalid paste link: Missing decryption key.".into());
|
||||
return;
|
||||
}
|
||||
};
|
||||
let nonce = match partial_parsed_url.nonce {
|
||||
Some(nonce) => nonce,
|
||||
None => {
|
||||
let nonce = if let Some(nonce) = partial_parsed_url.nonce {
|
||||
nonce
|
||||
} else {
|
||||
error!("Nonce is missing in url; bailing.");
|
||||
render_message("Invalid paste link: Missing nonce.".into());
|
||||
return;
|
||||
}
|
||||
};
|
||||
(key, nonce, partial_parsed_url.needs_password)
|
||||
};
|
||||
|
@ -175,20 +173,15 @@ async fn fetch_resources(
|
|||
DecryptedData::Blob(blob) => {
|
||||
IdbObject::new().blob().expiration_text(&expires).data(blob)
|
||||
}
|
||||
DecryptedData::Image(blob, (width, height), size) => IdbObject::new()
|
||||
DecryptedData::Image(blob, size) => IdbObject::new()
|
||||
.image()
|
||||
.expiration_text(&expires)
|
||||
.data(blob)
|
||||
.extra("width", *width)
|
||||
.extra("height", *height)
|
||||
.extra(
|
||||
"button",
|
||||
&format!(
|
||||
"Download {} \u{2014} {} by {}",
|
||||
Byte::from_bytes(*size as u128).get_appropriate_unit(true),
|
||||
width,
|
||||
height,
|
||||
),
|
||||
"file_size",
|
||||
Byte::from_bytes(*size as u128)
|
||||
.get_appropriate_unit(true)
|
||||
.to_string(),
|
||||
),
|
||||
DecryptedData::Audio(blob) => IdbObject::new()
|
||||
.audio()
|
||||
|
@ -233,7 +226,7 @@ async fn fetch_resources(
|
|||
));
|
||||
let on_upgrade = Closure::wrap(Box::new(move |event: 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)>);
|
||||
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());
|
||||
}
|
||||
Ok(err) => {
|
||||
render_message(format!("{}", err.status_text()).into());
|
||||
render_message(err.status_text().into());
|
||||
}
|
||||
Err(err) => {
|
||||
render_message(format!("{}", err).into());
|
||||
|
|
|
@ -117,8 +117,12 @@ function createBlobPasteUi(data) {
|
|||
bodyEle.appendChild(mainEle);
|
||||
}
|
||||
|
||||
function createImagePasteUi({ expiration, data, button }) {
|
||||
createMultiMediaPasteUi("img", expiration, data, button);
|
||||
function createImagePasteUi({ expiration, data, file_size }) {
|
||||
createMultiMediaPasteUi("img", expiration, data, (downloadEle, imgEle) => {
|
||||
imgEle.onload = () => {
|
||||
downloadEle.textContent = "Download " + file_size + " \u2014 " + imgEle.naturalWidth + " by " + imgEle.naturalHeight;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createAudioPasteUi({ expiration, data }) {
|
||||
|
@ -129,7 +133,7 @@ function createVideoPasteUi({ expiration, data }) {
|
|||
createMultiMediaPasteUi("video", expiration, data, "Download");
|
||||
}
|
||||
|
||||
function createMultiMediaPasteUi(tag, expiration, data, downloadMessage) {
|
||||
function createMultiMediaPasteUi(tag, expiration, data, on_create?) {
|
||||
let bodyEle = document.getElementsByTagName("body")[0];
|
||||
bodyEle.textContent = '';
|
||||
|
||||
|
@ -144,19 +148,24 @@ function createMultiMediaPasteUi(tag, expiration, data, downloadMessage) {
|
|||
expirationEle.textContent = expiration;
|
||||
mainEle.appendChild(expirationEle);
|
||||
|
||||
let videoEle = document.createElement(tag);
|
||||
videoEle.src = downloadLink;
|
||||
videoEle.controls = true;
|
||||
mainEle.appendChild(videoEle);
|
||||
let mediaEle = document.createElement(tag);
|
||||
mediaEle.src = downloadLink;
|
||||
mediaEle.controls = true;
|
||||
mainEle.appendChild(mediaEle);
|
||||
|
||||
let downloadEle = document.createElement("a");
|
||||
downloadEle.href = downloadLink;
|
||||
downloadEle.download = window.location.pathname;
|
||||
downloadEle.classList.add("hljs-meta");
|
||||
downloadEle.textContent = downloadMessage;
|
||||
mainEle.appendChild(downloadEle);
|
||||
|
||||
bodyEle.appendChild(mainEle);
|
||||
|
||||
if (on_create instanceof Function) {
|
||||
on_create(downloadEle, mediaEle);
|
||||
} else {
|
||||
downloadEle.textContent = on_create;
|
||||
}
|
||||
}
|
||||
|
||||
function renderMessage(message) {
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
use js_sys::Function;
|
||||
use wasm_bindgen::closure::WasmClosure;
|
||||
use wasm_bindgen::prelude::Closure;
|
||||
use wasm_bindgen::JsCast;
|
||||
use web_sys::{Event, IdbDatabase, IdbOpenDbRequest};
|
||||
|
||||
|
|
Loading…
Reference in a new issue