diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f4cc9fb5..bb975c93 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,7 +26,7 @@ jobs: - uses: flatpak/flatpak-github-actions/flatpak-builder@v6 with: bundle: reflection.flatpak - manifest-path: org.p2panda.reflection.json + manifest-path: cx.modal.reflection.json cache-key: flatpak-builder-${{ github.sha }} arch: ${{ matrix.variant.arch }} run-tests: true @@ -36,11 +36,10 @@ jobs: # the zip artifact, extract it, install the flatpak and run it. # unzip reflection-x86_64.zip # flatpak --user install reflection.flatpak - # flatpak run org.p2panda.reflection + # flatpak run cx.modal.reflection - macos: - if: false # This disable macos for now. - name: macOS + macos: + name: macOS (${{ matrix.arch }}) runs-on: macos-latest strategy: fail-fast: false @@ -53,6 +52,9 @@ jobs: steps: - uses: actions/checkout@v4 - uses: moonrepo/setup-rust@v1 + with: + targets: ${{ matrix.target }} + channel: nightly env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -62,8 +64,9 @@ jobs: path: | ~/Library/Caches/Homebrew /usr/local/Homebrew - /opt/homebrew - key: ${{ runner.os }}-${{ matrix.arch }}-brew-${{ hashFiles('.github/workflows/build.yml') }} + # FIXME: Cache action is not allowed to cache x86_64 Homebrew directory + # /opt/homebrew + key: ${{ runner.os }}-${{ matrix.arch }}-brew-${{ hashFiles('**/Brewfile', '.github/workflows/build.yml') }} restore-keys: | ${{ runner.os }}-${{ matrix.arch }}-brew- @@ -74,158 +77,38 @@ jobs: sudo mkdir -p /usr/local sudo chown -R $(whoami) /usr/local arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" - eval "$(/usr/local/bin/brew shellenv)" - echo "PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/local/opt/pango/lib/pkgconfig:/usr/local/opt/cairo/lib/pkgconfig:/usr/local/opt/gdk-pixbuf/lib/pkgconfig:/usr/local/opt/graphene/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig:/usr/local/opt/gtk4/lib/pkgconfig:/usr/local/opt/libadwaita/lib/pkgconfig" >> $GITHUB_ENV - - - name: Install pkg-config (x86_64) - if: matrix.arch == 'x86_64' - run: arch -x86_64 /usr/local/bin/brew install pkg-config || echo ERROR - - - name: Install GDK-Pixbuf (x86_64) - if: matrix.arch == 'x86_64' - run: arch -x86_64 /usr/local/bin/brew install gdk-pixbuf || echo ERROR - - - name: Install Cairo (x86_64) - if: matrix.arch == 'x86_64' - run: arch -x86_64 /usr/local/bin/brew install cairo || echo ERROR - - - name: Install Pango (x86_64) - if: matrix.arch == 'x86_64' - run: arch -x86_64 /usr/local/bin/brew install pango || echo ERROR - - - name: Install AT-SPI2-Core (x86_64) - if: matrix.arch == 'x86_64' - run: arch -x86_64 /usr/local/bin/brew install at-spi2-core || echo ERROR - - - name: Install Graphene (x86_64) - if: matrix.arch == 'x86_64' - run: arch -x86_64 /usr/local/bin/brew install graphene || echo ERROR - - - name: Install GTK4 (x86_64) - if: matrix.arch == 'x86_64' - run: arch -x86_64 /usr/local/bin/brew install gtk4 || echo ERROR - - - name: Install GtkSourceView5 (x86_64) - if: matrix.arch == 'x86_64' - run: arch -x86_64 /usr/local/bin/brew install gtksourceview5 || echo ERROR - - - name: Install Libadwaita (x86_64) - if: matrix.arch == 'x86_64' - run: arch -x86_64 /usr/local/bin/brew install -v libadwaita - - name: Install dylibbundler (x86_64) - if: matrix.arch == 'x86_64' - run: arch -x86_64 /usr/local/bin/brew install -v dylibbundler - - - name: Install dylibbundler ARM64 - if: matrix.arch == 'arm64' - run: brew install -v dylibbundler - - - name: Verify and link x86_64 packages - if: matrix.arch == 'x86_64' - run: | - # Verify installations - arch -x86_64 /usr/local/bin/brew list pango - arch -x86_64 /usr/local/bin/brew list cairo - arch -x86_64 /usr/local/bin/brew list gdk-pixbuf - arch -x86_64 /usr/local/bin/brew list gtk4 - arch -x86_64 /usr/local/bin/brew list gtksourceview5 - arch -x86_64 /usr/local/bin/brew list libadwaita - - # Link packages individually with error handling - for package in pango cairo gdk-pixbuf gtk4 gtksourceview5 libadwaita; do - arch -x86_64 /usr/local/bin/brew link --force $package || true - done - - - name: Install ARM64 dependencies - if: matrix.arch == 'arm64' - run: | - brew install pkg-config gtk4 pango cairo gdk-pixbuf at-spi2-core graphene libadwaita gtksourceview5 || true - brew upgrade pkg-config gtk4 pango cairo gdk-pixbuf at-spi2-core graphene libadwaita gtksourceview5 || true - - - name: Finalize ARM64 setup - if: matrix.arch == 'arm64' + - name: Run macOS Build Script run: | - echo "PKG_CONFIG_PATH=/opt/homebrew/lib/pkgconfig" >> $GITHUB_ENV - echo "PKG_CONFIG_ALLOW_CROSS=1" >> $GITHUB_ENV - - name: Add target ${{ matrix.target }} - run: rustup target add ${{ matrix.target }} - - name: Build + if [ "${{ matrix.arch }}" = "x86_64" ]; then + eval "$(/usr/local/bin/brew shellenv)" + echo "Homebrew prefix: $HOMEBREW_PREFIX" + export PKG_CONFIG_PATH="$HOMEBREW_PREFIX/lib/pkgconfig:$PKG_CONFIG_PATH" + chmod +x scripts/build_macos.sh + ./scripts/build_macos.sh --release --app-bundle --dmg --arch x86_64 + else + chmod +x scripts/build_macos.sh + ./scripts/build_macos.sh --release --app-bundle --dmg + fi env: PKG_CONFIG_ALLOW_CROSS: "1" - CFLAGS: "-I/usr/local/include -I/usr/local/include/gtk-4.0 -I/usr/local/include/glib-2.0 -I/usr/local/lib/glib-2.0/include" - LDFLAGS: "-L/usr/local/lib -framework Cocoa -framework Security" MACOSX_DEPLOYMENT_TARGET: "10.15" - PKG_CONFIG_SYSROOT_DIR: "" - PKG_CONFIG_PATH: "${{ env.PKG_CONFIG_PATH }}" - run: cargo build --release --target ${{ matrix.target }} - - name: Install glib-compile-resources - if: matrix.arch == 'x86_64' - run: arch -x86_64 /usr/local/bin/brew install glib || echo ERROR - - - name: Install glib-compile-resources ARM64 - if: matrix.arch == 'arm64' - run: brew install glib || echo ERROR - - name: Compile GResource - run: | - mkdir -p target/${{ matrix.target }}/release/ - glib-compile-resources --sourcedir reflection-app/src --target target/${{ matrix.target }}/release/reflection.gresource reflection-app/src/reflection.gresource.xml - - - name: Create App Bundle - run: | - mkdir -p Reflection.app/Contents/{MacOS,Resources}/share/reflection - cp target/${{ matrix.target }}/release/reflection Reflection.app/Contents/MacOS/ - cp target/${{ matrix.target }}/release/reflection.gresource Reflection.app/Contents/Resources/share/reflection/ - - # Create Info.plist - cat > Reflection.app/Contents/Info.plist << EOF - - - - - CFBundleExecutable - reflection - CFBundleIdentifier - org.p2panda.reflection - CFBundleName - Reflection - CFBundlePackageType - APPL - CFBundleShortVersionString - 0.1.0 - LSMinimumSystemVersion - 10.15 - CFBundleSupportedPlatforms - - MacOSX - - - - EOF - - # Bundle dependencies - - name: Bundle dependencies - run: | - dylibbundler -od -b -x Reflection.app/Contents/MacOS/reflection \ - -d Reflection.app/Contents/Frameworks/ \ - -p @executable_path/../Frameworks/ - # Create DMG - - name: Create DMG - run: hdiutil create -volname "Reflection" -srcfolder Reflection.app -ov -format UDZO reflection-${{ matrix.arch }}.dmg - name: Upload Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: reflection-macos-${{ matrix.arch }} - path: reflection-${{ matrix.arch }}.dmg + # Build script creates artifacts in the current directory + name: aardvark-macos-${{ matrix.arch }} + path: aardvark-${{ matrix.arch }}.dmg + - name: Smoke test the artifact env: RUST_BACKTRACE: "full" RUST_LOG: "debug" G_MESSAGES_DEBUG: "all" run: | - ./Reflection.app/Contents/MacOS/reflection & + ./Aardvark.app/Contents/MacOS/aardvark & PID=$! sleep 5 - echo Killing reflection - kill $PID || true + echo Killing aardvark + kill $PID || true \ No newline at end of file diff --git a/.gitignore b/.gitignore index f38fe0aa..8989f934 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,8 @@ target reflection-app/src/config.rs /subprojects/blueprint-compiler + +# Build artifacts +Reflection.app/ +install/ +reflection*.dmg diff --git a/Brewfile b/Brewfile new file mode 100644 index 00000000..dfc8e8ce --- /dev/null +++ b/Brewfile @@ -0,0 +1,32 @@ +# Build tools +brew "meson" +brew "ninja" +brew "pkg-config" + +# Rust toolchain (if not already installed) +brew "rustup-init" + +# Core GTK4 and GNOME dependencies +brew "gtk4" +brew "libadwaita" +brew "gtksourceview5" +brew "glib" + +# Graphics and text rendering +brew "cairo" +brew "pango" +brew "gdk-pixbuf" +brew "graphene" +brew "libspelling" + +# Accessibility +brew "at-spi2-core" + +# Desktop file utilities (for update-desktop-database) +brew "desktop-file-utils" + +# App bundling for macOS +brew "dylibbundler" + +# Optional: For creating DMG files +brew "create-dmg" \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 17ad293a..be7df348 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,15 +2,40 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "acto" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a026259da4f1a13b4af60cda453c392de64c58c12d239c560923e0382f42f2b9" +dependencies = [ + "parking_lot", + "pin-project-lite", + "rustc_version", + "smol_str", + "tokio", + "tracing", +] + [[package]] name = "aead" -version = "0.5.2" +version = "0.6.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +checksum = "ac8202ab55fcbf46ca829833f347a82a2a4ce0596f0304ac322c2d100030cd56" dependencies = [ "bytes", - "crypto-common", - "generic-array", + "crypto-common 0.2.0-rc.4", + "inout 0.2.1", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher 0.4.4", + "cpufeatures", ] [[package]] @@ -145,7 +170,7 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da0986d5b4f0802160191ad75f8d33ada000558757db3defb70299ca95d9fcbd" dependencies = [ - "async-fs", + "async-fs 2.2.0", "async-net", "enumflags2", "futures-channel", @@ -155,46 +180,17 @@ dependencies = [ "serde_repr", "tracing", "url", - "zbus", -] - -[[package]] -name = "asn1-rs" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" -dependencies = [ - "asn1-rs-derive", - "asn1-rs-impl", - "displaydoc", - "nom", - "num-traits", - "rusticata-macros", - "thiserror 1.0.69", - "time", + "zbus 5.12.0", ] [[package]] -name = "asn1-rs-derive" +name = "async-broadcast" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", - "synstructure", -] - -[[package]] -name = "asn1-rs-impl" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +checksum = "7c48ccdbf6ca6b121e0f586cbc0e73ae440e56c67c30fa0873b4e110d9c26d2b" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", + "event-listener 2.5.3", + "futures-core", ] [[package]] @@ -203,7 +199,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" dependencies = [ - "event-listener", + "event-listener 5.4.1", "event-listener-strategy", "futures-core", "pin-project-lite", @@ -221,6 +217,19 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-compat" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ba85bc55464dcbf728b56d97e119d673f4cf9062be330a9a26f3acf504a590" +dependencies = [ + "futures-core", + "futures-io", + "once_cell", + "pin-project-lite", + "tokio", +] + [[package]] name = "async-executor" version = "1.13.3" @@ -229,21 +238,53 @@ checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" dependencies = [ "async-task", "concurrent-queue", - "fastrand", - "futures-lite", + "fastrand 2.3.0", + "futures-lite 2.6.1", "pin-project-lite", "slab", ] +[[package]] +name = "async-fs" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "blocking", + "futures-lite 1.13.0", +] + [[package]] name = "async-fs" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8034a681df4aed8b8edbd7fbe472401ecf009251c8b40556b304567052e294c5" dependencies = [ - "async-lock", + "async-lock 3.4.1", "blocking", - "futures-lite", + "futures-lite 2.6.1", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite 1.13.0", + "log", + "parking", + "polling 2.8.0", + "rustix 0.37.28", + "slab", + "socket2 0.4.10", + "waker-fn", ] [[package]] @@ -256,21 +297,30 @@ dependencies = [ "cfg-if", "concurrent-queue", "futures-io", - "futures-lite", + "futures-lite 2.6.1", "parking", - "polling", - "rustix", + "polling 3.11.0", + "rustix 1.1.2", "slab", "windows-sys 0.61.2", ] +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener 2.5.3", +] + [[package]] name = "async-lock" version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" dependencies = [ - "event-listener", + "event-listener 5.4.1", "event-listener-strategy", "pin-project-lite", ] @@ -281,9 +331,26 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" dependencies = [ - "async-io", + "async-io 2.6.0", + "blocking", + "futures-lite 2.6.1", +] + +[[package]] +name = "async-process" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88" +dependencies = [ + "async-io 1.13.0", + "async-lock 2.8.0", + "async-signal", "blocking", - "futures-lite", + "cfg-if", + "event-listener 3.1.0", + "futures-lite 1.13.0", + "rustix 0.38.44", + "windows-sys 0.48.0", ] [[package]] @@ -293,15 +360,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" dependencies = [ "async-channel", - "async-io", - "async-lock", + "async-io 2.6.0", + "async-lock 3.4.1", "async-signal", "async-task", "blocking", "cfg-if", - "event-listener", - "futures-lite", - "rustix", + "event-listener 5.4.1", + "futures-lite 2.6.1", + "rustix 1.1.2", ] [[package]] @@ -321,13 +388,13 @@ version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" dependencies = [ - "async-io", - "async-lock", + "async-io 2.6.0", + "async-lock 3.4.1", "atomic-waker", "cfg-if", "futures-core", "futures-io", - "rustix", + "rustix 1.1.2", "signal-hook-registry", "slab", "windows-sys 0.61.2", @@ -350,6 +417,17 @@ dependencies = [ "syn 2.0.111", ] +[[package]] +name = "async_io_stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" +dependencies = [ + "futures", + "pharos", + "rustc_version", +] + [[package]] name = "atoi" version = "2.0.0" @@ -376,11 +454,12 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "attohttpc" -version = "0.24.1" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9a9bf8b79a749ee0b911b91b671cc2b6c670bdbc7e3dfd537576ddc94bb2a2" +checksum = "16e2cdb6d5ed835199484bb92bb8b3edd526effe995c61732580439c1a67e2e9" dependencies = [ - "http 0.2.12", + "base64 0.22.1", + "http", "log", "url", ] @@ -397,16 +476,16 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cffb0e931875b666fc4fcb20fee52e9bbd1ef836fd9e9e04ec21555f9f85f7ef" dependencies = [ - "fastrand", + "fastrand 2.3.0", "gloo-timers", "tokio", ] [[package]] name = "base16ct" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +checksum = "d8b59d472eab27ade8d770dcb11da7201c11234bef9f82ce7aa517be028d462b" [[package]] name = "base32" @@ -414,6 +493,12 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "022dfe9eb35f19ebbcb51e0b40a5ab759f46ad60cadf7297e0bd085afb50e076" +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "base64" version = "0.22.1" @@ -422,9 +507,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" +checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a" [[package]] name = "bitflags" @@ -478,6 +563,25 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96eb4cdd6cf1b31d671e9efe75c5d1ec614776856cefbe109ca373554a6d514f" +dependencies = [ + "hybrid-array", + "zeroize", +] + +[[package]] +name = "block-padding" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array", +] + [[package]] name = "blocking" version = "1.6.2" @@ -487,15 +591,32 @@ dependencies = [ "async-channel", "async-task", "futures-io", - "futures-lite", + "futures-lite 2.6.1", "piper", ] [[package]] -name = "bounded-integer" -version = "0.5.8" +name = "bon" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97493a391b4b18ee918675fb8663e53646fd09321c58b46afa04e8ce2499c869" +dependencies = [ + "bon-macros", + "rustversion", +] + +[[package]] +name = "bon-macros" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "102dbef1187b1893e6dfe05a774e79fd52265f49f214f6879c8ff49f52c8188b" +checksum = "2a2af3eac944c12cdf4423eab70d310da0a8e5851a18ffb192c0a5e3f7ae1663" +dependencies = [ + "darling", + "ident_case", + "proc-macro2", + "quote", + "syn 2.0.111", +] [[package]] name = "bumpalo" @@ -520,9 +641,9 @@ dependencies = [ [[package]] name = "cairo-rs" -version = "0.21.2" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfe4354df4da648870e363387679081f8f9fc538ec8b55901e3740c6a0ef81b1" +checksum = "b01fe135c0bd16afe262b6dea349bd5ea30e6de50708cec639aae7c5c14cc7e4" dependencies = [ "bitflags 2.10.0", "cairo-sys-rs", @@ -532,20 +653,29 @@ dependencies = [ [[package]] name = "cairo-sys-rs" -version = "0.21.2" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47d6c3300c7103eb8e4de07591003511aa25664438f8c6fc317a3a9902c103f8" +checksum = "06c28280c6b12055b5e39e4554271ae4e6630b27c0da9148c4cf6485fc6d245c" dependencies = [ "glib-sys", "libc", "system-deps", ] +[[package]] +name = "cbc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +dependencies = [ + "cipher 0.4.4", +] + [[package]] name = "cc" -version = "1.2.48" +version = "1.2.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c481bdbf0ed3b892f6f806287d72acd515b352a4ec27a208489b8c1bc839633a" +checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215" dependencies = [ "find-msvc-tools", "shlex", @@ -581,13 +711,14 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chacha20" -version = "0.9.1" +version = "0.10.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +checksum = "9bd162f2b8af3e0639d83f28a637e4e55657b7a74508dba5a9bf4da523d5c9e9" dependencies = [ "cfg-if", - "cipher", + "cipher 0.5.0-rc.1", "cpufeatures", + "zeroize", ] [[package]] @@ -637,8 +768,19 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "crypto-common", - "inout", + "crypto-common 0.1.7", + "inout 0.1.4", +] + +[[package]] +name = "cipher" +version = "0.5.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e12a13eb01ded5d32ee9658d94f553a19e804204f2dc811df69ab4d9e0cb8c7" +dependencies = [ + "block-buffer 0.11.0", + "crypto-common 0.2.0-rc.4", + "inout 0.2.1", "zeroize", ] @@ -682,12 +824,27 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const-oid" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dabb6555f92fb9ee4140454eb5dcd14c7960e1225c6d1a6cc361f032947713e" + [[package]] name = "constant_time_eq" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "cordyceps" version = "0.3.4" @@ -800,20 +957,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", - "rand_core 0.6.4", "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.0-rc.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8235645834fbc6832939736ce2f2d08192652269e11010a6240f61b908a1c6" +dependencies = [ + "hybrid-array", + "rand_core 0.9.3", +] + [[package]] name = "crypto_box" -version = "0.9.1" +version = "0.10.0-pre.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16182b4f39a82ec8a6851155cc4c0cda3065bb1db33651726a29e1951de0f009" +checksum = "2bda4de3e070830cf3a27a394de135b6709aefcc54d1e16f2f029271254a6ed9" dependencies = [ "aead", "chacha20", "crypto_secretbox", - "curve25519-dalek", + "curve25519-dalek 5.0.0-pre.1", "salsa20", "serdect", "subtle", @@ -822,14 +988,14 @@ dependencies = [ [[package]] name = "crypto_secretbox" -version = "0.1.1" +version = "0.2.0-pre.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d6cf87adf719ddf43a805e92c6870a531aedda35ff640442cbaf8674e141e1" +checksum = "54532aae6546084a52cef855593daf9555945719eeeda9974150e0def854873e" dependencies = [ "aead", "chacha20", - "cipher", - "generic-array", + "cipher 0.5.0-rc.1", + "hybrid-array", "poly1305", "salsa20", "subtle", @@ -845,9 +1011,25 @@ dependencies = [ "cfg-if", "cpufeatures", "curve25519-dalek-derive", - "digest", - "fiat-crypto", - "rand_core 0.6.4", + "digest 0.10.7", + "fiat-crypto 0.2.9", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek" +version = "5.0.0-pre.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f9200d1d13637f15a6acb71e758f64624048d85b31a5fdbfd8eca1e2687d0b7" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.11.0-rc.3", + "fiat-crypto 0.3.0", + "rand_core 0.9.3", "rustc_version", "serde", "subtle", @@ -900,6 +1082,20 @@ dependencies = [ "syn 2.0.111", ] +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "data-encoding" version = "2.9.0" @@ -912,44 +1108,40 @@ version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ - "const-oid", - "der_derive", - "pem-rfc7468", + "const-oid 0.9.6", + "pem-rfc7468 0.7.0", "zeroize", ] [[package]] -name = "der-parser" -version = "9.0.0" +name = "der" +version = "0.8.0-rc.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" +checksum = "02c1d73e9668ea6b6a28172aa55f3ebec38507131ce179051c8033b5c6037653" dependencies = [ - "asn1-rs", - "displaydoc", - "nom", - "num-bigint", - "num-traits", - "rusticata-macros", + "const-oid 0.10.1", + "pem-rfc7468 1.0.0", + "zeroize", ] [[package]] -name = "der_derive" -version = "0.7.3" +name = "deranged" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", + "powerfmt", ] [[package]] -name = "deranged" -version = "0.5.5" +name = "derivative" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "powerfmt", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] @@ -969,7 +1161,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" dependencies = [ - "derive_more-impl", + "derive_more-impl 1.0.0", +] + +[[package]] +name = "derive_more" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10b768e943bed7bf2cab53df09f4bc34bfd217cdb57d971e769874c9a6710618" +dependencies = [ + "derive_more-impl 2.1.0", ] [[package]] @@ -984,6 +1185,20 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "derive_more-impl" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d286bfdaf75e988b4a78e013ecd79c581e06399ab53fbacd2d916c2f904f30b" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.111", + "unicode-xid", +] + [[package]] name = "diatomic-waker" version = "0.2.3" @@ -1002,12 +1217,23 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", + "block-buffer 0.10.4", + "const-oid 0.9.6", + "crypto-common 0.1.7", "subtle", ] +[[package]] +name = "digest" +version = "0.11.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac89f8a64533a9b0eaa73a68e424db0fb1fd6271c74cc0125336a05f090568d" +dependencies = [ + "block-buffer 0.11.0", + "const-oid 0.10.1", + "crypto-common 0.2.0-rc.4", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -1045,15 +1271,31 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + [[package]] name = "ed25519" version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ - "pkcs8", + "pkcs8 0.10.2", + "signature 2.2.0", +] + +[[package]] +name = "ed25519" +version = "3.0.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "594435fe09e345ee388e4e8422072ff7dfeca8729389fbd997b3f5504c44cd47" +dependencies = [ + "pkcs8 0.11.0-rc.8", "serde", - "signature", + "signature 3.0.0-rc.5", ] [[package]] @@ -1062,17 +1304,33 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" dependencies = [ - "curve25519-dalek", - "ed25519", + "curve25519-dalek 4.1.3", + "ed25519 2.2.3", "rand_core 0.6.4", "serde", - "sha2", + "sha2 0.10.9", "subtle", "zeroize", ] [[package]] -name = "either" +name = "ed25519-dalek" +version = "3.0.0-pre.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad207ed88a133091f83224265eac21109930db09bedcad05d5252f2af2de20a1" +dependencies = [ + "curve25519-dalek 5.0.0-pre.1", + "ed25519 3.0.0-rc.2", + "rand_core 0.9.3", + "serde", + "sha2 0.11.0-rc.2", + "signature 3.0.0-rc.5", + "subtle", + "zeroize", +] + +[[package]] +name = "either" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" @@ -1188,21 +1446,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" -[[package]] -name = "erased-serde" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c138974f9d5e7fe373eb04df7cae98833802ae4b11c24ac7039a21d5af4b26c" -dependencies = [ - "serde", -] - -[[package]] -name = "erased_set" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a02a5d186d7bf1cb21f1f95e1a9cfa5c1f2dcd803a47aad454423ceec13525c5" - [[package]] name = "errno" version = "0.3.14" @@ -1224,6 +1467,23 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + [[package]] name = "event-listener" version = "5.4.1" @@ -1241,15 +1501,18 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "event-listener", + "event-listener 5.4.1", "pin-project-lite", ] [[package]] -name = "fallible-iterator" -version = "0.3.0" +name = "fastrand" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] [[package]] name = "fastrand" @@ -1263,13 +1526,19 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +[[package]] +name = "fiat-crypto" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24" + [[package]] name = "field-offset" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" dependencies = [ - "memoffset", + "memoffset 0.9.1", "rustc_version", ] @@ -1293,7 +1562,6 @@ checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" dependencies = [ "futures-core", "futures-sink", - "nanorand", "spin 0.9.8", ] @@ -1309,6 +1577,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "foreign-types" version = "0.3.2" @@ -1386,7 +1660,7 @@ dependencies = [ "fixedbitset", "futures-buffered", "futures-core", - "futures-lite", + "futures-lite 2.6.1", "pin-project", "slab", "smallvec", @@ -1426,13 +1700,28 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + [[package]] name = "futures-lite" version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" dependencies = [ - "fastrand", + "fastrand 2.3.0", "futures-core", "futures-io", "parking", @@ -1482,9 +1771,9 @@ dependencies = [ [[package]] name = "gdk-pixbuf" -version = "0.21.2" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a3c64459f569154f37616fc28923bfac490d4aaa134aaf5eca58a2c0c13050f" +checksum = "debb0d39e3cdd84626edfd54d6e4a6ba2da9a0ef2e796e691c4e9f8646fda00c" dependencies = [ "gdk-pixbuf-sys", "gio", @@ -1494,9 +1783,9 @@ dependencies = [ [[package]] name = "gdk-pixbuf-sys" -version = "0.21.2" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3854ef7a6a8b8f3b4013a01d5f9cb0d1794ec4e810c6cb4e2cc6d980f1baf724" +checksum = "bd95ad50b9a3d2551e25dd4f6892aff0b772fe5372d84514e9d0583af60a0ce7" dependencies = [ "gio-sys", "glib-sys", @@ -1507,9 +1796,9 @@ dependencies = [ [[package]] name = "gdk4" -version = "0.10.1" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7e292649dc26e3440c508a00f42ab39156008320dd6e962d63eaf626ba4d7f0" +checksum = "756564212bbe4a4ce05d88ffbd2582581ac6003832d0d32822d0825cca84bfbf" dependencies = [ "cairo-rs", "gdk-pixbuf", @@ -1522,9 +1811,9 @@ dependencies = [ [[package]] name = "gdk4-sys" -version = "0.10.1" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f3174fa4f1e0bf2a7e04469b65db8f4d1db89a6f5cdc57727b14e97ce438cf" +checksum = "a6d4e5b3ccf591826a4adcc83f5f57b4e59d1925cb4bf620b0d645f79498b034" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -1559,7 +1848,6 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", - "zeroize", ] [[package]] @@ -1625,9 +1913,9 @@ dependencies = [ [[package]] name = "gio" -version = "0.21.4" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daeff3dd716d1ba91850b976b76a1c2d28f99ef6c1602cd8fdaa8fab8017fd9c" +checksum = "c5ff48bf600c68b476e61dc6b7c762f2f4eb91deef66583ba8bb815c30b5811a" dependencies = [ "futures-channel", "futures-core", @@ -1642,9 +1930,9 @@ dependencies = [ [[package]] name = "gio-sys" -version = "0.21.2" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "171ed2f6dd927abbe108cfd9eebff2052c335013f5879d55bab0dc1dee19b706" +checksum = "0071fe88dba8e40086c8ff9bbb62622999f49628344b1d1bf490a48a29d80f22" dependencies = [ "glib-sys", "gobject-sys", @@ -1655,9 +1943,9 @@ dependencies = [ [[package]] name = "glib" -version = "0.21.4" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9dbecb1c33e483a98be4acfea2ab369e1c28f517c6eadb674537409c25c4b2" +checksum = "16de123c2e6c90ce3b573b7330de19be649080ec612033d397d72da265f1bd8b" dependencies = [ "bitflags 2.10.0", "futures-channel", @@ -1676,12 +1964,12 @@ dependencies = [ [[package]] name = "glib-macros" -version = "0.21.4" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "880e524e0085f3546cfb38532b2c202c0d64741d9977a6e4aa24704bfc9f19fb" +checksum = "cf59b675301228a696fe01c3073974643365080a76cc3ed5bc2cbc466ad87f17" dependencies = [ "heck 0.5.0", - "proc-macro-crate", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", "syn 2.0.111", @@ -1689,20 +1977,14 @@ dependencies = [ [[package]] name = "glib-sys" -version = "0.21.2" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d09d3d0fddf7239521674e57b0465dfbd844632fec54f059f7f56112e3f927e1" +checksum = "2d95e1a3a19ae464a7286e14af9a90683c64d70c02532d88d87ce95056af3e6c" dependencies = [ "libc", "system-deps", ] -[[package]] -name = "glob" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" - [[package]] name = "gloo-timers" version = "0.3.0" @@ -1717,9 +1999,9 @@ dependencies = [ [[package]] name = "gobject-sys" -version = "0.21.2" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "538e41d8776173ec107e7b0f2aceced60abc368d7e1d81c1f0e2ecd35f59080d" +checksum = "2dca35da0d19a18f4575f3cb99fe1c9e029a2941af5662f326f738a21edaf294" dependencies = [ "glib-sys", "libc", @@ -1728,9 +2010,9 @@ dependencies = [ [[package]] name = "graphene-rs" -version = "0.21.2" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7749aaf5d3b955bf3bfce39e3423705878a666b561384134da0e7786a45ddc3" +checksum = "2730030ac9db663fd8bfe1e7093742c1cafb92db9c315c9417c29032341fe2f9" dependencies = [ "glib", "graphene-sys", @@ -1739,9 +2021,9 @@ dependencies = [ [[package]] name = "graphene-sys" -version = "0.21.2" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "250abaee850a90a276509890a78029c356173f9573412bded5f155b0e41fa568" +checksum = "915e32091ea9ad241e4b044af62b7351c2d68aeb24f489a0d7f37a0fc484fd93" dependencies = [ "glib-sys", "libc", @@ -1751,9 +2033,9 @@ dependencies = [ [[package]] name = "gsk4" -version = "0.10.1" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6687e9f92ca89c000c376400cfaf7914d099413d72fdf4f84a25775a0b1fb2d" +checksum = "e755de9d8c5896c5beaa028b89e1969d067f1b9bf1511384ede971f5983aa153" dependencies = [ "cairo-rs", "gdk4", @@ -1766,9 +2048,9 @@ dependencies = [ [[package]] name = "gsk4-sys" -version = "0.10.1" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e76bcf64d9c4846f19651f45b400cc0c9c4c17b651849da520f3d77c6988c52" +checksum = "7ce91472391146f482065f1041876d8f869057b195b95399414caa163d72f4f7" dependencies = [ "cairo-sys-rs", "gdk4-sys", @@ -1782,9 +2064,9 @@ dependencies = [ [[package]] name = "gtk4" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58ea71795b91a0725b0e926e72e3d209d920ce60166e3a8f9f4dd46f287fee87" +checksum = "acb21d53cfc6f7bfaf43549731c43b67ca47d87348d81c8cfc4dcdd44828e1a4" dependencies = [ "cairo-rs", "field-offset", @@ -1803,11 +2085,11 @@ dependencies = [ [[package]] name = "gtk4-macros" -version = "0.10.1" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "821160b4f17e7e4ed748818c23682d0a46bed04c287dbaac54dd4869d2c5e06a" +checksum = "3ccfb5a14a3d941244815d5f8101fa12d4577b59cc47245778d8d907b0003e42" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", "syn 2.0.111", @@ -1815,9 +2097,9 @@ dependencies = [ [[package]] name = "gtk4-sys" -version = "0.10.1" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d274cbaf7d9aa55b7aff78cb21b43299d64e514e1300671469b66f691cc5a011" +checksum = "842577fe5a1ee15d166cd3afe804ce0cab6173bc789ca32e21308834f20088dd" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -1843,7 +2125,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.4.0", + "http", "indexmap", "slab", "tokio", @@ -1880,6 +2162,12 @@ dependencies = [ "byteorder", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "hashbrown" version = "0.15.5" @@ -1888,7 +2176,7 @@ checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.1.5", ] [[package]] @@ -1896,6 +2184,11 @@ name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] [[package]] name = "hashlink" @@ -1952,6 +2245,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + [[package]] name = "hermit-abi" version = "0.5.2" @@ -1974,20 +2273,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8a6fe56c0038198998a6f217ca4e7ef3a5e51f46163bd6dd60b5c71ca6c6502" dependencies = [ "async-trait", + "bytes", "cfg-if", "data-encoding", "enum-as-inner 0.6.1", "futures-channel", "futures-io", "futures-util", + "h2", + "http", "idna", "ipnet", "once_cell", "rand 0.9.2", "ring", + "rustls", "thiserror 2.0.17", "tinyvec", "tokio", + "tokio-rustls", "tracing", "url", ] @@ -2007,9 +2311,11 @@ dependencies = [ "parking_lot", "rand 0.9.2", "resolv-conf", + "rustls", "smallvec", "thiserror 2.0.17", "tokio", + "tokio-rustls", "tracing", ] @@ -2028,25 +2334,9 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", -] - -[[package]] -name = "hmac-sha1" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b05da5b9e5d4720bfb691eebb2b9d42da3570745da71eac8a1f5bb7e59aab88" -dependencies = [ - "hmac", - "sha1", + "digest 0.10.7", ] -[[package]] -name = "hmac-sha256" -version = "1.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad6880c8d4a9ebf39c6e8b77007ce223f646a4d21ce29d99f70cb16420545425" - [[package]] name = "home" version = "0.5.12" @@ -2056,23 +2346,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "hostname-validator" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f558a64ac9af88b5ba400d99b579451af0d39c6d360980045b91aac966d705e2" - -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - [[package]] name = "http" version = "1.4.0" @@ -2090,7 +2363,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.4.0", + "http", ] [[package]] @@ -2101,7 +2374,7 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.4.0", + "http", "http-body", "pin-project-lite", ] @@ -2118,6 +2391,16 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "hybrid-array" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f471e0a81b2f90ffc0cb2f951ae04da57de8baa46fa99112b062a5173a5088d0" +dependencies = [ + "typenum", + "zeroize", +] + [[package]] name = "hyper" version = "1.8.1" @@ -2129,7 +2412,7 @@ dependencies = [ "futures-channel", "futures-core", "h2", - "http 1.4.0", + "http", "http-body", "httparse", "httpdate", @@ -2147,7 +2430,7 @@ version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "http 1.4.0", + "http", "hyper", "hyper-util", "rustls", @@ -2155,21 +2438,21 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots 1.0.4", + "webpki-roots", ] [[package]] name = "hyper-util" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56" +checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "futures-channel", "futures-core", "futures-util", - "http 1.4.0", + "http", "http-body", "hyper", "ipnet", @@ -2254,9 +2537,9 @@ checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ "icu_collections", "icu_locale_core", @@ -2268,9 +2551,9 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" [[package]] name = "icu_provider" @@ -2316,20 +2599,20 @@ dependencies = [ [[package]] name = "igd-next" -version = "0.15.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76b0d7d4541def58a37bf8efc559683f21edce7c82f0d866c93ac21f7e098f93" +checksum = "516893339c97f6011282d5825ac94fc1c7aad5cad26bdc2d0cee068c0bf97f97" dependencies = [ "async-trait", "attohttpc", "bytes", "futures", - "http 1.4.0", + "http", "http-body-util", "hyper", "hyper-util", "log", - "rand 0.8.5", + "rand 0.9.2", "tokio", "url", "xmltree", @@ -2366,9 +2649,19 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ + "block-padding", "generic-array", ] +[[package]] +name = "inout" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7357b6e7aa75618c7864ebd0634b115a7218b0615f4cb1df33ac3eca23943d4" +dependencies = [ + "hybrid-array", +] + [[package]] name = "instant" version = "0.1.13" @@ -2381,6 +2674,17 @@ dependencies = [ "web-sys", ] +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "ipconfig" version = "0.3.2" @@ -2411,25 +2715,22 @@ dependencies = [ [[package]] name = "iroh" -version = "0.34.1" +version = "0.95.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37432887a6836e7a832fccb121b5f0ee6cd953c506f99b0278bdbedf8dee0e88" +checksum = "2374ba3cdaac152dc6ada92d971f7328e6408286faab3b7350842b2ebbed4789" dependencies = [ "aead", - "anyhow", - "atomic-waker", "backon", "bytes", "cfg_aliases", - "concurrent-queue", "crypto_box", "data-encoding", - "der", - "derive_more", - "ed25519-dalek", + "derive_more 2.1.0", + "ed25519-dalek 3.0.0-pre.1", "futures-util", + "getrandom 0.3.4", "hickory-resolver", - "http 1.4.0", + "http", "igd-next", "instant", "iroh-base", @@ -2438,24 +2739,25 @@ dependencies = [ "iroh-quinn-proto", "iroh-quinn-udp", "iroh-relay", + "n0-error", "n0-future", + "n0-watcher", "netdev", "netwatch", "pin-project", "pkarr", + "pkcs8 0.11.0-rc.8", "portmapper", - "rand 0.8.5", - "rcgen", + "rand 0.9.2", "reqwest", - "ring", "rustls", - "rustls-webpki 0.102.8", + "rustls-pki-types", + "rustls-platform-verifier", + "rustls-webpki", "serde", "smallvec", - "strum", - "stun-rs", - "surge-ping", - "thiserror 2.0.17", + "strum 0.27.2", + "swarm-discovery", "time", "tokio", "tokio-stream", @@ -2463,67 +2765,53 @@ dependencies = [ "tracing", "url", "wasm-bindgen-futures", - "webpki-roots 0.26.11", - "x509-parser", + "webpki-roots", "z32", ] [[package]] name = "iroh-base" -version = "0.34.1" +version = "0.95.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cd952d9e25e521d6aeb5b79f2fe32a0245da36aae3569e50f6010b38a5f0923" +checksum = "25a8c5fb1cc65589f0d7ab44269a76f615a8c4458356952c9b0ef1c93ea45ff8" dependencies = [ - "curve25519-dalek", + "curve25519-dalek 5.0.0-pre.1", "data-encoding", - "derive_more", - "ed25519-dalek", - "postcard", - "rand_core 0.6.4", + "derive_more 2.1.0", + "ed25519-dalek 3.0.0-pre.1", + "n0-error", + "rand_core 0.9.3", "serde", - "thiserror 2.0.17", "url", -] - -[[package]] -name = "iroh-blake3" -version = "1.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efbba31f40a650f58fa28dd585a8ca76d8ae3ba63aacab4c8269004a0c803930" -dependencies = [ - "arrayref", - "arrayvec", - "cc", - "cfg-if", - "constant_time_eq", + "zeroize", + "zeroize_derive", ] [[package]] name = "iroh-gossip" -version = "0.34.1" +version = "0.95.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71a9d638618fb6a4dac68d59cb694774478ea039bc9afca4709e242726591be1" +checksum = "026dd31b487ec5e80ac0240f4eb70cd6c0a2800f6ef44beca5329443c194bb22" dependencies = [ - "anyhow", - "async-channel", + "blake3", "bytes", - "derive_more", - "ed25519-dalek", + "data-encoding", + "derive_more 2.1.0", + "ed25519-dalek 3.0.0-pre.1", "futures-concurrency", - "futures-lite", + "futures-lite 2.6.1", "futures-util", "hex", "indexmap", "iroh", - "iroh-blake3", + "iroh-base", "iroh-metrics", + "irpc", + "n0-error", "n0-future", "postcard", - "rand 0.8.5", - "rand_core 0.6.4", + "rand 0.9.2", "serde", - "serde-error", - "thiserror 2.0.17", "tokio", "tokio-util", "tracing", @@ -2531,26 +2819,39 @@ dependencies = [ [[package]] name = "iroh-metrics" -version = "0.32.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0f7cd1ffe3b152a5f4f4c1880e01e07d96001f20e02cc143cb7842987c616b3" +checksum = "79e3381da7c93c12d353230c74bba26131d1c8bf3a4d8af0fec041546454582e" dependencies = [ - "erased_set", + "iroh-metrics-derive", + "itoa", + "n0-error", + "postcard", + "ryu", "serde", - "struct_iterable", - "thiserror 2.0.17", "tracing", ] +[[package]] +name = "iroh-metrics-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e12bd0763fd16062f5cc5e8db15dd52d26e75a8af4c7fb57ccee3589b344b8" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "iroh-quinn" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76c6245c9ed906506ab9185e8d7f64857129aee4f935e899f398a3bd3b70338d" +checksum = "0cde160ebee7aabede6ae887460cd303c8b809054224815addf1469d54a6fcf7" dependencies = [ "bytes", "cfg_aliases", - "futures-io", "iroh-quinn-proto", "iroh-quinn-udp", "pin-project-lite", @@ -2576,7 +2877,6 @@ dependencies = [ "rustc-hash", "rustls", "rustls-pki-types", - "rustls-platform-verifier", "slab", "thiserror 2.0.17", "tinyvec", @@ -2600,17 +2900,18 @@ dependencies = [ [[package]] name = "iroh-relay" -version = "0.34.1" +version = "0.95.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40d2d7b50d999922791c6c14c25e13f55711e182618cb387bafa0896ffe0b930" +checksum = "43fbdf2aeffa7d6ede1a31f6570866c2199b1cee96a0b563994623795d1bac2c" dependencies = [ - "anyhow", + "blake3", "bytes", "cfg_aliases", "data-encoding", - "derive_more", + "derive_more 2.1.0", + "getrandom 0.3.4", "hickory-resolver", - "http 1.4.0", + "http", "http-body-util", "hyper", "hyper-util", @@ -2618,30 +2919,59 @@ dependencies = [ "iroh-metrics", "iroh-quinn", "iroh-quinn-proto", - "lru", + "lru 0.16.2", + "n0-error", "n0-future", "num_enum", "pin-project", "pkarr", "postcard", - "rand 0.8.5", + "rand 0.9.2", "reqwest", "rustls", - "rustls-webpki 0.102.8", + "rustls-pki-types", "serde", - "strum", - "stun-rs", - "thiserror 2.0.17", + "serde_bytes", + "sha1 0.11.0-rc.2", + "strum 0.27.2", "tokio", "tokio-rustls", - "tokio-tungstenite-wasm", "tokio-util", + "tokio-websockets", "tracing", "url", - "webpki-roots 0.26.11", + "webpki-roots", + "ws_stream_wasm", "z32", ] +[[package]] +name = "irpc" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bee97aaa18387c4f0aae61058195dc9f9dea3e41c0e272973fe3e9bf611563d" +dependencies = [ + "futures-util", + "irpc-derive", + "n0-error", + "n0-future", + "serde", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "irpc-derive" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58148196d2230183c9679431ac99b57e172000326d664e8456fa2cd27af6505a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -2704,6 +3034,20 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "keyring" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "363387f0019d714aa60cc30ab4fe501a747f4c08fc58f069dd14be971bd495a0" +dependencies = [ + "byteorder", + "lazy_static", + "linux-keyutils", + "secret-service", + "security-framework 2.11.1", + "windows-sys 0.52.0", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -2752,9 +3096,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.177" +version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "libm" @@ -2813,6 +3157,28 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "linux-keyutils" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "761e49ec5fd8a5a463f9b84e877c373d888935b71c6be78f3767fe2ae6bed18e" +dependencies = [ + "bitflags 2.10.0", + "libc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + [[package]] name = "linux-raw-sys" version = "0.11.0" @@ -2855,9 +3221,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.28" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "loom" @@ -3005,11 +3371,17 @@ dependencies = [ [[package]] name = "lru" -version = "0.12.5" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465" + +[[package]] +name = "lru" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96051b46fc183dc9cd4a223960ef37b9af631b55191852a8274bfef064cda20f" dependencies = [ - "hashbrown 0.15.5", + "hashbrown 0.16.1", ] [[package]] @@ -3052,7 +3424,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ "cfg-if", - "digest", + "digest 0.10.7", ] [[package]] @@ -3069,24 +3441,27 @@ checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "memoffset" -version = "0.9.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" dependencies = [ "autocfg", ] [[package]] -name = "minimal-lexical" -version = "0.2.1" +name = "memoffset" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] [[package]] name = "mio" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", "wasi", @@ -3111,16 +3486,38 @@ dependencies = [ "uuid", ] +[[package]] +name = "n0-error" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7d5969a2f40e9d9ed121a789c415f4114ac2b28e5731c080bdefee217d3b3fb" +dependencies = [ + "anyhow", + "n0-error-macros", + "spez", +] + +[[package]] +name = "n0-error-macros" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a6908df844696d9af91c7c3950d50e52d67df327d02a95367f95bbf177d6556" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "n0-future" -version = "0.1.3" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb0e5d99e681ab3c938842b96fcb41bf8a7bb4bfdb11ccbd653a7e83e06c794" +checksum = "8c0709ac8235ce13b82bc4d180ee3c42364b90c1a8a628c3422d991d75a728b5" dependencies = [ "cfg_aliases", - "derive_more", + "derive_more 1.0.0", "futures-buffered", - "futures-lite", + "futures-lite 2.6.1", "futures-util", "js-sys", "pin-project", @@ -3133,87 +3530,59 @@ dependencies = [ ] [[package]] -name = "nanorand" -version = "0.7.0" +name = "n0-watcher" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +checksum = "38acf13c1ddafc60eb7316d52213467f8ccb70b6f02b65e7d97f7799b1f50be4" dependencies = [ - "getrandom 0.2.16", + "derive_more 2.1.0", + "n0-error", + "n0-future", ] [[package]] name = "netdev" -version = "0.31.0" +version = "0.38.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f901362e84cd407be6f8cd9d3a46bccf09136b095792785401ea7d283c79b91d" +checksum = "67ab878b4c90faf36dab10ea51d48c69ae9019bcca47c048a7c9b273d5d7a823" dependencies = [ "dlopen2", "ipnet", "libc", "netlink-packet-core", - "netlink-packet-route 0.17.1", + "netlink-packet-route", "netlink-sys", "once_cell", "system-configuration", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "netlink-packet-core" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72724faf704479d67b388da142b186f916188505e7e0b26719019c525882eda4" -dependencies = [ - "anyhow", - "byteorder", - "netlink-packet-utils", -] - -[[package]] -name = "netlink-packet-route" -version = "0.17.1" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053998cea5a306971f88580d0829e90f270f940befd7cf928da179d4187a5a66" +checksum = "3463cbb78394cb0141e2c926b93fc2197e473394b761986eca3b9da2c63ae0f4" dependencies = [ - "anyhow", - "bitflags 1.3.2", - "byteorder", - "libc", - "netlink-packet-core", - "netlink-packet-utils", + "paste", ] [[package]] name = "netlink-packet-route" -version = "0.19.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74c171cd77b4ee8c7708da746ce392440cb7bcf618d122ec9ecc607b12938bf4" +checksum = "3ec2f5b6839be2a19d7fa5aab5bc444380f6311c2b693551cb80f45caaa7b5ef" dependencies = [ - "anyhow", - "byteorder", + "bitflags 2.10.0", "libc", "log", "netlink-packet-core", - "netlink-packet-utils", -] - -[[package]] -name = "netlink-packet-utils" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34" -dependencies = [ - "anyhow", - "byteorder", - "paste", - "thiserror 1.0.69", ] [[package]] name = "netlink-proto" -version = "0.11.5" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72452e012c2f8d612410d89eea01e2d9b56205274abb35d53f60200b2ec41d60" +checksum = "b65d130ee111430e47eed7896ea43ca693c387f097dd97376bffafbf25812128" dependencies = [ "bytes", "futures", @@ -3238,34 +3607,35 @@ dependencies = [ [[package]] name = "netwatch" -version = "0.4.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7879c2cfdf30d92f2be89efa3169b3d78107e3ab7f7b9a37157782569314e1" +checksum = "26f2acd376ef48b6c326abf3ba23c449e0cb8aa5c2511d189dd8a8a3bfac889b" dependencies = [ "atomic-waker", "bytes", "cfg_aliases", - "derive_more", + "derive_more 2.1.0", "iroh-quinn-udp", "js-sys", "libc", + "n0-error", "n0-future", + "n0-watcher", "netdev", "netlink-packet-core", - "netlink-packet-route 0.19.0", + "netlink-packet-route", + "netlink-proto", "netlink-sys", - "rtnetlink 0.13.1", - "rtnetlink 0.14.1", + "pin-project-lite", "serde", - "socket2 0.5.10", - "thiserror 2.0.17", + "socket2 0.6.1", "time", "tokio", "tokio-util", "tracing", "web-sys", - "windows 0.59.0", - "windows-result 0.3.4", + "windows 0.62.2", + "windows-result 0.4.1", "wmi", ] @@ -3278,17 +3648,7 @@ dependencies = [ "bitflags 1.3.2", "cfg-if", "libc", -] - -[[package]] -name = "nix" -version = "0.27.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" -dependencies = [ - "bitflags 2.10.0", - "cfg-if", - "libc", + "memoffset 0.7.1", ] [[package]] @@ -3301,31 +3661,30 @@ dependencies = [ "cfg-if", "cfg_aliases", "libc", - "memoffset", + "memoffset 0.9.1", ] [[package]] -name = "no-std-net" -version = "0.6.0" +name = "nonmax" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" +checksum = "610a5acd306ec67f907abe5567859a3c693fb9886eb1f012ab8f2a47bef3db51" [[package]] -name = "nom" -version = "7.1.3" +name = "ntimestamp" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +checksum = "c50f94c405726d3e0095e89e72f75ce7f6587b94a8bd8dc8054b73f65c0fd68c" dependencies = [ - "memchr", - "minimal-lexical", + "base32", + "document-features", + "getrandom 0.2.16", + "httpdate", + "js-sys", + "once_cell", + "serde", ] -[[package]] -name = "nonmax" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "610a5acd306ec67f907abe5567859a3c693fb9886eb1f012ab8f2a47bef3db51" - [[package]] name = "nu-ansi-term" version = "0.50.3" @@ -3448,7 +3807,7 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", "syn 2.0.111", @@ -3483,15 +3842,6 @@ dependencies = [ "objc", ] -[[package]] -name = "oid-registry" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" -dependencies = [ - "asn1-rs", -] - [[package]] name = "once_cell" version = "1.21.3" @@ -3515,12 +3865,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3299dd401feaf1d45afd8fd1c0586f10fcfb22f244bb9afa942cec73503b89d" dependencies = [ "ashpd", - "async-fs", - "async-io", - "async-lock", + "async-fs 2.2.0", + "async-io 2.6.0", + "async-lock 3.4.1", "blocking", "endi", - "futures-lite", + "futures-lite 2.6.1", "futures-util", "getrandom 0.3.4", "num", @@ -3529,18 +3879,12 @@ dependencies = [ "rand 0.9.2", "serde", "tracing", - "zbus", - "zbus_macros", + "zbus 5.12.0", + "zbus_macros 5.12.0", "zeroize", - "zvariant", + "zvariant 5.8.0", ] -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - [[package]] name = "openssl" version = "0.10.75" @@ -3598,11 +3942,11 @@ dependencies = [ [[package]] name = "p2panda-core" version = "0.4.0" -source = "git+https://github.com/p2panda/p2panda#61ea7101eb4af6e672666e35c2b750d8d9621f4a" +source = "git+https://github.com/p2panda/p2panda?rev=365f5848a3014a69a4b692153bdf77e59b43eb81#365f5848a3014a69a4b692153bdf77e59b43eb81" dependencies = [ "blake3", "ciborium", - "ed25519-dalek", + "ed25519-dalek 2.2.0", "hex", "rand 0.8.5", "serde", @@ -3611,44 +3955,36 @@ dependencies = [ ] [[package]] -name = "p2panda-discovery" +name = "p2panda-discovery-next" version = "0.4.0" -source = "git+https://github.com/p2panda/p2panda#61ea7101eb4af6e672666e35c2b750d8d9621f4a" +source = "git+https://github.com/p2panda/p2panda?rev=365f5848a3014a69a4b692153bdf77e59b43eb81#365f5848a3014a69a4b692153bdf77e59b43eb81" dependencies = [ - "anyhow", - "base32", - "flume", - "futures-buffered", - "futures-lite", - "hickory-proto", - "iroh", - "iroh-base", - "netwatch", - "socket2 0.5.10", + "futures-util", + "rand 0.9.2", + "rand_chacha 0.9.0", + "serde", + "thiserror 2.0.17", "tokio", - "tokio-util", - "tracing", ] [[package]] -name = "p2panda-net" +name = "p2panda-net-next" version = "0.4.0" -source = "git+https://github.com/p2panda/p2panda#61ea7101eb4af6e672666e35c2b750d8d9621f4a" +source = "git+https://github.com/p2panda/p2panda?rev=365f5848a3014a69a4b692153bdf77e59b43eb81#365f5848a3014a69a4b692153bdf77e59b43eb81" dependencies = [ - "anyhow", - "async-trait", "ciborium", - "futures-lite", + "futures-channel", "futures-util", + "hex", "iroh", "iroh-base", "iroh-gossip", - "iroh-quinn", - "netwatch", "p2panda-core", - "p2panda-discovery", - "p2panda-sync", - "rand 0.8.5", + "p2panda-discovery-next", + "p2panda-sync-next", + "ractor", + "rand 0.9.2", + "rand_chacha 0.9.0", "serde", "thiserror 2.0.17", "tokio", @@ -3660,7 +3996,7 @@ dependencies = [ [[package]] name = "p2panda-store" version = "0.4.0" -source = "git+https://github.com/p2panda/p2panda#61ea7101eb4af6e672666e35c2b750d8d9621f4a" +source = "git+https://github.com/p2panda/p2panda?rev=365f5848a3014a69a4b692153bdf77e59b43eb81#365f5848a3014a69a4b692153bdf77e59b43eb81" dependencies = [ "ciborium", "hex", @@ -3673,7 +4009,7 @@ dependencies = [ [[package]] name = "p2panda-stream" version = "0.4.0" -source = "git+https://github.com/p2panda/p2panda#61ea7101eb4af6e672666e35c2b750d8d9621f4a" +source = "git+https://github.com/p2panda/p2panda?rev=365f5848a3014a69a4b692153bdf77e59b43eb81#365f5848a3014a69a4b692153bdf77e59b43eb81" dependencies = [ "ciborium", "futures-channel", @@ -3686,25 +4022,26 @@ dependencies = [ ] [[package]] -name = "p2panda-sync" +name = "p2panda-sync-next" version = "0.4.0" -source = "git+https://github.com/p2panda/p2panda#61ea7101eb4af6e672666e35c2b750d8d9621f4a" +source = "git+https://github.com/p2panda/p2panda?rev=365f5848a3014a69a4b692153bdf77e59b43eb81#365f5848a3014a69a4b692153bdf77e59b43eb81" dependencies = [ - "async-trait", "futures", + "futures-util", "p2panda-core", "p2panda-store", "serde", "thiserror 2.0.17", "tokio", - "tokio-util", + "tokio-stream", + "tracing", ] [[package]] name = "pango" -version = "0.21.3" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e37b7a678e18c2e9f2485f7e39b7b2dac99590d5ddef08a7f56eae38a145402e" +checksum = "52d1d85e2078077a065bb7fc072783d5bcd4e51b379f22d67107d0a16937eb69" dependencies = [ "gio", "glib", @@ -3714,9 +4051,9 @@ dependencies = [ [[package]] name = "pango-sys" -version = "0.21.2" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f5daf21da43fba9f2a0092da0eebeb77637c23552bccaf58f791c518009c94" +checksum = "b4f06627d36ed5ff303d2df65211fc2e52ba5b17bf18dd80ff3d9628d6e06cfd" dependencies = [ "glib-sys", "gobject-sys", @@ -3760,20 +4097,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] -name = "pem" -version = "3.0.6" +name = "pem-rfc7468" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" dependencies = [ - "base64", - "serde_core", + "base64ct", ] [[package]] name = "pem-rfc7468" -version = "0.7.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +checksum = "a6305423e0e7738146434843d1694d621cce767262b2a86910beab705e4493d9" dependencies = [ "base64ct", ] @@ -3785,46 +4121,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] -name = "pest" -version = "2.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbcfd20a6d4eeba40179f05735784ad32bdaef05ce8e8af05f180d45bb3e7e22" -dependencies = [ - "memchr", - "ucd-trie", -] - -[[package]] -name = "pest_derive" -version = "2.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51f72981ade67b1ca6adc26ec221be9f463f2b5839c7508998daa17c23d94d7f" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee9efd8cdb50d719a80088b76f81aec7c41ed6d522ee750178f83883d271625" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn 2.0.111", -] - -[[package]] -name = "pest_meta" -version = "2.8.4" +name = "pharos" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf1d70880e76bdc13ba52eafa6239ce793d85c8e43896507e43dd8984ff05b82" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" dependencies = [ - "pest", - "sha2", + "futures", + "rustc_version", ] [[package]] @@ -3866,32 +4169,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ "atomic-waker", - "fastrand", + "fastrand 2.3.0", "futures-io", ] [[package]] name = "pkarr" -version = "2.3.1" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92eff194c72f00f3076855b413ad2d940e3a6e307fa697e5c7733e738341aed4" +checksum = "792c1328860f6874e90e3b387b4929819cc7783a6bd5a4728e918706eb436a48" dependencies = [ + "async-compat", + "base32", "bytes", + "cfg_aliases", "document-features", - "ed25519-dalek", - "flume", - "futures", - "js-sys", - "lru", + "dyn-clone", + "ed25519-dalek 3.0.0-pre.1", + "futures-buffered", + "futures-lite 2.6.1", + "getrandom 0.3.4", + "log", + "lru 0.13.0", + "ntimestamp", + "reqwest", "self_cell", + "serde", + "sha1_smol", "simple-dns", "thiserror 2.0.17", + "tokio", "tracing", - "ureq", - "wasm-bindgen", + "url", "wasm-bindgen-futures", - "web-sys", - "z32", ] [[package]] @@ -3900,9 +4210,9 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" dependencies = [ - "der", - "pkcs8", - "spki", + "der 0.7.10", + "pkcs8 0.10.2", + "spki 0.7.3", ] [[package]] @@ -3911,56 +4221,40 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "der", - "spki", + "der 0.7.10", + "spki 0.7.3", ] [[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - -[[package]] -name = "pnet_base" -version = "0.34.0" +name = "pkcs8" +version = "0.11.0-rc.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4cf6fb3ab38b68d01ab2aea03ed3d1132b4868fa4e06285f29f16da01c5f4c" +checksum = "77089aec8290d0b7bb01b671b091095cf1937670725af4fd73d47249f03b12c0" dependencies = [ - "no-std-net", + "der 0.8.0-rc.10", + "spki 0.8.0-rc.4", ] [[package]] -name = "pnet_macros" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688b17499eee04a0408aca0aa5cba5fc86401d7216de8a63fdf7a4c227871804" -dependencies = [ - "proc-macro2", - "quote", - "regex", - "syn 2.0.111", -] - -[[package]] -name = "pnet_macros_support" -version = "0.34.0" +name = "pkg-config" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eea925b72f4bd37f8eab0f221bbe4c78b63498350c983ffa9dd4bcde7e030f56" -dependencies = [ - "pnet_base", -] +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] -name = "pnet_packet" -version = "0.34.0" +name = "polling" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a005825396b7fe7a38a8e288dbc342d5034dac80c15212436424fef8ea90ba" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" dependencies = [ - "glob", - "pnet_base", - "pnet_macros", - "pnet_macros_support", + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.48.0", ] [[package]] @@ -3971,20 +4265,19 @@ checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" dependencies = [ "cfg-if", "concurrent-queue", - "hermit-abi", + "hermit-abi 0.5.2", "pin-project-lite", - "rustix", + "rustix 1.1.2", "windows-sys 0.61.2", ] [[package]] name = "poly1305" -version = "0.8.0" +version = "0.9.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +checksum = "fb78a635f75d76d856374961deecf61031c0b6f928c83dc9c0924ab6c019c298" dependencies = [ "cpufeatures", - "opaque-debug", "universal-hash", ] @@ -3996,28 +4289,30 @@ checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "portmapper" -version = "0.4.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "247dcb75747c53cc433d6d8963a064187eec4a676ba13ea33143f1c9100e754f" +checksum = "7b575f975dcf03e258b0c7ab3f81497d7124f508884c37da66a7314aa2a8d467" dependencies = [ - "base64", + "base64 0.22.1", "bytes", - "derive_more", - "futures-lite", + "derive_more 2.1.0", + "futures-lite 2.6.1", "futures-util", + "hyper-util", "igd-next", "iroh-metrics", "libc", + "n0-error", "netwatch", "num_enum", - "rand 0.8.5", + "rand 0.9.2", "serde", "smallvec", - "socket2 0.5.10", - "thiserror 2.0.17", + "socket2 0.6.1", "time", "tokio", "tokio-util", + "tower-layer", "tracing", "url", ] @@ -4064,45 +4359,11 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "precis-core" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c2e7b31f132e0c6f8682cfb7bf4a5340dbe925b7986618d0826a56dfe0c8e56" -dependencies = [ - "precis-tools", - "ucd-parse", - "unicode-normalization", -] - -[[package]] -name = "precis-profiles" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e2768890a47af73a032af9f0cedbddce3c9d06cf8de201d5b8f2436ded7674" -dependencies = [ - "lazy_static", - "precis-core", - "precis-tools", - "unicode-normalization", -] - -[[package]] -name = "precis-tools" -version = "0.1.9" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cc1eb2d5887ac7bfd2c0b745764db89edb84b856e4214e204ef48ef96d10c4a" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "lazy_static", - "regex", - "ucd-parse", + "zerocopy", ] [[package]] @@ -4115,13 +4376,23 @@ dependencies = [ "yansi", ] +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + [[package]] name = "proc-macro-crate" version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit", + "toml_edit 0.23.9", ] [[package]] @@ -4209,22 +4480,32 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "quoted-string-parser" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc75379cdb451d001f1cb667a9f74e8b355e9df84cc5193513cbe62b96fc5e9" -dependencies = [ - "pest", - "pest_derive", -] - [[package]] name = "r-efi" version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "ractor" +version = "0.15.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9500e0be6f12a0539cb1154d654ef2e888bf8529164e54aff4a097baad5bb001" +dependencies = [ + "bon", + "dashmap", + "futures", + "js-sys", + "once_cell", + "strum 0.26.3", + "tokio", + "tokio_with_wasm", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-time", +] + [[package]] name = "rand" version = "0.8.5" @@ -4293,19 +4574,6 @@ dependencies = [ "rand_core 0.6.4", ] -[[package]] -name = "rcgen" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2" -dependencies = [ - "pem", - "ring", - "rustls-pki-types", - "time", - "yasna", -] - [[package]] name = "redox_syscall" version = "0.5.18" @@ -4320,10 +4588,12 @@ name = "reflection" version = "0.1.0" dependencies = [ "ashpd", + "base64 0.21.7", "formatx", "futures-util", "gettext-rs", "gtk4", + "keyring", "libadwaita", "libspelling", "oo7", @@ -4357,16 +4627,17 @@ dependencies = [ name = "reflection-node" version = "0.1.0" dependencies = [ - "async-trait", "chrono", "ciborium", "hex", + "iroh", "p2panda-core", - "p2panda-discovery", - "p2panda-net", + "p2panda-discovery-next", + "p2panda-net-next", "p2panda-store", "p2panda-stream", - "p2panda-sync", + "p2panda-sync-next", + "rand_chacha 0.9.0", "serde", "serde_bytes", "sqlx", @@ -4400,12 +4671,6 @@ dependencies = [ "regex-syntax", ] -[[package]] -name = "regex-lite" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da" - [[package]] name = "regex-syntax" version = "0.8.8" @@ -4414,15 +4679,15 @@ checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "reqwest" -version = "0.12.24" +version = "0.12.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" +checksum = "b6eff9328d40131d43bd911d42d79eb6a47312002a4daefc9e37f17e74a7701a" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "futures-core", "futures-util", - "http 1.4.0", + "http", "http-body", "http-body-util", "hyper", @@ -4450,7 +4715,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 1.0.4", + "webpki-roots", ] [[package]] @@ -4479,56 +4744,20 @@ version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40a0376c50d0358279d9d643e4bf7b7be212f1f4ff1da9070a7b54d22ef75c88" dependencies = [ - "const-oid", - "digest", + "const-oid 0.9.6", + "digest 0.10.7", "num-bigint-dig", "num-integer", "num-traits", "pkcs1", - "pkcs8", + "pkcs8 0.10.2", "rand_core 0.6.4", - "signature", - "spki", + "signature 2.2.0", + "spki 0.7.3", "subtle", "zeroize", ] -[[package]] -name = "rtnetlink" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a552eb82d19f38c3beed3f786bd23aa434ceb9ac43ab44419ca6d67a7e186c0" -dependencies = [ - "futures", - "log", - "netlink-packet-core", - "netlink-packet-route 0.17.1", - "netlink-packet-utils", - "netlink-proto", - "netlink-sys", - "nix 0.26.4", - "thiserror 1.0.69", - "tokio", -] - -[[package]] -name = "rtnetlink" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b684475344d8df1859ddb2d395dd3dac4f8f3422a1aa0725993cb375fc5caba5" -dependencies = [ - "futures", - "log", - "netlink-packet-core", - "netlink-packet-route 0.19.0", - "netlink-packet-utils", - "netlink-proto", - "netlink-sys", - "nix 0.27.1", - "thiserror 1.0.69", - "tokio", -] - [[package]] name = "rustc-hash" version = "2.1.1" @@ -4545,12 +4774,30 @@ dependencies = [ ] [[package]] -name = "rusticata-macros" -version = "4.1.0" +name = "rustix" +version = "0.37.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "519165d378b97752ca44bbe15047d5d3409e875f39327546b42ac81d7e18c1b6" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "nom", + "bitflags 2.10.0", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", ] [[package]] @@ -4562,7 +4809,7 @@ dependencies = [ "bitflags 2.10.0", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.11.0", "windows-sys 0.61.2", ] @@ -4576,7 +4823,7 @@ dependencies = [ "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.103.8", + "rustls-webpki", "subtle", "zeroize", ] @@ -4590,7 +4837,7 @@ dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework", + "security-framework 3.5.1", ] [[package]] @@ -4617,8 +4864,8 @@ dependencies = [ "rustls", "rustls-native-certs", "rustls-platform-verifier-android", - "rustls-webpki 0.103.8", - "security-framework", + "rustls-webpki", + "security-framework 3.5.1", "security-framework-sys", "webpki-root-certs 0.26.11", "windows-sys 0.59.0", @@ -4630,17 +4877,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" -[[package]] -name = "rustls-webpki" -version = "0.102.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - [[package]] name = "rustls-webpki" version = "0.103.8" @@ -4666,11 +4902,12 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "salsa20" -version = "0.10.2" +version = "0.11.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +checksum = "d3ff3b81c8a6e381bc1673768141383f9328048a60edddcfc752a8291a138443" dependencies = [ - "cipher", + "cfg-if", + "cipher 0.5.0-rc.1", ] [[package]] @@ -4703,6 +4940,38 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "secret-service" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5204d39df37f06d1944935232fd2dfe05008def7ca599bf28c0800366c8a8f9" +dependencies = [ + "aes", + "cbc", + "futures-util", + "generic-array", + "hkdf", + "num", + "once_cell", + "rand 0.8.5", + "serde", + "sha2 0.10.9", + "zbus 3.15.2", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.10.0", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + [[package]] name = "security-framework" version = "3.5.1" @@ -4754,15 +5023,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde-error" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342110fb7a5d801060c885da03bf91bfa7c7ca936deafcc64bb6706375605d47" -dependencies = [ - "serde", -] - [[package]] name = "serde_bytes" version = "0.11.19" @@ -4865,9 +5125,9 @@ dependencies = [ [[package]] name = "serdect" -version = "0.2.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" +checksum = "d3ef0e35b322ddfaecbc60f34ab448e157e48531288ee49fafbb053696b8ffe2" dependencies = [ "base16ct", "serde", @@ -4881,9 +5141,26 @@ checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha1" +version = "0.11.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e046edf639aa2e7afb285589e5405de2ef7e61d4b0ac1e30256e3eab911af9" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.11.0-rc.3", ] +[[package]] +name = "sha1_smol" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" + [[package]] name = "sha2" version = "0.10.9" @@ -4892,7 +5169,18 @@ checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1e3878ab0f98e35b2df35fe53201d088299b41a6bb63e3e34dada2ac4abd924" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.11.0-rc.3", ] [[package]] @@ -4925,10 +5213,22 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest", + "digest 0.10.7", "rand_core 0.6.4", ] +[[package]] +name = "signature" +version = "3.0.0-rc.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0251c9d6468f4ba853b6352b190fb7c1e405087779917c238445eb03993826" + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "simple-dns" version = "0.9.3" @@ -4963,6 +5263,22 @@ dependencies = [ "serde", ] +[[package]] +name = "smol_str" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad6c857cbab2627dcf01ec85a623ca4e7dcb5691cbaa3d7fb7653671f0d09c9" + +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "socket2" version = "0.5.10" @@ -5018,6 +5334,17 @@ dependencies = [ "system-deps", ] +[[package]] +name = "spez" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87e960f4dca2788eeb86bbdde8dd246be8948790b7618d656e68f9b720a86e8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "spin" version = "0.9.8" @@ -5040,7 +5367,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", - "der", + "der 0.7.10", +] + +[[package]] +name = "spki" +version = "0.8.0-rc.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8baeff88f34ed0691978ec34440140e1572b68c7dd4a495fd14a3dc1944daa80" +dependencies = [ + "base64ct", + "der 0.8.0-rc.10", ] [[package]] @@ -5062,13 +5399,13 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "chrono", "crc", "crossbeam-queue", "either", - "event-listener", + "event-listener 5.4.1", "futures-core", "futures-intrusive", "futures-io", @@ -5082,7 +5419,7 @@ dependencies = [ "percent-encoding", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "smallvec", "thiserror 2.0.17", "tokio", @@ -5119,7 +5456,7 @@ dependencies = [ "quote", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "sqlx-core", "sqlx-mysql", "sqlx-postgres", @@ -5136,13 +5473,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" dependencies = [ "atoi", - "base64", + "base64 0.22.1", "bitflags 2.10.0", "byteorder", "bytes", "chrono", "crc", - "digest", + "digest 0.10.7", "dotenvy", "either", "futures-channel", @@ -5162,8 +5499,8 @@ dependencies = [ "rand 0.8.5", "rsa", "serde", - "sha1", - "sha2", + "sha1 0.10.6", + "sha2 0.10.9", "smallvec", "sqlx-core", "stringprep", @@ -5179,7 +5516,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" dependencies = [ "atoi", - "base64", + "base64 0.22.1", "bitflags 2.10.0", "byteorder", "chrono", @@ -5201,7 +5538,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "smallvec", "sqlx-core", "stringprep", @@ -5265,41 +5602,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] -name = "struct_iterable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "849a064c6470a650b72e41fa6c057879b68f804d113af92900f27574828e7712" -dependencies = [ - "struct_iterable_derive", - "struct_iterable_internal", -] - -[[package]] -name = "struct_iterable_derive" -version = "0.1.0" +name = "strum" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb939ce88a43ea4e9d012f2f6b4cc789deb2db9d47bad697952a85d6978662c" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" dependencies = [ - "erased-serde", - "proc-macro2", - "quote", - "struct_iterable_internal", - "syn 2.0.111", + "strum_macros 0.26.4", ] -[[package]] -name = "struct_iterable_internal" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9426b2a0c03e6cc2ea8dbc0168dbbf943f88755e409fb91bcb8f6a268305f4a" - [[package]] name = "strum" -version = "0.26.3" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" dependencies = [ - "strum_macros", + "strum_macros 0.27.2", ] [[package]] @@ -5316,27 +5633,15 @@ dependencies = [ ] [[package]] -name = "stun-rs" -version = "0.1.11" +name = "strum_macros" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb921f10397d5669e1af6455e9e2d367bf1f9cebcd6b1dd1dc50e19f6a9ac2ac" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" dependencies = [ - "base64", - "bounded-integer", - "byteorder", - "crc", - "enumflags2", - "fallible-iterator", - "hmac-sha1", - "hmac-sha256", - "hostname-validator", - "lazy_static", - "md5", - "paste", - "precis-core", - "precis-profiles", - "quoted-string-parser", - "rand 0.9.2", + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.111", ] [[package]] @@ -5346,17 +5651,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] -name = "surge-ping" -version = "0.8.3" +name = "swarm-discovery" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f27ea7b4bfbd3d9980392cd9f90e4158212a5f775fa58e9b85216a0bf739067d" +checksum = "790d8444f7db1e88f70aed3234cab8e42c48e05360bfc86ca7dce0d9a5d95d26" dependencies = [ - "hex", - "parking_lot", - "pnet_packet", + "acto", + "hickory-proto", "rand 0.9.2", - "socket2 0.6.1", - "thiserror 1.0.69", + "socket2 0.5.10", + "thiserror 2.0.17", "tokio", "tracing", ] @@ -5461,10 +5765,10 @@ version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ - "fastrand", + "fastrand 2.3.0", "getrandom 0.3.4", "once_cell", - "rustix", + "rustix 1.1.2", "windows-sys 0.61.2", ] @@ -5546,13 +5850,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", - "itoa", "js-sys", "num-conv", "powerfmt", "serde", "time-core", - "time-macros", ] [[package]] @@ -5561,16 +5863,6 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" -[[package]] -name = "time-macros" -version = "0.2.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" -dependencies = [ - "num-conv", - "time-core", -] - [[package]] name = "tinystr" version = "0.8.2" @@ -5609,6 +5901,7 @@ dependencies = [ "signal-hook-registry", "socket2 0.6.1", "tokio-macros", + "tracing", "windows-sys 0.61.2", ] @@ -5646,48 +5939,64 @@ dependencies = [ ] [[package]] -name = "tokio-tungstenite" -version = "0.24.0" +name = "tokio-util" +version = "0.7.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" +checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" dependencies = [ + "bytes", + "futures-core", + "futures-io", + "futures-sink", "futures-util", - "log", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-websockets" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1b6348ebfaaecd771cecb69e832961d277f59845d4220a584701f72728152b7" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-sink", + "getrandom 0.3.4", + "http", + "httparse", + "rand 0.9.2", + "ring", + "rustls-pki-types", + "simdutf8", "tokio", - "tungstenite", + "tokio-rustls", + "tokio-util", ] [[package]] -name = "tokio-tungstenite-wasm" -version = "0.4.0" +name = "tokio_with_wasm" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e21a5c399399c3db9f08d8297ac12b500e86bca82e930253fdc62eaf9c0de6ae" +checksum = "4dfba9b946459940fb564dcf576631074cdfb0bfe4c962acd4c31f0dca7897e6" dependencies = [ - "futures-channel", - "futures-util", - "http 1.4.0", - "httparse", "js-sys", - "thiserror 1.0.69", "tokio", - "tokio-tungstenite", + "tokio_with_wasm_proc", "wasm-bindgen", + "wasm-bindgen-futures", "web-sys", ] [[package]] -name = "tokio-util" -version = "0.7.17" +name = "tokio_with_wasm_proc" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" +checksum = "37e04c1865c281139e5ccf633cb9f76ffdaabeebfe53b703984cf82878e2aabb" dependencies = [ - "bytes", - "futures-core", - "futures-io", - "futures-sink", - "futures-util", - "pin-project-lite", - "tokio", + "quote", + "syn 2.0.111", ] [[package]] @@ -5699,12 +6008,18 @@ dependencies = [ "indexmap", "serde_core", "serde_spanned", - "toml_datetime", + "toml_datetime 0.7.3", "toml_parser", "toml_writer", - "winnow", + "winnow 0.7.14", ] +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" + [[package]] name = "toml_datetime" version = "0.7.3" @@ -5716,14 +6031,25 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.23.7" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap", + "toml_datetime 0.6.11", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.23.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" +checksum = "5d7cbc3b4b49633d57a0509303158ca50de80ae32c265093b24c414705807832" dependencies = [ "indexmap", - "toml_datetime", + "toml_datetime 0.7.3", "toml_parser", - "winnow", + "winnow 0.7.14", ] [[package]] @@ -5732,7 +6058,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" dependencies = [ - "winnow", + "winnow 0.7.14", ] [[package]] @@ -5758,14 +6084,14 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf146f99d442e8e68e585f5d798ccd3cad9a7835b917e09728880a862706456" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ "bitflags 2.10.0", "bytes", "futures-util", - "http 1.4.0", + "http", "http-body", "iri-string", "pin-project-lite", @@ -5865,24 +6191,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "tungstenite" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http 1.4.0", - "httparse", - "log", - "rand 0.8.5", - "sha1", - "thiserror 1.0.69", - "utf-8", -] - [[package]] name = "twox-hash" version = "2.1.2" @@ -5895,28 +6203,13 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" -[[package]] -name = "ucd-parse" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06ff81122fcbf4df4c1660b15f7e3336058e7aec14437c9f85c6b31a0f279b9" -dependencies = [ - "regex-lite", -] - -[[package]] -name = "ucd-trie" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" - [[package]] name = "uds_windows" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" dependencies = [ - "memoffset", + "memoffset 0.9.1", "tempfile", "winapi", ] @@ -5948,6 +6241,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + [[package]] name = "unicode-xid" version = "0.2.6" @@ -5956,11 +6255,11 @@ checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "universal-hash" -version = "0.5.1" +version = "0.6.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +checksum = "a55be643b40a21558f44806b53ee9319595bc7ca6896372e4e08e5d7d83c9cd6" dependencies = [ - "crypto-common", + "crypto-common 0.2.0-rc.4", "subtle", ] @@ -5970,21 +6269,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" -[[package]] -name = "ureq" -version = "2.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" -dependencies = [ - "base64", - "log", - "once_cell", - "rustls", - "rustls-pki-types", - "url", - "webpki-roots 0.26.11", -] - [[package]] name = "url" version = "2.5.7" @@ -5997,12 +6281,6 @@ dependencies = [ "serde", ] -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -6017,13 +6295,13 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.18.1" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" +checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" dependencies = [ "getrandom 0.3.4", "js-sys", - "serde", + "serde_core", "wasm-bindgen", ] @@ -6051,6 +6329,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "waker-fn" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" + [[package]] name = "walkdir" version = "2.5.0" @@ -6200,15 +6484,6 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "webpki-roots" -version = "0.26.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" -dependencies = [ - "webpki-roots 1.0.4", -] - [[package]] name = "webpki-roots" version = "1.0.4" @@ -6267,25 +6542,27 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.59.0" +version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f919aee0a93304be7f62e8e5027811bbba96bcb1de84d6618be56e43f8a32a1" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ - "windows-core 0.59.0", - "windows-targets 0.53.5", + "windows-collections 0.2.0", + "windows-core 0.61.2", + "windows-future 0.2.1", + "windows-link 0.1.3", + "windows-numerics 0.2.0", ] [[package]] name = "windows" -version = "0.61.3" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" dependencies = [ - "windows-collections", - "windows-core 0.61.2", - "windows-future", - "windows-link 0.1.3", - "windows-numerics", + "windows-collections 0.3.2", + "windows-core 0.62.2", + "windows-future 0.3.2", + "windows-numerics 0.3.1", ] [[package]] @@ -6298,16 +6575,12 @@ dependencies = [ ] [[package]] -name = "windows-core" -version = "0.59.0" +name = "windows-collections" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "810ce18ed2112484b0d4e15d022e5f598113e220c53e373fb31e67e21670c1ce" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" dependencies = [ - "windows-implement 0.59.0", - "windows-interface", - "windows-result 0.3.4", - "windows-strings 0.3.1", - "windows-targets 0.53.5", + "windows-core 0.62.2", ] [[package]] @@ -6316,7 +6589,7 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ - "windows-implement 0.60.2", + "windows-implement", "windows-interface", "windows-link 0.1.3", "windows-result 0.3.4", @@ -6329,7 +6602,7 @@ version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ - "windows-implement 0.60.2", + "windows-implement", "windows-interface", "windows-link 0.2.1", "windows-result 0.4.1", @@ -6344,18 +6617,18 @@ checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ "windows-core 0.61.2", "windows-link 0.1.3", - "windows-threading", + "windows-threading 0.1.0", ] [[package]] -name = "windows-implement" -version = "0.59.0" +name = "windows-future" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", + "windows-core 0.62.2", + "windows-link 0.2.1", + "windows-threading 0.2.1", ] [[package]] @@ -6402,6 +6675,16 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-numerics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" +dependencies = [ + "windows-core 0.62.2", + "windows-link 0.2.1", +] + [[package]] name = "windows-result" version = "0.3.4" @@ -6420,15 +6703,6 @@ dependencies = [ "windows-link 0.2.1", ] -[[package]] -name = "windows-strings" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" -dependencies = [ - "windows-link 0.1.3", -] - [[package]] name = "windows-strings" version = "0.4.2" @@ -6573,6 +6847,15 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-threading" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -6753,6 +7036,15 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + [[package]] name = "winnow" version = "0.7.14" @@ -6780,17 +7072,17 @@ checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "wmi" -version = "0.14.5" +version = "0.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7787dacdd8e71cbc104658aade4009300777f9b5fda6a75f19145fedb8a18e71" +checksum = "120d8c2b6a7c96c27bf4a7947fd7f02d73ca7f5958b8bd72a696e46cb5521ee6" dependencies = [ "chrono", "futures", "log", "serde", "thiserror 2.0.17", - "windows 0.59.0", - "windows-core 0.59.0", + "windows 0.62.2", + "windows-core 0.62.2", ] [[package]] @@ -6800,20 +7092,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] -name = "x509-parser" -version = "0.16.0" +name = "ws_stream_wasm" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" +checksum = "6c173014acad22e83f16403ee360115b38846fe754e735c5d9d3803fe70c6abc" dependencies = [ - "asn1-rs", - "data-encoding", - "der-parser", - "lazy_static", - "nom", - "oid-registry", - "rusticata-macros", - "thiserror 1.0.69", - "time", + "async_io_stream", + "futures", + "js-sys", + "log", + "pharos", + "rustc_version", + "send_wrapper", + "thiserror 2.0.17", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "xdg-home" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6" +dependencies = [ + "libc", + "windows-sys 0.59.0", ] [[package]] @@ -6843,15 +7147,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" -[[package]] -name = "yasna" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" -dependencies = [ - "time", -] - [[package]] name = "yoke" version = "0.8.1" @@ -6881,25 +7176,66 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2164e798d9e3d84ee2c91139ace54638059a3b23e361f5c11781c2c6459bde0f" +[[package]] +name = "zbus" +version = "3.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "675d170b632a6ad49804c8cf2105d7c31eddd3312555cffd4b740e08e97c25e6" +dependencies = [ + "async-broadcast 0.5.1", + "async-executor", + "async-fs 1.6.0", + "async-io 1.13.0", + "async-lock 2.8.0", + "async-process 1.8.1", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "byteorder", + "derivative", + "enumflags2", + "event-listener 2.5.3", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "nix 0.26.4", + "once_cell", + "ordered-stream", + "rand 0.8.5", + "serde", + "serde_repr", + "sha1 0.10.6", + "static_assertions", + "tracing", + "uds_windows", + "winapi", + "xdg-home", + "zbus_macros 3.15.2", + "zbus_names 2.6.1", + "zvariant 3.15.2", +] + [[package]] name = "zbus" version = "5.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b622b18155f7a93d1cd2dc8c01d2d6a44e08fb9ebb7b3f9e6ed101488bad6c91" dependencies = [ - "async-broadcast", + "async-broadcast 0.7.2", "async-executor", - "async-io", - "async-lock", - "async-process", + "async-io 2.6.0", + "async-lock 3.4.1", + "async-process 2.5.0", "async-recursion", "async-task", "async-trait", "blocking", "enumflags2", - "event-listener", + "event-listener 5.4.1", "futures-core", - "futures-lite", + "futures-lite 2.6.1", "hex", "nix 0.30.1", "ordered-stream", @@ -6909,10 +7245,24 @@ dependencies = [ "uds_windows", "uuid", "windows-sys 0.61.2", - "winnow", - "zbus_macros", - "zbus_names", - "zvariant", + "winnow 0.7.14", + "zbus_macros 5.12.0", + "zbus_names 4.2.0", + "zvariant 5.8.0", +] + +[[package]] +name = "zbus_macros" +version = "3.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7131497b0f887e8061b430c530240063d33bf9455fa34438f388a245da69e0a5" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "regex", + "syn 1.0.109", + "zvariant_utils 1.0.1", ] [[package]] @@ -6921,13 +7271,24 @@ version = "5.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cdb94821ca8a87ca9c298b5d1cbd80e2a8b67115d99f6e4551ac49e42b6a314" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", "syn 2.0.111", - "zbus_names", - "zvariant", - "zvariant_utils", + "zbus_names 4.2.0", + "zvariant 5.8.0", + "zvariant_utils 3.2.1", +] + +[[package]] +name = "zbus_names" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "437d738d3750bed6ca9b8d423ccc7a8eb284f6b1d6d4e225a0e4e6258d864c8d" +dependencies = [ + "serde", + "static_assertions", + "zvariant 3.15.2", ] [[package]] @@ -6938,8 +7299,8 @@ checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97" dependencies = [ "serde", "static_assertions", - "winnow", - "zvariant", + "winnow 0.7.14", + "zvariant 5.8.0", ] [[package]] @@ -7036,6 +7397,20 @@ dependencies = [ "syn 2.0.111", ] +[[package]] +name = "zvariant" +version = "3.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eef2be88ba09b358d3b58aca6e41cd853631d44787f319a1383ca83424fb2db" +dependencies = [ + "byteorder", + "enumflags2", + "libc", + "serde", + "static_assertions", + "zvariant_derive 3.15.2", +] + [[package]] name = "zvariant" version = "5.8.0" @@ -7046,9 +7421,22 @@ dependencies = [ "enumflags2", "serde", "url", - "winnow", - "zvariant_derive", - "zvariant_utils", + "winnow 0.7.14", + "zvariant_derive 5.8.0", + "zvariant_utils 3.2.1", +] + +[[package]] +name = "zvariant_derive" +version = "3.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37c24dc0bed72f5f90d1f8bb5b07228cbf63b3c6e9f82d82559d4bae666e7ed9" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", + "zvariant_utils 1.0.1", ] [[package]] @@ -7057,11 +7445,22 @@ version = "5.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da58575a1b2b20766513b1ec59d8e2e68db2745379f961f86650655e862d2006" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", "syn 2.0.111", - "zvariant_utils", + "zvariant_utils 3.2.1", +] + +[[package]] +name = "zvariant_utils" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7234f0d811589db492d16893e3f21e8e2fd282e6d01b0cddee310322062cc200" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] @@ -7074,5 +7473,5 @@ dependencies = [ "quote", "serde", "syn 2.0.111", - "winnow", + "winnow 0.7.14", ] diff --git a/README.md b/README.md index 4efe9428..9389efe9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

