From 903134c7c7b525c0c7b0766067f7a9ce41ed373f Mon Sep 17 00:00:00 2001 From: "Aode (Lion)" Date: Mon, 2 May 2022 20:38:46 -0500 Subject: [PATCH] Use pict-rs's background uploading feature --- Cargo.lock | 372 +++++++++++++++++++++-------- Cargo.toml | 3 +- src/main.rs | 201 +++++++++++++++- static/uploads.js | 11 + templates/confirm_delete.rs.html | 38 +-- templates/deleted.rs.html | 12 +- templates/error.rs.html | 18 +- templates/finished_uploads.rs.html | 63 +++++ templates/images.rs.html | 114 ++++----- templates/index.rs.html | 62 +++-- templates/layout.rs.html | 49 ++-- templates/not_found.rs.html | 20 +- templates/return_home.rs.html | 2 +- templates/thumbnails.rs.html | 70 +++--- templates/uploads.rs.html | 14 ++ templates/view.rs.html | 79 +++--- 16 files changed, 776 insertions(+), 352 deletions(-) create mode 100644 static/uploads.js create mode 100644 templates/finished_uploads.rs.html create mode 100644 templates/uploads.rs.html diff --git a/Cargo.lock b/Cargo.lock index 4768150..804ad1c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -218,9 +218,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" +checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" [[package]] name = "async-stream" @@ -304,6 +304,49 @@ dependencies = [ "tokio", ] +[[package]] +name = "axum" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4af7447fc1214c1f3a1ace861d0216a6c8bb13965b64bbad9650f375b67689a" +dependencies = [ + "async-trait", + "axum-core", + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "hyper", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde", + "sync_wrapper", + "tokio", + "tower", + "tower-http", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da31c0ed7b4690e2c78fe4b880d21cd7db04a346ebc658b4270251b695437f17" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "mime", +] + [[package]] name = "base64" version = "0.13.0" @@ -381,22 +424,21 @@ dependencies = [ [[package]] name = "console-api" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc347c19eb5b940f396ac155822caee6662f850d97306890ac3773ed76c90c5a" +checksum = "24cb05777feccbb2642d4f2df44d0505601a2cd88ca517d8c913f263a5a8dc8b" dependencies = [ - "prost", - "prost-types", - "tonic", - "tonic-build", + "prost 0.10.1", + "prost-types 0.10.1", + "tonic 0.7.1", "tracing-core", ] [[package]] name = "console-subscriber" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "565a7dfea2d10dd0e5c57cc394d5d441b1910960d8c9211ed14135e0e6ec3a20" +checksum = "8f21a16ee925aa9d2bad2e296beffd6c5b1bfaad50af509d305b8e7f23af20fb" dependencies = [ "console-api", "crossbeam-channel", @@ -404,13 +446,13 @@ dependencies = [ "futures", "hdrhistogram", "humantime", - "prost-types", + "prost-types 0.10.1", "serde", "serde_json", "thread_local", "tokio", "tokio-stream", - "tonic", + "tonic 0.7.1", "tracing", "tracing-core", "tracing-subscriber", @@ -537,9 +579,9 @@ checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e" [[package]] name = "flate2" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" +checksum = "b39522e96686d38f4bc984b9198e3a0613264abaebaff2c5c918bfa6b6da09af" dependencies = [ "cfg-if", "crc32fast", @@ -571,6 +613,7 @@ checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" dependencies = [ "futures-channel", "futures-core", + "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -610,6 +653,17 @@ version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" +[[package]] +name = "futures-macro" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "futures-sink" version = "0.3.21" @@ -631,6 +685,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-io", + "futures-macro", "futures-sink", "futures-task", "memchr", @@ -718,9 +773,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03" +checksum = "ff8670570af52249509a86f5e3e18a08c60b177071826898fde8997cf5f6bfbb" dependencies = [ "bytes", "fnv", @@ -739,10 +794,16 @@ dependencies = [ ] [[package]] -name = "httparse" -version = "1.6.0" +name = "http-range-header" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9100414882e15fb7feccb4897e5f0ff0ff1ca7d1a86a23208ada4d7a18e6c6c4" +checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" + +[[package]] +name = "httparse" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" [[package]] name = "httpdate" @@ -839,9 +900,9 @@ checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" [[package]] name = "js-sys" -version = "0.3.56" +version = "0.3.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" +checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" dependencies = [ "wasm-bindgen", ] @@ -860,9 +921,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.122" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec647867e2bf0772e28c8bcde4f0d19a9216916e890543b5a03ed8ef27b8f259" +checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" [[package]] name = "local-channel" @@ -894,9 +955,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.16" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if", ] @@ -916,6 +977,12 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" +[[package]] +name = "matchit" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" + [[package]] name = "md5" version = "0.7.0" @@ -924,9 +991,9 @@ checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" [[package]] name = "memchr" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "mime" @@ -953,12 +1020,11 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.4.4" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082" dependencies = [ "adler", - "autocfg", ] [[package]] @@ -1033,9 +1099,9 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ "autocfg", "num-traits", @@ -1118,10 +1184,10 @@ dependencies = [ "futures-util", "http", "opentelemetry", - "prost", + "prost 0.9.0", "thiserror", "tokio", - "tonic", + "tonic 0.6.2", "tonic-build", ] @@ -1137,9 +1203,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "995f667a6c822200b0433ac218e05582f0e2efa1b922a3fd2fbaadc5f87bab37" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" dependencies = [ "cfg-if", "libc", @@ -1172,7 +1238,7 @@ dependencies = [ [[package]] name = "pict-rs-proxy" -version = "0.3.1" +version = "0.4.0-alpha.1" dependencies = [ "actix-rt", "actix-web", @@ -1187,6 +1253,7 @@ dependencies = [ "opentelemetry-otlp", "ructe", "serde", + "serde_qs", "structopt", "thiserror", "tracing", @@ -1222,9 +1289,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" [[package]] name = "pin-utils" @@ -1278,7 +1345,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.9.0", +] + +[[package]] +name = "prost" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a07b0857a71a8cb765763950499cae2413c3f9cede1133478c43600d9e146890" +dependencies = [ + "bytes", + "prost-derive 0.10.1", ] [[package]] @@ -1294,8 +1371,8 @@ dependencies = [ "log", "multimap", "petgraph", - "prost", - "prost-types", + "prost 0.9.0", + "prost-types 0.9.0", "regex", "tempfile", "which", @@ -1314,6 +1391,19 @@ dependencies = [ "syn", ] +[[package]] +name = "prost-derive" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b670f45da57fb8542ebdbb6105a925fe571b67f9e7ed9f47a06a84e72b4e7cc" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "prost-types" version = "0.9.0" @@ -1321,14 +1411,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a" dependencies = [ "bytes", - "prost", + "prost 0.9.0", +] + +[[package]] +name = "prost-types" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d0a014229361011dc8e69c8a1ec6c2e8d0f2af7c91e3ea3f5b2170298461e68" +dependencies = [ + "bytes", + "prost 0.10.1", ] [[package]] name = "quote" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ "proc-macro2", ] @@ -1461,24 +1561,24 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "semver" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4" +checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" [[package]] name = "serde" -version = "1.0.136" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.136" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" dependencies = [ "proc-macro2", "quote", @@ -1487,15 +1587,28 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +checksum = "f972498cf015f7c0746cac89ebe1d6ef10c293b94175a243a2d9442c163d9944" dependencies = [ "itoa", "ryu", "serde", ] +[[package]] +name = "serde_qs" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af4cee6cd4b23b45e6709150d1e9af5c748131de7e3316a7c2b3008051ed725" +dependencies = [ + "actix-web", + "futures", + "percent-encoding", + "serde", + "thiserror", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -1591,15 +1704,21 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.91" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" +checksum = "7ff7c592601f11445996a06f8ad0c27f094a58857c2f89e97974ab9235b92c52" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] +[[package]] +name = "sync_wrapper" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" + [[package]] name = "tempfile" version = "3.3.0" @@ -1625,18 +1744,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ "proc-macro2", "quote", @@ -1665,9 +1784,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] @@ -1680,9 +1799,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.17.0" +version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" +checksum = "dce653fb475565de9f6fb0614b28bca8df2c430c0cf84bcd9c843f15de5414cc" dependencies = [ "bytes", "libc", @@ -1778,8 +1897,8 @@ dependencies = [ "hyper-timeout", "percent-encoding", "pin-project", - "prost", - "prost-derive", + "prost 0.9.0", + "prost-derive 0.9.0", "tokio", "tokio-stream", "tokio-util 0.6.9", @@ -1790,6 +1909,38 @@ dependencies = [ "tracing-futures", ] +[[package]] +name = "tonic" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30fb54bf1e446f44d870d260d99957e7d11fb9d0a0f5bd1a662ad1411cc103f9" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64", + "bytes", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost 0.10.1", + "prost-derive 0.10.1", + "tokio", + "tokio-stream", + "tokio-util 0.7.1", + "tower", + "tower-layer", + "tower-service", + "tracing", + "tracing-futures", +] + [[package]] name = "tonic-build" version = "0.6.2" @@ -1822,6 +1973,25 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower-http" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e980386f06883cf4d0578d6c9178c81f68b45d77d00f2c2c1bc034b3439c2c56" +dependencies = [ + "bitflags", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" version = "0.3.1" @@ -1836,9 +2006,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.32" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f" +checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" dependencies = [ "cfg-if", "log", @@ -1864,9 +2034,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e65ce065b4b5c53e73bb28912318cb8c9e9ad3921f1d669eb0e68b4c8143a2b" +checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" dependencies = [ "proc-macro2", "quote", @@ -1892,9 +2062,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90442985ee2f57c9e1b548ee72ae842f4a9a20e3f417cc38dbc5dc684d9bb4ee" +checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" dependencies = [ "lazy_static", "valuable", @@ -1922,9 +2092,9 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" dependencies = [ "lazy_static", "log", @@ -1946,9 +2116,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9df98b037d039d03400d9dd06b0f8ce05486b5f25e9a2d7d36196e142ebbc52" +checksum = "4bc28f93baff38037f64e6f43d34cfa1605f27a49c34e8a04c5e78b0babf2596" dependencies = [ "ansi_term", "lazy_static", @@ -1976,9 +2146,9 @@ checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "unicode-bidi" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-normalization" @@ -2003,9 +2173,9 @@ checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" [[package]] name = "url" @@ -2070,9 +2240,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" +checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2080,9 +2250,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" +checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" dependencies = [ "bumpalo", "lazy_static", @@ -2095,9 +2265,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" +checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2105,9 +2275,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" +checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" dependencies = [ "proc-macro2", "quote", @@ -2118,9 +2288,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" +checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" [[package]] name = "which" @@ -2157,9 +2327,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5acdd78cb4ba54c0045ac14f62d8f94a03d10047904ae2a40afa1e99d8f70825" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" dependencies = [ "windows_aarch64_msvc", "windows_i686_gnu", @@ -2170,30 +2340,30 @@ dependencies = [ [[package]] name = "windows_aarch64_msvc" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" [[package]] name = "windows_i686_gnu" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" [[package]] name = "windows_i686_msvc" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" [[package]] name = "windows_x86_64_gnu" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" [[package]] name = "windows_x86_64_msvc" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" diff --git a/Cargo.toml b/Cargo.toml index 56e2ed1..0e43646 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "pict-rs-proxy" description = "A simple web frontend for pict-rs" -version = "0.3.1" +version = "0.4.0-alpha.1" authors = ["asonix "] license = "AGPL-3.0" readme = "README.md" @@ -28,6 +28,7 @@ once_cell = "1.4" opentelemetry = { version = "0.17", features = ["rt-tokio"] } opentelemetry-otlp = "0.10" serde = { version = "1.0", features = ["derive"] } +serde_qs = { version = "0.9", features = ["actix4"] } structopt = "0.3.14" thiserror = "1.0" tracing = "0.1" diff --git a/src/main.rs b/src/main.rs index 225a2cf..082157f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -38,6 +38,7 @@ include!(concat!(env!("OUT_DIR"), "/templates.rs")); const HOURS: u32 = 60 * 60; const DAYS: u32 = 24 * HOURS; +// TODO: change structopt use to clap #[derive(Clone, Debug, StructOpt)] struct Config { #[structopt( @@ -86,7 +87,15 @@ struct Config { impl Config { fn upstream_upload_url(&self) -> String { let mut url = self.upstream.clone(); - url.set_path("image"); + url.set_path("image/backgrounded"); + + url.to_string() + } + + fn upstream_claim_url(&self, upload_id: &str) -> String { + let mut url = self.upstream.clone(); + url.set_path("image/backgrounded/claim"); + url.set_query(Some(&format!("upload_id={}", upload_id))); url.to_string() } @@ -172,6 +181,12 @@ impl Config { static CONFIG: Lazy = Lazy::new(Config::from_args); +pub enum UploadResult<'a> { + Image(Image), + UploadId(&'a str), + Error(Error), +} + #[derive(Debug, serde::Deserialize)] enum FileType { #[serde(rename = "jpg")] @@ -195,6 +210,40 @@ pub struct Images { files: Option>, } +#[derive(Debug, serde::Deserialize)] +pub struct Upload { + // This is technically a UUID, but we don't care in this program + upload_id: String, +} + +#[derive(Debug, serde::Deserialize)] +pub struct Uploads { + msg: String, + uploads: Option>, +} + +#[derive(Debug, Default, PartialEq, Eq, serde::Deserialize, serde::Serialize)] +pub struct UploadQuery { + #[serde(default)] + uploads: Vec, + + #[serde(default)] + files: Vec<(String, String)>, +} + +impl UploadQuery { + fn try_from_uploads(uploads: Uploads) -> Result { + if let Some(uploads) = uploads.uploads { + Ok(UploadQuery { + uploads: uploads.into_iter().map(|u| u.upload_id).collect(), + files: vec![], + }) + } else { + Err(uploads.msg) + } + } +} + impl Images { fn files(&self) -> Option<&[Image]> { self.files.as_ref().map(|v| v.as_ref()) @@ -272,7 +321,7 @@ fn statics(file: &str) -> String { } #[derive(Debug)] -struct Error { +pub struct Error { context: SpanTrace, kind: ErrorKind, } @@ -319,8 +368,12 @@ impl ResponseError for Error { } } +// TODO: make this error type better (do not forward display impl) #[derive(Debug, thiserror::Error)] enum ErrorKind { + #[error("{0}")] + UploadFailed(String), + #[error("{0}")] Io(#[from] std::io::Error), @@ -329,15 +382,139 @@ enum ErrorKind { #[error("{0}")] JsonPayload(#[from] awc::error::JsonPayloadError), + + #[error("{0}")] + Query(#[from] serde_qs::Error), + + #[error("{0}")] + Canceled(#[from] actix_rt::task::JoinError), } -#[tracing::instrument(name = "Upload")] +#[tracing::instrument(name = "Upload Page")] async fn index() -> Result { render(HttpResponse::Ok(), |cursor| { self::templates::index(cursor, "/upload", "images[]") }) } +#[tracing::instrument(name = "List Uploads", skip(client))] +async fn list_uploads( + query: serde_qs::actix::QsQuery, + client: web::Data, +) -> Result { + let query = query.into_inner(); + + let mut upload_handles = Vec::new(); + let mut details_handles = Vec::new(); + + for upload_id in &query.uploads { + let claim_url = CONFIG.upstream_claim_url(upload_id.as_str()); + let client = client.clone(); + + upload_handles.push(actix_rt::spawn(async move { + let mut res = client.get(claim_url).send().await?; + + if res.status() == 204 { + return Ok(None) as Result, Error>; + } + + let result = res.json::().await?; + + match result.files { + Some(files) if files.len() == 1 => Ok(files.into_iter().next()), + Some(_) => Err(ErrorKind::UploadFailed("Bad response".into()).into()), + None => Err(ErrorKind::UploadFailed(result.msg).into()), + } + })); + } + + for (file, delete_token) in &query.files { + let details_url = CONFIG.upstream_details_url(file); + + let file = file.clone(); + let delete_token = delete_token.clone(); + let client = client.clone(); + + details_handles.push(actix_rt::spawn(async move { + let mut res = client.get(details_url).send().await?; + + let details = res.json::
().await?; + + Ok(Image { + file, + delete_token, + details, + }) + })) + } + + let mut results = Vec::new(); + let mut any_incomplete = false; + + for handle in details_handles { + let res = handle.await.map_err(Error::from).and_then(|res| res); + + match res { + Ok(image) => { + results.push(UploadResult::Image(image)); + } + Err(e) => { + results.push(UploadResult::Error(e)); + } + } + } + + for (handle, upload_id) in upload_handles.into_iter().zip(&query.uploads) { + let res = handle.await.map_err(Error::from).and_then(|res| res); + + match res { + Ok(Some(image)) => { + results.push(UploadResult::Image(image)); + } + Ok(None) => { + any_incomplete = true; + results.push(UploadResult::UploadId(upload_id)); + } + Err(e) => { + results.push(UploadResult::Error(e)); + } + } + } + + if any_incomplete { + let new_query = + results + .into_iter() + .fold(UploadQuery::default(), |mut query, res| match res { + UploadResult::Image(img) => { + query.files.push((img.file, img.delete_token)); + query + } + UploadResult::UploadId(id) => { + query.uploads.push(id.to_owned()); + query + } + _ => query, + }); + + if new_query != query { + let query = serde_qs::to_string(&new_query)?; + + return Ok(HttpResponse::SeeOther() + .insert_header((LOCATION, format!("/upload?{}", query))) + .finish()); + } + + return render(HttpResponse::Ok(), |cursor| { + self::templates::uploads(cursor) + }); + } + + render(HttpResponse::Ok(), |cursor| { + self::templates::finished_uploads(cursor, results) + }) +} + #[tracing::instrument(name = "Upload", skip(req, body, client))] async fn upload( req: HttpRequest, @@ -354,11 +531,15 @@ async fn upload( let mut res = client_request.send_stream(body).await?; - let images = res.json::().await?; + let uploads = res.json::().await?; - render(HttpResponse::build(res.status()), |cursor| { - self::templates::images(cursor, images) - }) + let query = UploadQuery::try_from_uploads(uploads).map_err(ErrorKind::UploadFailed)?; + + let query = serde_qs::to_string(&query)?; + + Ok(HttpResponse::SeeOther() + .insert_header((LOCATION, format!("/upload?{}", query))) + .finish()) } const THUMBNAIL_SIZES: &[u64] = &[40, 50, 80, 100, 200, 400, 800, 1200]; @@ -713,7 +894,11 @@ async fn main() -> Result<(), anyhow::Error> { .app_data(web::Data::new(client)) .wrap(TracingLogger::default()) .service(web::resource("/").route(web::get().to(index))) - .service(web::resource("/upload").route(web::post().to(upload))) + .service( + web::resource("/upload") + .route(web::post().to(upload)) + .route(web::get().to(list_uploads)), + ) .service(web::resource("/image/{filename}").route(web::get().to(full_res))) .service(web::resource("/thumbnails").route(web::get().to(thumbs))) .service(web::resource("/view/{size}/{filename}").route(web::get().to(view))) diff --git a/static/uploads.js b/static/uploads.js new file mode 100644 index 0000000..1e6accc --- /dev/null +++ b/static/uploads.js @@ -0,0 +1,11 @@ +(function() { + function reloadOnComplete() { + if (document.readyState === 'complete') { + // Do not use window.reload() because it's bugged on firefox + window.location.href = window.location.href; + } + } + + document.addEventListener('readystatechange', reloadOnComplete); + reloadOnComplete(); +})() diff --git a/templates/confirm_delete.rs.html b/templates/confirm_delete.rs.html index 6d79dac..18ec8ab 100644 --- a/templates/confirm_delete.rs.html +++ b/templates/confirm_delete.rs.html @@ -4,24 +4,24 @@ @(image: &Image) @:layout_html("Confirm Delete", Some(&format!("Delete {} from pict-rs", image.filename())), { - Confirm Delete - +Confirm Delete + }, { -
-
-

