diff --git a/Cargo.lock b/Cargo.lock index 4e7f4c38..165377ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aho-corasick" @@ -43,41 +43,19 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.95" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" - -[[package]] -name = "async-stream" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.98", -] +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "async-trait" -version = "0.1.86" +version = "0.1.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.104", ] [[package]] @@ -88,17 +66,16 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "axum" -version = "0.7.9" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" +checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5" dependencies = [ - "async-trait", "axum-core", "bytes", "futures-util", @@ -114,20 +91,19 @@ dependencies = [ "rustversion", "serde", "sync_wrapper", - "tower 0.5.2", + "tower", "tower-layer", "tower-service", ] [[package]] name = "axum-core" -version = "0.4.5" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" +checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6" dependencies = [ - "async-trait", "bytes", - "futures-util", + "futures-core", "http", "http-body", "http-body-util", @@ -141,9 +117,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", @@ -162,15 +138,15 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" -version = "2.8.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "bstr" -version = "1.11.3" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" +checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" dependencies = [ "memchr", "serde", @@ -178,27 +154,21 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "bytes" -version = "1.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cc" -version = "1.2.14" +version = "1.2.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3d1b2e905a3a7b00a6141adb0e4c0bb941d11caf55349d863942a1cc44e3c9" +checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" dependencies = [ "shlex", ] @@ -211,22 +181,22 @@ checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "chrono" -version = "0.4.39" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -246,7 +216,7 @@ dependencies = [ "pyo3", "pyo3-build-config", "serde", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tokio-stream", "tonic", @@ -258,13 +228,13 @@ dependencies = [ [[package]] name = "codemp-proto" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69a4d042572106ec01a58676fd57ebfab11b653b26fa46c887580097d90eb191" +version = "0.8.0" +source = "git+https://github.com/hexedtech/codemp-proto?rev=23012c1ddd2c488a923d4c71f1d8a1a7a61f7412#23012c1ddd2c488a923d4c71f1d8a1a7a61f7412" dependencies = [ "prost", "tonic", - "tonic-build", + "tonic-prost", + "tonic-prost-build", "uuid", ] @@ -291,18 +261,18 @@ dependencies = [ [[package]] name = "convert_case" -version = "0.6.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f" dependencies = [ "unicode-segmentation", ] [[package]] name = "core-foundation" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ "core-foundation-sys", "libc", @@ -337,14 +307,20 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "ctor" -version = "0.2.9" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" +checksum = "ec09e802f5081de6157da9a75701d6c713d8dc3ba52571fd4bd25f412644e8a6" dependencies = [ - "quote", - "syn 2.0.98", + "ctor-proc-macro", + "dtor", ] +[[package]] +name = "ctor-proc-macro" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2931af7e13dc045d8e9d26afccc6fa115d64e115c9c84b1166288b46f6782c2" + [[package]] name = "dashmap" version = "6.1.0" @@ -378,11 +354,26 @@ dependencies = [ "str_indices 0.3.2", ] +[[package]] +name = "dtor" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97cbdf2ad6846025e8e25df05171abfb30e3ababa12ee0a0e44b9bbe570633a8" +dependencies = [ + "dtor-proc-macro", +] + +[[package]] +name = "dtor-proc-macro" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7454e41ff9012c00d53cf7f475c5e3afa3b91b7c90568495495e8d9bf47a1055" + [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "encoding_rs" @@ -401,9 +392,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "erased-serde" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" +checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7" dependencies = [ "serde", "typeid", @@ -411,12 +402,12 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.10" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -478,25 +469,25 @@ 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", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", ] [[package]] name = "getrandom" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", - "wasi 0.13.3+wasi-0.2.2", - "windows-targets 0.52.6", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", ] [[package]] @@ -513,9 +504,9 @@ checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "h2" -version = "0.4.7" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" +checksum = "17da50a276f1e01e0ba6c029e47b7100754904ee8a278f886546e98575380785" dependencies = [ "atomic-waker", "bytes", @@ -523,19 +514,13 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.7.1", + "indexmap", "slab", "tokio", "tokio-util", "tracing", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.14.5" @@ -544,9 +529,9 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" [[package]] name = "heck" @@ -556,9 +541,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "http" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", "fnv", @@ -577,12 +562,12 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", - "futures-util", + "futures-core", "http", "http-body", "pin-project-lite", @@ -590,9 +575,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "httpdate" @@ -642,16 +627,18 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.10" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" dependencies = [ "bytes", "futures-channel", + "futures-core", "futures-util", "http", "http-body", "hyper", + "libc", "pin-project-lite", "socket2", "tokio", @@ -661,14 +648,15 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", "windows-core", ] @@ -684,39 +672,40 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - -[[package]] -name = "indexmap" -version = "2.7.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown 0.15.4", ] [[package]] name = "indoc" -version = "2.0.5" +version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" +checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" [[package]] name = "inventory" -version = "0.3.19" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b12ebb6799019b044deaf431eadfe23245b259bba5a2c0796acec3943a3cdb" +checksum = "ab08d7cd2c5897f2c949e5383ea7c7db03fb19130ffcfbf7eda795137ae3cb83" dependencies = [ "rustversion", ] +[[package]] +name = "io-uring" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4" +dependencies = [ + "bitflags", + "cfg-if", + "libc", +] + [[package]] name = "itertools" version = "0.14.0" @@ -728,9 +717,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "java-locator" @@ -784,7 +773,7 @@ checksum = "609491ce00edcf12946945a514d033bf6e8bfbab02c6a25a46ed8cd4749707da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.104", ] [[package]] @@ -815,9 +804,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.169" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libloading" @@ -831,25 +820,25 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.53.3", ] [[package]] name = "linux-raw-sys" -version = "0.4.15" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[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", @@ -857,9 +846,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.25" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "lz4_flex" @@ -872,15 +861,15 @@ dependencies = [ [[package]] name = "matchit" -version = "0.7.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "memoffset" @@ -899,29 +888,29 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.8.4" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", ] [[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", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", ] [[package]] name = "mlua" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3f763c1041eff92ffb5d7169968a327e1ed2ebfe425dac0ee5a35f29082534b" +checksum = "de25fc513588ac1273aa8c6dc0fffee6d32c12f38dc75f5cdc74547121a107ef" dependencies = [ "bstr", "either", @@ -931,15 +920,16 @@ dependencies = [ "num-traits", "parking_lot", "rustc-hash", + "rustversion", "serde", "serde-value", ] [[package]] name = "mlua-sys" -version = "0.6.7" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1901c1a635a22fe9250ffcc4fcc937c16b47c2e9e71adba8784af8bca1f69594" +checksum = "bcdf7c9e260ca82aaa32ac11148941952b856bb8c69aa5a9e65962f21fcb8637" dependencies = [ "cc", "cfg-if", @@ -948,34 +938,35 @@ dependencies = [ [[package]] name = "mlua_derive" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870d71c172fcf491c6b5fb4c04160619a2ee3e5a42a1402269c66bcbf1dd4deb" +checksum = "465bddde514c4eb3b50b543250e97c1d4b284fa3ef7dc0ba2992c77545dbceb2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.104", ] [[package]] name = "multimap" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" +checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" [[package]] name = "napi" -version = "2.16.16" +version = "3.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "839ae2ee5e62c6348669c50098b187c08115bd3cced658c9c0bf945fca0fec83" +checksum = "afaf586c21f260e9dc327ae3585fc6efcbb24a416d5151da38bbd35a1f2663c8" dependencies = [ "bitflags", "chrono", "ctor", "encoding_rs", - "napi-derive", + "napi-build", "napi-sys", - "once_cell", + "nohash-hasher", + "rustc-hash", "serde", "serde_json", "tokio", @@ -983,48 +974,52 @@ dependencies = [ [[package]] name = "napi-build" -version = "2.1.4" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db836caddef23662b94e16bf1f26c40eceb09d6aee5d5b06a7ac199320b69b19" +checksum = "dcae8ad5609d14afb3a3b91dee88c757016261b151e9dcecabf1b2a31a6cab14" [[package]] name = "napi-derive" -version = "2.16.13" +version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cbe2585d8ac223f7d34f13701434b9d5f4eb9c332cccce8dee57ea18ab8ab0c" +checksum = "7e6d190d5e09d449b2b38127cdcdb7aed860599e492a15c73f977d5d87df69a5" dependencies = [ - "cfg-if", "convert_case", + "ctor", "napi-derive-backend", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.104", ] [[package]] name = "napi-derive-backend" -version = "1.0.75" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1639aaa9eeb76e91c6ae66da8ce3e89e921cd3885e99ec85f4abacae72fc91bf" +checksum = "15158ced16693eaa0c709e4c9768ca08eb56325691e68510db8440d27ccd41d1" dependencies = [ "convert_case", - "once_cell", "proc-macro2", "quote", - "regex", "semver", - "syn 2.0.98", + "syn 2.0.104", ] [[package]] name = "napi-sys" -version = "2.4.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "427802e8ec3a734331fec1035594a210ce1ff4dc5bc1950530920ab717964ea3" +checksum = "3e4e7135a8f97aa0f1509cce21a8a1f9dcec1b50d8dee006b48a5adb69a9d64d" dependencies = [ - "libloading 0.8.6", + "libloading 0.8.8", ] +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -1076,9 +1071,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.3" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "openssl-probe" @@ -1103,9 +1098,9 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[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", @@ -1113,9 +1108,9 @@ 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", @@ -1137,27 +1132,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" dependencies = [ "fixedbitset", - "indexmap 2.7.1", + "indexmap", ] [[package]] name = "pin-project" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfe2e71e1471fe07709406bf725f710b02927c9c54b2b5b2ec0e8087d97c327d" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6e859e6e5bd50440ab63c47e3ebabc90f26251f7c73c3d3e837b74a1cc3fa67" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.104", ] [[package]] @@ -1174,33 +1169,33 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "portable-atomic" -version = "1.10.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ "zerocopy", ] [[package]] name = "prettyplease" -version = "0.2.29" +version = "0.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac" +checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2" dependencies = [ "proc-macro2", - "syn 2.0.98", + "syn 2.0.104", ] [[package]] @@ -1215,18 +1210,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.93" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] name = "prost" -version = "0.13.5" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d" dependencies = [ "bytes", "prost-derive", @@ -1234,9 +1229,9 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.13.5" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" +checksum = "ac6c3320f9abac597dcbc668774ef006702672474aad53c6d596b62e487b40b1" dependencies = [ "heck", "itertools", @@ -1247,40 +1242,61 @@ dependencies = [ "prettyplease", "prost", "prost-types", + "pulldown-cmark", + "pulldown-cmark-to-cmark", "regex", - "syn 2.0.98", + "syn 2.0.104", "tempfile", ] [[package]] name = "prost-derive" -version = "0.13.5" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425" dependencies = [ "anyhow", "itertools", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.104", ] [[package]] name = "prost-types" -version = "0.13.5" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" +checksum = "b9b4db3d6da204ed77bb26ba83b6122a73aeb2e87e25fbf7ad2e84c4ccbf8f72" dependencies = [ "prost", ] +[[package]] +name = "pulldown-cmark" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e8bbe1a966bd2f362681a44f6edce3c2310ac21e4d5067a6e7ec396297a6ea0" +dependencies = [ + "bitflags", + "memchr", + "unicase", +] + +[[package]] +name = "pulldown-cmark-to-cmark" +version = "21.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5b6a0769a491a08b31ea5c62494a8f144ee0987d86d670a8af4df1e1b7cde75" +dependencies = [ + "pulldown-cmark", +] + [[package]] name = "pyo3" -version = "0.23.4" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57fe09249128b3173d092de9523eaa75136bf7ba85e0d69eca241c7939c933cc" +checksum = "8970a78afe0628a3e3430376fc5fd76b6b45c4d43360ffd6cdd40bdde72b682a" dependencies = [ - "cfg-if", "indoc", "inventory", "libc", @@ -1295,9 +1311,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.23.4" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd3927b5a78757a0d71aa9dff669f903b1eb64b54142a9bd9f757f8fde65fd7" +checksum = "458eb0c55e7ece017adeba38f2248ff3ac615e53660d7c71a238d7d2a01c7598" dependencies = [ "once_cell", "target-lexicon", @@ -1305,9 +1321,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.23.4" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dab6bb2102bd8f991e7749f130a70d05dd557613e39ed2deeee8e9ca0c4d548d" +checksum = "7114fe5457c61b276ab77c5055f206295b812608083644a5c5b2640c3102565c" dependencies = [ "libc", "pyo3-build-config", @@ -1315,38 +1331,44 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.23.4" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91871864b353fd5ffcb3f91f2f703a22a9797c91b9ab497b1acac7b07ae509c7" +checksum = "a8725c0a622b374d6cb051d11a0983786448f7785336139c3c94f5aa6bef7e50" dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn 2.0.98", + "syn 2.0.104", ] [[package]] name = "pyo3-macros-backend" -version = "0.23.4" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43abc3b80bc20f3facd86cd3c60beed58c3e2aa26213f3cda368de39c60a27e4" +checksum = "4109984c22491085343c05b0dbc54ddc405c3cf7b4374fc533f5c3313a572ccc" dependencies = [ "heck", "proc-macro2", "pyo3-build-config", "quote", - "syn 2.0.98", + "syn 2.0.104", ] [[package]] name = "quote" -version = "1.0.38" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "rand" version = "0.8.5" @@ -1374,14 +1396,14 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", ] [[package]] name = "redox_syscall" -version = "0.5.8" +version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ "bitflags", ] @@ -1417,13 +1439,13 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "ring" -version = "0.17.9" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e75ec5e92c4d8aede845126adc388046234541629e76029599ed35a003c7ed24" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.16", "libc", "untrusted", "windows-sys 0.52.0", @@ -1440,9 +1462,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" [[package]] name = "rustc-hash" @@ -1452,26 +1474,25 @@ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustix" -version = "0.38.44" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "rustls" -version = "0.23.23" +version = "0.23.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395" +checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" dependencies = [ "log", "once_cell", - "ring", "rustls-pki-types", "rustls-webpki", "subtle", @@ -1491,25 +1512,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.102.8" +version = "0.103.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" dependencies = [ "ring", "rustls-pki-types", @@ -1518,15 +1533,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.19" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] name = "ryu" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "same-file" @@ -1577,15 +1592,15 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.25" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" [[package]] name = "serde" -version = "1.0.217" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] @@ -1602,20 +1617,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.104", ] [[package]] name = "serde_json" -version = "1.0.138" +version = "1.0.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" +checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" dependencies = [ "itoa", "memchr", @@ -1640,18 +1655,15 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "slab" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" [[package]] name = "smallvec" -version = "1.14.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "smartstring" @@ -1666,12 +1678,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.8" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1711,9 +1723,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.98" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", @@ -1728,19 +1740,18 @@ checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" [[package]] name = "target-lexicon" -version = "0.12.16" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" +checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" [[package]] name = "tempfile" -version = "3.17.1" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ - "cfg-if", "fastrand", - "getrandom 0.3.1", + "getrandom 0.3.3", "once_cell", "rustix", "windows-sys 0.59.0", @@ -1757,11 +1768,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl 2.0.11", + "thiserror-impl 2.0.12", ] [[package]] @@ -1772,44 +1783,45 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.104", ] [[package]] name = "thiserror-impl" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.104", ] [[package]] name = "thread_local" -version = "1.1.8" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ "cfg-if", - "once_cell", ] [[package]] name = "tokio" -version = "1.43.0" +version = "1.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" +checksum = "43864ed400b6043a4757a25c7a64a8efde741aed79a056a2fb348a406701bb35" dependencies = [ "backtrace", "bytes", + "io-uring", "libc", "mio", "pin-project-lite", + "slab", "socket2", "tokio-macros", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1820,14 +1832,14 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.104", ] [[package]] name = "tokio-rustls" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" dependencies = [ "rustls", "tokio", @@ -1846,9 +1858,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.13" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" dependencies = [ "bytes", "futures-core", @@ -1859,9 +1871,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" [[package]] name = "toml_edit" @@ -1869,18 +1881,17 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.7.1", + "indexmap", "toml_datetime", "winnow", ] [[package]] name = "tonic" -version = "0.12.3" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" +checksum = "308e1db96abdccdf0a9150fb69112bf6ea72640e0bd834ef0c4a618ccc8c8ddc" dependencies = [ - "async-stream", "async-trait", "axum", "base64", @@ -1894,14 +1905,13 @@ dependencies = [ "hyper-util", "percent-encoding", "pin-project", - "prost", "rustls-native-certs", - "rustls-pemfile", "socket2", + "sync_wrapper", "tokio", "tokio-rustls", "tokio-stream", - "tower 0.4.13", + "tower", "tower-layer", "tower-service", "tracing", @@ -1909,36 +1919,41 @@ dependencies = [ [[package]] name = "tonic-build" -version = "0.12.3" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9557ce109ea773b399c9b9e5dca39294110b74f1f342cb347a80d1fce8c26a11" +checksum = "18262cdd13dec66e8e3f2e3fe535e4b2cc706fab444a7d3678d75d8ac2557329" dependencies = [ "prettyplease", "proc-macro2", - "prost-build", - "prost-types", "quote", - "syn 2.0.98", + "syn 2.0.104", ] [[package]] -name = "tower" -version = "0.4.13" +name = "tonic-prost" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +checksum = "2d8b5b7a44512c59f5ad45e0c40e53263cbbf4426d74fe6b569e04f1d4206e9c" dependencies = [ - "futures-core", - "futures-util", - "indexmap 1.9.3", - "pin-project", - "pin-project-lite", - "rand", - "slab", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", + "bytes", + "prost", + "tonic", +] + +[[package]] +name = "tonic-prost-build" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "114cca66d757d72422ef8cccf8be3065321860ac9fa4be73aab37a8a20a9a805" +dependencies = [ + "prettyplease", + "proc-macro2", + "prost-build", + "prost-types", + "quote", + "syn 2.0.104", + "tempfile", + "tonic-build", ] [[package]] @@ -1949,10 +1964,15 @@ checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", + "indexmap", "pin-project-lite", + "slab", "sync_wrapper", + "tokio", + "tokio-util", "tower-layer", "tower-service", + "tracing", ] [[package]] @@ -1980,20 +2000,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.28" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.104", ] [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", "valuable", @@ -2042,15 +2062,21 @@ dependencies = [ [[package]] name = "typeid" -version = "1.0.2" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + +[[package]] +name = "unicase" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-ident" -version = "1.0.16" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-segmentation" @@ -2060,9 +2086,9 @@ checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unindent" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce" +checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3" [[package]] name = "untrusted" @@ -2072,12 +2098,14 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "uuid" -version = "1.13.2" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c1f41ffb7cf259f1ecc2876861a17e7142e63ead296f671f81f6ae85903e0d6" +checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" dependencies = [ - "getrandom 0.3.1", + "getrandom 0.3.3", + "js-sys", "serde", + "wasm-bindgen", ] [[package]] @@ -2113,15 +2141,15 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.13.3+wasi-0.2.2" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" dependencies = [ "wit-bindgen-rt", ] @@ -2148,7 +2176,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.104", "wasm-bindgen-shared", ] @@ -2170,7 +2198,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.104", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2217,11 +2245,61 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.52.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ - "windows-targets 0.52.6", + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link", ] [[package]] @@ -2251,6 +2329,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.3", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -2275,13 +2362,30 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -2294,6 +2398,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -2306,6 +2416,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -2318,12 +2434,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -2336,6 +2464,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -2348,6 +2482,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -2360,6 +2500,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -2372,6 +2518,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winnow" version = "0.5.40" @@ -2383,9 +2535,9 @@ dependencies = [ [[package]] name = "wit-bindgen-rt" -version = "0.33.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ "bitflags", ] @@ -2398,23 +2550,22 @@ checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" [[package]] name = "zerocopy" -version = "0.7.35" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" dependencies = [ - "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.104", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 57cc3281..e2207364 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ authors = [ "cschen " ] license = "GPL-3.0-only" -edition = "2021" +edition = "2024" version = "0.8.5" exclude = ["dist/*"] @@ -25,11 +25,11 @@ thiserror = "2.0" # crdt diamond-types = "1.0" # proto -codemp-proto = "0.7" -uuid = { version = "1.13", features = ["v4"] } -tonic = { version = "0.12", features = ["tls", "tls-roots"] } +codemp-proto = { git = "https://github.com/hexedtech/codemp-proto", rev = "23012c1ddd2c488a923d4c71f1d8a1a7a61f7412", features = ["client"] } +uuid = { version = "1.17", features = ["v4"] } +tonic = { version = "0.14", features = ["tls-native-roots"] } # api -tokio = { version = "1.43", features = ["macros", "rt-multi-thread", "sync"] } +tokio = { version = "1.47", features = ["macros", "rt-multi-thread", "sync"] } xxhash-rust = { version = "0.8", features = ["xxh3"] } # client tokio-stream = "0.1" @@ -43,14 +43,14 @@ jni = { version = "0.21", features = ["invocation"], optional = true } jni-toolbox = { version = "0.2", optional = true, features = ["uuid"] } # glue (lua) -mlua = { version = "0.10", features = ["module", "serialize", "error-send"], optional = true } +mlua = { version = "0.11", features = ["module", "serialize", "error-send"], optional = true } # glue (js) -napi = { version = "2.16", features = ["full"], optional = true } -napi-derive = { version="2.16", optional = true} +napi = { version = "3.1", features = ["full"], optional = true } +napi-derive = { version="3.1", optional = true} # glue (python) -pyo3 = { version = "0.23", features = ["extension-module", "multiple-pymethods"], optional = true} +pyo3 = { version = "0.25", features = ["extension-module", "multiple-pymethods", "uuid"], optional = true} # extra async-trait = { version = "0.1", optional = true } @@ -58,9 +58,9 @@ serde = { version = "1.0", features = ["derive"], optional = true } [build-dependencies] # glue (js) -napi-build = { version = "2.1", optional = true } +napi-build = { version = "2.2", optional = true } # glue (python) -pyo3-build-config = { version = "0.23", optional = true } +pyo3-build-config = { version = "0.25", optional = true } [features] default = ["lua-jit", "py-abi3"] diff --git a/dist/lua/annotations.lua b/dist/lua/annotations.lua index 1b638e10..05726df6 100644 --- a/dist/lua/annotations.lua +++ b/dist/lua/annotations.lua @@ -169,6 +169,39 @@ function UserListPromise:cancel() end ---invoke callback asynchronously as soon as promise is ready function UserListPromise:and_then(cb) end +---@class (exact) WorkspaceInfoPromise : Promise +local WorkspaceInfoPromise = {} +--- block until promise is ready and return value +--- @return WorkspaceInfo +function WorkspaceInfoPromise:await() end +--- cancel promise execution +function WorkspaceInfoPromise:cancel() end +---@param cb fun(x: WorkspaceInfo) callback to invoke +---invoke callback asynchronously as soon as promise is ready +function WorkspaceInfoPromise:and_then(cb) end + +---@class (exact) WorkspaceInfoListPromise : Promise +local WorkspaceInfoListPromise = {} +--- block until promise is ready and return value +--- @return WorkspaceInfo[] +function WorkspaceInfoListPromise:await() end +--- cancel promise execution +function WorkspaceInfoListPromise:cancel() end +---@param cb fun(x: WorkspaceInfo[]) callback to invoke +---invoke callback asynchronously as soon as promise is ready +function WorkspaceInfoListPromise:and_then(cb) end + +---@class (exact) BufferNodeListPromise : Promise +local BufferNodeListPromise = {} +--- block until promise is ready and return value +--- @return BufferNode[] +function BufferNodeListPromise:await() end +--- cancel promise execution +function BufferNodeListPromise:cancel() end +---@param cb fun(x: BufferNode[]) callback to invoke +---invoke callback asynchronously as soon as promise is ready +function BufferNodeListPromise:and_then(cb) end + -- [[ END ASYNC STUFF ]] @@ -198,7 +231,7 @@ function Client:refresh() end function Client:attach_workspace(ws) end ---@param ws string workspace id to create ----@return NilPromise +---@return WorkspaceInfoPromise ---@async ---@nodiscard ---create a new workspace with given id @@ -223,13 +256,13 @@ function Client:delete_workspace(ws) end ---grant user acccess to workspace function Client:invite_to_workspace(ws, user) end ----@return StringArrayPromise +---@return WorkspaceInfoListPromise ---@async ---@nodiscard ---fetch and list owned workspaces function Client:fetch_owned_workspaces() end ----@return StringArrayPromise +---@return WorkspaceInfoListPromise ---@async ---@nodiscard ---fetch and list joined workspaces @@ -243,10 +276,18 @@ function Client:get_workspace(ws) end ---@class User +---represents a service user and contains all its relevant info ---@field id string user uuid ---@field name string user display name +---@class WorkspaceInfo +---represents informations about a workspace, without having an handle to it +---@field id string +---@field name string +---@field owner User + + ---@class (exact) Workspace ---a joined codemp workspace @@ -265,11 +306,12 @@ function Workspace:active_buffers() end function Workspace:cursor() end ---@param path string relative path ("name") of new buffer +---@param ephemeral boolean wether this buffer is ephemeral (auto deletes) ---@return NilPromise ---@async ---@nodiscard ---create a new empty buffer -function Workspace:create_buffer(path) end +function Workspace:create_buffer(path, ephemeral) end ---@param path string relative path ("name") of buffer to delete ---@return NilPromise @@ -304,11 +346,12 @@ function Workspace:search_buffers(filter) end ---return all names of users currently in this workspace function Workspace:user_list() end ----@return NilPromise +---@param filter string filter buffers we want to fetch relative to this path +---@return BufferNodeListPromise ---@async ---@nodiscard ---force refresh buffer list from workspace -function Workspace:fetch_buffers(path) end +function Workspace:list_buffers(filter) end ---@return NilPromise ---@async @@ -356,6 +399,13 @@ function Workspace:callback(cb) end +---@class BufferNode +---@field id string +---@field name string +---@field owner User + + + ---@class (exact) BufferController ---handle to a remote buffer, for async send/recv operations local BufferController = {} diff --git a/dist/py/src/codemp/codemp.pyi b/dist/py/src/codemp/codemp.pyi index f383f044..eeda90e4 100644 --- a/dist/py/src/codemp/codemp.pyi +++ b/dist/py/src/codemp/codemp.pyi @@ -1,4 +1,5 @@ from typing import Optional, Callable +from uuid import uuid4, UUID def version() -> str: ... @@ -49,15 +50,15 @@ class Client: Handle to the actual client that manages the session. It manages the connection to a server and joining/creating new workspaces """ - def attach_workspace(self, workspace: str) -> Promise[Workspace]: ... + def attach_workspace(self, workspace: UUID) -> Promise[Workspace]: ... def create_workspace(self, workspace: str) -> Promise[None]: ... def delete_workspace(self, workspace: str) -> Promise[None]: ... def invite_to_workspace(self, workspace: str, username: str) -> Promise[None]: ... def fetch_owned_workspaces(self) -> Promise[list[str]]: ... def fetch_joined_workspaces(self) -> Promise[list[str]]: ... - def leave_workspace(self, workspace: str) -> bool: ... - def get_workspace(self, id: str) -> Workspace: ... - def active_workspaces(self) -> list[str]: ... + def leave_workspace(self, workspace: UUID) -> bool: ... + def get_workspace(self, id: UUID) -> Workspace: ... + def active_workspaces(self) -> list[UUID]: ... def current_user(self) -> User: ... def refresh(self) -> Promise[None]: ... @@ -93,12 +94,12 @@ class Workspace: Handle to a workspace inside codemp. It manages buffers. A cursor is tied to the single workspace. """ - def create_buffer(self, path: str) -> Promise[None]: ... + def create_buffer(self, path: str, ephemeral: str) -> Promise[None]: ... def attach_buffer(self, path: str) -> Promise[BufferController]: ... def detach_buffer(self, path: str) -> bool: ... - def fetch_buffers(self) -> Promise[list[str]]: ... - def fetch_users(self) -> Promise[list[User]]: ... - def fetch_buffer_users(self, path: str) -> Promise[list[User]]: ... + def list_buffers(self, filter: str) -> Promise[list[str]]: ... + def list_users(self) -> Promise[list[User]]: ... + def list_buffer_users(self, path: str) -> Promise[list[User]]: ... def delete_buffer(self, path: str) -> Promise[None]: ... def id(self) -> str: ... def cursor(self) -> CursorController: ... diff --git a/src/api/buffer.rs b/src/api/buffer.rs new file mode 100644 index 00000000..9f834045 --- /dev/null +++ b/src/api/buffer.rs @@ -0,0 +1,22 @@ +//! # Buffer +//! TODO TODO TODO + +/// Represents a service buffer +#[derive(Debug, Clone)] +#[cfg_attr(feature = "py", pyo3::pyclass)] +#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +pub struct BufferNode { + /// Buffer path, sort of like a UNIX path. + pub path: String, + /// Wether this buffer gets auto-deleted once all users left + pub ephemeral: bool, +} + +impl From for BufferNode { + fn from(value: codemp_proto::files::BufferNode) -> Self { + Self { + path: value.path, + ephemeral: value.ephemeral, + } + } +} diff --git a/src/api/config.rs b/src/api/config.rs index 8cfea00c..09e15707 100644 --- a/src/api/config.rs +++ b/src/api/config.rs @@ -68,8 +68,9 @@ impl Config { impl std::fmt::Debug for Config { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if f.alternate() { - write!(f, -r#"""Config {{ + write!( + f, + r#"""Config {{ username: {}, password: ********, host: {:#?}, @@ -79,7 +80,11 @@ r#"""Config {{ self.username, self.host, self.port, self.tls ) } else { - write!(f, "Config {{ username: {}, password: ********, host: {:?}, port: {:?}, tls: {:?} }}", self.username, self.host, self.port, self.tls) + write!( + f, + "Config {{ username: {}, password: ********, host: {:?}, port: {:?}, tls: {:?} }}", + self.username, self.host, self.port, self.tls + ) } } } diff --git a/src/api/cursor.rs b/src/api/cursor.rs index 42dcad35..a9eed4e6 100644 --- a/src/api/cursor.rs +++ b/src/api/cursor.rs @@ -10,11 +10,25 @@ use pyo3::prelude::*; #[cfg_attr(feature = "py", pyclass(get_all))] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] // #[cfg_attr(feature = "py", pyo3(crate = "reexported::pyo3"))] -pub struct Cursor { +pub struct CursorEvent { /// User who sent the cursor. pub user: String, + /// Cursor position data + pub cursor: Cursor, +} + + +/// An event that occurred about a user's cursor. +#[derive(Clone, Debug, Default)] +#[cfg_attr(feature = "js", napi_derive::napi(object))] +#[cfg_attr(feature = "py", pyclass(get_all))] +#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +// #[cfg_attr(feature = "py", pyo3(crate = "reexported::pyo3"))] +pub struct Cursor { + /// Path of buffer this cursor is on + pub buffer: String, /// The updated cursor selection. - pub sel: Selection, + pub sel: Vec, } /// A cursor selection span. @@ -32,6 +46,4 @@ pub struct Selection { pub end_row: i32, /// Cursor position final column in buffer. pub end_col: i32, - /// Path of buffer this cursor is on. - pub buffer: String, } diff --git a/src/api/mod.rs b/src/api/mod.rs index 9e27c22a..43bea9ef 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -13,15 +13,23 @@ pub mod config; /// representation for an user's cursor pub mod cursor; +/// representation of remote buffers +pub mod buffer; + /// live events in workspaces pub mod event; /// data structure for remote users pub mod user; +/// data structure for workspaces +pub mod workspace; + +pub use buffer::BufferNode; pub use change::{BufferUpdate, TextChange}; pub use config::Config; pub use controller::{AsyncReceiver, AsyncSender, Controller}; pub use cursor::{Cursor, Selection}; pub use event::Event; pub use user::User; +pub use workspace::WorkspaceInfo; diff --git a/src/api/workspace.rs b/src/api/workspace.rs new file mode 100644 index 00000000..61e47fc8 --- /dev/null +++ b/src/api/workspace.rs @@ -0,0 +1,31 @@ +//! # Workspace +//! A workspace is a working environment containing many buffers, owned by one user. +//! Many users can be invited and join a workspace, accessing its buffer list and being able to +//! attach to its buffers (depending on permissions) to send changes. Workspaces are namespaced to +//! users, meaning two workspaces with the same name can exist, but one user can own only one +//! workspace with a given name. + +use uuid::Uuid; + +/// Represents a service workspace +#[derive(Debug, Clone)] +#[cfg_attr(feature = "py", pyo3::pyclass)] +#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +pub struct WorkspaceInfo { + /// Workspace unique identifier, should never change. + pub id: Uuid, + /// Workspace name, cannot change and is unique per owner. + pub name: String, + /// Workspace owning user + pub owner: super::User, +} + +impl From for WorkspaceInfo { + fn from(value: codemp_proto::common::WorkspaceInfo) -> Self { + Self { + id: Uuid::from(value.id), + name: value.name, + owner: super::User::from(value.owner), + } + } +} diff --git a/src/buffer/controller.rs b/src/buffer/controller.rs index 9f1a9d13..13b5005e 100644 --- a/src/buffer/controller.rs +++ b/src/buffer/controller.rs @@ -6,9 +6,9 @@ use std::sync::Arc; use diamond_types::LocalVersion; use tokio::sync::{mpsc, oneshot, watch}; -use crate::api::controller::{AsyncReceiver, AsyncSender, Controller, ControllerCallback}; use crate::api::BufferUpdate; use crate::api::TextChange; +use crate::api::controller::{AsyncReceiver, AsyncSender, Controller, ControllerCallback}; use crate::errors::ControllerResult; use crate::ext::IgnorableError; diff --git a/src/buffer/worker.rs b/src/buffer/worker.rs index 9b6b434a..67ec5463 100644 --- a/src/buffer/worker.rs +++ b/src/buffer/worker.rs @@ -1,15 +1,15 @@ use std::sync::Arc; +use diamond_types::LocalVersion; use diamond_types::list::encoding::ENCODE_PATCH; use diamond_types::list::{Branch, OpLog}; -use diamond_types::LocalVersion; use tokio::sync::{mpsc, oneshot, watch}; use tonic::Streaming; use uuid::Uuid; -use crate::api::controller::ControllerCallback; use crate::api::BufferUpdate; use crate::api::TextChange; +use crate::api::controller::ControllerCallback; use crate::ext::IgnorableError; use codemp_proto::buffer::{BufferEvent, Operation}; @@ -41,7 +41,7 @@ impl BufferController { path: &str, tx: mpsc::Sender, rx: Streaming, - workspace_id: &str, + workspace_id: Uuid, ) -> Self { let init = diamond_types::LocalVersion::default(); diff --git a/src/client.rs b/src/client.rs index 0df972c2..d535227b 100644 --- a/src/client.rs +++ b/src/client.rs @@ -17,9 +17,11 @@ use crate::{ workspace::Workspace, }; use codemp_proto::{ - auth::{auth_client::AuthClient, LoginRequest}, - common::{Empty, Token}, - session::{session_client::SessionClient, InviteRequest, WorkspaceRequest}, + auth::{LoginRequest, auth_client::AuthClient}, + common::{Empty, Identifier, Token}, + session::{ + InviteRequest, OwnedWorkspaceRequest, WorkspaceRequest, session_client::SessionClient, + }, }; #[cfg(feature = "py")] @@ -39,7 +41,7 @@ pub struct Client(Arc); struct ClientInner { user: Arc, config: crate::api::Config, - workspaces: DashMap, + workspaces: DashMap, auth: AuthClient, session: SessionClient>, claims: InternallyMutable, @@ -91,15 +93,20 @@ impl Client { } /// Attempt to create a new workspace with given name. - pub async fn create_workspace(&self, name: impl AsRef) -> RemoteResult<()> { - self.0 + pub async fn create_workspace( + &self, + name: impl AsRef, + ) -> RemoteResult { + let info = self + .0 .session .clone() - .create_workspace(WorkspaceRequest { - workspace: name.as_ref().to_string(), + .create_workspace(OwnedWorkspaceRequest { + name: name.as_ref().to_string(), }) - .await?; - Ok(()) + .await? + .into_inner(); + Ok(crate::api::WorkspaceInfo::from(info)) } /// Delete an existing workspace if possible. @@ -107,8 +114,8 @@ impl Client { self.0 .session .clone() - .delete_workspace(WorkspaceRequest { - workspace: name.as_ref().to_string(), + .delete_workspace(OwnedWorkspaceRequest { + name: name.as_ref().to_string(), }) .await?; Ok(()) @@ -132,82 +139,104 @@ impl Client { } /// Fetch the names of all workspaces owned by the current user. - pub async fn fetch_owned_workspaces(&self) -> RemoteResult> { - self.fetch_workspaces(true).await + pub async fn fetch_owned_workspaces(&self) -> RemoteResult> { + Ok(self + .0 + .session + .clone() + .fetch_owned_workspaces(Empty {}) + .await? + .into_inner() + .owned + .into_iter() + .map(|x| crate::api::WorkspaceInfo::from(x)) + .collect()) } /// Fetch the names of all workspaces the current user has joined. - pub async fn fetch_joined_workspaces(&self) -> RemoteResult> { - self.fetch_workspaces(false).await - } - - async fn fetch_workspaces(&self, owned: bool) -> RemoteResult> { - let workspaces = self + pub async fn fetch_joined_workspaces(&self) -> RemoteResult> { + Ok(self .0 .session .clone() - .list_workspaces(Empty {}) + .fetch_invited_workspaces(Empty {}) .await? - .into_inner(); - - if owned { - Ok(workspaces.owned) - } else { - Ok(workspaces.invited) - } + .into_inner() + .invited + .into_iter() + .map(|x| crate::api::WorkspaceInfo::from(x)) + .collect()) } /// Join and return a [`Workspace`]. - #[tracing::instrument(skip(self, workspace), fields(ws = workspace.as_ref()))] - pub async fn attach_workspace( - &self, - workspace: impl AsRef, - ) -> ConnectionResult { - let token = self - .0 - .session - .clone() - .access_workspace(WorkspaceRequest { - workspace: workspace.as_ref().to_string(), + #[tracing::instrument(skip(self, workspace), fields(ws = %workspace))] + pub async fn attach_workspace(&self, workspace: uuid::Uuid) -> ConnectionResult { + let mut session_client = self.0.session.clone(); + let token = session_client + .get_workspace_token(WorkspaceRequest { + id: Identifier::from(workspace), }) .await? .into_inner(); + let workspace_claims = InternallyMutable::new(token); + let ws = Workspace::connect( - workspace.as_ref().to_string(), + workspace, self.0.user.clone(), self.0.config.clone(), - token, + workspace_claims.channel(), self.0.claims.channel(), ) .await?; - - self.0 - .workspaces - .insert(workspace.as_ref().to_string(), ws.clone()); + self.0.workspaces.insert(workspace, ws.clone()); + let mut workspace_client = ws.services().ws(); + + let weak = Arc::downgrade(&ws.0); + tokio::spawn(async move { + let fut = async move { + loop { + // TODO either configurable token refresh time or calculate depending on token lifetime + tokio::time::sleep(std::time::Duration::from_secs(240)).await; + if weak.upgrade().is_none() { break }; + let new_credentials = session_client.get_workspace_token( + tonic::Request::new(WorkspaceRequest { id: Identifier::from(workspace) }) + ) + .await? + .into_inner(); + workspace_claims.set(new_credentials); + workspace_client.keep_alive(tonic::Request::new(Empty {})).await?; + } + Ok::<(), tonic::Status>(()) + }; + + if let Err(e) = fut.await { + tracing::error!("error in keepalive task for workspace {workspace}: {e}"); + } + }); Ok(ws) } /// Leave the [`Workspace`] with the given name. - pub fn leave_workspace(&self, id: &str) -> bool { - match self.0.workspaces.remove(id) { + pub fn leave_workspace(&self, id: uuid::Uuid) -> bool { + match self.0.workspaces.remove(&id) { None => true, Some(x) => x.1.consume(), } } /// Gets a [`Workspace`] handle by name. - pub fn get_workspace(&self, id: &str) -> Option { - self.0.workspaces.get(id).map(|x| x.clone()) + pub fn get_workspace(&self, id: uuid::Uuid) -> Option { + self.0.workspaces.get(&id).map(|x| x.clone()) } /// Get the names of all active [`Workspace`]s. - pub fn active_workspaces(&self) -> Vec { + pub fn active_workspaces(&self) -> Vec { self.0 .workspaces .iter() - .map(|x| x.key().to_string()) + .map(|x| *x.key()) .collect() } diff --git a/src/cursor/controller.rs b/src/cursor/controller.rs index d0c544c5..a4bb786a 100644 --- a/src/cursor/controller.rs +++ b/src/cursor/controller.rs @@ -7,15 +7,11 @@ use tokio::sync::{mpsc, oneshot, watch}; use crate::{ api::{ - controller::{AsyncReceiver, AsyncSender, ControllerCallback}, - Controller, Cursor, Selection, + controller::{AsyncReceiver, AsyncSender, ControllerCallback}, cursor::CursorEvent, Controller, Cursor }, errors::ControllerResult, }; -use codemp_proto::{ - cursor::{CursorPosition, RowCol}, - files::BufferNode, -}; +use codemp_proto::cursor::{CursorPosition, CursorUpdate, RowCol}; /// A [Controller] for asynchronously sending and receiving [Cursor] event. /// @@ -33,45 +29,50 @@ impl CursorController { #[derive(Debug)] pub(crate) struct CursorControllerInner { - pub(crate) op: mpsc::UnboundedSender, - pub(crate) stream: mpsc::Sender>>, + pub(crate) op: mpsc::UnboundedSender, + pub(crate) stream: mpsc::Sender>>, pub(crate) poll: mpsc::UnboundedSender>, pub(crate) callback: watch::Sender>>, pub(crate) workspace_id: String, } #[cfg_attr(feature = "async-trait", async_trait::async_trait)] -impl Controller for CursorController {} +impl Controller for CursorController {} #[cfg_attr(feature = "async-trait", async_trait::async_trait)] -impl AsyncSender for CursorController { - fn send(&self, mut cursor: Selection) -> ControllerResult<()> { - if cursor.start_row > cursor.end_row - || (cursor.start_row == cursor.end_row && cursor.start_col > cursor.end_col) - { - std::mem::swap(&mut cursor.start_row, &mut cursor.end_row); - std::mem::swap(&mut cursor.start_col, &mut cursor.end_col); +impl AsyncSender for CursorController { + fn send(&self, mut cursor: Cursor) -> ControllerResult<()> { + for sel in cursor.sel.iter_mut() { + if sel.start_row > sel.end_row + || (sel.start_row == sel.end_row && sel.start_col > sel.end_col) + { + std::mem::swap(&mut sel.start_row, &mut sel.end_row); + std::mem::swap(&mut sel.start_col, &mut sel.end_col); + } } - Ok(self.0.op.send(CursorPosition { - buffer: BufferNode { - path: cursor.buffer, - }, - start: RowCol { - row: cursor.start_row, - col: cursor.start_col, - }, - end: RowCol { - row: cursor.end_row, - col: cursor.end_col, - }, + Ok(self.0.op.send(CursorUpdate { + buffer: cursor.buffer, + cursors: cursor.sel + .into_iter() + .map(|x| CursorPosition { + start: RowCol { + row: x.start_row, + col: x.start_col, + }, + end: RowCol { + row: x.end_row, + col: x.end_col, + } + }) + .collect() })?) } } #[cfg_attr(feature = "async-trait", async_trait::async_trait)] -impl AsyncReceiver for CursorController { - async fn try_recv(&self) -> ControllerResult> { +impl AsyncReceiver for CursorController { + async fn try_recv(&self) -> ControllerResult> { let (tx, rx) = oneshot::channel(); self.0.stream.send(tx).await?; Ok(rx.await?) diff --git a/src/cursor/worker.rs b/src/cursor/worker.rs index 2e6e62ea..368c4352 100644 --- a/src/cursor/worker.rs +++ b/src/cursor/worker.rs @@ -5,18 +5,18 @@ use tonic::Streaming; use uuid::Uuid; use crate::{ - api::{controller::ControllerCallback, Cursor, Selection, User}, + api::{Cursor, Selection, User, controller::ControllerCallback}, ext::IgnorableError, }; -use codemp_proto::cursor::{CursorEvent, CursorPosition}; +use codemp_proto::cursor::{CursorEvent, CursorUpdate}; use super::controller::{CursorController, CursorControllerInner}; struct CursorWorker { workspace_id: String, - op: mpsc::UnboundedReceiver, + op: mpsc::UnboundedReceiver, map: Arc>, - stream: mpsc::Receiver>>, + stream: mpsc::Receiver>>, poll: mpsc::UnboundedReceiver>, pollers: Vec>, store: std::collections::VecDeque, @@ -26,36 +26,42 @@ struct CursorWorker { impl CursorWorker { #[tracing::instrument(skip(self, tx))] - fn handle_recv(&mut self, tx: oneshot::Sender>) { - tx.send( - self.store.pop_front().and_then(|event| { - let user_id = Uuid::from(event.user); - if let Some(user_name) = self.map.get(&user_id).map(|u| u.name.clone()) { - Some(Cursor { - user: user_name, - sel: Selection { - buffer: event.position.buffer.path, - start_row: event.position.start.row, - start_col: event.position.start.col, - end_row: event.position.end.row, - end_col: event.position.end.col - } - }) - } else { - tracing::warn!("received cursor for unknown user {user_id}"); - None - } - }) - ).unwrap_or_warn("client gave up receiving!"); + fn handle_recv(&mut self, tx: oneshot::Sender>) { + tx.send(self.store.pop_front().and_then(|event| { + let user_id = Uuid::from(event.user); + if let Some(user_name) = self.map.get(&user_id).map(|u| u.name.clone()) { + Some(crate::api::cursor::CursorEvent { + user: user_name, + cursor: Cursor { + buffer: event.position.buffer, + sel: event + .position + .cursors + .into_iter() + .map(|x| Selection { + start_row: x.start.row, + start_col: x.start.col, + end_row: x.end.row, + end_col: x.end.col, + }) + .collect(), + } + }) + } else { + tracing::warn!("received cursor for unknown user {user_id}"); + None + } + })) + .unwrap_or_warn("client gave up receiving!"); } } impl CursorController { pub(crate) fn spawn( user_map: Arc>, - tx: mpsc::Sender, + tx: mpsc::Sender, rx: Streaming, - workspace_id: &str, + workspace_id: Uuid, ) -> Self { // TODO we should tweak the channel buffer size to better propagate backpressure let (op_tx, op_rx) = mpsc::unbounded_channel(); @@ -92,7 +98,7 @@ impl CursorController { #[tracing::instrument(skip(worker, tx, rx), fields(ws = worker.workspace_id))] async fn work( mut worker: CursorWorker, - tx: mpsc::Sender, + tx: mpsc::Sender, mut rx: Streaming, ) { tracing::debug!("starting cursor worker"); diff --git a/src/ext.rs b/src/ext.rs index 32a6594f..ab7e57a9 100644 --- a/src/ext.rs +++ b/src/ext.rs @@ -115,3 +115,9 @@ where } } } + +pub(crate) fn token_to_metadata(tok: codemp_proto::common::Token) -> tonic::Result> { + tonic::metadata::MetadataValue::try_from(tok.token).map_err(|e| { + tonic::Status::internal(format!("failed representing token to string: {e}")) + }) +} diff --git a/src/ffi/java/buffer.rs b/src/ffi/java/buffer.rs index edd7b9a3..e30a6718 100644 --- a/src/ffi/java/buffer.rs +++ b/src/ffi/java/buffer.rs @@ -1,4 +1,4 @@ -use jni::{objects::JObject, JNIEnv}; +use jni::{JNIEnv, objects::JObject}; use jni_toolbox::jni; use crate::{ diff --git a/src/ffi/java/client.rs b/src/ffi/java/client.rs index 230b26a1..ecd392f6 100644 --- a/src/ffi/java/client.rs +++ b/src/ffi/java/client.rs @@ -1,8 +1,8 @@ use crate::{ + Workspace, api::Config, client::Client, errors::{ConnectionError, RemoteError}, - Workspace, }; use jni_toolbox::jni; diff --git a/src/ffi/java/cursor.rs b/src/ffi/java/cursor.rs index 4457ddcc..60dae442 100644 --- a/src/ffi/java/cursor.rs +++ b/src/ffi/java/cursor.rs @@ -2,7 +2,7 @@ use crate::{ api::{AsyncReceiver, AsyncSender, Cursor, Selection}, errors::ControllerError, }; -use jni::{objects::JObject, JNIEnv}; +use jni::{JNIEnv, objects::JObject}; use jni_toolbox::jni; use super::null_check; diff --git a/src/ffi/java/mod.rs b/src/ffi/java/mod.rs index 80ac0289..bd88f7ab 100644 --- a/src/ffi/java/mod.rs +++ b/src/ffi/java/mod.rs @@ -26,7 +26,7 @@ pub(crate) fn jvm() -> std::sync::Arc { /// Called upon initialisation of the JVM. #[allow(non_snake_case)] -#[no_mangle] +#[unsafe(no_mangle)] pub extern "system" fn JNI_OnLoad(vm: jni::JavaVM, _: *mut std::ffi::c_void) -> jni::sys::jint { unsafe { JVM = Some(std::sync::Arc::new(vm)) }; jni::sys::JNI_VERSION_1_1 @@ -320,23 +320,25 @@ impl<'j> jni_toolbox::FromJava<'j> for crate::api::Config { config: Self::From, ) -> Result { let username = { - let jfield = env + let jfield: jni::objects::JString<'j> = env .get_field(&config, "username", "Ljava/lang/String;")? - .l()?; + .l()? + .into(); if jfield.is_null() { return Err(jni::errors::Error::NullPtr("Username can never be null!")); } - unsafe { env.get_string_unchecked(&jfield.into()) }?.into() + unsafe { env.get_string_unchecked(&jfield) }?.into() }; let password = { - let jfield = env + let jfield: jni::objects::JString<'j> = env .get_field(&config, "password", "Ljava/lang/String;")? - .l()?; + .l()? + .into(); if jfield.is_null() { return Err(jni::errors::Error::NullPtr("Password can never be null!")); } - unsafe { env.get_string_unchecked(&jfield.into()) }?.into() + unsafe { env.get_string_unchecked(&jfield) }?.into() }; let host = { @@ -346,8 +348,9 @@ impl<'j> jni_toolbox::FromJava<'j> for crate::api::Config { if env.call_method(&jfield, "isPresent", "()Z", &[])?.z()? { let field = env .call_method(&jfield, "get", "()Ljava/lang/Object;", &[])? - .l()?; - Some(unsafe { env.get_string_unchecked(&field.into()) }?.into()) + .l()? + .into(); + Some(unsafe { env.get_string_unchecked(&field) }?.into()) } else { None } @@ -412,13 +415,14 @@ impl<'j> jni_toolbox::FromJava<'j> for crate::api::Selection { let end_col = env.get_field(&cursor, "endCol", "I")?.i()?; let buffer = { - let jfield = env + let jfield: jni::objects::JString<'j> = env .get_field(&cursor, "buffer", "Ljava/lang/String;")? - .l()?; + .l()? + .into(); if jfield.is_null() { return Err(jni::errors::Error::NullPtr("Buffer can never be null!")); } - unsafe { env.get_string_unchecked(&jfield.into()) }?.into() + unsafe { env.get_string_unchecked(&jfield) }?.into() }; Ok(Self { @@ -447,13 +451,14 @@ impl<'j> jni_toolbox::FromJava<'j> for crate::api::TextChange { .clamp(0, u32::MAX.into()) as u32; let content = { - let jfield = env + let jfield: jni::objects::JString<'j> = env .get_field(&change, "content", "Ljava/lang/String;")? - .l()?; + .l()? + .into(); if jfield.is_null() { return Err(jni::errors::Error::NullPtr("Content can never be null!")); } - unsafe { env.get_string_unchecked(&jfield.into()) }?.into() + unsafe { env.get_string_unchecked(&jfield) }?.into() }; Ok(Self { diff --git a/src/ffi/java/workspace.rs b/src/ffi/java/workspace.rs index 3548a926..42174cb2 100644 --- a/src/ffi/java/workspace.rs +++ b/src/ffi/java/workspace.rs @@ -1,10 +1,10 @@ use crate::{ - api::{controller::AsyncReceiver, User}, + Workspace, + api::{User, controller::AsyncReceiver}, errors::{ConnectionError, ControllerError, RemoteError}, ffi::java::null_check, - Workspace, }; -use jni::{objects::JObject, JNIEnv}; +use jni::{JNIEnv, objects::JObject}; use jni_toolbox::jni; /// Get the workspace id. diff --git a/src/ffi/js/buffer.rs b/src/ffi/js/buffer.rs index 79f10719..ae3742aa 100644 --- a/src/ffi/js/buffer.rs +++ b/src/ffi/js/buffer.rs @@ -2,7 +2,7 @@ use crate::api::controller::{AsyncReceiver, AsyncSender}; use crate::api::{BufferUpdate, TextChange}; use crate::buffer::controller::BufferController; use napi::threadsafe_function::{ - ErrorStrategy::Fatal, ThreadSafeCallContext, ThreadsafeFunction, ThreadsafeFunctionCallMode, + ThreadsafeFunction, ThreadsafeFunctionCallMode, }; use napi_derive::napi; @@ -14,16 +14,9 @@ impl BufferController { js_name = "callback", ts_args_type = "fun: (event: BufferController) => void" )] - pub fn js_callback(&self, fun: napi::JsFunction) -> napi::Result<()> { - let tsfn: ThreadsafeFunction = fun - .create_threadsafe_function( - 0, - |ctx: ThreadSafeCallContext| { - Ok(vec![ctx.value]) - }, - )?; + pub fn js_callback(&self, fun: ThreadsafeFunction) -> napi::Result<()> { self.callback(move |controller: BufferController| { - tsfn.call(controller.clone(), ThreadsafeFunctionCallMode::Blocking); + fun.call(Ok(controller.clone()), ThreadsafeFunctionCallMode::Blocking); //check this with tracing also we could use Ok(event) to get the error // If it blocks the main thread too many time we have to change this }); diff --git a/src/ffi/js/cursor.rs b/src/ffi/js/cursor.rs index eb173ad3..fc14ad0b 100644 --- a/src/ffi/js/cursor.rs +++ b/src/ffi/js/cursor.rs @@ -1,9 +1,6 @@ use crate::api::controller::{AsyncReceiver, AsyncSender}; use crate::cursor::controller::CursorController; -use napi::threadsafe_function::ErrorStrategy::Fatal; -use napi::threadsafe_function::{ - ThreadSafeCallContext, ThreadsafeFunction, ThreadsafeFunctionCallMode, -}; +use napi::threadsafe_function::{ ThreadsafeFunction, ThreadsafeFunctionCallMode}; use napi_derive::napi; #[napi] @@ -14,16 +11,9 @@ impl CursorController { js_name = "callback", ts_args_type = "fun: (event: CursorController) => void" )] - pub fn js_callback(&self, fun: napi::JsFunction) -> napi::Result<()> { - let tsfn: ThreadsafeFunction = fun - .create_threadsafe_function( - 0, - |ctx: ThreadSafeCallContext| { - Ok(vec![ctx.value]) - }, - )?; + pub fn js_callback(&self, fun: ThreadsafeFunction) -> napi::Result<()> { self.callback(move |controller: CursorController| { - tsfn.call(controller.clone(), ThreadsafeFunctionCallMode::Blocking); + fun.call(Ok(controller.clone()), ThreadsafeFunctionCallMode::Blocking); //check this with tracing also we could use Ok(event) to get the error // If it blocks the main thread too many time we have to change this }); diff --git a/src/ffi/js/workspace.rs b/src/ffi/js/workspace.rs index e862322c..a46e70a1 100644 --- a/src/ffi/js/workspace.rs +++ b/src/ffi/js/workspace.rs @@ -1,11 +1,8 @@ +use crate::Workspace; use crate::api::controller::AsyncReceiver; use crate::buffer::controller::BufferController; use crate::cursor::controller::CursorController; -use crate::Workspace; -use napi::threadsafe_function::ErrorStrategy::Fatal; -use napi::threadsafe_function::{ - ThreadSafeCallContext, ThreadsafeFunction, ThreadsafeFunctionCallMode, -}; +use napi::threadsafe_function::{ThreadsafeFunction, ThreadsafeFunctionCallMode}; use napi_derive::napi; use super::client::JsUser; @@ -45,8 +42,8 @@ impl Workspace { /// List all available buffers in this workspace #[napi(js_name = "searchBuffers")] - pub fn js_search_buffers(&self, filter: Option<&str>) -> Vec { - self.search_buffers(filter) + pub fn js_search_buffers(&self, filter: Option) -> Vec { + self.search_buffers(filter.as_deref()) } /// List all user names currently in this workspace @@ -114,14 +111,11 @@ impl Workspace { } #[napi(js_name = "callback", ts_args_type = "fun: (event: Workspace) => void")] - pub fn js_callback(&self, fun: napi::JsFunction) -> napi::Result<()> { - let tsfn: ThreadsafeFunction = fun - .create_threadsafe_function(0, |ctx: ThreadSafeCallContext| { - Ok(vec![ctx.value]) - })?; + pub fn js_callback(&self, fun: ThreadsafeFunction) -> napi::Result<()> { + let tsfn: ThreadsafeFunction = fun; self.callback(move |controller: Workspace| { - tsfn.call(controller.clone(), ThreadsafeFunctionCallMode::Blocking); //check this with tracing also we could use Ok(event) to get the error - // If it blocks the main thread too many time we have to change this + tsfn.call(Ok(controller.clone()), ThreadsafeFunctionCallMode::Blocking); //check this with tracing also we could use Ok(event) to get the error + // If it blocks the main thread too many time we have to change this }); Ok(()) diff --git a/src/ffi/lua/buffer.rs b/src/ffi/lua/buffer.rs index d061b9ca..dff38dc9 100644 --- a/src/ffi/lua/buffer.rs +++ b/src/ffi/lua/buffer.rs @@ -3,7 +3,7 @@ use mlua::prelude::*; use super::ext::a_sync::a_sync; -super::ext::impl_lua_serde! { CodempTextChange CodempBufferUpdate } +super::ext::impl_lua_serde! { CodempTextChange CodempBufferUpdate CodempBufferNode } impl LuaUserData for CodempBufferController { fn add_methods>(methods: &mut M) { @@ -47,6 +47,10 @@ impl LuaUserData for CodempBufferController { impl CodempBufferController { fn lua_callback_id(&self) -> String { - format!("codemp-buffercontroller({}:{})-callback-registry", self.workspace_id(), self.path()) + format!( + "codemp-buffercontroller({}:{})-callback-registry", + self.workspace_id(), + self.path() + ) } } diff --git a/src/ffi/lua/client.rs b/src/ffi/lua/client.rs index 4c69c40e..5921d869 100644 --- a/src/ffi/lua/client.rs +++ b/src/ffi/lua/client.rs @@ -15,7 +15,7 @@ impl LuaUserData for CodempClient { Ok(this.current_user().clone()) }); methods.add_method("active_workspaces", |_, this, ()| { - Ok(this.active_workspaces()) + Ok(this.active_workspaces().into_iter().map(|x| x.to_string()).collect::>()) }); methods.add_method( @@ -25,7 +25,10 @@ impl LuaUserData for CodempClient { methods.add_method( "attach_workspace", - |_, this, (ws,): (String,)| a_sync! { this => this.attach_workspace(ws).await? }, + |_, this, (ws,): (String,)| { + let ws_id = super::ext::lua_parse_uuid(&ws, 1, "ws")?; + a_sync! { this => this.attach_workspace(ws_id).await? } + }, ); methods.add_method( @@ -53,11 +56,13 @@ impl LuaUserData for CodempClient { ); methods.add_method("leave_workspace", |_, this, (ws,): (String,)| { - Ok(this.leave_workspace(&ws)) + let ws_id = super::ext::lua_parse_uuid(&ws, 1, "ws")?; + Ok(this.leave_workspace(ws_id)) }); methods.add_method("get_workspace", |_, this, (ws,): (String,)| { - Ok(this.get_workspace(&ws)) + let ws_id = super::ext::lua_parse_uuid(&ws, 1, "ws")?; + Ok(this.get_workspace(ws_id)) }); } } diff --git a/src/ffi/lua/cursor.rs b/src/ffi/lua/cursor.rs index d590034a..17f18fb4 100644 --- a/src/ffi/lua/cursor.rs +++ b/src/ffi/lua/cursor.rs @@ -37,6 +37,9 @@ impl LuaUserData for CodempCursorController { impl CodempCursorController { fn lua_callback_id(&self) -> String { - format!("codemp-cursorcontroller({})-callback-registry", self.workspace_id()) + format!( + "codemp-cursorcontroller({})-callback-registry", + self.workspace_id() + ) } } diff --git a/src/ffi/lua/ext/a_sync.rs b/src/ffi/lua/ext/a_sync.rs index 13600dc1..fe68402a 100644 --- a/src/ffi/lua/ext/a_sync.rs +++ b/src/ffi/lua/ext/a_sync.rs @@ -47,12 +47,10 @@ impl LuaUserData for Promise { // TODO: await MUST NOT be used in callbacks!! methods.add_method_mut("await", |_, this, ()| match this.0.take() { None => Err(LuaError::runtime("Promise already awaited")), - Some(x) => Ok( - tokio() - .block_on(x) - .map_err(LuaError::runtime)? - .map_err(LuaError::runtime)? - ), + Some(x) => Ok(tokio() + .block_on(x) + .map_err(LuaError::runtime)? + .map_err(LuaError::runtime)?), }); methods.add_method_mut("cancel", |_, this, ()| match this.0.take() { None => Err(LuaError::runtime("Promise already awaited")), diff --git a/src/ffi/lua/ext/callback.rs b/src/ffi/lua/ext/callback.rs index 269fa8f9..6426886d 100644 --- a/src/ffi/lua/ext/callback.rs +++ b/src/ffi/lua/ext/callback.rs @@ -32,7 +32,9 @@ impl CallbackChannel { pub(crate) fn failure(&self, err: impl std::error::Error) { self.tx - .send(LuaCallback::Fail(format!("callback returned error: {err:?}"))) + .send(LuaCallback::Fail(format!( + "callback returned error: {err:?}" + ))) .unwrap_or_warn("error scheduling callback failure") } @@ -51,14 +53,14 @@ impl CallbackChannel { Ok(LuaCallback::Fail(msg)) => { tracing::error!("callback returned error: {msg}"); None - }, + } Ok(LuaCallback::Invoke(key, arg, cleanup)) => { let cb = match lua.named_registry_value::(&key) { Ok(x) => x, Err(e) => { tracing::error!("could not get callback to invoke: {e}"); return None; - }, + } }; if cleanup { if let Err(e) = lua.unset_named_registry_value(&key) { @@ -66,7 +68,7 @@ impl CallbackChannel { } } Some((cb, arg)) - }, + } }, } } @@ -121,14 +123,19 @@ callback_args! { CursorController: CodempCursorController, BufferController: CodempBufferController, Workspace: CodempWorkspace, + WorkspaceInfo: CodempWorkspaceInfo, + VecWorkspaceInfo: Vec, Event: CodempEvent, MaybeEvent: Option, Cursor: CodempCursor, MaybeCursor: Option, Selection: CodempSelection, + VecSelection: Vec, MaybeSelection: Option, TextChange: CodempTextChange, MaybeTextChange: Option, BufferUpdate: CodempBufferUpdate, MaybeBufferUpdate: Option, + BufferNode: CodempBufferNode, + VecBufferNode: Vec, } diff --git a/src/ffi/lua/ext/log.rs b/src/ffi/lua/ext/log.rs index b9728e98..2509351d 100644 --- a/src/ffi/lua/ext/log.rs +++ b/src/ffi/lua/ext/log.rs @@ -72,7 +72,7 @@ pub(crate) fn setup_tracing( }); } res - }, + } _ => return Err(LuaError::BindError), // TODO full BadArgument type?? }; diff --git a/src/ffi/lua/ext/mod.rs b/src/ffi/lua/ext/mod.rs index a209c0a1..8062db64 100644 --- a/src/ffi/lua/ext/mod.rs +++ b/src/ffi/lua/ext/mod.rs @@ -5,6 +5,23 @@ pub mod log; pub(crate) use a_sync::tokio; pub(crate) use callback::callback; +pub(crate) fn lua_parse_uuid(uuid: &str, pos: usize, name: &str) -> mlua::Result { + use std::str::FromStr; + match uuid::Uuid::from_str(uuid) { + Ok(x) => Ok(x), + Err(e) => Err(mlua::Error::BadArgument { + pos, + name: Some(name.to_string()), + to: Some("Uuid::from_str".to_string()), + cause: std::sync::Arc::new(mlua::Error::FromLuaConversionError { + from: "string", + to: "Uuid".to_string(), + message: Some(e.to_string()), + }), + }), + } +} + macro_rules! impl_lua_serde { ($($t:ty)*) => { $( @@ -24,3 +41,4 @@ macro_rules! impl_lua_serde { } pub(crate) use impl_lua_serde; + diff --git a/src/ffi/lua/workspace.rs b/src/ffi/lua/workspace.rs index 3ce118e6..c5ac5e97 100644 --- a/src/ffi/lua/workspace.rs +++ b/src/ffi/lua/workspace.rs @@ -3,7 +3,7 @@ use mlua::prelude::*; use super::ext::a_sync::a_sync; -super::ext::impl_lua_serde! { CodempEvent } +super::ext::impl_lua_serde! { CodempEvent CodempWorkspaceInfo } impl LuaUserData for CodempWorkspace { fn add_methods>(methods: &mut M) { @@ -12,7 +12,7 @@ impl LuaUserData for CodempWorkspace { }); methods.add_method( "create_buffer", - |_, this, (name,): (String,)| a_sync! { this => this.create_buffer(&name).await? }, + |_, this, (name, ephemeral): (String, bool)| a_sync! { this => this.create_buffer(&name, ephemeral).await? }, ); methods.add_method( @@ -34,25 +34,25 @@ impl LuaUserData for CodempWorkspace { }); methods.add_method( - "fetch_buffers", - |_, this, ()| a_sync! { this => this.fetch_buffers().await? }, + "list_buffers", + |_, this, (filter,): (String,)| a_sync! { this => this.list_buffers(filter).await? }, ); methods.add_method( - "fetch_users", - |_, this, ()| a_sync! { this => this.fetch_users().await? }, + "list_users", + |_, this, ()| a_sync! { this => this.list_users().await? }, ); methods.add_method("search_buffers", |_, this, (filter,): (Option,)| { Ok(this.search_buffers(filter.as_deref())) }); - methods.add_method("fetch_buffer_users", |_, this, (path,): (String,)| { + methods.add_method("list_buffer_users", |_, this, (path,): (String,)| { a_sync! { - this => this.fetch_buffer_users(&path).await? + this => this.list_buffer_users(&path).await? } }); - methods.add_method("id", |_, this, ()| Ok(this.id())); + methods.add_method("id", |_, this, ()| Ok(this.id().to_string())); methods.add_method("cursor", |_, this, ()| Ok(this.cursor())); methods.add_method("active_buffers", |_, this, ()| Ok(this.active_buffers())); methods.add_method("user_list", |_, this, ()| Ok(this.user_list())); diff --git a/src/ffi/python/client.rs b/src/ffi/python/client.rs index 90c12a6c..fa28bbb8 100644 --- a/src/ffi/python/client.rs +++ b/src/ffi/python/client.rs @@ -1,8 +1,9 @@ -use super::a_sync_allow_threads; use super::Client; +use super::a_sync_allow_threads; use crate::api::User; use crate::workspace::Workspace; use pyo3::prelude::*; +use uuid::Uuid; #[pymethods] impl Client { @@ -16,7 +17,7 @@ impl Client { // } #[pyo3(name = "attach_workspace")] - fn pyattach_workspace(&self, py: Python<'_>, workspace: String) -> PyResult { + fn pyattach_workspace(&self, py: Python<'_>, workspace: Uuid) -> PyResult { tracing::info!("attempting to join the workspace {}", workspace); let this = self.clone(); a_sync_allow_threads!(py, this.attach_workspace(workspace).await) @@ -70,18 +71,18 @@ impl Client { } #[pyo3(name = "leave_workspace")] - fn pyleave_workspace(&self, id: String) -> bool { - self.leave_workspace(id.as_str()) + fn pyleave_workspace(&self, id: Uuid) -> bool { + self.leave_workspace(id) } // join a workspace #[pyo3(name = "get_workspace")] - fn pyget_workspace(&self, id: String) -> Option { - self.get_workspace(id.as_str()) + fn pyget_workspace(&self, id: Uuid) -> Option { + self.get_workspace(id) } #[pyo3(name = "active_workspaces")] - fn pyactive_workspaces(&self) -> Vec { + fn pyactive_workspaces(&self) -> Vec { self.active_workspaces() } diff --git a/src/ffi/python/controllers.rs b/src/ffi/python/controllers.rs index 3dd17bd5..848ccf2b 100644 --- a/src/ffi/python/controllers.rs +++ b/src/ffi/python/controllers.rs @@ -1,13 +1,13 @@ -use crate::api::controller::{AsyncReceiver, AsyncSender}; use crate::api::TextChange; +use crate::api::controller::{AsyncReceiver, AsyncSender}; use crate::api::{Cursor, Selection}; use crate::buffer::Controller as BufferController; use crate::cursor::Controller as CursorController; use pyo3::exceptions::PyValueError; use pyo3::prelude::*; -use super::a_sync_allow_threads; use super::Promise; +use super::a_sync_allow_threads; // need to do manually since Controller is a trait implementation #[pymethods] @@ -72,7 +72,7 @@ impl BufferController { } #[pyo3(name = "ack")] - fn pyack(&self, v: Vec) -> () { + fn pyack(&self, v: Vec) { self.ack(v) } @@ -128,18 +128,21 @@ impl BufferController { #[pymethods] impl Cursor { #[getter(start)] - fn pystart(&self) -> (i32, i32) { - (self.sel.start_row, self.sel.start_col) + fn pystart(&self) -> Vec<(i32, i32)> { + self.sel + .iter() + .map(|s| (s.start_row, s.start_col)) + .collect() } #[getter(end)] - fn pyend(&self) -> (i32, i32) { - (self.sel.end_row, self.sel.end_col) + fn pyend(&self) -> Vec<(i32, i32)> { + self.sel.iter().map(|s| (s.end_row, s.end_col)).collect() } #[getter(buffer)] fn pybuffer(&self) -> String { - self.sel.buffer.clone() + self.sel.iter().map(|s| s.buffer.clone()).collect() } #[getter(user)] diff --git a/src/ffi/python/mod.rs b/src/ffi/python/mod.rs index a68e5e6e..86563808 100644 --- a/src/ffi/python/mod.rs +++ b/src/ffi/python/mod.rs @@ -3,10 +3,10 @@ pub mod controllers; pub mod workspace; use crate::{ + Client, Workspace, api::{BufferUpdate, Config, Cursor, Event, Selection, TextChange, User}, buffer::Controller as BufferController, cursor::Controller as CursorController, - Client, Workspace, }; use pyo3::{ @@ -91,7 +91,7 @@ macro_rules! a_sync { ))) }}; } -pub(crate) use a_sync; +//pub(crate) use a_sync; macro_rules! a_sync_allow_threads { ($py:ident, $x:expr) => {{ @@ -330,10 +330,10 @@ fn set_logger(py: Python, logging_cb: PyObject, debug: bool) -> bool { .with_level(true) .with_target(true) .with_thread_ids(false) - .with_thread_names(false) + .with_thread_names(true) .with_file(false) .with_line_number(false) - .with_source_location(false) + .with_source_location(true) .compact(); let log_subscribed = tracing_subscriber::fmt() diff --git a/src/ffi/python/workspace.rs b/src/ffi/python/workspace.rs index 8d3c5251..bbd040bb 100644 --- a/src/ffi/python/workspace.rs +++ b/src/ffi/python/workspace.rs @@ -1,21 +1,21 @@ -use crate::api::controller::AsyncReceiver; use crate::api::User; +use crate::api::controller::AsyncReceiver; use crate::buffer::Controller as BufferController; use crate::cursor::Controller as CursorController; use crate::workspace::Workspace; use pyo3::exceptions::PyValueError; use pyo3::prelude::*; -use super::a_sync_allow_threads; use super::Promise; +use super::a_sync_allow_threads; #[pymethods] impl Workspace { // join a workspace #[pyo3(name = "create_buffer")] - fn pycreate_buffer(&self, py: Python, path: String) -> PyResult { + fn pycreate_buffer(&self, py: Python, path: String, ephemeral: bool) -> PyResult { let this = self.clone(); - a_sync_allow_threads!(py, this.create_buffer(path.as_str()).await) + a_sync_allow_threads!(py, this.create_buffer(path.as_str(), ephemeral).await) } #[pyo3(name = "attach_buffer")] @@ -30,22 +30,22 @@ impl Workspace { } #[pyo3(name = "fetch_buffers")] - fn pyfetch_buffers(&self, py: Python) -> PyResult { + fn pylist_buffers(&self, py: Python, filter: String) -> PyResult { let this = self.clone(); - a_sync_allow_threads!(py, this.fetch_buffers().await) + a_sync_allow_threads!(py, this.list_buffers(filter.as_str()).await) } #[pyo3(name = "fetch_users")] - fn pyfetch_users(&self, py: Python) -> PyResult { + fn pylist_users(&self, py: Python) -> PyResult { let this = self.clone(); - a_sync_allow_threads!(py, this.fetch_users().await) + a_sync_allow_threads!(py, this.list_users().await) } #[pyo3(name = "fetch_buffer_users")] - fn pyfetch_buffer_users(&self, py: Python, path: String) -> PyResult { + fn pylist_buffer_users(&self, py: Python, path: String) -> PyResult { // crate::Result> let this = self.clone(); - a_sync_allow_threads!(py, this.fetch_buffer_users(path.as_str()).await) + a_sync_allow_threads!(py, this.list_buffer_users(path.as_str()).await) } #[pyo3(name = "delete_buffer")] @@ -55,7 +55,7 @@ impl Workspace { } #[pyo3(name = "id")] - fn pyid(&self) -> String { + fn pyid(&self) -> uuid::Uuid { self.id() } diff --git a/src/network.rs b/src/network.rs index aaa39c10..c4994abb 100644 --- a/src/network.rs +++ b/src/network.rs @@ -3,7 +3,7 @@ use codemp_proto::{ workspace::workspace_client::WorkspaceClient, }; use tonic::{ - service::{interceptor::InterceptedService, Interceptor}, + service::{Interceptor, interceptor::InterceptedService}, transport::{Channel, Endpoint}, }; @@ -40,10 +40,10 @@ impl Services { let channel = Endpoint::from_shared(dest.to_string())?.connect().await?; let inter = WorkspaceInterceptor { session, workspace }; Ok(Self { - cursor: CursorClient::with_interceptor(channel.clone(), inter.clone()), workspace: WorkspaceClient::with_interceptor(channel.clone(), inter.clone()), - // TODO technically we could keep buffers on separate servers, and thus manage buffer - // connections separately, but for now it's more convenient to bundle them with workspace + // TODO technically we could keep buffers and cursors on separate servers, and thus manage + // their connections separately, but for now it's more convenient to bundle them with workspace + cursor: CursorClient::with_interceptor(channel.clone(), inter.clone()), buffer: BufferClient::with_interceptor(channel.clone(), inter.clone()), }) } diff --git a/src/prelude.rs b/src/prelude.rs index 5f96584c..0d5a434a 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -6,6 +6,7 @@ pub use crate::api::{ BufferUpdate as CodempBufferUpdate, Config as CodempConfig, Controller as CodempController, Cursor as CodempCursor, Event as CodempEvent, Selection as CodempSelection, TextChange as CodempTextChange, User as CodempUser, + WorkspaceInfo as CodempWorkspaceInfo, BufferNode as CodempBufferNode, }; pub use crate::{ diff --git a/src/tests/client.rs b/src/tests/client.rs index 6b960a3b..5c7daa6b 100644 --- a/src/tests/client.rs +++ b/src/tests/client.rs @@ -244,9 +244,11 @@ async fn test_buffer_search() { async move { workspace_alice.create_buffer(&buffer_name).await?; - assert_or_err!(!workspace_alice - .search_buffers(Some(&buffer_name[0..4])) - .is_empty()); + assert_or_err!( + !workspace_alice + .search_buffers(Some(&buffer_name[0..4])) + .is_empty() + ); assert_or_err!(workspace_alice.search_buffers(Some("_")).is_empty()); workspace_alice.delete_buffer(&buffer_name).await?; Ok(()) diff --git a/src/tests/fixtures.rs b/src/tests/fixtures.rs index b52712cb..f6ba6887 100644 --- a/src/tests/fixtures.rs +++ b/src/tests/fixtures.rs @@ -109,14 +109,14 @@ impl WorkspaceFixture { impl ScopedFixture<(crate::Client, crate::Workspace)> for WorkspaceFixture { async fn setup(&mut self) -> Result<(crate::Client, crate::Workspace), Box> { let client = ClientFixture::of(&self.user).setup().await?; - client.create_workspace(&self.workspace).await?; - let workspace = client.attach_workspace(&self.workspace).await?; + let ws_info = client.create_workspace(&self.workspace).await?; + let workspace = client.attach_workspace(ws_info.id).await?; Ok((client, workspace)) } async fn cleanup(&mut self, resource: Option<(crate::Client, crate::Workspace)>) { - if let Some((client, _workspace)) = resource { - client.leave_workspace(&self.workspace); + if let Some((client, workspace)) = resource { + client.leave_workspace(workspace.id()); if let Err(e) = client.delete_workspace(&self.workspace).await { eprintln!("could not delete workspace: {e}"); } @@ -152,12 +152,12 @@ impl ) .setup() .await?; - client.create_workspace(&self.workspace).await?; + let ws_info = client.create_workspace(&self.workspace).await?; client .invite_to_workspace(&self.workspace, invitee_client.current_user().name.clone()) .await?; - let workspace = client.attach_workspace(&self.workspace).await?; - let invitee_workspace = invitee_client.attach_workspace(&self.workspace).await?; + let workspace = client.attach_workspace(ws_info.id).await?; + let invitee_workspace = invitee_client.attach_workspace(ws_info.id).await?; Ok((client, workspace, invitee_client, invitee_workspace)) } @@ -170,8 +170,8 @@ impl crate::Workspace, )>, ) { - if let Some((client, _, _, _)) = resource { - client.leave_workspace(&self.workspace); + if let Some((client, ws, _, _)) = resource { + client.leave_workspace(ws.id()); if let Err(e) = client.delete_workspace(&self.workspace).await { eprintln!("could not delete workspace: {e}"); } @@ -247,17 +247,17 @@ impl ) .setup() .await?; - client.create_workspace(&self.workspace).await?; + let ws_info = client.create_workspace(&self.workspace).await?; client .invite_to_workspace(&self.workspace, invitee_client.current_user().name.clone()) .await?; - let workspace = client.attach_workspace(&self.workspace).await?; - workspace.create_buffer(&self.buffer).await?; - let buffer = workspace.attach_buffer(&self.buffer).await?; + let workspace = client.attach_workspace(ws_info.id).await?; + workspace.create_buffer(&self.buffer, false).await?; + let buffer = workspace.attach_buffer(self.buffer.clone()).await?; - let invitee_workspace = invitee_client.attach_workspace(&self.workspace).await?; - let invitee_buffer = invitee_workspace.attach_buffer(&self.buffer).await?; + let invitee_workspace = invitee_client.attach_workspace(ws_info.id).await?; + let invitee_buffer = invitee_workspace.attach_buffer(self.buffer.clone()).await?; Ok(( client, @@ -280,9 +280,9 @@ impl crate::buffer::Controller, )>, ) { - if let Some((client, _, _, _, _, _)) = resource { + if let Some((client, ws, _, _, _, _)) = resource { // buffer deletion is implied in workspace deletion - client.leave_workspace(&self.workspace); + client.leave_workspace(ws.id()); if let Err(e) = client.delete_workspace(&self.workspace).await { eprintln!("could not delete workspace: {e}"); } diff --git a/src/tests/server.rs b/src/tests/server.rs index ebcf4ce0..815d3286 100644 --- a/src/tests/server.rs +++ b/src/tests/server.rs @@ -73,10 +73,12 @@ async fn test_workspace_interactions() { .invite_to_workspace(&workspace_name, &client_bob.current_user().name) .await?; client_bob.attach_workspace(&workspace_name).await?; - assert_or_err!(client_bob - .fetch_joined_workspaces() - .await? - .contains(&workspace_name)); + assert_or_err!( + client_bob + .fetch_joined_workspaces() + .await? + .contains(&workspace_name) + ); assert_or_err!(client_bob.leave_workspace(&workspace_name)); assert_or_err!(client_alice.leave_workspace(&workspace_name)); diff --git a/src/workspace.rs b/src/workspace.rs index 80d2af05..2d7a177d 100644 --- a/src/workspace.rs +++ b/src/workspace.rs @@ -5,29 +5,31 @@ use crate::{ api::{ - controller::{AsyncReceiver, ControllerCallback}, Event, User, + controller::{AsyncReceiver, ControllerCallback}, }, buffer, cursor, errors::{ConnectionResult, ControllerResult, RemoteResult}, - ext::{IgnorableError, InternallyMutable}, + ext::IgnorableError, network::Services, }; use codemp_proto::{ - common::{Empty, Token}, - files::BufferNode, + common::Empty, + files::{BufferNode, BufferRequest}, workspace::{ workspace_event::{ - Event as WorkspaceEventInner, FileCreate, FileDelete, FileRename, UserJoin, UserLeave, - }, - WorkspaceEvent, + Event as WorkspaceEventInner, FileCreate, FileDelete, FileRename, UserJoinBuffer, UserJoinWorkspace, UserLeaveBuffer, UserLeaveWorkspace + }, WorkspaceEvent }, }; -use dashmap::{DashMap, DashSet}; +use dashmap::DashMap; use std::sync::{Arc, Weak}; -use tokio::sync::{mpsc::{self, error::TryRecvError}, oneshot, watch}; +use tokio::sync::{ + mpsc::{self, error::TryRecvError}, + oneshot, watch, +}; use tonic::Streaming; use uuid::Uuid; @@ -43,16 +45,17 @@ use napi_derive::napi; #[derive(Debug, Clone)] #[cfg_attr(feature = "py", pyo3::pyclass)] #[cfg_attr(feature = "js", napi)] -pub struct Workspace(Arc); +pub struct Workspace(pub(crate) Arc); #[derive(Debug)] struct WorkspaceInner { - name: String, + id: Uuid, current_user: Arc, cursor: cursor::Controller, buffers: DashMap, services: Services, - filetree: DashSet, + filetree: DashMap, + buffer_users: DashMap>, users: Arc>, events: tokio::sync::Mutex>, callback: watch::Sender>>, @@ -84,17 +87,16 @@ impl AsyncReceiver for Workspace { } impl Workspace { - #[tracing::instrument(skip(name, user, token, claims), fields(ws = name))] + #[tracing::instrument(skip(id, user, workspace_claim, user_claim), fields(ws = %id))] pub(crate) async fn connect( - name: String, + id: Uuid, user: Arc, config: crate::api::Config, - token: Token, - claims: tokio::sync::watch::Receiver, + workspace_claim: tokio::sync::watch::Receiver, + user_claim: tokio::sync::watch::Receiver, ) -> ConnectionResult { - let workspace_claim = InternallyMutable::new(token); let services = - Services::try_new(&config.endpoint(), claims, workspace_claim.channel()).await?; + Services::try_new(&config.endpoint(), user_claim, workspace_claim).await?; let ws_stream = services.ws().attach(Empty {}).await?.into_inner(); let (tx, rx) = mpsc::channel(128); @@ -108,14 +110,15 @@ impl Workspace { .into_inner(); let users = Arc::new(DashMap::default()); - let controller = cursor::Controller::spawn(users.clone(), tx, cur_stream, &name); + let controller = cursor::Controller::spawn(users.clone(), tx, cur_stream, id); let ws = Self(Arc::new(WorkspaceInner { - name: name.clone(), + id, current_user: user, cursor: controller, buffers: DashMap::default(), - filetree: DashSet::default(), + filetree: DashMap::default(), + buffer_users: DashMap::default(), users, events: tokio::sync::Mutex::new(ev_rx), services, @@ -133,59 +136,94 @@ impl Workspace { }; let _t = tokio::spawn(async move { - worker.work(name, ws_stream, weak).await; + worker.work(id, ws_stream, weak).await; }); ws.fetch_users().await?; - ws.fetch_buffers().await?; + ws.fetch_buffers("".to_string()).await?; + + for buffer_ref in ws.0.buffers.iter() { + ws.fetch_buffer_users(buffer_ref.key().clone()).await?; + } Ok(ws) } + pub(crate) fn services(&self) -> &Services { + &self.0.services + } + /// drop arc, return true if was last pub(crate) fn consume(self) -> bool { Arc::into_inner(self.0).is_some() } /// Create a new buffer in the current workspace. - pub async fn create_buffer(&self, path: &str) -> RemoteResult<()> { + pub async fn create_buffer(&self, path: &str, ephemeral: bool) -> RemoteResult<()> { let mut workspace_client = self.0.services.ws(); workspace_client .create_buffer(tonic::Request::new(BufferNode { path: path.to_string(), + ephemeral, })) .await?; - // add to filetree - self.0.filetree.insert(path.to_string()); - - // fetch buffers - self.fetch_buffers().await?; + // add to filetree, not really necessary as we will get an event for it + self.0.filetree.insert( + path.to_string(), + crate::api::BufferNode { + path: path.to_string(), + ephemeral, + }, + ); Ok(()) } /// Attach to a buffer and return a handle to it. #[tracing::instrument(skip(self))] - pub async fn attach_buffer(&self, path: &str) -> ConnectionResult { - let mut worskspace_client = self.0.services.ws(); - let request = tonic::Request::new(BufferNode { - path: path.to_string(), + pub async fn attach_buffer(&self, path: String) -> ConnectionResult { + let mut workspace_client = self.0.services.ws(); + let mut buffer_client = self.0.services.buf(); + let request = tonic::Request::new(BufferRequest { + path: path.clone(), }); - let credentials = worskspace_client.access_buffer(request).await?.into_inner(); + let credentials = workspace_client.get_buffer_token(request).await?.into_inner(); let (tx, rx) = mpsc::channel(256); let mut req = tonic::Request::new(tokio_stream::wrappers::ReceiverStream::new(rx)); - req.metadata_mut().insert( - "buffer", - tonic::metadata::MetadataValue::try_from(credentials.token).map_err(|e| { - tonic::Status::internal(format!("failed representing token to string: {e}")) - })?, - ); - let stream = self.0.services.buf().attach(req).await?.into_inner(); - - let controller = buffer::Controller::spawn(self.0.current_user.id, path, tx, stream, &self.0.name); - self.0.buffers.insert(path.to_string(), controller.clone()); + req.metadata_mut().insert("buffer", crate::ext::token_to_metadata(credentials)?); + let stream = buffer_client.attach(req).await?.into_inner(); + + let controller = + buffer::Controller::spawn(self.0.current_user.id, &path, tx, stream, self.0.id); + + self.0.buffers.insert(path.clone(), controller.clone()); + + let weak = Arc::downgrade(&controller.0); + tokio::spawn(async move { + let _p = path.clone(); + let fut = async move { + loop { + // TODO either configurable token refresh time or calculate depending on token lifetime + tokio::time::sleep(std::time::Duration::from_secs(20)).await; + if weak.upgrade().is_none() { break }; + let new_credentials = workspace_client.get_buffer_token( + tonic::Request::new(BufferRequest { path: path.clone() }) + ) + .await? + .into_inner(); + let mut request = tonic::Request::new(Empty {}); + request.metadata_mut().insert("buffer", crate::ext::token_to_metadata(new_credentials)?); + buffer_client.keep_alive(request).await?; + } + Ok::<(), tonic::Status>(()) + }; + + if let Err(e) = fut.await { + tracing::error!("error in keepalive task for buffer {_p}: {e}"); + } + }); Ok(controller) } @@ -210,61 +248,58 @@ impl Workspace { } /// Re-fetch the list of available buffers in the workspace. - pub async fn fetch_buffers(&self) -> RemoteResult> { + pub async fn fetch_buffers(&self, path: String) -> RemoteResult<()> { let mut workspace_client = self.0.services.ws(); let resp = workspace_client - .list_buffers(tonic::Request::new(Empty {})) + .fetch_buffers(tonic::Request::new(BufferRequest { path })) .await? .into_inner(); - let mut out = Vec::new(); - self.0.filetree.clear(); for b in resp.buffers { - self.0.filetree.insert(b.path.clone()); - out.push(b.path); + self.0 + .filetree + .insert(b.path.clone(), crate::api::BufferNode::from(b)); } - Ok(out) + Ok(()) } /// Re-fetch the list of all users in the workspace. - pub async fn fetch_users(&self) -> RemoteResult> { - let mut workspace_client = self.0.services.ws(); + pub async fn fetch_users(&self) -> RemoteResult<()> { + let mut workspace_client = self.services().ws(); let users = workspace_client - .list_users(tonic::Request::new(Empty {})) + .fetch_users(tonic::Request::new(Empty {})) .await? .into_inner() .users .into_iter() .map(User::from); - let mut result = Vec::new(); - self.0.users.clear(); for u in users { - self.0.users.insert(u.id, u.clone()); - result.push(u); + self.0.users.insert(u.id, u); } - Ok(result) + Ok(()) } /// Fetch a list of the [User]s attached to a specific buffer. - pub async fn fetch_buffer_users(&self, path: &str) -> RemoteResult> { - let mut workspace_client = self.0.services.ws(); - let buffer_users = workspace_client - .list_buffer_users(tonic::Request::new(BufferNode { + pub async fn fetch_buffer_users(&self, path: String) -> RemoteResult<()> { + let users = self.services().ws() + .fetch_buffer_users(tonic::Request::new(BufferRequest { path: path.to_string(), })) .await? .into_inner() .users .into_iter() - .map(|id| id.into()) + .map(|x| Uuid::from(x.id)) .collect(); - Ok(buffer_users) + self.0.buffer_users.insert(path, users); + + Ok(()) } /// Delete a buffer. @@ -273,7 +308,7 @@ impl Workspace { let mut workspace_client = self.0.services.ws(); workspace_client - .delete_buffer(tonic::Request::new(BufferNode { + .delete_buffer(tonic::Request::new(BufferRequest { path: path.to_string(), })) .await?; @@ -285,8 +320,8 @@ impl Workspace { /// Get the workspace unique id. // #[cfg_attr(feature = "js", napi)] // https://github.com/napi-rs/napi-rs/issues/1120 - pub fn id(&self) -> String { - self.0.name.clone() + pub fn id(&self) -> Uuid { + self.0.id } /// Return a handle to the [`cursor::Controller`]. @@ -311,7 +346,7 @@ impl Workspace { .collect() } - /// Get all names of users currently in this workspace + /// Get all users currently in this workspace pub fn user_list(&self) -> Vec { self.0 .users @@ -320,6 +355,19 @@ impl Workspace { .collect() } + /// Get all users currently attached to specified buffer + pub fn buffer_user_list(&self, path: &str) -> Vec { + let mut out = Vec::new(); + if let Some(buf_ref) = self.0.buffer_users.get(path) { + for uid in buf_ref.value() { + if let Some(user_ref) = self.0.users.get(uid) { + out.push(user_ref.value().clone()); + } + } + } + out + } + /// Get the filetree as it is currently cached. /// A filter may be applied, and it may be strict (equality check) or not (starts_with check). // #[cfg_attr(feature = "js", napi)] // https://github.com/napi-rs/napi-rs/issues/1120 @@ -328,14 +376,15 @@ impl Workspace { .0 .filetree .iter() - .filter(|f| filter.is_none_or(|flt| f.starts_with(flt))) - .map(|f| f.clone()) + .filter(|f| filter.is_none_or(|flt| f.key().starts_with(flt))) + .map(|f| f.key().clone()) .collect::>(); tree.sort(); tree } } + struct WorkspaceWorker { callback: watch::Receiver>>, pollers: Vec>, @@ -345,7 +394,12 @@ struct WorkspaceWorker { impl WorkspaceWorker { #[tracing::instrument(skip(self, stream, weak))] - pub(crate) async fn work(mut self, ws: String, mut stream: Streaming, weak: Weak) { + pub(crate) async fn work( + mut self, + ws: Uuid, + mut stream: Streaming, + weak: Weak, + ) { tracing::debug!("workspace worker starting"); loop { tokio::select! { @@ -368,22 +422,43 @@ impl WorkspaceWorker { let update = crate::api::Event::from(&ev); match ev { // user - WorkspaceEventInner::Join(UserJoin { user }) => { + WorkspaceEventInner::WorkspaceJoin(UserJoinWorkspace { user }) => { inner.users.insert(user.id.uuid(), user.into()); } - WorkspaceEventInner::Leave(UserLeave { user }) => { + WorkspaceEventInner::WorkspaceLeave(UserLeaveWorkspace { user }) => { inner.users.remove(&user.id.uuid()); } + WorkspaceEventInner::BufferJoin(UserJoinBuffer { user, buffer }) => { + match inner.buffer_users.get_mut(&buffer) { + Some(mut buf_users_ref) => buf_users_ref.push(Uuid::from(user.id)), + None => tracing::warn!("received UserJoinBuffer event for an unknown buffer"), + } + }, + WorkspaceEventInner::BufferLeave(UserLeaveBuffer { user, buffer }) => { + match inner.buffer_users.get_mut(&buffer) { + Some(mut buf_users_ref) => buf_users_ref.retain(|x| *x != Uuid::from(user.id)), + None => tracing::warn!("received UserLeaveBuffer event for an unknown buffer"), + } + }, // buffer - WorkspaceEventInner::Create(FileCreate { path }) => { - inner.filetree.insert(path); + WorkspaceEventInner::Create(FileCreate { path, ephemeral }) => { + inner.buffer_users.insert(path.clone(), Vec::new()); + inner.filetree.insert(path.clone(), crate::api::BufferNode { path, ephemeral }); } WorkspaceEventInner::Rename(FileRename { before, after }) => { - inner.filetree.remove(&before); - inner.filetree.insert(after); + if let Some((_path, controller)) = inner.buffers.remove(&before) { + inner.buffers.insert(after.clone(), controller); + } + if let Some((_path, node)) = inner.filetree.remove(&before) { + inner.filetree.insert(after.clone(), node); + } + if let Some((_path, users)) = inner.buffer_users.remove(&before) { + inner.buffer_users.insert(after, users); + } } WorkspaceEventInner::Delete(FileDelete { path }) => { inner.filetree.remove(&path); + inner.buffer_users.remove(&path); let _ = inner.buffers.remove(&path); } }