diff --git a/Cargo.lock b/Cargo.lock index e31a89c..a0c630d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -55,9 +55,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" @@ -95,9 +95,9 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "async-trait" -version = "0.1.80" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", @@ -125,17 +125,11 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "block-buffer" @@ -182,9 +176,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.5.4" +version = "4.5.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "69371e34337c4c984bbe322360c2547210bf632eb2814bbe78a6e87a2935bd2b" dependencies = [ "clap_builder", "clap_derive", @@ -192,9 +186,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "6e24c1b4099818523236a8ca881d2b45db98dadfb4625cf6608c12069fcbbde1" dependencies = [ "anstream", "anstyle", @@ -204,9 +198,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck", "proc-macro2", @@ -226,12 +220,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" -[[package]] -name = "const_fn" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373e9fafaa20882876db20562275ff58d50e0caa2590077fe7ce7bef90211d0d" - [[package]] name = "cookie" version = "0.18.1" @@ -244,9 +232,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.9.4" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" dependencies = [ "core-foundation-sys", "libc", @@ -254,9 +242,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cove" @@ -271,6 +259,7 @@ dependencies = [ "crossterm", "directories", "euphoxide", + "jiff", "linkify", "log", "once_cell", @@ -279,10 +268,8 @@ dependencies = [ "rusqlite", "serde_json", "thiserror", - "time", "tokio", "toss", - "tz-rs", "unicode-width", "vault", ] @@ -339,7 +326,7 @@ dependencies = [ "bitflags", "crossterm_winapi", "libc", - "mio", + "mio 0.8.11", "parking_lot", "signal-hook", "signal-hook-mio", @@ -378,7 +365,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", - "serde", ] [[package]] @@ -447,17 +433,17 @@ dependencies = [ [[package]] name = "euphoxide" version = "0.5.1" -source = "git+https://github.com/Garmelon/euphoxide.git?tag=v0.5.1#0256329f65f3ed853092cc210ae2a4a8c526a4bf" +source = "git+https://github.com/Garmelon/euphoxide.git#fe6869493225abb1229631816ffdc2fdae5d32e3" dependencies = [ "async-trait", "caseless", "clap", "cookie", "futures-util", + "jiff", "log", "serde", "serde_json", - "time", "tokio", "tokio-stream", "tokio-tungstenite", @@ -488,38 +474,29 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", "futures-sink", @@ -580,12 +557,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - [[package]] name = "home" version = "0.5.9" @@ -612,16 +583,6 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" -[[package]] -name = "idna" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "indexmap" version = "2.2.6" @@ -664,10 +625,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] -name = "libc" -version = "0.2.155" +name = "jiff" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "db69f08d4fb10524cacdb074c10b296299d71274ddbc830a8ee65666867002e9" +dependencies = [ + "jiff-tzdb-platform", + "serde", + "windows-sys 0.52.0", +] + +[[package]] +name = "jiff-tzdb" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91335e575850c5c4c673b9bd467b0e025f164ca59d0564f69d0c2ee0ffad4653" + +[[package]] +name = "jiff-tzdb-platform" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9835f0060a626fe59f160437bc725491a6af23133ea906500027d1bd2f8f4329" +dependencies = [ + "jiff-tzdb", +] + +[[package]] +name = "libc" +version = "0.2.167" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" [[package]] name = "libredox" @@ -717,9 +704,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "memchr" @@ -748,6 +735,17 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.52.0", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -763,16 +761,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "object" version = "0.32.2" @@ -849,12 +837,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - [[package]] name = "pin-project-lite" version = "0.2.14" @@ -1033,12 +1015,11 @@ dependencies = [ [[package]] name = "rustls" -version = "0.22.4" +version = "0.23.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" dependencies = [ - "log", - "ring", + "once_cell", "rustls-pki-types", "rustls-webpki", "subtle", @@ -1047,38 +1028,27 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" dependencies = [ "openssl-probe", - "rustls-pemfile", "rustls-pki-types", "schannel", "security-framework", ] -[[package]] -name = "rustls-pemfile" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" -dependencies = [ - "base64", - "rustls-pki-types", -] - [[package]] name = "rustls-pki-types" -version = "1.7.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-webpki" -version = "0.102.4" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring", "rustls-pki-types", @@ -1108,9 +1078,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "security-framework" -version = "2.11.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +checksum = "e1415a607e92bec364ea2cf9264646dcce0f91e6d65281bd6f2819cca3bf39c8" dependencies = [ "bitflags", "core-foundation", @@ -1121,9 +1091,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" dependencies = [ "core-foundation-sys", "libc", @@ -1131,9 +1101,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.202" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] @@ -1150,9 +1120,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.202" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", @@ -1171,11 +1141,12 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -1217,7 +1188,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" dependencies = [ "libc", - "mio", + "mio 0.8.11", "signal-hook", ] @@ -1275,9 +1246,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" -version = "2.0.65" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", @@ -1364,28 +1335,27 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.37.0" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ "backtrace", "bytes", "libc", - "mio", - "num_cpus", + "mio 1.0.3", "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", @@ -1394,9 +1364,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ "rustls", "rustls-pki-types", @@ -1405,9 +1375,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", "pin-project-lite", @@ -1416,9 +1386,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.21.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" +checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" dependencies = [ "futures-util", "log", @@ -1478,9 +1448,9 @@ dependencies = [ [[package]] name = "tungstenite" -version = "0.21.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" dependencies = [ "byteorder", "bytes", @@ -1493,7 +1463,6 @@ dependencies = [ "rustls-pki-types", "sha1", "thiserror", - "url", "utf-8", ] @@ -1503,21 +1472,6 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" -[[package]] -name = "tz-rs" -version = "0.6.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33851b15c848fad2cf4b105c6bb66eb9512b6f6c44a4b13f57c53c73c707e2b4" -dependencies = [ - "const_fn", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - [[package]] name = "unicode-ident" version = "1.0.12" @@ -1532,9 +1486,9 @@ checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] @@ -1557,17 +1511,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" -[[package]] -name = "url" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - [[package]] name = "utf-8" version = "0.7.6" diff --git a/Cargo.toml b/Cargo.toml index ffb4919..8ec7185 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ cookie = "0.18.1" crossterm = "0.27.0" directories = "5.0.1" edit = "0.1.5" +jiff = "0.1.15" linkify = "0.10.0" log = { version = "0.4.21", features = ["std"] } once_cell = "1.19.0" @@ -29,18 +30,12 @@ syn = "2.0.65" thiserror = "1.0.61" tokio = { version = "1.37.0", features = ["full"] } toml = "0.8.13" -tz-rs = "0.6.14" unicode-width = "0.1.12" [workspace.dependencies.euphoxide] git = "https://github.com/Garmelon/euphoxide.git" -tag = "v0.5.1" features = ["bot"] -[workspace.dependencies.time] -version = "0.3.36" -features = ["macros", "formatting", "parsing", "serde"] - [workspace.dependencies.toss] git = "https://github.com/Garmelon/toss.git" tag = "v0.2.3" diff --git a/cove/Cargo.toml b/cove/Cargo.toml index ad0e7f9..115d781 100644 --- a/cove/Cargo.toml +++ b/cove/Cargo.toml @@ -14,6 +14,7 @@ cookie.workspace = true crossterm.workspace = true directories.workspace = true euphoxide.workspace = true +jiff.workspace = true linkify.workspace = true log.workspace = true once_cell.workspace = true @@ -22,10 +23,8 @@ parking_lot.workspace = true rusqlite.workspace = true serde_json.workspace = true thiserror.workspace = true -time.workspace = true tokio.workspace = true toss.workspace = true -tz-rs.workspace = true unicode-width.workspace = true vault.workspace = true diff --git a/cove/src/euph/small_message.rs b/cove/src/euph/small_message.rs index 0642801..994b0ae 100644 --- a/cove/src/euph/small_message.rs +++ b/cove/src/euph/small_message.rs @@ -2,9 +2,8 @@ use std::mem; use crossterm::style::Stylize; use euphoxide::api::{MessageId, Snowflake, Time}; -use time::OffsetDateTime; +use jiff::Timestamp; use toss::{Style, Styled}; -use tz::TimeZone; use crate::store::Msg; use crate::ui::ChatMsg; @@ -208,7 +207,6 @@ pub struct SmallMessage { pub id: MessageId, pub parent: Option, pub time: Time, - pub time_zone: &'static TimeZone, pub nick: String, pub content: String, pub seen: bool, @@ -272,8 +270,8 @@ impl Msg for SmallMessage { } impl ChatMsg for SmallMessage { - fn time(&self) -> Option { - crate::util::convert_to_time_zone(self.time_zone, self.time.0) + fn time(&self) -> Option { + Some(self.time.as_timestamp()) } fn styled(&self) -> (Styled, Styled) { diff --git a/cove/src/export/text.rs b/cove/src/export/text.rs index bb3cfa1..23a75d8 100644 --- a/cove/src/export/text.rs +++ b/cove/src/export/text.rs @@ -1,16 +1,13 @@ use std::io::Write; use euphoxide::api::MessageId; -use time::format_description::FormatItem; -use time::macros::format_description; use unicode_width::UnicodeWidthStr; use crate::euph::SmallMessage; use crate::store::Tree; use crate::vault::EuphRoomVault; -const TIME_FORMAT: &[FormatItem<'_>] = - format_description!("[year]-[month]-[day] [hour]:[minute]:[second]"); +const TIME_FORMAT: &str = "%Y-%m-%d %H:%M:%S"; const TIME_EMPTY: &str = " "; pub async fn export(vault: &EuphRoomVault, out: &mut W) -> anyhow::Result<()> { @@ -67,11 +64,7 @@ fn write_msg( for (i, line) in msg.content.lines().enumerate() { if i == 0 { - let time = msg - .time - .0 - .format(TIME_FORMAT) - .expect("time can be formatted"); + let time = msg.time.as_timestamp().strftime(TIME_FORMAT); writeln!(file, "{time} {indent_string}[{nick}] {line}")?; } else { writeln!(file, "{TIME_EMPTY} {indent_string}| {nick_empty} {line}")?; diff --git a/cove/src/logger.rs b/cove/src/logger.rs index b8b696b..5574960 100644 --- a/cove/src/logger.rs +++ b/cove/src/logger.rs @@ -4,9 +4,9 @@ use std::vec; use async_trait::async_trait; use crossterm::style::Stylize; +use jiff::Timestamp; use log::{Level, LevelFilter, Log}; use parking_lot::Mutex; -use time::OffsetDateTime; use tokio::sync::mpsc; use toss::{Style, Styled}; @@ -16,7 +16,7 @@ use crate::ui::ChatMsg; #[derive(Debug, Clone)] pub struct LogMsg { id: usize, - time: OffsetDateTime, + time: Timestamp, level: Level, content: String, } @@ -42,7 +42,7 @@ impl Msg for LogMsg { } impl ChatMsg for LogMsg { - fn time(&self) -> Option { + fn time(&self) -> Option { Some(self.time) } @@ -209,7 +209,7 @@ impl Log for Logger { let mut guard = self.messages.lock(); let msg = LogMsg { id: guard.len(), - time: OffsetDateTime::now_utc(), + time: Timestamp::now(), level: record.level(), content: format!("<{}> {}", record.target(), record.args()), }; diff --git a/cove/src/main.rs b/cove/src/main.rs index fc14b56..4a3ce9e 100644 --- a/cove/src/main.rs +++ b/cove/src/main.rs @@ -118,16 +118,12 @@ fn update_config_with_args(config: &mut Config, args: &Args) { } fn open_vault(config: &Config, dirs: &ProjectDirs) -> anyhow::Result { - let time_zone = - util::load_time_zone(config.time_zone_ref()).context("failed to load time zone")?; - let time_zone = Box::leak(Box::new(time_zone)); - let vault = if config.ephemeral { - vault::launch_in_memory(time_zone)? + vault::launch_in_memory()? } else { let data_dir = data_dir(config, dirs); eprintln!("Data dir: {}", data_dir.to_string_lossy()); - vault::launch(&data_dir.join("vault.db"), time_zone)? + vault::launch(&data_dir.join("vault.db"))? }; Ok(vault) @@ -174,11 +170,13 @@ async fn run( ) -> anyhow::Result<()> { info!("Welcome to {NAME} {VERSION}",); + let tz = util::load_time_zone(config.time_zone_ref()).context("failed to load time zone")?; + let vault = open_vault(config, dirs)?; let mut terminal = Terminal::new()?; terminal.set_measuring(config.measure_widths); - Ui::run(config, &mut terminal, vault.clone(), logger, logger_rx).await?; + Ui::run(config, tz, &mut terminal, vault.clone(), logger, logger_rx).await?; drop(terminal); vault.close().await; diff --git a/cove/src/ui.rs b/cove/src/ui.rs index 95cc4d1..0263325 100644 --- a/cove/src/ui.rs +++ b/cove/src/ui.rs @@ -12,6 +12,7 @@ use std::time::{Duration, Instant}; use cove_config::Config; use cove_input::InputEvent; +use jiff::tz::TimeZone; use parking_lot::FairMutex; use tokio::sync::mpsc::error::TryRecvError; use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender}; @@ -84,6 +85,7 @@ impl Ui { pub async fn run( config: &'static Config, + tz: TimeZone, terminal: &mut Terminal, vault: Vault, logger: Logger, @@ -112,8 +114,8 @@ impl Ui { config, event_tx: event_tx.clone(), mode: Mode::Main, - rooms: Rooms::new(config, vault, event_tx.clone()).await, - log_chat: ChatState::new(logger), + rooms: Rooms::new(config, tz.clone(), vault, event_tx.clone()).await, + log_chat: ChatState::new(logger, tz), key_bindings_visible: false, key_bindings_list: ListState::new(), }; diff --git a/cove/src/ui/chat.rs b/cove/src/ui/chat.rs index c8a310c..cc7acc7 100644 --- a/cove/src/ui/chat.rs +++ b/cove/src/ui/chat.rs @@ -6,7 +6,8 @@ mod widgets; use cove_config::Keys; use cove_input::InputEvent; -use time::OffsetDateTime; +use jiff::tz::TimeZone; +use jiff::Timestamp; use toss::widgets::{BoxedAsync, EditorState}; use toss::{Styled, WidgetExt}; @@ -19,7 +20,7 @@ use self::tree::TreeViewState; use super::UiError; pub trait ChatMsg { - fn time(&self) -> Option; + fn time(&self) -> Option; fn styled(&self) -> (Styled, Styled); fn edit(nick: &str, content: &str) -> (Styled, Styled); fn pseudo(nick: &str, content: &str) -> (Styled, Styled); @@ -41,14 +42,14 @@ pub struct ChatState> { } impl + Clone> ChatState { - pub fn new(store: S) -> Self { + pub fn new(store: S, tz: TimeZone) -> Self { Self { cursor: Cursor::Bottom, editor: EditorState::new(), caesar: 0, mode: Mode::Tree, - tree: TreeViewState::new(store.clone()), + tree: TreeViewState::new(store.clone(), tz), store, } diff --git a/cove/src/ui/chat/tree.rs b/cove/src/ui/chat/tree.rs index 37972e5..b01602c 100644 --- a/cove/src/ui/chat/tree.rs +++ b/cove/src/ui/chat/tree.rs @@ -11,6 +11,7 @@ use std::collections::HashSet; use async_trait::async_trait; use cove_config::Keys; use cove_input::InputEvent; +use jiff::tz::TimeZone; use toss::widgets::EditorState; use toss::{AsyncWidget, Frame, Pos, Size, WidgetExt, WidthDb}; @@ -25,6 +26,7 @@ use super::Reaction; pub struct TreeViewState> { store: S, + tz: TimeZone, last_size: Size, last_nick: String, @@ -36,9 +38,10 @@ pub struct TreeViewState> { } impl> TreeViewState { - pub fn new(store: S) -> Self { + pub fn new(store: S, tz: TimeZone) -> Self { Self { store, + tz, last_size: Size::ZERO, last_nick: String::new(), last_cursor: Cursor::Bottom, @@ -443,6 +446,7 @@ where let mut renderer = TreeRenderer::new( context, &self.state.store, + &self.state.tz, &mut self.state.folded, self.cursor, self.editor, diff --git a/cove/src/ui/chat/tree/renderer.rs b/cove/src/ui/chat/tree/renderer.rs index 8b7b192..845e803 100644 --- a/cove/src/ui/chat/tree/renderer.rs +++ b/cove/src/ui/chat/tree/renderer.rs @@ -4,6 +4,7 @@ use std::collections::HashSet; use std::convert::Infallible; use async_trait::async_trait; +use jiff::tz::TimeZone; use toss::widgets::{EditorState, Empty, Predrawn, Resize}; use toss::{Size, Widget, WidthDb}; @@ -81,6 +82,7 @@ pub struct TreeRenderer<'a, M: Msg, S: MsgStore> { context: TreeContext, store: &'a S, + tz: &'a TimeZone, folded: &'a mut HashSet, cursor: &'a mut Cursor, editor: &'a mut EditorState, @@ -108,6 +110,7 @@ where pub fn new( context: TreeContext, store: &'a S, + tz: &'a TimeZone, folded: &'a mut HashSet, cursor: &'a mut Cursor, editor: &'a mut EditorState, @@ -116,6 +119,7 @@ where Self { context, store, + tz, folded, cursor, editor, @@ -191,7 +195,14 @@ where }; let highlighted = highlighted && self.context.focused; - let widget = widgets::msg(highlighted, indent, msg, self.context.caesar, folded_info); + let widget = widgets::msg( + highlighted, + self.tz.clone(), + indent, + msg, + self.context.caesar, + folded_info, + ); let widget = Self::predraw(widget, self.context.size, self.widthdb); Block::new(TreeBlockId::Msg(msg_id), widget, true) } diff --git a/cove/src/ui/chat/tree/scroll.rs b/cove/src/ui/chat/tree/scroll.rs index 822b0b5..b02c4a1 100644 --- a/cove/src/ui/chat/tree/scroll.rs +++ b/cove/src/ui/chat/tree/scroll.rs @@ -37,6 +37,7 @@ where let mut renderer = TreeRenderer::new( context, &self.store, + &self.tz, &mut self.folded, cursor, editor, @@ -64,6 +65,7 @@ where let mut renderer = TreeRenderer::new( context, &self.store, + &self.tz, &mut self.folded, cursor, editor, diff --git a/cove/src/ui/chat/tree/widgets.rs b/cove/src/ui/chat/tree/widgets.rs index 9eb6690..b302670 100644 --- a/cove/src/ui/chat/tree/widgets.rs +++ b/cove/src/ui/chat/tree/widgets.rs @@ -1,6 +1,7 @@ use std::convert::Infallible; use crossterm::style::Stylize; +use jiff::tz::TimeZone; use toss::widgets::{Boxed, EditorState, Join2, Join4, Join5, Text}; use toss::{Style, Styled, WidgetExt}; @@ -49,6 +50,7 @@ fn style_pseudo_highlight() -> Style { pub fn msg( highlighted: bool, + tz: TimeZone, indent: usize, msg: &M, caesar: i8, @@ -72,7 +74,7 @@ pub fn msg( Join5::horizontal( Seen::new(msg.seen()).segment().with_fixed(true), - Time::new(msg.time(), style_time(highlighted)) + Time::new(msg.time().map(|t| t.to_zoned(tz)), style_time(highlighted)) .padding() .with_right(1) .with_stretch(true) diff --git a/cove/src/ui/chat/widgets.rs b/cove/src/ui/chat/widgets.rs index 5d35e9c..43ad29e 100644 --- a/cove/src/ui/chat/widgets.rs +++ b/cove/src/ui/chat/widgets.rs @@ -1,9 +1,7 @@ use std::convert::Infallible; use crossterm::style::Stylize; -use time::format_description::FormatItem; -use time::macros::format_description; -use time::OffsetDateTime; +use jiff::Zoned; use toss::widgets::{Boxed, Empty, Text}; use toss::{Frame, Pos, Size, Style, Widget, WidgetExt, WidthDb}; @@ -46,15 +44,15 @@ impl Widget for Indent { } } -const TIME_FORMAT: &[FormatItem<'_>] = format_description!("[year]-[month]-[day] [hour]:[minute]"); +const TIME_FORMAT: &str = "%Y-%m-%d %H:%M"; const TIME_WIDTH: u16 = 16; pub struct Time(Boxed<'static, Infallible>); impl Time { - pub fn new(time: Option, style: Style) -> Self { + pub fn new(time: Option, style: Style) -> Self { let widget = if let Some(time) = time { - let text = time.format(TIME_FORMAT).expect("could not format time"); + let text = time.strftime(TIME_FORMAT).to_string(); Text::new((text, style)) .background() .with_style(style) diff --git a/cove/src/ui/euph/room.rs b/cove/src/ui/euph/room.rs index 8fc2fe5..15da008 100644 --- a/cove/src/ui/euph/room.rs +++ b/cove/src/ui/euph/room.rs @@ -6,6 +6,7 @@ use crossterm::style::Stylize; use euphoxide::api::{Data, Message, MessageId, PacketType, SessionId}; use euphoxide::bot::instance::{Event, ServerConfig}; use euphoxide::conn::{self, Joined, Joining, SessionInfo}; +use jiff::tz::TimeZone; use tokio::sync::oneshot::error::TryRecvError; use tokio::sync::{mpsc, oneshot}; use toss::widgets::{BoxedAsync, EditorState, Join2, Layer, Text}; @@ -66,6 +67,7 @@ impl EuphRoom { server_config: ServerConfig, room_config: cove_config::EuphRoom, vault: EuphRoomVault, + tz: TimeZone, ui_event_tx: mpsc::UnboundedSender, ) -> Self { Self { @@ -77,7 +79,7 @@ impl EuphRoom { focus: Focus::Chat, state: State::Normal, popups: VecDeque::new(), - chat: ChatState::new(vault), + chat: ChatState::new(vault, tz), last_msg_sent: None, nick_list: ListState::new(), } diff --git a/cove/src/ui/rooms.rs b/cove/src/ui/rooms.rs index f40bfc5..0157b01 100644 --- a/cove/src/ui/rooms.rs +++ b/cove/src/ui/rooms.rs @@ -13,6 +13,7 @@ use crossterm::style::Stylize; use euphoxide::api::SessionType; use euphoxide::bot::instance::{Event, ServerConfig}; use euphoxide::conn::{self, Joined}; +use jiff::tz::TimeZone; use tokio::sync::mpsc; use toss::widgets::{BoxedAsync, Empty, Join2, Text}; use toss::{Style, Styled, Widget, WidgetExt}; @@ -73,6 +74,7 @@ impl EuphServer { pub struct Rooms { config: &'static Config, + tz: TimeZone, vault: Vault, ui_event_tx: mpsc::UnboundedSender, @@ -89,11 +91,13 @@ pub struct Rooms { impl Rooms { pub async fn new( config: &'static Config, + tz: TimeZone, vault: Vault, ui_event_tx: mpsc::UnboundedSender, ) -> Self { let mut result = Self { config, + tz, vault, ui_event_tx, state: State::ShowList, @@ -142,6 +146,7 @@ impl Rooms { server.config.clone(), self.config.euph_room(&room.domain, &room.name), self.vault.euph().room(room), + self.tz.clone(), self.ui_event_tx.clone(), ) }) @@ -158,6 +163,7 @@ impl Rooms { server.config.clone(), self.config.euph_room(&room.domain, &room.name), self.vault.euph().room(room), + self.tz.clone(), self.ui_event_tx.clone(), ) }); diff --git a/cove/src/util.rs b/cove/src/util.rs index 4844d68..ff8a05a 100644 --- a/cove/src/util.rs +++ b/cove/src/util.rs @@ -1,8 +1,7 @@ use std::convert::Infallible; use std::env; -use time::{OffsetDateTime, UtcOffset}; -use tz::{TimeZone, TzError}; +use jiff::tz::TimeZone; pub trait InfallibleExt { type Inner; @@ -26,27 +25,30 @@ impl InfallibleExt for Result { /// /// If no `TZ` environment variable could be found and no string is provided, /// the system local time (or UTC on Windows) is used. -pub fn load_time_zone(tz_string: Option<&str>) -> Result { +pub fn load_time_zone(tz_string: Option<&str>) -> Result { let env_string = env::var("TZ").ok(); let tz_string = env_string.as_ref().map(|s| s as &str).or(tz_string); - match &tz_string { - // At the moment, TimeZone::from_posix_tz does not support "localtime" - // on Windows, so we handle that case manually. - Some("localtime") | None => TimeZone::local(), - Some(tz_string) => TimeZone::from_posix_tz(tz_string), + let Some(tz_string) = tz_string else { + return Ok(TimeZone::system()); + }; + + if tz_string == "localtime" { + return Ok(TimeZone::system()); } -} -pub fn convert_to_time_zone(tz: &TimeZone, time: OffsetDateTime) -> Option { - let utc_offset_in_seconds = tz - .find_local_time_type(time.unix_timestamp()) - .ok()? - .ut_offset(); + if let Some(tz_string) = tz_string.strip_prefix(':') { + return TimeZone::get(tz_string); + } - let utc_offset = UtcOffset::from_whole_seconds(utc_offset_in_seconds).ok()?; + // The time zone is either a manually specified string or a file in the tz + // database. We'll try to parse it as a manually specified string first + // because that doesn't require a fs lookup. + if let Ok(tz) = TimeZone::posix(tz_string) { + return Ok(tz); + } - Some(time.to_offset(utc_offset)) + TimeZone::get(tz_string) } pub fn caesar(text: &str, by: i8) -> String { diff --git a/cove/src/vault.rs b/cove/src/vault.rs index 55abbf0..6861901 100644 --- a/cove/src/vault.rs +++ b/cove/src/vault.rs @@ -6,7 +6,6 @@ use std::fs; use std::path::Path; use rusqlite::Connection; -use tz::TimeZone; use vault::tokio::TokioVault; use vault::Action; @@ -15,7 +14,6 @@ pub use self::euph::{EuphRoomVault, EuphVault, RoomIdentifier}; #[derive(Debug, Clone)] pub struct Vault { tokio_vault: TokioVault, - time_zone: &'static TimeZone, ephemeral: bool, } @@ -48,23 +46,18 @@ impl Vault { } } -fn launch_from_connection( - conn: Connection, - time_zone: &'static TimeZone, - ephemeral: bool, -) -> rusqlite::Result { +fn launch_from_connection(conn: Connection, ephemeral: bool) -> rusqlite::Result { conn.pragma_update(None, "foreign_keys", true)?; conn.pragma_update(None, "trusted_schema", false)?; let tokio_vault = TokioVault::launch_and_prepare(conn, &migrate::MIGRATIONS, prepare::prepare)?; Ok(Vault { tokio_vault, - time_zone, ephemeral, }) } -pub fn launch(path: &Path, time_zone: &'static TimeZone) -> rusqlite::Result { +pub fn launch(path: &Path) -> rusqlite::Result { // If this fails, rusqlite will complain about not being able to open the db // file, which saves me from adding a separate vault error type. let _ = fs::create_dir_all(path.parent().expect("path to file")); @@ -79,10 +72,10 @@ pub fn launch(path: &Path, time_zone: &'static TimeZone) -> rusqlite::Result rusqlite::Result { +pub fn launch_in_memory() -> rusqlite::Result { let conn = Connection::open_in_memory()?; - launch_from_connection(conn, time_zone, true) + launch_from_connection(conn, true) } diff --git a/cove/src/vault/euph.rs b/cove/src/vault/euph.rs index f922345..c7d6410 100644 --- a/cove/src/vault/euph.rs +++ b/cove/src/vault/euph.rs @@ -6,7 +6,6 @@ use cookie::{Cookie, CookieJar}; use euphoxide::api::{Message, MessageId, SessionId, SessionView, Snowflake, Time, UserId}; use rusqlite::types::{FromSql, FromSqlError, ToSqlOutput, Value, ValueRef}; use rusqlite::{named_params, params, Connection, OptionalExtension, Row, ToSql, Transaction}; -use time::OffsetDateTime; use vault::Action; use crate::euph::SmallMessage; @@ -32,7 +31,7 @@ struct WTime(Time); impl ToSql for WTime { fn to_sql(&self) -> rusqlite::Result> { - let timestamp = self.0 .0.unix_timestamp(); + let timestamp = self.0 .0; Ok(ToSqlOutput::Owned(Value::Integer(timestamp))) } } @@ -40,9 +39,7 @@ impl ToSql for WTime { impl FromSql for WTime { fn column_result(value: ValueRef<'_>) -> rusqlite::types::FromSqlResult { let timestamp = i64::column_result(value)?; - Ok(Self(Time( - OffsetDateTime::from_unix_timestamp(timestamp).expect("timestamp in range"), - ))) + Ok(Self(Time(timestamp))) } } @@ -255,8 +252,6 @@ macro_rules! euph_room_vault_actions { $( struct $struct { room: RoomIdentifier, - #[allow(unused)] - time_zone: &'static tz::TimeZone, $( $arg: $arg_ty, )* } )* @@ -266,7 +261,6 @@ macro_rules! euph_room_vault_actions { pub async fn $fn(&self, $( $arg: $arg_ty, )* ) -> Result<$res, vault::tokio::Error> { self.vault.vault.tokio_vault.execute($struct { room: self.room.clone(), - time_zone: self.vault.vault.time_zone, $( $arg, )* }).await } @@ -626,7 +620,6 @@ impl Action for GetMsg { id: MessageId(row.get::<_, WSnowflake>(0)?.0), parent: row.get::<_, Option>(1)?.map(|s| MessageId(s.0)), time: row.get::<_, WTime>(2)?.0, - time_zone: self.time_zone, nick: row.get(3)?, content: row.get(4)?, seen: row.get(5)?, @@ -720,7 +713,6 @@ impl Action for GetTree { id: MessageId(row.get::<_, WSnowflake>(0)?.0), parent: row.get::<_, Option>(1)?.map(|s| MessageId(s.0)), time: row.get::<_, WTime>(2)?.0, - time_zone: self.time_zone, nick: row.get(3)?, content: row.get(4)?, seen: row.get(5)?,