diff --git a/.env.example b/.env.example index 7b91545b..dc28a059 100644 --- a/.env.example +++ b/.env.example @@ -1,18 +1,17 @@ -# the address of the simulator backend, found in crates/simulator -SIMULATOR_BACKEND_ADDRESS=localhost:8000 +LIVE_ADDRESS=localhost:4000 +API_ADDRESS=localhost:4001 +ANALYTICS_ADDRESS=localhost:4002 -# the address of the api backend, found in crates/api -API_BACKEND_ADDRESS=localhost:4001 - -# the address of the live backend, found in crates/live -LIVE_BACKEND_ADDRESS=localhost:4000 - -# the origin of the frontend, found in dash/ ORIGIN=http://localhost:3000 -# by setting WS_URL you are telling the live backend to connect to this address +# by setting WS_URL you are telling the live backend to connect to this address # (preferably from the simualtor) and not to the f1 address # WS_URL=ws://localhost:8000/ws +SIMULATOR_ADDRESS=localhost:8000 + # sets the rust log level, used by all packages (live, api, simulator, saver) RUST_LOG="live=debug,info" + +# timescale database used by importer and analytics +DATABASE_URL= diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 2bd8efef..3ec50294 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -19,7 +19,14 @@ jobs: strategy: matrix: - image: [f1-dash, f1-dash-api, f1-dash-live] + image: + [ + f1-dash, + f1-dash-api, + f1-dash-live, + f1-dash-importer, + f1-dash-analytics, + ] permissions: contents: read diff --git a/Cargo.lock b/Cargo.lock index 5722275b..badecd69 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,14 +19,14 @@ checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "ahash" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", "once_cell", "version_check", - "zerocopy 0.7.35", + "zerocopy", ] [[package]] @@ -44,6 +44,23 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +[[package]] +name = "analytics" +version = "0.3.0" +dependencies = [ + "anyhow", + "axum", + "dotenvy", + "serde", + "serde_json", + "sqlx", + "timescale", + "tokio", + "tower-http", + "tracing", + "tracing-subscriber", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -73,13 +90,14 @@ dependencies = [ "axum", "cached", "chrono", - "env", + "dotenvy", "ical", "regex", "reqwest", "serde", "serde_json", "tokio", + "tower-http", "tracing", "tracing-subscriber", ] @@ -95,6 +113,15 @@ dependencies = [ "syn", ] +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -109,9 +136,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "axum" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de45108900e1f9b9242f7f2e254aa3e2c029c921c258fe9e6b4217eeebd54288" +checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5" dependencies = [ "axum-core", "base64", @@ -166,9 +193,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.74" +version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ "addr2line", "cfg-if", @@ -185,6 +212,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" + [[package]] name = "bitflags" version = "1.3.2" @@ -193,9 +226,12 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +dependencies = [ + "serde", +] [[package]] name = "block-buffer" @@ -266,9 +302,9 @@ checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0" [[package]] name = "cc" -version = "1.2.19" +version = "1.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" +checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951" dependencies = [ "shlex", ] @@ -281,9 +317,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", @@ -309,6 +345,21 @@ dependencies = [ "tracing", ] +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "core-foundation" version = "0.9.4" @@ -334,6 +385,21 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + [[package]] name = "crc32fast" version = "1.4.2" @@ -352,6 +418,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -419,6 +494,17 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + [[package]] name = "digest" version = "0.10.7" @@ -426,7 +512,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", + "subtle", ] [[package]] @@ -468,19 +556,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" [[package]] -name = "encoding_rs" -version = "0.8.35" +name = "either" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" dependencies = [ - "cfg-if", + "serde", ] [[package]] -name = "env" -version = "0.1.0" +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ - "dotenvy", + "cfg-if", ] [[package]] @@ -491,14 +581,36 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" dependencies = [ "libc", "windows-sys 0.59.0", ] +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] + +[[package]] +name = "event-listener" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + [[package]] name = "fastrand" version = "2.3.0" @@ -515,12 +627,29 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "futures-core", + "futures-sink", + "spin", +] + [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "foreign-types" version = "0.3.2" @@ -597,6 +726,17 @@ dependencies = [ "futures-util", ] +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot 0.12.4", +] + [[package]] name = "futures-io" version = "0.3.31" @@ -665,9 +805,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", @@ -676,9 +816,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", @@ -694,9 +834,9 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "h2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633" +checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" dependencies = [ "atomic-waker", "bytes", @@ -723,9 +863,23 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.3", +] [[package]] name = "heck" @@ -733,6 +887,39 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "http" version = "1.3.1" @@ -802,11 +989,10 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.5" +version = "0.27.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +checksum = "03a01595e11bdcec50946522c32dde3fc6914743000a68b93000965f2f02406d" dependencies = [ - "futures-util", "http", "hyper", "hyper-util", @@ -835,22 +1021,28 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.11" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" +checksum = "b1c293b6b3d21eca78250dc7dbebd6b9210ec5530e038cbfe0661b5c47ab06e8" dependencies = [ + "base64", "bytes", "futures-channel", + "futures-core", "futures-util", "http", "http-body", "hyper", + "ipnet", "libc", + "percent-encoding", "pin-project-lite", "socket2", + "system-configuration", "tokio", "tower-service", "tracing", + "windows-registry", ] [[package]] @@ -888,21 +1080,22 @@ dependencies = [ [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", + "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_locale_core" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ "displaydoc", "litemap", @@ -911,31 +1104,11 @@ dependencies = [ "zerovec", ] -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" - [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ "displaydoc", "icu_collections", @@ -943,67 +1116,54 @@ dependencies = [ "icu_properties", "icu_provider", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" dependencies = [ "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr", + "potential_utf", + "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" [[package]] name = "icu_provider" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ "displaydoc", - "icu_locid", - "icu_provider_macros", + "icu_locale_core", "stable_deref_trait", "tinystr", "writeable", "yoke", "zerofrom", + "zerotrie", "zerovec", ] -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "ident_case" version = "1.0.1" @@ -1023,14 +1183,31 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", ] +[[package]] +name = "importer" +version = "0.3.0" +dependencies = [ + "anyhow", + "client", + "dotenvy", + "serde", + "serde_json", + "sqlx", + "timescale", + "tokio", + "tokio-stream", + "tracing", + "tracing-subscriber", +] + [[package]] name = "indexmap" version = "2.9.0" @@ -1038,7 +1215,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown 0.15.3", ] [[package]] @@ -1056,6 +1233,16 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "itoa" version = "1.0.15" @@ -1077,6 +1264,9 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] name = "libc" @@ -1084,16 +1274,32 @@ version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + [[package]] name = "libredox" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "libc", ] +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.9.4" @@ -1102,9 +1308,9 @@ checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "litemap" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "live" @@ -1112,21 +1318,15 @@ version = "0.3.0" dependencies = [ "anyhow", "axum", - "base64", "client", "data", "dotenvy", - "env", - "flate2", "futures", - "heck", - "regex", "reqwest", "serde", "serde_json", "tokio", "tokio-stream", - "tokio-tungstenite", "tower-http", "tracing", "tracing-subscriber", @@ -1134,9 +1334,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -1163,6 +1363,16 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + [[package]] name = "memchr" version = "2.7.4" @@ -1186,13 +1396,13 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1223,36 +1433,74 @@ dependencies = [ ] [[package]] -name = "num-traits" -version = "0.2.19" +name = "num-bigint-dig" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" dependencies = [ - "autocfg", + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "smallvec", + "zeroize", ] [[package]] -name = "object" -version = "0.36.7" +name = "num-integer" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "memchr", + "num-traits", ] [[package]] -name = "once_cell" -version = "1.21.3" +name = "num-iter" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "openssl" -version = "0.10.72" +version = "0.10.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "cfg-if", "foreign-types", "libc", @@ -1280,9 +1528,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.107" +version = "0.9.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" dependencies = [ "cc", "libc", @@ -1302,6 +1550,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + [[package]] name = "parking_lot" version = "0.11.2" @@ -1315,12 +1569,12 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", - "parking_lot_core 0.9.10", + "parking_lot_core 0.9.11", ] [[package]] @@ -1339,13 +1593,13 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.11", + "redox_syscall 0.5.12", "smallvec", "windows-targets 0.52.6", ] @@ -1356,6 +1610,15 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -1374,19 +1637,49 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + [[package]] name = "ppv-lite86" version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.8.24", + "zerocopy", ] [[package]] @@ -1413,14 +1706,35 @@ version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + [[package]] name = "rand" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ - "rand_chacha", - "rand_core", + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", ] [[package]] @@ -1430,7 +1744,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", ] [[package]] @@ -1439,7 +1762,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", ] [[package]] @@ -1453,11 +1776,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", ] [[package]] @@ -1466,7 +1789,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "libredox", "thiserror 2.0.12", ] @@ -1517,15 +1840,14 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.15" +version = "0.12.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" +checksum = "e98ff6b0dbbe4d5a37318f433d4fc82babd21631f194d370409ceb2e40b2f0b5" dependencies = [ "base64", "bytes", "encoding_rs", "futures-core", - "futures-util", "h2", "http", "http-body", @@ -1542,21 +1864,20 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", - "system-configuration", "tokio", "tokio-native-tls", "tower", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "windows-registry", ] [[package]] @@ -1567,7 +1888,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.16", "libc", "untrusted", "windows-sys 0.52.0", @@ -1595,6 +1916,26 @@ dependencies = [ "serde", ] +[[package]] +name = "rsa" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -1603,11 +1944,11 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustix" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "errno", "libc", "linux-raw-sys", @@ -1616,9 +1957,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.26" +version = "0.23.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0" +checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" dependencies = [ "once_cell", "rustls-pki-types", @@ -1628,25 +1969,19 @@ dependencies = [ ] [[package]] -name = "rustls-pemfile" -version = "2.2.0" +name = "rustls-pki-types" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" dependencies = [ - "rustls-pki-types", + "zeroize", ] -[[package]] -name = "rustls-pki-types" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" - [[package]] name = "rustls-webpki" -version = "0.103.1" +version = "0.103.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" +checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" dependencies = [ "ring", "rustls-pki-types", @@ -1655,9 +1990,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] name = "ryu" @@ -1697,7 +2032,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "core-foundation", "core-foundation-sys", "libc", @@ -1779,6 +2114,17 @@ dependencies = [ "digest", ] +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -1803,6 +2149,16 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + [[package]] name = "simulator" version = "0.2.1" @@ -1844,23 +2200,248 @@ name = "smallvec" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +dependencies = [ + "serde", +] [[package]] name = "socket2" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlx" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" +dependencies = [ + "base64", + "bytes", + "chrono", + "crc", + "crossbeam-queue", + "either", + "event-listener", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.15.3", + "hashlink", + "indexmap", + "log", + "memchr", + "once_cell", + "percent-encoding", + "serde", + "serde_json", + "sha2", + "smallvec", + "thiserror 2.0.12", + "tokio", + "tokio-stream", + "tracing", + "url", +] + +[[package]] +name = "sqlx-macros" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b" +dependencies = [ + "dotenvy", + "either", + "heck", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" +dependencies = [ + "atoi", + "base64", + "bitflags 2.9.1", + "byteorder", + "bytes", + "chrono", + "crc", + "digest", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "percent-encoding", + "rand 0.8.5", + "rsa", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.12", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" +dependencies = [ + "atoi", + "base64", + "bitflags 2.9.1", + "byteorder", + "chrono", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand 0.8.5", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.12", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" +dependencies = [ + "atoi", + "chrono", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "serde_urlencoded", + "sqlx-core", + "thiserror 2.0.12", + "tracing", + "url", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + [[package]] name = "strsim" version = "0.11.1" @@ -1875,9 +2456,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.100" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", @@ -1895,9 +2476,9 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", @@ -1910,7 +2491,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "core-foundation", "system-configuration-sys", ] @@ -1927,12 +2508,12 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.19.1" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ "fastrand", - "getrandom 0.3.2", + "getrandom 0.3.3", "once_cell", "rustix", "windows-sys 0.59.0", @@ -1988,31 +2569,60 @@ dependencies = [ "once_cell", ] +[[package]] +name = "timescale" +version = "0.3.0" +dependencies = [ + "anyhow", + "chrono", + "serde", + "serde_json", + "sqlx", + "tokio", + "tracing", +] + [[package]] name = "tinystr" -version = "0.7.6" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", "zerovec", ] +[[package]] +name = "tinyvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" -version = "1.44.2" +version = "1.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" +checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" dependencies = [ "backtrace", "bytes", "libc", "mio", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", + "tracing", "windows-sys 0.52.0", ] @@ -2075,9 +2685,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.14" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" dependencies = [ "bytes", "futures-core", @@ -2104,14 +2714,18 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.2" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403fa3b783d4b626a8ad51d766ab03cb6d2dbfc46b1c5d4448395e6628dc9697" +checksum = "0fdb0c213ca27a9f57ab69ddb290fd80d970922355b83ae380b395d3986b8a2e" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "bytes", + "futures-util", "http", + "http-body", + "iri-string", "pin-project-lite", + "tower", "tower-layer", "tower-service", ] @@ -2208,7 +2822,7 @@ dependencies = [ "httparse", "log", "native-tls", - "rand", + "rand 0.9.1", "sha1", "thiserror 2.0.12", "url", @@ -2221,12 +2835,33 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + [[package]] name = "unicode-ident" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +[[package]] +name = "unicode-normalization" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" + [[package]] name = "untrusted" version = "0.9.0" @@ -2250,12 +2885,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -2304,6 +2933,12 @@ dependencies = [ "wit-bindgen-rt", ] +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + [[package]] name = "wasm-bindgen" version = "0.2.100" @@ -2395,6 +3030,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "whoami" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6994d13118ab492c3c80c1f81928718159254c53c472bf9ce36f8dae4add02a7" +dependencies = [ + "redox_syscall 0.5.12", + "wasite", +] + [[package]] name = "winapi" version = "0.3.9" @@ -2419,15 +3064,15 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.61.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ "windows-implement", "windows-interface", "windows-link", "windows-result", - "windows-strings 0.4.0", + "windows-strings 0.4.2", ] [[package]] @@ -2471,9 +3116,9 @@ dependencies = [ [[package]] name = "windows-result" -version = "0.3.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ "windows-link", ] @@ -2489,13 +3134,22 @@ dependencies = [ [[package]] name = "windows-strings" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ "windows-link", ] +[[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", +] + [[package]] name = "windows-sys" version = "0.52.0" @@ -2514,6 +3168,21 @@ dependencies = [ "windows-targets 0.52.6", ] +[[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", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -2546,6 +3215,12 @@ dependencies = [ "windows_x86_64_msvc 0.53.0", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -2558,6 +3233,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -2570,6 +3251,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -2594,6 +3281,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -2606,6 +3299,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +[[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.6" @@ -2618,6 +3317,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -2630,6 +3335,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -2648,26 +3359,20 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", ] -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "yoke" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" dependencies = [ "serde", "stable_deref_trait", @@ -2677,9 +3382,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", @@ -2689,38 +3394,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "zerocopy-derive 0.7.35", -] - -[[package]] -name = "zerocopy" -version = "0.8.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" -dependencies = [ - "zerocopy-derive 0.8.24", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ - "proc-macro2", - "quote", - "syn", + "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", @@ -2754,11 +3439,22 @@ version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + [[package]] name = "zerovec" -version = "0.10.4" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" dependencies = [ "yoke", "zerofrom", @@ -2767,9 +3463,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 7ae43aef..a06d98f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,30 +1,43 @@ [workspace] members = [ - "crates/data", # lib - "crates/client", # lib - "crates/env", # lib - "crates/api", # bin - "crates/live", # bin - "crates/saver", # bin - "crates/simulator", # bin + "crates/data", # lib + "crates/client", # lib + "crates/timescale", # lib + "services/api", # bin - service + "services/live", # bin - service + "services/analytics", # bin - service + "services/importer", # bin - service + "crates/saver", # bin - util + "crates/simulator", # bin - util +] +default-members = [ + "services/live", + "services/api", + "services/analytics", + "services/importer", ] -default-members = ["crates/live", "crates/api"] resolver = "2" [workspace.dependencies] data = { path = "crates/data" } client = { path = "crates/client" } -env = { path = "crates/env" } +timescale = { path = "crates/timescale" } + -tokio = { version = "1.44.2", features = ["full"] } +tokio = { version = "1.44.2", features = ["full", "tracing"] } tokio-stream = { version = "0.1.15", features = ["full"] } + tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } +sqlx = { version = "0.8.6", features = ["postgres", "runtime-tokio", "chrono"] } + axum = { version = "0.8.3", features = ["http2"] } -tower-http = { version = "0.6.2", features = ["cors"] } +tower-http = { version = "0.6.4", features = ["cors"] } + tokio-tungstenite = { version = "0.26.2", features = ["native-tls", "url"] } -reqwest = { version = "0.12.15", features = ["native-tls"] } +reqwest = { version = "0.12.18", features = ["native-tls"] } + serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", features = ["raw_value"] } diff --git a/DOCKER.md b/DOCKER.md index a837c901..b44acf70 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -1,8 +1,10 @@ # Docker and Docker Compose -## Environment Variables +> [!NOTE] +> The docker compose is not meant as a production deployment rather a tool to setup f1-dash locally for testing or development. +> If you want to deploy f1-dash, it can be used as a base but -To substitute the environment variables in [`compose.yaml`](compose.yaml), use the `--env-file` flag as follows: +To substitute the environment variables in compose.yaml, use `--env-file` flag as follows: ```bash docker compose --env-file ./compose.env up @@ -20,4 +22,4 @@ environment: - API_BACKEND_ADDRESS=${API_BACKEND_ADDRESS} - RUST_LOG=${RUST_LOG} - RUST_BACKTRACE=${RUST_BACKTRACE} -``` \ No newline at end of file +``` diff --git a/compose.yaml b/compose.yaml index af615314..803b7c78 100644 --- a/compose.yaml +++ b/compose.yaml @@ -9,7 +9,7 @@ services: - 4000:4000 environment: - ORIGIN=http://localhost:3000 - - LIVE_BACKEND_ADDRESS=0.0.0.0:4000 + - LIVE_ADDRESS=0.0.0.0:4000 - RUST_LOG="live=debug" api: @@ -22,7 +22,7 @@ services: - 4001:4001 environment: - ORIGIN=http://localhost:3000 - - API_BACKEND_ADDRESS=0.0.0.0:4001 + - API_ADDRESS=0.0.0.0:4001 - RUST_LOG="api=debug" frontend: @@ -32,7 +32,6 @@ services: restart: unless-stopped ports: - 3000:3000 - depends_on: - api - live @@ -42,7 +41,28 @@ services: - DISABLE_IFRAME=1 - - TRACKING_ID=G-3ZKX0JY1QW - - TRACKING_URL=https://base.slowly.dev/rep.js + timescaledb: + image: timescale/timescaledb:latest-pg16 + ports: + - 5432:5432 + restart: unless-stopped + environment: + - POSTGRES_PASSWORD=password + + importer: + image: ghcr.io/slowlydev/f1-dash-importer:latest + build: + context: . + target: importer + environment: + - DATABASE_URL=postgres://postgres:password@timescaledb:5432/postgres - - NEXT_PUBLIC_MAP_KEY=lcgTreisBzMYLrFFSTK2 + analytics: + image: ghcr.io/slowlydev/f1-dash-analytics:latest + build: + context: . + target: analytics + environment: + - ORIGIN=http://localhost:3000 + - ANALYTICS_ADDRESS=0.0.0.0:4002 + - RUST_LOG="analytics=debug" diff --git a/crates/api/src/main.rs b/crates/api/src/main.rs deleted file mode 100644 index e723ec39..00000000 --- a/crates/api/src/main.rs +++ /dev/null @@ -1,45 +0,0 @@ -use axum::{routing::get, Router}; -use tokio::net::TcpListener; -use tracing::info; -use tracing::level_filters::LevelFilter; - -use env; - -mod endpoints { - pub(crate) mod health; - pub(crate) mod schedule; -} - -#[tokio::main] -async fn main() { - env::init(); - init_logs(); - - let app = Router::new() - .route("/api/schedule", get(endpoints::schedule::get)) - .route("/api/schedule/next", get(endpoints::schedule::get_next)) - .route("/api/health", get(endpoints::health::check)); - - let addr = addr(); - - info!("running on {}", addr); - - let listener = TcpListener::bind(addr).await.expect("failed to bind"); - - axum::serve(listener, app) - .await - .expect("failed to setup server"); -} - -fn addr() -> String { - std::env::var("API_BACKEND_ADDRESS").unwrap_or("0.0.0.0:5000".to_string()) -} - -fn init_logs() { - let env_filter = tracing_subscriber::EnvFilter::builder() - .with_default_directive(LevelFilter::INFO.into()) - .with_env_var("RUST_LOG") - .from_env_lossy(); - - tracing_subscriber::fmt().with_env_filter(env_filter).init(); -} diff --git a/crates/client/src/client.rs b/crates/client/src/client.rs index 0561930a..58608c30 100644 --- a/crates/client/src/client.rs +++ b/crates/client/src/client.rs @@ -5,18 +5,23 @@ use axum::http::HeaderValue; use futures::SinkExt; use reqwest::{header, Url}; use serde_json::Value; -use tokio_stream::Stream; -use tokio_stream::StreamExt; +use tokio_stream::{Stream, StreamExt}; use tokio_tungstenite::tungstenite::client::IntoClientRequest; use tokio_tungstenite::{tungstenite::http::Request, MaybeTlsStream, WebSocketStream}; -use tracing::{debug, trace}; +use tracing::{debug, info, trace}; pub use tokio_tungstenite::tungstenite; mod consts; +pub mod consumers; +pub mod manager; pub mod message; +pub use consumers::broadcast; +pub use consumers::keep_state; +pub use manager::manage; + type WsStream = WebSocketStream>; pub async fn parse_stream(stream: WsStream) -> impl Stream { @@ -32,19 +37,17 @@ pub async fn parse_stream(stream: WsStream) -> impl Stream Result> { let req = create_request().await?; - debug!("created request"); - - trace!("request='{:?}'", req); + debug!(?req, "created request"); let (mut socket, _) = tokio_tungstenite::connect_async(req).await?; - debug!("connected"); + info!("connected"); socket .send(tungstenite::Message::text(consts::SIGNALR_SUBSCRIBE)) .await?; - debug!("subscribed"); + info!("subscribed"); Ok(socket) } @@ -59,11 +62,7 @@ async fn create_request() -> Result, Box> { let negotiation = negotiate().await?; - trace!( - "token='{}' cookie='{}'", - negotiation.token, - negotiation.cookie - ); + trace!(negotiation.token, negotiation.cookie); let url = Url::parse_with_params( &format!("wss://{}/connect", consts::F1_BASE_URL), @@ -71,11 +70,11 @@ async fn create_request() -> Result, Box> { ("clientProtocol", "1.5"), ("transport", "webSockets"), ("connectionToken", &negotiation.token), - ("connectionData", &consts::SIGNALR_HUB), + ("connectionData", consts::SIGNALR_HUB), ], )?; - trace!("url='{}'", url); + trace!(?url); let mut req: Request<()> = url.into_client_request()?; @@ -89,7 +88,7 @@ async fn create_request() -> Result, Box> { HeaderValue::from_static("gzip,identity"), ); headers.insert( - header::COOKIE, //asd + header::COOKIE, // asd negotiation.cookie.parse().unwrap(), ); @@ -110,7 +109,7 @@ async fn negotiate() -> Result> { &format!("https://{}/negotiate", consts::F1_BASE_URL), &[ ("clientProtocol", "1.5"), - ("connectionData", &consts::SIGNALR_HUB), + ("connectionData", consts::SIGNALR_HUB), ], )?; @@ -121,7 +120,7 @@ async fn negotiate() -> Result> { let body = res.text().await?; let json = serde_json::from_str::(&body)?; - trace!("negotiation response='{}'", json); + trace!(?json, "negotiation response"); Ok(Negotiaion { token: json["ConnectionToken"] diff --git a/crates/client/src/consumers.rs b/crates/client/src/consumers.rs new file mode 100644 index 00000000..dbe9a809 --- /dev/null +++ b/crates/client/src/consumers.rs @@ -0,0 +1,58 @@ +use std::sync::{Arc, Mutex}; + +use data::merge::merge; +use serde_json::{json, Map, Value}; +use tokio::sync::broadcast::{self, Receiver, Sender}; +use tokio_stream::{wrappers::ReceiverStream, StreamExt}; +use tracing::error; + +use crate::message::Message; + +pub fn broadcast(mut stream: ReceiverStream) -> (Sender, Receiver) { + let (tx, rx) = broadcast::channel::(32); + + let manage_tx = tx.clone(); + + tokio::spawn(async move { + while let Some(message) = stream.next().await { + let _ = manage_tx.send(message); + } + }); + + (tx, rx) +} + +pub fn keep_state(mut reciver: Receiver) -> Arc> { + let state = Arc::new(Mutex::new(json!({}))); + + let manage_state = state.clone(); + + tokio::spawn(async move { + while let Ok(message) = reciver.recv().await { + match message { + Message::Updates(updates) => { + let Ok(mut state) = manage_state.lock() else { + error!("failed to lock state"); + continue; + }; + + for (topic, update) in updates { + let mut map = Map::new(); + map.insert(topic, update); + merge(&mut state, Value::Object(map)); + } + } + Message::Initial(initial) => { + let Ok(mut state) = manage_state.lock() else { + error!("failed to lock state"); + continue; + }; + + *state = initial; + } + } + } + }); + + state +} diff --git a/crates/client/src/manager.rs b/crates/client/src/manager.rs new file mode 100644 index 00000000..8c90f1f9 --- /dev/null +++ b/crates/client/src/manager.rs @@ -0,0 +1,52 @@ +use std::time::Duration; + +use tokio::{sync::mpsc, time::sleep}; +use tokio_stream::{wrappers::ReceiverStream, StreamExt}; +use tracing::error; + +use crate::{init, message::Message, parse_stream}; + +pub fn manage() -> ReceiverStream { + let (tx, rx) = mpsc::channel::(32); + + tokio::spawn(async move { + 'manage: loop { + sleep(Duration::from_secs(3)).await; + + let stream = match init().await { + Ok(stream) => stream, + Err(err) => { + error!(?err, "error occored starting the client, restarting"); + continue 'manage; + } + }; + + let mut parsed_stream = parse_stream(stream).await; + + while let Some(message) = parsed_stream.next().await { + if check_restart(&message) { + continue 'manage; + } + + let _ = tx.send(message).await; + } + } + }); + + ReceiverStream::new(rx) +} + +fn check_restart(message: &Message) -> bool { + match message { + Message::Updates(updates) => { + for (cat, update) in updates { + if cat == "sessionInfo" && update.pointer("/name").is_some() { + return true; + } + } + + false + } + Message::Initial(_) => false, + } +} diff --git a/crates/client/src/message.rs b/crates/client/src/message.rs index 13570dc2..00e628c8 100644 --- a/crates/client/src/message.rs +++ b/crates/client/src/message.rs @@ -1,21 +1,23 @@ -use std::mem; - -use serde_json::{Map, Value}; +use data::transformer::{to_camel_case, transform}; +use serde_json::Value; use tokio_tungstenite::tungstenite::Utf8Bytes; use tracing::trace; +#[derive(Clone)] pub enum Message { - Updates(Vec>), + Updates(Vec<(String, Value)>), Initial(Value), } pub fn parse(data: Utf8Bytes) -> Option { - trace!("parsing message '{}'", data); + trace!(?data, "parsing message"); let msg = serde_json::from_str::(&data).ok()?; if let Some(initial) = msg.pointer("/R") { - return Some(Message::Initial(initial.clone())); + let mut data = initial.clone(); + transform(&mut data); + return Some(Message::Initial(data)); }; if let Some(Value::Array(updates)) = msg.pointer("/M") { @@ -26,18 +28,23 @@ pub fn parse(data: Utf8Bytes) -> Option { let mut ups = Vec::new(); for update in updates { - let cat = update.pointer("/A/0")?.as_str()?; - let data = update.pointer("/A/1")?; + let Some(cat) = update.pointer("/A/0").and_then(|v| v.as_str()) else { + continue; + }; + + let Some(data) = update.pointer("/A/1") else { + continue; + }; + + let mut update_value = data.clone(); - let mut up = Map::new(); - up.insert(cat.to_owned(), data.clone()); - ups.push(up); + transform(&mut update_value); + + ups.push((to_camel_case(cat), update_value)); } return Some(Message::Updates(ups)); } - mem::drop(msg); // idk why I put this here - None } diff --git a/crates/data/src/transformer.rs b/crates/data/src/transformer.rs index 81c922d3..be5a62ac 100644 --- a/crates/data/src/transformer.rs +++ b/crates/data/src/transformer.rs @@ -2,7 +2,7 @@ use std::mem; use serde_json::{Map, Value}; -fn to_camel_case(string: &str) -> String { +pub fn to_camel_case(string: &str) -> String { heck::AsLowerCamelCase(string).to_string() } diff --git a/crates/env/Cargo.toml b/crates/env/Cargo.toml deleted file mode 100644 index 3990a652..00000000 --- a/crates/env/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "env" -version = "0.1.0" -edition = "2021" -publish = false - -[lib] -path = "src/env.rs" - -[dependencies] -dotenvy.workspace = true - diff --git a/crates/env/src/env.rs b/crates/env/src/env.rs deleted file mode 100644 index 4de25987..00000000 --- a/crates/env/src/env.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub fn init() { - // we cant use info and warn here yet - // because we load envs before log levels because log levels are set by envs - match dotenvy::dotenv() { - Ok(_) => println!("successfully found env file and loaded vars"), - Err(_) => println!("no env file found"), - } -} diff --git a/crates/live/src/main.rs b/crates/live/src/main.rs deleted file mode 100644 index a9d9d0df..00000000 --- a/crates/live/src/main.rs +++ /dev/null @@ -1,58 +0,0 @@ -use std::sync::{Arc, Mutex}; - -use serde_json::{json, Value}; -use tokio::sync::broadcast; - -mod server; -mod state; - -use env; -use tracing::level_filters::LevelFilter; - -type LiveState = Arc>; - -#[derive(Clone)] -pub enum LiveEvent { - Initial(String), - Update(String), -} - -impl LiveEvent { - pub fn name(&self) -> &str { - match self { - LiveEvent::Initial(_) => "initial", - LiveEvent::Update(_) => "update", - } - } - - pub fn inner(self) -> String { - match self { - LiveEvent::Initial(v) => v, - LiveEvent::Update(v) => v, - } - } -} - -#[tokio::main] -async fn main() { - env::init(); - init_logs(); - - let (tx, _rx) = broadcast::channel::(10); - let state = Arc::new(Mutex::new(json!({}))); - - state::manage(tx.clone(), state.clone()); - - server::init(tx, state) - .await - .expect("http server setup failed"); -} - -fn init_logs() { - let env_filter = tracing_subscriber::EnvFilter::builder() - .with_default_directive(LevelFilter::INFO.into()) - .with_env_var("RUST_LOG") - .from_env_lossy(); - - tracing_subscriber::fmt().with_env_filter(env_filter).init(); -} diff --git a/crates/live/src/server.rs b/crates/live/src/server.rs deleted file mode 100644 index 5d7f2b4e..00000000 --- a/crates/live/src/server.rs +++ /dev/null @@ -1,53 +0,0 @@ -use std::{error::Error, net::SocketAddr, sync::Arc}; - -use axum::{routing::get, Router}; -use tokio::sync::broadcast; - -use tracing::info; - -use crate::{LiveEvent, LiveState}; - -mod cors; -mod drivers; -mod health; -pub mod live; - -pub struct AppState { - tx: broadcast::Sender, - state: LiveState, -} - -fn addr() -> String { - std::env::var("LIVE_BACKEND_ADDRESS").unwrap_or("0.0.0.0:4000".to_string()) -} - -pub async fn init( - tx: broadcast::Sender, - state: LiveState, -) -> Result<(), Box> { - let cors = cors::init(); - - let app_state = Arc::new(AppState { tx, state }); - - let app = Router::new() - .route("/api/sse", get(live::sse_handler)) - .route("/api/health", get(health::check)) - .route("/api/drivers", get(drivers::get_drivers)) - .layer(cors) - .with_state(app_state) - .into_make_service_with_connect_info::(); - - let addr = addr(); - - info!("running on {}", addr); - - let listener = tokio::net::TcpListener::bind(addr) - .await - .expect("failed to bind to port"); - - axum::serve(listener, app) - .await - .expect("failed to serve http server"); - - Ok(()) -} diff --git a/crates/live/src/server/cors.rs b/crates/live/src/server/cors.rs deleted file mode 100644 index e735766b..00000000 --- a/crates/live/src/server/cors.rs +++ /dev/null @@ -1,10 +0,0 @@ -use axum::http::{HeaderValue, Method}; -use tower_http::cors::CorsLayer; - -pub fn init() -> CorsLayer { - let origin = std::env::var("ORIGIN").expect("no origin env found"); - - CorsLayer::new() - .allow_origin(origin.parse::().unwrap()) - .allow_methods([Method::GET, Method::CONNECT]) -} diff --git a/crates/live/src/server/live.rs b/crates/live/src/server/live.rs deleted file mode 100644 index b42af806..00000000 --- a/crates/live/src/server/live.rs +++ /dev/null @@ -1,45 +0,0 @@ -use std::{convert::Infallible, mem, sync::Arc, time::Duration}; - -use axum::{ - extract::State, - response::{sse, Sse}, -}; -use futures::Stream; -use tokio_stream::{wrappers::BroadcastStream, StreamExt}; -use tracing::{debug, info}; - -use data::compression; - -use super::AppState; - -pub async fn sse_handler( - State(state): State>, -) -> Sse>> { - let rx = state.tx.subscribe(); - - debug!("new sse connection"); - info!("connections: {}", state.tx.receiver_count()); - - let initial_stream = futures::stream::once(async { - let initial_state = state.state.lock().unwrap().to_string(); - mem::drop(state); - let initial = compression::deflate(initial_state).unwrap(); - - debug!("streaming current initial"); - - Ok(sse::Event::default().event("initial").data(initial)) - }); - - let updates_stream = BroadcastStream::new(rx) - .filter_map(|msg| msg.ok()) - .map(|msg| sse::Event::default().event(msg.name()).data(msg.inner())) - .map(Ok); - - let stream = initial_stream.chain(updates_stream); - - let keep_alive = sse::KeepAlive::new() - .interval(Duration::from_secs(10)) - .text("keep-alive-text"); - - Sse::new(stream).keep_alive(keep_alive) -} diff --git a/crates/live/src/state.rs b/crates/live/src/state.rs deleted file mode 100644 index 7fa820e9..00000000 --- a/crates/live/src/state.rs +++ /dev/null @@ -1,120 +0,0 @@ -use std::{mem, thread, time::Duration}; - -use futures::{pin_mut, Stream}; -use tokio::{sync::broadcast::Sender, time::sleep}; -use tokio_stream::StreamExt; -use tracing::{debug, error, info, trace}; - -use crate::{LiveEvent, LiveState}; - -use client; -use data::{compression, merge::merge, transformer}; - -pub fn manage(tx: Sender, state: LiveState) { - // TODO start and stop on connect and disconnect - - thread::spawn(|| { - let rt = tokio::runtime::Runtime::new().unwrap(); - - rt.block_on(async { - keep_client_alive(tx, state).await; - }) - }); -} - -async fn keep_client_alive(tx: Sender, state: LiveState) { - loop { - if tx.receiver_count() < 2 { - debug!("no connections yet"); - sleep(Duration::from_secs(5)).await; - continue; - } - - info!("starting client..."); - - let stream = client::init().await; - - let stream = match stream { - Ok(stream) => stream, - Err(e) => { - error!("client setup failed, restarting in 5 seconds {}", e); - sleep(Duration::from_secs(5)).await; - continue; - } - }; - - let parsed_stream = client::parse_stream(stream).await; - - handle_stream(parsed_stream, tx.clone(), state.clone()).await; - } -} - -async fn handle_stream( - stream: impl Stream, - tx: Sender, - state: LiveState, -) { - pin_mut!(stream); - - while let Some(message) = stream.next().await { - match message { - client::message::Message::Updates(mut updates) => { - trace!("recived update"); - - let mut state = state.lock().unwrap(); - - for update in updates.iter_mut() { - let update = transformer::transform_map(update); - - if let Some(new_session_name) = update.pointer("/sessionInfo/name") { - let current_session_name = state - .pointer("/sessionInfo/name") - .expect("we always should have a session name"); - - if new_session_name != current_session_name { - info!("session name changed, restarting client"); - return; - } - } - - let Some(update_compressed) = compression::deflate(update.to_string()) else { - error!("failed compressing update"); - continue; - }; - - trace!("update compressed='{}'", update_compressed); - - match tx.send(LiveEvent::Update(update_compressed)) { - Ok(_) => trace!("update sent"), - Err(e) => error!("failed sending update: {}", e), - }; - - merge(&mut state, update) - } - - mem::drop(state); - } - client::message::Message::Initial(mut initial) => { - trace!("recived initial"); - - transformer::transform(&mut initial); - - let mut state = state.lock().unwrap(); - *state = initial.clone(); - mem::drop(state); - - let Some(initial) = compression::deflate(initial.to_string()) else { - error!("failed compressing update"); - continue; - }; - - trace!("initial compressed='{}'", initial); - - match tx.send(LiveEvent::Initial(initial)) { - Ok(_) => trace!("initial sent"), - Err(e) => error!("failed sending initial: {}", e), - }; - } - } - } -} diff --git a/crates/simulator/src/server.rs b/crates/simulator/src/server.rs index da10f84c..67fff7e6 100644 --- a/crates/simulator/src/server.rs +++ b/crates/simulator/src/server.rs @@ -20,7 +20,7 @@ pub struct AppState { } fn addr() -> String { - std::env::var("SIMULATOR_BACKEND_ADDRESS").unwrap_or("0.0.0.0:8000".to_string()) + std::env::var("SIMULATOR_ADDRESS").unwrap_or("0.0.0.0:8000".to_string()) } pub async fn init(tx: broadcast::Sender, mpsc_tx: mpsc::Sender<()>) { diff --git a/crates/timescale/.sqlx/query-242dca2d8a422e6043b05db01d42903fb29d257e5edb641211ee1148637b33d5.json b/crates/timescale/.sqlx/query-242dca2d8a422e6043b05db01d42903fb29d257e5edb641211ee1148637b33d5.json new file mode 100644 index 00000000..ee3769b6 --- /dev/null +++ b/crates/timescale/.sqlx/query-242dca2d8a422e6043b05db01d42903fb29d257e5edb641211ee1148637b33d5.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n select\n gap as \"gap!\",\n time as \"time!\"\n from\n timing_driver\n where\n nr = $1\n and gap != 0\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "gap!", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "time!", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + true, + false + ] + }, + "hash": "242dca2d8a422e6043b05db01d42903fb29d257e5edb641211ee1148637b33d5" +} diff --git a/crates/timescale/.sqlx/query-558382d26b558498dea63c4afdcc8bce1bd85adf440a424f35ac774b5535cb39.json b/crates/timescale/.sqlx/query-558382d26b558498dea63c4afdcc8bce1bd85adf440a424f35ac774b5535cb39.json new file mode 100644 index 00000000..1de30a0f --- /dev/null +++ b/crates/timescale/.sqlx/query-558382d26b558498dea63c4afdcc8bce1bd85adf440a424f35ac774b5535cb39.json @@ -0,0 +1,34 @@ +{ + "db_name": "PostgreSQL", + "query": "\n select\n lap,\n min(laptime) AS \"laptime!\",\n min(time) AS \"time!\"\n from\n timing_driver\n where\n nr = $1\n and laptime != 0\n group by\n lap\n order by\n lap;\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "lap", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "laptime!", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "time!", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + true, + null, + null + ] + }, + "hash": "558382d26b558498dea63c4afdcc8bce1bd85adf440a424f35ac774b5535cb39" +} diff --git a/crates/timescale/.sqlx/query-c899c95cf53a6b6d0d4e3a0b96b2d507d58a569841601cafcd7d486a245f62fe.json b/crates/timescale/.sqlx/query-c899c95cf53a6b6d0d4e3a0b96b2d507d58a569841601cafcd7d486a245f62fe.json new file mode 100644 index 00000000..d7a17df0 --- /dev/null +++ b/crates/timescale/.sqlx/query-c899c95cf53a6b6d0d4e3a0b96b2d507d58a569841601cafcd7d486a245f62fe.json @@ -0,0 +1,21 @@ +{ + "db_name": "PostgreSQL", + "query": "\n insert into timing_driver (nr, lap, gap, leader_gap, laptime, sector_1, sector_2, sector_3)\n values ($1, $2, $3, $4, $5, $6, $7, $8)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int4", + "Int8", + "Int8", + "Int8", + "Int8", + "Int8", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "c899c95cf53a6b6d0d4e3a0b96b2d507d58a569841601cafcd7d486a245f62fe" +} diff --git a/crates/timescale/Cargo.toml b/crates/timescale/Cargo.toml new file mode 100644 index 00000000..92d40707 --- /dev/null +++ b/crates/timescale/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "timescale" +version = "0.3.0" +edition = "2021" +publish = false +authors = ["slowlydev"] + +[lib] +name = "timescale" +path = "src/lib.rs" + +[dependencies] +tokio.workspace = true + +tracing.workspace = true + +anyhow.workspace = true +serde.workspace = true +serde_json.workspace = true + +sqlx.workspace = true + +chrono = { version = "0.4", features = ["serde"] } diff --git a/crates/timescale/migrations/20250520180813_initial.sql b/crates/timescale/migrations/20250520180813_initial.sql new file mode 100644 index 00000000..a1bf03dc --- /dev/null +++ b/crates/timescale/migrations/20250520180813_initial.sql @@ -0,0 +1,32 @@ +create table timing_driver ( + time timestamptz not null default now(), + nr text not null, + lap integer, + + -- timing data + gap bigint, + leader_gap bigint, + + laptime bigint, + sector_1 bigint, + sector_2 bigint, + sector_3 bigint +); + +create index on timing_driver (nr, time desc); +select create_hypertable('timing_driver', 'time'); +select add_retention_policy('timing_driver', interval '4 hours'); + +create table tire_driver ( + time timestamptz not null default now(), + nr text not null, + lap integer, + + -- timing app data + compound text, + laps integer +); + +create index on tire_driver (nr, time desc); +select create_hypertable('tire_driver', 'time'); +select add_retention_policy('tire_driver', interval '4 hours'); diff --git a/crates/timescale/src/app_timing.rs b/crates/timescale/src/app_timing.rs new file mode 100644 index 00000000..19bfd3b1 --- /dev/null +++ b/crates/timescale/src/app_timing.rs @@ -0,0 +1,25 @@ +use sqlx::PgPool; + +pub struct TireDriver { + pub nr: String, + pub lap: Option, + pub compound: String, + pub laps: i32, +} + +pub async fn insert_tire_driver(pool: &PgPool, driver: TireDriver) -> Result<(), anyhow::Error> { + sqlx::query( + r#" + insert into tire_driver (nr, lap, compound, laps) + values ($1, $2, $3, $4) + "#, + ) + .bind(driver.nr) + .bind(driver.lap) + .bind(driver.compound) + .bind(driver.laps) + .execute(pool) + .await?; + + Ok(()) +} diff --git a/crates/timescale/src/lib.rs b/crates/timescale/src/lib.rs new file mode 100644 index 00000000..bd39d606 --- /dev/null +++ b/crates/timescale/src/lib.rs @@ -0,0 +1,23 @@ +use sqlx::{postgres::PgPoolOptions, PgPool}; +use std::env; + +pub mod app_timing; +pub mod timing; + +// pub use app_timing::insert_tire_driver; +// pub use timing::{get_laptimes, insert_timing_driver}; + +pub async fn init_timescaledb(migrate: bool) -> Result { + let database_url = env::var("DATABASE_URL")?; + + let pool = PgPoolOptions::new() + .max_connections(10) + .connect(&database_url) + .await?; + + if migrate { + sqlx::migrate!().run(&pool).await?; + } + + Ok(pool) +} diff --git a/crates/timescale/src/timing.rs b/crates/timescale/src/timing.rs new file mode 100644 index 00000000..03ecd485 --- /dev/null +++ b/crates/timescale/src/timing.rs @@ -0,0 +1,107 @@ +use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; +use sqlx::PgPool; + +pub struct TimingDriver { + pub nr: String, + pub lap: Option, + pub gap: i64, + pub leader_gap: i64, + pub laptime: i64, + pub sector_1: i64, + pub sector_2: i64, + pub sector_3: i64, +} + +pub async fn insert_timing_driver( + pool: &PgPool, + driver: TimingDriver, +) -> Result<(), anyhow::Error> { + sqlx::query!( + r#" + insert into timing_driver (nr, lap, gap, leader_gap, laptime, sector_1, sector_2, sector_3) + values ($1, $2, $3, $4, $5, $6, $7, $8) + "#, + driver.nr, + driver.lap, + driver.gap, + driver.leader_gap, + driver.laptime, + driver.sector_1, + driver.sector_2, + driver.sector_3 + ) + .execute(pool) + .await?; + + Ok(()) +} + +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Laptime { + pub time: DateTime, + pub lap: Option, + pub laptime: i64, +} + +pub async fn get_laptimes(pool: &PgPool, nr: &str) -> Result, anyhow::Error> { + let laptimes = sqlx::query!( + r#" + select + lap, + min(laptime) AS "laptime!", + min(time) AS "time!" + from + timing_driver + where + nr = $1 + and laptime != 0 + group by + lap + order by + lap; + "#, + nr + ) + .map(|row| Laptime { + time: row.time, + lap: row.lap, + laptime: row.laptime, + }) + .fetch_all(pool) + .await?; + + Ok(laptimes) +} + +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Gap { + pub time: DateTime, + pub gap: i64, +} + +pub async fn get_gaps(pool: &PgPool, nr: &str) -> Result, anyhow::Error> { + let gaps = sqlx::query!( + r#" + select + gap as "gap!", + time as "time!" + from + timing_driver + where + nr = $1 + and gap != 0 + "#, + nr + ) + .map(|row| Gap { + time: row.time, + gap: row.gap, + }) + .fetch_all(pool) + .await?; + + Ok(gaps) +} diff --git a/dash/next.config.ts b/dash/next.config.ts index 7f84d27b..dd5da0d6 100644 --- a/dash/next.config.ts +++ b/dash/next.config.ts @@ -1,4 +1,4 @@ -import { NextConfig } from "next"; +import type { NextConfig } from "next"; import pack from "./package.json" with { type: "json" }; diff --git a/dash/package.json b/dash/package.json index d1f8afcc..2582e350 100644 --- a/dash/package.json +++ b/dash/package.json @@ -1,6 +1,6 @@ { "name": "f1-dash", - "version": "3.0.2", + "version": "3.1.0", "private": true, "scripts": { "build": "next build", diff --git a/dash/public/team-logos/alpine.svg b/dash/public/team-logos/alpine.svg new file mode 100644 index 00000000..e5ce0280 --- /dev/null +++ b/dash/public/team-logos/alpine.svg @@ -0,0 +1 @@ +Alpine logomark logo - Brandlogos.net \ No newline at end of file diff --git a/dash/public/team-logos/aston-martin.svg b/dash/public/team-logos/aston-martin.svg new file mode 100644 index 00000000..4c428a01 --- /dev/null +++ b/dash/public/team-logos/aston-martin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dash/public/team-logos/ferrari.svg b/dash/public/team-logos/ferrari.svg new file mode 100644 index 00000000..75535f28 --- /dev/null +++ b/dash/public/team-logos/ferrari.svg @@ -0,0 +1 @@ +image/svg+xml \ No newline at end of file diff --git a/dash/public/team-logos/haas-f1-team.svg b/dash/public/team-logos/haas-f1-team.svg new file mode 100644 index 00000000..f6414f98 --- /dev/null +++ b/dash/public/team-logos/haas-f1-team.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dash/public/team-logos/kick-sauber.svg b/dash/public/team-logos/kick-sauber.svg new file mode 100644 index 00000000..472a6318 --- /dev/null +++ b/dash/public/team-logos/kick-sauber.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dash/public/team-logos/mclaren.svg b/dash/public/team-logos/mclaren.svg new file mode 100644 index 00000000..b844e0e9 --- /dev/null +++ b/dash/public/team-logos/mclaren.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dash/public/team-logos/mercedes.svg b/dash/public/team-logos/mercedes.svg new file mode 100644 index 00000000..46bef0f7 --- /dev/null +++ b/dash/public/team-logos/mercedes.svg @@ -0,0 +1 @@ +image/svg+xml \ No newline at end of file diff --git a/dash/public/team-logos/racing-bulls.svg b/dash/public/team-logos/racing-bulls.svg new file mode 100644 index 00000000..62bdb73e --- /dev/null +++ b/dash/public/team-logos/racing-bulls.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dash/public/team-logos/red-bull-racing.svg b/dash/public/team-logos/red-bull-racing.svg new file mode 100644 index 00000000..8bf36eea --- /dev/null +++ b/dash/public/team-logos/red-bull-racing.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dash/public/team-logos/williams.svg b/dash/public/team-logos/williams.svg new file mode 100644 index 00000000..c145f997 --- /dev/null +++ b/dash/public/team-logos/williams.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dash/src/app/dashboard/settings/page.tsx b/dash/src/app/dashboard/settings/page.tsx index 42ca4111..f9d263f4 100644 --- a/dash/src/app/dashboard/settings/page.tsx +++ b/dash/src/app/dashboard/settings/page.tsx @@ -47,6 +47,11 @@ export default function SettingsPage() {