Are you sure you want to delete @image.filename()?

-
- - @:return_home_html() -
+
+
+

Are you sure you want to delete @image.filename()?

+
+ + @:return_home_html() +
}) diff --git a/templates/deleted.rs.html b/templates/deleted.rs.html index e925156..e043186 100644 --- a/templates/deleted.rs.html +++ b/templates/deleted.rs.html @@ -3,10 +3,10 @@ @(filename: &str) @:layout_html(&format!("Deleted {}", filename), None, {}, { -
-
-

Deleted @filename

-
- @:return_home_html() -
+
+
+

Deleted @filename

+
+ @:return_home_html() +
}) diff --git a/templates/error.rs.html b/templates/error.rs.html index 1944700..7436b43 100644 --- a/templates/error.rs.html +++ b/templates/error.rs.html @@ -3,13 +3,13 @@ @(msg: &str) @:layout_html("Error", None, {}, { -
-
-

There was an error processing your request

-
-
-

@msg

-
- @:return_home_html() -
+
+
+

There was an error processing your request

+
+
+

@msg

+
+ @:return_home_html() +
}) diff --git a/templates/finished_uploads.rs.html b/templates/finished_uploads.rs.html new file mode 100644 index 0000000..8ca491a --- /dev/null +++ b/templates/finished_uploads.rs.html @@ -0,0 +1,63 @@ +@use super::{layout_html, return_home_html, statics::images_css}; +@use crate::{UploadResult, FileType}; + +@(results: Vec) + + @:layout_html("Upload Complete!", None, { + + }, { +
+
+

Your images have been uploaded

+
+
+

Do not lose these links

+
+
    + @for result in results { +
  • + +
  • + } +
+ @:return_home_html() +
+ }) diff --git a/templates/images.rs.html b/templates/images.rs.html index 4fc1066..f3c67be 100644 --- a/templates/images.rs.html +++ b/templates/images.rs.html @@ -4,68 +4,56 @@ @(images: Images) @:layout_html(images.message(), None, { - + }, { -
- @if let Some(images) = images.files() { -
-

Your images have been uploaded

-
-
-

Do not lose these links

-
- - } else { -
-

There was an error uploading your images

-
-
-

@images.msg()

-
- } - @:return_home_html() -
+
+ @if let Some(images) = images.files() { +
+

Your images have been uploaded

+
+
+

Do not lose these links

+
+ + } else { +
+

There was an error uploading your images

+
+
+

@images.msg()

+
+ } + @:return_home_html() +
}) diff --git a/templates/index.rs.html b/templates/index.rs.html index cd70e2a..c9dcec4 100644 --- a/templates/index.rs.html +++ b/templates/index.rs.html @@ -3,37 +3,35 @@ @(endpoint: &str, name: &str) @:layout_html("Upload Images", None, { - - + + }, { -
-
-
-
-

Upload Images

-
-
-
- -
-
- Select Files - -
-
-
-
-
- Upload - -
-
-
-
+
+
+
+
+

+ Upload Images +

+
+
+
+ +
+
+ Select Files + +
+
+
+
+
+ Upload + +
+
+
+
}) diff --git a/templates/layout.rs.html b/templates/layout.rs.html index 85a9df9..83fde7a 100644 --- a/templates/layout.rs.html +++ b/templates/layout.rs.html @@ -2,26 +2,31 @@ @(title: &str, description: Option<&str>, head: Content, body: Content) - + - - - - - @title - - - @if let Some(description) = description { - - } else { - - } - - - @:head() - - -