+

Reflection

Collaboratively take meeting notes, even when there's no internet

diff --git a/org.p2panda.reflection.json b/cx.modal.reflection.json similarity index 97% rename from org.p2panda.reflection.json rename to cx.modal.reflection.json index 79612f8a..055e434b 100644 --- a/org.p2panda.reflection.json +++ b/cx.modal.reflection.json @@ -1,5 +1,5 @@ { - "id" : "org.p2panda.reflection", + "id" : "cx.modal.reflection", "runtime" : "org.gnome.Platform", "runtime-version" : "49", "sdk" : "org.gnome.Sdk", diff --git a/meson.build b/meson.build index b03e07dc..ba76793b 100644 --- a/meson.build +++ b/meson.build @@ -7,7 +7,7 @@ project('reflection', 'rust', i18n = import('i18n') gnome = import('gnome') -application_id = 'org.p2panda.reflection' +application_id = 'cx.modal.reflection' pkgdatadir = get_option('prefix') / get_option('datadir') / meson.project_name() iconsdir = get_option('datadir') / 'icons' diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 00000000..1b03a140 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,4 @@ +option('macos_bundle', + type: 'boolean', + value: false, + description: 'Build for macOS app bundle with relative resource paths') \ No newline at end of file diff --git a/reflection-app/Cargo.toml b/reflection-app/Cargo.toml index a81bb8da..a1254d10 100644 --- a/reflection-app/Cargo.toml +++ b/reflection-app/Cargo.toml @@ -15,14 +15,8 @@ gtk = { version = "0.10", package = "gtk4", features = ["gnome_48", "v4_20", "bl sourceview = { package = "sourceview5", version = "0.10" } tracing = "0.1" tracing-subscriber = { version = "0.3.20", features = ["env-filter"] } -ashpd = { version = "0.12", default-features = false, features = ["tracing", "async-std"] } thiserror = { version = "2.0" } futures-util = "0.3" -oo7 = { version = "0.5", default-features = false, features = [ - "openssl_crypto", - "async-std", - "tracing", -] } libspelling = "0.4.1" formatx = "0.2.4" @@ -30,3 +24,15 @@ formatx = "0.2.4" package = "libadwaita" version = "0.8" features = ["v1_7"] + +[target.'cfg(target_os = "linux")'.dependencies] +oo7 = { version = "0.5", default-features = false, features = [ + "openssl_crypto", + "async-std", + "tracing", +] } +ashpd = { version = "0.12", default-features = false, features = ["tracing", "async-std"] } + +[target.'cfg(target_os = "macos")'.dependencies] +keyring = "2.0" +base64 = "0.21" diff --git a/reflection-app/data/org.p2panda.reflection.desktop.in b/reflection-app/data/cx.modal.reflection.desktop.in similarity index 84% rename from reflection-app/data/org.p2panda.reflection.desktop.in rename to reflection-app/data/cx.modal.reflection.desktop.in index 8f79accf..cdf59061 100644 --- a/reflection-app/data/org.p2panda.reflection.desktop.in +++ b/reflection-app/data/cx.modal.reflection.desktop.in @@ -1,7 +1,7 @@ [Desktop Entry] Name=reflection Exec=reflection -Icon=org.p2panda.reflection +Icon=cx.modal.reflection Terminal=false Type=Application Categories=Utility; diff --git a/reflection-app/data/org.p2panda.reflection.gschema.xml b/reflection-app/data/cx.modal.reflection.gschema.xml similarity index 60% rename from reflection-app/data/org.p2panda.reflection.gschema.xml rename to reflection-app/data/cx.modal.reflection.gschema.xml index f3a8d957..d3a14510 100644 --- a/reflection-app/data/org.p2panda.reflection.gschema.xml +++ b/reflection-app/data/cx.modal.reflection.gschema.xml @@ -1,5 +1,5 @@ - + diff --git a/reflection-app/data/org.p2panda.reflection.metainfo.xml.in b/reflection-app/data/cx.modal.reflection.metainfo.xml.in similarity index 97% rename from reflection-app/data/org.p2panda.reflection.metainfo.xml.in rename to reflection-app/data/cx.modal.reflection.metainfo.xml.in index ee94722d..71b02a82 100644 --- a/reflection-app/data/org.p2panda.reflection.metainfo.xml.in +++ b/reflection-app/data/cx.modal.reflection.metainfo.xml.in @@ -1,6 +1,6 @@ - org.p2panda.reflection + cx.modal.reflection CC0-1.0 GPL-3.0-or-later @@ -43,7 +43,7 @@ reflection - org.p2panda.reflection.desktop + cx.modal.reflection.desktop intense diff --git a/reflection-app/data/org.p2panda.reflection.service.in b/reflection-app/data/cx.modal.reflection.service.in similarity index 69% rename from reflection-app/data/org.p2panda.reflection.service.in rename to reflection-app/data/cx.modal.reflection.service.in index 0eb9ecc9..b4ba6295 100644 --- a/reflection-app/data/org.p2panda.reflection.service.in +++ b/reflection-app/data/cx.modal.reflection.service.in @@ -1,3 +1,3 @@ [D-BUS Service] -Name=org.p2panda.reflection +Name=cx.modal.reflection Exec=@bindir@/reflection --gapplication-service diff --git a/reflection-app/data/icons/org.p2panda.reflection-symbolic.svg b/reflection-app/data/icons/cx.modal.reflection-symbolic.svg similarity index 100% rename from reflection-app/data/icons/org.p2panda.reflection-symbolic.svg rename to reflection-app/data/icons/cx.modal.reflection-symbolic.svg diff --git a/reflection-app/data/icons/org.p2panda.reflection.Devel.svg b/reflection-app/data/icons/cx.modal.reflection.Devel.svg similarity index 100% rename from reflection-app/data/icons/org.p2panda.reflection.Devel.svg rename to reflection-app/data/icons/cx.modal.reflection.Devel.svg diff --git a/reflection-app/data/icons/org.p2panda.reflection.Source.svg b/reflection-app/data/icons/cx.modal.reflection.Source.svg similarity index 99% rename from reflection-app/data/icons/org.p2panda.reflection.Source.svg rename to reflection-app/data/icons/cx.modal.reflection.Source.svg index 66e79356..e7c152af 100644 --- a/reflection-app/data/icons/org.p2panda.reflection.Source.svg +++ b/reflection-app/data/icons/cx.modal.reflection.Source.svg @@ -10,7 +10,7 @@ id="svg11300" sodipodi:version="0.32" inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)" - sodipodi:docname="org.p2panda.Reflection.Source.svg" + sodipodi:docname="cx.modal.reflection.Source.svg" inkscape:output_extension="org.inkscape.output.svg.inkscape" version="1.0" style="display:inline;enable-background:new" diff --git a/reflection-app/data/icons/org.p2panda.reflection.svg b/reflection-app/data/icons/cx.modal.reflection.svg similarity index 100% rename from reflection-app/data/icons/org.p2panda.reflection.svg rename to reflection-app/data/icons/cx.modal.reflection.svg diff --git a/reflection-app/data/meson.build b/reflection-app/data/meson.build index d9d09e58..033cdaf3 100644 --- a/reflection-app/data/meson.build +++ b/reflection-app/data/meson.build @@ -1,6 +1,6 @@ desktop_file = i18n.merge_file( - input: 'org.p2panda.reflection.desktop.in', - output: 'org.p2panda.reflection.desktop', + input: 'cx.modal.reflection.desktop.in', + output: 'cx.modal.reflection.desktop', type: 'desktop', po_dir: '../po', install: true, @@ -13,8 +13,8 @@ if desktop_utils.found() endif appstream_file = i18n.merge_file( - input: 'org.p2panda.reflection.metainfo.xml.in', - output: 'org.p2panda.reflection.metainfo.xml', + input: 'cx.modal.reflection.metainfo.xml.in', + output: 'cx.modal.reflection.metainfo.xml', po_dir: '../po', install: true, install_dir: get_option('datadir') / 'metainfo' @@ -24,7 +24,7 @@ appstreamcli = find_program('appstreamcli', required: false, disabler: true) test('Validate appstream file', appstreamcli, args: ['validate', '--no-net', '--explain', appstream_file]) -install_data('org.p2panda.reflection.gschema.xml', +install_data('cx.modal.reflection.gschema.xml', install_dir: get_option('datadir') / 'glib-2.0' / 'schemas' ) @@ -37,8 +37,8 @@ test('Validate schema file', service_conf = configuration_data() service_conf.set('bindir', get_option('prefix') / get_option('bindir')) configure_file( - input: 'org.p2panda.reflection.service.in', - output: 'org.p2panda.reflection.service', + input: 'cx.modal.reflection.service.in', + output: 'cx.modal.reflection.service', configuration: service_conf, install_dir: get_option('datadir') / 'dbus-1' / 'services' ) diff --git a/reflection-app/data/resources/resources.gresource.xml b/reflection-app/data/resources/resources.gresource.xml index 50f24b64..e76528ea 100644 --- a/reflection-app/data/resources/resources.gresource.xml +++ b/reflection-app/data/resources/resources.gresource.xml @@ -1,6 +1,6 @@ - + icons/scalable/actions/about-symbolic.svg icons/scalable/actions/bluetooth-symbolic.svg icons/scalable/status/folder-symbolic.svg diff --git a/reflection-app/po/POTFILES.in b/reflection-app/po/POTFILES.in index 8200340c..b130fed6 100644 --- a/reflection-app/po/POTFILES.in +++ b/reflection-app/po/POTFILES.in @@ -1,8 +1,8 @@ # List of source files containing translatable strings. # Please keep this file sorted alphabetically. -data/org.p2panda.reflection.desktop.in -data/org.p2panda.reflection.metainfo.xml.in -data/org.p2panda.reflection.gschema.xml +data/cx.modal.reflection.desktop.in +data/cx.modal.reflection.metainfo.xml.in +data/cx.modal.reflection.gschema.xml src/application.rs src/components/zoom_level_selector.blp src/connection_popover/author_list.rs diff --git a/reflection-app/src/config.rs.in b/reflection-app/src/config.rs.in index 0e057e17..bcb5941e 100644 --- a/reflection-app/src/config.rs.in +++ b/reflection-app/src/config.rs.in @@ -2,6 +2,4 @@ pub const APP_ID: &str = @APP_ID@; pub const VERSION: &str = @VERSION@; pub const GETTEXT_PACKAGE: &str = @GETTEXT_PACKAGE@; pub const LOCALEDIR: &str = @LOCALEDIR@; -pub const PKGDATADIR: &str = @PKGDATADIR@; -pub const RESOURCES_FILE: &str = concat!(@PKGDATADIR@, "/resources.gresource"); -pub const UI_RESOURCES_FILE: &str = concat!(@PKGDATADIR@, "/ui-resources.gresource"); \ No newline at end of file +pub const PKGDATADIR: &str = @PKGDATADIR@; \ No newline at end of file diff --git a/reflection-app/src/landing_view/landing_view.blp b/reflection-app/src/landing_view/landing_view.blp index 0c617d84..2833cdc7 100644 --- a/reflection-app/src/landing_view/landing_view.blp +++ b/reflection-app/src/landing_view/landing_view.blp @@ -49,7 +49,7 @@ template $ReflectionLandingView: Adw.NavigationPage { StackPage { name: "no-documents"; child: Adw.StatusPage no-document-page { - icon-name: "org.p2panda.reflection-symbolic"; + icon-name: "cx.modal.reflection-symbolic"; title: _("Take Notes, Together"); child: Box { orientation: vertical; diff --git a/reflection-app/src/main.rs b/reflection-app/src/main.rs index d7d6314d..09484c82 100644 --- a/reflection-app/src/main.rs +++ b/reflection-app/src/main.rs @@ -36,6 +36,7 @@ mod window; use gettextrs::{bind_textdomain_codeset, bindtextdomain, textdomain}; use gtk::prelude::*; use gtk::{gio, glib}; +use std::path::PathBuf; use tracing::info; use tracing_subscriber::EnvFilter; use tracing_subscriber::prelude::*; @@ -50,23 +51,12 @@ pub use self::config::APP_ID; fn main() -> glib::ExitCode { setup_logging(); - - // Set up gettext translations - bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR).expect("Unable to bind the text domain"); - bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8") - .expect("Unable to set the text domain encoding"); - textdomain(GETTEXT_PACKAGE).expect("Unable to switch to the text domain"); - - // Load resources - let res = gio::Resource::load(RESOURCES_FILE).expect("Could not load gresource file"); - gio::resources_register(&res); - let ui_res = gio::Resource::load(UI_RESOURCES_FILE).expect("Could not load UI gresource file"); - gio::resources_register(&ui_res); + load_resources(); // Create a new GtkApplication. The application manages our main loop, // application windows, integration with the window manager/compositor, and // desktop features such as file opening and single-instance applications. - let app = ReflectionApplication::new("org.p2panda.reflection", &gio::ApplicationFlags::empty()); + let app = ReflectionApplication::new("cx.modal.reflection", &gio::ApplicationFlags::empty()); info!("Reflection ({})", APP_ID); info!("Version: {}", VERSION); @@ -86,3 +76,43 @@ fn setup_logging() { .try_init() .ok(); } + +fn load_resources() { + // Used for macOS app bundle + let mut base_bundle_path = + std::env::current_exe().expect("Failed to get current executable path."); + base_bundle_path.pop(); // -> Reflection.app/Contents/MacOS/ + base_bundle_path.pop(); // -> Reflection.app/Contents/ + + let local_dir_path = if cfg!(target_os = "macos") { + base_bundle_path.join(LOCALEDIR) + } else { + PathBuf::from(LOCALEDIR) + }; + + let resources_dir_path = if cfg!(target_os = "macos") { + base_bundle_path.join(PKGDATADIR) + } else { + PathBuf::from(PKGDATADIR) + }; + + bindtextdomain( + GETTEXT_PACKAGE, + local_dir_path + .to_str() + .expect("Locale path is not valid UTF-8"), + ) + .expect("Unable to bind the text domain"); + bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8") + .expect("Unable to set the text domain encoding"); + textdomain(GETTEXT_PACKAGE).expect("Unable to switch to the text domain"); + + let res = gio::Resource::load(resources_dir_path.join("resources.gresource")) + .expect("Could not load gresource file"); + gio::resources_register(&res); + + let ui_res = gio::Resource::load(resources_dir_path.join("ui-resources.gresource")) + .expect("Could not load UI gresource file"); + gio::resources_register(&ui_res); +} + diff --git a/reflection-app/src/meson.build b/reflection-app/src/meson.build index 29cb0c2b..8a3f3929 100644 --- a/reflection-app/src/meson.build +++ b/reflection-app/src/meson.build @@ -16,12 +16,24 @@ gnome.compile_resources('ui-resources', install_dir: pkgdatadir, ) +# Detect if we're building for a macOS app bundle +is_macos_bundle = get_option('macos_bundle') + conf = configuration_data() conf.set_quoted('APP_ID', application_id) conf.set_quoted('VERSION', meson.project_version()) conf.set_quoted('GETTEXT_PACKAGE', 'reflection') -conf.set_quoted('LOCALEDIR', get_option('prefix') / get_option('localedir')) -conf.set_quoted('PKGDATADIR', pkgdatadir) + +# Set paths based on whether we're building for macOS app bundle or not +if is_macos_bundle + # For macOS app bundles, use relative paths that will be resolved at runtime + conf.set_quoted('LOCALEDIR', 'Resources/share/locale') + conf.set_quoted('PKGDATADIR', 'Resources/share/reflection') +else + # For Flatpak and other installations, use absolute paths + conf.set_quoted('LOCALEDIR', get_option('prefix') / get_option('localedir')) + conf.set_quoted('PKGDATADIR', pkgdatadir) +endif configure_file( input: 'config.rs.in', @@ -75,4 +87,4 @@ test( ], is_parallel: false, timeout: 1800, -) \ No newline at end of file +) diff --git a/reflection-app/src/secret.rs b/reflection-app/src/secret.rs index 6fc4edce..7cf1a910 100644 --- a/reflection-app/src/secret.rs +++ b/reflection-app/src/secret.rs @@ -16,27 +16,42 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ +#[cfg(target_os = "linux")] use std::collections::HashMap; use thiserror::Error; use tracing::info; +#[cfg(target_os = "linux")] use crate::APP_ID; use reflection_doc::identity::{IdentityError, PrivateKey}; -const XDG_SCHEMA: &str = "xdg:schema"; +#[cfg(target_os = "linux")] +const XDG_SCHEMA: &'static str = "xdg:schema"; +#[cfg(target_os = "linux")] fn attributes() -> HashMap<&'static str, String> { HashMap::from([(XDG_SCHEMA, APP_ID.to_owned())]) } +#[cfg(target_os = "macos")] +use base64::engine::general_purpose::STANDARD as Base64Engine; + +#[cfg(target_os = "macos")] +use base64::Engine as _; + #[derive(Debug, Error)] pub enum Error { + #[cfg(target_os = "linux")] #[error(transparent)] Service(#[from] oo7::Error), + #[cfg(target_os = "macos")] + #[error(transparent)] + Service(#[from] keyring::Error), #[error(transparent)] Format(#[from] IdentityError), } +#[cfg(target_os = "linux")] pub async fn get_or_create_identity() -> Result { let keyring = oo7::Keyring::new().await?; @@ -64,3 +79,35 @@ pub async fn get_or_create_identity() -> Result { Ok(private_key) } + +#[cfg(target_os = "macos")] +pub async fn get_or_create_identity() -> Result { + let entry = keyring::Entry::new("Reflection Identity", "default user").map_err(Error::Service)?; + + let private_key: PrivateKey = match entry.get_password() { + Ok(password) => { + let private_key = PrivateKey::try_from( + Base64Engine + .decode(password) + .expect("Failed to decode base64 secret from keyring") + .as_slice(), + )?; + info!("Found existing identity: {}", private_key.public_key()); + private_key + } + Err(keyring::Error::NoEntry) => { + let private_key = PrivateKey::new(); + entry + .set_password(&Base64Engine.encode(private_key.as_bytes())) + .map_err(Error::Service)?; + info!( + "No existing identity found. Create new identity: {}", + private_key.public_key() + ); + private_key + } + Err(e) => return Err(Error::Service(e)), + }; + + Ok(private_key) +} diff --git a/reflection-app/src/system_settings.rs b/reflection-app/src/system_settings.rs index bbe8f9d3..44e3b76b 100644 --- a/reflection-app/src/system_settings.rs +++ b/reflection-app/src/system_settings.rs @@ -20,14 +20,21 @@ use adw::prelude::*; use adw::subclass::prelude::*; +#[cfg(target_os = "linux")] use ashpd::{desktop::settings::Settings as SettingsProxy, zvariant}; +#[cfg(target_os = "linux")] use futures_util::stream::StreamExt; use gtk::{glib, glib::Properties, glib::clone, pango}; use std::cell::{Cell, RefCell}; use tracing::error; +#[cfg(target_os = "linux")] const GNOME_DESKTOP_NAMESPACE: &str = "org.gnome.desktop.interface"; + +#[cfg(target_os = "linux")] const CLOCK_FORMAT_KEY: &str = "clock-format"; + +#[cfg(target_os = "linux")] const MONOSPACE_FONT_NAME_KEY: &str = "monospace-font-name"; /// The clock format setting. @@ -89,7 +96,11 @@ mod imp { self, async move { if let Err(error) = this.init().await { + #[cfg(target_os = "linux")] error!("Unable to read system settings: {error}"); + + #[cfg(target_os = "macos")] + let _ = error; } } )); @@ -97,6 +108,7 @@ mod imp { } impl SystemSettings { + #[cfg(target_os = "linux")] async fn init(&self) -> Result<(), ashpd::Error> { let proxy = SettingsProxy::new().await?; let settings = proxy.read_all(&[GNOME_DESKTOP_NAMESPACE]).await?; @@ -173,6 +185,13 @@ mod imp { Ok(()) } + #[cfg(target_os = "macos")] + async fn init(&self) -> Result<(), ()> { + // TODO: Implement reading macOS system settings + Ok(()) + } + + #[cfg(target_os = "linux")] fn set_clock_format(&self, clock_format: ClockFormat) { if self.obj().clock_format() == clock_format { return; @@ -182,6 +201,7 @@ mod imp { self.obj().notify_clock_format(); } + #[cfg(target_os = "linux")] fn set_monospace_font_name(&self, font_name: Option) { if self.obj().monospace_font_name() == font_name { return; @@ -209,6 +229,7 @@ impl Default for SystemSettings { } } +#[cfg(target_os = "linux")] impl TryFrom<&zvariant::OwnedValue> for ClockFormat { type Error = zvariant::Error; @@ -227,6 +248,7 @@ impl TryFrom<&zvariant::OwnedValue> for ClockFormat { } } +#[cfg(target_os = "linux")] impl TryFrom for ClockFormat { type Error = zvariant::Error; diff --git a/reflection-app/src/ui-resources.gresource.xml b/reflection-app/src/ui-resources.gresource.xml index 2e2f5724..57dbd12a 100644 --- a/reflection-app/src/ui-resources.gresource.xml +++ b/reflection-app/src/ui-resources.gresource.xml @@ -1,6 +1,6 @@ - + shortcuts-dialog.ui style.css diff --git a/reflection-doc/src/document.rs b/reflection-doc/src/document.rs index 479b8ff7..bb5fa1b8 100644 --- a/reflection-doc/src/document.rs +++ b/reflection-doc/src/document.rs @@ -9,8 +9,8 @@ use glib::{Properties, clone}; pub use hex::FromHexError; use loro::{ExportMode, LoroDoc, LoroText, event::Diff}; use p2panda_core::cbor::{decode_cbor, encode_cbor}; -use reflection_node::document::{SubscribableDocument, Subscription as DocumentSubscription}; use reflection_node::p2panda_core; +use reflection_node::topic::{SubscribableTopic, Subscription as TopicSubscription}; use tracing::error; use crate::author::Author; @@ -127,7 +127,7 @@ mod imp { #[property(get, construct_only)] id: OnceCell, #[property(name = "subscribed", get = Self::subscribed, type = bool)] - pub(super) subscription: RwLock>>>, + pub(super) subscription: RwLock>>>, #[property(get = Self::service, set = Self::set_service, construct_only, type = Service)] service: glib::WeakRef, #[property(get)] @@ -639,7 +639,7 @@ mod imp { } } - pub(super) fn subscription(&self) -> Option>> { + pub(super) fn subscription(&self) -> Option>> { self.subscription.read().unwrap().clone() } } @@ -879,7 +879,7 @@ impl Document { } pub async fn delete(&self) { - if let Err(error) = self.service().node().delete_document(self.id()).await { + if let Err(error) = self.service().node().delete_topic(self.id()).await { error!("Failed to delete document from document store: {}", error); return; } @@ -893,7 +893,7 @@ unsafe impl Sync for Document {} struct DocumentHandle(glib::WeakRef); -impl SubscribableDocument for DocumentHandle { +impl SubscribableTopic for DocumentHandle { fn bytes_received(&self, author: p2panda_core::PublicKey, data: Vec) { if let Some(document) = self.0.upgrade() { document.main_context().invoke(move || { diff --git a/reflection-doc/src/documents.rs b/reflection-doc/src/documents.rs index ab9ba18d..d9dc6096 100644 --- a/reflection-doc/src/documents.rs +++ b/reflection-doc/src/documents.rs @@ -70,7 +70,7 @@ impl Documents { pub(crate) async fn load(&self, service: &Service) -> Result<(), StartupError> { let public_key = service.private_key().public_key(); - let documents = service.node().documents::().await?; + let documents = service.node().topics::().await?; let mut list = self.imp().list.write().unwrap(); assert!(list.is_empty()); diff --git a/reflection-doc/src/service.rs b/reflection-doc/src/service.rs index 820d2798..67bba885 100644 --- a/reflection-doc/src/service.rs +++ b/reflection-doc/src/service.rs @@ -13,9 +13,9 @@ use crate::{ documents::Documents, }; use reflection_node::{ - document::DocumentError, node, node::{Node, NodeError}, + topic::TopicError, }; #[derive(Error, Debug)] @@ -23,7 +23,7 @@ pub enum StartupError { #[error(transparent)] Node(#[from] NodeError), #[error(transparent)] - Document(#[from] DocumentError), + Topic(#[from] TopicError), } #[derive(Debug, Copy, Clone, PartialEq, Eq, glib::Enum, Default)] diff --git a/reflection-node/Cargo.toml b/reflection-node/Cargo.toml index e2f1f338..05de2272 100644 --- a/reflection-node/Cargo.toml +++ b/reflection-node/Cargo.toml @@ -10,15 +10,14 @@ authors = [ [dependencies] thiserror = "2.0.17" -async-trait = "0.1.89" chrono = "0.4.42" ciborium = "0.2.2" -p2panda-core = { git = "https://github.com/p2panda/p2panda" } -p2panda-discovery = { git = "https://github.com/p2panda/p2panda", features = ["mdns"] } -p2panda-net = { git = "https://github.com/p2panda/p2panda" } -p2panda-store = { git = "https://github.com/p2panda/p2panda", features = ["sqlite"], default-features = false} -p2panda-stream = { git = "https://github.com/p2panda/p2panda" } -p2panda-sync = { git = "https://github.com/p2panda/p2panda", features = ["log-sync"] } +p2panda-core = { git = "https://github.com/p2panda/p2panda", rev = "365f5848a3014a69a4b692153bdf77e59b43eb81" } +p2panda-discovery = { git = "https://github.com/p2panda/p2panda", rev = "365f5848a3014a69a4b692153bdf77e59b43eb81", package = "p2panda-discovery-next"} +p2panda-net = { git = "https://github.com/p2panda/p2panda", rev = "365f5848a3014a69a4b692153bdf77e59b43eb81", package = "p2panda-net-next"} +p2panda-store = { git = "https://github.com/p2panda/p2panda", features = ["sqlite"], default-features = false, rev = "365f5848a3014a69a4b692153bdf77e59b43eb81"} +p2panda-stream = { git = "https://github.com/p2panda/p2panda", rev = "365f5848a3014a69a4b692153bdf77e59b43eb81" } +p2panda-sync = { git = "https://github.com/p2panda/p2panda", rev = "365f5848a3014a69a4b692153bdf77e59b43eb81", package = "p2panda-sync-next" } serde = { version = "1.0.228", features = ["derive"] } serde_bytes = "0.11.19" sqlx = { version = "0.8.6", features = ["runtime-tokio", "sqlite", "chrono"], default-features = false} @@ -27,3 +26,5 @@ tokio-stream = "0.1.17" tracing = "0.1" test-log = { version = "0.2.18", default-features = false, features = ["trace", "color"] } hex = "0.4.3" +rand_chacha = { version = "0.9.0", features = ["os_rng"] } +iroh = "0.95.1" diff --git a/reflection-node/migrations/20250418140035_create_tables.sql b/reflection-node/migrations/20250418140035_create_tables.sql index 39ad1047..186eb4c8 100644 --- a/reflection-node/migrations/20250418140035_create_tables.sql +++ b/reflection-node/migrations/20250418140035_create_tables.sql @@ -1,13 +1,13 @@ CREATE TABLE IF NOT EXISTS authors ( public_key TEXT NOT NULL, - document_id TEXT NOT NULL, + topic_id TEXT NOT NULL, last_seen INTEGER, - UNIQUE(public_key, document_id), - FOREIGN KEY(document_id) REFERENCES documents(document_id) + UNIQUE(public_key, topic_id), + FOREIGN KEY(topic_id) REFERENCES topics(id) ON DELETE CASCADE ); -CREATE TABLE IF NOT EXISTS documents ( - document_id TEXT NOT NULL PRIMARY KEY, +CREATE TABLE IF NOT EXISTS topics ( + id TEXT NOT NULL PRIMARY KEY, name TEXT, last_accessed INTEGER ); \ No newline at end of file diff --git a/reflection-node/migrations/20251130191542_cascate_deletion.sql b/reflection-node/migrations/20251130191542_cascate_deletion.sql deleted file mode 100644 index 04ca923b..00000000 --- a/reflection-node/migrations/20251130191542_cascate_deletion.sql +++ /dev/null @@ -1,13 +0,0 @@ -CREATE TABLE IF NOT EXISTS new_authors ( - public_key TEXT NOT NULL, - document_id TEXT NOT NULL, - last_seen INTEGER, - UNIQUE(public_key, document_id), - FOREIGN KEY(document_id) REFERENCES documents(document_id) ON DELETE CASCADE -); - -INSERT INTO new_authors SELECT * FROM authors; - -DROP TABLE authors; - -ALTER TABLE new_authors RENAME TO authors; \ No newline at end of file diff --git a/reflection-node/src/author_tracker.rs b/reflection-node/src/author_tracker.rs index 693f62e6..a7d57911 100644 --- a/reflection-node/src/author_tracker.rs +++ b/reflection-node/src/author_tracker.rs @@ -3,18 +3,15 @@ use std::ops::DerefMut; use std::sync::Arc; use std::time::{Duration, Instant, SystemTime}; -use crate::document::SubscribableDocument; use crate::ephemerial_operation::EphemerialOperation; use crate::node_inner::MessageType; use crate::node_inner::NodeInner; +use crate::topic::SubscribableTopic; use chrono::Utc; use p2panda_core::cbor::{DecodeError, decode_cbor, encode_cbor}; use p2panda_core::{PrivateKey, PublicKey}; -use p2panda_net::ToNetwork; -use tokio::{ - sync::mpsc, - sync::{Mutex, RwLock}, -}; +use p2panda_net::streams::EphemeralStream; +use tokio::sync::{Mutex, RwLock}; use tracing::error; const OFFLINE_TIMEOUT: Duration = Duration::from_secs(60); @@ -48,22 +45,22 @@ impl TryFrom<&[u8]> for AuthorMessage { pub struct AuthorTracker { last_ping: Mutex>, - document: Arc, + subscribable_topic: Arc, node: Arc, - tx: RwLock>>, + tx: RwLock>, } -impl AuthorTracker { - pub fn new(node: Arc, document: Arc) -> Arc { +impl AuthorTracker { + pub fn new(node: Arc, subscribable_topic: Arc) -> Arc { Arc::new(Self { last_ping: Mutex::new(HashMap::new()), - document, + subscribable_topic, node, tx: RwLock::new(None), }) } - pub async fn set_document_tx(&self, tx: Option>) { + pub async fn set_topic_tx(&self, tx: Option) { let mut tx_guard = self.tx.write().await; // Send good bye message to the network if let Some(tx) = tx_guard.as_ref() { @@ -73,15 +70,15 @@ impl AuthorTracker { // Set all authors that the tracker has seen to offline, authors the tracker hasn't seen are already offline let old_authors = std::mem::take(self.last_ping.lock().await.deref_mut()); for author in old_authors.into_keys() { - self.document.author_left(author); + self.subscribable_topic.author_left(author); self.set_last_seen(author).await; } let this_author = self.node.private_key.public_key(); if tx.is_some() { - self.document.author_joined(this_author); + self.subscribable_topic.author_joined(this_author); } else { - self.document.author_left(this_author); + self.subscribable_topic.author_left(this_author); self.set_last_seen(this_author).await; } @@ -110,7 +107,7 @@ impl AuthorTracker { async fn join(&self, author: PublicKey) { self.last_ping.lock().await.insert(author, Instant::now()); - self.document.author_joined(author); + self.subscribable_topic.author_joined(author); self.set_last_seen(author).await; // Send a ping to the network to ensure that the new author knows we exist @@ -123,19 +120,19 @@ impl AuthorTracker { // If this is a new author emit author join if old.is_none() { - self.document.author_joined(author); + self.subscribable_topic.author_joined(author); } self.set_last_seen(author).await; } async fn left(&self, author: PublicKey) { self.last_ping.lock().await.remove(&author); - self.document.author_left(author); + self.subscribable_topic.author_left(author); self.set_last_seen(author).await; } pub async fn spawn(&self) { - // Send a hello to the network so other authors know we joined the document + // Send a hello to the network so other authors know we joined the topic self.send(AuthorMessage::Hello).await; let mut interval = tokio::time::interval(OFFLINE_TIMEOUT / 2); @@ -159,7 +156,7 @@ impl AuthorTracker { }); for author in expired { - self.document.author_left(author); + self.subscribable_topic.author_left(author); self.set_last_seen(author).await; } } @@ -168,7 +165,7 @@ impl AuthorTracker { async fn set_last_seen(&self, author: PublicKey) { if let Err(error) = self .node - .document_store + .topic_store .set_last_seen_for_author(author, Some(Utc::now())) .await { @@ -177,11 +174,7 @@ impl AuthorTracker { } } -async fn send_message( - private_key: &PrivateKey, - tx: &mpsc::Sender, - message: AuthorMessage, -) { +async fn send_message(private_key: &PrivateKey, tx: &EphemeralStream, message: AuthorMessage) { // FIXME: We need to add the current time to the message, // because iroh doesn't broadcast twice the same message message. let author_message = match encode_cbor(&(&message, SystemTime::now())) { @@ -199,7 +192,7 @@ async fn send_message( return; } }; - if let Err(error) = tx.send(ToNetwork::Message { bytes }).await { + if let Err(error) = tx.publish(bytes).await { error!("Failed to sent {message} to the network: {error}"); } } diff --git a/reflection-node/src/lib.rs b/reflection-node/src/lib.rs index 8e736cb2..bcd59d83 100644 --- a/reflection-node/src/lib.rs +++ b/reflection-node/src/lib.rs @@ -1,68 +1,56 @@ mod author_tracker; -pub mod document; -mod document_store; mod ephemerial_operation; pub mod node; mod node_inner; mod operation; mod operation_store; -mod persistent_operation; mod subscription_inner; +pub mod topic; +mod topic_store; mod utils; -pub use document::SubscribableDocument; pub use p2panda_core; +pub use topic::SubscribableTopic; #[cfg(test)] mod tests { - use crate::SubscribableDocument; + use crate::SubscribableTopic; use crate::node::{ConnectionMode, Node}; use p2panda_core::Hash; use p2panda_core::PrivateKey; use p2panda_core::PublicKey; use std::sync::Arc; - use test_log::test; use tokio::sync::{Mutex, mpsc}; - #[test] - fn create_document() { - let runtime = tokio::runtime::Builder::new_multi_thread() - .worker_threads(1) - .build() + #[tokio::test] + #[test_log::test] + async fn create_topic() { + let private_key = PrivateKey::new(); + let network_id = Hash::new(b"reflection"); + let node = Node::new(private_key, network_id, None, ConnectionMode::Network) + .await .unwrap(); - let node = runtime.block_on(async move { - let private_key = PrivateKey::new(); - let network_id = Hash::new(b"reflection"); - let node = Node::new(private_key, network_id, None, ConnectionMode::Network) - .await - .unwrap(); + let id: [u8; 32] = [0; 32]; + let _sub = node.subscribe(id, TestTopic::new()).await; + let topics = node.topics::<[u8; 32]>().await.unwrap(); - let document_id: [u8; 32] = [0; 32]; - let _sub = node.subscribe(document_id, TestDocument::new()).await; - let documents = node.documents::<[u8; 32]>().await.unwrap(); + assert_eq!(topics.len(), 1); + assert_eq!(topics.first().unwrap().id, id); - assert_eq!(documents.len(), 1); - assert_eq!(documents.first().unwrap().id, document_id); - - node.shutdown().await.unwrap(); - node - }); - - // Node can't be dropped inside an async context - drop(node); + node.shutdown().await.unwrap(); } #[derive(Clone)] - struct TestDocument { + struct TestTopic { tx: mpsc::UnboundedSender>, rx: Arc>>>, } - impl TestDocument { + impl TestTopic { fn new() -> Self { let (tx, rx) = mpsc::unbounded_channel::>(); - TestDocument { + TestTopic { tx, rx: Arc::new(Mutex::new(rx)), } @@ -73,7 +61,7 @@ mod tests { } } - impl SubscribableDocument for TestDocument { + impl SubscribableTopic for TestTopic { fn bytes_received(&self, _author: PublicKey, data: Vec) { self.tx.send(data).unwrap(); } @@ -83,61 +71,47 @@ mod tests { fn ephemeral_bytes_received(&self, _author: PublicKey, _data: Vec) {} } - #[test] - fn subscribe_document() { - let runtime = tokio::runtime::Builder::new_multi_thread() - .worker_threads(1) - .build() + #[tokio::test] + #[test_log::test] + async fn subscribe_topic() { + let private_key = PrivateKey::new(); + let network_id = Hash::new(b"reflection"); + let node = Node::new(private_key, network_id, None, ConnectionMode::Network) + .await .unwrap(); - let nodes = runtime.block_on(async move { - let private_key = PrivateKey::new(); - let network_id = Hash::new(b"reflection"); - let node = Node::new(private_key, network_id, None, ConnectionMode::Network) - .await - .unwrap(); - - let test_document = TestDocument::new(); - - let document_id: [u8; 32] = [0; 32]; - let subscription = node.subscribe(document_id, test_document).await.unwrap(); + let test_topic = TestTopic::new(); - let documents = node.documents::<[u8; 32]>().await.unwrap(); - assert_eq!(documents.len(), 1); - assert_eq!(documents.first().unwrap().id, document_id); + let id: [u8; 32] = [0; 32]; + let subscription = node.subscribe(id, test_topic).await.unwrap(); - let private_key2 = PrivateKey::new(); - let network_id2 = Hash::new(b"reflection"); - let node2 = Node::new(private_key2, network_id2, None, ConnectionMode::Network) - .await - .unwrap(); + let topics = node.topics::<[u8; 32]>().await.unwrap(); + assert_eq!(topics.len(), 1); + assert_eq!(topics.first().unwrap().id, id); - let test_document2 = TestDocument::new(); - - let _subscription2 = node2 - .subscribe(document_id, test_document2.clone()) - .await - .unwrap(); + let private_key2 = PrivateKey::new(); + let network_id2 = Hash::new(b"reflection"); + let node2 = Node::new(private_key2, network_id2, None, ConnectionMode::Network) + .await + .unwrap(); - let documents2 = node2.documents::<[u8; 32]>().await.unwrap(); - assert_eq!(documents2.len(), 1); - assert_eq!(documents2.first().unwrap().id, document_id); + let test_topic2 = TestTopic::new(); - let test_snapshot = "test".as_bytes().to_vec(); - subscription - .send_snapshot(test_snapshot.clone()) - .await - .unwrap(); + let _subscription2 = node2.subscribe(id, test_topic2.clone()).await.unwrap(); - assert_eq!(test_document2.wait_for_bytes().await, test_snapshot); + let topics2 = node2.topics::<[u8; 32]>().await.unwrap(); + assert_eq!(topics2.len(), 1); + assert_eq!(topics2.first().unwrap().id, id); - node.shutdown().await.unwrap(); - node2.shutdown().await.unwrap(); + let test_snapshot = "test".as_bytes().to_vec(); + subscription + .send_snapshot(test_snapshot.clone()) + .await + .unwrap(); - (node, node2) - }); + assert_eq!(test_topic2.wait_for_bytes().await, test_snapshot); - // Node can't be dropped inside a tokio async context - drop(nodes); + node.shutdown().await.unwrap(); + node2.shutdown().await.unwrap(); } } diff --git a/reflection-node/src/node.rs b/reflection-node/src/node.rs index 432ca995..e8a03306 100644 --- a/reflection-node/src/node.rs +++ b/reflection-node/src/node.rs @@ -3,12 +3,14 @@ use std::sync::Arc; use chrono::{DateTime, Utc}; use p2panda_core::{Hash, PrivateKey}; +use p2panda_net::TopicId; use thiserror::Error; +use tracing::info; -use crate::document::{DocumentError, DocumentId, SubscribableDocument, Subscription}; -pub use crate::document_store::Author; -use crate::document_store::StoreDocument; use crate::node_inner::NodeInner; +use crate::topic::{SubscribableTopic, Subscription, TopicError}; +pub use crate::topic_store::Author; +use crate::topic_store::StoreTopic; #[derive(Debug, Error)] pub enum NodeError { @@ -31,16 +33,34 @@ pub enum ConnectionMode { } #[derive(Clone, Debug)] -pub struct Document { +pub struct Topic { pub id: ID, pub name: Option, pub last_accessed: Option>, pub authors: Vec, } +#[derive(Debug)] +enum OwnedRuntimeOrHandle { + Handle(tokio::runtime::Handle), + OwnedRuntime(tokio::runtime::Runtime), +} + +impl std::ops::Deref for OwnedRuntimeOrHandle { + type Target = tokio::runtime::Handle; + + fn deref(&self) -> &Self::Target { + match self { + OwnedRuntimeOrHandle::Handle(handle) => handle, + OwnedRuntimeOrHandle::OwnedRuntime(runtime) => runtime.handle(), + } + } +} + #[derive(Debug)] pub struct Node { inner: Arc, + runtime: OwnedRuntimeOrHandle, } impl Node { @@ -50,10 +70,26 @@ impl Node { db_location: Option<&Path>, connection_mode: ConnectionMode, ) -> Result { + let runtime = if let Ok(handle) = tokio::runtime::Handle::try_current() { + OwnedRuntimeOrHandle::Handle(handle) + } else { + OwnedRuntimeOrHandle::OwnedRuntime( + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build()?, + ) + }; + + let db_file = db_location.map(|location| location.join("database.sqlite")); + let inner = runtime + .spawn(async move { + NodeInner::new(network_id, private_key, db_file, connection_mode).await + }) + .await??; + Ok(Self { - inner: Arc::new( - NodeInner::new(network_id, private_key, db_location, connection_mode).await?, - ), + inner: Arc::new(inner), + runtime, }) } @@ -62,8 +98,7 @@ impl Node { connection_mode: ConnectionMode, ) -> Result<(), NodeError> { let inner_clone = self.inner.clone(); - self.inner - .runtime + self.runtime .spawn(async move { inner_clone.set_connection_mode(connection_mode).await; }) @@ -74,8 +109,7 @@ impl Node { pub async fn shutdown(&self) -> Result<(), NodeError> { let inner_clone = self.inner.clone(); - self.inner - .runtime + self.runtime .spawn(async move { inner_clone.shutdown().await; }) @@ -84,25 +118,24 @@ impl Node { Ok(()) } - pub async fn documents>(&self) -> Result>, DocumentError> { + pub async fn topics>(&self) -> Result>, TopicError> { let inner_clone = self.inner.clone(); - let documents = self - .inner + let topics = self .runtime - .spawn(async move { inner_clone.document_store.documents().await }) + .spawn(async move { inner_clone.topic_store.topics().await }) .await??; - let documents = documents + let topics = topics .into_iter() - .map(|document| { - let StoreDocument { + .map(|topic| { + let StoreTopic { id, name, last_accessed, authors, - } = document; - Document { - id: <[u8; 32]>::from(id).into(), + } = topic; + Topic { + id: id.into(), name, last_accessed, authors, @@ -110,32 +143,33 @@ impl Node { }) .collect(); - Ok(documents) + Ok(topics) } - pub async fn subscribe, T: SubscribableDocument + 'static>( + pub async fn subscribe, T: SubscribableTopic + 'static>( &self, - document_id: ID, - document_handle: T, - ) -> Result, DocumentError> { - let document_id: DocumentId = DocumentId::from(document_id.into()); - let document_handle = Arc::new(document_handle); + id: ID, + topic_handle: T, + ) -> Result, TopicError> { + let id: TopicId = id.into(); + let topic_handle = Arc::new(topic_handle); let inner_clone = self.inner.clone(); - self.inner + let inner_subscription = self .runtime - .spawn(async move { inner_clone.subscribe(document_id, document_handle).await }) - .await? + .spawn(async move { inner_clone.subscribe(id, topic_handle).await }) + .await??; + + let subscription = Subscription::new(self.runtime.clone(), inner_subscription).await; + info!("Subscribed to topic {}", hex::encode(id)); + + Ok(subscription) } - pub async fn delete_document>( - &self, - document_id: ID, - ) -> Result<(), DocumentError> { - let document_id: DocumentId = DocumentId::from(document_id.into()); + pub async fn delete_topic>(&self, id: ID) -> Result<(), TopicError> { + let id: TopicId = id.into(); let inner_clone = self.inner.clone(); - self.inner - .runtime - .spawn(async move { inner_clone.delete_document(document_id).await }) + self.runtime + .spawn(async move { inner_clone.delete_topic(id).await }) .await? } } diff --git a/reflection-node/src/node_inner.rs b/reflection-node/src/node_inner.rs index 79ef91a2..c91f7acc 100644 --- a/reflection-node/src/node_inner.rs +++ b/reflection-node/src/node_inner.rs @@ -1,84 +1,90 @@ -use std::ops::DerefMut; -use std::path::Path; -use std::sync::Arc; +use std::path::PathBuf; +use std::sync::{Arc, LazyLock}; -use crate::document::{DocumentError, DocumentId, SubscribableDocument, Subscription}; -use crate::document_store::DocumentStore; use crate::ephemerial_operation::EphemerialOperation; use crate::node::{ConnectionMode, NodeError}; +use crate::operation::ReflectionExtensions; use crate::operation_store::OperationStore; -use crate::persistent_operation::PersistentOperation; +use crate::subscription_inner::SubscriptionInner; +use crate::topic::{SubscribableTopic, TopicError}; +use crate::topic_store::{LogId, TopicStore}; use crate::utils::CombinedMigrationSource; use p2panda_core::{Hash, PrivateKey}; -use p2panda_discovery::mdns::LocalDiscovery; -use p2panda_net::config::GossipConfig; -use p2panda_net::{Network, NetworkBuilder, SyncConfiguration}; +use p2panda_discovery::address_book::AddressBookStore; +use p2panda_discovery::address_book::memory::MemoryStore as MemoryAddressBook; +use p2panda_net::{MdnsDiscoveryMode, NodeInfo, TopicId}; +use p2panda_net::{Network, NetworkBuilder}; use p2panda_store::sqlite::store::migrations as operation_store_migrations; -use p2panda_sync::log_sync::LogSyncProtocol; +use p2panda_sync::managers::topic_sync_manager::TopicSyncManagerConfig; +use rand_chacha::rand_core::SeedableRng; use sqlx::{migrate::Migrator, sqlite}; -use tokio::{ - runtime::{Builder, Runtime}, - sync::{Notify, RwLock}, -}; -use tracing::{info, warn}; +use tokio::sync::{Notify, RwLock}; +use tracing::{error, info, warn}; + +pub type TopicSyncManager = p2panda_sync::managers::topic_sync_manager::TopicSyncManager< + TopicId, + p2panda_store::SqliteStore, + TopicStore, + LogId, + ReflectionExtensions, +>; #[derive(Debug, serde::Serialize, serde::Deserialize)] pub(crate) enum MessageType { - Persistent(PersistentOperation), Ephemeral(EphemerialOperation), AuthorEphemeral(EphemerialOperation), } #[derive(Debug)] pub struct NodeInner { - pub(crate) runtime: Runtime, pub(crate) operation_store: OperationStore, - pub(crate) document_store: DocumentStore, + pub(crate) topic_store: TopicStore, pub(crate) private_key: PrivateKey, pub(crate) network_id: Hash, - pub(crate) network: RwLock>>, + pub(crate) network: RwLock>>, pub(crate) network_notifier: Notify, } -//const RELAY_URL: &str = "https://staging-euw1-1.relay.iroh.network/"; -//const BOOTSTRAP_NODE_ID: &str = "d825a2f929f935efcd6889bed5c3f5510b40f014969a729033d3fb7e33b97dbe"; +static RELAY_URL: LazyLock = LazyLock::new(|| { + "https://euc1-1.relay.n0.iroh-canary.iroh.link" + .parse() + .expect("valid relay URL") +}); + +static BOOTSTRAP_NODE: LazyLock = LazyLock::new(|| { + let endpoint_addr = iroh::EndpointAddr::new( + "7ccdbeed587a8ec8c71cdc9b98e941ac597e11b0216aac1387ef81089a4930b2" + .parse() + .expect("valid bootstrap node id"), + ) + .with_relay_url(RELAY_URL.clone()); + NodeInfo::from(endpoint_addr).bootstrap() +}); impl NodeInner { pub async fn new( network_id: Hash, private_key: PrivateKey, - db_location: Option<&Path>, + db_file: Option, connection_mode: ConnectionMode, ) -> Result { - let runtime = Builder::new_multi_thread() - .worker_threads(1) - .enable_all() - .build()?; - - let _guard = runtime.enter(); - let connection_options = sqlx::sqlite::SqliteConnectOptions::new() .shared_cache(true) .create_if_missing(true); - let connection_options = if let Some(db_location) = db_location { - let db_file = db_location.join("database.sqlite"); + let pool = if let Some(db_file) = db_file { info!("Database file location: {db_file:?}"); - connection_options.filename(db_file) - } else { - connection_options.in_memory(true) - }; - - let pool = if db_location.is_some() { + let connection_options = connection_options.filename(db_file); sqlx::sqlite::SqlitePool::connect_with(connection_options).await? } else { + let connection_options = connection_options.in_memory(true); // FIXME: we need to set max connection to 1 for in memory sqlite DB. // Probably has to do something with this issue: https://github.com/launchbadge/sqlx/issues/2510 let pool_options = sqlite::SqlitePoolOptions::new().max_connections(1); pool_options.connect_with(connection_options).await? }; - // Run migration for p2panda OperationStore and for the our DocumentStore + // Run migration for p2panda OperationStore and for the our TopicStore Migrator::new(CombinedMigrationSource::new(vec![ operation_store_migrations(), sqlx::migrate!(), @@ -88,7 +94,7 @@ impl NodeInner { .await?; let operation_store = OperationStore::new(pool.clone()); - let document_store = DocumentStore::new(pool); + let topic_store = TopicStore::new(pool); let network = match connection_mode { ConnectionMode::None => None, @@ -96,14 +102,13 @@ impl NodeInner { unimplemented!("Bluetooth is currently not implemented") } ConnectionMode::Network => { - setup_network(&private_key, &network_id, &document_store, &operation_store).await + setup_network(&private_key, &network_id, &topic_store, &operation_store).await } }; Ok(Self { - runtime, operation_store, - document_store, + topic_store, private_key, network_id, network: RwLock::new(network), @@ -127,65 +132,50 @@ impl NodeInner { setup_network( &self.private_key, &self.network_id, - &self.document_store, + &self.topic_store, &self.operation_store, ) .await } }; - let old_network = std::mem::replace(network_guard.deref_mut(), network); - - if let Some(old_network) = old_network { - // FIXME: For some reason we shutdown before the bye message is actually send - // This doesn't happen when shutting down the entire node, maybe because tokio is more busy here? - if let Err(error) = old_network.shutdown().await { - warn!("Failed to shutdown network: {error}"); - } - } + *network_guard = network; } pub async fn shutdown(&self) { // Wake up all subscriptions that may still exist self.network_notifier.notify_waiters(); - if let Some(network) = self.network.write().await.take() - && let Err(error) = network.shutdown().await - { - warn!("Failed to shutdown network: {error}"); - } + self.network.write().await.take(); } - pub async fn subscribe( + pub async fn subscribe( self: Arc, - document_id: DocumentId, - document: Arc, - ) -> Result, DocumentError> { - self.document_store.add_document(&document_id).await?; - // Add ourselves as an author to the document store. - self.document_store - .add_author(&document_id, &self.private_key.public_key()) + id: TopicId, + subscribable_topic: Arc, + ) -> Result, TopicError> { + self.topic_store.add_topic(&id).await?; + // Add ourselves as an author to the topic store. + self.topic_store + .add_author(&id, &self.private_key.public_key()) .await?; let stored_operations = self - .document_store - .operations_for_document(&self.operation_store, &document_id) + .topic_store + .operations_for_topic(&self.operation_store, &id) .await?; for operation in stored_operations { // Send all stored operation bytes to the app, // it doesn't matter if the app already knows some or all of them if let Some(body) = operation.body { - document.bytes_received(operation.header.public_key, body.to_bytes()); + subscribable_topic.bytes_received(operation.header.public_key, body.to_bytes()); } } - Ok(Subscription::new(self, document_id, document).await) + Ok(SubscriptionInner::new(self.clone(), id, subscribable_topic)) } - pub async fn delete_document( - self: Arc, - document_id: DocumentId, - ) -> Result<(), DocumentError> { - self.document_store.delete_document(&document_id).await?; + pub async fn delete_topic(self: Arc, id: TopicId) -> Result<(), TopicError> { + self.topic_store.delete_topic(&id).await?; Ok(()) } } @@ -193,35 +183,24 @@ impl NodeInner { async fn setup_network( private_key: &PrivateKey, network_id: &Hash, - document_store: &DocumentStore, + topic_store: &TopicStore, operation_store: &OperationStore, -) -> Option> { - let sync_config = { - let sync = LogSyncProtocol::new(document_store.clone(), operation_store.clone_inner()); - SyncConfiguration::::new(sync) - }; +) -> Option> { + let address_book = MemoryAddressBook::new(rand_chacha::ChaCha20Rng::from_os_rng()); + if let Err(error) = address_book.insert_node_info(BOOTSTRAP_NODE.clone()).await { + error!("Failed to add bootstrap node to the address book: {error}"); + } + + let sync_conf = TopicSyncManagerConfig { + store: operation_store.clone_inner(), + topic_map: topic_store.clone(), + }; let network = NetworkBuilder::new(network_id.into()) .private_key(private_key.clone()) - .discovery(LocalDiscovery::new()) - // NOTE(glyph): Internet networking is disabled until we can fix the - // more-than-two-peers gossip issue. - // - //.relay(RELAY_URL.parse().expect("valid relay URL"), false, 0) - //.direct_address( - // BOOTSTRAP_NODE_ID.parse().expect("valid node ID"), - // vec![], - // None, - //) - .gossip(GossipConfig { - // FIXME: This is a temporary workaround to account for larger delta patches (for - // example when the user Copy & Pastes a big chunk of text). - // - // Related issue: https://github.com/p2panda/reflection/issues/24 - max_message_size: 512_000, - }) - .sync(sync_config) - .build() + .mdns(MdnsDiscoveryMode::Active) + .relay(RELAY_URL.clone()) + .build(address_book, sync_conf) .await; if let Err(error) = network { diff --git a/reflection-node/src/operation.rs b/reflection-node/src/operation.rs index 7c5d8301..beb5c99b 100644 --- a/reflection-node/src/operation.rs +++ b/reflection-node/src/operation.rs @@ -1,10 +1,10 @@ use std::hash::Hash as StdHash; use p2panda_core::{Extension, Header, PruneFlag}; +use p2panda_net::TopicId; use serde::{Deserialize, Serialize}; -use crate::document::DocumentId; -use crate::document_store::LogId; +use crate::topic_store::LogId; /// Custom extensions for p2panda header. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] @@ -13,7 +13,7 @@ pub struct ReflectionExtensions { /// /// This usually indicates that a "snapshot" has been inserted into the body of this operation, /// containing all required state to reconstruct the full version including all previous edits - /// of this document. + /// of this topic. /// /// In our case of a text-editor, this would be the encoded payload of a state-based CRDT. #[serde( @@ -26,15 +26,15 @@ pub struct ReflectionExtensions { /// Operations can be organised in separate logs. With a "log id" we can declare where this /// operation belongs to. /// - /// We organise two logs per author per document, one for "short lived" / ephemeral deltas - /// (small text changes) and one for persisted snapshots (full document history). These are two + /// We organise two logs per author per topic, one for "short lived" / ephemeral deltas + /// (small text changes) and one for persisted snapshots (full topic history). These are two /// distinct "log types". #[serde(rename = "t")] pub log_type: LogType, - /// Identifier of the document this operation relates to. + /// Identifier of the topic this operation relates to. #[serde(rename = "d")] - pub document: DocumentId, + pub topic: TopicId, } #[derive(Copy, Clone, Default, Debug, PartialEq, Eq, StdHash, Serialize, Deserialize)] @@ -56,17 +56,17 @@ impl Extension for ReflectionExtensions { } } -impl Extension for ReflectionExtensions { - fn extract(header: &Header) -> Option { - Some(header.extensions.document) +impl Extension for ReflectionExtensions { + fn extract(header: &Header) -> Option { + Some(header.extensions.topic) } } impl Extension for ReflectionExtensions { fn extract(header: &Header) -> Option { let log_type: LogType = header.extension()?; - let document_id: DocumentId = header.extension()?; + let id: TopicId = header.extension()?; - Some(LogId::new(log_type, &document_id)) + Some(LogId::new(log_type, &id)) } } diff --git a/reflection-node/src/operation_store.rs b/reflection-node/src/operation_store.rs index abaaf98e..44b72191 100644 --- a/reflection-node/src/operation_store.rs +++ b/reflection-node/src/operation_store.rs @@ -1,9 +1,9 @@ use std::sync::Arc; use std::time::{SystemTime, SystemTimeError}; -use crate::document::DocumentId; -use crate::document_store::LogId; +use crate::topic_store::LogId; use p2panda_core::{Body, Header, Operation, PrivateKey, PruneFlag}; +use p2panda_net::TopicId; use p2panda_store::{ LogStore, OperationStore as TraitOperationStore, SqliteStore, SqliteStoreError, }; @@ -46,13 +46,13 @@ impl OperationStore { /// Creates, signs and stores new operation in the author's append-only log. /// - /// If no document is specified we create a new operation in a new log. The resulting hash of the - /// header can be used to identify that new document. + /// If no topic is specified we create a new operation in a new log. The resulting hash of the + /// header can be used to identify that new topic. pub async fn create_operation( &self, private_key: &PrivateKey, log_type: LogType, - document: DocumentId, + topic: TopicId, body: Option<&[u8]>, prune_flag: bool, ) -> Result, CreationError> { @@ -65,7 +65,7 @@ impl OperationStore { let body = body.map(Body::new); let public_key = private_key.public_key(); - let log_id = LogId::new(log_type, &document); + let log_id = LogId::new(log_type, &topic); let latest_operation = self.inner.latest_operation(&public_key, &log_id).await?; let (seq_num, backlink) = match latest_operation { @@ -80,7 +80,7 @@ impl OperationStore { let extensions = ReflectionExtensions { prune_flag: PruneFlag::new(prune_flag), log_type, - document, + topic, }; let mut header = Header { diff --git a/reflection-node/src/persistent_operation.rs b/reflection-node/src/persistent_operation.rs index 251e07d6..dd90a215 100644 --- a/reflection-node/src/persistent_operation.rs +++ b/reflection-node/src/persistent_operation.rs @@ -4,7 +4,7 @@ use p2panda_core::{ }; use thiserror::Error; -use crate::document::DocumentId; +use crate::topic::TopicId; use crate::operation::ReflectionExtensions; type OperationWithRawHeader = (Header, Option, Vec); @@ -13,8 +13,8 @@ type OperationWithRawHeader = (Header, Option, Vec Result { let PersistentOperation { header, body } = self; @@ -50,13 +50,13 @@ impl PersistentOperation { let header_deserialized: Header = decode_cbor(&header[..])?; let body_deserialized = body.map(|body| Body::from(body.into_vec())); - let Some(operation_document_id): Option = header_deserialized.extension() + let Some(operation_id): Option = header_deserialized.extension() else { - return Err(UnpackError::InvalidDocumentId); + return Err(UnpackError::InvalidTopicId); }; - if operation_document_id != document_id { - return Err(UnpackError::InvalidDocumentId); + if operation_id != id { + return Err(UnpackError::InvalidTopicId); } Ok((header_deserialized, body_deserialized, header)) diff --git a/reflection-node/src/subscription_inner.rs b/reflection-node/src/subscription_inner.rs index f7020fc2..a52eea50 100644 --- a/reflection-node/src/subscription_inner.rs +++ b/reflection-node/src/subscription_inner.rs @@ -3,12 +3,17 @@ use std::ops::{Deref, DerefMut, Drop}; use std::sync::Arc; use chrono::Utc; +use p2panda_core::Hash; use p2panda_core::{ Body, Header, cbor::{decode_cbor, encode_cbor}, }; -use p2panda_net::{FromNetwork, Network, ToNetwork}; +use p2panda_net::{ + Network, TopicId, + streams::{EphemeralStream, EventuallyConsistentStream}, +}; use p2panda_stream::IngestExt; +use p2panda_sync::protocols::topic_log_sync::TopicLogSyncEvent; use tokio::{ sync::{RwLock, mpsc}, task::{AbortHandle, spawn}, @@ -17,18 +22,18 @@ use tokio_stream::{StreamExt, wrappers::ReceiverStream}; use tracing::{error, info, warn}; use crate::author_tracker::{AuthorMessage, AuthorTracker}; -use crate::document::{DocumentError, DocumentId, SubscribableDocument}; use crate::ephemerial_operation::EphemerialOperation; use crate::node_inner::MessageType; -use crate::node_inner::NodeInner; +use crate::node_inner::{NodeInner, TopicSyncManager}; use crate::operation::{LogType, ReflectionExtensions}; -use crate::persistent_operation::PersistentOperation; +use crate::topic::{SubscribableTopic, TopicError}; pub struct SubscriptionInner { - tx: RwLock>>, + ephemeral_tx: RwLock>, + tx: RwLock>>, pub(crate) node: Arc, - pub(crate) id: DocumentId, - pub(crate) document: Arc, + pub(crate) id: TopicId, + pub(crate) subscribable_topic: Arc, author_tracker: Arc>, abort_handles: RwLock>, } @@ -41,17 +46,18 @@ impl Drop for SubscriptionInner { } } -impl SubscriptionInner { - pub fn new(node: Arc, id: DocumentId, document: Arc) -> Arc { - let author_tracker = AuthorTracker::new(node.clone(), document.clone()); - Arc::new(SubscriptionInner { +impl SubscriptionInner { + pub fn new(node: Arc, id: TopicId, subscribable_topic: Arc) -> Self { + let author_tracker = AuthorTracker::new(node.clone(), subscribable_topic.clone()); + SubscriptionInner { tx: RwLock::new(None), + ephemeral_tx: RwLock::new(None), node, id, abort_handles: RwLock::new(Vec::new()), - document, + subscribable_topic, author_tracker, - }) + } } pub async fn spawn_network_monitor(&self) { @@ -60,20 +66,22 @@ impl SubscriptionInner { let mut notify = Some(self.node.network_notifier.notified()); let mut network_guard = Some(self.node.network.read().await); - let (tx, abort_handles) = if let Some(network) = network_guard.as_ref().unwrap().deref() { - setup_network( - &self.node, - network, - self.id, - &self.document, - &self.author_tracker, - ) - .await - } else { - (None, Vec::new()) - }; + let (tx, ephemeral_tx, abort_handles) = + if let Some(network) = network_guard.as_ref().unwrap().deref() { + setup_network( + &self.node, + network, + self.id, + &self.subscribable_topic, + &self.author_tracker, + ) + .await + } else { + (None, None, Vec::new()) + }; *self.tx.write().await = tx; + *self.ephemeral_tx.write().await = ephemeral_tx; *self.abort_handles.write().await = abort_handles; loop { @@ -83,53 +91,72 @@ impl SubscriptionInner { let mut abort_handles_guard = self.abort_handles.write().await; let mut tx_guard = self.tx.write().await; + let mut ephemeral_tx_guard = self.ephemeral_tx.write().await; let old_tx = take(tx_guard.deref_mut()); + let old_ephemeral_tx = take(ephemeral_tx_guard.deref_mut()); let old_abort_handles = take(abort_handles_guard.deref_mut()); - teardown_network(&self.id, &self.author_tracker, old_tx, old_abort_handles).await; + teardown_network( + &self.id, + &self.author_tracker, + old_tx, + old_ephemeral_tx, + old_abort_handles, + ) + .await; // Release network lock and get a new one, so that the network can be change between them network_guard.take(); notify = Some(self.node.network_notifier.notified()); network_guard = Some(self.node.network.read().await); - let (tx, abort_handles) = if let Some(network) = network_guard.as_ref().unwrap().deref() - { - setup_network( - &self.node, - network, - self.id, - &self.document, - &self.author_tracker, - ) - .await - } else { - (None, Vec::new()) - }; + let (tx, ephemeral_tx, abort_handles) = + if let Some(network) = network_guard.as_ref().unwrap().deref() { + setup_network( + &self.node, + network, + self.id, + &self.subscribable_topic, + &self.author_tracker, + ) + .await + } else { + (None, None, Vec::new()) + }; *tx_guard = tx; + *ephemeral_tx_guard = ephemeral_tx; *abort_handles_guard = abort_handles; } } - pub async fn unsubscribe(&self) -> Result<(), DocumentError> { + pub async fn unsubscribe(&self) -> Result<(), TopicError> { let mut tx_guard = self.tx.write().await; + let mut ephemeral_tx_guard = self.ephemeral_tx.write().await; let mut abort_handles_guard = self.abort_handles.write().await; let tx = take(tx_guard.deref_mut()); + let ephemeral_tx = take(ephemeral_tx_guard.deref_mut()); let abort_handles = take(abort_handles_guard.deref_mut()); self.node - .document_store - .set_last_accessed_for_document(&self.id, Some(Utc::now())) + .topic_store + .set_last_accessed_for_topic(&self.id, Some(Utc::now())) .await?; - teardown_network(&self.id, &self.author_tracker, tx, abort_handles).await; + teardown_network( + &self.id, + &self.author_tracker, + tx, + ephemeral_tx, + abort_handles, + ) + .await; Ok(()) } - pub async fn send_delta(&self, data: Vec) -> Result<(), DocumentError> { + pub async fn send_delta(&self, data: Vec) -> Result<(), TopicError> { let operation = // Append one operation to our "ephemeral" delta log. self.node.operation_store @@ -142,26 +169,24 @@ impl SubscriptionInner { ) .await?; - info!("Delta operation sent for document with id {}", self.id); + info!( + "Delta operation sent for topic with id {}", + hex::encode(self.id) + ); if let Some(tx) = self.tx.read().await.as_ref() { - let bytes = encode_cbor(&MessageType::Persistent(PersistentOperation::new( - operation, - )))?; - - // Broadcast operation on gossip overlay. - tx.send(ToNetwork::Message { bytes }).await?; + tx.publish(operation).await?; } Ok(()) } - pub async fn send_snapshot(&self, data: Vec) -> Result<(), DocumentError> { + pub async fn send_snapshot(&self, data: Vec) -> Result<(), TopicError> { // Append an operation to our "snapshot" log and set the prune flag to // true. This will remove previous snapshots. // // Snapshots are not broadcasted on the gossip overlay as they would be - // too large. Peers will sync them up when they join the document. + // too large. Peers will sync them up when they join the topic. self.node .operation_store .create_operation( @@ -186,118 +211,132 @@ impl SubscriptionInner { .create_operation(&self.node.private_key, LogType::Delta, self.id, None, true) .await?; - info!("Snapshot saved for document with id {}", self.id); + info!("Snapshot saved for topic with id {}", hex::encode(self.id)); if let Some(tx) = self.tx.read().await.as_ref() { - let bytes = encode_cbor(&MessageType::Persistent(PersistentOperation::new( - operation, - )))?; - - // Broadcast operation on gossip overlay. - tx.send(ToNetwork::Message { bytes }).await?; + tx.publish(operation).await?; } Ok(()) } - pub async fn send_ephemeral(&self, data: Vec) -> Result<(), DocumentError> { - if let Some(tx) = self.tx.read().await.as_ref() { + pub async fn send_ephemeral(&self, data: Vec) -> Result<(), TopicError> { + if let Some(ephemeral_tx) = self.ephemeral_tx.read().await.as_ref() { let operation = EphemerialOperation::new(data, &self.node.private_key); let bytes = encode_cbor(&MessageType::Ephemeral(operation))?; - tx.send(ToNetwork::Message { bytes }).await?; + ephemeral_tx.publish(bytes).await?; } Ok(()) } - /// Set the name for a given document + /// Set the name for a given topic /// /// This information will be written to the database - pub async fn set_name(&self, name: Option) -> Result<(), DocumentError> { + pub async fn set_name(&self, name: Option) -> Result<(), TopicError> { self.node - .document_store - .set_name_for_document(&self.id, name) + .topic_store + .set_name_for_topic(&self.id, name) .await?; Ok(()) } } -async fn setup_network( +// FIXME: return errors +async fn setup_network( node: &Arc, - network: &Network, - document_id: DocumentId, - document: &Arc, + network: &Network, + id: TopicId, + subscribable_topic: &Arc, author_tracker: &Arc>, -) -> (Option>, Vec) { +) -> ( + Option>, + Option, + Vec, +) { let mut abort_handles = Vec::with_capacity(3); - let (document_tx, mut document_rx, gossip_ready) = match network.subscribe(document_id).await { + let stream = match network.stream(id, true).await { Ok(result) => result, Err(error) => { - warn!("Failed to setup network for subscription to document {document_id}: {error}"); - return (None, abort_handles); + warn!( + "Failed to setup network for subscription to topic {}: {error}", + hex::encode(id) + ); + return (None, None, abort_handles); } }; + let mut topic_rx = stream.subscribe().await.unwrap(); + let topic_tx = stream; + let (persistent_tx, persistent_rx) = mpsc::channel::<(Header, Option, Vec)>(128); - author_tracker - .set_document_tx(Some(document_tx.clone())) - .await; - - let author_tracker_clone = author_tracker.clone(); - let document_clone = document.clone(); let abort_handle = spawn(async move { - while let Some(event) = document_rx.recv().await { - match event { - FromNetwork::GossipMessage { bytes, .. } => match decode_cbor(&bytes[..]) { - Ok(MessageType::Ephemeral(operation)) => { - if let Some((author, body)) = operation.validate_and_unpack() { - document_clone.ephemeral_bytes_received(author, body); - } else { - warn!("Got ephemeral operation with a bad signature"); + while let Ok(event) = topic_rx.recv().await { + match event.event() { + TopicLogSyncEvent::Operation(operation) => { + match validate_and_unpack(operation.as_ref().to_owned(), id) { + Ok(data) => { + persistent_tx.send(data).await.unwrap(); } - } - Ok(MessageType::AuthorEphemeral(operation)) => { - if let Some((author, body)) = operation.validate_and_unpack() { - match AuthorMessage::try_from(&body[..]) { - Ok(message) => { - author_tracker_clone.received(message, author).await; - } - Err(error) => { - warn!("Failed to deserialize AuthorMessage: {error}"); - } - } - } else { - warn!("Got internal ephemeral operation with a bad signature"); + Err(err) => { + error!("Failed to unpack operation: {err}"); } } - Ok(MessageType::Persistent(operation)) => { - match operation.validate_and_unpack(document_id) { - Ok(data) => { - persistent_tx.send(data).await.unwrap(); + } + _ => { + // TODO: Handle sync events + } + } + } + }) + .abort_handle(); + + abort_handles.push(abort_handle); + + // Generate a different id than the eventually consistent streams to avoid collisions. + // + // @TODO(adz): We want to throw an error if users try to subscribe with the same id across + // different streams. + let ephemeral_id = Hash::new(id); + let ephemeral_stream = network.ephemeral_stream(ephemeral_id.into()).await.unwrap(); + let mut ephemeral_rx = ephemeral_stream.subscribe().await.unwrap(); + let ephemeral_tx = ephemeral_stream; + + author_tracker.set_topic_tx(Some(ephemeral_tx)).await; + + let author_tracker_clone = author_tracker.clone(); + let subscribable_topic_clone = subscribable_topic.clone(); + let abort_handle = spawn(async move { + while let Ok(bytes) = ephemeral_rx.recv().await { + match decode_cbor(&bytes[..]) { + Ok(MessageType::Ephemeral(operation)) => { + if let Some((author, body)) = operation.validate_and_unpack() { + subscribable_topic_clone.ephemeral_bytes_received(author, body); + } else { + warn!("Got ephemeral operation with a bad signature"); + } + } + Ok(MessageType::AuthorEphemeral(operation)) => { + if let Some((author, body)) = operation.validate_and_unpack() { + match AuthorMessage::try_from(&body[..]) { + Ok(message) => { + author_tracker_clone.received(message, author).await; } - Err(err) => { - error!("Failed to unpack operation: {err}"); + Err(error) => { + warn!("Failed to deserialize AuthorMessage: {error}"); } } + } else { + warn!("Got internal ephemeral operation with a bad signature"); } - Err(err) => { - error!("Failed to decode gossip message: {err}"); - } - }, - FromNetwork::SyncMessage { - header, payload, .. - } => match PersistentOperation::from_serialized(header, payload) - .validate_and_unpack(document_id) - { - Ok(data) => persistent_tx.send(data).await.unwrap(), - Err(err) => { - error!("Failed to unpack operation: {err}"); - } - }, + } + Err(err) => { + error!("Failed to decode gossip message: {err}"); + } } } }) @@ -328,14 +367,14 @@ async fn setup_network( }); let node = node.clone(); - let document_clone = document.clone(); - // Send checked and ingested operations for this document to application layer. + let subscribable_topic_clone = subscribable_topic.clone(); + // Send checked and ingested operations for this topic to application layer. let abort_handle = spawn(async move { while let Some(operation) = stream.next().await { - // When we discover a new author we need to add them to our document store. + // When we discover a new author we need to add them to our topic store. if let Err(error) = node - .document_store - .add_author(&document_id, &operation.header.public_key) + .topic_store + .add_author(&id, &operation.header.public_key) .await { error!("Can't store author to database: {error}"); @@ -343,7 +382,8 @@ async fn setup_network( // Forward the payload up to the app. if let Some(body) = operation.body { - document_clone.bytes_received(operation.header.public_key, body.to_bytes()); + subscribable_topic_clone + .bytes_received(operation.header.public_key, body.to_bytes()); } } }) @@ -352,35 +392,79 @@ async fn setup_network( abort_handles.push(abort_handle); let author_tracker_clone = author_tracker.clone(); let abort_handle = spawn(async move { - // Only start track authors once we have joined the gossip overlay - if let Err(error) = gossip_ready.await { - error!("Failed to join the gossip overlay: {error}"); - } - author_tracker_clone.spawn().await; }) .abort_handle(); abort_handles.push(abort_handle); - info!("Network subscription set up for document {document_id}"); + info!("Network subscription set up for topic {}", hex::encode(id)); - (Some(document_tx), abort_handles) + let ephemeral_id = Hash::new(id); + let ephemeral_tx = network.ephemeral_stream(ephemeral_id.into()).await.unwrap(); + + (Some(topic_tx), Some(ephemeral_tx), abort_handles) } -async fn teardown_network( - document_id: &DocumentId, +async fn teardown_network( + id: &TopicId, author_tracker: &Arc>, - tx: Option>, + tx: Option>, + ephemeral_tx: Option, abort_handles: Vec, ) { for handle in abort_handles { handle.abort(); } - author_tracker.set_document_tx(None).await; + author_tracker.set_topic_tx(None).await; - if tx.is_some() { - info!("Network subscription torn down for document {document_id}"); + if let Some(ephemeral_tx) = ephemeral_tx + && let Err(error) = ephemeral_tx.close() + { + error!( + "Failed to tear down ephemeral channel for topic {}: {error}", + hex::encode(id) + ); } + + if let Some(tx) = tx { + if let Err(error) = tx.close() { + error!( + "Failed to tear down persistent channel for topic {}: {error}", + hex::encode(id) + ); + } + info!( + "Network subscription torn down for topic {}", + hex::encode(id) + ); + } +} + +type OperationWithRawHeader = (Header, Option, Vec); + +#[derive(Debug, thiserror::Error)] +pub enum UnpackError { + #[error(transparent)] + Cbor(#[from] p2panda_core::cbor::DecodeError), + #[error("Operation with invalid topic id")] + InvalidTopicId, +} + +fn validate_and_unpack( + operation: p2panda_core::Operation, + id: TopicId, +) -> Result { + let p2panda_core::Operation:: { header, body, .. } = operation; + + let Some(operation_id): Option = header.extension() else { + return Err(UnpackError::InvalidTopicId); + }; + + if operation_id != id { + return Err(UnpackError::InvalidTopicId); + } + + Ok((header.clone(), body, header.to_bytes())) } diff --git a/reflection-node/src/document.rs b/reflection-node/src/topic.rs similarity index 51% rename from reflection-node/src/document.rs rename to reflection-node/src/topic.rs index c18af595..c2319d0e 100644 --- a/reflection-node/src/document.rs +++ b/reflection-node/src/topic.rs @@ -1,72 +1,39 @@ -use std::fmt; -use std::hash::Hash; use std::sync::Arc; -use crate::node_inner::NodeInner; +use crate::operation::ReflectionExtensions; use crate::operation_store::CreationError; use crate::subscription_inner::SubscriptionInner; -use p2panda_core::PublicKey; -use p2panda_net::{ToNetwork, TopicId}; -use p2panda_sync::TopicQuery; -use serde::{Deserialize, Serialize}; +use p2panda_core::{Operation, PublicKey}; +use p2panda_net::streams::StreamError; use thiserror::Error; -use tokio::{ - sync::mpsc, - task::{AbortHandle, JoinError}, -}; +use tokio::task::{AbortHandle, JoinError}; use tracing::info; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub(crate) struct DocumentId(#[serde(with = "serde_bytes")] [u8; 32]); - -impl DocumentId { - pub const fn as_slice(&self) -> &[u8] { - self.0.as_slice() - } -} - -impl TopicQuery for DocumentId {} - -impl TopicId for DocumentId { - fn id(&self) -> [u8; 32] { - self.0 - } -} - -impl From<[u8; 32]> for DocumentId { - fn from(bytes: [u8; 32]) -> Self { - Self(bytes) - } -} - -impl From for [u8; 32] { - fn from(id: DocumentId) -> Self { - id.0 - } -} - -impl fmt::Display for DocumentId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&hex::encode(self.0)) +impl From>> for TopicError { + fn from(value: StreamError>) -> Self { + TopicError::Publish(Box::new(value)) } } #[derive(Debug, Error)] -pub enum DocumentError { +pub enum TopicError { #[error(transparent)] - DocumentStore(#[from] sqlx::Error), + TopicStore(#[from] sqlx::Error), #[error(transparent)] OperationStore(#[from] CreationError), #[error(transparent)] Encode(#[from] p2panda_core::cbor::EncodeError), #[error(transparent)] - Send(#[from] mpsc::error::SendError), + // FIXME: The error is huge so but it into a Box + Publish(Box>>), + #[error(transparent)] + PublishEphemeral(#[from] StreamError>), #[error(transparent)] Runtime(#[from] JoinError), } -pub trait SubscribableDocument: Sync + Send { +pub trait SubscribableTopic: Sync + Send { fn bytes_received(&self, author: PublicKey, data: Vec); fn author_joined(&self, author: PublicKey); fn author_left(&self, author: PublicKey); @@ -75,6 +42,7 @@ pub trait SubscribableDocument: Sync + Send { pub struct Subscription { pub(crate) inner: Arc>, + pub(crate) runtime: tokio::runtime::Handle, network_monitor_task: AbortHandle, } @@ -84,79 +52,65 @@ impl Drop for Subscription { } } -impl Subscription { - pub(crate) async fn new(node: Arc, id: DocumentId, document: Arc) -> Self { - let inner = SubscriptionInner::new(node, id, document); +impl Subscription { + pub(crate) async fn new(runtime: tokio::runtime::Handle, inner: SubscriptionInner) -> Self { + let inner = Arc::new(inner); let inner_clone = inner.clone(); - let network_monitor_task = inner - .node - .runtime + let network_monitor_task = runtime .spawn(async move { inner_clone.spawn_network_monitor().await; }) .abort_handle(); - info!("Subscribed to document {}", id); - Subscription { inner, + runtime, network_monitor_task, } } - pub async fn send_delta(&self, data: Vec) -> Result<(), DocumentError> { + pub async fn send_delta(&self, data: Vec) -> Result<(), TopicError> { let inner = self.inner.clone(); - self.inner - .node - .runtime + self.runtime .spawn(async move { inner.send_delta(data).await }) .await? } - pub async fn send_snapshot(&self, data: Vec) -> Result<(), DocumentError> { + pub async fn send_snapshot(&self, data: Vec) -> Result<(), TopicError> { let inner = self.inner.clone(); - self.inner - .node - .runtime + self.runtime .spawn(async move { inner.send_snapshot(data).await }) .await? } - pub async fn send_ephemeral(&self, data: Vec) -> Result<(), DocumentError> { + pub async fn send_ephemeral(&self, data: Vec) -> Result<(), TopicError> { let inner = self.inner.clone(); - self.inner - .node - .runtime + self.runtime .spawn(async move { inner.send_ephemeral(data).await }) .await? } - pub async fn unsubscribe(self) -> Result<(), DocumentError> { - let document_id = self.inner.id; + pub async fn unsubscribe(self) -> Result<(), TopicError> { + let id = self.inner.id; self.network_monitor_task.abort(); let inner = self.inner.clone(); - inner - .node - .clone() - .runtime + self.runtime .spawn(async move { inner.unsubscribe().await }) .await??; - info!("Unsubscribed from document {}", document_id); + info!("Unsubscribed from topic {}", hex::encode(id)); Ok(()) } - /// Set the name for a given document + /// Set the name for a given topic /// /// This information will be written to the database - pub async fn set_name(&self, name: Option) -> Result<(), DocumentError> { + pub async fn set_name(&self, name: Option) -> Result<(), TopicError> { let inner = self.inner.clone(); - self.inner - .node - .runtime + self.runtime .spawn(async move { inner.set_name(name).await }) .await? } diff --git a/reflection-node/src/document_store.rs b/reflection-node/src/topic_store.rs similarity index 51% rename from reflection-node/src/document_store.rs rename to reflection-node/src/topic_store.rs index 26760bd5..6d33a9bb 100644 --- a/reflection-node/src/document_store.rs +++ b/reflection-node/src/topic_store.rs @@ -1,28 +1,22 @@ use std::collections::HashMap; use std::hash::Hash as StdHash; -use async_trait::async_trait; use chrono::{DateTime, Utc}; use p2panda_core::PublicKey; +use p2panda_net::TopicId; use p2panda_store::LogStore; -use p2panda_sync::log_sync::TopicLogMap; +use p2panda_sync::{log_sync::Logs, topic_log_sync::TopicLogMap}; use serde::{Deserialize, Serialize}; -use sqlx::{ - Decode, Encode, FromRow, Row, Sqlite, Type, - encode::IsNull, - error::BoxDynError, - sqlite::{SqliteArgumentValue, SqliteTypeInfo, SqliteValueRef}, -}; +use sqlx::{FromRow, Row}; use tracing::error; -use crate::document::DocumentId; use crate::operation::{LogType, ReflectionExtensions}; use crate::operation_store::OperationStore; #[derive(Debug, FromRow)] -pub struct StoreDocument { - #[sqlx(rename = "document_id")] - pub id: DocumentId, +pub struct StoreTopic { + #[sqlx(try_from = "Vec")] + pub id: TopicId, #[sqlx(default)] pub name: Option, pub last_accessed: Option>, @@ -36,46 +30,19 @@ pub struct Author { pub last_seen: Option>, } -impl Type for DocumentId { - fn type_info() -> SqliteTypeInfo { - <&[u8] as Type>::type_info() - } - - fn compatible(ty: &SqliteTypeInfo) -> bool { - <&[u8] as Type>::compatible(ty) - } -} - -impl<'q> Encode<'q, Sqlite> for &'q DocumentId { - fn encode_by_ref( - &self, - args: &mut Vec>, - ) -> Result { - <&[u8] as Encode>::encode_by_ref(&self.as_slice(), args) - } -} - -impl Decode<'_, Sqlite> for DocumentId { - fn decode(value: SqliteValueRef<'_>) -> Result { - let value = <&[u8] as Decode>::decode(value)?; - - Ok(DocumentId::from(TryInto::<[u8; 32]>::try_into(value)?)) - } -} - #[derive(Clone, Debug)] -pub struct DocumentStore { +pub struct TopicStore { pool: sqlx::SqlitePool, } -impl DocumentStore { +impl TopicStore { pub fn new(pool: sqlx::SqlitePool) -> Self { Self { pool } } - async fn authors(&self, document_id: &DocumentId) -> sqlx::Result> { - let list = sqlx::query("SELECT public_key FROM authors WHERE document_id = ?") - .bind(document_id) + async fn authors(&self, id: &TopicId) -> sqlx::Result> { + let list = sqlx::query("SELECT public_key FROM authors WHERE topic_id = ?") + .bind(id.as_slice()) .fetch_all(&self.pool) .await?; @@ -85,17 +52,17 @@ impl DocumentStore { .collect()) } - pub async fn documents(&self) -> sqlx::Result> { - let mut documents: Vec = - sqlx::query_as("SELECT document_id, name, last_accessed FROM documents") + pub async fn topics(&self) -> sqlx::Result> { + let mut topics: Vec = + sqlx::query_as("SELECT id, name, last_accessed FROM topics") .fetch_all(&self.pool) .await?; - let authors = sqlx::query("SELECT public_key, document_id, last_seen FROM authors") + let authors = sqlx::query("SELECT public_key, topic_id, last_seen FROM authors") .fetch_all(&self.pool) .await?; - let mut authors_per_document = authors.iter().fold(HashMap::new(), |mut acc, row| { - let Ok(document_id) = row.try_get::("document_id") else { + let mut authors_per_topic = authors.iter().fold(HashMap::new(), |mut acc, row| { + let Ok(id) = TopicId::try_from(row.get::<&[u8], _>("topic_id")) else { return acc; }; let Ok(public_key) = PublicKey::try_from(row.get::<&[u8], _>("public_key")) else { @@ -104,62 +71,56 @@ impl DocumentStore { let Ok(last_seen) = row.try_get::>, _>("last_seen") else { return acc; }; - acc.entry(document_id) - .or_insert_with(Vec::new) - .push(Author { - public_key, - last_seen, - }); + acc.entry(id).or_insert_with(Vec::new).push(Author { + public_key, + last_seen, + }); acc }); - for document in &mut documents { - if let Some(authors) = authors_per_document.remove(&document.id) { - document.authors = authors; + for topic in &mut topics { + if let Some(authors) = authors_per_topic.remove(&topic.id) { + topic.authors = authors; } } - Ok(documents) + Ok(topics) } - pub async fn add_document(&self, document_id: &DocumentId) -> sqlx::Result<()> { - // The document_id is the primary key in the table therefore ignore insertion when the document exists already + pub async fn add_topic(&self, id: &TopicId) -> sqlx::Result<()> { + // The id is the primary key in the table therefore ignore insertion when the topic exists already sqlx::query( " - INSERT OR IGNORE INTO documents ( document_id ) + INSERT OR IGNORE INTO topics ( id ) VALUES ( ? ) ", ) - .bind(document_id) + .bind(id.as_slice()) .execute(&self.pool) .await?; Ok(()) } - pub async fn delete_document(&self, document_id: &DocumentId) -> sqlx::Result<()> { - sqlx::query("DELETE FROM documents WHERE document_id = ?") - .bind(document_id) + pub async fn delete_topic(&self, id: &TopicId) -> sqlx::Result<()> { + sqlx::query("DELETE FROM topics WHERE id = ?") + .bind(id.as_slice()) .execute(&self.pool) .await?; Ok(()) } - pub async fn add_author( - &self, - document_id: &DocumentId, - public_key: &PublicKey, - ) -> sqlx::Result<()> { - // The author/document_id pair is required to be unique therefore ignore if the insertion fails + pub async fn add_author(&self, id: &TopicId, public_key: &PublicKey) -> sqlx::Result<()> { + // The author/id pair is required to be unique therefore ignore if the insertion fails sqlx::query( " - INSERT OR IGNORE INTO authors ( public_key, document_id ) + INSERT OR IGNORE INTO authors ( public_key, topic_id ) VALUES ( ?, ? ) ", ) .bind(public_key.as_bytes().as_slice()) - .bind(document_id) + .bind(id.as_slice()) .execute(&self.pool) .await?; @@ -186,57 +147,53 @@ impl DocumentStore { Ok(()) } - pub async fn set_name_for_document( - &self, - document_id: &DocumentId, - name: Option, - ) -> sqlx::Result<()> { + pub async fn set_name_for_topic(&self, id: &TopicId, name: Option) -> sqlx::Result<()> { sqlx::query( " - UPDATE documents + UPDATE topics SET name = ? - WHERE document_id = ? + WHERE id = ? ", ) .bind(name) - .bind(document_id) + .bind(id.as_slice()) .execute(&self.pool) .await?; Ok(()) } - pub async fn set_last_accessed_for_document( + pub async fn set_last_accessed_for_topic( &self, - document_id: &DocumentId, + id: &TopicId, last_accessed: Option>, ) -> sqlx::Result<()> { sqlx::query( " - UPDATE documents + UPDATE topics SET last_accessed = ? - WHERE document_id = ? + WHERE id = ? ", ) .bind(last_accessed) - .bind(document_id) + .bind(id.as_slice()) .execute(&self.pool) .await?; Ok(()) } - pub async fn operations_for_document( + pub async fn operations_for_topic( &self, operation_store: &OperationStore, - document_id: &DocumentId, + id: &TopicId, ) -> sqlx::Result>> { let operation_store = operation_store.inner(); - let authors = self.authors(document_id).await?; + let authors = self.authors(id).await?; let log_ids = [ - LogId::new(LogType::Delta, document_id), - LogId::new(LogType::Snapshot, document_id), + LogId::new(LogType::Delta, id), + LogId::new(LogType::Snapshot, id), ]; let mut result = Vec::new(); @@ -273,29 +230,27 @@ impl DocumentStore { } #[derive(Clone, Debug, PartialEq, Eq, StdHash, Serialize, Deserialize)] -pub struct LogId(LogType, DocumentId); +pub struct LogId(LogType, TopicId); impl LogId { - pub fn new(log_type: LogType, document: &DocumentId) -> Self { - Self(log_type, *document) + pub fn new(log_type: LogType, topic: &TopicId) -> Self { + Self(log_type, *topic) } } -#[async_trait] -impl TopicLogMap for DocumentStore { - async fn get(&self, topic: &DocumentId) -> Option>> { - let Ok(authors) = self.authors(topic).await else { - return None; - }; +impl TopicLogMap for TopicStore { + type Error = sqlx::Error; + + async fn get(&self, topic: &TopicId) -> Result, Self::Error> { + let authors = self.authors(topic).await?; + let log_ids = [ LogId::new(LogType::Delta, topic), LogId::new(LogType::Snapshot, topic), ]; - Some( - authors - .into_iter() - .map(|author| (author, log_ids.to_vec())) - .collect(), - ) + Ok(authors + .into_iter() + .map(|author| (author, log_ids.to_vec())) + .collect()) } } diff --git a/scripts/build_macos.sh b/scripts/build_macos.sh new file mode 100755 index 00000000..5b671832 --- /dev/null +++ b/scripts/build_macos.sh @@ -0,0 +1,252 @@ +#!/bin/bash + +# Copyright 2024 The Reflection Developers +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# SPDX-License-Identifier: GPL-3.0-or-later + +set -e + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +echo -e "${GREEN}๐Ÿ—๏ธ Reflection Build Script${NC}" + +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +# Initialize flags +CREATE_APP_BUNDLE=false +CREATE_DMG=false +CREATE_CLEAN=false +BUILD_TYPE="debug" +ARCH=$(uname -m) +# Parse command line arguments +while [[ "$#" -gt 0 ]]; do + case $1 in + --help|-h) + echo "Usage: $0 [options]" + echo "Options:" + echo " --app-bundle Create macOS .app bundle" + echo " --dmg Create DMG installer" + echo " --clean Clean build directory before building" + echo " --release Build in release mode" + echo " --arch ARCH Target architecture (default: $(uname -m))" + echo " --help, -h Show this help message" + exit 0 + ;; + --app-bundle) CREATE_APP_BUNDLE=true ;; + --dmg) CREATE_DMG=true ;; + --clean) CREATE_CLEAN=true ;; + --release) BUILD_TYPE="release" ;; + --arch) ARCH="$2"; shift ;; + *) echo "Unknown parameter passed: $1"; exit 1 ;; + esac + shift +done + +# Determine if we need to cross-compile based on target architecture +if [ "$ARCH" != "$(uname -m)" ]; then + CROSS_COMPILE=true + echo -e "${YELLOW}๐Ÿ‘ฝ Cross-compiling for $ARCH architecture${NC}" +else + CROSS_COMPILE=false +fi + + +# Ask before installing dependencies unless in CI +if [ -z "$CI" ]; then + read -p "Please confirm you want to install dependencies, build and install Reflection (y/n) " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo -e "${RED}โŒ Aborting...${NC}" + exit 1 + fi +fi + +# Check if Homebrew is installed +if ! command_exists brew; then + echo -e "${RED}โŒ Homebrew not found. Please install it first.${NC}" + exit 1 +fi + +if [ "$CROSS_COMPILE" = true ]; then + BREW_ARCH_CMD="arch -$ARCH brew" +else + BREW_ARCH_CMD="brew" +fi + +# Install dependencies +echo -e "${BLUE}๐Ÿ“ฆ Installing/updating dependencies...${NC}" +if ! $BREW_ARCH_CMD bundle; then + echo -e "${YELLOW}โš ๏ธ brew bundle failed, attempting to resolve Python linking conflicts...${NC}" + + # Try to force link python if it exists but isn't linked + if brew list python@3.13 &> /dev/null; then + echo -e "${YELLOW}๐Ÿ”— Force linking Python...${NC}" + $BREW_ARCH_CMD link --overwrite python@3.13 || true + fi + + # Retry brew bundle + echo -e "${YELLOW}๐Ÿ”„ Retrying brew bundle...${NC}" + if ! $BREW_ARCH_CMD bundle; then + echo -e "${RED}โŒ brew bundle failed again. Please check the dependencies.${NC}" + exit 1 + fi +fi + +# Set up environment for system libraries +export PKG_CONFIG_PATH="$HOMEBREW_PREFIX/lib/pkgconfig:$PKG_CONFIG_PATH" +export GETTEXT_SYSTEM=1 +export GETTEXT_DIR="$HOMEBREW_PREFIX" +export GETTEXT_LIB_DIR="$HOMEBREW_PREFIX/lib" +export GETTEXT_INCLUDE_DIR="$HOMEBREW_PREFIX/include" + +echo -e "${BLUE}โš™๏ธ Configuring build with Meson...${NC}" + +# Only remove builddir if explicitly requested +if [ "$CREATE_CLEAN" = true ]; then + echo -e "${YELLOW}๐Ÿงน Clean build requested, removing builddir...${NC}" + rm -rf builddir +fi + +if [ ! -d "builddir" ]; then + BUILD_ARGS=( + --buildtype=$BUILD_TYPE \ + --prefix="$(pwd)/install" \ + -Dmacos_bundle=true + ) + if [ "$CROSS_COMPILE" = true ]; then + BUILD_ARGS+=(--cross-file="$(pwd)/$ARCH-darwin-cross.txt") + fi + meson setup builddir "${BUILD_ARGS[@]}" +else + echo -e "${YELLOW}๐Ÿ“ Using existing builddir (use --clean for clean build)${NC}" +fi + +# Build the project +echo -e "${BLUE}๐Ÿ”จ Building Reflection...${NC}" +meson compile -C builddir + +# Install to local directory +echo -e "${BLUE}๐Ÿ“ฆ Installing to local directory...${NC}" +meson install -C builddir + +echo -e "${GREEN}โœ… Build completed successfully!${NC}" + +echo -e "${GREEN}๐Ÿ“‹ Built for: $ARCH${NC}" + +# Optional: Create macOS app bundle +if [ "$CREATE_APP_BUNDLE" = true ]; then + echo -e "${BLUE}๐Ÿ“ฑ Creating app bundle...${NC}" + + # Find the installed binary + BINARY_PATH="install/bin/reflection" + if [ ! -f "$BINARY_PATH" ]; then + echo -e "${RED}โŒ Binary not found at $BINARY_PATH${NC}" + exit 1 + fi + + # Create app bundle structure + rm -rf Reflection.app + mkdir -p Reflection.app/Contents/{MacOS,Resources,Frameworks} + + # Copy binary + cp "$BINARY_PATH" Reflection.app/Contents/MacOS/ + + # Copy resources if they exist + if [ -d "install/share" ]; then + cp -r install/share Reflection.app/Contents/Resources/ + fi + + # Create Info.plist + cat > Reflection.app/Contents/Info.plist << 'EOF' + + + + + CFBundleExecutable + reflection + CFBundleIdentifier + org.p2panda.reflection + CFBundleName + Reflection + CFBundleDisplayName + Reflection + CFBundlePackageType + APPL + CFBundleShortVersionString + 0.1.0 + CFBundleVersion + 1 + LSMinimumSystemVersion + 10.15 + CFBundleSupportedPlatforms + + MacOSX + + NSHighResolutionCapable + + + +EOF + + # Bundle dependencies + echo -e "${BLUE}๐Ÿ”— Bundling dependencies...${NC}" + dylibbundler -od -b -x Reflection.app/Contents/MacOS/reflection \ + -d Reflection.app/Contents/Frameworks/ \ + -p @executable_path/../Frameworks/ > /dev/null 2>&1 || echo -e "${YELLOW}โš ๏ธ Some libraries may not be bundled${NC}" + + echo -e "${GREEN}โœ… App bundle created: Reflection.app${NC}" + + # Optional: Create DMG + if [ "$CREATE_DMG" = true ]; then + if command_exists create-dmg; then + echo -e "${BLUE}๐Ÿ’ฟ Creating DMG...${NC}" + rm -f "reflection-$ARCH.dmg" + create-dmg \ + --volname "Reflection" \ + --window-pos 200 120 \ + --window-size 600 400 \ + --icon-size 100 \ + --icon "Reflection.app" 175 120 \ + --hide-extension "Reflection.app" \ + --app-drop-link 425 120 \ + "reflection-$ARCH.dmg" \ + "Reflection.app" + echo -e "${GREEN}โœ… DMG created: reflection-$ARCH.dmg${NC}" + else + echo -e "${YELLOW}โš ๏ธ create-dmg command not found. Skipping DMG creation.${NC}" + fi + fi +fi + +echo -e " Direct: ${BLUE}./install/bin/reflection${NC}" + +if [ "$CREATE_APP_BUNDLE" = true ]; then + if [ -d "Reflection.app" ]; then + echo -e " App bundle: ${BLUE}open Reflection.app${NC}" + fi +fi + +if [ "$CREATE_DMG" = true ]; then + if [ -f "reflection-$ARCH.dmg" ]; then + echo -e " DMG: ${BLUE}open \"reflection-$ARCH.dmg\"${NC}" + fi +fi \ No newline at end of file diff --git a/x86_64-darwin-cross.txt b/x86_64-darwin-cross.txt new file mode 100644 index 00000000..86ab85eb --- /dev/null +++ b/x86_64-darwin-cross.txt @@ -0,0 +1,11 @@ +[binaries] +c = ['clang', '-target', 'x86_64-apple-darwin'] +cpp = ['clang++', '-target', 'x86_64-apple-darwin'] +rust = ['rustc', '--target', 'x86_64-apple-darwin'] +pkgconfig = 'pkg-config' + +[host_machine] +system = 'darwin' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little'