Show Drivers Mini Sectors

+
+ settings.setOledMode(v)} /> +

OLED Mode (Pure Black Background)

+
+

Race Control

diff --git a/dash/src/app/dashboard/standings/page.tsx b/dash/src/app/dashboard/standings/page.tsx index d3506c59..fee8ee63 100644 --- a/dash/src/app/dashboard/standings/page.tsx +++ b/dash/src/app/dashboard/standings/page.tsx @@ -3,6 +3,7 @@ import { useDataStore } from "@/stores/useDataStore"; import NumberDiff from "@/components/NumberDiff"; +import Image from "next/image"; export default function Standings() { const driverStandings = useDataStore((state) => state?.championshipPrediction?.drivers); @@ -78,13 +79,21 @@ export default function Standings() {

{team.predictedPosition}

+ {team.teamName} +

{team.teamName}

{team.predictedPoints}

@@ -106,6 +115,7 @@ const SkeletonItem = () => { gridTemplateColumns: "2rem 2rem auto 4rem 4rem 4rem", }} > +
diff --git a/dash/src/app/dashboard/track-map/page.tsx b/dash/src/app/dashboard/track-map/page.tsx index 52fd2162..dd3f2382 100644 --- a/dash/src/app/dashboard/track-map/page.tsx +++ b/dash/src/app/dashboard/track-map/page.tsx @@ -13,7 +13,7 @@ import DriverLapTime from "@/components/driver/DriverLapTime"; import { sortPos } from "@/lib/sorting"; import { useCarDataStore, useDataStore } from "@/stores/useDataStore"; -import { Driver, TimingDataDriver } from "@/types/state.type"; +import type { Driver, TimingDataDriver } from "@/types/state.type"; import { useSettingsStore } from "@/stores/useSettingsStore"; export default function TrackMap() { diff --git a/dash/src/app/dashboard/weather/map-timeline.tsx b/dash/src/app/dashboard/weather/map-timeline.tsx index ef35a5e3..6c1fb5d3 100644 --- a/dash/src/app/dashboard/weather/map-timeline.tsx +++ b/dash/src/app/dashboard/weather/map-timeline.tsx @@ -3,7 +3,7 @@ import { unix } from "moment"; import { motion, useMotionValue, useDragControls, AnimatePresence } from "motion/react"; -import { useState, useRef, useEffect, RefObject } from "react"; +import { useState, useRef, useEffect, type RefObject } from "react"; function getProgressFromX({ x, diff --git a/dash/src/app/dashboard/weather/map.tsx b/dash/src/app/dashboard/weather/map.tsx index f1e5da52..70626df3 100644 --- a/dash/src/app/dashboard/weather/map.tsx +++ b/dash/src/app/dashboard/weather/map.tsx @@ -5,8 +5,6 @@ import { useEffect, useRef, useState } from "react"; import maplibregl, { Map, Marker } from "maplibre-gl"; import "maplibre-gl/dist/maplibre-gl.css"; -import { env } from "@/env"; - import { fetchCoords } from "@/lib/geocode"; import { getRainviewer } from "@/lib/rainviewer"; @@ -74,7 +72,7 @@ export function WeatherMap() { const libMap = new maplibregl.Map({ container: mapContainerRef.current, - style: `https://api.maptiler.com/maps/dataviz-dark/style.json?key=${env.NEXT_PUBLIC_MAP_KEY}`, + style: "https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json", center: coords ? [coords.lon, coords.lat] : undefined, zoom: 10, canvasContextAttributes: { diff --git a/dash/src/app/dashboard/weather/page.tsx b/dash/src/app/dashboard/weather/page.tsx index 555d8885..b65a89ff 100644 --- a/dash/src/app/dashboard/weather/page.tsx +++ b/dash/src/app/dashboard/weather/page.tsx @@ -1,19 +1,10 @@ import { WeatherMap } from "@/app/dashboard/weather/map"; -import { env } from "@/env"; - export default function WeatherPage() { // calc height is a workaround, maybe think about refactoring sometime return (
- {!!env.NEXT_PUBLIC_MAP_KEY ? ( - - ) : ( -
-

weather map unavailable

-

setup the map key to the use the weather map

-
- )} +
); } diff --git a/dash/src/app/layout.tsx b/dash/src/app/layout.tsx index 448940de..47698516 100644 --- a/dash/src/app/layout.tsx +++ b/dash/src/app/layout.tsx @@ -5,6 +5,7 @@ import "@/styles/globals.css"; import { env } from "@/env"; import EnvScript from "@/env-script"; +import OledModeProvider from "@/components/OledModeProvider"; import { GeistMono } from "geist/font/mono"; import { GeistSans } from "geist/font/sans"; @@ -18,7 +19,7 @@ type Props = Readonly<{ export default function RootLayout({ children }: Props) { return ( - + @@ -34,7 +35,9 @@ export default function RootLayout({ children }: Props) { )} - {children} + + {children} + ); -} +} \ No newline at end of file diff --git a/dash/src/components/Flag.tsx b/dash/src/components/Flag.tsx index f8f1e7b6..f26ede95 100644 --- a/dash/src/components/Flag.tsx +++ b/dash/src/components/Flag.tsx @@ -1,20 +1,20 @@ +import { clsx } from "clsx"; import Image from "next/image"; type Props = { countryCode: string | undefined; - width: number | undefined; - height: number | undefined; + className?: string; }; -export default function Flag({ countryCode, width, height }: Props) { +export default function Flag({ countryCode, className }: Props) { return ( -
+
{countryCode ? ( {countryCode} ) : ( diff --git a/dash/src/components/OledModeProvider.tsx b/dash/src/components/OledModeProvider.tsx new file mode 100644 index 00000000..f4e72d8b --- /dev/null +++ b/dash/src/components/OledModeProvider.tsx @@ -0,0 +1,20 @@ +"use client"; + +import { useEffect, type ReactNode } from "react"; + +import { useSettingsStore } from "@/stores/useSettingsStore"; + +type Props = { + children: ReactNode; +}; + +export default function OledModeProvider({ children }: Props) { + const oledMode = useSettingsStore((state) => state.oledMode); + + useEffect(() => { + document.documentElement.classList.toggle("bg-zinc-950", !oledMode); + document.documentElement.classList.toggle("bg-black", oledMode); + }, [oledMode]); + + return children; +} diff --git a/dash/src/components/QualifyingDriver.tsx b/dash/src/components/QualifyingDriver.tsx index 779a29f6..1d1b79b0 100644 --- a/dash/src/components/QualifyingDriver.tsx +++ b/dash/src/components/QualifyingDriver.tsx @@ -6,9 +6,7 @@ import clsx from "clsx"; import DriverTag from "./driver/DriverTag"; -import { getSectorColorBG, getSectorColorText } from "@/lib/getTimeColor"; - -import { Driver as DriverType, TimingAppDataDriver, TimingDataDriver } from "@/types/state.type"; +import type { Driver as DriverType, TimingAppDataDriver, TimingDataDriver } from "@/types/state.type"; type Props = { driver: DriverType; @@ -85,18 +83,20 @@ export default function DriverQuali({ {timingDriver.sectors.map((sector, i) => (

{!!sector.value ? sector.value : "-- ---"}

diff --git a/dash/src/components/SessionInfo.tsx b/dash/src/components/SessionInfo.tsx index c66b0ad6..8f69349c 100644 --- a/dash/src/components/SessionInfo.tsx +++ b/dash/src/components/SessionInfo.tsx @@ -38,7 +38,7 @@ export default function SessionInfo() { return (
- +
{session ? ( diff --git a/dash/src/components/Sidebar.tsx b/dash/src/components/Sidebar.tsx index cb39b893..925daae5 100644 --- a/dash/src/components/Sidebar.tsx +++ b/dash/src/components/Sidebar.tsx @@ -7,6 +7,7 @@ import Link from "next/link"; import clsx from "clsx"; import { useSidebarStore } from "@/stores/useSidebarStore"; +import { useSettingsStore } from "@/stores/useSettingsStore"; import ConnectionStatus from "@/components/ConnectionStatus"; import DelayInput from "@/components/DelayInput"; @@ -57,6 +58,8 @@ export default function Sidebar({ connected }: Props) { const pin = useSidebarStore((state) => state.pin); const unpin = useSidebarStore((state) => state.unpin); + + const oledMode = useSettingsStore((state) => state.oledMode); useEffect(() => { const handleResize = () => { @@ -97,8 +100,10 @@ export default function Sidebar({ connected }: Props) { transition={{ type: "spring", bounce: 0.1 }} >