diff --git a/.gitignore b/.gitignore index ce7477a..94d4de4 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ graph.bin nodes*.json nodes*.json.br +.env # Logs logs diff --git a/Cargo.lock b/Cargo.lock index 623b287..1bf4ed9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -67,9 +67,9 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.72" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17c6a35df3749d2e8bb1b7b21a976d82b15548788d2735b9d82f329268f71a11" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ "addr2line", "cc", @@ -109,15 +109,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cc" -version = "1.0.99" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" +checksum = "e9e8aabfac534be767c909e0690571677d49f41bd8465ae876fe043d52ba5292" [[package]] name = "cfg-if" @@ -136,7 +136,7 @@ dependencies = [ "js-sys", "num-traits", "wasm-bindgen", - "windows-targets 0.52.5", + "windows-targets", ] [[package]] @@ -150,15 +150,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" dependencies = [ "libc", ] @@ -195,9 +195,9 @@ dependencies = [ [[package]] name = "either" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "equivalent" @@ -217,6 +217,7 @@ dependencies = [ "memmap2", "serde", "serde_derive", + "thiserror", "tokio", "warp", ] @@ -479,9 +480,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "httpdate" @@ -491,9 +492,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.29" +version = "0.14.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33" +checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" dependencies = [ "bytes", "futures-channel", @@ -538,9 +539,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" dependencies = [ "equivalent", "hashbrown", @@ -563,18 +564,18 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" @@ -590,15 +591,15 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" @@ -617,9 +618,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "mime_guess" -version = "2.0.4" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" dependencies = [ "mime", "unicase", @@ -627,22 +628,23 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.11" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ + "hermit-abi", "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -655,21 +657,11 @@ dependencies = [ "libm", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "object" -version = "0.35.0" +version = "0.36.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" +checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" dependencies = [ "memchr", ] @@ -720,9 +712,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "proc-macro2" -version = "1.0.85" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -779,18 +771,18 @@ checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] name = "serde" -version = "1.0.203" +version = "1.0.207" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "5665e14a49a4ea1b91029ba7d3bca9f299e1f7cfa194388ccc20f14743e784f2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.207" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "6aea2634c86b0e8ef2cfdc0c340baede54ec27b1e46febd7f80dffb2aa44a00e" dependencies = [ "proc-macro2", "quote", @@ -799,11 +791,12 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.124" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "66ad62847a56b3dba58cc891acd13884b9c61138d330c0d7b6181713d4fce38d" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -862,14 +855,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] name = "spade" -version = "2.8.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b20a809169ae442497e41a997fc5f14e2eea04e6ac590816a910d5d8068c8c0" +checksum = "9bd14cf9e23b5241e1b1289ed3b9afc7746c95ead8df52d9254f5ed2d40c561b" dependencies = [ "hashbrown", "num-traits", @@ -885,9 +878,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "syn" -version = "2.0.66" +version = "2.0.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7" dependencies = [ "proc-macro2", "quote", @@ -896,18 +889,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", @@ -916,27 +909,26 @@ dependencies = [ [[package]] name = "tokio" -version = "1.38.0" +version = "1.39.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] name = "tokio-macros" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", @@ -958,9 +950,9 @@ dependencies = [ [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -1011,9 +1003,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "want" @@ -1059,19 +1051,20 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", @@ -1084,9 +1077,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1094,9 +1087,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", @@ -1107,9 +1100,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "windows-core" @@ -1117,16 +1110,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.5", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", + "windows-targets", ] [[package]] @@ -1135,144 +1119,87 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "zerocopy" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", diff --git a/api.Dockerfile b/Dockerfile similarity index 52% rename from api.Dockerfile rename to Dockerfile index 5fdc614..44a5d44 100644 --- a/api.Dockerfile +++ b/Dockerfile @@ -1,4 +1,9 @@ -FROM rust:1.78-bookworm as build +FROM node:20-alpine as ui-build +COPY . /app +WORKDIR /app/fastreach-ui +RUN npm install && npm run build + +FROM rust:1.80-bookworm as build WORKDIR /app COPY . /app ENV RUSTFLAGS="-C target-cpu=native" @@ -6,7 +11,9 @@ RUN cargo build --release FROM gcr.io/distroless/cc-debian12:nonroot COPY --from=build /app/target/release/fastreach-api / +COPY --from=ui-build /app/fastreach-ui/dist /usr/share/fastreach ENV FASTREACH_GRAPH=/data/graph.bin +ENV FASTREACH_STATIC=/usr/share/fastreach EXPOSE 8080 STOPSIGNAL SIGINT CMD ["/fastreach-api"] diff --git a/README.md b/README.md index b7e6813..2ff89d4 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ npm run dev ``` within the fastreach-ui folder. The `nodes.json` file generated by [netex-parse](https://github.com/Nuckal777/netex-parse) should be placed in the same folder. -Additionally, a `docker-compose.yaml` is available. +Additionally, a `docker-compose.yaml` with labels for [traefik](https://doc.traefik.io/traefik/) is available. ## How it works Fastreach models the transportation network as a graph. diff --git a/docker-compose.yaml b/docker-compose.yaml index 768fb41..28d4ef2 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,21 +1,29 @@ -version: "3.3" +version: "3.6" services: - ui: - build: - context: . - dockerfile: ui.Dockerfile - ports: - # Host:Container - - "443:443" - volumes: - - ./Caddyfile:/etc/caddy/Caddyfile - - ./fastreach-ui/nodes-v1.json:/usr/share/caddy/nodes-v1.json - - ./fastreach-ui/nodes-v1.json.br:/usr/share/caddy/nodes-v1.json.br - restart: on-failure server: build: context: . - dockerfile: api.Dockerfile + read_only: true + labels: + - traefik.enable=true + + - traefik.http.middlewares.fr-compression.compress=true + - traefik.http.middlewares.fr-ratelimit.ratelimit.period=1m + - traefik.http.middlewares.fr-ratelimit.ratelimit.average=10 + - traefik.http.middlewares.fr-ratelimit.ratelimit.burst=20 + + - traefik.http.routers.static.rule=Host(`${HOSTNAME}`) + - traefik.http.routers.static.tls=true + - traefik.http.routers.static.middlewares=fr-compression + + - traefik.http.routers.api.rule=Host(`${HOSTNAME}`) && PathPrefix(`/api`) + - traefik.http.routers.api.tls=true + - traefik.http.routers.api.middlewares=fr-ratelimit volumes: + - ./fastreach-ui/nodes-v1.json:/usr/share/fastreach/nodes-v1.json + - ./fastreach-ui/nodes-v1.json.br:/usr/share/fastreach/nodes-v1.json.br - ./graph.bin:/data/graph.bin - restart: on-failure + environment: + - TOKIO_WORKER_THREADS=3 + - FASTREACH_PARALLEL=2 + restart: unless-stopped diff --git a/fastreach-api/Cargo.toml b/fastreach-api/Cargo.toml index c532f93..acb45a7 100644 --- a/fastreach-api/Cargo.toml +++ b/fastreach-api/Cargo.toml @@ -14,5 +14,6 @@ lazy_static = "1.4" memmap2 = "0.9" serde = "1" serde_derive = "1" +thiserror = "1.0" tokio = { version = "1", features = ["macros", "signal", "rt-multi-thread"] } warp = { version = "0.3", default-features = false } diff --git a/fastreach-api/src/filters.rs b/fastreach-api/src/filters.rs new file mode 100644 index 0000000..a46f464 --- /dev/null +++ b/fastreach-api/src/filters.rs @@ -0,0 +1,37 @@ +use warp::{reply, Filter}; + +fn precompressed_br( + base_path: &str, + file: &str, +) -> impl Filter + Clone { + let with_br = file.to_owned() + ".br"; + let prefix = warp::get() + .and(warp::path(file.to_owned())) + .and(warp::path::end()); + let brotli = prefix + .clone() + .and(warp::filters::header::header::("accept-encoding")) + .and_then(|encoding: String| async move { + for chunk in encoding.split(',') { + if chunk.trim() == "br" { + return Ok(()); + } + } + Err(warp::reject()) + }) + .untuple_one() + .and( + warp::filters::fs::file(std::path::PathBuf::from(base_path).join(with_br)) + .with(reply::with::header("content-encoding", "br")), + ); + let uncompressed = prefix.and(warp::filters::fs::file( + std::path::PathBuf::from(base_path).join(file), + )); + brotli.or(uncompressed) +} + +pub(crate) fn static_content( + base_path: String, +) -> impl Filter + Clone { + precompressed_br(&base_path, "nodes-v1.json").or(warp::filters::fs::dir(base_path)) +} diff --git a/fastreach-api/src/main.rs b/fastreach-api/src/main.rs index b3cfeb1..dbf8381 100644 --- a/fastreach-api/src/main.rs +++ b/fastreach-api/src/main.rs @@ -8,10 +8,15 @@ use fastreach_core::{ use geo::{ChamberlainDuquetteArea, Polygon}; use lazy_static::lazy_static; use memmap2::Mmap; -use warp::Filter; +use thiserror::Error; +use warp::{http::StatusCode, reply, Filter}; + +mod filters; -const MAX_MINUTES_DEFAULT: i64 = 120; const GRAPH_DEFAULT: &str = "graph.bin"; +const STATIC_DEFAULT: &str = "static"; +const MAX_MINUTES_DEFAULT: i64 = 120; +const PARALLEL_DEFAULT: usize = 2; lazy_static! { static ref GRAPH_DATA: Mmap = { @@ -36,65 +41,91 @@ struct IsochroneReply { geometry: geojson::GeoJson, } +#[derive(Error, Debug)] +pub enum HandlerError { + #[error("{0}")] + BadRequest(String), + #[error("{0}")] + InternalServerError(String), +} + +struct IsochroneHandler<'a> { + graph: Graph<'a>, + max_minutes: i64, +} + +impl<'a> IsochroneHandler<'a> { + fn handle_isochrone(&self, body: &IsochroneBody) -> Result { + if body.minutes < 0 || body.minutes > self.max_minutes { + return Err(HandlerError::BadRequest("minutes out of range".to_owned())); + } + let id = str::parse::(&body.id) + .map_err(|_| HandlerError::BadRequest("cannot parse id".to_owned()))?; + let start_idx = self + .graph + .ids + .get(&id) + .ok_or(HandlerError::BadRequest("station not found".to_owned()))?; + let start_time = NaiveDateTime::from_timestamp_millis(body.start) + .ok_or(HandlerError::BadRequest("invalid start time".to_owned()))?; + let mut algo = IsochroneDijsktra::new(&self.graph); + let reached = algo + .nodes_within(*start_idx, start_time, Duration::minutes(body.minutes)) + .map_err(|_| HandlerError::InternalServerError("failed dijsktra".to_owned()))?; + + let polys: Vec> = reached.into_iter().map(|n| n.to_poly()).collect(); + let merged = cascade::union_polys(polys); + + Ok(IsochroneReply { + area: merged.chamberlain_duquette_unsigned_area() / 1_000_000.0, + diameter: cascade::diameter(&merged) / 1000.0, + geometry: geojson::GeoJson::from(&merged), + }) + } +} + #[tokio::main] async fn main() { let max_minutes = match std::env::var("FASTREACH_MAX_MINUTES") { Ok(val) => str::parse(&val).unwrap_or(MAX_MINUTES_DEFAULT), Err(_) => MAX_MINUTES_DEFAULT, }; - let graph = Arc::new(Graph::from_slice(&GRAPH_DATA).expect("failed to parse graph")); + let parallel = match std::env::var("FASTREACH_PARALLEL") { + Ok(val) => str::parse(&val).unwrap_or(PARALLEL_DEFAULT), + Err(_) => PARALLEL_DEFAULT, + }; + let static_path = + std::env::var("FASTREACH_STATIC").unwrap_or_else(|_| STATIC_DEFAULT.to_owned()); + + let graph = Graph::from_slice(&GRAPH_DATA).expect("failed to parse graph"); let node_count = graph.nodes.len(); - let handler = warp::post() + let semaphore = Arc::new(tokio::sync::Semaphore::new(parallel)); + let iso_handler = Arc::new(IsochroneHandler { graph, max_minutes }); + let api = warp::post() .and(warp::path!("api" / "v1" / "isochrone")) .and(warp::body::json::()) - .map(move |body: IsochroneBody| { - if body.minutes < 0 || body.minutes > max_minutes { - return warp::reply::with_status( - warp::reply::json(&"minutes out of range".to_owned()), - warp::http::StatusCode::BAD_REQUEST, - ); + .then(move |body: IsochroneBody| { + let local_handler = iso_handler.clone(); + let local_semaphore = semaphore.clone(); + async move { + let _permit = local_semaphore + .acquire() + .await + .expect("semaphore closed unexpectedly"); + match local_handler.handle_isochrone(&body) { + Ok(reply) => reply::with_status(reply::json(&reply), StatusCode::OK), + Err(HandlerError::BadRequest(msg)) => { + reply::with_status(reply::json(&msg), StatusCode::BAD_REQUEST) + } + Err(HandlerError::InternalServerError(msg)) => { + reply::with_status(reply::json(&msg), StatusCode::INTERNAL_SERVER_ERROR) + } + } } - let Ok(id) = str::parse::(&body.id) else { - return warp::reply::with_status( - warp::reply::json(&"cannot parse id".to_owned()), - warp::http::StatusCode::BAD_REQUEST, - ); - }; - let Some(start_idx) = graph.ids.get(&id) else { - return warp::reply::with_status( - warp::reply::json(&"station not found".to_owned()), - warp::http::StatusCode::BAD_REQUEST, - ); - }; - let Some(start_time) = NaiveDateTime::from_timestamp_millis(body.start) else { - return warp::reply::with_status( - warp::reply::json(&"invalid start time".to_owned()), - warp::http::StatusCode::BAD_REQUEST, - ); - }; - let mut algo = IsochroneDijsktra::new(&graph); - let Ok(reached) = - algo.nodes_within(*start_idx, start_time, Duration::minutes(body.minutes)) - else { - return warp::reply::with_status( - warp::reply::json(&"failed dijsktra".to_owned()), - warp::http::StatusCode::INTERNAL_SERVER_ERROR, - ); - }; - - let polys: Vec> = reached.into_iter().map(|n| n.to_poly()).collect(); - let merged = cascade::union_polys(polys); - - let iso_reply = IsochroneReply { - area: merged.chamberlain_duquette_unsigned_area() / 1_000_000.0, - diameter: cascade::diameter(&merged) / 1000.0, - geometry: geojson::GeoJson::from(&merged), - }; - warp::reply::with_status(warp::reply::json(&iso_reply), warp::http::StatusCode::OK) }); - let (_addr, serve) = - warp::serve(handler).bind_with_graceful_shutdown(([0, 0, 0, 0], 8080), async move { + let (_addr, serve) = warp::serve(api.or(filters::static_content(static_path))) + .bind_with_graceful_shutdown(([0, 0, 0, 0], 8080), async move { tokio::signal::ctrl_c() .await .expect("failed to listen to shutdown signal"); diff --git a/ui.Dockerfile b/ui.Dockerfile deleted file mode 100644 index 23145b9..0000000 --- a/ui.Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM node:18-alpine as ui-build -WORKDIR /app/fastreach-ui -COPY . /app -RUN npm install && npm run build - -FROM caddy:2.8-builder-alpine AS caddy-build -RUN xcaddy build --with github.com/RussellLuo/caddy-ext/ratelimit - -FROM caddy:2.8-alpine -COPY --from=caddy-build /usr/bin/caddy /usr/bin/caddy -COPY --from=ui-build /app/fastreach-ui/dist /usr/share/caddy -RUN addgroup -g 4200 nonroot && adduser -h /home/nonroot -s /sbin/nologin -G nonroot -D -u 4200 nonroot && chown -R nonroot /data/caddy -USER 4200:4200