diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 0000000..2723aa9 --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,3 @@ +image: yusdacra/gitpod-workspace-base-nix:latest +tasks: + - command: nix develop diff --git a/Cargo.lock b/Cargo.lock index cb2e886..7378263 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "ab_glyph" -version = "0.2.13" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61caed9aec6daeee1ea38ccf5fb225e4f96c1eeead1b4a5c267324a63cf02326" +checksum = "24606928a235e73cdef55a0c909719cadd72fce573e5713d58cb2952d8f5794c" dependencies = [ "ab_glyph_rasterizer", "owned_ttf_parser", @@ -36,7 +36,7 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom 0.2.5", + "getrandom", "once_cell", "serde", "version_check", @@ -68,27 +68,33 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.55" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd" +checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" [[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" - -[[package]] -name = "arrayvec" -version = "0.5.2" +name = "arboard" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +checksum = "6045ca509e4abacde2b884ac4618a51d0c017b5d85a3ee84a7226eb33b3154a9" +dependencies = [ + "clipboard-win", + "log", + "objc", + "objc-foundation", + "objc_id", + "once_cell", + "parking_lot 0.12.0", + "thiserror", + "winapi", + "x11rb", +] [[package]] name = "ashpd" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7915e26e0786f91768d23de32afafa4ee5e2ea76be21c0ecd8e14441543c1655" +checksum = "7db023823e72175ec1a514231d5ff28ad7f7e15702a3ad7507dbc7ac1feea7b6" dependencies = [ "enumflags2", "futures", @@ -175,15 +181,15 @@ dependencies = [ [[package]] name = "async-task" -version = "4.1.0" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d306121baf53310a3fd342d88dc0824f6bbeace68347593658525565abee8" +checksum = "30696a84d817107fc028e049980e09d5e140e8da8f1caeb17e8e950658a3cea9" [[package]] name = "async-trait" -version = "0.1.52" +version = "0.1.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3" +checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600" dependencies = [ "proc-macro2", "quote", @@ -225,17 +231,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "blake2b_simd" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" -dependencies = [ - "arrayref", - "arrayvec", - "constant_time_eq", -] - [[package]] name = "block" version = "0.1.6" @@ -244,9 +239,9 @@ checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" [[package]] name = "block-buffer" -version = "0.9.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" dependencies = [ "generic-array", ] @@ -280,18 +275,18 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.7.3" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439989e6b8c38d1b6570a384ef1e49c8848128f5a97f3914baef02920842712f" +checksum = "cdead85bdec19c194affaeeb670c0e41fe23de31459efd1c174d049269cf02cc" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e215f8c2f9f79cb53c8335e687ffd07d5bfcb6fe5fc80723762d0be46e7cc54" +checksum = "562e382481975bc61d11275ac5e62a19abd00b0547d99516a415336f183dcd0e" dependencies = [ "proc-macro2", "quote", @@ -332,11 +327,17 @@ version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cfb" -version = "0.4.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca453e8624711b2f0f4eb47076a318feda166252a827ee25d067b43de83dcba0" +checksum = "74f89d248799e3f15f91b70917f65381062a01bb8e222700ea0e5a7ff9785f9c" dependencies = [ "byteorder", "uuid", @@ -383,7 +384,7 @@ dependencies = [ "ahash", "chrono", "directories-next", - "getrandom 0.2.5", + "getrandom", "gloo-storage", "harmony_rust_sdk", "indexmap", @@ -401,14 +402,24 @@ dependencies = [ [[package]] name = "clipboard-win" -version = "3.1.1" +version = "4.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fdf5e01086b6be750428ba4a40619f847eb2e95756eee84b18e06e5f0b50342" +checksum = "2f3e1238132dc01f081e1cbb9dace14e5ef4c3a51ee244bd982275fb514605db" dependencies = [ - "lazy-bytes-cast", + "error-code", + "str-buf", "winapi", ] +[[package]] +name = "cmake" +version = "0.1.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" +dependencies = [ + "cc", +] + [[package]] name = "cocoa" version = "0.24.0" @@ -446,6 +457,16 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "combine" +version = "4.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a604e93b79d1808327a6fca85a6f2d69de66461e7620f5a4cbf5fb4d1d7c948" +dependencies = [ + "bytes", + "memchr", +] + [[package]] name = "concurrent-queue" version = "1.2.2" @@ -465,32 +486,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "copypasta" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4423d79fed83ebd9ab81ec21fa97144300a961782158287dc9bf7eddac37ff0b" -dependencies = [ - "clipboard-win", - "objc", - "objc-foundation", - "objc_id", - "smithay-clipboard", - "x11-clipboard", -] - [[package]] name = "core-foundation" version = "0.7.0" @@ -575,9 +570,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" dependencies = [ "libc", ] @@ -593,9 +588,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" +checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -614,10 +609,11 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9" +checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" dependencies = [ + "autocfg", "cfg-if 1.0.0", "crossbeam-utils", "lazy_static", @@ -627,14 +623,24 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" dependencies = [ "cfg-if 1.0.0", "lazy_static", ] +[[package]] +name = "crypto-common" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "cty" version = "0.2.2" @@ -643,9 +649,9 @@ checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" [[package]] name = "darling" -version = "0.13.1" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0d720b8683f8dd83c65155f0530560cba68cd2bf395f6513a483caee57ff7f4" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" dependencies = [ "darling_core", "darling_macro", @@ -653,9 +659,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.13.1" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a340f241d2ceed1deb47ae36c4144b2707ec7dd0b649f894cb39bb595986324" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" dependencies = [ "fnv", "ident_case", @@ -667,9 +673,9 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.13.1" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c41b3b7352feb3211a0d743dc5700a4e3b60f51bd2b368892d1e0f9a95f44b" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ "darling_core", "quote", @@ -696,37 +702,14 @@ dependencies = [ "syn", ] -[[package]] -name = "derive-new" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3418329ca0ad70234b9735dc4ceed10af4df60eff9c8e7b06cb5e520d92c3535" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn", -] - [[package]] name = "digest" -version = "0.9.0" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" dependencies = [ - "generic-array", + "block-buffer", + "crypto-common", ] [[package]] @@ -740,14 +723,13 @@ dependencies = [ ] [[package]] -name = "dirs" -version = "1.0.5" +name = "dirs-next" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" dependencies = [ - "libc", - "redox_users 0.3.5", - "winapi", + "cfg-if 1.0.0", + "dirs-sys-next", ] [[package]] @@ -757,7 +739,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", - "redox_users 0.4.0", + "redox_users", "winapi", ] @@ -790,20 +772,28 @@ checksum = "6907e25393cdcc1f4f3f513d9aac1e840eb1cc341a0fccb01171f7d14d10b946" [[package]] name = "eframe" -version = "0.16.0" -source = "git+https://github.com/yusdacra/egui.git?branch=loqui#60e407e74b3f95b5acf4b89dec36a964978a6b16" +version = "0.17.0" +source = "git+https://github.com/yusdacra/egui.git?branch=loqui#a9bba9380e4abfa0cf9dea62ed9cc408eba76191" dependencies = [ + "bytemuck", "egui", "egui-winit", "egui_glow", - "egui_web", - "epi", + "glow", + "glutin", + "js-sys", + "percent-encoding", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winit", ] [[package]] name = "egui" -version = "0.16.1" -source = "git+https://github.com/yusdacra/egui.git?branch=loqui#60e407e74b3f95b5acf4b89dec36a964978a6b16" +version = "0.17.0" +source = "git+https://github.com/yusdacra/egui.git?branch=loqui#a9bba9380e4abfa0cf9dea62ed9cc408eba76191" dependencies = [ "ahash", "epaint", @@ -814,51 +804,31 @@ dependencies = [ [[package]] name = "egui-winit" -version = "0.16.0" -source = "git+https://github.com/yusdacra/egui.git?branch=loqui#60e407e74b3f95b5acf4b89dec36a964978a6b16" +version = "0.17.0" +source = "git+https://github.com/yusdacra/egui.git?branch=loqui#a9bba9380e4abfa0cf9dea62ed9cc408eba76191" dependencies = [ - "copypasta", + "arboard", "egui", - "epi", "instant", "tracing", - "webbrowser", + "webbrowser 0.6.0", "winit", ] [[package]] name = "egui_glow" -version = "0.16.0" -source = "git+https://github.com/yusdacra/egui.git?branch=loqui#60e407e74b3f95b5acf4b89dec36a964978a6b16" +version = "0.17.0" +source = "git+https://github.com/yusdacra/egui.git?branch=loqui#a9bba9380e4abfa0cf9dea62ed9cc408eba76191" dependencies = [ "bytemuck", "egui", - "egui-winit", - "epi", "glow", - "glutin", "memoffset", "tracing", "wasm-bindgen", "web-sys", ] -[[package]] -name = "egui_web" -version = "0.16.0" -source = "git+https://github.com/yusdacra/egui.git?branch=loqui#60e407e74b3f95b5acf4b89dec36a964978a6b16" -dependencies = [ - "bytemuck", - "egui", - "egui_glow", - "epi", - "js-sys", - "tracing", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "either" version = "1.6.1" @@ -867,8 +837,8 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "emath" -version = "0.16.0" -source = "git+https://github.com/yusdacra/egui.git?branch=loqui#60e407e74b3f95b5acf4b89dec36a964978a6b16" +version = "0.17.0" +source = "git+https://github.com/yusdacra/egui.git?branch=loqui#a9bba9380e4abfa0cf9dea62ed9cc408eba76191" dependencies = [ "bytemuck", "serde", @@ -876,18 +846,18 @@ dependencies = [ [[package]] name = "encoding_rs" -version = "0.8.30" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" +checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" dependencies = [ "cfg-if 1.0.0", ] [[package]] name = "enumflags2" -version = "0.7.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a25c90b056b3f84111cf183cbeddef0d3a0bbe9a674f057e1a1533c315f24def" +checksum = "e75d4cd21b95383444831539909fbb14b9dc3fdceb2a6f5d36577329a1f55ccb" dependencies = [ "enumflags2_derive", "serde", @@ -895,9 +865,9 @@ dependencies = [ [[package]] name = "enumflags2_derive" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "144ec79496cbab6f84fa125dc67be9264aef22eb8a28da8454d9c33f15108da4" +checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae" dependencies = [ "proc-macro2", "quote", @@ -906,8 +876,8 @@ dependencies = [ [[package]] name = "epaint" -version = "0.16.0" -source = "git+https://github.com/yusdacra/egui.git?branch=loqui#60e407e74b3f95b5acf4b89dec36a964978a6b16" +version = "0.17.0" +source = "git+https://github.com/yusdacra/egui.git?branch=loqui#a9bba9380e4abfa0cf9dea62ed9cc408eba76191" dependencies = [ "ab_glyph", "ahash", @@ -915,16 +885,18 @@ dependencies = [ "bytemuck", "emath", "nohash-hasher", + "parking_lot 0.12.0", "serde", ] [[package]] -name = "epi" -version = "0.16.0" -source = "git+https://github.com/yusdacra/egui.git?branch=loqui#60e407e74b3f95b5acf4b89dec36a964978a6b16" +name = "error-code" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64f18991e7bf11e7ffee451b5318b5c1a73c52d0d0ada6e5a3017c8c1ced6a21" dependencies = [ - "egui", - "tracing", + "libc", + "str-buf", ] [[package]] @@ -950,14 +922,14 @@ checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e" [[package]] name = "flate2" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" +checksum = "b39522e96686d38f4bc984b9198e3a0613264abaebaff2c5c918bfa6b6da09af" dependencies = [ "cfg-if 1.0.0", "crc32fast", "libc", - "miniz_oxide 0.4.4", + "miniz_oxide", ] [[package]] @@ -1106,21 +1078,20 @@ dependencies = [ ] [[package]] -name = "getrandom" -version = "0.1.16" +name = "gethostname" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" dependencies = [ - "cfg-if 1.0.0", "libc", - "wasi 0.9.0+wasi-snapshot-preview1", + "winapi", ] [[package]] name = "getrandom" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77" +checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -1150,11 +1121,31 @@ dependencies = [ "xml-rs", ] +[[package]] +name = "gloo-net" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2899cb1a13be9020b010967adc6b2a8a343b6f1428b90238c9d53ca24decc6db" +dependencies = [ + "futures-channel", + "futures-core", + "futures-sink", + "gloo-utils", + "js-sys", + "pin-project", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "gloo-storage" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5057761927af1b1929d02b1f49cf83553dd347a473ee7c8bb08420f2673ffc" +checksum = "1caa4ba51c99de680dee3ad99c32ca45e9f13311be72079154d222c3f9a6b6f5" dependencies = [ "gloo-utils", "js-sys", @@ -1167,9 +1158,9 @@ dependencies = [ [[package]] name = "gloo-timers" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d12a7f4e95cfe710f1d624fb1210b7d961a5fb05c4fd942f4feab06e61f590e" +checksum = "5fb7d06c1c8cc2a29bee7ec961009a0b2caa0793ee4900c2ffb348734ba1c8f9" dependencies = [ "futures-channel", "futures-core", @@ -1179,9 +1170,9 @@ dependencies = [ [[package]] name = "gloo-utils" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05c77af6f96a4f9e27c8ac23a88407381a31f4a74c3fb985c85aa79b8d898136" +checksum = "5c0bbef55e98d946adbd89f3c65a497cf9adb995a73b99573f30180e8813ab21" dependencies = [ "js-sys", "wasm-bindgen", @@ -1220,7 +1211,7 @@ dependencies = [ "log", "objc", "osmesa-sys", - "parking_lot", + "parking_lot 0.11.2", "wayland-client", "wayland-egl", "winapi", @@ -1274,9 +1265,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.11" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9f1f717ddc7b2ba36df7e871fd88db79326551d3d6f1fc406fbfd28b582ff8e" +checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" dependencies = [ "bytes", "fnv", @@ -1294,7 +1285,7 @@ dependencies = [ [[package]] name = "harmony_build" version = "0.1.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=master#4aae84c93d6b8dd3b9932ff7c76309778c4e669f" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#96b75d8f7b065b1269e186d8b43eb306843478e1" dependencies = [ "hrpc-build", "prost-build", @@ -1305,7 +1296,7 @@ dependencies = [ [[package]] name = "harmony_derive" version = "0.1.3" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=master#4aae84c93d6b8dd3b9932ff7c76309778c4e669f" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#96b75d8f7b065b1269e186d8b43eb306843478e1" dependencies = [ "proc-macro2", "quote", @@ -1315,10 +1306,8 @@ dependencies = [ [[package]] name = "harmony_rust_sdk" version = "0.8.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=master#4aae84c93d6b8dd3b9932ff7c76309778c4e669f" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#96b75d8f7b065b1269e186d8b43eb306843478e1" dependencies = [ - "derive-new", - "derive_more", "harmony_build", "harmony_derive", "hrpc", @@ -1355,6 +1344,12 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -1372,14 +1367,13 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hrpc" -version = "0.33.22" +version = "0.33.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7808b92a1a40d44ed5ea66d2fca9dbabe5d9a694d95c5ca49b05b87886345135" +checksum = "e202d7fc9f596c3dc80f3af80fdcbbc54164f42b37b2cdf119b7d22562739a0e" dependencies = [ "bytes", "futures-util", "gloo-timers", - "hrpc-build", "http", "http-body", "hyper", @@ -1400,9 +1394,9 @@ dependencies = [ [[package]] name = "hrpc-build" -version = "0.33.0" +version = "0.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "370eb264a57b2841bf588ab01a4de725df1a99a0410956b3010dc3663044f34d" +checksum = "ace803952c7504e41d30016a4e2573cc3f97bdd32479f951eb3e68c2b48d6a24" dependencies = [ "proc-macro2", "prost-build", @@ -1412,9 +1406,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03" +checksum = "ff8670570af52249509a86f5e3e18a08c60b177071826898fde8997cf5f6bfbb" dependencies = [ "bytes", "fnv", @@ -1434,9 +1428,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.6.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9100414882e15fb7feccb4897e5f0ff0ff1ca7d1a86a23208ada4d7a18e6c6c4" +checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" [[package]] name = "httpdate" @@ -1446,9 +1440,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" -version = "0.14.17" +version = "0.14.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "043f0e083e9901b6cc658a77d1eb86f4fc650bbb977a4337dd63192826aa85dd" +checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2" dependencies = [ "bytes", "futures-channel", @@ -1501,14 +1495,14 @@ dependencies = [ [[package]] name = "image" -version = "0.24.1" -source = "git+https://github.com/image-rs/image.git?branch=master#060a41c491a7b9cb7d1ebb3be5a100c8c3c73972" +version = "0.24.2" +source = "git+https://github.com/image-rs/image.git?branch=master#9112bc8af73fd07bab7d9a25f5f0427af758929e" dependencies = [ "bytemuck", "byteorder", "color_quant", "gif", - "jpeg-decoder 0.2.2", + "jpeg-decoder", "num-iter", "num-rational", "num-traits", @@ -1530,9 +1524,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" +checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" dependencies = [ "autocfg", "hashbrown 0.11.2", @@ -1540,9 +1534,9 @@ dependencies = [ [[package]] name = "infer" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fe51fa1be60e2a136243674bf4b938279ebddc7019dd5671211e375145759e9" +checksum = "20b2b533137b9cad970793453d4f921c2e91312a6d88b1085c07bc15fc51bb3b" dependencies = [ "cfb", ] @@ -1561,9 +1555,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.3.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" +checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" [[package]] name = "itertools" @@ -1581,31 +1575,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" [[package]] -name = "jni-sys" -version = "0.3.0" +name = "jni" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] [[package]] -name = "jpeg-decoder" -version = "0.1.22" +name = "jni-sys" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jpeg-decoder" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "105fb082d64e2100074587f59a74231f771750c664af903f1f9f76c9dedfc6f1" +checksum = "744c24117572563a98a7e9168a5ac1ee4a1ca7f702211258797bbe0ed0346c3c" dependencies = [ "rayon", ] [[package]] name = "js-sys" -version = "0.3.56" +version = "0.3.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" +checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" dependencies = [ "wasm-bindgen", ] @@ -1616,12 +1618,6 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" -[[package]] -name = "lazy-bytes-cast" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10257499f089cd156ad82d0a9cd57d9501fa2c989068992a97eb3c27836f206b" - [[package]] name = "lazy_static" version = "1.4.0" @@ -1630,9 +1626,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.119" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" +checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" [[package]] name = "libloading" @@ -1646,18 +1642,19 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" dependencies = [ + "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.14" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" dependencies = [ "cfg-if 1.0.0", ] @@ -1694,19 +1691,20 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webbrowser", + "webbrowser 0.7.1", ] [[package]] name = "mac-notification-sys" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb6b71a9a89cd38b395d994214297447e8e63b1ba5708a9a2b0b1048ceda76" +checksum = "297c13fc8ff9fa8b2d0e53850f80e0aa962628e865d447031ce58cdb062e5b29" dependencies = [ "cc", - "chrono", - "dirs", + "dirs-next", "objc-foundation", + "objc_id", + "time 0.3.9", ] [[package]] @@ -1735,9 +1733,9 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "memchr" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memmap2" @@ -1779,16 +1777,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" -dependencies = [ - "adler", - "autocfg", -] - [[package]] name = "miniz_oxide" version = "0.5.1" @@ -1800,14 +1788,15 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2" +checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9" dependencies = [ "libc", "log", "miow", "ntapi", + "wasi 0.11.0+wasi-snapshot-preview1", "winapi", ] @@ -1834,30 +1823,58 @@ checksum = "96d868f654c72e75f8687572699cdabe755f03effbb62542768e995d5b8d699d" dependencies = [ "bitflags", "jni-sys", - "ndk-sys", + "ndk-sys 0.2.2", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" +dependencies = [ + "bitflags", + "jni-sys", + "ndk-sys 0.3.0", "num_enum", "thiserror", ] [[package]] name = "ndk-context" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5cc68637e21fe8f077f6a1c9e0b9ca495bb74895226b476310f613325884" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" [[package]] name = "ndk-glue" -version = "0.5.1" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71bee8ea72d685477e28bd004cfe1bf99c754d688cd78cad139eae4089484d4" +dependencies = [ + "lazy_static", + "libc", + "log", + "ndk 0.5.0", + "ndk-context", + "ndk-macro", + "ndk-sys 0.2.2", +] + +[[package]] +name = "ndk-glue" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1c68f70683c5fc9a747a383744206cd371741b2f0b31781ab6770487ec572e2" +checksum = "0d0c4a7b83860226e6b4183edac21851f05d5a51756e97a1144b7f5a6b63e65f" dependencies = [ "lazy_static", "libc", "log", - "ndk", + "ndk 0.6.0", "ndk-context", "ndk-macro", - "ndk-sys", + "ndk-sys 0.3.0", ] [[package]] @@ -1879,6 +1896,15 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121" +[[package]] +name = "ndk-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97" +dependencies = [ + "jni-sys", +] + [[package]] name = "nix" version = "0.22.3" @@ -1913,20 +1939,19 @@ checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" [[package]] name = "nom" -version = "7.1.0" +version = "7.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" dependencies = [ "memchr", "minimal-lexical", - "version_check", ] [[package]] name = "notify-rust" -version = "4.5.6" +version = "4.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "367e1355a950d3e758e414f3ca1b3981a57a2aa1fa3338eb0059f5b230b6ffa4" +checksum = "a995a3d2834cefa389218e7a35156e8ce544bc95f836900da01ee0b26a07e9d4" dependencies = [ "mac-notification-sys", "serde", @@ -1947,9 +1972,9 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ "autocfg", "num-traits", @@ -1957,9 +1982,9 @@ dependencies = [ [[package]] name = "num-iter" -version = "0.1.42" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" dependencies = [ "autocfg", "num-integer", @@ -1998,18 +2023,18 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "720d3ea1055e4e4574c0c0b0f8c3fd4f24c4cdaf465948206dea090b57b526ad" +checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d992b768490d7fe0d8586d9b5745f6c49f557da6d81dc982b1d167ad4edbb21" +checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -2019,9 +2044,9 @@ dependencies = [ [[package]] name = "num_threads" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ba99ba6393e2c3734791401b66902d981cb03bf190af674ca69949b6d5fb15" +checksum = "aba1801fb138d8e85e11d0fc70baf4fe1cdfffda7c6cd34a854905df588e5ed0" dependencies = [ "libc", ] @@ -2057,21 +2082,15 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" - -[[package]] -name = "opaque-debug" -version = "0.3.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" [[package]] name = "open" -version = "2.1.0" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a82915836ef43159bb6a3c64d884c42329ccd0b8afdca737cf1e3dd701709dc" +checksum = "e0524af9508f9b5c4eb41dce095860456727748f63b478d625f119a70e0d764a" dependencies = [ "pathdiff", "winapi", @@ -2104,9 +2123,9 @@ dependencies = [ [[package]] name = "owned_ttf_parser" -version = "0.14.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ef05f2882a8b3e7acc10c153ade2631f7bfc8ce00d2bf3fb8f4e9d2ae6ea5c3" +checksum = "4fb1e509cfe7a12db2a90bfa057dfcdbc55a347f5da677c506b53dd099cfec9d" dependencies = [ "ttf-parser", ] @@ -2125,7 +2144,17 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", - "parking_lot_core", + "parking_lot_core 0.8.5", +] + +[[package]] +name = "parking_lot" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.3", ] [[package]] @@ -2137,11 +2166,24 @@ dependencies = [ "cfg-if 1.0.0", "instant", "libc", - "redox_syscall 0.2.10", + "redox_syscall", "smallvec", "winapi", ] +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + [[package]] name = "pathdiff" version = "0.2.1" @@ -2196,9 +2238,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" [[package]] name = "pin-utils" @@ -2208,20 +2250,20 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" [[package]] name = "png" -version = "0.17.3" +version = "0.17.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8f1882177b17c98ec33a51f5910ecbf4db92ca0def706781a1f8d0c661f393" +checksum = "dc38c0ad57efb786dd57b9864e5b18bae478c00c824dc55a38bbc9da95dde3ba" dependencies = [ "bitflags", "crc32fast", "deflate", - "miniz_oxide 0.5.1", + "miniz_oxide", ] [[package]] @@ -2261,18 +2303,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" dependencies = [ "unicode-xid", ] [[package]] name = "prost" -version = "0.9.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" +checksum = "a07b0857a71a8cb765763950499cae2413c3f9cede1133478c43600d9e146890" dependencies = [ "bytes", "prost-derive", @@ -2280,12 +2322,14 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.9.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5" +checksum = "120fbe7988713f39d780a58cf1a7ef0d7ef66c6d87e5aa3438940c05357929f4" dependencies = [ "bytes", - "heck", + "cfg-if 1.0.0", + "cmake", + "heck 0.4.0", "itertools", "lazy_static", "log", @@ -2300,9 +2344,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.9.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" +checksum = "7b670f45da57fb8542ebdbb6105a925fe571b67f9e7ed9f47a06a84e72b4e7cc" dependencies = [ "anyhow", "itertools", @@ -2313,9 +2357,9 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.9.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a" +checksum = "2d0a014229361011dc8e69c8a1ec6c2e8d0f2af7c91e3ea3f5b2170298461e68" dependencies = [ "bytes", "prost", @@ -2341,20 +2385,11 @@ dependencies = [ "syn", ] -[[package]] -name = "quick-xml" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8533f14c8382aaad0d592c812ac3b826162128b65662331e1127b45c3d18536b" -dependencies = [ - "memchr", -] - [[package]] name = "quote" -version = "1.0.15" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ "proc-macro2", ] @@ -2386,23 +2421,23 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ - "getrandom 0.2.5", + "getrandom", ] [[package]] name = "raw-window-handle" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fba75eee94a9d5273a68c9e1e105d9cffe1ef700532325788389e5a83e2522b7" +checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41" dependencies = [ "cty", ] [[package]] name = "rayon" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +checksum = "fd249e82c21598a9a426a4e00dd7adc1d640b22445ec8545feef801d1a74c221" dependencies = [ "autocfg", "crossbeam-deque", @@ -2412,58 +2447,41 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.9.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +checksum = "9f51245e1e62e1f1629cbfec37b5793bbabcaeb90f30e94d2ba03564687353e4" dependencies = [ "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "lazy_static", "num_cpus", ] [[package]] name = "redox_syscall" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - -[[package]] -name = "redox_syscall" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" dependencies = [ "bitflags", ] [[package]] name = "redox_users" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" -dependencies = [ - "getrandom 0.1.16", - "redox_syscall 0.1.57", - "rust-argon2", -] - -[[package]] -name = "redox_users" -version = "0.4.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.2.5", - "redox_syscall 0.2.10", + "getrandom", + "redox_syscall", + "thiserror", ] [[package]] name = "regex" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" dependencies = [ "aho-corasick", "memchr", @@ -2505,23 +2523,18 @@ dependencies = [ [[package]] name = "reqwasm" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee625fb8e28ee1dac344e1d135c3b9815ddd5b44b3062cb69fe83168e5225a10" +checksum = "05b89870d729c501fa7a68c43bf4d938bbb3a8c156d333d90faa0e8b3e3212fb" dependencies = [ - "gloo-utils", - "js-sys", - "thiserror", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", + "gloo-net", ] [[package]] name = "reqwest" -version = "0.11.9" +version = "0.11.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f242f1488a539a79bac6dbe7c8609ae43b7914b7736210f239a37cccb32525" +checksum = "46a1f7aa4f35e5e8b4160449f51afc758f0ce6454315a9fa7d0d113e958c41eb" dependencies = [ "base64", "bytes", @@ -2543,7 +2556,7 @@ dependencies = [ "pin-project-lite", "rustls", "rustls-native-certs", - "rustls-pemfile", + "rustls-pemfile 0.3.0", "serde", "serde_json", "serde_urlencoded", @@ -2558,9 +2571,9 @@ dependencies = [ [[package]] name = "rfd" -version = "0.7.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aaf1d71ccd44689f7c2c72da1117fd8db71f72a76fe9b5c5dbb17ab903007e0" +checksum = "92e3107b2e81967df7c0617e978dc656795583a73ad0ddbf645ce60109caf8c2" dependencies = [ "ashpd", "block", @@ -2575,7 +2588,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "windows 0.30.0", + "windows 0.35.0", ] [[package]] @@ -2595,9 +2608,9 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.7.35" +version = "0.7.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cdcf5caf69bcc87b1e3f5427b4f21a32fdd53c2847687bdf9861abb1cdaa0d8" +checksum = "1f08c8062c1fe1253064043b8fc07bfea1b9702b71b4a86c11ea3588183b12e1" dependencies = [ "bytecheck", "hashbrown 0.12.0", @@ -2609,27 +2622,15 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.7.35" +version = "0.7.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cf557da1f81b8c7e889c59c9c3abaf6978f7feb156b9579e4f8bf6d7a2bada" +checksum = "e289706df51226e84814bf6ba1a9e1013112ae29bc7a9878f73fce360520c403" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "rust-argon2" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" -dependencies = [ - "base64", - "blake2b_simd", - "constant_time_eq", - "crossbeam-utils", -] - [[package]] name = "rustc_version" version = "0.4.0" @@ -2653,21 +2654,30 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca9ebdfa27d3fc180e42879037b5338ab1c040c06affd00d8338598e7800943" +checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" dependencies = [ "openssl-probe", - "rustls-pemfile", + "rustls-pemfile 1.0.0", "schannel", "security-framework", ] [[package]] name = "rustls-pemfile" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" +checksum = "1ee86d63972a7c661d1536fefe8c3c8407321c3df668891286de28abcd087360" +dependencies = [ + "base64", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7522c9de787ff061458fe9a829dc790a3f5b22dc571694fc5883f448b94d9a9" dependencies = [ "base64", ] @@ -2750,9 +2760,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a3381e03edd24287172047536f20cabde766e2cd3e65e6b00fb3af51c4f38d" +checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4" [[package]] name = "send_wrapper" @@ -2816,15 +2826,13 @@ dependencies = [ [[package]] name = "sha-1" -version = "0.9.8" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" +checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" dependencies = [ - "block-buffer", "cfg-if 1.0.0", "cpufeatures", "digest", - "opaque-debug", ] [[package]] @@ -2863,9 +2871,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" [[package]] name = "slotmap" @@ -2884,9 +2892,9 @@ checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" [[package]] name = "smithay-client-toolkit" -version = "0.15.3" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1325f292209cee78d5035530932422a30aa4c8fda1a16593ac083c1de211e68a" +checksum = "8a28f16a97fa0e8ce563b2774d1e732dd5d4025d2772c5dba0a41a0f90a29da3" dependencies = [ "bitflags", "calloop", @@ -2901,21 +2909,11 @@ dependencies = [ "wayland-protocols", ] -[[package]] -name = "smithay-clipboard" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "610b551bd25378bfd2b8e7a0fcbd83d427e8f2f6a40c47ae0f70688e9949dd55" -dependencies = [ - "smithay-client-toolkit", - "wayland-client", -] - [[package]] name = "smol_str" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61d15c83e300cce35b7c8cd39ff567c1ef42dde6d4a1a38dbdbf9a59902261bd" +checksum = "7475118a28b7e3a2e157ce0131ba8c5526ea96e90ee601d9f6bb2e286a35ab44" dependencies = [ "serde", ] @@ -2942,6 +2940,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "str-buf" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a" + [[package]] name = "strsim" version = "0.10.0" @@ -2963,7 +2967,7 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "339f799d8b549e3744c7ac7feb216383e4005d94bdb22561b3ab8f3b808ae9fb" dependencies = [ - "heck", + "heck 0.3.3", "proc-macro2", "quote", "syn", @@ -2971,9 +2975,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.86" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" +checksum = "7ff7c592601f11445996a06f8ad0c27f094a58857c2f89e97974ab9235b92c52" dependencies = [ "proc-macro2", "quote", @@ -2989,7 +2993,7 @@ dependencies = [ "cfg-if 1.0.0", "fastrand", "libc", - "redox_syscall 0.2.10", + "redox_syscall", "remove_dir_all", "winapi", ] @@ -3025,12 +3029,12 @@ dependencies = [ [[package]] name = "tiff" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0247608e998cb6ce39dfc8f4a16c50361ce71e5b52e6d24ea1227ea8ea8ee0b2" +checksum = "7cfada0986f446a770eca461e8c6566cb879682f7d687c8348aa0c857bd52286" dependencies = [ "flate2", - "jpeg-decoder 0.1.22", + "jpeg-decoder", "weezl", ] @@ -3047,9 +3051,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "004cbc98f30fa233c61a38bc77e96a9106e65c88f2d3bef182ae952027e5753d" +checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" dependencies = [ "itoa", "libc", @@ -3058,9 +3062,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] @@ -3073,15 +3077,16 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" +checksum = "0f48b6d60512a392e34dbf7fd456249fd2de3c83669ab642e021903f4015185b" dependencies = [ "bytes", "libc", "memchr", "mio", "num_cpus", + "once_cell", "pin-project-lite", "socket2", "tokio-macros", @@ -3101,9 +3106,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.23.2" +version = "0.23.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27d5f2b839802bd8267fa19b0530f5a08b9c08cd417976be2a65d130fe1c11b" +checksum = "4151fda0cf2798550ad0b34bcfc9b9dcc2a9d2471c895c68f3a8818e54f2389e" dependencies = [ "rustls", "tokio", @@ -3112,9 +3117,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.16.1" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e80b39df6afcc12cdf752398ade96a6b9e99c903dfdc36e53ad10b9c366bca72" +checksum = "06cda1232a49558c46f8a504d5b93101d42c0bf7f911f12a105ba48168f821ae" dependencies = [ "futures-util", "log", @@ -3128,23 +3133,23 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.6.9" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" +checksum = "0edfdeb067411dba2044da6d1cb2df793dd35add7888d73c16e3381ded401764" dependencies = [ "bytes", "futures-core", "futures-sink", - "log", "pin-project-lite", "tokio", + "tracing", ] [[package]] name = "toml" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" dependencies = [ "serde", ] @@ -3177,9 +3182,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.31" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6c650a8ef0cd2dd93736f033d21cbd1224c5a967aa0c258d00fcf7dafef9b9f" +checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" dependencies = [ "cfg-if 1.0.0", "pin-project-lite", @@ -3189,20 +3194,20 @@ dependencies = [ [[package]] name = "tracing-appender" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94571df2eae3ed4353815ea5a90974a594a1792d8782ff2cbcc9392d1101f366" +checksum = "09d48f71a791638519505cefafe162606f706c25592e4bde4d97600c0195312e" dependencies = [ "crossbeam-channel", - "time 0.3.7", + "time 0.3.9", "tracing-subscriber", ] [[package]] name = "tracing-attributes" -version = "0.1.19" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8276d9a4a3a558d7b7ad5303ad50b53d58264641b82914b7ada36bd762e7a716" +checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" dependencies = [ "proc-macro2", "quote", @@ -3211,9 +3216,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.22" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23" +checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" dependencies = [ "lazy_static", "valuable", @@ -3221,9 +3226,9 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" dependencies = [ "lazy_static", "log", @@ -3232,9 +3237,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.9" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e0ab7bdc962035a87fba73f3acca9b8a8d0034c2e6f60b84aeaaddddc155dce" +checksum = "4bc28f93baff38037f64e6f43d34cfa1605f27a49c34e8a04c5e78b0babf2596" dependencies = [ "ansi_term", "lazy_static", @@ -3267,15 +3272,15 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "ttf-parser" -version = "0.14.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ccbe8381883510b6a2d8f1e32905bddd178c11caef8083086d0c0c9ab0ac281" +checksum = "c74c96594835e10fa545e2a51e8709f30b173a092bfd6036ef2cec53376244f3" [[package]] name = "tungstenite" -version = "0.16.0" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ad3713a14ae247f22a728a0456a545df14acf3867f905adff84be99e23b3ad1" +checksum = "d96a2dea40e7570482f28eb57afbe42d97551905da6a9400acc5c328d24004f5" dependencies = [ "base64", "byteorder", @@ -3309,9 +3314,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-normalization" @@ -3411,21 +3416,21 @@ dependencies = [ [[package]] name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" +version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" +checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" dependencies = [ "cfg-if 1.0.0", "serde", @@ -3435,9 +3440,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" +checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" dependencies = [ "bumpalo", "lazy_static", @@ -3450,9 +3455,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.29" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb6ec270a31b1d3c7e266b999739109abce8b6c87e4b31fcfcd788b65267395" +checksum = "6f741de44b75e14c35df886aff5f1eb73aa114fa5d4d00dcd37b5e01259bf3b2" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -3462,9 +3467,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" +checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3472,9 +3477,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" +checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" dependencies = [ "proc-macro2", "quote", @@ -3485,9 +3490,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" +checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" [[package]] name = "wasm-streams" @@ -3587,9 +3592,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.56" +version = "0.3.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" +checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" dependencies = [ "js-sys", "wasm-bindgen", @@ -3597,10 +3602,27 @@ dependencies = [ [[package]] name = "webbrowser" -version = "0.5.5" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecad156490d6b620308ed411cfee90d280b3cbd13e189ea0d3fada8acc89158a" +checksum = "f9c28b6b6a78440b02647358625e3febc90724126480b9da6a967b5f674b3554" dependencies = [ + "jni", + "ndk-glue 0.6.2", + "url", + "web-sys", + "widestring", + "winapi", +] + +[[package]] +name = "webbrowser" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a3cffdb686fbb24d9fb8f03a213803277ed2300f11026a3afe1f108dc021b" +dependencies = [ + "jni", + "ndk-glue 0.6.2", + "url", "web-sys", "widestring", "winapi", @@ -3618,9 +3640,9 @@ dependencies = [ [[package]] name = "weezl" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b77fdfd5a253be4ab714e4ffa3c49caf146b4de743e97510c0656cf90f1e8e" +checksum = "9c97e489d8f836838d497091de568cf16b117486d529ec5579233521065bd5e4" [[package]] name = "wepoll-ffi" @@ -3633,9 +3655,9 @@ dependencies = [ [[package]] name = "which" -version = "4.2.4" +version = "4.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a5a7e487e921cf220206864a94a89b6c6905bfc19f1057fa26a4cb360e5c1d2" +checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae" dependencies = [ "either", "lazy_static", @@ -3644,9 +3666,9 @@ dependencies = [ [[package]] name = "widestring" -version = "0.4.3" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c" +checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983" [[package]] name = "winapi" @@ -3673,6 +3695,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "winapi-wsapoll" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c17110f57155602a80dca10be03852116403c9ff3cd25b079d666f2aa3df6e" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -3693,22 +3724,41 @@ dependencies = [ [[package]] name = "windows" -version = "0.30.0" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08746b4b7ac95f708b3cccceb97b7f9a21a8916dd47fc99b0e6aaf7208f26fd7" +dependencies = [ + "windows_aarch64_msvc 0.35.0", + "windows_i686_gnu 0.35.0", + "windows_i686_msvc 0.35.0", + "windows_x86_64_gnu 0.35.0", + "windows_x86_64_msvc 0.35.0", +] + +[[package]] +name = "windows-sys" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b749ebd2304aa012c5992d11a25d07b406bdbe5f79d371cb7a918ce501a19eb0" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu 0.30.0", - "windows_i686_msvc 0.30.0", - "windows_x86_64_gnu 0.30.0", - "windows_x86_64_msvc 0.30.0", + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", ] [[package]] name = "windows_aarch64_msvc" -version = "0.30.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29277a4435d642f775f63c7d1faeb927adba532886ce0287bd985bffb16b6bca" +checksum = "db3bc5134e8ce0da5d64dcec3529793f1d33aee5a51fc2b4662e0f881dd463e6" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" [[package]] name = "windows_i686_gnu" @@ -3718,9 +3768,15 @@ checksum = "c0866510a3eca9aed73a077490bbbf03e5eaac4e1fd70849d89539e5830501fd" [[package]] name = "windows_i686_gnu" -version = "0.30.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1145e1989da93956c68d1864f32fb97c8f561a8f89a5125f6a2b7ea75524e4b8" +checksum = "0343a6f35bf43a07b009b8591b78b10ea03de86b06f48e28c96206cd0f453b50" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" [[package]] name = "windows_i686_msvc" @@ -3730,9 +3786,15 @@ checksum = "bf0ffed56b7e9369a29078d2ab3aaeceea48eb58999d2cff3aa2494a275b95c6" [[package]] name = "windows_i686_msvc" -version = "0.30.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a09e3a0d4753b73019db171c1339cd4362c8c44baf1bcea336235e955954a6" +checksum = "1acdcbf4ca63d8e7a501be86fee744347186275ec2754d129ddeab7a1e3a02e4" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" [[package]] name = "windows_x86_64_gnu" @@ -3742,9 +3804,15 @@ checksum = "384a173630588044205a2993b6864a2f56e5a8c1e7668c07b93ec18cf4888dc4" [[package]] name = "windows_x86_64_gnu" -version = "0.30.0" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "893c0924c5a990ec73cd2264d1c0cba1773a929e1a3f5dbccffd769f8c4edebb" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca64fcb0220d58db4c119e050e7af03c69e6f4f415ef69ec1773d9aab422d5a" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" [[package]] name = "windows_x86_64_msvc" @@ -3754,9 +3822,15 @@ checksum = "9bd8f062d8ca5446358159d79a90be12c543b3a965c847c8f3eedf14b321d399" [[package]] name = "windows_x86_64_msvc" -version = "0.30.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08cabc9f0066848fef4bc6a1c1668e6efce38b661d2aeec75d18d8617eebb5f1" +checksum = "a29bd61f32889c822c99a8fdf2e93378bd2fae4d7efd2693fab09fcaaf7eff4b" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" [[package]] name = "winit" @@ -3775,11 +3849,11 @@ dependencies = [ "libc", "log", "mio", - "ndk", - "ndk-glue", - "ndk-sys", + "ndk 0.5.0", + "ndk-glue 0.5.2", + "ndk-sys 0.2.2", "objc", - "parking_lot", + "parking_lot 0.11.2", "percent-encoding", "raw-window-handle", "smithay-client-toolkit", @@ -3793,9 +3867,9 @@ dependencies = [ [[package]] name = "winreg" -version = "0.7.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi", ] @@ -3829,15 +3903,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "x11-clipboard" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "473068b7b80ac86a18328824f1054e5e007898c47b5bbc281bd7abe32bc3653c" -dependencies = [ - "xcb", -] - [[package]] name = "x11-dl" version = "2.19.1" @@ -3850,14 +3915,15 @@ dependencies = [ ] [[package]] -name = "xcb" -version = "0.10.1" +name = "x11rb" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771e2b996df720cd1c6dd9ff90f62d91698fd3610cc078388d0564bdd6622a9c" +checksum = "6e99be55648b3ae2a52342f9a870c0e138709a3493261ce9b469afe6e4df6d8a" dependencies = [ - "libc", - "log", - "quick-xml", + "gethostname", + "nix 0.22.3", + "winapi", + "winapi-wsapoll", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 2d8843a..d06d0d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Yusuf Bera Ertan "] edition = "2021" description = "Rust client for the Harmony protocol." -license = "GPLv3" +license = "GPL-3.0-only" repository = "https://github.com/harmony-development/loqui" homepage = "https://github.com/harmony-development/loqui" resolver = "2" @@ -37,12 +37,9 @@ codegen-units = 1 panic = 'abort' [dependencies] -eframe = { git = "https://github.com/yusdacra/egui.git", branch = "loqui", default-features = false, features = [ - "egui_glow", -] } +eframe = { git = "https://github.com/yusdacra/egui.git", branch = "loqui", default-features = false } egui = { git = "https://github.com/yusdacra/egui.git", branch = "loqui", default-features = false, features = [ "serde", - "single_threaded", ] } epaint = { git = "https://github.com/yusdacra/egui.git", branch = "loqui", default-features = false, features = [ "serde", @@ -55,8 +52,8 @@ client = { path = "./client" } image_worker = { path = "./image_worker" } urlencoding = "2" -webbrowser = "0.5" -rfd = { version = "0.7", default-features = false, features = ["parent"] } +webbrowser = "0.7" +rfd = { version = "0.8", default-features = false, features = ["xdg-portal"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1" reqwest = { version = "0.11", default-features = false } @@ -75,6 +72,9 @@ web-sys = { version = "0.3", features = [ "MessageEvent", "Notification", "NotificationOptions", + "Blob", + "BlobPropertyBag", + "Url", ] } rkyv = "0.7" tokio = { version = "1.9", features = ["sync", "macros"] } @@ -126,9 +126,11 @@ runtimeLibs = [ [workspace.metadata.nix] buildInputs = ["libxkbcommon"] -devshell.packages = ["cargo-deny", "wasm-bindgen-cli"] -devshell.name = "loqui-shell" -devshell.commands = [{ package = "tagref" }] + +[workspace.metadata.nix.devshell] +packages = ["cargo-deny", "wasm-bindgen-cli"] +name = "loqui-shell" +commands = [{ package = "tagref" }] [package.metadata.nix.desktopFile] name = "Loqui" diff --git a/client/Cargo.toml b/client/Cargo.toml index 6364a2d..2eee8ca 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -8,7 +8,7 @@ repository = "https://github.com/harmony-development/loqui" homepage = "https://github.com/harmony-development/loqui" [dependencies] -infer = "0.6.0" +infer = "0.7.0" tokio = { version = "1.9", features = ["sync"] } ahash = "0.7" @@ -27,7 +27,7 @@ itertools = "0.10" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] directories-next = "2.0.0" -harmony_rust_sdk = { git = "https://github.com/harmony-development/harmony_rust_sdk.git", branch = "master", features = [ +harmony_rust_sdk = { git = "https://github.com/harmony-development/harmony_rust_sdk.git", branch = "refactored", features = [ "client_native", "client_backoff", "client_recommended", @@ -36,7 +36,7 @@ harmony_rust_sdk = { git = "https://github.com/harmony-development/harmony_rust_ getrandom = "0.2" [target.'cfg(target_arch = "wasm32")'.dependencies] -harmony_rust_sdk = { git = "https://github.com/harmony-development/harmony_rust_sdk.git", branch = "master", features = [ +harmony_rust_sdk = { git = "https://github.com/harmony-development/harmony_rust_sdk.git", branch = "refactored", features = [ "client_web", "client_backoff", "client_recommended", diff --git a/client/src/channel.rs b/client/src/channel.rs index c3e34b7..f5e8c07 100644 --- a/client/src/channel.rs +++ b/client/src/channel.rs @@ -1,9 +1,8 @@ -use indexmap::IndexSet; - use crate::role::RolePerms; -use super::message::Messages; +use super::message::{Messages, PinnedMessages}; use harmony_rust_sdk::api::chat::{permission::has_permission, Permission}; +use indexmap::IndexSet; use smol_str::SmolStr; #[derive(Default, Debug, Clone)] @@ -11,15 +10,42 @@ pub struct Channel { pub name: SmolStr, pub is_category: bool, pub messages: Messages, - pub pinned_messages: IndexSet, + pub pinned_messages: PinnedMessages, pub reached_top: bool, pub perms: Vec, pub role_perms: RolePerms, pub fetched_msgs_pins: bool, + pub private_channel_data: Option, } impl Channel { pub fn has_perm(&self, query: &str) -> bool { has_permission(self.perms.iter().map(|p| (p.matches.as_str(), p.ok)), query).unwrap_or(false) } + + pub fn get_priv_mut(&mut self) -> &mut PrivateChannel { + if self.private_channel_data.is_none() { + self.private_channel_data = Some(PrivateChannel::default()); + } + self.private_channel_data.as_mut().unwrap() + } + + /// Get the private channel data. + /// + /// # Panics + /// Panics if this is not a private channel. + pub fn get_priv(&self) -> &PrivateChannel { + self.private_channel_data + .as_ref() + .expect("not private channel -- this is a bug") + } +} + +#[derive(Default, Debug, Clone)] +pub struct PrivateChannel { + pub server_id: Option, + pub members: IndexSet, + pub owner: u64, + pub is_dm: bool, + pub fetched: bool, } diff --git a/client/src/guild.rs b/client/src/guild.rs index c6afbf5..00b6df8 100644 --- a/client/src/guild.rs +++ b/client/src/guild.rs @@ -2,7 +2,6 @@ use ahash::AHashMap; use harmony_rust_sdk::api::{ chat::{permission::has_permission, Invite, Permission}, harmonytypes::{item_position::Position, ItemPosition}, - rest::FileId, }; use smol_str::SmolStr; @@ -12,12 +11,12 @@ use crate::role::{Role, RolePerms, Roles}; pub struct Guild { pub name: SmolStr, pub owners: Vec, - pub picture: Option, + pub picture: Option, pub channels: Vec, pub roles: Roles, pub role_perms: RolePerms, pub members: AHashMap>, - pub homeserver: SmolStr, + pub homeserver: Option, pub perms: Vec, pub invites: AHashMap, pub fetched: bool, diff --git a/client/src/lib.rs b/client/src/lib.rs index 5b3c856..741e36c 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -21,20 +21,22 @@ use harmony_rust_sdk::{ api::{ auth::Session as InnerSession, chat::{ - all_permissions, color, + all_permissions, color, embed, get_channel_messages_request::Direction, + send_message_request, stream_event::{Event as ChatEvent, *}, - BanUserRequest, ChannelKind, Content as HarmonyContent, CreateChannelRequest, CreateGuildRequest, - CreateInviteRequest, DeleteChannelRequest, DeleteInviteRequest, DeleteMessageRequest, Event, FormattedText, - GetChannelMessagesRequest, GetGuildChannelsRequest, GetGuildInvitesRequest, GetGuildListRequest, - GetGuildMembersRequest, GetGuildRequest, GetGuildRolesRequest, GetMessageRequest, GetPermissionsRequest, - GetPinnedMessagesRequest, GetUserRolesRequest, Invite, JoinGuildRequest, KickUserRequest, - LeaveGuildRequest, Message as HarmonyMessage, Permission, PinMessageRequest, QueryHasPermissionRequest, - Role, SendMessageRequest, SetPermissionsRequest, TypingRequest, UnbanUserRequest, UnpinMessageRequest, - UpdateChannelInformationRequest, UpdateGuildInformationRequest, UpdateMessageTextRequest, + Attachment, BanUserRequest, ChannelKind, CreateChannelRequest, CreateGuildRequest, CreateInviteRequest, + DeleteChannelRequest, DeleteInviteRequest, DeleteMessageRequest, Embed, Event, GetChannelMessagesRequest, + GetGuildChannelsRequest, GetGuildInvitesRequest, GetGuildListRequest, GetGuildMembersRequest, + GetGuildRequest, GetGuildRolesRequest, GetMessageRequest, GetPermissionsRequest, GetPinnedMessagesRequest, + GetPrivateChannelListRequest, GetPrivateChannelRequest, GetUserRolesRequest, HasPermissionRequest, Invite, + JoinGuildRequest, KickUserRequest, LeaveGuildRequest, Message as HarmonyMessage, Permission, + PinMessageRequest, Role, SendMessageRequest, SetPermissionsRequest, TypingRequest, UnbanUserRequest, + UnpinMessageRequest, UpdateChannelInformationRequest, UpdateGuildInformationRequest, + UpdateMessageContentRequest, }, emote::{stream_event::Event as EmoteEvent, *}, - mediaproxy::{fetch_link_metadata_response::Data as FetchLinkData, FetchLinkMetadataRequest}, + mediaproxy::{fetch_link_metadata_response::metadata::Data as FetchLinkData, FetchLinkMetadataRequest}, profile::{stream_event::Event as ProfileEvent, UserStatus, *}, rest::{About, FileId}, }, @@ -43,21 +45,20 @@ use harmony_rust_sdk::{ use error::ClientResult; use instant::Instant; -use itertools::Itertools; use member::Member; -use message::{Attachment, Content, Embed, MessageId, ReadMessagesView, WriteMessagesView}; +use message::{AttachmentExt, MessageId, Messages, ReadMessagesView, WriteMessagesView}; use serde::{Deserialize, Serialize}; use smol_str::SmolStr; use std::{ + collections::HashMap, fmt::{self, Debug, Display, Formatter}, ops::Not, - str::FromStr, }; use crate::emotes::EmotePack; -use self::message::{EmbedHeading, Message}; +use self::message::Message; pub use ahash::{AHashMap, AHashSet, AHasher}; pub use smol_str; @@ -113,10 +114,11 @@ impl From for InnerSession { pub enum PostProcessEvent { FetchProfile(u64), FetchGuildData(u64), + FetchPrivateChannel(u64), FetchThumbnail(Attachment), CheckPermsForChannel(u64, u64), FetchMessage { - guild_id: u64, + guild_id: Option, channel_id: u64, message_id: u64, }, @@ -142,18 +144,18 @@ pub enum FetchEvent { file: DownloadedFile, }, FetchedReply { - guild_id: u64, + guild_id: Option, channel_id: u64, message_id: u64, message: HarmonyMessage, }, FailedToSendMessage { - guild_id: u64, + guild_id: Option, channel_id: u64, echo_id: u64, }, FetchedMessageHistory { - guild_id: u64, + guild_id: Option, channel_id: u64, messages: Vec<(u64, HarmonyMessage)>, anchor: Option, @@ -166,9 +168,28 @@ pub enum FetchEvent { picture: Option, owners: Vec, }, + FetchedPrivateChannel { + id: u64, + name: Option, + members: Vec, + is_dm: bool, + }, + FetchedProfile { + id: u64, + name: String, + picture: Option, + status: UserStatus, + kind: AccountKind, + }, InitialSyncComplete, } +impl FetchEvent { + fn new_chat(ev: ChatEvent) -> Self { + Self::Harmony(Event::Chat(ev)) + } +} + pub struct Cache { users: AHashMap, guilds: AHashMap, @@ -182,7 +203,7 @@ pub struct Cache { impl Cache { pub fn new(event_receiver: EventReceiver, post_sender: PostEventSender) -> Self { - Self { + let mut this = Self { event_receiver, post_sender, channels: Default::default(), @@ -191,7 +212,15 @@ impl Cache { initial_sync_complete: false, link_embeds: Default::default(), users: Default::default(), - } + }; + + // setup dm guild + let dms = this.get_guild_mut(0); + dms.name = "DMs".into(); + dms.fetched = true; + dms.fetched_invites = true; + + this } pub fn maintain(&mut self, mut event_fn: impl FnMut(FetchEvent) -> Option) { @@ -218,6 +247,10 @@ impl Cache { self.channels.entry((guild_id, channel_id)).or_default() } + fn get_priv_channel_mut(&mut self, channel_id: u64) -> &mut Channel { + self.get_channel_mut(0, channel_id) + } + fn get_user_mut(&mut self, user_id: u64) -> &mut Member { self.users.entry(user_id).or_default() } @@ -226,6 +259,10 @@ impl Cache { self.emote_packs.entry(pack_id).or_default() } + fn get_messages(&mut self, guild_id: Option, channel_id: u64) -> &mut Messages { + &mut self.get_channel_mut(guild_id.unwrap_or(0), channel_id).messages + } + pub fn is_initial_sync_complete(&self) -> bool { self.initial_sync_complete } @@ -293,6 +330,26 @@ impl Cache { pub fn process_event(&mut self, event: FetchEvent) { match event { + FetchEvent::FetchedPrivateChannel { + id, + is_dm, + members, + name, + } => { + for member in &members { + if self.users.contains_key(member).not() { + let _ = self.post_sender.send(PostProcessEvent::FetchProfile(*member)); + } + } + + let mut channel = self.get_channel_mut(0, id); + channel.name = name.map_or_else(|| SmolStr::new_inline(""), Into::into); + if let Some(data) = channel.private_channel_data.as_mut() { + data.members = members.into_iter().collect(); + data.is_dm = is_dm; + } + channel.get_priv_mut().fetched = true; + } FetchEvent::FetchedGuild { id, name, @@ -301,14 +358,15 @@ impl Cache { } => { let mut guild = self.get_guild_mut(id); guild.name = name.into(); - guild.picture = picture.and_then(|s| FileId::from_str(&s).ok()); + guild.picture = picture; guild.owners = owners; guild.fetched = true; if let Some(id) = guild.picture.clone() { let _ = self.post_sender.send(PostProcessEvent::FetchThumbnail(Attachment { - kind: "image".into(), + mimetype: "image".into(), name: "guild".into(), - ..Attachment::new_unknown(id) + id, + ..Default::default() })); } } @@ -334,7 +392,8 @@ impl Cache { channel_id, echo_id, } => { - let mut view = self.get_channel_mut(guild_id, channel_id).messages.view_mut(); + let messages = self.get_messages(guild_id, channel_id); + let mut view = messages.view_mut(); if let Some(msg) = view.get_message_mut(&MessageId::Unack(echo_id)) { msg.failed_to_send = true; } @@ -352,19 +411,21 @@ impl Cache { FetchEvent::LinkMetadata { url, data } => { match &data { FetchLinkData::IsSite(site) => { - if let Ok(url) = site.image.parse::() { + if let Some(url) = site.thumbnail.first().and_then(|i| i.url.parse::().ok()) { let id = FileId::External(url); - let _ = self - .post_sender - .send(PostProcessEvent::FetchThumbnail(Attachment::new_unknown(id))); + let _ = self.post_sender.send(PostProcessEvent::FetchThumbnail(Attachment { + id: id.into(), + ..Default::default() + })); } } FetchLinkData::IsMedia(media) => { let attachment = Attachment { - name: media.filename.clone(), - kind: media.mimetype.clone(), + name: media.name.clone(), + mimetype: media.mimetype.clone(), size: media.size.unwrap_or(u32::MAX), - ..Attachment::new_unknown(FileId::External(url.clone())) + id: url.to_string(), + ..Default::default() }; if attachment.is_thumbnail() { @@ -388,14 +449,36 @@ impl Cache { let _ = self.post_sender.send(PostProcessEvent::FetchLinkMetadata(urls)); } - let channel = self.get_channel_mut(guild_id, channel_id); + let messages = self.get_messages(guild_id, channel_id); - channel.messages.create_reply_view(id).insert_message(id, message); + messages.create_reply_view(id).insert_message(id, message); } FetchEvent::Attachment { .. } => {} FetchEvent::InitialSyncComplete => { self.initial_sync_complete = true; } + FetchEvent::FetchedProfile { + id, + name, + picture, + status, + kind, + } => { + if let Some(id) = picture.clone() { + let _ = self.post_sender.send(PostProcessEvent::FetchThumbnail(Attachment { + mimetype: "image".into(), + name: "avatar".into(), + id, + ..Default::default() + })); + } + let mut user = self.get_user_mut(id); + user.username = name.into(); + user.avatar_url = picture; + user.kind = kind; + user.status = status; + user.fetched = true; + } } } @@ -432,9 +515,9 @@ impl Cache { let _ = self.post_sender.send(PostProcessEvent::FetchLinkMetadata(urls)); } - let channel = self.get_channel_mut(guild_id, channel_id); + let messages = self.get_messages(guild_id, channel_id); - let message_view = channel.messages.continuous_view_mut(); + let message_view = messages.continuous_view_mut(); if let Some(echo_id) = echo_id { message_view.ack_message(MessageId::Unack(echo_id), MessageId::Ack(message_id), message); } else { @@ -447,8 +530,9 @@ impl Cache { channel_id, message_id, }) => { - self.get_channel_mut(guild_id, channel_id) - .messages + let messages = self.get_messages(guild_id, channel_id); + + messages .continuous_view_mut() .remove_message(&MessageId::Ack(message_id)); } @@ -457,16 +541,15 @@ impl Cache { let channel_id = message_updated.channel_id; let message_id = MessageId::Ack(message_updated.message_id); - if let Some(msg) = self - .get_channel_mut(guild_id, channel_id) - .messages - .view_mut() - .get_message_mut(&message_id) - { - msg.content = Content::Text(message_updated.new_content.map_or_else(String::new, |f| f.text)); + let messages = self.get_messages(guild_id, channel_id); + + if let Some(msg) = messages.view_mut().get_message_mut(&message_id) { + msg.content.text = message_updated.new_content.map_or_else(String::new, |f| f.text); } - let maybe_view = self.get_channel(guild_id, channel_id).map(|chan| chan.messages.view()); + let maybe_view = self + .get_channel(guild_id.unwrap_or(0), channel_id) + .map(|chan| chan.messages.view()); if let Some(msg) = maybe_view.as_ref().and_then(|view| view.get_message(&message_id)) { let mut urls = Vec::new(); msg.post_process(&self.post_sender, &mut urls, guild_id, channel_id); @@ -552,18 +635,15 @@ impl Cache { }) => { self.get_guild_mut(guild_id).members.remove(&member_id); } - ChatEvent::GuildAddedToList(GuildAddedToList { guild_id, homeserver }) => { + ChatEvent::GuildAddedToList(GuildAddedToList { guild_id, server_id }) => { let guild = self.get_guild_mut(guild_id); - guild.homeserver = homeserver.into(); + guild.homeserver = server_id; if guild.fetched.not() { let _ = self.post_sender.send(PostProcessEvent::FetchGuildData(guild_id)); } } - ChatEvent::GuildRemovedFromList(GuildRemovedFromList { - guild_id, - homeserver: _, - }) => { + ChatEvent::GuildRemovedFromList(GuildRemovedFromList { guild_id, server_id: _ }) => { self.guilds.remove(&guild_id); } ChatEvent::DeletedGuild(GuildDeleted { guild_id }) => { @@ -576,12 +656,12 @@ impl Cache { new_metadata: _, }) => { let fetched = new_name.is_some() && new_picture.is_some(); - let parsed_pic = new_picture.and_then(|new_picture| FileId::from_str(&new_picture).ok()); - if let Some(id) = parsed_pic.clone() { + if let Some(id) = new_picture.clone() { let _ = self.post_sender.send(PostProcessEvent::FetchThumbnail(Attachment { - kind: "image".into(), + mimetype: "image".into(), name: "guild".into(), - ..Attachment::new_unknown(id) + id, + ..Default::default() })); } let mut guild = self.get_guild_mut(guild_id); @@ -593,7 +673,7 @@ impl Cache { if let Some(name) = new_name { guild.name = name.into(); } - if let Some(picture) = parsed_pic { + if let Some(picture) = new_picture { guild.picture = Some(picture); } } @@ -670,7 +750,7 @@ impl Cache { channel_id, message_id, }) => { - self.get_channel_mut(guild_id, channel_id) + self.get_channel_mut(guild_id.unwrap_or(0), channel_id) .pinned_messages .insert(message_id); } @@ -679,42 +759,81 @@ impl Cache { channel_id, message_id, }) => { - self.get_channel_mut(guild_id, channel_id) + self.get_channel_mut(guild_id.unwrap_or(0), channel_id) .pinned_messages .remove(&message_id); } + ChatEvent::PrivateChannelAddedToList(PrivateChannelAddedToList { channel_id, server_id }) => { + let c = self.get_priv_channel_mut(channel_id); + c.get_priv_mut().server_id = server_id; + + if c.get_priv().fetched.not() { + let _ = self.post_sender.send(PostProcessEvent::FetchPrivateChannel(channel_id)); + } + } + ChatEvent::PrivateChannelRemovedFromList(PrivateChannelRemovedFromList { + channel_id, + server_id: _, + }) => { + self.channels.remove(&(0, channel_id)); + let g = self.get_guild_mut(0); + if let Some(index) = g.channels.iter().position(|id| channel_id.eq(id)) { + g.channels.remove(index); + } + } + ChatEvent::PrivateChannelDeleted(PrivateChannelDeleted { channel_id }) => { + self.channels.remove(&(0, channel_id)); + let g = self.get_guild_mut(0); + if let Some(index) = g.channels.iter().position(|id| channel_id.eq(id)) { + g.channels.remove(index); + } + } + ChatEvent::UserLeftPrivateChannel(UserLeftPrivateChannel { channel_id, user_id }) => { + self.get_priv_channel_mut(channel_id) + .get_priv_mut() + .members + .remove(&user_id); + } + ChatEvent::UserJoinedPrivateChannel(UserJoinedPrivateChannel { channel_id, user_id }) => { + self.get_priv_channel_mut(channel_id) + .get_priv_mut() + .members + .insert(user_id); + + if !self.users.contains_key(&user_id) { + let _ = self.post_sender.send(PostProcessEvent::FetchProfile(user_id)); + } + } ev => tracing::error!("event not implemented: {:?}", ev), }, Event::Profile(ev) => match ev { + ProfileEvent::StatusUpdated(StatusUpdated { user_id, new_status }) => { + let mut user = self.get_user_mut(user_id); + if let Some(new_status) = new_status { + user.status = new_status; + } + } ProfileEvent::ProfileUpdated(ProfileUpdated { user_id, new_username, new_avatar, - new_status, - new_account_kind, .. }) => { - let parsed_avatar = new_avatar.and_then(|new_avatar| FileId::from_str(&new_avatar).ok()); - if let Some(id) = parsed_avatar.clone() { + if let Some(id) = new_avatar.clone() { let _ = self.post_sender.send(PostProcessEvent::FetchThumbnail(Attachment { - kind: "image".into(), + mimetype: "image".into(), name: "avatar".into(), - ..Attachment::new_unknown(id) + id, + ..Default::default() })); } let mut user = self.get_user_mut(user_id); if let Some(new_username) = new_username { user.username = new_username.into(); } - if let Some(new_status) = new_status { - user.status = UserStatus::from_i32(new_status).unwrap_or(UserStatus::OfflineUnspecified); - } - if let Some(new_avatar) = parsed_avatar { + if let Some(new_avatar) = new_avatar { user.avatar_url = Some(new_avatar); } - if let Some(new_kind) = new_account_kind { - user.kind = AccountKind::from_i32(new_kind).unwrap_or_default(); - } user.fetched = true; } }, @@ -731,9 +850,10 @@ impl Cache { }) => { let evs = added_emotes.iter().map(|emote| { PostProcessEvent::FetchThumbnail(Attachment { - kind: "image".to_string(), + mimetype: "image".to_string(), name: "emote".to_string(), - ..Attachment::new_unknown(FileId::Id(emote.image_id.clone())) + id: emote.image_id.clone(), + ..Default::default() }) }); for ev in evs { @@ -772,7 +892,7 @@ impl Cache { pub fn process_get_message_history_response( &mut self, - guild_id: u64, + guild_id: Option, channel_id: u64, message_id: Option, messages: Vec<(u64, HarmonyMessage)>, @@ -793,20 +913,22 @@ impl Cache { let _ = self.post_sender.send(PostProcessEvent::FetchLinkMetadata(urls)); } - let channel = self.get_channel_mut(guild_id, channel_id); - channel.reached_top = reached_top; - channel - .messages + let messages_view = { + let channel = self.get_channel_mut(guild_id.unwrap_or(0), channel_id); + channel.reached_top = reached_top; + &mut channel.messages + }; + messages_view .continuous_view_mut() .append_messages(anchor_id.as_ref(), direction, messages); } - pub fn prepare_send_message(&mut self, guild_id: u64, channel_id: u64, message: Message) -> u64 { + pub fn prepare_send_message(&mut self, user_id: u64, request: SendMessageRequest) -> u64 { let echo_id = get_random_u64(); - self.get_channel_mut(guild_id, channel_id) + self.get_channel_mut(request.guild_id.unwrap_or(0), request.channel_id) .messages .continuous_view_mut() - .insert_message(MessageId::Unack(echo_id), message); + .insert_message(MessageId::Unack(echo_id), Message::from_request(user_id, request)); echo_id } } @@ -840,7 +962,7 @@ impl Client { pub async fn logout(self) -> ClientResult<()> { self.inner - .call(UpdateProfileRequest::default().with_new_user_status(UserStatus::OfflineUnspecified)) + .call(UpdateStatusRequest::update_kind(user_status::Kind::OfflineUnspecified)) .await?; self.remove_session().await } @@ -884,19 +1006,12 @@ impl Client { self.inner.clone() } - pub async fn update_profile( - &self, - username: Option, - avatar: Option, - status: Option, - ) -> ClientResult<()> { + pub async fn update_profile(&self, username: Option, avatar: Option) -> ClientResult<()> { self.inner - .call( - UpdateProfileRequest::default() - .with_new_user_name(username) - .with_new_user_avatar(avatar.map(Into::into)) - .with_new_user_status(status.map(Into::into)), - ) + .call(UpdateProfileRequest { + new_user_avatar: avatar.map(Into::into), + new_user_name: username, + }) .await?; Ok(()) } @@ -927,7 +1042,7 @@ impl Client { UpdateChannelInformationRequest::default() .with_guild_id(guild_id) .with_channel_id(channel_id) - .with_new_name(Some(new_name.into())), + .with_new_name(new_name.into()), ) .await?; Ok(()) @@ -937,15 +1052,15 @@ impl Client { &self, guild_id: u64, new_name: Option, - new_picture: Option, + new_picture: Option, ) -> ClientResult<()> { self.inner - .call( - UpdateGuildInformationRequest::default() - .with_guild_id(guild_id) - .with_new_name(new_name) - .with_new_picture(new_picture.map(Into::into)), - ) + .call(UpdateGuildInformationRequest { + guild_id, + new_name, + new_picture, + ..Default::default() + }) .await?; Ok(()) } @@ -1019,49 +1134,38 @@ impl Client { Ok(()) } - pub async fn send_typing(&self, guild_id: u64, channel_id: u64) -> ClientResult<()> { - self.inner.call(TypingRequest::new(guild_id, channel_id)).await?; + pub async fn send_typing(&self, guild_id: Option, channel_id: u64) -> ClientResult<()> { + self.inner.call(TypingRequest { guild_id, channel_id }).await?; Ok(()) } pub async fn edit_message( &self, - guild_id: u64, + guild_id: Option, channel_id: u64, message_id: u64, new_content: String, ) -> ClientResult<()> { self.inner - .call(UpdateMessageTextRequest::new( + .call(UpdateMessageContentRequest { guild_id, channel_id, message_id, - Some(FormattedText::new(new_content, Vec::new())), - )) + new_content: Some(send_message_request::Content { + text: new_content, + ..Default::default() + }), + }) .await?; Ok(()) } - pub async fn send_message( - &self, - echo_id: u64, - guild_id: u64, - channel_id: u64, - message: Message, - event_sender: &EventSender, - ) -> ClientResult { - let res = self - .inner - .call( - SendMessageRequest::default() - .with_guild_id(guild_id) - .with_channel_id(channel_id) - .with_content(HarmonyContent::new(Some(message.content.into()))) - .with_echo_id(echo_id) - .with_in_reply_to(message.reply_to) - .with_overrides(message.overrides.map(Into::into)), - ) - .await; + pub async fn send_message(&self, request: SendMessageRequest, event_sender: &EventSender) -> ClientResult { + let echo_id = request.echo_id(); + let guild_id = request.guild_id; + let channel_id = request.channel_id; + + let res = self.inner.call(request).await; let resp = match res { Ok(resp) => resp, @@ -1121,19 +1225,19 @@ impl Client { Ok(()) } - pub async fn upload_file(&self, name: String, mimetype: String, data: Vec) -> ClientResult { + pub async fn upload_file(&self, name: String, mimetype: String, data: Vec) -> ClientResult { let id = self.inner.upload_extract_id(name, mimetype, data).await?; - Ok(FileId::Id(id)) + Ok(id) } - pub async fn fetch_attachment(&self, id: FileId) -> ClientResult<(FileId, DownloadedFile)> { - let resp = self.inner.download_extract_file(id.clone()).await?; - Ok((id, resp)) + pub async fn fetch_attachment(&self, id: String) -> ClientResult { + let resp = self.inner.download_extract_file(id).await?; + Ok(resp) } pub async fn fetch_messages( &self, - guild_id: u64, + guild_id: Option, channel_id: u64, anchor: Option, direction: Option, @@ -1141,13 +1245,13 @@ impl Client { ) -> ClientResult<()> { let resp = self .inner - .call(GetChannelMessagesRequest::new( + .call(GetChannelMessagesRequest { guild_id, channel_id, - anchor, - direction.map(Into::into), - None, - )) + direction: direction.map(Into::into), + message_id: anchor, + ..Default::default() + }) .await?; let messages = resp .messages @@ -1178,7 +1282,12 @@ impl Client { perms_to_give: Vec, ) -> ClientResult<()> { self.inner - .call(SetPermissionsRequest::new(guild_id, channel_id, role_id, perms_to_give)) + .call(SetPermissionsRequest { + guild_id, + channel_id, + role_id, + perms_to_give, + }) .await?; Ok(()) } @@ -1190,53 +1299,72 @@ impl Client { role_id: u64, event_sender: &EventSender, ) -> ClientResult<()> { - let chunked_reqs = std::iter::once(GetPermissionsRequest::new(guild_id, None, role_id)) - .chain( - channel_ids - .iter() - .map(|channel_id| GetPermissionsRequest::new(guild_id, Some(*channel_id), role_id)), - ) - .chunks(64) - .into_iter() - .map(|chunk| chunk.collect_vec()) - .collect_vec(); - let chunked_ids = std::iter::once(None) - .chain(channel_ids.iter().map(|id| Some(*id))) - .chunks(64) - .into_iter() - .map(|chunk| chunk.collect_vec()) - .collect_vec(); - for (reqs, ids) in chunked_reqs.into_iter().zip(chunked_ids.into_iter()) { - let resps = self.inner.batch_call(reqs).await?; - for (resp, channel_id) in resps.into_iter().zip(ids.into_iter()) { - let _ = event_sender.send(FetchEvent::Harmony(Event::Chat(ChatEvent::RolePermsUpdated( - RolePermissionsUpdated { - guild_id, - channel_id, - new_perms: resp.perms, - role_id, - }, - )))); - } + let resp = self + .inner + .call(GetPermissionsRequest { + guild_id, + channel_ids, + role_id, + }) + .await?; + let send = |channel_id, perms| { + let _ = event_sender.send(FetchEvent::Harmony(Event::Chat(ChatEvent::RolePermsUpdated( + RolePermissionsUpdated { + guild_id, + channel_id, + new_perms: perms, + role_id, + }, + )))); + }; + if let Some(perms) = resp.guild_perms { + send(None, perms.perms); + } + for (channel_id, perms) in resp.channel_perms { + send(Some(channel_id), perms.perms); } Ok(()) } + pub async fn fetch_private_channels(&self, event_sender: &EventSender) -> ClientResult<()> { + let channels = self.inner.call(GetPrivateChannelListRequest::new()).await?.channels; + + let channel_ids = channels.iter().map(|c| c.channel_id).collect::>(); + let resp = self.inner.call(GetPrivateChannelRequest::new(channel_ids)).await?; + for (id, data) in resp.channels { + let _ = event_sender.send(FetchEvent::FetchedPrivateChannel { + id, + is_dm: data.is_dm, + members: data.members, + name: data.name, + }); + } + + for entry in channels { + let _ = event_sender.send(FetchEvent::new_chat(ChatEvent::PrivateChannelAddedToList( + PrivateChannelAddedToList { + channel_id: entry.channel_id, + server_id: entry.server_id, + }, + ))); + } + + Ok(()) + } + pub async fn fetch_channels(&self, guild_id: u64, event_sender: &EventSender) -> ClientResult<()> { let resp = self.inner.call(GetGuildChannelsRequest::new(guild_id)).await?; let evs = resp.channels.into_iter().filter_map(move |channel| { let channel_id = channel.channel_id; let channel = channel.channel?; - Some(FetchEvent::Harmony(Event::Chat(ChatEvent::new_created_channel( - ChannelCreated { - guild_id, - channel_id, - name: channel.channel_name, - kind: channel.kind, - position: None, - metadata: channel.metadata, - }, - )))) + Some(FetchEvent::new_chat(ChatEvent::CreatedChannel(ChannelCreated { + guild_id, + channel_id, + name: channel.channel_name, + kind: channel.kind, + position: None, + metadata: channel.metadata, + }))) }); for ev in evs { let _ = event_sender.send(ev); @@ -1250,16 +1378,14 @@ impl Client { let evs = resp.roles.into_iter().filter_map(|role| { let role_id = role.role_id; let role = role.role?; - Some(FetchEvent::Harmony(Event::Chat(ChatEvent::new_role_created( - RoleCreated { - role_id, - guild_id, - name: role.name, - color: role.color, - pingable: role.pingable, - hoist: role.hoist, - }, - )))) + Some(FetchEvent::new_chat(ChatEvent::RoleCreated(RoleCreated { + role_id, + guild_id, + name: role.name, + color: role.color, + pingable: role.pingable, + hoist: role.hoist, + }))) }); for ev in evs { let _ = event_sender.send(ev); @@ -1267,46 +1393,33 @@ impl Client { let members = self.inner.call(GetGuildMembersRequest::new(guild_id)).await?.members; let resp_user_roles = self .inner - .batch_call( - members - .iter() - .map(|user_id| GetUserRolesRequest::new(guild_id, *user_id)) - .collect(), - ) + .call(GetUserRolesRequest { + guild_id, + user_ids: members.clone(), + }) .await?; - let evs = resp_user_roles.into_iter().zip(members.iter()).map(|(resp, user_id)| { - FetchEvent::Harmony(Event::Chat(ChatEvent::new_user_roles_updated(UserRolesUpdated::new( - guild_id, *user_id, resp.roles, - )))) - }); - for ev in evs { - let _ = event_sender.send(ev); + for (user_id, roles) in resp_user_roles.user_roles { + let _ = event_sender.send(FetchEvent::new_chat(ChatEvent::UserRolesUpdated(UserRolesUpdated { + guild_id, + user_id, + new_role_ids: roles.roles, + }))); } - let resp_user_profiles = self - .inner - .batch_call(members.iter().map(|user_id| GetProfileRequest::new(*user_id)).collect()) - .await?; + let resp_user_profiles = self.inner.call(GetProfileRequest::new(members.clone())).await?; let evs = resp_user_profiles + .profile .into_iter() - .zip(members.iter()) - .filter_map(|(resp, user_id)| { - let profile = resp.profile?; - Some(FetchEvent::Harmony(Event::Profile(ProfileEvent::new_profile_updated( - ProfileUpdated { - user_id: *user_id, - new_avatar: profile.user_avatar, - new_username: Some(profile.user_name), - new_status: Some(profile.user_status), - new_account_kind: Some(profile.account_kind), - ..Default::default() - }, - )))) + .map(|(user_id, profile)| FetchEvent::FetchedProfile { + id: user_id, + kind: profile.account_kind(), + name: profile.user_name, + picture: profile.user_avatar, + status: profile.user_status.unwrap_or_default(), }); - let evs = evs.chain(members.iter().map(move |id| { - FetchEvent::Harmony(Event::Chat(ChatEvent::new_joined_member(MemberJoined::new( - *id, guild_id, - )))) - })); + let evs = + evs.chain(members.into_iter().map(move |id| { + FetchEvent::Harmony(Event::Chat(ChatEvent::JoinedMember(MemberJoined::new(id, guild_id)))) + })); for ev in evs { let _ = event_sender.send(ev); } @@ -1317,78 +1430,60 @@ impl Client { let self_id = self.user_id(); let self_profile = self .inner - .call(GetProfileRequest::new(self_id)) + .call(GetProfileRequest::new_one(self_id)) .await? .profile - .unwrap_or_default(); + .one(); let guilds = self.inner.call(GetGuildListRequest::new()).await?.guilds; - let mut guild_info_reqs = Vec::with_capacity(guilds.len()); - let mut guild_added_to_list_events = Vec::with_capacity(guilds.len()); + let resp_guild_info = self + .inner + .call(GetGuildRequest::new( + guilds.iter().map(|g| g.guild_id).collect::>(), + )) + .await?; + + for (guild_id, info) in resp_guild_info.guild { + let _ = event_sender.send(FetchEvent::FetchedGuild { + id: guild_id, + name: info.name, + owners: info.owner_ids, + picture: info.picture, + }); + } for guild in guilds { - guild_info_reqs.push(GetGuildRequest::new(guild.guild_id)); - guild_added_to_list_events.push(FetchEvent::Harmony(Event::Chat(ChatEvent::GuildAddedToList( + let _ = event_sender.send(FetchEvent::Harmony(Event::Chat(ChatEvent::GuildAddedToList( GuildAddedToList { guild_id: guild.guild_id, - homeserver: guild.server_id, + server_id: guild.server_id, }, )))); } - let chunked_guild_info_reqs = guild_info_reqs.into_iter().fold(vec![Vec::new()], |mut tot, item| { - if tot.last().unwrap().len() < 64 { - tot.last_mut().unwrap().push(item); - } else { - tot.push(vec![item]); - } - tot - }); - - for chunk in chunked_guild_info_reqs { - let guild_infos = self.inner.batch_call(chunk.clone()).await?; - let evs = guild_infos.into_iter().zip(chunk.into_iter()).map(|(resp, req)| { - let guild = resp.guild.unwrap_or_default(); - FetchEvent::FetchedGuild { - id: req.guild_id, - name: guild.name, - owners: guild.owner_ids, - picture: guild.picture, - } - }); - for ev in evs { - let _ = event_sender.send(ev); - } - } - - for ev in guild_added_to_list_events { - let _ = event_sender.send(ev); - } - - let evs = self.inner.call(GetEmotePacksRequest::new()).await.map(|resp| { - resp.packs.into_iter().map(|pack| { - FetchEvent::Harmony(Event::Emote(EmoteEvent::EmotePackAdded(EmotePackAdded { - pack: Some(pack), - }))) - }) - })?; - for ev in evs { - let _ = event_sender.send(ev); + let resp_emote_packs = self.inner.call(GetEmotePacksRequest::new()).await?; + for pack in resp_emote_packs.packs { + let _ = event_sender.send(FetchEvent::Harmony(Event::Emote(EmoteEvent::EmotePackAdded( + EmotePackAdded::new(pack), + )))); } self.inner - .call(UpdateProfileRequest::default().with_new_user_status(UserStatus::Online)) + .call(UpdateStatusRequest::update_kind(user_status::Kind::Online)) .await?; let _ = event_sender.send(FetchEvent::Harmony(Event::Profile(ProfileEvent::ProfileUpdated( ProfileUpdated { new_avatar: self_profile.user_avatar, - new_status: Some(UserStatus::Online.into()), new_username: Some(self_profile.user_name), user_id: self_id, - new_account_kind: None, - ..Default::default() + }, + )))); + let _ = event_sender.send(FetchEvent::Harmony(Event::Profile(ProfileEvent::StatusUpdated( + StatusUpdated { + user_id: self_id, + new_status: Some(UserStatus::default().with_kind(user_status::Kind::Online)), }, )))); @@ -1417,25 +1512,23 @@ impl Client { "permissions.manage.get", all_permissions::MESSAGES_SEND, ]; - let queries = perm_queries - .into_iter() - .map(|query| QueryHasPermissionRequest::new(guild_id, None, None, query.to_string())) - .collect(); - let evs = self.inner.batch_call(queries).await.map(move |response| { - response - .into_iter() - .zip(perm_queries.into_iter()) - .map(move |(resp, query)| { - FetchEvent::Harmony(Event::Chat(ChatEvent::PermissionUpdated(PermissionUpdated { - guild_id, - channel_id: None, - ok: resp.ok, - query: query.to_string(), - }))) - }) - })?; - for ev in evs { - let _ = event_sender.send(ev); + let resp = self + .inner + .call(HasPermissionRequest { + guild_id, + check_for: perm_queries.into_iter().map(str::to_string).collect(), + ..Default::default() + }) + .await?; + for perm in resp.perms { + let _ = event_sender.send(FetchEvent::Harmony(Event::Chat(ChatEvent::PermissionUpdated( + PermissionUpdated { + guild_id, + channel_id: None, + ok: perm.ok, + query: perm.matches, + }, + )))); } Ok(()) } @@ -1451,37 +1544,33 @@ impl Client { all_permissions::MESSAGES_PINS_ADD, all_permissions::MESSAGES_PINS_REMOVE, ]; - let queries = perm_queries - .into_iter() - .map(|query| QueryHasPermissionRequest::new(guild_id, Some(channel_id), None, query.to_string())) - .collect(); - let evs = self + let resp = self .inner - .batch_call(queries) - .await? - .into_iter() - .zip(perm_queries.into_iter()) - .map(move |(resp, query)| { - FetchEvent::Harmony(Event::Chat(ChatEvent::PermissionUpdated(PermissionUpdated { + .call(HasPermissionRequest { + guild_id, + check_for: perm_queries.into_iter().map(str::to_string).collect(), + ..Default::default() + }) + .await?; + for perm in resp.perms { + let _ = event_sender.send(FetchEvent::Harmony(Event::Chat(ChatEvent::PermissionUpdated( + PermissionUpdated { guild_id, channel_id: Some(channel_id), - ok: resp.ok, - query: query.to_string(), - }))) - }); - for ev in evs { - let _ = event_sender.send(ev); + ok: perm.ok, + query: perm.matches, + }, + )))); } Ok(()) } PostProcessEvent::FetchThumbnail(attachment) => { - let (id, resp) = self.fetch_attachment(attachment.id.clone()).await?; - tracing::debug!("fetched attachment: {} {}", id, resp.mimetype); + let resp = self.fetch_attachment(attachment.id.clone()).await?; + tracing::debug!("fetched attachment: {} {}", attachment.id, resp.mimetype); let _ = event_sender.send(FetchEvent::Attachment { attachment: Attachment { - id, - kind: resp.mimetype.clone(), + mimetype: resp.mimetype.clone(), size: resp.data.len() as u32, ..attachment }, @@ -1490,30 +1579,38 @@ impl Client { Ok(()) } PostProcessEvent::FetchProfile(user_id) => { - let _ = event_sender.send(self.inner.call(GetProfileRequest::new(user_id)).await.map(|resp| { - let profile = resp.profile.unwrap_or_default(); - FetchEvent::Harmony(Event::Profile(ProfileEvent::ProfileUpdated(ProfileUpdated { - user_id, - new_avatar: profile.user_avatar, - new_status: Some(profile.user_status), - new_username: Some(profile.user_name), - new_account_kind: Some(profile.account_kind), - ..Default::default() - }))) - })?); + let resp = self.inner.call(GetProfileRequest::new_one(user_id)).await?; + let profile = resp.profile.one(); + let _ = event_sender.send(FetchEvent::FetchedProfile { + kind: profile.account_kind(), + id: user_id, + name: profile.user_name, + picture: profile.user_avatar, + status: profile.user_status.unwrap_or_default(), + }); Ok(()) } + PostProcessEvent::FetchPrivateChannel(channel_id) => { + let resp = self.inner.call(GetPrivateChannelRequest::new_one(channel_id)).await?; + let channel = resp.channels.one(); + let _ = event_sender.send(FetchEvent::FetchedPrivateChannel { + id: channel_id, + name: channel.name, + members: channel.members, + is_dm: channel.is_dm, + }); + Ok(()) + } PostProcessEvent::FetchGuildData(guild_id) => { - let _ = event_sender.send(self.inner.call(GetGuildRequest::new(guild_id)).await.map(|resp| { - let guild = resp.guild.unwrap_or_default(); - FetchEvent::Harmony(Event::Chat(ChatEvent::EditedGuild(GuildUpdated { - guild_id, - new_metadata: guild.metadata, - new_name: Some(guild.name), - new_picture: guild.picture, - }))) - })?); + let resp = self.inner.call(GetGuildRequest::new_one(guild_id)).await?; + let guild = resp.guild.one(); + let _ = event_sender.send(FetchEvent::Harmony(Event::Chat(ChatEvent::EditedGuild(GuildUpdated { + guild_id, + new_metadata: guild.metadata, + new_name: Some(guild.name), + new_picture: guild.picture, + })))); tracing::debug!("fetched guild data: {}", guild_id); Ok(()) } @@ -1524,7 +1621,11 @@ impl Client { } => { let message = self .inner - .call(GetMessageRequest::new(guild_id, channel_id, message_id)) + .call(GetMessageRequest { + guild_id, + channel_id, + message_id, + }) .await? .message; if let Some(message) = message { @@ -1537,34 +1638,32 @@ impl Client { } Ok(()) } - PostProcessEvent::FetchLinkMetadata(mut urls) => { - if urls.len() == 1 { - let url = urls.pop().unwrap(); - let resp = self.inner.call(FetchLinkMetadataRequest::new(url.to_string())).await?; - if let Some(data) = resp.data { - let _ = event_sender.send(FetchEvent::LinkMetadata { data, url }); - } - } else if urls.is_empty().not() { - let reqs = urls - .iter() - .map(|url| FetchLinkMetadataRequest::new(url.to_string())) - .collect(); - let resps = self.inner.batch_call(reqs).await?; - for (resp, url) in resps.into_iter().zip(urls) { - if let Some(data) = resp.data { - let _ = event_sender.send(FetchEvent::LinkMetadata { data, url }); - } - } + PostProcessEvent::FetchLinkMetadata(urls) => { + let resp = self + .inner + .call(FetchLinkMetadataRequest::new( + urls.iter().map(Uri::to_string).collect::>(), + )) + .await?; + for (url, data) in resp + .metadata + .into_iter() + .filter_map(|(k, data)| data.data.map(|data| (k, data))) + { + let _ = event_sender.send(FetchEvent::LinkMetadata { + data, + url: url.parse().unwrap(), + }); } Ok(()) } PostProcessEvent::FetchEmotes(pack_id) => { - let _ = event_sender.send(self.inner.call(GetEmotePackEmotesRequest { pack_id }).await.map( + let _ = event_sender.send(self.inner.call(GetEmotePackEmotesRequest::new_one(pack_id)).await.map( |resp| { FetchEvent::Harmony(Event::Emote(EmoteEvent::EmotePackEmotesUpdated( EmotePackEmotesUpdated { pack_id, - added_emotes: resp.emotes, + added_emotes: resp.pack_emotes.one().emotes, deleted_emotes: Vec::new(), }, ))) @@ -1578,11 +1677,12 @@ impl Client { fn post_heading(post: &PostEventSender, embeds: &[Embed]) { for embed in embeds { - let inner = |h: Option<&EmbedHeading>| { + let inner = |h: Option<&embed::Heading>| { if let Some(id) = h.and_then(|h| h.icon.clone()) { let _ = post.send(PostProcessEvent::FetchThumbnail(Attachment { - kind: "image".into(), - ..Attachment::new_unknown(id) + mimetype: "image".into(), + id, + ..Default::default() })); } }; @@ -1600,3 +1700,23 @@ pub fn get_random_u64() -> u64 { pub fn has_perm(guild: &Guild, channel: &Channel, query: &str) -> bool { channel.has_perm(query) || guild.has_perm(query) } + +pub trait HashMapExt { + fn one(self) -> T; +} + +impl HashMapExt for HashMap { + fn one(self) -> V { + self.into_values().next().expect("expected at least one item") + } +} + +pub trait U64Ext { + fn if_not_zero(self) -> Option; +} + +impl U64Ext for u64 { + fn if_not_zero(self) -> Option { + self.eq(&0).not().then(|| self) + } +} diff --git a/client/src/member.rs b/client/src/member.rs index 8ecc82e..10fa3b0 100644 --- a/client/src/member.rs +++ b/client/src/member.rs @@ -1,17 +1,14 @@ use instant::Instant; -use harmony_rust_sdk::api::{ - profile::{AccountKind, UserStatus}, - rest::FileId, -}; +use harmony_rust_sdk::api::profile::{AccountKind, UserStatus}; use smol_str::SmolStr; #[derive(Debug, Clone)] pub struct Member { - pub avatar_url: Option, + pub avatar_url: Option, pub username: SmolStr, pub display_user: bool, - pub typing_in_channel: Option<(u64, u64, Instant)>, + pub typing_in_channel: Option<(Option, u64, Instant)>, pub status: UserStatus, pub fetched: bool, pub kind: AccountKind, @@ -24,7 +21,7 @@ impl Default for Member { username: SmolStr::default(), display_user: true, typing_in_channel: None, - status: UserStatus::OfflineUnspecified, + status: UserStatus::default(), fetched: false, kind: AccountKind::FullUnspecified, } diff --git a/client/src/message.rs b/client/src/message.rs index ccc1a1f..d8fc370 100644 --- a/client/src/message.rs +++ b/client/src/message.rs @@ -2,19 +2,46 @@ use ahash::AHashMap; use chrono::NaiveDateTime; use harmony_rust_sdk::api::{ chat::{ - self, color, content, embed, get_channel_messages_request::Direction, overrides::Reason, FormattedText, - Message as HarmonyMessage, Minithumbnail, Photo, + get_channel_messages_request::Direction, send_message_request, Attachment, Content, Message as HarmonyMessage, + Overrides, SendMessageRequest, }, exports::hrpc::exports::http::Uri, - rest::FileId, }; +use indexmap::IndexSet; use instant::Duration; -use smol_str::SmolStr; -use std::{ops::Not, ptr::NonNull, str::FromStr}; +use std::{ops::Not, ptr::NonNull}; -use crate::{IndexMap, PostEventSender}; +use crate::{content::MAX_THUMB_SIZE, IndexMap, PostEventSender}; -use super::{content::MAX_THUMB_SIZE, post_heading, PostProcessEvent}; +use super::{post_heading, PostProcessEvent}; + +pub type PinnedMessages = IndexSet; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum MessageId { + Ack(u64), + Unack(u64), +} + +impl MessageId { + pub fn is_ack(&self) -> bool { + matches!(self, MessageId::Ack(_)) + } + + pub fn transaction_id(&self) -> Option { + match self { + MessageId::Unack(transaction) => Some(*transaction), + _ => None, + } + } + + pub fn id(&self) -> Option { + match self { + MessageId::Ack(id) => Some(*id), + _ => None, + } + } +} pub trait ReadMessagesView { fn get_message(&self, id: &MessageId) -> Option<&Message>; @@ -312,135 +339,19 @@ impl Messages { } } -#[derive(Debug, Clone)] -pub struct EmbedField { - pub title: String, - pub subtitle: Option, - pub body: Option, -} - -impl From for embed::EmbedField { - fn from(f: EmbedField) -> embed::EmbedField { - embed::EmbedField { - title: f.title, - subtitle: f.subtitle, - body: f.body.map(|text| FormattedText::default().with_text(text)), - ..Default::default() - } - } -} - -#[derive(Debug, Clone)] -pub struct EmbedHeading { - pub url: Option, - pub icon: Option, - pub text: String, - pub subtext: Option, -} - -impl From for embed::EmbedHeading { - fn from(h: EmbedHeading) -> embed::EmbedHeading { - embed::EmbedHeading { - icon: h.icon.map(|id| id.to_string()), - subtext: h.subtext, - text: h.text, - url: h.url.map(Into::into), - } - } -} - -#[derive(Debug, Clone)] -pub struct Embed { - pub title: String, - pub body: Option, - pub color: Option<[u8; 3]>, - pub footer: Option, - pub header: Option, - pub fields: Vec, -} - -impl From for chat::Embed { - fn from(e: Embed) -> chat::Embed { - chat::Embed { - body: e.body.map(|text| FormattedText::default().with_text(text)), - color: e.color.map(color::encode_rgb), - fields: e.fields.into_iter().map(Into::into).collect(), - title: e.title, - footer: e.footer.map(Into::into), - header: e.header.map(Into::into), - } - } -} - -#[derive(Debug, Clone)] -pub struct Attachment { - pub kind: String, - pub name: String, - pub id: FileId, - pub size: u32, - pub resolution: Option<(u32, u32)>, - pub minithumbnail: Option, -} - -impl PartialEq for Attachment { - fn eq(&self, other: &Self) -> bool { - self.id == other.id - } -} - -impl From for chat::Attachment { - fn from(a: Attachment) -> chat::Attachment { - chat::Attachment { - id: a.id.to_string(), - name: a.name, - size: a.size, - mimetype: a.kind, - caption: Default::default(), - } - } +pub trait AttachmentExt { + fn is_thumbnail(&self) -> bool; + fn is_raster_image(&self) -> bool; } -impl Attachment { - pub fn new_unknown(id: FileId) -> Self { - Self { - id, - kind: "application/octet-stream".into(), - name: "unknown".to_string(), - size: 0, - resolution: None, - minithumbnail: None, - } - } - - pub fn is_thumbnail(&self) -> bool { +impl AttachmentExt for Attachment { + fn is_thumbnail(&self) -> bool { self.is_raster_image() && (self.size as u64) < MAX_THUMB_SIZE } #[inline(always)] - pub fn is_raster_image(&self) -> bool { - is_raster_image(&self.kind) - } - - pub fn from_harmony_attachment(attachment: chat::Attachment) -> Option { - Some(Attachment { - id: FileId::from_str(&attachment.id).ok()?, - kind: attachment.mimetype, - name: attachment.name, - size: attachment.size as u32, - resolution: None, - minithumbnail: None, - }) - } - - pub fn from_harmony_photo(photo: chat::Photo) -> Option { - Some(Attachment { - id: FileId::from_str(&photo.hmc).ok()?, - kind: "image/jpeg".into(), - name: photo.name, - size: photo.file_size, - resolution: Some((photo.width, photo.height)), - minithumbnail: photo.minithumbnail, - }) + fn is_raster_image(&self) -> bool { + is_raster_image(&self.mimetype) } } @@ -448,132 +359,28 @@ pub fn is_raster_image(mimetype: &str) -> bool { mimetype.starts_with("image") && mimetype.ends_with("svg+xml").not() } -#[derive(Debug, Default, Clone)] -pub struct Override { - pub name: Option, - pub avatar_url: Option, - pub reason: Option, -} - -impl From for chat::Overrides { - fn from(o: Override) -> Self { - Self { - avatar: o.avatar_url.map(|id| id.into()), - username: o.name, - reason: o.reason, - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum MessageId { - Ack(u64), - Unack(u64), -} - -impl MessageId { - pub fn is_ack(&self) -> bool { - matches!(self, MessageId::Ack(_)) - } - - pub fn transaction_id(&self) -> Option { - match self { - MessageId::Unack(transaction) => Some(*transaction), - _ => None, - } - } - - pub fn id(&self) -> Option { - match self { - MessageId::Ack(id) => Some(*id), - _ => None, - } - } -} - -#[derive(Debug, Clone)] -pub enum Content { - Text(String), - Files(Vec), - Embeds(Vec), -} - -impl From for content::Content { - fn from(c: Content) -> content::Content { - match c { - Content::Text(content) => content::Content::TextMessage(content::TextContent { - content: Some(FormattedText::default().with_text(content)), - }), - Content::Embeds(embeds) => content::Content::EmbedMessage(content::EmbedContent { - embeds: embeds.into_iter().map(Into::into).collect(), - }), - Content::Files(attachments) => { - if attachments.iter().all(Attachment::is_raster_image) { - content::Content::PhotoMessage(content::PhotoContent { - photos: attachments - .into_iter() - .map(|attachment| Photo { - name: attachment.name, - hmc: attachment.id.into(), - file_size: attachment.size, - ..Default::default() - }) - .collect(), - }) - } else { - content::Content::AttachmentMessage(content::AttachmentContent { - files: attachments.into_iter().map(Into::into).collect(), - }) - } - } - } - } -} - -impl From for Content { - fn from(content: content::Content) -> Self { - match content { - content::Content::TextMessage(text) => Self::Text(text.content.map_or_else(String::new, |f| f.text)), - content::Content::AttachmentMessage(files) => Self::Files( - files - .files - .into_iter() - .flat_map(Attachment::from_harmony_attachment) - .collect(), - ), - content::Content::EmbedMessage(embeds) => Self::Embeds(embeds.embeds.into_iter().map(Into::into).collect()), - content::Content::PhotoMessage(photos) => Self::Files( - photos - .photos - .into_iter() - .flat_map(Attachment::from_harmony_photo) - .collect(), - ), - content::Content::InviteRejected(_) => todo!(), - content::Content::InviteAccepted(_) => todo!(), - content::Content::RoomUpgradedToGuild(_) => todo!(), - } - } -} - -impl Default for Content { - fn default() -> Self { - Content::Text(Default::default()) - } -} - #[derive(Debug, Clone)] pub struct Message { pub content: Content, pub sender: u64, pub timestamp: NaiveDateTime, - pub overrides: Option, + pub overrides: Option, pub reply_to: Option, pub failed_to_send: bool, } impl Message { - pub fn post_process(&self, post: &PostEventSender, urls: &mut Vec, guild_id: u64, channel_id: u64) { + pub fn from_request(user_id: u64, request: SendMessageRequest) -> Self { + Message { + overrides: request.overrides, + sender: user_id, + reply_to: request.in_reply_to, + content: request.content.map(send_content_to_content).unwrap_or_default(), + ..Default::default() + } + } + + pub fn post_process(&self, post: &PostEventSender, urls: &mut Vec, guild_id: Option, channel_id: u64) { if let Some(message_id) = self.reply_to.filter(|id| id != &0) { let _ = post.send(PostProcessEvent::FetchMessage { guild_id, @@ -581,34 +388,27 @@ impl Message { message_id, }); } - if let Some(id) = self.overrides.as_ref().and_then(|ov| ov.avatar_url.clone()) { + if let Some(id) = self.overrides.as_ref().and_then(|ov| ov.avatar.clone()) { let _ = post.send(PostProcessEvent::FetchThumbnail(Attachment { - kind: "image".into(), + mimetype: "image".into(), name: "avatar".into(), - ..Attachment::new_unknown(id) + id, + ..Default::default() })); } - match &self.content { - Content::Files(attachments) => { - for attachment in attachments { - if attachment.is_thumbnail() { - let _ = post.send(PostProcessEvent::FetchThumbnail(attachment.clone())); - } - } - } - Content::Embeds(embeds) => { - post_heading(post, embeds); - } - Content::Text(text) => { - let urlss = text - .split_whitespace() - .flat_map(|a| a.trim_end_matches('>').trim_start_matches('<').parse::()) - .filter(|url| matches!(url.scheme_str(), Some("http" | "https"))); - for url in urlss { - urls.push(url); - } + for attachment in &self.content.attachments { + if attachment.is_thumbnail() { + let _ = post.send(PostProcessEvent::FetchThumbnail(attachment.clone())); } } + post_heading(post, &self.content.embeds); + let urlss = self + .content + .text + .split_whitespace() + .flat_map(|a| a.trim_end_matches('>').trim_start_matches('<').parse::()) + .filter(|url| matches!(url.scheme_str(), Some("http" | "https"))); + urls.extend(urlss); } } @@ -628,61 +428,45 @@ impl Default for Message { } } -impl From for Override { - fn from(overrides: chat::Overrides) -> Self { - Override { - name: overrides.username.map(Into::into), - avatar_url: overrides.avatar.and_then(|a| FileId::from_str(&a).ok()), - reason: overrides.reason, - } - } -} - -impl From for EmbedHeading { - fn from(h: embed::EmbedHeading) -> Self { - EmbedHeading { - text: h.text, - subtext: h.subtext, - url: h.url.map(Into::into), - icon: h.icon.and_then(|i| FileId::from_str(&i).ok()), - } - } -} - -impl From for Embed { - fn from(e: chat::Embed) -> Self { - Embed { - title: e.title, - body: e.body.map(|f| f.text), - footer: e.footer.map(From::from), - header: e.header.map(From::from), - fields: e - .fields - .into_iter() - .map(|f| EmbedField { - title: f.title, - subtitle: f.subtitle, - body: f.body.map(|f| f.text), - }) - .collect(), - color: e.color.map(color::decode_rgb), - } - } -} - impl From for Message { fn from(message: HarmonyMessage) -> Self { Message { reply_to: message.in_reply_to, - content: message - .content - .and_then(|c| c.content) - .map(|c| c.into()) - .unwrap_or_default(), + content: message.content.unwrap_or_default(), sender: message.author_id, - timestamp: { NaiveDateTime::from_timestamp((message.created_at / 1000) as i64, ((message.created_at % 1000) as u32) * 1000000) }, - overrides: message.overrides.map(From::from), + timestamp: { + NaiveDateTime::from_timestamp( + (message.created_at / 1000) as i64, + ((message.created_at % 1000) as u32) * 1000000, + ) + }, + overrides: message.overrides, failed_to_send: false, } } } + +fn send_content_to_content(from: send_message_request::Content) -> Content { + Content { + text: from.text, + text_formats: from.text_formats, + embeds: from.embeds, + attachments: from + .attachments + .into_iter() + .map(send_attachment_to_attachment) + .collect(), + extra: None, + } +} + +fn send_attachment_to_attachment(from: send_message_request::Attachment) -> Attachment { + Attachment { + id: from.id, + name: from.name, + mimetype: "application/octet-stream".to_string(), + size: 0, + // TODO: also convert this + info: None, + } +} diff --git a/flake.lock b/flake.lock index 1dc886c..4bee767 100644 --- a/flake.lock +++ b/flake.lock @@ -1,19 +1,35 @@ { "nodes": { + "crane": { + "flake": false, + "locked": { + "lastModified": 1644785799, + "narHash": "sha256-VpAJO1L0XeBvtCuNGK4IDKp6ENHIpTrlaZT7yfBCvwo=", + "owner": "ipetkov", + "repo": "crane", + "rev": "fc7a94f841347c88f2cb44217b2a3faa93e2a0b2", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, "devshell": { "inputs": { "flake-utils": "flake-utils", "nixpkgs": [ - "nixCargoIntegration", + "nci", "nixpkgs" ] }, "locked": { - "lastModified": 1644227066, - "narHash": "sha256-FHcFZtpZEWnUh62xlyY3jfXAXHzJNEDLDzLsJxn+ve0=", + "lastModified": 1650900878, + "narHash": "sha256-qhNncMBSa9STnhiLfELEQpYC1L4GrYHNIzyCZ/pilsI=", "owner": "numtide", "repo": "devshell", - "rev": "7033f64dd9ef8d9d8644c5030c73913351d2b660", + "rev": "d97df53b5ddaa1cfbea7cddbd207eb2634304733", "type": "github" }, "original": { @@ -22,6 +38,56 @@ "type": "github" } }, + "dream2nix": { + "inputs": { + "alejandra": [ + "nci", + "nixpkgs" + ], + "crane": "crane", + "flake-utils-pre-commit": [ + "nci", + "nixpkgs" + ], + "gomod2nix": [ + "nci", + "nixpkgs" + ], + "mach-nix": [ + "nci", + "nixpkgs" + ], + "nixpkgs": [ + "nci", + "nixpkgs" + ], + "node2nix": [ + "nci", + "nixpkgs" + ], + "poetry2nix": [ + "nci", + "nixpkgs" + ], + "pre-commit-hooks": [ + "nci", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1651693671, + "narHash": "sha256-LtaGt2DdrXrG5j4rM1fiRm0tOOyL+ZOSreTA++qZ/vQ=", + "owner": "nix-community", + "repo": "dream2nix", + "rev": "9733fd26da344cbc634fadbc868ab927b4d06bc8", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "dream2nix", + "type": "github" + } + }, "flake-utils": { "locked": { "lastModified": 1642700792, @@ -40,11 +106,11 @@ "flakeCompat": { "flake": false, "locked": { - "lastModified": 1641205782, - "narHash": "sha256-4jY7RCWUoZ9cKD8co0/4tFARpWB+57+r1bLLvXNJliY=", + "lastModified": 1650374568, + "narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=", "owner": "edolstra", "repo": "flake-compat", - "rev": "b7547d3eed6f32d06102ead8991ec52ab0a4f1a7", + "rev": "b4a34015c698c7793d592d66adbab377907a2be8", "type": "github" }, "original": { @@ -53,20 +119,21 @@ "type": "github" } }, - "nixCargoIntegration": { + "nci": { "inputs": { "devshell": "devshell", + "dream2nix": "dream2nix", "nixpkgs": [ "nixpkgs" ], "rustOverlay": "rustOverlay" }, "locked": { - "lastModified": 1645769477, - "narHash": "sha256-fha6sgL7qezlAWD7e9HpGH7oPphYvOQ4fhWxfSyryA0=", + "lastModified": 1651694197, + "narHash": "sha256-U1UHUxbGAicwWCPIqUNvzqIzzfjYMRDcktW/iMfZxjc=", "owner": "yusdacra", "repo": "nix-cargo-integration", - "rev": "00e5378c73c0594304195882ab6eeb5118252484", + "rev": "8fc0d6eeac7998be497ef4e4e0bbb1676c89af16", "type": "github" }, "original": { @@ -77,11 +144,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1645433236, - "narHash": "sha256-4va4MvJ076XyPp5h8sm5eMQvCrJ6yZAbBmyw95dGyw4=", + "lastModified": 1651007983, + "narHash": "sha256-GNay7yDPtLcRcKCNHldug85AhAvBpTtPEJWSSDYBw8U=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "7f9b6e2babf232412682c09e57ed666d8f84ac2d", + "rev": "e10da1c7f542515b609f8dfbcf788f3d85b14936", "type": "github" }, "original": { @@ -94,18 +161,18 @@ "root": { "inputs": { "flakeCompat": "flakeCompat", - "nixCargoIntegration": "nixCargoIntegration", + "nci": "nci", "nixpkgs": "nixpkgs" } }, "rustOverlay": { "flake": false, "locked": { - "lastModified": 1645755566, - "narHash": "sha256-BwjpcywzB+4hHuStgYcOWRomI8I2PCtORUbNEL6qMBk=", + "lastModified": 1651632340, + "narHash": "sha256-Kq1yghXZxJ12Sw1nbzoO2Ag8/AxqbbD84wiz8go159o=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "46d8d20fce510c6a25fa66f36e31f207f6ea49e4", + "rev": "88991ffbd57e10b474ea768ec0b54c4f379c566c", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 94bf601..a33eb2c 100644 --- a/flake.nix +++ b/flake.nix @@ -5,118 +5,105 @@ flake = false; }; nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - nixCargoIntegration = { + nci = { url = "github:yusdacra/nix-cargo-integration"; inputs.nixpkgs.follows = "nixpkgs"; }; - /*androidPkgs = { - url = "github:tadfisher/android-nixpkgs"; - inputs.nixpkgs.follows = "nixpkgs"; - };*/ + /* + androidPkgs = { + url = "github:tadfisher/android-nixpkgs"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + */ }; - outputs = inputs: - let - outputs = inputs.nixCargoIntegration.lib.makeOutputs { - root = ./.; - buildPlatform = "crate2nix"; - overrides = { - pkgs = common: prev: { - overlays = prev.overlays ++ [ - (_: prev: { - android-sdk = inputs.androidPkgs.sdk.${prev.system} (sdkPkgs: with sdkPkgs; [ - cmdline-tools-latest - build-tools-32-0-0 - platform-tools - platforms-android-32 - emulator - ndk-bundle - ]); - }) - (_: prev: { - trunk = prev.nciUtils.buildCrate { - root = builtins.fetchGit { - url = "https://github.com/kristoff3r/trunk.git"; - ref = "rust_worker"; - rev = "0ff1842640553dfefcf0e0b13aee619b17916844"; + outputs = {nci, ...} @ inputs: let + outputs = nci.lib.makeOutputs { + root = ./.; + overrides = { + pkgsOverlays = [ + (_: prev: { + android-sdk = inputs.androidPkgs.sdk.${prev.system} (sdkPkgs: + with sdkPkgs; [ + cmdline-tools-latest + build-tools-32-0-0 + platform-tools + platforms-android-32 + emulator + ndk-bundle + ]); + }) + ]; + shell = common: prev: + with common.pkgs; { + packages = + prev.packages + ++ [ + (common.internal.nci-pkgs.utils.buildCrate { + pname = "trunk"; + source = builtins.fetchGit { + url = "https://github.com/thedodd/trunk.git"; + rev = "5c799dc35f1f1d8f8d3d30c8723cbb761a9b6a08"; + shallow = true; }; - release = true; - }; - twiggy = prev.nciUtils.buildCrate { - root = builtins.fetchGit { - url = "https://github.com/rustwasm/twiggy.git"; - ref = "master"; - rev = "195feee4045f0b89d7cba7492900131ac89803dd"; + packageOverrides.trunk.disable-test = { + doCheck = false; }; - memberName = "twiggy"; - release = true; - }; - }) - ]; - }; - crateOverrides = common: _: { - loqui = prev: { - nativeBuildInputs = (prev.nativeBuildInputs or [ ]) ++ (with common.pkgs; [ makeWrapper wrapGAppsHook ]); - postInstall = with common.pkgs; '' - if [ -f $out/bin/loqui ]; then - wrapProgram $out/bin/loqui\ - --set LD_LIBRARY_PATH ${lib.makeLibraryPath common.runtimeLibs}\ - --set XDG_DATA_DIRS ${hicolor-icon-theme}/share:${gnome3.adwaita-icon-theme}/share - fi - ''; - }; + }) + ]; + env = + prev.env + ++ [ + { + name = "XDG_DATA_DIRS"; + eval = "$GSETTINGS_SCHEMAS_PATH:$XDG_DATA_DIRS:${hicolor-icon-theme}/share:${gnome3.adwaita-icon-theme}/share"; + } + /* + { + name = "ANDROID_HOME"; + value = "${android-sdk}/share/android-sdk"; + } + { + name = "ANDROID_SDK_ROOT"; + value = "${android-sdk}/share/android-sdk"; + } + { + name = "JAVA_HOME"; + value = jdk11.home; + } + */ + ]; + commands = + prev.commands + ++ [ + { + name = "local-dev"; + command = "SSL_CERT_FILE=~/.local/share/mkcert/rootCA.pem cargo r"; + } + { + name = "cargo-mobile"; + help = "Build for mobile."; + command = "$HOME/.cargo/bin/cargo-mobile $@"; + } + ]; }; - shell = common: prev: with common.pkgs; { - #packages = [ android-sdk ]; - env = prev.env ++ [ - { - name = "XDG_DATA_DIRS"; - eval = "$GSETTINGS_SCHEMAS_PATH:$XDG_DATA_DIRS:${hicolor-icon-theme}/share:${gnome3.adwaita-icon-theme}/share"; - } - /*{ - name = "ANDROID_HOME"; - value = "${android-sdk}/share/android-sdk"; - } - { - name = "ANDROID_SDK_ROOT"; - value = "${android-sdk}/share/android-sdk"; - } - { - name = "JAVA_HOME"; - value = jdk11.home; - }*/ - ]; - commands = prev.commands ++ [ - { - name = "local-dev"; - command = "SSL_CERT_FILE=~/.local/share/mkcert/rootCA.pem cargo r"; - } - { - help = "Build for the web."; - package = trunk; - } - { - help = "Profile binary size."; - package = twiggy; - } - { - name = "cargo-mobile"; - help = "Build for mobile."; - command = "$HOME/.cargo/bin/cargo-mobile $@"; - } - ]; - }; - }; }; - in - outputs // { - apps = outputs.apps // { - x86_64-linux = outputs.apps.x86_64-linux // { - run-latest = - let - pkgs = import inputs.nixpkgs { system = "x86_64-linux"; config = { allowUnfree = true; }; }; - cmd = - pkgs.writeScriptBin "run-loqui-latest" '' + }; + in + outputs + // { + apps = + outputs.apps + // { + x86_64-linux = + outputs.apps.x86_64-linux + // { + run-latest = let + pkgs = import inputs.nixpkgs { + system = "x86_64-linux"; + config = {allowUnfree = true;}; + }; + cmd = pkgs.writeScriptBin "run-loqui-latest" '' #!${pkgs.stdenv.shell} mkdir -p /tmp/loqui-binary cd /tmp/loqui-binary @@ -124,12 +111,11 @@ chmod +x loqui ${pkgs.steam-run}/bin/steam-run ./loqui ''; - in - { - type = "app"; - program = "${cmd}/bin/run-loqui-latest"; + in { + type = "app"; + program = "${cmd}/bin/run-loqui-latest"; + }; }; }; - }; }; } diff --git a/image_worker/src/lib.rs b/image_worker/src/lib.rs index 6b9af77..37b3d0d 100644 --- a/image_worker/src/lib.rs +++ b/image_worker/src/lib.rs @@ -24,6 +24,7 @@ pub struct ImageData { pub fn load_image(data: Vec) -> Vec { #[allow(unsafe_code)] let image_data = unsafe { rkyv::archived_root::(&data) }; + tracing::debug!("received image (id {})", image_data.id); let Some(mut loaded) = load_image_logic(image_data.data.as_ref(), image_data.kind.as_str()) else { tracing::error!( "could not load an image (id {}); most likely unsupported format", diff --git a/image_worker/src/main.rs b/image_worker/src/main.rs index 135304d..522be91 100644 --- a/image_worker/src/main.rs +++ b/image_worker/src/main.rs @@ -7,8 +7,7 @@ mod op { use image_worker::load_image; pub fn main() { - let worker_scope: DedicatedWorkerGlobalScope = - js_sys::eval("self").expect_throw("cant get self").unchecked_into(); + let worker_scope = DedicatedWorkerGlobalScope::from(JsValue::from(js_sys::global())); let handler = { let worker_scope = worker_scope.clone(); diff --git a/nix/default.nix b/nix/default.nix index 9a3139b..df97abf 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -1,12 +1,14 @@ # Flake's default package for non-flake-enabled nix instances (import ( - let lock = builtins.fromJSON (builtins.readFile ../flake.lock); + let + lock = builtins.fromJSON (builtins.readFile ../flake.lock); in - fetchTarball { - url = - "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flakeCompat.locked.rev}.tar.gz"; - sha256 = lock.nodes.flakeCompat.locked.narHash; - } + fetchTarball { + url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flakeCompat.locked.rev}.tar.gz"; + sha256 = lock.nodes.flakeCompat.locked.narHash; + } ) - { src = ./..; }).defaultNix.default + {src = ./..;}) +.defaultNix +.default diff --git a/nix/shell.nix b/nix/shell.nix index be86c97..530a3e6 100644 --- a/nix/shell.nix +++ b/nix/shell.nix @@ -1,12 +1,14 @@ # Flake's devShell for non-flake-enabled nix instances (import ( - let lock = builtins.fromJSON (builtins.readFile ../flake.lock); + let + lock = builtins.fromJSON (builtins.readFile ../flake.lock); in - fetchTarball { - url = - "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flakeCompat.locked.rev}.tar.gz"; - sha256 = lock.nodes.flakeCompat.locked.narHash; - } + fetchTarball { + url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flakeCompat.locked.rev}.tar.gz"; + sha256 = lock.nodes.flakeCompat.locked.narHash; + } ) - { src = ./..; }).shellNix.default + {src = ./..;}) +.shellNix +.default diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 78b7bc7..29986ca 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2022-01-17" +channel = "nightly-2022-04-30" targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"] components = ["rust-src"] \ No newline at end of file diff --git a/src/app.rs b/src/app.rs index 5368fce..c151f35 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,11 +1,7 @@ use std::ops::Not; use client::{content, Client}; -use eframe::{ - egui::{self, vec2, Color32, FontData, FontDefinitions, Style, Ui}, - epi, -}; -use egui::Margin; +use eframe::egui::{self, vec2, Color32, FontData, FontDefinitions, Style, Ui}; use super::utils::*; @@ -73,7 +69,7 @@ impl App { } #[inline(always)] - fn view_bottom_panel(&mut self, ui: &mut Ui, _frame: &epi::Frame) { + fn view_bottom_panel(&mut self, ui: &mut Ui, _frame: &mut eframe::Frame) { ui.horizontal_top(|ui| { ui.style_mut().spacing.item_spacing = vec2(2.0, 0.0); @@ -203,16 +199,14 @@ impl App { }); }); } -} -impl epi::App for App { - fn name(&self) -> &str { - "loqui" - } + pub fn setup(&mut self, cc: &eframe::CreationContext) { + let ctx = &cc.egui_ctx; - fn setup(&mut self, ctx: &egui::Context, frame: &epi::Frame, _storage: Option<&dyn epi::Storage>) { - self.state.init(ctx, frame); - ctx.set_pixels_per_point(self.state.local_config.scale_factor); + self.state.init(ctx, cc.integration_info.clone()); + if self.state.local_config.scale_factor != 0.0 { + ctx.set_pixels_per_point(self.state.local_config.scale_factor); + } self.state.futures.spawn(async move { let Some(session) = Client::read_latest_session().await else { return Ok(None) }; @@ -262,12 +256,14 @@ impl epi::App for App { ctx.set_style(style); } } +} +impl eframe::App for App { fn max_size_points(&self) -> egui::Vec2 { [f32::INFINITY, f32::INFINITY].into() } - fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) { + fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { self.state.maintain(ctx); // ui drawing starts here @@ -276,7 +272,6 @@ impl epi::App for App { if self.state.is_connected.not() || is_main_screen.not() || ctx.is_mobile().not() { let style = ctx.style(); let frame_panel = egui::Frame { - margin: Margin::same(0.0), fill: style.visuals.extreme_bg_color, stroke: style.visuals.window_stroke(), ..Default::default() @@ -310,7 +305,7 @@ impl epi::App for App { } } - fn on_exit(&mut self) { + fn on_exit(&mut self, _glow: &eframe::glow::Context) { self.state.save_config(); } } diff --git a/src/config.rs b/src/config.rs index 0c6b042..81739b4 100644 --- a/src/config.rs +++ b/src/config.rs @@ -10,7 +10,6 @@ use client::{ harmony_rust_sdk::api::{ exports::prost::{bytes::Bytes, Message}, profile::{AppDataOverrides, GetAppDataRequest, SetAppDataRequest}, - rest::FileId, }, Client, }; @@ -71,7 +70,7 @@ impl BgImage { match res { Ok(data) => { - crate::image_cache::op::decode_image(data, FileId::Id(String::new()), "bg_image".to_string()); + crate::image_cache::op::decode_image(data, String::new(), "bg_image".to_string()); Ok(()) } Err(err) => Err(ClientError::Custom(err)), diff --git a/src/futures.rs b/src/futures.rs index 45c2ad0..f90af3f 100644 --- a/src/futures.rs +++ b/src/futures.rs @@ -1,11 +1,5 @@ -use client::{message::Attachment, tracing}; -use eframe::epi::backend::RepaintSignal; -use std::{ - any::Any, - cell::RefCell, - future::Future, - sync::{mpsc, Arc}, -}; +use client::{harmony_rust_sdk::api::chat::send_message_request::Attachment, tracing}; +use std::{any::Any, cell::RefCell, future::Future, sync::mpsc}; #[cfg(not(target_arch = "wasm32"))] use tokio::spawn; @@ -24,7 +18,7 @@ pub struct Futures { queue: RefCell>, rx: mpsc::Receiver, tx: mpsc::Sender, - rr: Option>, + rr: Option, } impl Futures { @@ -38,8 +32,8 @@ impl Futures { } } - pub fn init(&mut self, frame: &eframe::epi::Frame) { - self.rr = Some(frame.lock().repaint_signal.clone()); + pub fn init(&mut self, ctx: egui::Context) { + self.rr = Some(ctx); } pub fn spawn< diff --git a/src/image_cache.rs b/src/image_cache.rs index 77bec5e..1d932c8 100644 --- a/src/image_cache.rs +++ b/src/image_cache.rs @@ -1,11 +1,11 @@ -use client::{harmony_rust_sdk::api::rest::FileId, AHashMap}; +use client::AHashMap; use eframe::egui::{self, ImageData as Image, TextureHandle}; #[derive(Default)] pub struct ImageCache { - avatar: AHashMap, - minithumbnail: AHashMap, - image: AHashMap, + avatar: AHashMap, + minithumbnail: AHashMap, + image: AHashMap, bg_image: Option<(TextureHandle, [f32; 2])>, } @@ -24,17 +24,17 @@ impl ImageCache { } /// Get an avatar image. Avatars are always 64 x 64 - pub fn get_avatar(&self, id: &FileId) -> Option<(&TextureHandle, [f32; 2])> { + pub fn get_avatar(&self, id: &str) -> Option<(&TextureHandle, [f32; 2])> { self.avatar.get(id).map(|(tex, size)| (tex, *size)) } /// Get a minithumbnail image. Minithumbnails are always blurred - pub fn get_thumbnail(&self, id: &FileId) -> Option<(&TextureHandle, [f32; 2])> { + pub fn get_thumbnail(&self, id: &str) -> Option<(&TextureHandle, [f32; 2])> { self.minithumbnail.get(id).map(|(tex, size)| (tex, *size)) } /// Get some image. - pub fn get_image(&self, id: &FileId) -> Option<(&TextureHandle, [f32; 2])> { + pub fn get_image(&self, id: &str) -> Option<(&TextureHandle, [f32; 2])> { self.image.get(id).map(|(tex, size)| (tex, *size)) } @@ -43,7 +43,7 @@ impl ImageCache { } } -fn add_generic(map: &mut AHashMap, ctx: &egui::Context, image: LoadedImage) { +fn add_generic(map: &mut AHashMap, ctx: &egui::Context, image: LoadedImage) { client::tracing::debug!("decoded image id {}, kind {}", image.id, image.kind); let dimensions = image.image.size(); let texid = ctx.load_texture(image.id.to_string(), image.image); @@ -52,13 +52,13 @@ fn add_generic(map: &mut AHashMap, ctx: &egui pub struct LoadedImage { pub image: Image, - pub id: FileId, + pub id: String, pub kind: String, } impl LoadedImage { #[inline] - pub fn id(&self) -> &FileId { + pub fn id(&self) -> &str { &self.id } } @@ -67,17 +67,13 @@ impl LoadedImage { pub mod op { use super::*; - use client::harmony_rust_sdk::api::{exports::prost::bytes::Bytes, rest::FileId}; - use eframe::epi::backend::RepaintSignal; + use client::{harmony_rust_sdk::api::exports::prost::bytes::Bytes, tracing}; use egui::ColorImage; use image_worker::{ArchivedImageLoaded, ImageData, ImageLoaded}; use js_sys::Uint8Array; - use std::{ - lazy::SyncOnceCell, - sync::{mpsc::SyncSender as Sender, Arc}, - }; + use std::{lazy::SyncOnceCell, sync::mpsc::SyncSender as Sender}; use wasm_bindgen::{prelude::*, JsCast}; - use web_sys::{MessageEvent, Worker as WebWorker}; + use web_sys::{window, Blob, BlobPropertyBag, MessageEvent, Url, Worker as WebWorker}; impl LoadedImage { pub fn from_archive(data: &ArchivedImageLoaded) -> Self { @@ -85,11 +81,10 @@ pub mod op { let dimensions = [data.dimensions[0] as usize, data.dimensions[1] as usize]; let image = Image::Color(ColorImage::from_rgba_unmultiplied(dimensions, data.pixels.as_slice())); - let id = FileId::from_str(data.id.as_str()); Self { image, - id: id.unwrap(), + id: data.id.to_string(), kind: data.kind.as_str().into(), } } @@ -100,7 +95,7 @@ pub mod op { } impl WorkerPool { - fn new(chan: Sender, rr: Arc) -> Self { + fn new(chan: Sender, rr: egui::Context) -> Self { Self { inner: spawn_worker(chan, rr), } @@ -118,8 +113,23 @@ pub mod op { static WORKER_POOL: SyncOnceCell = SyncOnceCell::new(); - fn spawn_worker(tx: Sender, rr: Arc) -> WebWorker { - let worker = WebWorker::new("./image_worker.js").expect("failed to start worker"); + fn spawn_worker(tx: Sender, rr: egui::Context) -> WebWorker { + let origin = window() + .expect("window to be available") + .location() + .origin() + .expect("origin to be available"); + + let script = js_sys::Array::new(); + let name = "image_worker"; + script.push(&format!(r#"importScripts("{origin}/{name}.js");wasm_bindgen("{origin}/{name}_bg.wasm");"#).into()); + + let blob = Blob::new_with_str_sequence_and_options(&script, BlobPropertyBag::new().type_("text/javascript")) + .expect("blob creation succeeds"); + + let url = Url::create_object_url_with_blob(&blob).expect("url creation succeeds"); + + let worker = WebWorker::new(&url).expect("failed to spawn worker"); let handler = Closure::wrap(Box::new(move |event: MessageEvent| { let data: Uint8Array = event.data().dyn_into().unwrap_throw(); @@ -141,18 +151,20 @@ pub mod op { worker } - pub fn set_image_channel(tx: Sender, rr: Arc) { + pub fn set_image_channel(tx: Sender, rr: egui::Context) { let worker_pool = WorkerPool::new(tx, rr); if WORKER_POOL.set(worker_pool).is_err() { unreachable!("worker pool must only be init once -- this is a bug"); } } - pub fn decode_image(data: Bytes, id: FileId, kind: String) { + pub fn decode_image(data: Bytes, id: String, kind: String) { + tracing::debug!("sending image (id {id}) for decoding"); + let val = rkyv::to_bytes::<_, 2048>(&ImageData { data: data.to_vec(), kind, - id: id.into(), + id, }) .unwrap() .into_vec(); @@ -162,7 +174,7 @@ pub mod op { WORKER_POOL .get() - .expect("must be initialized") + .expect_throw("must be initialized") .get_worker() .post_message(&data) .expect_throw("failed to decode image"); @@ -173,19 +185,13 @@ pub mod op { pub mod op { use super::*; - use std::{ - lazy::SyncOnceCell, - sync::{mpsc::SyncSender as Sender, Arc}, - }; + use std::{lazy::SyncOnceCell, sync::mpsc::SyncSender as Sender}; - use client::{ - harmony_rust_sdk::api::{exports::prost::bytes::Bytes, rest::FileId}, - tracing, - }; - use eframe::{egui::ColorImage, epi::backend::RepaintSignal}; + use client::{harmony_rust_sdk::api::exports::prost::bytes::Bytes, tracing}; + use eframe::egui::ColorImage; impl LoadedImage { - pub fn load(data: Bytes, id: FileId, kind: String) -> Option { + pub fn load(data: Bytes, id: String, kind: String) -> Option { let Some(loaded) = image_worker::load_image_logic(data.as_ref(), kind.as_str()) else { tracing::error!( "could not load an image (id {}); most likely unsupported format", @@ -202,17 +208,19 @@ pub mod op { } } - static CHANNEL: SyncOnceCell<(Sender, Arc)> = SyncOnceCell::new(); + static CHANNEL: SyncOnceCell<(Sender, egui::Context)> = SyncOnceCell::new(); /// This should only be called once. - pub fn set_image_channel(tx: Sender, rr: Arc) { + pub fn set_image_channel(tx: Sender, rr: egui::Context) { if CHANNEL.set((tx, rr)).is_err() { unreachable!("image channel already set -- this is a bug"); } } /// Do not call this before calling `set_image_channel`. - pub fn decode_image(data: Bytes, id: FileId, kind: String) { + pub fn decode_image(data: Bytes, id: String, kind: String) { + tracing::debug!("sending image (id {id}) for decoding"); + tokio::task::spawn_blocking(move || { let Some(loaded) = LoadedImage::load(data, id, kind) else { return }; let chan = CHANNEL.get().expect("no image channel set -- this is a bug"); diff --git a/src/main.rs b/src/main.rs index 786b45b..401b0ff 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,21 +37,28 @@ fn main() { let icon_raw = include_bytes!("../data/loqui.ico"); let image = image::load_from_memory(icon_raw).expect("icon must be valid"); let image = image.to_rgba8(); - eframe::epi::IconData { + eframe::IconData { width: image.width(), height: image.height(), rgba: image.into_vec(), } }; - let app = loqui::App::new(); let native_options = eframe::NativeOptions { initial_window_size: Some([1280.0, 720.0].into()), drag_and_drop_support: true, icon_data: Some(icon_data), ..Default::default() }; - eframe::run_native(Box::new(app), native_options); + eframe::run_native( + "loqui", + native_options, + Box::new(|cc| { + let mut app = loqui::App::new(); + app.setup(cc); + Box::new(app) + }), + ); } #[cfg(target_arch = "wasm32")] @@ -59,6 +66,12 @@ fn main() -> Result<(), eframe::wasm_bindgen::JsValue> { console_error_panic_hook::set_once(); tracing_wasm::set_as_global_default(); - let app = loqui::App::new(); - eframe::start_web("egui_canvas", Box::new(app)) + eframe::start_web( + "egui_canvas", + Box::new(|cc| { + let mut app = loqui::App::new(); + app.setup(cc); + Box::new(app) + }), + ) } diff --git a/src/screen/auth.rs b/src/screen/auth.rs index 101895d..cb5b831 100644 --- a/src/screen/auth.rs +++ b/src/screen/auth.rs @@ -238,7 +238,7 @@ impl AppScreen for Screen { "auth" } - fn update(&mut self, ctx: &egui::Context, _: &epi::Frame, state: &mut State) { + fn update(&mut self, ctx: &egui::Context, _: &eframe::Frame, state: &mut State) { self.handle_connect(state); self.handle_step(state); diff --git a/src/screen/guild_settings.rs b/src/screen/guild_settings.rs index 5d503e2..d618ddd 100644 --- a/src/screen/guild_settings.rs +++ b/src/screen/guild_settings.rs @@ -96,7 +96,7 @@ impl Screen { let avatar_but = ui .add_enabled( guild.has_perm(all_permissions::GUILD_MANAGE_CHANGE_INFORMATION), - Avatar::new(guild.picture.as_ref(), guild.name.as_str(), state).size(64.0), + Avatar::new(guild.picture.as_deref(), guild.name.as_str(), state).size(64.0), ) .on_hover_text("set picture"); if avatar_but.clicked() { @@ -187,11 +187,9 @@ impl Screen { .response; resp.on_hover_text("right click to manage").context_menu_styled(|ui| { if ui.button("copy invite").clicked() { - let homeserver = guild - .homeserver - .is_empty() - .then(|| state.client().inner().homeserver_url().authority().unwrap().as_str()) - .unwrap_or_else(|| guild.homeserver.as_str()); + let homeserver = guild.homeserver.as_deref().unwrap_or_else(|| { + state.client().inner().homeserver_url().authority().unwrap().as_str() + }); ui.output().copied_text = format!("hmc://{}/{}", homeserver, id); ui.close_menu(); } @@ -353,6 +351,7 @@ impl Screen { self.managing_perms = managing_perms; } + #[allow(clippy::too_many_arguments)] fn view_perm( &self, state: &State, @@ -386,7 +385,7 @@ impl Screen { } impl AppScreen for Screen { - fn update(&mut self, ctx: &egui::Context, _: &epi::Frame, state: &mut State) { + fn update(&mut self, ctx: &egui::Context, _: &eframe::Frame, state: &mut State) { self.view_manage_role_perms(state, ctx); egui::CentralPanel::default().show(ctx, |ui| { diff --git a/src/screen/main.rs b/src/screen/main.rs index 9558868..0054fcf 100644 --- a/src/screen/main.rs +++ b/src/screen/main.rs @@ -4,14 +4,22 @@ use client::{ channel::Channel, content, guild::Guild, - harmony_rust_sdk::api::{chat::all_permissions, exports::prost::bytes::Bytes, profile::UserStatus, rest::FileId}, + harmony_rust_sdk::api::{ + chat::{ + all_permissions, attachment::Info, embed, send_message_request, Attachment, Embed, Overrides, + SendMessageRequest, + }, + exports::prost::bytes::Bytes, + mediaproxy::fetch_link_metadata_response::metadata, + profile::user_status, + }, member::Member, - message::{Attachment, Content, Embed, EmbedHeading, Message, MessageId, Override, ReadMessagesView}, + message::{AttachmentExt, Message, MessageId, ReadMessagesView}, smol_str::SmolStr, - AHashMap, AHashSet, FetchEvent, Uri, + AHashMap, AHashSet, FetchEvent, U64Ext, Uri, }; use eframe::egui::{vec2, Color32, Event, RichText, Rounding, Vec2}; -use egui::Margin; +use egui::style::Margin; use crate::{ config::BgImage, @@ -127,7 +135,7 @@ pub struct Screen { dont_highlight_message: AHashSet<(u64, u64, MessageId)>, /// file id -> bool /// if `true`, then we are (down)loading this attachment - loading_attachment: AHashMap, + loading_attachment: AHashMap, /// current guild / channel current: CurrentIds, /// main message composer @@ -165,10 +173,12 @@ pub struct Screen { /// panel stack keeping track of where we are / were panel_stack: PanelStack, main_composer_id: OnceCell, + + fetching_channels: AtomBool, } impl Screen { - fn get_override(&self, state: &State) -> Option { + fn get_override(&self, state: &State) -> Option { let Some(guild_id) = self.current.guild() else { return None }; state .config @@ -220,10 +230,9 @@ impl Screen { .insert(attachment.id.clone(), image_load_bool.clone()); spawn_evs!(state, |sender, client| { - let res = image_load_bool + let file = image_load_bool .scope(client.fetch_attachment(attachment.id.clone())) - .await; - let (_, file) = res?; + .await?; let _ = sender.send(FetchEvent::Attachment { attachment, file }); ClientResult::Ok(()) }); @@ -317,7 +326,7 @@ impl Screen { let button = ui .add_enabled_ui(is_enabled, |ui| { if guild.fetched { - let mut avatar = Avatar::new(guild.picture.as_ref(), guild.name.as_str(), state); + let mut avatar = Avatar::new(guild.picture.as_deref(), guild.name.as_str(), state); if !is_enabled { avatar = avatar.fill_bg(loqui_style::BG_LIGHT); } @@ -342,15 +351,23 @@ impl Screen { self.current.set_channel(*channel_id); } if guild.channels.is_empty() && guild.members.is_empty() { - spawn_evs!(state, |events, c| { - c.fetch_channels(guild_id, events).await?; - }); - spawn_evs!(state, |events, c| { - c.fetch_guild_perms(guild_id, events).await?; - }); - spawn_evs!(state, |events, c| { - c.fetch_members(guild_id, events).await?; - }); + if guild_id != 0 { + let fetching_channels = self.fetching_channels.clone(); + spawn_evs!(state, |events, c| { + fetching_channels.scope(c.fetch_channels(guild_id, events)).await?; + }); + spawn_evs!(state, |events, c| { + c.fetch_guild_perms(guild_id, events).await?; + }); + spawn_evs!(state, |events, c| { + c.fetch_members(guild_id, events).await?; + }); + } else { + let fetching_channels = self.fetching_channels.clone(); + spawn_evs!(state, |events, c| { + fetching_channels.scope(c.fetch_private_channels(events)).await?; + }); + } } self.scroll_to_bottom(ui); } @@ -385,10 +402,10 @@ impl Screen { .map_or_else(|| "unknown", |g| g.name.as_str()); let menu_but_clicked = egui::Frame::group(ui.style()) - .margin(Margin::same(2.0)) + .inner_margin(Margin::same(2.0)) .show(ui, |ui| { let but = ui - .add(TextButton::text(guild_name).small()) + .add_enabled(guild_id != 0, TextButton::text(guild_name).small()) .on_hover_text("open guild settings"); but.clicked() @@ -425,7 +442,7 @@ impl Screen { && channel.messages.continuous_view().is_empty() { spawn_evs!(state, |events, c| { - c.fetch_messages(guild_id, channel_id, None, None, events).await?; + c.fetch_messages(Some(guild_id), channel_id, None, None, events).await?; let _ = events.send(FetchEvent::FetchedMsgsPins(guild_id, channel_id)); }); } @@ -438,9 +455,11 @@ impl Screen { self.scroll_to_bottom(ui); } } - } else { + } else if self.fetching_channels.get() { ui.add_sized(ui.available_size(), egui::Spinner::new().size(32.0)) .on_hover_text_at_pointer("loading channels"); + } else { + ui.centered_and_justified(|ui| ui.label("no channels")); } }); } @@ -485,7 +504,9 @@ impl Screen { let message_id = id.id().unwrap(); self.editing_message = None; spawn_client_fut!(state, |client| { - client.edit_message(guild_id, channel_id, message_id, text).await + client + .edit_message(guild_id.if_not_zero(), channel_id, message_id, text) + .await }); } } else if highlight_message { @@ -503,10 +524,14 @@ impl Screen { fn view_message_url_embeds<'a>(&mut self, state: &State, ui: &mut Ui, urls: impl Iterator) { let urls = urls.filter_map(|(og, url)| Some((state.cache.get_link_data(&url)?, url, og))); - for (data, url, raw_url) in urls { + for (data, _, raw_url) in urls { match data { - client::harmony_rust_sdk::api::mediaproxy::fetch_link_metadata_response::Data::IsSite(data) => { - let id = FileId::External(data.image.parse::().unwrap_or(url)); + metadata::Data::IsSite(data) => { + let id = data + .thumbnail + .first() + .map(|i| i.url.clone()) + .unwrap_or_else(|| raw_url.to_string()); let has_site_title = data.site_title.is_empty().not(); let has_page_title = data.page_title.is_empty().not(); let has_desc = data.description.is_empty().not(); @@ -550,14 +575,14 @@ impl Screen { }); } } - client::harmony_rust_sdk::api::mediaproxy::fetch_link_metadata_response::Data::IsMedia(data) => { - let id = FileId::External(url); + metadata::Data::IsMedia(data) => { let attachment = Attachment { - name: data.filename.clone(), - kind: data.mimetype.clone(), + name: data.name.clone(), + mimetype: data.mimetype.clone(), // we dont want the attachment to count as thumbnail size: u32::MAX, - ..Attachment::new_unknown(id) + id: raw_url.to_string(), + ..Default::default() }; let mut download = false; @@ -571,14 +596,14 @@ impl Screen { let open_but = ui.frameless_image_button(tex.id(), size); open = open_but.clicked(); } else { - download = ui.button(format!("download '{}'", data.filename)).clicked(); + download = ui.button(format!("download '{}'", data.name)).clicked(); } } else { - open = ui.button(format!("open '{}'", data.filename)).clicked(); + open = ui.button(format!("open '{}'", data.name)).clicked(); } } else { ui.add(egui::Spinner::new()) - .on_hover_text(format!("downloading '{}'", data.filename)); + .on_hover_text(format!("downloading '{}'", data.name)); } if open { @@ -597,12 +622,11 @@ impl Screen { let mut fetch = false; let mut open = false; - if attachment.is_raster_image() { + if let (Some(Info::Image(info)), true) = (&attachment.info, attachment.is_raster_image()) { let mut no_thumbnail = false; - let maybe_size = attachment - .resolution - .and_then(|(w, h)| (w == 0 || h == 0).not().then(|| ui.downscale([w as f32, h as f32]))); + let (w, h) = (info.width, info.height); + let maybe_size = (w == 0 || h == 0).not().then(|| ui.downscale([w as f32, h as f32])); let is_fetching = self.is_fetching_attachment(attachment); @@ -640,7 +664,14 @@ impl Screen { } let load_thumbnail = no_thumbnail && state.loading_images.borrow().iter().all(|id| id != &attachment.id); - if let (true, Some(minithumbnail)) = (load_thumbnail, &attachment.minithumbnail) { + let maybe_minithumb = attachment.info.as_ref().and_then(|a| { + if let Info::Image(info) = a { + info.minithumbnail.as_ref() + } else { + None + } + }); + if let (true, Some(minithumbnail)) = (load_thumbnail, maybe_minithumb) { state.loading_images.borrow_mut().push(attachment.id.clone()); let data = Bytes::copy_from_slice(minithumbnail.data.as_slice()); let id = attachment.id.clone(); @@ -662,14 +693,13 @@ impl Screen { } fn view_message_embed(&mut self, ui: &mut Ui, embed: &Embed) { - fn filter_empty(val: &Option) -> Option<&str> { - val.as_deref().map(str::trim).filter(|s| s.is_empty().not()) + fn filter_empty(val: Option<&String>) -> Option<&str> { + val.map(|s| s.trim()).filter(|s| s.is_empty().not()) } ui.group(|ui| { - let do_render_heading = - |heading: &&EmbedHeading| heading.text.is_empty().not() && filter_empty(&heading.subtext).is_some(); - let render_header = |header: &EmbedHeading, ui: &mut Ui| { + let do_render_heading = |heading: &&embed::Heading| heading.text.is_empty().not(); + let render_header = |header: &embed::Heading, ui: &mut Ui| { // TODO: render icon ui.horizontal(|ui| { let button = ui.add_enabled( @@ -681,9 +711,6 @@ impl Screen { open_url(url); } } - if let Some(subtext) = filter_empty(&header.subtext) { - ui.label(RichText::new(subtext).small()); - } }); }; @@ -696,7 +723,7 @@ impl Screen { ui.label(RichText::new(&embed.title).strong()); } - if let Some(body) = filter_empty(&embed.body) { + if let Some(body) = filter_empty(embed.body.as_ref().map(|f| &f.text)) { ui.label(body); } @@ -705,12 +732,9 @@ impl Screen { if field.title.is_empty().not() { ui.label(RichText::new(&field.title).strong()); } - if let Some(subtitle) = filter_empty(&field.subtitle) { - ui.label(RichText::new(subtitle).small()); - } ui.add_space(4.0); - if let Some(body) = filter_empty(&field.body) { - ui.label(body); + if field.body.is_empty().not() { + ui.label(&field.body); } }); } @@ -742,7 +766,7 @@ impl Screen { if display_user { let overrides = message.overrides.as_ref(); - let override_name = overrides.and_then(|ov| ov.name.as_deref()); + let override_name = overrides.and_then(|ov| ov.username.as_deref()); let sender_name = user.map_or_else(|| "unknown", |u| u.username.as_str()); let display_name = override_name.unwrap_or(sender_name); @@ -774,62 +798,52 @@ impl Screen { ui.add_space(ui.style().spacing.item_spacing.y); } - match &message.content { - client::message::Content::Text(text) => { - let (urls, has_only_image) = parse_urls(text, state); - self.view_message_text_content( - state, - ui, - id, - guild_id, - channel_id, - text.trim(), - message.failed_to_send, - has_only_image, - &urls, - ); - self.view_message_url_embeds(state, ui, urls.into_iter()); - } - client::message::Content::Files(attachments) => { - for attachment in attachments { - self.view_message_attachment(state, ui, attachment); - } - } - client::message::Content::Embeds(embeds) => { - for embed in embeds { - self.view_message_embed(ui, embed); - } - } + let (urls, has_only_image) = parse_urls(&message.content.text, state); + self.view_message_text_content( + state, + ui, + id, + guild_id, + channel_id, + message.content.text.trim(), + message.failed_to_send, + has_only_image, + &urls, + ); + self.view_message_url_embeds(state, ui, urls.into_iter()); + for attachment in &message.content.attachments { + self.view_message_attachment(state, ui, attachment); + } + for embed in &message.content.embeds { + self.view_message_embed(ui, embed); } }) .response; msg.context_menu_styled(|ui| { if let Some(message_id) = id.id() { - if let client::message::Content::Text(text) = &message.content { - if client::has_perm(guild, channel, all_permissions::MESSAGES_SEND) - && message.sender == user_id - && ui.button("edit").clicked() - { - self.editing_message = id.id(); - let edit_text = self.edit_message_composer.text_mut(); - edit_text.clear(); - edit_text.push_str(text); - ui.close_menu(); - } - if ui.button("quote reply").clicked() { - let composer_text = self.composer.text_mut(); - composer_text.clear(); - composer_text.push_str("> "); - composer_text.push_str(text); - composer_text.push('\n'); - ui.memory().request_focus(self.main_composer_id()); - ui.close_menu(); - } - if ui.button("copy").clicked() { - ui.output().copied_text = text.clone(); - ui.close_menu(); - } + if client::has_perm(guild, channel, all_permissions::MESSAGES_SEND) + && message.sender == user_id + && ui.button("edit").clicked() + { + self.editing_message = id.id(); + let edit_text = self.edit_message_composer.text_mut(); + edit_text.clear(); + edit_text.push_str(&message.content.text); + ui.close_menu(); + } + if ui.button("quote reply").clicked() { + let composer_text = self.composer.text_mut(); + composer_text.clear(); + composer_text.push_str("> "); + composer_text.push_str(&message.content.text); + composer_text.push('\n'); + ui.memory().request_focus(self.main_composer_id()); + ui.close_menu(); + } + if ui.button("copy").clicked() { + ui.output().copied_text = message.content.text.clone(); + ui.close_menu(); } if message.sender == state.client().user_id() && ui.button(dangerous_text("delete")).clicked() { spawn_client_fut!(state, |client| { @@ -901,7 +915,7 @@ impl Screen { tot }); for chunk in chunked_messages { - egui::Frame::none().margin(Margin::same(5.0)).show(ui, |ui| { + egui::Frame::none().inner_margin(Margin::same(5.0)).show(ui, |ui| { for (index, (id, message)) in chunk.into_iter().enumerate() { self.view_message( state, @@ -919,7 +933,7 @@ impl Screen { }); } if self.scroll_to_bottom { - ui.scroll_to_cursor(egui::Align::Max); + ui.scroll_to_cursor(Some(egui::Align::Max)); self.scroll_to_bottom = false; } }); @@ -1031,7 +1045,7 @@ impl Screen { } else { self.last_override_for_guild.remove(&guild_id); } - } else if let Some(name) = overrides.as_ref().and_then(|ov| ov.name.as_deref()) { + } else if let Some(name) = overrides.as_ref().and_then(|ov| ov.username.as_deref()) { let name = SmolStr::new(name); if is_latching_channel { self.last_override_for_channel.insert((guild_id, channel_id), name); @@ -1047,15 +1061,17 @@ impl Screen { if text_string.is_empty().not() && text_edit.has_focus() && did_submit_enter { self.composer.text_mut().clear(); - let message = Message { - content: Content::Text(text_string), - sender: state.client().user_id(), + let user_id = state.client().user_id(); + let request = SendMessageRequest { + guild_id: guild_id.if_not_zero(), + channel_id, overrides, ..Default::default() - }; - let echo_id = state.cache.prepare_send_message(guild_id, channel_id, message.clone()); + } + .with_text(text_string); + let echo_id = state.cache.prepare_send_message(user_id, request.clone()); spawn_evs!(state, |evs, client| { - client.send_message(echo_id, guild_id, channel_id, message, evs).await?; + client.send_message(request.with_echo_id(echo_id), evs).await?; }); self.scroll_to_bottom(ui); text_edit.surrender_focus(); @@ -1067,7 +1083,7 @@ impl Screen { .not() }); if should_send_typing { - spawn_client_fut!(state, |client| client.send_typing(guild_id, channel_id).await); + spawn_client_fut!(state, |client| client.send_typing(Some(guild_id), channel_id).await); } } } @@ -1075,9 +1091,11 @@ impl Screen { fn view_uploading_attachments(&mut self, state: &State, ui: &mut Ui) { ui.label(RichText::new("Uploading:").strong()); for name in state.uploading_files.read().expect("poisoned").iter() { - egui::Frame::group(ui.style()).margin(Margin::same(0.0)).show(ui, |ui| { - ui.label(name); - }); + egui::Frame::group(ui.style()) + .inner_margin(Margin::same(0.0)) + .show(ui, |ui| { + ui.label(name); + }); } } @@ -1100,16 +1118,12 @@ impl Screen { for file in files { let data = file.read().await; let mimetype = content::infer_type_from_bytes(&data); - let size = data.len() as u32; // TODO: return errors for files that failed to upload let id = client.upload_file(file.file_name(), mimetype.clone(), data).await?; - attachments.push(Attachment { + attachments.push(send_message_request::Attachment { id, - kind: mimetype, - size, name: file.file_name(), - minithumbnail: None, - resolution: None, + ..Default::default() }); } ClientResult::Ok(Some(UploadMessageResult { @@ -1129,28 +1143,27 @@ impl Screen { state: &State, ui: &mut Ui, user: Option<&Member>, - overrides: Option<&Override>, + overrides: Option<&Overrides>, fill_bg: Color32, ) { const SIZE: Vec2 = egui::vec2(28.0, 28.0); let maybe_tex = overrides - .and_then(|ov| ov.avatar_url.as_ref()) + .and_then(|ov| ov.avatar.as_ref()) .or_else(|| user.and_then(|u| u.avatar_url.as_ref())) .as_ref() .and_then(|id| state.image_cache.get_avatar(id)); - let status = user.map_or(UserStatus::OfflineUnspecified, |m| m.status); + let status = user.map_or(user_status::Kind::OfflineUnspecified, |m| m.status.kind()); let status_color = match status { - UserStatus::OfflineUnspecified => Color32::GRAY, - UserStatus::Online | UserStatus::Mobile => Color32::GREEN, - UserStatus::Streaming => Color32::from_rgb(160, 0, 160), - UserStatus::DoNotDisturb => Color32::RED, - UserStatus::Idle => Color32::GOLD, + user_status::Kind::OfflineUnspecified => Color32::GRAY, + user_status::Kind::Online => Color32::GREEN, + user_status::Kind::DoNotDisturb => Color32::RED, + user_status::Kind::Idle => Color32::GOLD, }; egui::Frame::group(ui.style()) - .margin(Vec2::ZERO) + .inner_margin(Vec2::ZERO) .rounding(0.0) .stroke(egui::Stroke::new(4.0, status_color)) .show(ui, |ui| { @@ -1159,7 +1172,7 @@ impl Screen { } else { ui.add_enabled_ui(false, |ui| { let username = overrides - .and_then(|ov| ov.name.as_deref()) + .and_then(|ov| ov.username.as_deref()) .or_else(|| user.map(|u| u.username.as_str())) .unwrap_or(""); let letter = username.get(0..1).unwrap_or("u").to_ascii_uppercase(); @@ -1221,7 +1234,7 @@ impl Screen { .keys() .filter_map(move |uid| Some((*uid, state.cache.get_user(*uid)?))) .filter_map(|member| Some((member, member.1.typing_in_channel?))) - .filter_map(move |(member, (gid, cid, _))| self.current.is_channel(gid, cid).then(|| member)) + .filter_map(move |(member, (gid, cid, _))| self.current.is_channel(gid.unwrap_or(0), cid).then(|| member)) } #[inline(always)] @@ -1244,13 +1257,7 @@ impl Screen { .into_iter() .rev() .filter_map(|(id, msg)| id.is_ack().then(|| (id.id().unwrap(), msg))) - .filter_map(|(id, msg)| { - if let Content::Text(text) = &msg.content { - Some((id, text, msg.sender)) - } else { - None - } - }) + .map(|(id, msg)| (id, &msg.content.text, msg.sender)) .find(|(_, _, sender)| *sender == user_id); if let Some((id, text, _)) = maybe_msg { @@ -1266,7 +1273,7 @@ impl Screen { #[inline(always)] fn show_guild_panel(&mut self, ui: &mut Ui, state: &mut State) { let panel_frame = egui::Frame { - margin: Margin::symmetric(8.0, 5.0), + inner_margin: Margin::symmetric(8.0, 5.0), fill: ui.style().visuals.extreme_bg_color, stroke: ui.style().visuals.window_stroke(), rounding: Rounding::same(4.0), @@ -1284,7 +1291,7 @@ impl Screen { #[inline(always)] fn show_channel_panel(&mut self, ui: &mut Ui, state: &mut State) { let panel_frame = egui::Frame { - margin: Margin::symmetric(8.0, 5.0), + inner_margin: Margin::symmetric(8.0, 5.0), fill: ui.style().visuals.window_fill(), stroke: ui.style().visuals.window_stroke(), rounding: Rounding::same(4.0), @@ -1311,7 +1318,7 @@ impl Screen { #[inline(always)] fn show_member_panel(&mut self, ui: &mut Ui, state: &mut State) { let panel_frame = egui::Frame { - margin: Margin::symmetric(8.0, 5.0), + inner_margin: Margin::symmetric(8.0, 5.0), fill: ui.style().visuals.extreme_bg_color, stroke: ui.style().visuals.window_stroke(), rounding: Rounding::same(4.0), @@ -1346,7 +1353,7 @@ impl Screen { ui.allocate_ui([top_channel_bar_width, interact_size.y].into(), |ui| { let frame = egui::Frame { - margin: Margin::symmetric(4.0, 2.0), + inner_margin: Margin::symmetric(4.0, 2.0), fill: ui.style().visuals.window_fill(), stroke: ui.style().visuals.window_stroke(), rounding: Rounding::same(2.0), @@ -1387,10 +1394,15 @@ impl Screen { } ui.offsetw(offset); - if self.current.has_guild() { - let show_members_but = ui - .add_sized([12.0, interact_size.y], TextButton::text("👤")) - .on_hover_text("toggle member list"); + if let Some(guild_id) = self.current.guild() { + let show_members_but = { + let layout = Layout::centered_and_justified(ui.layout().main_dir()); + ui.allocate_ui_with_layout([12.0, interact_size.y].into(), layout, |ui| { + ui.add_enabled(guild_id != 0, TextButton::text("👤")) + .on_hover_text("toggle member list") + }) + .inner + }; if show_members_but.clicked() { self.toggle_panel(Panel::Members); self.disable_users_bar = !self.disable_users_bar; @@ -1538,10 +1550,10 @@ impl Screen { ClientResult::Ok(Some(UploadMessageResult { guild_id, channel_id, - attachments: vec![Attachment { + attachments: vec![send_message_request::Attachment { + id, name, - kind: mimetype, - ..Attachment::new_unknown(id) + ..Default::default() }], })) }); @@ -1555,7 +1567,7 @@ impl AppScreen for Screen { "main" } - fn update(&mut self, ctx: &egui::Context, _: &epi::Frame, state: &mut State) { + fn update(&mut self, ctx: &egui::Context, _: &eframe::Frame, state: &mut State) { if ctx.input().key_pressed(egui::Key::Escape) { self.editing_message = None; } @@ -1568,7 +1580,7 @@ impl AppScreen for Screen { self.view_pinned_messages(state, ctx); let panel_frame = egui::Frame { - margin: Margin::same(8.0), + inner_margin: Margin::same(8.0), fill: loqui_style::BG_LIGHT, ..Default::default() }; @@ -1599,10 +1611,10 @@ impl AppScreen for Screen { let mut show_main = |state: &mut State, ui: &mut Ui| { self.show_guild_panel(ui, state); - if self.current.has_guild() { + if let Some(guild_id) = self.current.guild() { self.show_channel_panel(ui, state); - if !self.disable_users_bar { + if !self.disable_users_bar && guild_id != 0 { self.show_member_panel(ui, state); } diff --git a/src/screen/mod.rs b/src/screen/mod.rs index 17ef975..659f5da 100644 --- a/src/screen/mod.rs +++ b/src/screen/mod.rs @@ -3,10 +3,7 @@ use prelude::*; mod prelude { pub use super::Screen as AppScreen; pub use crate::{state::State, utils::*}; - pub use eframe::{ - egui::{self, Layout, Ui}, - epi, - }; + pub use eframe::egui::{self, Layout, Ui}; } pub mod auth; @@ -15,13 +12,13 @@ pub mod main; pub mod settings; pub trait Screen: 'static { - fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame, state: &mut State); + fn update(&mut self, ctx: &egui::Context, frame: &eframe::Frame, state: &mut State); // ran before push #[allow(unused_variables)] - fn on_push(&mut self, ctx: &egui::Context, frame: &epi::Frame, state: &mut State) {} + fn on_push(&mut self, ctx: &egui::Context, frame: &eframe::Frame, state: &mut State) {} // ran before pop #[allow(unused_variables)] - fn on_pop(&mut self, ctx: &egui::Context, frame: &epi::Frame, state: &mut State) {} + fn on_pop(&mut self, ctx: &egui::Context, frame: &eframe::Frame, state: &mut State) {} fn id(&self) -> &'static str { "" } diff --git a/src/screen/settings.rs b/src/screen/settings.rs index b3e5c70..7f90b98 100644 --- a/src/screen/settings.rs +++ b/src/screen/settings.rs @@ -80,7 +80,9 @@ impl Screen { if ui.ctx().is_using_pointer().not() { state.local_config.scale_factor = self.scale_factor; - ui.ctx().set_pixels_per_point(state.local_config.scale_factor); + if state.local_config.scale_factor != 0.0 { + ui.ctx().set_pixels_per_point(state.local_config.scale_factor); + } } }); @@ -131,7 +133,7 @@ impl Screen { fn view_general_profile(&mut self, state: &State, ui: &mut Ui, member: &Member) { ui.horizontal_top(|ui| { if self.uploading_user_pic.get().not() { - let avatar = Avatar::new(member.avatar_url.as_ref(), member.username.as_str(), state).size(64.0); + let avatar = Avatar::new(member.avatar_url.as_deref(), member.username.as_str(), state).size(64.0); let avatar_but = ui.add(avatar).on_hover_text("set picture"); if avatar_but.clicked() { let uploading_user_pic = self.uploading_user_pic.clone(); @@ -143,7 +145,7 @@ impl Screen { let data = file.read().await; let mimetype = content::infer_type_from_bytes(&data); let id = client.upload_file(name, mimetype, data).await?; - client.update_profile(None, Some(id), None).await?; + client.update_profile(None, Some(id)).await?; uploading_user_pic.set(false); } ClientResult::Ok(()) @@ -159,7 +161,7 @@ impl Screen { ui.add(egui::TextEdit::singleline(&mut self.user_name_edit_text).desired_width(100.0)); if ui.add(egui::Button::new("edit").small()).clicked() { let new_name = self.user_name_edit_text.clone(); - spawn_client_fut!(state, |client| client.update_profile(Some(new_name), None, None).await); + spawn_client_fut!(state, |client| client.update_profile(Some(new_name), None).await); } }); }); @@ -378,7 +380,7 @@ impl Screen { } impl AppScreen for Screen { - fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame, state: &mut State) { + fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame, state: &mut State) { self.handle_futures(state); egui::CentralPanel::default().show(ctx, |ui| { @@ -404,11 +406,11 @@ impl AppScreen for Screen { }); } - fn on_pop(&mut self, _: &egui::Context, _: &epi::Frame, state: &mut State) { + fn on_pop(&mut self, _: &egui::Context, _: &eframe::Frame, state: &mut State) { state.save_config(); } - fn on_push(&mut self, _: &egui::Context, _: &epi::Frame, state: &mut State) { + fn on_push(&mut self, _: &egui::Context, _: &eframe::Frame, state: &mut State) { state.save_config(); } } diff --git a/src/state.rs b/src/state.rs index 9b5539f..19442fa 100644 --- a/src/state.rs +++ b/src/state.rs @@ -10,18 +10,18 @@ use std::{ use client::{ harmony_rust_sdk::{ api::{ - chat::{stream_event::Event as ChatEvent, Event}, + chat::{stream_event::Event as ChatEvent, Event, SendMessageRequest}, profile::ProfileOverride, - rest::{About, FileId}, + rest::About, }, client::{EventsReadSocket, EventsSocket}, }, - message::{Content, Message}, + message::{AttachmentExt, Message}, tracing, Cache, Client, EventSender, FetchEvent, }; use eframe::{ egui::{self, TextureHandle, Vec2}, - epi::IntegrationInfo, + IntegrationInfo, }; use instant::Instant; use tokio::sync::mpsc as tokio_mpsc; @@ -76,7 +76,7 @@ pub struct State { pub images_tx: SyncSender, /// Images we are currently loading. - pub loading_images: RefCell>, + pub loading_images: RefCell>, /// Files that are being uploaded. pub uploading_files: Arc>>, /// Screen to push to screen stack on next frame. @@ -193,10 +193,10 @@ impl State { } } - pub fn init(&mut self, ctx: &egui::Context, frame: &eframe::epi::Frame) { - crate::image_cache::op::set_image_channel(self.images_tx.clone(), frame.lock().repaint_signal.clone()); + pub fn init(&mut self, ctx: &egui::Context, integration_info: eframe::IntegrationInfo) { + crate::image_cache::op::set_image_channel(self.images_tx.clone(), ctx.clone()); - self.integration_info = Some(frame.info()); + self.integration_info = Some(integration_info); #[cfg(not(target_arch = "wasm32"))] if self.local_config.scale_factor < 0.5 { self.local_config.scale_factor = self @@ -206,7 +206,7 @@ impl State { .unwrap_or(1.45); } - self.futures.init(frame); + self.futures.init(ctx.clone()); // load harmony lotus self.harmony_lotus.replace(load_harmony_lotus(ctx)); @@ -241,22 +241,21 @@ impl State { self.cache.maintain(|ev| match ev { FetchEvent::Attachment { attachment, file } => { if attachment.is_raster_image() { - crate::image_cache::op::decode_image(file.data, attachment.id, attachment.name); + crate::image_cache::op::decode_image(file.data, attachment.id.parse().unwrap(), attachment.name); } None } ev => { if let FetchEvent::Harmony(Event::Chat(ChatEvent::SentMessage(message_sent))) = &ev { let Some(message) = message_sent.message.as_ref() else { return Some(ev) }; - if let Some(text) = message.get_text_content() { + if let Some(text) = message.get_text() { if message.author_id != self.client.as_ref().unwrap().user_id() { let triggers_keyword = text - .text .split_whitespace() .filter_map(|word| self.config.mention_keywords.iter().find(|keyword| *keyword == word)) .next(); if let Some(keyword) = triggers_keyword { - show_notification(format!("mention keyword '{}' triggered", keyword), &text.text); + show_notification(format!("mention keyword '{}' triggered", keyword), text); } } } @@ -319,7 +318,7 @@ impl State { pub fn get_member_display_name<'a>(&'a self, msg: &'a Message) -> &'a str { let user = self.cache.get_user(msg.sender); let overrides = msg.overrides.as_ref(); - let override_name = overrides.and_then(|ov| ov.name.as_deref()); + let override_name = overrides.and_then(|ov| ov.username.as_deref()); let sender_name = user.map_or_else(|| "unknown", |u| u.username.as_str()); override_name.unwrap_or(sender_name) } @@ -390,14 +389,14 @@ impl State { } } - let message = Message { - content: Content::Files(attachments), - sender: self.client().user_id(), - ..Default::default() - }; - let echo_id = self.cache.prepare_send_message(guild_id, channel_id, message.clone()); + let user_id = self.client().user_id(); + let request = SendMessageRequest::default() + .with_guild_id(guild_id) + .with_channel_id(channel_id) + .with_attachments(attachments); + let echo_id = self.cache.prepare_send_message(user_id, request.clone()); spawn_evs!(self, |evs, client| { - client.send_message(echo_id, guild_id, channel_id, message, evs).await?; + client.send_message(request.with_echo_id(echo_id), evs).await?; }); } Err(err) => { diff --git a/src/utils.rs b/src/utils.rs index 1e71941..abbcee0 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -3,20 +3,18 @@ use std::{ cmp::Ordering, future::Future, ops::{Deref, Not}, - str::FromStr, sync::{atomic::AtomicBool, Arc}, }; use client::{ guild::Guild, harmony_rust_sdk::api::{ - chat::overrides::Reason, + chat::{overrides::Reason, Overrides}, mediaproxy::fetch_link_metadata_response, - profile::{profile_override, ProfileOverride, UserStatus}, - rest::FileId, + profile::{profile_override, user_status, ProfileOverride}, }, member::Member, - message::{is_raster_image, Override}, + message::is_raster_image, role::Role, tracing, Cache, Client, Uri, }; @@ -292,8 +290,8 @@ pub fn sort_members<'a, 'b>(state: &'a State, guild: &'b Guild) -> Vec<(&'b u64, .collect::>(); sorted_members.sort_unstable_by(|(_, member), (_, other_member)| { let name = member.username.as_str().cmp(other_member.username.as_str()); - let offline = matches!(member.status, UserStatus::OfflineUnspecified); - let other_offline = matches!(other_member.status, UserStatus::OfflineUnspecified); + let offline = matches!(member.status.kind(), user_status::Kind::OfflineUnspecified); + let other_offline = matches!(other_member.status.kind(), user_status::Kind::OfflineUnspecified); match (offline, other_offline) { (false, true) => Ordering::Less, @@ -329,27 +327,9 @@ pub fn dangerous_text(text: impl Into) -> RichText { } /// Construct a URL from a harmony file ID. -pub fn make_url_from_file_id(client: &Client, id: &FileId) -> String { - match id { - FileId::Hmc(hmc) => format!( - "https://{}:{}/_harmony/media/download/{}", - hmc.server(), - hmc.port(), - hmc.id(), - ), - FileId::Id(id) => { - let homeserver = client.inner().homeserver_url(); - format!("{}_harmony/media/download/{}", homeserver, id) - } - FileId::External(ext) => { - let homeserver = client.inner().homeserver_url(); - format!( - "{}_harmony/media/download/{}", - homeserver, - urlencoding::encode(&ext.to_string()) - ) - } - } +pub fn make_url_from_file_id(client: &Client, id: &str) -> String { + let homeserver = client.inner().homeserver_url(); + format!("{}_harmony/media/download/{}", homeserver, urlencoding::encode(id)) } // opens a URL in background @@ -387,7 +367,7 @@ pub fn parse_urls<'a>(text: &'a str, state: &State) -> (Vec<(&'a str, Uri)>, boo .filter(|u| matches!(u.scheme_str(), Some("http" | "https"))); if let Some(url) = parsed { let is_image = state.cache.get_link_data(&url).map_or(false, |d| { - if let fetch_link_metadata_response::Data::IsMedia(media) = d { + if let fetch_link_metadata_response::metadata::Data::IsMedia(media) = d { is_raster_image(&media.mimetype) } else { false @@ -448,10 +428,10 @@ pub fn show_notification(summary: impl AsRef, body: impl AsRef) { } } -pub fn override_from_profile(p: &ProfileOverride) -> Override { - Override { - name: p.username.clone(), - avatar_url: p.avatar.as_ref().and_then(|s| FileId::from_str(s).ok()), +pub fn override_from_profile(p: &ProfileOverride) -> Overrides { + Overrides { + username: p.username.clone(), + avatar: p.avatar.clone(), reason: p.reason.clone().map(|reason| match reason { profile_override::Reason::UserDefined(custom) => Reason::UserDefined(custom), profile_override::Reason::SystemPlurality(empty) => Reason::SystemPlurality(empty), diff --git a/src/widgets/bg_image.rs b/src/widgets/bg_image.rs index ce32bfa..6e8e630 100644 --- a/src/widgets/bg_image.rs +++ b/src/widgets/bg_image.rs @@ -1,8 +1,7 @@ //! Frame container -use eframe::egui::{self, epaint}; +use eframe::egui; use egui::{layers::ShapeIdx, *}; -use epaint::*; /// Put an image background behind some UI. #[derive(Clone, Copy, Debug)] diff --git a/src/widgets/easy_mark/easy_mark_editor.rs b/src/widgets/easy_mark/easy_mark_editor.rs index dfe955a..444c4c5 100644 --- a/src/widgets/easy_mark/easy_mark_editor.rs +++ b/src/widgets/easy_mark/easy_mark_editor.rs @@ -70,7 +70,7 @@ impl EasyMarkEditor { let response = if self.highlight_editor { let mut layouter = |ui: &egui::Ui, easymark: &str, wrap_width: f32| { let mut layout_job = highlighter.highlight(ui.style(), easymark); - layout_job.wrap_width = wrap_width; + layout_job.wrap.max_width = wrap_width; ui.fonts().layout_job(layout_job) }; diff --git a/src/widgets/mod.rs b/src/widgets/mod.rs index 46e8068..7c3ffa8 100644 --- a/src/widgets/mod.rs +++ b/src/widgets/mod.rs @@ -3,10 +3,7 @@ use std::ops::Not; use client::{ channel::Channel, guild::Guild, - harmony_rust_sdk::api::{ - chat::all_permissions, - rest::{About as AboutServer, FileId}, - }, + harmony_rust_sdk::api::{chat::all_permissions, rest::About as AboutServer}, member::Member, }; use eframe::egui::{self, Button, CollapsingHeader, Color32, Response, RichText, Ui, Widget, WidgetText}; @@ -90,14 +87,14 @@ impl Widget for About { /// View an avatar pub struct Avatar<'a> { state: &'a State, - maybe_id: Option<&'a FileId>, + maybe_id: Option<&'a str>, text: &'a str, size: f32, fill_bg: Option, } impl<'a> Avatar<'a> { - pub fn new(maybe_id: Option<&'a FileId>, text: &'a str, state: &'a State) -> Self { + pub fn new(maybe_id: Option<&'a str>, text: &'a str, state: &'a State) -> Self { Self { state, maybe_id,