From 6e90529420a2dec01f08b2bd18b4ecddcf1f07ad Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 23 Oct 2024 20:06:34 +0300 Subject: [PATCH] 0.1.0-overlay --- Cargo.lock | 594 +++++++++++++++++++++++-------------- Cargo.toml | 4 +- README.md | 5 + src/Muller-Regular.woff2 | Bin 0 -> 34872 bytes src/core.rs | 72 +++++ src/handlers/proxy.rs | 13 +- src/handlers/serve_file.rs | 10 +- src/main.rs | 2 + src/overlay.rs | 93 ++++++ 9 files changed, 556 insertions(+), 237 deletions(-) create mode 100644 src/Muller-Regular.woff2 create mode 100644 src/core.rs create mode 100644 src/overlay.rs diff --git a/Cargo.lock b/Cargo.lock index 9f844cd..88c6a25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,22 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ab_glyph" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3672c180e71eeaaac3a541fbbc5f5ad4def8b747c595ad30d674e43049f7b0" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" + [[package]] name = "actix" version = "0.13.5" @@ -261,9 +277,9 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] @@ -380,9 +396,18 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.89" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8" + +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] [[package]] name = "arbitrary" @@ -415,9 +440,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "async-trait" -version = "0.1.82" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", @@ -432,9 +457,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "av1-grain" @@ -452,18 +477,18 @@ dependencies = [ [[package]] name = "avif-serialize" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876c75a42f6364451a033496a14c44bffe41f5f4a8236f697391f11024e596d2" +checksum = "e335041290c43101ca215eed6f43ec437eb5a42125573f600fc3fa42b9bddd62" dependencies = [ "arrayvec", ] [[package]] name = "aws-config" -version = "1.5.6" +version = "1.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "848d7b9b605720989929279fa644ce8f244d0ce3146fcca5b70e4eb7b3c020fc" +checksum = "7198e6f03240fdceba36656d8be440297b6b82270325908c7381f37d826a74f6" dependencies = [ "aws-credential-types", "aws-runtime", @@ -529,9 +554,9 @@ dependencies = [ [[package]] name = "aws-sdk-s3" -version = "1.51.0" +version = "1.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c09fd4b5c7ed75f52b913b4f3ff0501dae7f8cb9125f6d45db4553980cbc0528" +checksum = "8888c238bf93c77c5df8274b3999fd7fc1bb3fb658616f40dfde9e4fcd9efd94" dependencies = [ "ahash", "aws-credential-types", @@ -564,9 +589,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.43.0" +version = "1.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a9d27ed1c12b1140c47daf1bc541606c43fdafd918c4797d520db0043ceef2" +checksum = "0dc2faec3205d496c7e57eff685dd944203df7ce16a4116d0281c44021788a7b" dependencies = [ "aws-credential-types", "aws-runtime", @@ -586,9 +611,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.44.0" +version = "1.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44514a6ca967686cde1e2a1b81df6ef1883d0e3e570da8d8bc5c491dcb6fc29b" +checksum = "c93c241f52bc5e0476e259c953234dab7e2a35ee207ee202e86c0095ec4951dc" dependencies = [ "aws-credential-types", "aws-runtime", @@ -608,9 +633,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.43.0" +version = "1.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7a4d279762a35b9df97209f6808b95d4fe78547fe2316b4d200a0283960c5a" +checksum = "b259429be94a3459fa1b00c5684faee118d74f9577cc50aebadc36e507c63b5f" dependencies = [ "aws-credential-types", "aws-runtime", @@ -743,9 +768,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.7.1" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1ce695746394772e7000b39fe073095db6d45a862d0767dd5ad0ac0d7f8eb87" +checksum = "a065c0fe6fdbdf9f11817eb68582b2ab4aff9e9c39e986ae48f7ec576c6322db" dependencies = [ "aws-smithy-async", "aws-smithy-http", @@ -758,7 +783,7 @@ dependencies = [ "http-body 0.4.6", "http-body 1.0.1", "httparse", - "hyper 0.14.30", + "hyper 0.14.31", "hyper-rustls 0.24.2", "once_cell", "pin-project-lite", @@ -787,9 +812,9 @@ dependencies = [ [[package]] name = "aws-smithy-types" -version = "1.2.6" +version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03701449087215b5369c7ea17fef0dd5d24cb93439ec5af0c7615f58c3f22605" +checksum = "147100a7bea70fa20ef224a6bad700358305f5dc0f84649c53769761395b355b" dependencies = [ "base64-simd", "bytes", @@ -939,9 +964,9 @@ dependencies = [ [[package]] name = "built" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "236e6289eda5a812bc6b53c3b024039382a2895fbbeef2d748b2931546d392c4" +checksum = "c360505aed52b7ec96a3636c3f039d99103c37d1d9b4f7a8c743d3ea9ffcd03b" [[package]] name = "bumpalo" @@ -951,9 +976,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" +checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" [[package]] name = "byteorder" @@ -969,9 +994,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.7.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] name = "bytes-utils" @@ -994,9 +1019,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.21" +version = "1.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" +checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" dependencies = [ "jobserver", "libc", @@ -1273,8 +1298,9 @@ dependencies = [ [[package]] name = "discoursio-quoter" -version = "0.0.9" +version = "0.1.0" dependencies = [ + "ab_glyph", "actix", "actix-multipart", "actix-web", @@ -1283,6 +1309,7 @@ dependencies = [ "env_logger", "futures", "image", + "imageproc", "log", "mime_guess", "redis", @@ -1405,9 +1432,9 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "fdeflate" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" +checksum = "d8090f921a24b04994d9929e204f50b498a33ea6ba559ffaa05e04f7ee7fb5ab" dependencies = [ "simd-adler32", ] @@ -1436,9 +1463,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.33" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", "miniz_oxide 0.8.0", @@ -1446,9 +1473,9 @@ dependencies = [ [[package]] name = "flume" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" dependencies = [ "spin", ] @@ -1459,6 +1486,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "foreign-types" version = "0.3.2" @@ -1485,9 +1518,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -1500,9 +1533,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -1510,15 +1543,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -1527,15 +1560,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", @@ -1544,21 +1577,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -1589,8 +1622,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -1605,9 +1640,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.31.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "group" @@ -1670,12 +1705,13 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" dependencies = [ - "ahash", "allocator-api2", + "equivalent", + "foldhash", ] [[package]] @@ -1774,9 +1810,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -1792,9 +1828,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.30" +version = "0.14.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" dependencies = [ "bytes", "futures-channel", @@ -1816,9 +1852,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" dependencies = [ "bytes", "futures-channel", @@ -1842,7 +1878,7 @@ checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http 0.2.12", - "hyper 0.14.30", + "hyper 0.14.31", "log", "rustls 0.21.12", "rustls-native-certs", @@ -1858,9 +1894,9 @@ checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http 1.1.0", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-util", - "rustls 0.23.13", + "rustls 0.23.15", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -1875,7 +1911,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-util", "native-tls", "tokio", @@ -1885,20 +1921,19 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da62f120a8a37763efb0cf8fdf264b884c7b8b9ac8660b900c8661030c00e6ba" +checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" dependencies = [ "bytes", "futures-channel", "futures-util", "http 1.1.0", "http-body 1.0.1", - "hyper 1.4.1", + "hyper 1.5.0", "pin-project-lite", "socket2", "tokio", - "tower", "tower-service", "tracing", ] @@ -1921,9 +1956,9 @@ dependencies = [ [[package]] name = "image" -version = "0.25.2" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99314c8a2152b8ddb211f924cdae532d8c5e4c8bb54728e12fff1b0cd5963a10" +checksum = "bc144d44a31d753b02ce64093d532f55ff8dc4ebf2ffb8a63c0dda691385acae" dependencies = [ "bytemuck", "byteorder-lite", @@ -1944,31 +1979,49 @@ dependencies = [ [[package]] name = "image-webp" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f79afb8cbee2ef20f59ccd477a218c12a93943d075b492015ecb1bb81f8ee904" +checksum = "e031e8e3d94711a9ccb5d6ea357439ef3dcbed361798bd4071dc4d9793fbe22f" dependencies = [ "byteorder-lite", "quick-error", ] [[package]] -name = "imgref" -version = "1.10.1" +name = "imageproc" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44feda355f4159a7c757171a77de25daf6411e217b4cabd03bd6650690468126" +checksum = "2393fb7808960751a52e8a154f67e7dd3f8a2ef9bd80d1553078a7b4e8ed3f0d" +dependencies = [ + "ab_glyph", + "approx", + "getrandom", + "image", + "itertools", + "nalgebra", + "num", + "rand", + "rand_distr", + "rayon", +] + +[[package]] +name = "imgref" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" [[package]] name = "impl-more" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206ca75c9c03ba3d4ace2460e57b189f39f43de612c2f85836e65c929701bb2d" +checksum = "aae21c3177a27788957044151cc2800043d127acaa460a47ebb9b84dfa2c6aa0" [[package]] name = "indexmap" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", "hashbrown", @@ -1987,9 +2040,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.10.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "is_terminal_polyfill" @@ -2029,9 +2082,9 @@ checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] @@ -2056,9 +2109,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" [[package]] name = "libc" -version = "0.2.158" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "libfuzzer-sys" @@ -2071,6 +2124,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -2121,13 +2180,23 @@ dependencies = [ [[package]] name = "lru" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ "hashbrown", ] +[[package]] +name = "matrixmultiply" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a" +dependencies = [ + "autocfg", + "rawpointer", +] + [[package]] name = "maybe-rayon" version = "0.1.1" @@ -2182,7 +2251,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", - "simd-adler32", ] [[package]] @@ -2192,6 +2260,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ "adler2", + "simd-adler32", ] [[package]] @@ -2207,6 +2276,21 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "nalgebra" +version = "0.32.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5c17de023a86f59ed79891b2e5d5a94c705dbe904a5b5c9c952ea6221b03e4" +dependencies = [ + "approx", + "matrixmultiply", + "num-complex", + "num-rational", + "num-traits", + "simba", + "typenum", +] + [[package]] name = "native-tls" version = "0.2.12" @@ -2246,6 +2330,20 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -2256,6 +2354,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -2282,6 +2389,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-rational" version = "0.4.2" @@ -2300,28 +2418,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] name = "object" -version = "0.36.4" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "openssl" -version = "0.10.66" +version = "0.10.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ "bitflags 2.6.0", "cfg-if", @@ -2351,9 +2470,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.103" +version = "0.9.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" dependencies = [ "cc", "libc", @@ -2378,6 +2497,15 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4030760ffd992bef45b0ae3f10ce1aba99e33464c90d14dd7c039884963ddc7a" +[[package]] +name = "owned_ttf_parser" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec719bbf3b2a81c109a4e20b1f129b5566b7dce654bc3872f6a05abf82b2c4" +dependencies = [ + "ttf-parser", +] + [[package]] name = "p256" version = "0.11.1" @@ -2430,26 +2558,6 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" -[[package]] -name = "pin-project" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "pin-project-lite" version = "0.2.14" @@ -2480,15 +2588,15 @@ checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "png" -version = "0.17.13" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" +checksum = "52f9d46a34a05a6a57566bc2bfae066ef07585a6e3fa30fbbdff5936380623f0" dependencies = [ "bitflags 1.3.2", "crc32fast", "fdeflate", "flate2", - "miniz_oxide 0.7.4", + "miniz_oxide 0.8.0", ] [[package]] @@ -2508,27 +2616,27 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] [[package]] name = "profiling" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58" +checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" dependencies = [ "profiling-procmacros", ] [[package]] name = "profiling-procmacros" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8021cf59c8ec9c432cfc2526ac6b8aa508ecaf29cd415f271b8406c1b851c3fd" +checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" dependencies = [ "quote", "syn", @@ -2588,6 +2696,16 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rand_distr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +dependencies = [ + "num-traits", + "rand", +] + [[package]] name = "rav1e" version = "0.7.1" @@ -2625,9 +2743,9 @@ dependencies = [ [[package]] name = "ravif" -version = "0.11.10" +version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f0bfd976333248de2078d350bfdf182ff96e168a24d23d2436cef320dd4bdd" +checksum = "2413fd96bd0ea5cdeeb37eaf446a22e6ed7b981d792828721e74ded1980a45c6" dependencies = [ "avif-serialize", "imgref", @@ -2637,6 +2755,12 @@ dependencies = [ "rgb", ] +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + [[package]] name = "rayon" version = "1.10.0" @@ -2659,9 +2783,9 @@ dependencies = [ [[package]] name = "redis" -version = "0.27.2" +version = "0.27.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7e86f5670bd8b028edfb240f0616cad620705b31ec389d55e4f3da2c38dcd48" +checksum = "81cccf17a692ce51b86564334614d72dcae1def0fd5ecebc9f02956da74352b5" dependencies = [ "arc-swap", "async-trait", @@ -2682,18 +2806,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.4" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "regex" -version = "1.10.6" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", @@ -2703,9 +2827,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", @@ -2720,15 +2844,15 @@ checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.7" +version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" +checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" dependencies = [ "base64 0.22.1", "bytes", @@ -2740,7 +2864,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.1", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-rustls 0.27.3", "hyper-tls", "hyper-util", @@ -2752,7 +2876,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile 2.1.3", + "rustls-pemfile 2.2.0", "serde", "serde_json", "serde_urlencoded", @@ -2784,9 +2908,6 @@ name = "rgb" version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" -dependencies = [ - "bytemuck", -] [[package]] name = "ring" @@ -2845,9 +2966,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.13" +version = "0.23.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" +checksum = "5fbb44d7acc4e873d613422379f69f237a1b141928c02f6bc6ccfddddc2d7993" dependencies = [ "once_cell", "rustls-pki-types", @@ -2879,19 +3000,18 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.3" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64 0.22.1", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-webpki" @@ -2921,10 +3041,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] -name = "schannel" -version = "0.1.24" +name = "safe_arch" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" +checksum = "c3460605018fdc9612bce72735cba0d27efbcd9904780d44c7e3a9948f96148a" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "schannel" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" dependencies = [ "windows-sys 0.59.0", ] @@ -3109,18 +3238,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.210" +version = "1.0.213" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.213" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5" dependencies = [ "proc-macro2", "quote", @@ -3129,9 +3258,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "itoa", "memchr", @@ -3150,9 +3279,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -3222,6 +3351,19 @@ dependencies = [ "rand_core", ] +[[package]] +name = "simba" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae" +dependencies = [ + "approx", + "num-complex", + "num-traits", + "paste", + "wide", +] + [[package]] name = "simd-adler32" version = "0.3.7" @@ -3295,9 +3437,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.77" +version = "2.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" dependencies = [ "proc-macro2", "quote", @@ -3355,9 +3497,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if", "fastrand", @@ -3368,18 +3510,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" dependencies = [ "proc-macro2", "quote", @@ -3445,9 +3587,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.40.0" +version = "1.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" dependencies = [ "backtrace", "bytes", @@ -3498,7 +3640,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.13", + "rustls 0.23.15", "rustls-pki-types", "tokio", ] @@ -3539,9 +3681,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.21" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap", "serde", @@ -3550,27 +3692,6 @@ dependencies = [ "winnow", ] -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "pin-project", - "pin-project-lite", - "tokio", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - [[package]] name = "tower-service" version = "0.3.3" @@ -3625,6 +3746,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "ttf-parser" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5902c5d130972a0000f60860bfbf46f7ca3db5391eddfedd1b8728bd9dc96c0e" + [[package]] name = "typenum" version = "1.17.0" @@ -3642,18 +3769,15 @@ dependencies = [ [[package]] name = "unicase" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" @@ -3715,9 +3839,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ "getrandom", "serde", @@ -3781,9 +3905,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", "once_cell", @@ -3792,9 +3916,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", @@ -3807,9 +3931,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.43" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" dependencies = [ "cfg-if", "js-sys", @@ -3819,9 +3943,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3829,9 +3953,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", @@ -3842,15 +3966,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "web-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" dependencies = [ "js-sys", "wasm-bindgen", @@ -3862,6 +3986,16 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" +[[package]] +name = "wide" +version = "0.7.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b828f995bf1e9622031f8009f8481a85406ce1f4d4588ff746d872043e855690" +dependencies = [ + "bytemuck", + "safe_arch", +] + [[package]] name = "winapi" version = "0.3.9" @@ -4017,9 +4151,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index a4b07e1..8033ba1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "discoursio-quoter" -version = "0.0.9" +version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -24,6 +24,8 @@ actix-multipart = "0.7.2" log = "0.4.22" env_logger = "0.11.5" actix = "0.13.5" +imageproc = "0.25.0" +ab_glyph = "0.2.29" [[bin]] name = "quoter" diff --git a/README.md b/README.md index 3411e3a..6fc8331 100644 --- a/README.md +++ b/README.md @@ -32,10 +32,15 @@ 7. **Сохранение информации о загруженных файлах в Redis**: - Имя каждого загруженного файла сохраняется в Redis для отслеживания загруженных пользователем файлов. Это позволяет учитывать квоты и управлять пространством, занимаемым файлами. +8. **Оверлей для shout**: + - При загрузке файла, если он является изображением, и в запросе присутствует параметр `s=`, то к файлу будет добавлен оверлей с данными shout. + ## Использование Нужно задать следующие переменные среды: - `REDIS_URL`: URL для подключения к Redis. Используется для управления квотами и хранения информации о загружаемых файлах. - `CDN_DOMAIN`: Домен CDN для генерации публичных URL-адресов загруженных файлов. +- `AUTH_URL`: URL для подключения к сервису аутентификации. +- `CORE_URL`: URL для подключения к сервису core. - `STORJ_ACCESS_KEY`, `STORJ_SECRET_KEY`, `AWS_ACCESS_KEY`, `AWS_SECRET_KEY` diff --git a/src/Muller-Regular.woff2 b/src/Muller-Regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..39772008be9c11e63c4f855b89ed9c4121e428d8 GIT binary patch literal 34872 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≧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 literal 0 HcmV?d00001 diff --git a/src/core.rs b/src/core.rs new file mode 100644 index 0000000..d06b717 --- /dev/null +++ b/src/core.rs @@ -0,0 +1,72 @@ + use reqwest::Client as HTTPClient; +use serde::Deserialize; +use serde_json::json; +use std::{collections::HashMap, env, error::Error}; + + +// Структура для десериализации ответа от сервиса аутентификации +#[derive(Deserialize)] +struct CoreResponse { + data: Option, +} + +#[derive(Deserialize)] +pub struct ShoutTopic { + pub slug: String, + pub title: String, +} + +#[derive(Deserialize)] +pub struct ShoutAuthor { + pub name: String, +} + +#[derive(Deserialize)] +pub struct Shout { + pub title: String, + pub created_at: String, + pub created_by: i32, + pub main_topic: String, + pub topics: Vec, + pub authors: Vec, + pub layout: String, +} + +pub async fn get_shout_by_id(shout_id: i32) -> Result> { + let mut variables = HashMap::::new(); + let api_base = env::var("CORE_URL")?; + let query_name = "get_shout"; + let operation = "GetShout"; + if shout_id != 0 { + variables.insert("shout_id".to_string(), shout_id); + } + + let gql = json!({ + "query": format!("query {}($slug: String, $shout_id: Int) {{ {}(slug: $slug, shout_id: $shout_id) {{ title created_at created_by topics {{ title slug }} authors {{ id name }} }} }}", operation, query_name), + "operationName": operation, + "variables": variables + }); + + let client = HTTPClient::new(); + let response = client + .post(&api_base) + .json(&gql) + .send() + .await?; + + if response.status().is_success() { + let core_response: CoreResponse = response.json().await?; + if let Some(shout) = core_response.data { + return Ok(shout); + } + Err(Box::new(std::io::Error::new( + std::io::ErrorKind::Other, + "Shout not found", + ))) + } else { + Err(Box::new(std::io::Error::new( + std::io::ErrorKind::Other, + response.status().to_string(), + ))) + } +} \ No newline at end of file diff --git a/src/handlers/proxy.rs b/src/handlers/proxy.rs index 16b3b04..ff4bbf8 100644 --- a/src/handlers/proxy.rs +++ b/src/handlers/proxy.rs @@ -9,7 +9,7 @@ use crate::thumbnail::{find_closest_width, parse_file_path, thumbdata_save}; /// Обработчик для скачивания файла и генерации миниатюры, если она недоступна. pub async fn proxy_handler( - _req: HttpRequest, + req: HttpRequest, requested_res: web::Path, state: web::Data, ) -> Result { @@ -48,6 +48,11 @@ pub async fn proxy_handler( warn!("content_type: {}", content_type); + let shout_id = match req.query_string().contains("s=") { + true => req.query_string().split("s=").collect::>().pop().unwrap_or(""), + false => "" + }; + return match state.get_path(&filekey).await { Ok(Some(stored_path)) => { warn!("stored_path: {}", stored_path); @@ -55,7 +60,7 @@ pub async fn proxy_handler( if check_file_exists(&state.storj_client, &state.bucket, &stored_path).await? { if content_type.starts_with("image") { return match requested_width == 0 { - true => serve_file(&stored_path, &state).await, + true => serve_file(&stored_path, &state, shout_id).await, false => { // find closest thumb width let closest: u32 = find_closest_width(requested_width as u32); @@ -71,7 +76,7 @@ pub async fn proxy_handler( { Ok(true) => { warn!("serve existed thumb file: {}", thumb_filename); - serve_file(thumb_filename, &state).await + serve_file(thumb_filename, &state, shout_id).await }, Ok(false) => { if let Ok(filedata) = load_file_from_s3( @@ -91,7 +96,7 @@ pub async fn proxy_handler( ) .await; warn!("serve new thumb file: {}", thumb_filename); - serve_file(thumb_filename, &state).await + serve_file(thumb_filename, &state, shout_id).await } else { error!("cannot generate thumbnail"); Err(ErrorInternalServerError( diff --git a/src/handlers/serve_file.rs b/src/handlers/serve_file.rs index 694580b..7c70a05 100644 --- a/src/handlers/serve_file.rs +++ b/src/handlers/serve_file.rs @@ -2,10 +2,11 @@ use actix_web::{error::ErrorInternalServerError, HttpResponse, Result}; use mime_guess::MimeGuess; use crate::app_state::AppState; +use crate::overlay::generate_overlay; use crate::s3_utils::check_file_exists; /// Функция для обслуживания файла по заданному пути. -pub async fn serve_file(filepath: &str, state: &AppState) -> Result { +pub async fn serve_file(filepath: &str, state: &AppState, shout_id: &str) -> Result { if filepath.is_empty() { return Err(ErrorInternalServerError("Filename is empty".to_string())); } @@ -32,7 +33,12 @@ pub async fn serve_file(filepath: &str, state: &AppState) -> Result data.into_bytes(), + false => generate_overlay(shout_id, data.into_bytes()).await? + }; + + let mime_type = MimeGuess::from_path(&filepath).first_or_octet_stream(); Ok(HttpResponse::Ok() diff --git a/src/main.rs b/src/main.rs index 931e462..7c78c0d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,8 @@ mod auth; mod handlers; mod s3_utils; mod thumbnail; +mod core; +mod overlay; use actix_web::{middleware::Logger, web, App, HttpServer}; use app_state::AppState; diff --git a/src/overlay.rs b/src/overlay.rs new file mode 100644 index 0000000..a4f991c --- /dev/null +++ b/src/overlay.rs @@ -0,0 +1,93 @@ +use std::{error::Error, io::Cursor}; +use actix_web::web::Bytes; +use log::warn; +use image::Rgba; +use imageproc::drawing::{draw_text_mut, draw_filled_rect_mut}; +use imageproc::rect::Rect; +use ab_glyph::{Font, FontArc, PxScale}; + +use crate::core::get_shout_by_id; + +pub async fn generate_overlay<'a>(shout_id: &'a str, filedata: Bytes) -> Result> { + // Получаем shout из GraphQL + let shout_id_int = shout_id.parse::().unwrap_or(0); + match get_shout_by_id(shout_id_int).await { + Ok(shout) => { + // Преобразуем Bytes в ImageBuffer + let img = image::load_from_memory(&filedata)?; + let mut img = img.to_rgba8(); + + // Загружаем шрифт + let font_vec = Vec::from(include_bytes!("Muller-Regular.woff2") as &[u8]); + let font = FontArc::try_from_vec(font_vec).unwrap(); + + // Получаем размеры изображения + let (img_width, img_height) = img.dimensions(); + let max_text_width = (img_width as f32) * 0.8; + let max_text_height = (img_height as f32) * 0.8; + + // Начальный масштаб + let mut scale: f32 = 24.0; + let text_length = shout.title.chars().count() as f32; + let mut text_width = scale * text_length; + let text_height = scale; + + // Регулируем масштаб, пока текст не впишется в 80% от размеров изображения + while text_width > max_text_width || text_height > max_text_height { + scale -= 1.0; + if scale <= 0.0 { + break; + } + text_width = scale * text_length; + // text_height остается равным scale + } + + // Рассчёт позиции текста для центрирования + let x = ((img_width as f32 - text_width) / 2.0).ceil() as i32; + let y = ((img_height as f32 - text_height) / 2.0).ceil() as i32; + + // Задаём отступы для подложки + let padding_x = 10; + let padding_y = 5; + + // Определяем размеры подложки + let rect_width = text_width.ceil() as u32 + (2 * padding_x); + let rect_height = text_height.ceil() as u32 + (2 * padding_y); + + // Определяем координаты подложки + let rect_x = x - padding_x as i32; + let rect_y = y - padding_y as i32; + + // Создаём прямоугольник + let rect = Rect::at(rect_x, rect_y).of_size(rect_width, rect_height); + + // Задаём цвет подложки (полупрозрачный серый) + let background_color = Rgba([128u8, 128u8, 128u8, 128u8]); // RGBA: серый с прозрачностью 50% + + // Рисуем подложку + draw_filled_rect_mut(&mut img, rect, background_color); + + // Рисуем текст поверх подложки + let scaled_font = font.as_scaled(scale).font; + draw_text_mut( + &mut img, + Rgba([255u8, 255u8, 255u8, 255u8]), // Белый цвет текста + x, + y, + PxScale::from(scale), + &scaled_font, + &shout.title, + ); + + // Преобразуем ImageBuffer обратно в Bytes + let mut buffer = Vec::new(); + img.write_to(&mut Cursor::new(&mut buffer), image::ImageFormat::Png)?; + + Ok(Bytes::from(buffer)) + }, + Err(e) => { + warn!("Error getting shout: {}", e); + Ok(filedata) + } + } +}