pict-rs

- @:body() - - + + + + + + @title + + + @if let Some(description) = description { + + } else { + + } + + + @:head() + + + +
+

pict-rs

+
+ @:body() + + + diff --git a/templates/not_found.rs.html b/templates/not_found.rs.html index 64b22d9..833281b 100644 --- a/templates/not_found.rs.html +++ b/templates/not_found.rs.html @@ -3,15 +3,15 @@ @() @:layout_html("Not Found", None, { - + }, { -
-
-

Oops!

-
-
-

The page you are looking for could not be found

-
- @:return_home_html() -
+
+
+

Oops!

+
+
+

The page you are looking for could not be found

+
+ @:return_home_html() +
}) diff --git a/templates/return_home.rs.html b/templates/return_home.rs.html index c4243cc..bb4c59f 100644 --- a/templates/return_home.rs.html +++ b/templates/return_home.rs.html @@ -1,5 +1,5 @@ @() diff --git a/templates/thumbnails.rs.html b/templates/thumbnails.rs.html index 72211e7..efae25c 100644 --- a/templates/thumbnails.rs.html +++ b/templates/thumbnails.rs.html @@ -4,42 +4,38 @@ @(image: Image, sizes: &[u64]) @:layout_html("Thumbnails", Some(&format!("Thumbnails for {}", image.filename())), { - - - - + + + + }, { -
-
-

Here are your thumbnails

-
- - @:return_home_html() -
+
+
+

Here are your thumbnails

+
+ + @:return_home_html() +
}) diff --git a/templates/uploads.rs.html b/templates/uploads.rs.html new file mode 100644 index 0000000..450fa80 --- /dev/null +++ b/templates/uploads.rs.html @@ -0,0 +1,14 @@ +@use super::{layout_html, return_home_html, statics::uploads_js}; + +@() + +@:layout_html("Waiting for uploads...", None, { + +}, { +
+
+

Your images are being uploaded, please refresh in a few seconds...

+
+ @:return_home_html() +
+}) diff --git a/templates/view.rs.html b/templates/view.rs.html index a5e43f5..656ef19 100644 --- a/templates/view.rs.html +++ b/templates/view.rs.html @@ -3,46 +3,39 @@ @(image: Image, size: Option) -@:layout_html(&format!("Image: {}", image.filename()), Some("An image hosted on pict-rs"), { - - @if let Some(size) = size { - - - - } else { - - - } - -}, { -
-
-
- @if let Some(size) = size { - - - @image.filename() - -

Direct Link

- } else { - @if image.is_video() { - - } else { - @image.filename() - } -

Direct Link

- } -
-
- @:return_home_html() -
-}) + @:layout_html(&format!("Image: {}", image.filename()), Some("An image hosted on pict-rs"), { + + @if let Some(size) = size { + + + + } else { + + + } + + }, { +
+
+
+ @if let Some(size) = size { + + + @image.filename() + +

Direct Link

+ } else { + @if image.is_video() { + + } else { + @image.filename() + } +

Direct Link

+ } +
+
+ @:return_home_html() +
+ })