From 5787c85522dd504912b6f825dd208e8bfd75fa9b Mon Sep 17 00:00:00 2001 From: koalp Date: Sun, 20 Jun 2021 19:09:17 +0200 Subject: [PATCH] feat: upload and serve websites --- Cargo.lock | 393 ++++++++++++++++++++++++++++------------------ Cargo.toml | 18 ++- README.md | 14 +- src/api.rs | 52 +++++- src/config.rs | 32 ++++ src/domain.rs | 0 src/main.rs | 21 ++- src/subdomains.rs | 110 ------------- src/website.rs | 203 ++++++++++++++++++++++++ 9 files changed, 548 insertions(+), 295 deletions(-) create mode 100644 src/config.rs create mode 100644 src/domain.rs delete mode 100644 src/subdomains.rs create mode 100644 src/website.rs diff --git a/Cargo.lock b/Cargo.lock index c3743dc..d40c92a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,15 +1,35 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "anyhow" version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" +[[package]] +name = "async-compression" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443ccbb270374a2b1055fc72da40e1f237809cd6bb0e97e66d264cd138473a6" +dependencies = [ + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", +] + [[package]] name = "async-stream" -version = "0.3.0" -source = "git+https://github.com/SergioBenitez/async-stream.git?rev=c46ada9#c46ada948e0d4800393836f57eb2a3db516beb1e" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "171374e7e3b2504e0e5236e3b59260560f9fe94bfe9ac39ba5e4e929c5590625" dependencies = [ "async-stream-impl", "futures-core", @@ -17,8 +37,9 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.0" -source = "git+https://github.com/SergioBenitez/async-stream.git?rev=c46ada9#c46ada948e0d4800393836f57eb2a3db516beb1e" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308" dependencies = [ "proc-macro2", "quote", @@ -82,9 +103,9 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "bumpalo" -version = "3.6.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" +checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" [[package]] name = "bytes" @@ -94,15 +115,9 @@ checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" [[package]] name = "cc" -version = "1.0.67" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787" [[package]] name = "cfg-if" @@ -112,9 +127,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "const_fn" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402da840495de3f976eaefc3485b7f5eb5b0bf9761f9a47be27fe975b3b8c2ec" +checksum = "f92cfa0fd5690b3cf8c1ef2cabbd9b7ef22fa53cf5e1f92b05103f6d5d1cf6e7" [[package]] name = "convert_case" @@ -134,10 +149,19 @@ dependencies = [ ] [[package]] -name = "derive_more" -version = "0.99.13" +name = "crc32fast" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f82b1b72f1263f214c0f823371768776c4f5841b942c9883aa8e5ec584fd0ba6" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "derive_more" +version = "0.99.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc7b9cef1e351660e5443924e4f43ab25fbbed3e9a5f052df3677deb4d6b320" dependencies = [ "convert_case", "proc-macro2", @@ -148,7 +172,7 @@ dependencies = [ [[package]] name = "devise" version = "0.3.0" -source = "git+https://github.com/SergioBenitez/Devise.git?rev=df00b5#df00b5162edd53e8d496e7935774e69b5f7f6bdf" +source = "git+https://github.com/SergioBenitez/Devise.git?rev=f2431b#f2431bd122f55b03c3bc5b1c8d2267894d3c8142" dependencies = [ "devise_codegen", "devise_core", @@ -157,7 +181,7 @@ dependencies = [ [[package]] name = "devise_codegen" version = "0.3.0" -source = "git+https://github.com/SergioBenitez/Devise.git?rev=df00b5#df00b5162edd53e8d496e7935774e69b5f7f6bdf" +source = "git+https://github.com/SergioBenitez/Devise.git?rev=f2431b#f2431bd122f55b03c3bc5b1c8d2267894d3c8142" dependencies = [ "devise_core", "quote", @@ -166,7 +190,7 @@ dependencies = [ [[package]] name = "devise_core" version = "0.3.0" -source = "git+https://github.com/SergioBenitez/Devise.git?rev=df00b5#df00b5162edd53e8d496e7935774e69b5f7f6bdf" +source = "git+https://github.com/SergioBenitez/Devise.git?rev=f2431b#f2431bd122f55b03c3bc5b1c8d2267894d3c8142" dependencies = [ "bitflags", "proc-macro2", @@ -199,7 +223,7 @@ version = "0.8.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -207,11 +231,17 @@ name = "feuille" version = "0.1.0" dependencies = [ "anyhow", + "async-compression", "dotenv", "rocket", - "rocket_contrib", + "serde", "thiserror", + "tokio", + "tokio-stream", + "tokio-tar", + "tokio-util", "url", + "uuid", ] [[package]] @@ -228,6 +258,30 @@ dependencies = [ "version_check", ] +[[package]] +name = "filetime" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "winapi", +] + +[[package]] +name = "flate2" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0" +dependencies = [ + "cfg-if", + "crc32fast", + "libc", + "miniz_oxide", +] + [[package]] name = "fnv" version = "1.0.7" @@ -246,9 +300,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d5813545e459ad3ca1bff9915e9ad7f1a47dc6a91b627ce321d5863b7dd253" +checksum = "0e7e43a803dae2fa37c1f6a8fe121e1f7bf9548b4dfc0522a42f34145dadfc27" dependencies = [ "futures-channel", "futures-core", @@ -261,9 +315,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce79c6a52a299137a6013061e0cf0e688fce5d7f1bc60125f520912fdb29ec25" +checksum = "e682a68b29a882df0545c143dc3646daefe80ba479bcdede94d5a703de2871e2" dependencies = [ "futures-core", "futures-sink", @@ -271,15 +325,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "098cd1c6dda6ca01650f1a37a794245eb73181d0d4d4e955e2f3c37db7af1815" +checksum = "0402f765d8a89a26043b889b26ce3c4679d268fa6bb22cd7c6aad98340e179d1" [[package]] name = "futures-executor" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f6cb7042eda00f0049b1d2080aa4b93442997ee507eb3828e8bd7577f94c9d" +checksum = "badaa6a909fac9e7236d0620a2f57f7664640c56575b71a7552fbd68deafab79" dependencies = [ "futures-core", "futures-task", @@ -288,16 +342,17 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "365a1a1fb30ea1c03a830fdb2158f5236833ac81fa0ad12fe35b29cddc35cb04" +checksum = "acc499defb3b348f8d8f3f66415835a9131856ff7714bf10dadfc4ec4bdb29a1" [[package]] name = "futures-macro" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668c6733a182cd7deb4f1de7ba3bf2120823835b3bcfbeacf7d2c4a773c1bb8b" +checksum = "a4c40298486cdf52cc00cd6d6987892ba502c7656a16a4192a9992b1ccedd121" dependencies = [ + "autocfg", "proc-macro-hack", "proc-macro2", "quote", @@ -306,22 +361,23 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5629433c555de3d82861a7a4e3794a4c40040390907cfbfd7143a92a426c23" +checksum = "a57bead0ceff0d6dde8f465ecd96c9338121bb7717d3e7b108059531870c4282" [[package]] name = "futures-task" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba7aa51095076f3ba6d9a1f702f74bd05ec65f555d70d2033d55ba8d69f581bc" +checksum = "8a16bef9fc1a4dddb5bee51c989e3fbba26569cbb0e31f5b303c184e3dd33dae" [[package]] name = "futures-util" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c144ad54d60f23927f0a6b6d816e4271278b64f005ad65e4e35291d2de9c025" +checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967" dependencies = [ + "autocfg", "futures-channel", "futures-core", "futures-io", @@ -338,9 +394,9 @@ dependencies = [ [[package]] name = "generator" -version = "0.6.25" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "061d3be1afec479d56fa3bd182bf966c7999ec175fcfdb87ac14d417241366c6" +checksum = "c1d9279ca822891c1a4dae06d185612cf8fc6acfe5dff37781b41297811b12ee" dependencies = [ "cc", "libc", @@ -351,11 +407,11 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi", ] @@ -413,9 +469,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfb77c123b4e2f72a2069aeae0b4b4949cc7e966df277813fc16347e7549737" +checksum = "60daa14be0e0786db0f03a9e57cb404c9d756eed2b6c62b9ea98ec5743ec75a9" dependencies = [ "bytes", "http", @@ -424,21 +480,21 @@ dependencies = [ [[package]] name = "httparse" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1ce40d6fc9764887c2fdc7305c3dcc429ba11ff981c1509416afd5697e4437" +checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68" [[package]] name = "httpdate" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05842d0d43232b23ccb7060ecb0f0626922c21f30012e97b767b30afd4a5d4b9" +checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440" [[package]] name = "hyper" -version = "0.14.7" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e5f105c494081baa3bf9e200b279e27ec1623895cd504c7dbef8d0b080fcf54" +checksum = "07d6baa1b441335f3ce5098ac421fb6547c46dda735ca1bc6d0153c838f9dd83" dependencies = [ "bytes", "futures-channel", @@ -450,7 +506,7 @@ dependencies = [ "httparse", "httpdate", "itoa", - "pin-project", + "pin-project-lite", "socket2", "tokio", "tower-service", @@ -492,7 +548,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -509,9 +565,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.94" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e" +checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36" [[package]] name = "lock_api" @@ -528,16 +584,16 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] name = "loom" -version = "0.3.6" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0e8460f2f2121162705187214720353c517b97bdfb3494c0b1e33d83ebe4bed" +checksum = "7aa5348dc45fa5f2419b6dd4ea20345e6b01b1fcc9d176a322eada1ac3f382ba" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", "generator", "scoped-tls", "serde", @@ -562,6 +618,16 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + [[package]] name = "mio" version = "0.7.11" @@ -586,8 +652,9 @@ dependencies = [ [[package]] name = "multer" -version = "1.2.2" -source = "git+https://github.com/rousan/multer-rs.git?rev=7e4f0c5f#7e4f0c5fe14e4c531f503922bfe04f68b32ddf17" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fdd568fea4758b30d6423f013f7171e193c34aa97828d1bd9f924fb3af30a8c" dependencies = [ "bytes", "derive_more", @@ -597,6 +664,7 @@ dependencies = [ "httparse", "log", "mime", + "spin", "tokio", "tokio-util", "twoway", @@ -645,7 +713,7 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "instant", "libc", "redox_syscall", @@ -655,9 +723,9 @@ dependencies = [ [[package]] name = "pear" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86ab3a2b792945ed67eadbbdcbd2898f8dd2319392b2a45ac21adea5245cb113" +checksum = "15e44241c5e4c868e3eaa78b7c1848cadd6344ed4f54d029832d32b415a58702" dependencies = [ "inlinable_string", "pear_codegen", @@ -666,9 +734,9 @@ dependencies = [ [[package]] name = "pear_codegen" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "620c9c4776ba41b59ab101360c9b1419c0c8c81cd2e6e39fae7109e7425994cb" +checksum = "82a5ca643c2303ecb740d506539deba189e16f2754040a42901cd8105d0282d0" dependencies = [ "proc-macro2", "proc-macro2-diagnostics", @@ -682,26 +750,6 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" -[[package]] -name = "pin-project" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7509cc106041c40a4518d2af7a61530e1eed0e6285296a3d8c5472806ccc4a4" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c950132583b500556b1efd71d45b319029f2b71518d979fcc208e16b42426f" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "pin-project-lite" version = "0.2.6" @@ -734,9 +782,9 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" dependencies = [ "unicode-xid", ] @@ -805,9 +853,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85dd92e586f7355c633911e11f77f3d12f04b1b1bd76a198bd34ae3af8341ef2" +checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc" dependencies = [ "bitflags", ] @@ -844,7 +892,7 @@ dependencies = [ [[package]] name = "rocket" version = "0.5.0-dev" -source = "git+https://github.com/SergioBenitez/Rocket?rev=3a7559edcec7c443e68e22e038aaa2d90ef27c23#3a7559edcec7c443e68e22e038aaa2d90ef27c23" +source = "git+https://github.com/SergioBenitez/Rocket?rev=7595450adc1aa3892004f02b606706597eb924e9#7595450adc1aa3892004f02b606706597eb924e9" dependencies = [ "async-stream", "async-trait", @@ -871,6 +919,7 @@ dependencies = [ "tempfile", "time", "tokio", + "tokio-stream", "tokio-util", "ubyte", "version_check", @@ -880,32 +929,22 @@ dependencies = [ [[package]] name = "rocket_codegen" version = "0.5.0-dev" -source = "git+https://github.com/SergioBenitez/Rocket?rev=3a7559edcec7c443e68e22e038aaa2d90ef27c23#3a7559edcec7c443e68e22e038aaa2d90ef27c23" +source = "git+https://github.com/SergioBenitez/Rocket?rev=7595450adc1aa3892004f02b606706597eb924e9#7595450adc1aa3892004f02b606706597eb924e9" dependencies = [ "devise", "glob", "indexmap", + "proc-macro2", "quote", "rocket_http", + "syn", "unicode-xid", ] -[[package]] -name = "rocket_contrib" -version = "0.5.0-dev" -source = "git+https://github.com/SergioBenitez/Rocket?rev=3a7559edcec7c443e68e22e038aaa2d90ef27c23#3a7559edcec7c443e68e22e038aaa2d90ef27c23" -dependencies = [ - "log", - "rocket", - "serde", - "serde_json", - "tokio", -] - [[package]] name = "rocket_http" version = "0.5.0-dev" -source = "git+https://github.com/SergioBenitez/Rocket?rev=3a7559edcec7c443e68e22e038aaa2d90ef27c23#3a7559edcec7c443e68e22e038aaa2d90ef27c23" +source = "git+https://github.com/SergioBenitez/Rocket?rev=7595450adc1aa3892004f02b606706597eb924e9#7595450adc1aa3892004f02b606706597eb924e9" dependencies = [ "cookie", "either", @@ -940,9 +979,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb5d2a036dc6d2d8fd16fde3498b04306e29bd193bf306a57427019b823d5acd" +checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088" [[package]] name = "ryu" @@ -979,18 +1018,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.125" +version = "1.0.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" +checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.125" +version = "1.0.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" +checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" dependencies = [ "proc-macro2", "quote", @@ -1016,9 +1055,9 @@ checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" [[package]] name = "signal-hook-registry" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" dependencies = [ "libc", ] @@ -1045,6 +1084,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "spin" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b87bbf98cb81332a56c1ee8929845836f85e8ddd693157c30d76660196014478" + [[package]] name = "stable-pattern" version = "0.1.0" @@ -1065,8 +1110,9 @@ dependencies = [ [[package]] name = "state" -version = "0.4.2" -source = "git+https://github.com/SergioBenitez/state.git?rev=8f94dc#8f94dce673b7d4b0e7b96c808a84f5e2a4be4a60" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b54c22963194db84a59ee48e1fa9ed6c1fa9909ad5db92a700aa6fe956d632b" dependencies = [ "loom", ] @@ -1122,9 +1168,9 @@ checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" [[package]] name = "syn" -version = "1.0.71" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad184cc9470f9117b2ac6817bfe297307418819ba40552f9b3846f05c33d5373" +checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82" dependencies = [ "proc-macro2", "quote", @@ -1137,7 +1183,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "rand", "redox_syscall", @@ -1147,18 +1193,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" +checksum = "fa6f76457f59514c7eeb4e59d891395fab0b2fd1d40723ae737d64153392e9c6" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" +checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d" dependencies = [ "proc-macro2", "quote", @@ -1220,9 +1266,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.5.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83f0c8e7c0addab50b663055baf787d0af7f413a46e6e7fb9559a4e4db7137a5" +checksum = "0a38d31d7831c6ed7aad00aa4c12d9375fd225a6dd77da1d25b707346319a975" dependencies = [ "autocfg", "bytes", @@ -1239,9 +1285,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf7b11a536f46a809a8a9f0bb4237020f70ecbf115b842360afb127ea2fda57" +checksum = "c49e3df43841dafb86046472506755d8501c5615673955f6aa17181125d13c37" dependencies = [ "proc-macro2", "quote", @@ -1249,10 +1295,36 @@ dependencies = [ ] [[package]] -name = "tokio-util" -version = "0.6.6" +name = "tokio-stream" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "940a12c99365c31ea8dd9ba04ec1be183ffe4920102bb7122c2f515437601e8e" +checksum = "f8864d706fdb3cc0843a49647ac892720dac98a6eeb818b77190592cf4994066" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-tar" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a50188549787c32c1c3d9c8c71ad7e003ccf2f102489c5a96e385c84760477f4" +dependencies = [ + "filetime", + "futures-core", + "libc", + "redox_syscall", + "tokio", + "tokio-stream", + "xattr", +] + +[[package]] +name = "tokio-util" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1caa0b0c8d94a049db56b5acf8cba99dc0623aab1b26d5b5f5e2d945846b3592" dependencies = [ "bytes", "futures-core", @@ -1283,7 +1355,7 @@ version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "pin-project-lite", "tracing-core", ] @@ -1305,9 +1377,9 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "twoway" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b40075910de3a912adbd80b5d8bad6ad10a23eeb1f5bf9d4006839e899ba5bc" +checksum = "c57ffb460d7c24cd6eda43694110189030a3d1dfe418416d9468fd1c1d290b47" dependencies = [ "memchr", "unchecked-index", @@ -1349,9 +1421,9 @@ dependencies = [ [[package]] name = "unicode-normalization" -version = "0.1.17" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" dependencies = [ "tinyvec", ] @@ -1364,9 +1436,9 @@ checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "url" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" dependencies = [ "form_urlencoded", "idna", @@ -1374,6 +1446,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", + "serde", +] + [[package]] name = "version_check" version = "0.9.3" @@ -1398,19 +1480,19 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasm-bindgen" -version = "0.2.73" +version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9" +checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.73" +version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae" +checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900" dependencies = [ "bumpalo", "lazy_static", @@ -1423,9 +1505,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.73" +version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f" +checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1433,9 +1515,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.73" +version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c" +checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97" dependencies = [ "proc-macro2", "quote", @@ -1446,9 +1528,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.73" +version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489" +checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f" [[package]] name = "winapi" @@ -1472,6 +1554,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "xattr" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" +dependencies = [ + "libc", +] + [[package]] name = "yansi" version = "0.5.0" diff --git a/Cargo.toml b/Cargo.toml index 6ad186c..854d7cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,15 +9,17 @@ edition = "2018" [dependencies] anyhow = "1.0.40" dotenv = "0.15.0" -url = "2.2.1" -thiserror = "1.0.24" +url = "2.2.2" +thiserror = "1.0.25" +uuid = { version = "0.8.2", features = ["serde", "v4"] } +tokio = "1.6.1" +async-compression = { version = "0.3.8", features = ['tokio', 'gzip'] } +tokio-util = "0.6.7" +tokio-tar = "0.3.0" +tokio-stream = "0.1.6" +serde = "1.0.126" [dependencies.rocket] git = "https://github.com/SergioBenitez/Rocket" -rev = "3a7559edcec7c443e68e22e038aaa2d90ef27c23" -version = "0.5.0-dev" - -[dependencies.rocket_contrib] -git = "https://github.com/SergioBenitez/Rocket" -rev = "3a7559edcec7c443e68e22e038aaa2d90ef27c23" +rev = "7595450adc1aa3892004f02b606706597eb924e9" version = "0.5.0-dev" diff --git a/README.md b/README.md index d4d7ac1..6c124f5 100644 --- a/README.md +++ b/README.md @@ -5,16 +5,16 @@ software forges and CI/CD services. # TODO -## Phase I -- [ ] upload /subdomain//upload -> untar -- [ ] serve for any subdomain +## [x] Phase I +- [x] upload /subdomain//upload -> untar +- [x] serve for any subdomain -## Phase II +## [ ] Phase II - [ ] store subdomains linked to each upload (which database ? sled ?) -- [ ] serve for specific subdomain (rewrite sub.pages.domain.net to pages.domain.net/sub ?) +- [x] serve for specific subdomain -## Phase III +## [ ] Phase III - [ ] config (ex: single page app, custom 404, et c) - config in static file, or in api ? (or both ?) @@ -22,7 +22,7 @@ software forges and CI/CD services. Yeah ! A minimal working service ! -## Phase IV +## [ ] Phase IV Highly hypothetical diff --git a/src/api.rs b/src/api.rs index 8220e65..83ff17d 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,19 +1,55 @@ +use std::io; + +use async_compression::tokio::bufread::GzipDecoder; use rocket::{ - data::TempFile, - post, - routes, - Route, + data::{Data, ToByteUnit}, + delete, post, routes, Route, State, }; +use tokio::io::{AsyncBufRead, AsyncRead, BufReader}; +use tokio_stream::StreamExt; +use tokio_tar::Archive; +use tokio_util::io::ReaderStream; + +use crate::Config; +use crate::Websites; pub fn routes() -> Vec { - routes![subdomain] + routes![subdomain_delete, subdomain_upload] +} + +#[delete("/subdomain/")] +pub fn subdomain_delete(subdomain: String, hosts: &State) { + println!("delete to subdomain {}", subdomain); } #[post( "/subdomain//upload", format = "application/x-gtar", - data = "" + data = "" )] -pub fn subdomain(subdomain: String, mut file: TempFile<'_>) { - println!("upload to subdomain {}", subdomain); +pub async fn subdomain_upload( + subdomain: String, + data: Data, + hosts: &State, + config: &State, +) { + // TODO: remove all unwraps. What to return ? option is easy, error can be logged + // TODO: move directory creation the Folder backend manager + let domain_path = match hosts.subdomain_path(&subdomain).unwrap() { + None => hosts.add_subdomain(&subdomain).unwrap(), + Some(path) => path, + }; + let path = config.data_dir.join(&domain_path); + println!( + "upload to subdomain {}, which is stored in path {:?}", + subdomain, path + ); + let data = data.open(5.megabytes()); + // FIXME: convert using BufReader may be slow, is it possible to obtain a more efficient + // AsyncBufRead from rocket::Data ? + let tar = GzipDecoder::new(BufReader::new(data)); + let mut archive_reader = Archive::new(tar); + + tokio::fs::create_dir_all(&path).await.unwrap(); + archive_reader.unpack(&path).await.unwrap(); } diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..0e546fc --- /dev/null +++ b/src/config.rs @@ -0,0 +1,32 @@ +use std::env; +use std::path::PathBuf; + +use rocket::figment::{ + providers::{Env, Format, Serialized, Toml}, + Figment, Profile, +}; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +#[derive(Debug, Deserialize, Serialize)] +pub struct Config { + pub data_dir: PathBuf, +} + +impl Default for Config { + fn default() -> Self { + let tmp_data_folder = PathBuf::from(format!("feuille-{}", Uuid::new_v4().to_string())); + let data_dir = env::temp_dir().join(tmp_data_folder); + Self { data_dir } + } +} + +impl Config { + pub fn figment() -> Figment { + Figment::from(rocket::Config::default()) + .merge(Serialized::defaults(Config::default())) + .merge(Toml::file("feuille.toml").nested()) + .merge(Env::prefixed("FEUILLE_").global()) + .select(Profile::from_env_or("FEUILLE_PROFILE", "default")) + } +} diff --git a/src/domain.rs b/src/domain.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/main.rs b/src/main.rs index d2199d3..14cea0a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,26 +1,25 @@ use std::env; -use std::sync::{Arc, Mutex}; use dotenv::dotenv; -use rocket::{get, launch, routes}; +use rocket::{fairing::AdHoc, launch}; use url::Host; -mod subdomains; -use subdomains::Hosts; mod api; +mod config; +use config::Config; +mod website; +use website::Websites; #[launch] fn rocket() -> _ { dotenv().ok(); - env::var("FEUILLE_DATA_DIR").expect("You have to set the FEUILLE_DATA_DIR configuration"); // TODO: replace by builder - let subdomain_hosts = - Hosts::new(Host::parse("example.com").expect("invalid host")).add_subdomain("test"); - - rocket::build() + let subdomain_hosts = Websites::new(Host::parse("example.com").expect("invalid host")); + subdomain_hosts.add_subdomain("test").unwrap(); + rocket::custom(Config::figment()) .mount("/", api::routes()) - .mount("/", subdomains::routes()) + .mount("/", website::routes()) + .attach(AdHoc::config::()) .manage(subdomain_hosts) - //.mount("/", StaticFiles::from("tmp.data/")) } diff --git a/src/subdomains.rs b/src/subdomains.rs deleted file mode 100644 index 563830e..0000000 --- a/src/subdomains.rs +++ /dev/null @@ -1,110 +0,0 @@ -use std::path::PathBuf; -use std::sync::{self, Arc, Mutex}; -use std::convert::TryInto; - -use thiserror::Error; -use url::Host; -use rocket::{get, Route, routes, State}; -use rocket::outcome::try_outcome; -use rocket::request::{FromRequest, Request, Outcome}; - -pub fn routes() -> Vec { - routes![static_website] -} - -#[derive(PartialEq, Clone, Debug, Error)] -pub enum Error { - #[error("Can't lock an underling mutex")] - Lock, - #[error("Malformed subdomain, did you put '.' in it ?")] - MalformedSubdomain, - #[error("IP host are not supported")] - IPHost, -} - -type Result = core::result::Result; - -#[derive(Debug, Clone, PartialEq)] -pub(crate) struct Website { - path: PathBuf, - host: Host, -} - -impl Website { - /// Creates a website from a given subdomain and a base_host - /// - /// # Errors - /// - /// If your subdomain contains dots, an Error::MalformedUrl is returned - /// Error::IPHost is returned if the given host is an IP - fn from_subdomain>(subdomain: S, base_host: &Host) -> Result { - // TODO: implement the path creation - let path = "".into(); - if subdomain.as_ref().contains(".") { - return Err(Error::MalformedSubdomain); - } - let host = match base_host { - Host::Domain(base_host) => format!("{}.{}", subdomain.as_ref(), base_host.to_string()), - _ => return Err(Error::IPHost), - }; - let host = Host::parse(&host).map_err(|_| Error::MalformedSubdomain)?; - Ok(Self { - path, - host, - }) - } -} - -#[derive(Debug, Clone)] -pub(crate) struct Hosts { - hosts: Arc>>, - base_host: Host, -} - -impl Hosts { - - pub fn new(base_host: Host) -> Self { - Self{ - hosts: Arc::new(Mutex::new(vec![])), - base_host, - } - } - - pub fn contains_host(&self, host: &Host) -> Result{ - match self.hosts.lock() { - Ok(hosts) => Ok(hosts.iter().any(|website| &website.host == host)), - Err(_) => Err(Error::Lock), - } - } - - pub fn add_subdomain>(&self, subdomain: S) -> Result<()> { - match &mut self.hosts.lock() { - Ok(hosts) => { - hosts.push(Website::from_subdomain(subdomain, &self.base_host)?); - Ok(()) - }, - Err(_) => Err(Error::Lock), - } - } -} - -pub struct Header<'a>(pub &'a str); - -#[rocket::async_trait] -impl<'a> FromRequest<'a> for Header<'a> { - type Error = (); - - async fn from_request(req: &'a Request<'_>) -> Outcome { - let subdomain_hosts = try_outcome!(req.guard::>().await); - match (req.headers().get_one("Host"), &subdomain_hosts) { - // TODO: those unwrap should return Outcome Errors - (Some(h), sh) if sh.contains_host(&Host::parse(h).unwrap()).unwrap() => Outcome::Success(Header(h)), - (_, _) => return Outcome::Forward(()), - } - } -} - -#[get("/")] -fn static_website(path: PathBuf, subdomain: Header) { - println!("go go go to the subdomain {} and path {:?} !", subdomain.0, path); -} diff --git a/src/website.rs b/src/website.rs new file mode 100644 index 0000000..bfb386b --- /dev/null +++ b/src/website.rs @@ -0,0 +1,203 @@ +use std::convert::TryInto; +use std::path::{Component, Path, PathBuf}; +use std::sync::{self, Arc, Mutex}; + +use rocket::{ + fs::{self, FileServer}, + get, + http::{uri::Origin, Method, Status}, + outcome::{ + try_outcome, + Outcome::{Failure, Success}, + }, + request::{FromRequest, Outcome, Request}, + response::{content, Response}, + routes, Route, State, +}; +use thiserror::Error; +use tokio::{ + fs::File, + io::{AsyncRead, AsyncReadExt}, +}; +use url::Host; +use uuid::Uuid; + +use crate::Config; + +pub fn routes() -> Vec { + routes![static_websites] +} + +/// Contains error for websites +#[derive(PartialEq, Clone, Debug, Error)] +pub enum Error { + #[error("Can't lock an underling mutex")] + Lock, + #[error("Malformed subdomain, did you put '.' in it ?")] + MalformedSubdomain, + #[error("IP host are not supported")] + IPHost, + #[error("Internal error")] + InternalError, +} + +type Result = core::result::Result; + +/// Contains information to serve files for a static website. +/// +/// A static website is identified by its host +#[derive(Debug, Clone, PartialEq)] +pub struct Website { + /// Path of storage for the website + path: PathBuf, + /// Host (domain) of the website + host: Host, +} + +fn host_from_subdomain>(subdomain: S, base_host: &Host) -> Result { + if subdomain.as_ref().contains(".") { + return Err(Error::MalformedSubdomain); + } + let host = match base_host { + Host::Domain(base_host) => format!("{}.{}", subdomain.as_ref(), base_host.to_string()), + _ => return Err(Error::IPHost), + }; + Ok(Host::parse(&host).map_err(|_| Error::MalformedSubdomain)?) +} + +impl Website { + /// Creates a website from a given subdomain and a base_host + /// + /// # Errors + /// + /// If your subdomain contains dots, an Error::MalformedUrl is returned + /// Error::IPHost is returned if the given host is an IP + fn from_subdomain>(subdomain: S, base_host: &Host) -> Result { + // TODO: implement the path creation + let path = Uuid::new_v4(); + let path = path.to_string().into(); + let host = host_from_subdomain(subdomain, base_host)?; + Ok(Self { path, host }) + } + + /// Returns the file for a path if the file exists, and None if there is no file found + async fn file

(&self, path: P, config: &Config) -> Option + where + P: AsRef, + { + let complete_path = config.data_dir.join(self.path.join(path.as_ref())); + let complete_path = match complete_path.is_dir() { + // TODO: add better sanitization + _ if complete_path.to_str().unwrap_or_default().contains("..") => None, + true => Some(complete_path.join(Path::new("index.html"))), + false => Some(complete_path), + }; + match complete_path { + None => None, + Some(path) => File::open(path).await.ok(), + } + } +} + +#[derive(Debug, Clone)] +pub struct Websites { + hosts: Arc>>, + // TODO: Move to domain.rs + base_host: Host, +} + +impl Websites { + pub fn new(base_host: Host) -> Self { + Self { + hosts: Arc::new(Mutex::new(vec![])), + base_host, + } + } + + /// Returns the website indentified by the host + /// + /// # Errors + /// + /// If the data can't be accessed, returns Error::Lock + pub fn website(&self, host: &Host) -> Result> { + match self.hosts.lock() { + Ok(hosts) => Ok(hosts + .iter() + .find(|website| &website.host == host) + .map(Clone::clone)), + Err(_) => Err(Error::Lock), + } + } + + /// Returns the path containing the data of the the host if the host exists, + /// Returns None if the subdomain is unknown + /// + /// # Errors + /// + /// If the data can't be accessed, returns Error::Lock + pub fn host_path(&self, host: &Host) -> Result> { + Ok(self.website(host)?.map(|w| w.path)) + } + + /// Returns the path containing the data of the the subdomain if the subdomain exists, + /// Returns None if the subdomain is unknown + /// + /// # Errors + /// + /// If the data can't be accessed, returns Error::Lock + pub fn subdomain_path>(&self, subdomain: S) -> Result> { + self.host_path(&host_from_subdomain(subdomain, &self.base_host)?) + } + + /// Adds a subdomain to the list of hosts + /// + /// Returns the PathBuf + pub fn add_subdomain>(&self, subdomain: S) -> Result { + match &mut self.hosts.lock() { + Ok(hosts) => { + hosts.push(Website::from_subdomain(&subdomain, &self.base_host)?); + Ok(()) + } + Err(_) => Err(Error::Lock), + }?; + Ok(self + .subdomain_path(&subdomain)? + .ok_or(Error::InternalError)?) + } +} + +#[rocket::async_trait] +impl<'a> FromRequest<'a> for Website { + type Error = (); + + async fn from_request(req: &'a Request<'_>) -> Outcome { + let subdomain_hosts = try_outcome!(req.guard::<&State>().await); + match (req.headers().get_one("Host"), &subdomain_hosts) { + // TODO: those unwrap should return Outcome Errors + (Some(h), sh) => match sh.website(&Host::parse(h).unwrap()).unwrap() { + None => Outcome::Forward(()), + Some(website) => Outcome::Success(website), + }, + (_, _) => Outcome::Forward(()), + } + } +} + +#[get("/")] +async fn static_websites( + path: PathBuf, + website: Website, + config: &State, +) -> Option> { + // TODO: serve any file, change output format + // TODO: switch to custom error to enhance error logging + let mut buffer = Vec::new(); + let mut file = match website.file(&path, &config).await { + None => return None, + Some(f) => f, + }; + match file.read_to_end(&mut buffer).await.ok() { + None => None, + Some(_) => String::from_utf8(buffer).ok().map(content::Html), + } +}