From 6aea1c486c284039c399e83427e465fa17899588 Mon Sep 17 00:00:00 2001 From: Joshua Parkin Date: Tue, 10 Oct 2023 11:55:50 +0100 Subject: [PATCH] add back old holochain only link language --- .../p-diff-sync-socket-signaling/.gitignore | 19 + .../p-diff-sync-socket-signaling/README.md | 3 + .../p-diff-sync-socket-signaling/esbuild.ts | 39 + .../hc-dna/Cargo.lock | 2795 +++++++++++++++++ .../hc-dna/Cargo.toml | 11 + .../hc-dna/build.ps1 | 2 + .../hc-dna/build.sh | 3 + .../hc-dna/default.nix | 14 + .../hc-dna/holochain_version.nix | 20 + .../hc-dna/nix/sources.json | 14 + .../hc-dna/nix/sources.nix | 174 + .../hc-dna/workdir/dna.yaml | 21 + .../zomes/perspective_diff_sync/Cargo.toml | 28 + .../zomes/perspective_diff_sync/src/errors.rs | 25 + .../zomes/perspective_diff_sync/src/inputs.rs | 29 + .../zomes/perspective_diff_sync/src/lib.rs | 195 ++ .../src/link_adapter/chunked_diffs.rs | 207 ++ .../src/link_adapter/commit.rs | 171 + .../src/link_adapter/mod.rs | 10 + .../src/link_adapter/pull.rs | 846 +++++ .../src/link_adapter/render.rs | 42 + .../src/link_adapter/revisions.rs | 32 + .../src/link_adapter/snapshots.rs | 264 ++ .../src/link_adapter/test_graphs.rs | 1495 +++++++++ .../src/link_adapter/tests.rs | 103 + .../src/link_adapter/topo_sort.rs | 143 + .../src/link_adapter/workspace.rs | 1427 +++++++++ .../perspective_diff_sync/src/retriever.rs | 35 + .../src/retriever/holochain.rs | 199 ++ .../src/retriever/mock.rs | 530 ++++ .../src/telepresence/mod.rs | 2 + .../src/telepresence/signal.rs | 30 + .../src/telepresence/status.rs | 232 ++ .../zomes/perspective_diff_sync/src/utils.rs | 46 + .../Cargo.toml | 18 + .../src/impls.rs | 68 + .../src/lib.rs | 169 + .../hc-dna/zomes/tests/common.ts | 6 + .../zomes/tests/download-hc-binaries.sh | 14 + .../hc-dna/zomes/tests/index.ts | 49 + .../hc-dna/zomes/tests/package.json | 40 + .../hc-dna/zomes/tests/pull.ts | 273 ++ .../hc-dna/zomes/tests/queue.ts | 82 + .../hc-dna/zomes/tests/render.ts | 270 ++ .../hc-dna/zomes/tests/revisions.ts | 92 + .../hc-dna/zomes/tests/signals.ts | 106 + .../hc-dna/zomes/tests/stress.ts | 355 +++ .../hc-dna/zomes/tests/telepresence.ts | 172 + .../hc-dna/zomes/tests/tsconfig.json | 16 + .../hc-dna/zomes/tests/utils.ts | 86 + .../hc-dna/zomes/tests/yarn.lock | 1833 +++++++++++ .../p-diff-sync-socket-signaling/index.ts | 59 + .../integration-test.js | 20 + .../linksAdapter.ts | 378 +++ .../p-diff-sync-socket-signaling/package.json | 43 + .../rollup.config.hc-dna.js | 71 + .../telepresenceAdapter.ts | 39 + .../tsconfig.json | 8 + bootstrap-languages/p-diff-sync/esbuild.ts | 19 +- .../zomes/perspective_diff_sync/src/lib.rs | 14 - .../src/link_adapter/commit.rs | 37 +- .../src/link_adapter/pull.rs | 2 +- bootstrap-languages/p-diff-sync/index.ts | 5 +- .../p-diff-sync/linksAdapter.ts | 104 +- bootstrap-languages/p-diff-sync/package.json | 2 +- cli/seed_proto.json | 11 +- turbo.json | 2 +- 67 files changed, 13503 insertions(+), 166 deletions(-) create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/.gitignore create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/README.md create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/esbuild.ts create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/Cargo.lock create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/Cargo.toml create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/build.ps1 create mode 100755 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/build.sh create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/default.nix create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/holochain_version.nix create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/nix/sources.json create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/nix/sources.nix create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/workdir/dna.yaml create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/Cargo.toml create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/errors.rs create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/inputs.rs create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/lib.rs create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/chunked_diffs.rs create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/commit.rs create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/mod.rs create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/pull.rs create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/render.rs create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/revisions.rs create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/snapshots.rs create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/test_graphs.rs create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/tests.rs create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/topo_sort.rs create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/workspace.rs create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/retriever.rs create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/retriever/holochain.rs create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/retriever/mock.rs create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/telepresence/mod.rs create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/telepresence/signal.rs create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/telepresence/status.rs create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/utils.rs create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync_integrity/Cargo.toml create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync_integrity/src/impls.rs create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync_integrity/src/lib.rs create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/common.ts create mode 100755 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/download-hc-binaries.sh create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/index.ts create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/package.json create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/pull.ts create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/queue.ts create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/render.ts create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/revisions.ts create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/signals.ts create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/stress.ts create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/telepresence.ts create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/tsconfig.json create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/utils.ts create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/yarn.lock create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/index.ts create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/integration-test.js create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/linksAdapter.ts create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/package.json create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/rollup.config.hc-dna.js create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/telepresenceAdapter.ts create mode 100644 bootstrap-languages/p-diff-sync-socket-signaling/tsconfig.json diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/.gitignore b/bootstrap-languages/p-diff-sync-socket-signaling/.gitignore new file mode 100644 index 000000000..d302556a5 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/.gitignore @@ -0,0 +1,19 @@ +.cargo +target +hc-dna/workdir/perspective-diff-sync.dna +hc-dna/zomes/tests/node_modules +hc-dna/zomes/tests/out.log +node_modules +.hc* +perspect-diff-sync.dna +*.log +.turbo + +*.js +*.js.map +!rollup.config* +!.dna.js +!integration-test.js + +.ad4m-test +ad4m-test-* \ No newline at end of file diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/README.md b/bootstrap-languages/p-diff-sync-socket-signaling/README.md new file mode 100644 index 000000000..dadc2cd48 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/README.md @@ -0,0 +1,3 @@ +# Perspective Diff Sync + +Git like holochain syncing DNA for sharing of mutation to a shared perspective. \ No newline at end of file diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/esbuild.ts b/bootstrap-languages/p-diff-sync-socket-signaling/esbuild.ts new file mode 100644 index 000000000..e479a51dd --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/esbuild.ts @@ -0,0 +1,39 @@ +import * as esbuild from "https://deno.land/x/esbuild@v0.17.18/mod.js"; +// Import the WASM build on platforms where running subprocesses is not +// permitted, such as Deno Deploy, or when running without `--allow-run`. +// import * as esbuild from "https://deno.land/x/esbuild@v0.17.18/wasm.js"; + +import { denoPlugins } from "https://deno.land/x/esbuild_deno_loader@0.7.0/mod.ts"; +import { loadSource, resolveUrl } from "./customHttpDownloader.js"; + +const result = await esbuild.build({ + plugins: [ + { + name: `buffer-alias`, + setup(build) { + build.onResolve({ filter: new RegExp(`^buffer$`) }, (args) => { + return { path: `https://deno.land/std@0.177.0/node/buffer.ts`, namespace: 'imports' }; + }); + + build.onResolve({filter: /.*/, namespace: 'imports'}, resolveUrl) + + build.onLoad({filter: /.*/, namespace: 'imports'}, (args) => { + return loadSource(args) + }) + }, + }, + ...denoPlugins() + ], + entryPoints: ['index.ts'], + outfile: 'build/bundle.js', + bundle: true, + platform: 'node', + target: 'deno1.32.4', + format: 'esm', + globalName: 'perspective.diff.sync.language', + charset: 'ascii', + legalComments: 'inline' +}); +console.log(result.outputFiles); + +esbuild.stop(); \ No newline at end of file diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/Cargo.lock b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/Cargo.lock new file mode 100644 index 000000000..7482a52c9 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/Cargo.lock @@ -0,0 +1,2795 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" +dependencies = [ + "addr2line", + "cc", + "cfg-if 1.0.0", + "libc", + "miniz_oxide", + "object 0.29.0", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "blake2b_simd" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + +[[package]] +name = "block-buffer" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" + +[[package]] +name = "bytecheck" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d11cac2c12b5adc6570dad2ee1b87eff4955dac476fe12d81e5fdd352e52406f" +dependencies = [ + "bytecheck_derive", + "ptr_meta", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13e576ebe98e605500b3c8041bb888e966653577172df6dd97398714eb30b9bf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "camino" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c77df041dc383319cc661b428b6961a005db4d6808d5e12536931b1ca9556055" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08a1ec454bc3eead8719cb56e15dbbfecdbc14e4b3a3ae4936cc6e31f5fc0d07" +dependencies = [ + "camino", + "cargo-platform", + "semver 1.0.13", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" +dependencies = [ + "iana-time-zone", + "num-integer", + "num-traits", + "serde", + "time", + "winapi", +] + +[[package]] +name = "colored" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "corosensei" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9847f90f32a50b0dcbd68bc23ff242798b13080b97b0569f6ed96a45ce4cf2cd" +dependencies = [ + "autocfg", + "cfg-if 1.0.0", + "libc", + "scopeguard", + "windows-sys 0.33.0", +] + +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "cranelift-bforest" +version = "0.82.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38faa2a16616c8e78a18d37b4726b98bfd2de192f2fdc8a39ddf568a408a0f75" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-codegen" +version = "0.82.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26f192472a3ba23860afd07d2b0217dc628f21fcc72617aa1336d98e1671f33b" +dependencies = [ + "cranelift-bforest", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-entity", + "gimli", + "log", + "regalloc", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.82.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f32ddb89e9b89d3d9b36a5b7d7ea3261c98235a76ac95ba46826b8ec40b1a24" +dependencies = [ + "cranelift-codegen-shared", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.82.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01fd0d9f288cc1b42d9333b7a776b17e278fc888c28e6a0f09b5573d45a150bc" + +[[package]] +name = "cranelift-entity" +version = "0.82.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3bfe172b83167604601faf9dc60453e0d0a93415b57a9c4d1a7ae6849185cf" + +[[package]] +name = "cranelift-frontend" +version = "0.82.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a006e3e32d80ce0e4ba7f1f9ddf66066d052a8c884a110b91d05404d6ce26dce" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1" +dependencies = [ + "autocfg", + "cfg-if 1.0.0", + "crossbeam-utils", + "memoffset", + "once_cell", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" +dependencies = [ + "cfg-if 1.0.0", + "once_cell", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "darling" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core 0.13.4", + "darling_macro 0.13.4", +] + +[[package]] +name = "darling" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4529658bdda7fd6769b8614be250cdcfc3aeb0ee72fe66f9e41e5e5eb73eac02" +dependencies = [ + "darling_core 0.14.1", + "darling_macro 0.14.1", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "darling_core" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "649c91bc01e8b1eac09fb91e8dbc7d517684ca6be8ebc75bb9cafc894f9fdb6f" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core 0.13.4", + "quote", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc69c5bfcbd2fc09a0f38451d2daf0e372e367986a83906d1b0dbc88134fb5" +dependencies = [ + "darling_core 0.14.1", + "quote", + "syn", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn", +] + +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dot-generator" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322e00783838d540a6288c25ae085983750521fb8cca82fc653eb2457c369565" +dependencies = [ + "dot-structures", +] + +[[package]] +name = "dot-generator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aaac7ada45f71873ebce336491d1c1bc4a7c8042c7cea978168ad59e805b871" +dependencies = [ + "dot-structures", +] + +[[package]] +name = "dot-structures" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "545da7d6df7f8fd0de7106669a7d0bfa3dbcfa24d81da46906ad658188b2ff7c" + +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + +[[package]] +name = "either" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" + +[[package]] +name = "enum-iterator" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eeac5c5edb79e4e39fe8439ef35207780a11f69c52cbe424ce3dfad4cb78de6" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c134c37760b27a871ba422106eedbb8247da973a09e82558bf26d619c882b159" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "enumset" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4799cdb24d48f1f8a7a98d06b7fde65a85a2d1e42b25a889f5406aa1fbefe074" +dependencies = [ + "enumset_derive", +] + +[[package]] +name = "enumset_derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea83a3fbdc1d999ccfbcbee717eab36f8edf2d71693a23ce0d7cca19e085304c" +dependencies = [ + "darling 0.13.4", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fastrand" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +dependencies = [ + "instant", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "futures" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "531ac96c6ff5fd7c62263c5e3c67a603af4fcaee2e1a0ae5565ba3a11e69e549" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-executor" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1997dd9df74cdac935c76252744c1ed5794fac083242ea4fe77ef3ed60ba0f83" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-macro" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb14ed937631bd8b8b8977f2c198443447a8355b6e3ca599f38c975e5a963b6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-util" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "gcollections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f551fdf23ef80329f754919669147a71c67b6cfe3569cd93b6fabdd62044377" +dependencies = [ + "bit-set", + "num-integer", + "num-traits", + "trilean", +] + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "gimli" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] + +[[package]] +name = "graphviz-rust" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a478d6485a680dcea01e3deba796c01866d63dabf06a20df4f969aaa1bac3f43" +dependencies = [ + "dot-generator 0.2.0", + "dot-structures", + "into-attr", + "into-attr-derive", + "pest", + "pest_derive", + "rand", + "tempfile", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "hdi" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b12f620a0d22b7dcd534a849f0024b0b47c4343b15f1c0ec02e37f4990f6f16" +dependencies = [ + "hdk_derive", + "holo_hash", + "holochain_integrity_types", + "holochain_wasmer_guest", + "paste", + "serde", + "serde_bytes", + "tracing", + "tracing-core", +] + +[[package]] +name = "hdk" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d50da8f292a1b819ae6a7651e9c3cb2ec97f00729125ad9ec3d31df8154eef7" +dependencies = [ + "getrandom", + "hdi", + "hdk_derive", + "holo_hash", + "holochain_wasmer_guest", + "holochain_zome_types", + "paste", + "serde", + "serde_bytes", + "thiserror", + "tracing", + "tracing-core", +] + +[[package]] +name = "hdk_derive" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc855dc170fec9ca44d2b21cba90fb961ef92acadaae0f0c7d090312a6212552" +dependencies = [ + "darling 0.14.1", + "heck", + "holochain_integrity_types", + "paste", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "holo_hash" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a5aa5c7b7c2d99ba6769e58ead10d5d4ead9036724a54a7fcea1c0203aac00e" +dependencies = [ + "base64", + "blake2b_simd", + "derive_more", + "holochain_serialized_bytes", + "holochain_util", + "holochain_wasmer_common", + "kitsune_p2p_dht_arc", + "serde", + "serde_bytes", + "thiserror", +] + +[[package]] +name = "holochain_integrity_types" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdfffeca0c6dea328a1ff7097946a951035dd137f4b9ad0db00f5377cd6c9326" +dependencies = [ + "holo_hash", + "holochain_serialized_bytes", + "holochain_util", + "kitsune_p2p_dht", + "kitsune_p2p_timestamp", + "paste", + "serde", + "serde_bytes", + "subtle", + "tracing", +] + +[[package]] +name = "holochain_serialized_bytes" +version = "0.0.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9805b3e01e7b5c144782a0823db4dc895fec18a9ccd45a492ce7c7bf157a9e38" +dependencies = [ + "holochain_serialized_bytes_derive", + "rmp-serde", + "serde", + "serde-transcode", + "serde_bytes", + "serde_json", + "thiserror", +] + +[[package]] +name = "holochain_serialized_bytes_derive" +version = "0.0.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1077232d0c427d64feb9e138fa22800e447eafb1810682d6c13beb95333cb32c" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "holochain_util" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c507f39c150414b64bb2fe8da311dc4e925435be887f8dfc3a97f8183d829878" +dependencies = [ + "cfg-if 0.1.10", + "derive_more", + "dunce", + "futures", + "num_cpus", + "once_cell", +] + +[[package]] +name = "holochain_wasmer_common" +version = "0.0.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "223daec7ca62d4e36841a99d8799b29cc616f5976ad0e2975e6ca6810de8f14f" +dependencies = [ + "holochain_serialized_bytes", + "serde", + "serde_bytes", + "test-fuzz", + "thiserror", + "wasmer", + "wasmer-engine", +] + +[[package]] +name = "holochain_wasmer_guest" +version = "0.0.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92b2026e44595cb16108464973622577936605582aa22932933a5130ad32ce42" +dependencies = [ + "holochain_serialized_bytes", + "holochain_wasmer_common", + "parking_lot", + "paste", + "serde", + "tracing", +] + +[[package]] +name = "holochain_zome_types" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b77f5caa760c7b34019739fb3b0a986a235fa0a09086b8eaff8cf7a72a2a6ce" +dependencies = [ + "holo_hash", + "holochain_integrity_types", + "holochain_serialized_bytes", + "holochain_wasmer_common", + "kitsune_p2p_bin_data", + "kitsune_p2p_block", + "kitsune_p2p_dht", + "kitsune_p2p_timestamp", + "paste", + "serde", + "serde_bytes", + "subtle", + "thiserror", + "tracing", +] + +[[package]] +name = "home" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "747309b4b440c06d57b0b25f2aee03ee9b5e5397d288c60e21fc709bb98a7408" +dependencies = [ + "winapi", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c495f162af0bf17656d0014a0eded5f3cd2f365fdd204548c2869db89359dc7" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "js-sys", + "once_cell", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "if_chain" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" + +[[package]] +name = "indexmap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "intervallum" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ccecd834666f695ecec3ff0d5fc32e32c91abea91a28fd0aceb4b35a82cee1" +dependencies = [ + "bit-set", + "gcollections", + "num-integer", + "num-traits", + "trilean", +] + +[[package]] +name = "into-attr" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6ec0dd848c05d2695dd73818984fb156ac8cbcbfdf4e474243590bfcc2468e9" +dependencies = [ + "dot-structures", +] + +[[package]] +name = "into-attr-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b88c3c684271aa7810934ae69a0b904c59f478cb551f3f388cc1c384f0c3145" +dependencies = [ + "dot-generator 0.1.0", + "dot-structures", + "into-attr", + "quote", + "syn", +] + +[[package]] +name = "itertools" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" + +[[package]] +name = "js-sys" +version = "0.3.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "kitsune_p2p_bin_data" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0b2032c0ee5683bc4d4c7c705f545992655bd5dc6235e62d0f916197a5c0af" +dependencies = [ + "base64", + "derive_more", + "holochain_util", + "kitsune_p2p_dht_arc", + "serde", + "serde_bytes", + "shrinkwraprs", +] + +[[package]] +name = "kitsune_p2p_block" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e15586a9b4f1ec2190d1b92b706995f15a871003955548e6be434cadd75413dd" +dependencies = [ + "kitsune_p2p_bin_data", + "kitsune_p2p_timestamp", + "serde", + "serde_bytes", +] + +[[package]] +name = "kitsune_p2p_dht" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf6ff683970365a1c3b71192a116abeb986512ced906e4e25cc7ad40bf65b1b3" +dependencies = [ + "colored", + "derivative", + "derive_more", + "futures", + "gcollections", + "intervallum", + "kitsune_p2p_dht_arc", + "kitsune_p2p_timestamp", + "must_future", + "num-traits", + "once_cell", + "rand", + "serde", + "statrs", + "thiserror", + "tracing", +] + +[[package]] +name = "kitsune_p2p_dht_arc" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f71f358459319708884f9295f122cb7b69a8589300fb232b573a36af04d0a7bc" +dependencies = [ + "derive_more", + "gcollections", + "intervallum", + "num-traits", + "serde", +] + +[[package]] +name = "kitsune_p2p_timestamp" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e173408aabd1fccedec2ba096b8feac7ef769c435294607f4ae5bc5b83ebc9e" +dependencies = [ + "chrono", + "derive_more", + "serde", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + +[[package]] +name = "libc" +version = "0.2.132" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" + +[[package]] +name = "libloading" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" +dependencies = [ + "cfg-if 1.0.0", + "winapi", +] + +[[package]] +name = "libm" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" + +[[package]] +name = "lock_api" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f80bf5aacaf25cbfc8210d1cfb718f2bf3b11c4c54e5afe36c236853a8ec390" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "loupe" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6a72dfa44fe15b5e76b94307eeb2ff995a8c5b283b55008940c02e0c5b634d" +dependencies = [ + "indexmap", + "loupe-derive", + "rustversion", +] + +[[package]] +name = "loupe-derive" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fbfc88337168279f2e9ae06e157cfed4efd3316e14dc96ed074d4f2e6c5952" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + +[[package]] +name = "matrixmultiply" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090126dc04f95dc0d1c1c91f61bdd474b3930ca064c1edc8a849da2c6cbe1e77" +dependencies = [ + "autocfg", + "rawpointer", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memmap2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95af15f345b17af2efc8ead6080fb8bc376f8cec1b35277b935637595fe77498" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miniz_oxide" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" +dependencies = [ + "adler", +] + +[[package]] +name = "more-asserts" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389" + +[[package]] +name = "must_future" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a160ffed3c2f98d2906c67a9b6e4e1f09cca7e17e3f780286a349061459eeebe" +dependencies = [ + "futures", + "pin-utils", +] + +[[package]] +name = "nalgebra" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "462fffe4002f4f2e1f6a9dcf12cc1a6fc0e15989014efc02a941d3e0f5dc2120" +dependencies = [ + "approx", + "matrixmultiply", + "nalgebra-macros", + "num-complex", + "num-rational", + "num-traits", + "rand", + "rand_distr", + "simba", + "typenum", +] + +[[package]] +name = "nalgebra-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01fcc0b8149b4632adc89ac3b7b31a12fb6099a0317a4eb2ebff574ef7de7218" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-complex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.28.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" +dependencies = [ + "crc32fast", + "hashbrown 0.11.2", + "indexmap", + "memchr", +] + +[[package]] +name = "object" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "smallvec", + "windows-sys 0.42.0", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "perspective_diff_sync" +version = "0.0.1" +dependencies = [ + "chrono", + "derive_more", + "dot-structures", + "graphviz-rust", + "hdk", + "holo_hash", + "itertools 0.10.3", + "lazy_static", + "maplit", + "perspective_diff_sync_integrity", + "petgraph", + "serde", + "sha2", + "thiserror", +] + +[[package]] +name = "perspective_diff_sync_integrity" +version = "0.0.1" +dependencies = [ + "chrono", + "derive_more", + "hdi", + "hdk", + "holo_hash", + "serde", +] + +[[package]] +name = "pest" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb779fcf4bb850fbbb0edc96ff6cf34fd90c4b1a112ce042653280d9a7364048" +dependencies = [ + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502b62a6d0245378b04ffe0a7fb4f4419a4815fce813bd8a0ec89a56e07d67b1" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "451e629bf49b750254da26132f1a5a9d11fd8a95a3df51d15c4abd1ba154cb6c" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcec162c71c45e269dfc3fc2916eaeb97feab22993a21bcce4721d08cd7801a6" +dependencies = [ + "once_cell", + "pest", + "sha1", +] + +[[package]] +name = "petgraph" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_distr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "rayon" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regalloc" +version = "0.0.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62446b1d3ebf980bdc68837700af1d77b37bc430e524bf95319c6eada2a4cc02" +dependencies = [ + "log", + "rustc-hash", + "smallvec", +] + +[[package]] +name = "regex" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" + +[[package]] +name = "region" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76e189c2369884dce920945e2ddf79b3dff49e071a167dd1817fa9c4c00d512e" +dependencies = [ + "bitflags", + "libc", + "mach", + "winapi", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "rend" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79af64b4b6362ffba04eef3a4e10829718a4896dac19daa741851c86781edf95" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "rkyv" +version = "0.7.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cec2b3485b07d96ddfd3134767b8a447b45ea4eb91448d0a35180ec0ffd5ed15" +dependencies = [ + "bytecheck", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eaedadc88b53e36dd32d940ed21ae4d850d5916f2581526921f553a72ac34c4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "rmp" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44519172358fd6d58656c86ab8e7fbc9e1490c3e8f14d35ed78ca0dd07403c9f" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "723ecff9ad04f4ad92fe1c8ca6c20d2196d9286e9c60727c4cb5511629260e9d" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.13", +] + +[[package]] +name = "rustversion" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" + +[[package]] +name = "ryu" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f6841e709003d68bb2deee8c343572bf446003ec20a583e76f7b15cebf3711" +dependencies = [ + "serde", +] + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] +name = "serde" +version = "1.0.144" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-transcode" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "590c0e25c2a5bb6e85bf5c1bce768ceb86b316e7a01bdf07d2cb4ec2271990e2" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_bytes" +version = "0.11.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfc50e8183eeeb6178dcb167ae34a8051d63535023ae38b5d8d12beae193d37b" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.144" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha-1" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha1" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "006769ba83e921b3085caa8334186b00cf92b4cb1a6cf4632fbccc8eff5c7549" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9db03534dff993187064c4e0c05a5708d2a9728ace9a8959b77bedf415dac5" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest", +] + +[[package]] +name = "shrinkwraprs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e63e6744142336dfb606fe2b068afa2e1cca1ee6a5d8377277a92945d81fa331" +dependencies = [ + "bitflags", + "itertools 0.8.2", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "simba" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e82063457853d00243beda9952e910b82593e4b07ae9f721b9278a99a0d3d5c" +dependencies = [ + "approx", + "num-complex", + "num-traits", + "paste", +] + +[[package]] +name = "slab" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "statrs" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05bdbb8e4e78216a85785a85d3ec3183144f98d0097b9281802c019bb07a6f05" +dependencies = [ + "approx", + "lazy_static", + "nalgebra", + "num-traits", + "rand", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "subprocess" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2e86926081dda636c546d8c5e641661049d7562a68f5488be4a1f7f66f6086" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "target-lexicon" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02424087780c9b71cc96799eaeddff35af2bc513278cda5c99fc1f5d026d3c1" + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if 1.0.0", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "test-fuzz" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "125df852011c4f8f31df5620f4aea38ecddb5dfb4d9bc569b30485b15ffc3d4e" +dependencies = [ + "serde", + "test-fuzz-internal", + "test-fuzz-macro", + "test-fuzz-runtime", +] + +[[package]] +name = "test-fuzz-internal" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58071dc2471840e9f374eeb0f6e405a31bccb3cc5d59bb4598f02cafc274b5c4" +dependencies = [ + "cargo_metadata", + "proc-macro2", + "quote", + "serde", + "strum_macros", +] + +[[package]] +name = "test-fuzz-macro" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "856bbca0314c328004691b9c0639fb198ca764d1ce0e20d4dd8b78f2697c2a6f" +dependencies = [ + "darling 0.14.1", + "if_chain", + "lazy_static", + "proc-macro2", + "quote", + "subprocess", + "syn", + "test-fuzz-internal", + "toolchain_find", + "unzip-n", +] + +[[package]] +name = "test-fuzz-runtime" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "303774eb17994c2ddb59c460369f4c3a55496f013380278d78eeebd2deb896ac" +dependencies = [ + "bincode", + "hex", + "num-traits", + "serde", + "sha-1", + "test-fuzz-internal", +] + +[[package]] +name = "thiserror" +version = "1.0.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c1b05ca9d106ba7d2e31a9dab4a64e7be2cce415321966ea3132c49a656e252" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8f2591983642de85c921015f3f070c665a197ed69e417af436115e3a1407487" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + +[[package]] +name = "toolchain_find" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e85654a10e7a07a47c6f19d93818f3f343e22927f2fa280c84f7c8042743413" +dependencies = [ + "home", + "lazy_static", + "regex", + "semver 0.11.0", + "walkdir", +] + +[[package]] +name = "tracing" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" +dependencies = [ + "cfg-if 1.0.0", + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "trilean" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683ba5022fe6dbd7133cad150478ccf51bdb6d861515181e5fc6b4323d4fa424" + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "ucd-trie" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" + +[[package]] +name = "unicode-ident" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" + +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + +[[package]] +name = "unzip-n" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2e7e85a0596447f0f2ac090e16bc4c516c6fe91771fb0c0ccf7fa3dae896b9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" +dependencies = [ + "cfg-if 1.0.0", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" + +[[package]] +name = "wasm-encoder" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d443c5a7daae71697d97ec12ad70b4fe8766d3a0f4db16158ac8b781365892f7" +dependencies = [ + "leb128", +] + +[[package]] +name = "wasmer" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea8d8361c9d006ea3d7797de7bd6b1492ffd0f91a22430cfda6c1658ad57bedf" +dependencies = [ + "cfg-if 1.0.0", + "indexmap", + "js-sys", + "loupe", + "more-asserts", + "target-lexicon", + "thiserror", + "wasm-bindgen", + "wasmer-artifact", + "wasmer-compiler", + "wasmer-compiler-cranelift", + "wasmer-derive", + "wasmer-engine", + "wasmer-engine-dylib", + "wasmer-engine-universal", + "wasmer-types", + "wasmer-vm", + "wat", + "winapi", +] + +[[package]] +name = "wasmer-artifact" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aaf9428c29c1d8ad2ac0e45889ba8a568a835e33fd058964e5e500f2f7ce325" +dependencies = [ + "enumset", + "loupe", + "thiserror", + "wasmer-compiler", + "wasmer-types", +] + +[[package]] +name = "wasmer-compiler" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67a6cd866aed456656db2cfea96c18baabbd33f676578482b85c51e1ee19d2c" +dependencies = [ + "enumset", + "loupe", + "rkyv", + "serde", + "serde_bytes", + "smallvec", + "target-lexicon", + "thiserror", + "wasmer-types", + "wasmparser", +] + +[[package]] +name = "wasmer-compiler-cranelift" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48be2f9f6495f08649e4f8b946a2cbbe119faf5a654aa1457f9504a99d23dae0" +dependencies = [ + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "gimli", + "loupe", + "more-asserts", + "rayon", + "smallvec", + "target-lexicon", + "tracing", + "wasmer-compiler", + "wasmer-types", +] + +[[package]] +name = "wasmer-derive" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00e50405cc2a2f74ff574584710a5f2c1d5c93744acce2ca0866084739284b51" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "wasmer-engine" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f98f010978c244db431b392aeab0661df7ea0822343334f8f2a920763548e45" +dependencies = [ + "backtrace", + "enumset", + "lazy_static", + "loupe", + "memmap2", + "more-asserts", + "rustc-demangle", + "serde", + "serde_bytes", + "target-lexicon", + "thiserror", + "wasmer-artifact", + "wasmer-compiler", + "wasmer-types", + "wasmer-vm", +] + +[[package]] +name = "wasmer-engine-dylib" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0358af9c154724587731175553805648d9acb8f6657880d165e378672b7e53" +dependencies = [ + "cfg-if 1.0.0", + "enum-iterator", + "enumset", + "leb128", + "libloading", + "loupe", + "object 0.28.4", + "rkyv", + "serde", + "tempfile", + "tracing", + "wasmer-artifact", + "wasmer-compiler", + "wasmer-engine", + "wasmer-object", + "wasmer-types", + "wasmer-vm", + "which", +] + +[[package]] +name = "wasmer-engine-universal" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "440dc3d93c9ca47865a4f4edd037ea81bf983b5796b59b3d712d844b32dbef15" +dependencies = [ + "cfg-if 1.0.0", + "enumset", + "leb128", + "loupe", + "region", + "rkyv", + "wasmer-compiler", + "wasmer-engine", + "wasmer-engine-universal-artifact", + "wasmer-types", + "wasmer-vm", + "winapi", +] + +[[package]] +name = "wasmer-engine-universal-artifact" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f1db3f54152657eb6e86c44b66525ff7801dad8328fe677da48dd06af9ad41" +dependencies = [ + "enum-iterator", + "enumset", + "loupe", + "rkyv", + "thiserror", + "wasmer-artifact", + "wasmer-compiler", + "wasmer-types", +] + +[[package]] +name = "wasmer-object" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d831335ff3a44ecf451303f6f891175c642488036b92ceceb24ac8623a8fa8b" +dependencies = [ + "object 0.28.4", + "thiserror", + "wasmer-compiler", + "wasmer-types", +] + +[[package]] +name = "wasmer-types" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39df01ea05dc0a9bab67e054c7cb01521e53b35a7bb90bd02eca564ed0b2667f" +dependencies = [ + "backtrace", + "enum-iterator", + "indexmap", + "loupe", + "more-asserts", + "rkyv", + "serde", + "thiserror", +] + +[[package]] +name = "wasmer-vm" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d965fa61f4dc4cdb35a54daaf7ecec3563fbb94154a6c35433f879466247dd" +dependencies = [ + "backtrace", + "cc", + "cfg-if 1.0.0", + "corosensei", + "enum-iterator", + "indexmap", + "lazy_static", + "libc", + "loupe", + "mach", + "memoffset", + "more-asserts", + "region", + "rkyv", + "scopeguard", + "serde", + "thiserror", + "wasmer-artifact", + "wasmer-types", + "winapi", +] + +[[package]] +name = "wasmparser" +version = "0.83.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "718ed7c55c2add6548cca3ddd6383d738cd73b892df400e96b9aa876f0141d7a" + +[[package]] +name = "wast" +version = "46.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea0ab19660e3ea6891bba69167b9be40fad00fb1fe3dd39c5eebcee15607131b" +dependencies = [ + "leb128", + "memchr", + "unicode-width", + "wasm-encoder", +] + +[[package]] +name = "wat" +version = "1.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f775282def4d5bffd94d60d6ecd57bfe6faa46171cdbf8d32bd5458842b1e3e" +dependencies = [ + "wast", +] + +[[package]] +name = "which" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b" +dependencies = [ + "either", + "libc", + "once_cell", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43dbb096663629518eb1dfa72d80243ca5a6aca764cae62a2df70af760a9be75" +dependencies = [ + "windows_aarch64_msvc 0.33.0", + "windows_i686_gnu 0.33.0", + "windows_i686_msvc 0.33.0", + "windows_x86_64_gnu 0.33.0", + "windows_x86_64_msvc 0.33.0", +] + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.42.0", + "windows_i686_gnu 0.42.0", + "windows_i686_msvc 0.42.0", + "windows_x86_64_gnu 0.42.0", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.42.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd761fd3eb9ab8cc1ed81e56e567f02dd82c4c837e48ac3b2181b9ffc5060807" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" + +[[package]] +name = "windows_i686_gnu" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab0cf703a96bab2dc0c02c0fa748491294bf9b7feb27e1f4f96340f208ada0e" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" + +[[package]] +name = "windows_i686_msvc" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cfdbe89cc9ad7ce618ba34abc34bbb6c36d99e96cae2245b7943cd75ee773d0" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4dd9b0c0e9ece7bb22e84d70d01b71c6d6248b81a3c60d11869451b4cb24784" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff1e4aa646495048ec7f3ffddc411e1d829c026a2ec62b39da15c1055e406eaa" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/Cargo.toml b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/Cargo.toml new file mode 100644 index 000000000..208186f1e --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/Cargo.toml @@ -0,0 +1,11 @@ +[workspace] +members = [ + "zomes/perspective_diff_sync", + "zomes/perspective_diff_sync_integrity" +] + +[profile.dev] +opt-level = "z" + +[profile.release] +opt-level = "z" \ No newline at end of file diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/build.ps1 b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/build.ps1 new file mode 100644 index 000000000..81582cbd3 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/build.ps1 @@ -0,0 +1,2 @@ +cargo build --release --target wasm32-unknown-unknown +hc dna pack workdir \ No newline at end of file diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/build.sh b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/build.sh new file mode 100755 index 000000000..a089cc772 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/build.sh @@ -0,0 +1,3 @@ +#!/bin/bash +CARGO_TARGET_DIR=target cargo build --release --target wasm32-unknown-unknown +hc dna pack workdir \ No newline at end of file diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/default.nix b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/default.nix new file mode 100644 index 000000000..33f97a914 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/default.nix @@ -0,0 +1,14 @@ +let + holonixPath = (import ./nix/sources.nix).holonix; # points to the current state of the Holochain repository + holonix = import (holonixPath) { + holochainVersionId = "main"; + }; + nixpkgs = holonix.pkgs; +in nixpkgs.mkShell { + inputsFrom = [ holonix.main ]; + packages = with nixpkgs; [ + binaryen + nodejs-16_x + swiProlog + ]; +} \ No newline at end of file diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/holochain_version.nix b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/holochain_version.nix new file mode 100644 index 000000000..acfe9651f --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/holochain_version.nix @@ -0,0 +1,20 @@ +# This file was generated with the following command: +# update-holochain-versions --git-src=revision:holochain-0.0.161 --lair-version-req=~0.2 --output-file=holochain_version.nix +# For usage instructions please visit https://github.com/holochain/holochain-nixpkgs/#readme + +{ + url = "https://github.com/holochain/holochain"; + rev = "holochain-0.2.2"; + sha256 = "sha256-xp1DTVrhGZc1CZr6LvBFZZhoOUbUPpg3/mWOj4DDXjI="; + cargoLock = { + outputHashes = { + }; + }; + + binsFilter = [ + "holochain" + "hc" + "kitsune-p2p-proxy" + "kitsune-p2p-tx2-proxy" + ]; +} diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/nix/sources.json b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/nix/sources.json new file mode 100644 index 000000000..451563814 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/nix/sources.json @@ -0,0 +1,14 @@ +{ + "holonix": { + "branch": "main", + "description": "NixOS && Holochain", + "homepage": "", + "owner": "holochain", + "repo": "holonix", + "rev": "241c1754a37881f51f2f33921a2777b38c34fa24", + "sha256": "sha256:0zaa477kyzpsrcc3nk1jznp4gchwm4pk5p37pwkq6mjhiizcxshy", + "type": "tarball", + "url": "https://github.com/holochain/holonix/archive/241c1754a37881f51f2f33921a2777b38c34fa24.tar.gz", + "url_template": "https://github.com///archive/.tar.gz" + } +} \ No newline at end of file diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/nix/sources.nix b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/nix/sources.nix new file mode 100644 index 000000000..fe2468872 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/nix/sources.nix @@ -0,0 +1,174 @@ +# This file has been generated by Niv. + +let + + # + # The fetchers. fetch_ fetches specs of type . + # + + fetch_file = pkgs: name: spec: + let + name' = sanitizeName name + "-src"; + in + if spec.builtin or true then + builtins_fetchurl { inherit (spec) url sha256; name = name'; } + else + pkgs.fetchurl { inherit (spec) url sha256; name = name'; }; + + fetch_tarball = pkgs: name: spec: + let + name' = sanitizeName name + "-src"; + in + if spec.builtin or true then + builtins_fetchTarball { name = name'; inherit (spec) url sha256; } + else + pkgs.fetchzip { name = name'; inherit (spec) url sha256; }; + + fetch_git = name: spec: + let + ref = + if spec ? ref then spec.ref else + if spec ? branch then "refs/heads/${spec.branch}" else + if spec ? tag then "refs/tags/${spec.tag}" else + abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!"; + in + builtins.fetchGit { url = spec.repo; inherit (spec) rev; inherit ref; }; + + fetch_local = spec: spec.path; + + fetch_builtin-tarball = name: throw + ''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`. + $ niv modify ${name} -a type=tarball -a builtin=true''; + + fetch_builtin-url = name: throw + ''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`. + $ niv modify ${name} -a type=file -a builtin=true''; + + # + # Various helpers + # + + # https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695 + sanitizeName = name: + ( + concatMapStrings (s: if builtins.isList s then "-" else s) + ( + builtins.split "[^[:alnum:]+._?=-]+" + ((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name) + ) + ); + + # The set of packages used when specs are fetched using non-builtins. + mkPkgs = sources: system: + let + sourcesNixpkgs = + import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; }; + hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath; + hasThisAsNixpkgsPath = == ./.; + in + if builtins.hasAttr "nixpkgs" sources + then sourcesNixpkgs + else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then + import {} + else + abort + '' + Please specify either (through -I or NIX_PATH=nixpkgs=...) or + add a package called "nixpkgs" to your sources.json. + ''; + + # The actual fetching function. + fetch = pkgs: name: spec: + + if ! builtins.hasAttr "type" spec then + abort "ERROR: niv spec ${name} does not have a 'type' attribute" + else if spec.type == "file" then fetch_file pkgs name spec + else if spec.type == "tarball" then fetch_tarball pkgs name spec + else if spec.type == "git" then fetch_git name spec + else if spec.type == "local" then fetch_local spec + else if spec.type == "builtin-tarball" then fetch_builtin-tarball name + else if spec.type == "builtin-url" then fetch_builtin-url name + else + abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}"; + + # If the environment variable NIV_OVERRIDE_${name} is set, then use + # the path directly as opposed to the fetched source. + replace = name: drv: + let + saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name; + ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}"; + in + if ersatz == "" then drv else + # this turns the string into an actual Nix path (for both absolute and + # relative paths) + if builtins.substring 0 1 ersatz == "/" then /. + ersatz else /. + builtins.getEnv "PWD" + "/${ersatz}"; + + # Ports of functions for older nix versions + + # a Nix version of mapAttrs if the built-in doesn't exist + mapAttrs = builtins.mapAttrs or ( + f: set: with builtins; + listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set)) + ); + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295 + range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1); + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257 + stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1)); + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269 + stringAsChars = f: s: concatStrings (map f (stringToCharacters s)); + concatMapStrings = f: list: concatStrings (map f list); + concatStrings = builtins.concatStringsSep ""; + + # https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331 + optionalAttrs = cond: as: if cond then as else {}; + + # fetchTarball version that is compatible between all the versions of Nix + builtins_fetchTarball = { url, name ? null, sha256 }@attrs: + let + inherit (builtins) lessThan nixVersion fetchTarball; + in + if lessThan nixVersion "1.12" then + fetchTarball ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; })) + else + fetchTarball attrs; + + # fetchurl version that is compatible between all the versions of Nix + builtins_fetchurl = { url, name ? null, sha256 }@attrs: + let + inherit (builtins) lessThan nixVersion fetchurl; + in + if lessThan nixVersion "1.12" then + fetchurl ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; })) + else + fetchurl attrs; + + # Create the final "sources" from the config + mkSources = config: + mapAttrs ( + name: spec: + if builtins.hasAttr "outPath" spec + then abort + "The values in sources.json should not have an 'outPath' attribute" + else + spec // { outPath = replace name (fetch config.pkgs name spec); } + ) config.sources; + + # The "config" used by the fetchers + mkConfig = + { sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null + , sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile) + , system ? builtins.currentSystem + , pkgs ? mkPkgs sources system + }: rec { + # The sources, i.e. the attribute set of spec name to spec + inherit sources; + + # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers + inherit pkgs; + }; + +in +mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); } \ No newline at end of file diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/workdir/dna.yaml b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/workdir/dna.yaml new file mode 100644 index 000000000..8a41b760b --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/workdir/dna.yaml @@ -0,0 +1,21 @@ +--- +manifest_version: 1 +name: "perspective-diff-sync" +integrity: + network_seed: 00000000-0000-0000-0000-000000000000 + properties: { + "enforce_spam_limit": 20, + "max_chunk_interval": 3599000, + "active_agent_duration_s": 300, + "enable_signals": true + } + origin_time: 2022-02-11T23:05:19.470323Z + zomes: + - name: perspective_diff_sync_integrity + bundled: ../target/wasm32-unknown-unknown/release/perspective_diff_sync_integrity.wasm +coordinator: + zomes: + - name: perspective_diff_sync + bundled: ../target/wasm32-unknown-unknown/release/perspective_diff_sync.wasm + dependencies: + - name: perspective_diff_sync_integrity \ No newline at end of file diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/Cargo.toml b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/Cargo.toml new file mode 100644 index 000000000..cfda8d8c6 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/Cargo.toml @@ -0,0 +1,28 @@ +[package] +authors = ["josh@junto.foundation"] +edition = "2018" +name = "perspective_diff_sync" +version = "0.0.1" + +[lib] +crate-type = ["cdylib", "rlib"] +name = "perspective_diff_sync" + +[dependencies] +derive_more = "0" +serde = "1" +lazy_static = "*" +chrono = { version = "0.4.22", default-features = false, features = ["clock", "std", "oldtime", "serde"] } +thiserror = "1.0.20" +petgraph = "0.6.2" +maplit = "1.0.2" +graphviz-rust = "0.2.1" +dot-structures = "0.1.0" +itertools = "0.10.3" +perspective_diff_sync_integrity = { path = "../perspective_diff_sync_integrity" } +sha2 = "0.10.5" +hdk = "0.2.2" +holo_hash = "0.2.2" + +[features] +test = [] \ No newline at end of file diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/errors.rs b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/errors.rs new file mode 100644 index 000000000..83eb919ab --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/errors.rs @@ -0,0 +1,25 @@ +use hdk::prelude::*; +use holo_hash::error::HoloHashError; +use std::convert::Infallible; + +#[derive(thiserror::Error, Debug)] +pub enum SocialContextError { + #[error(transparent)] + Serialization(#[from] SerializedBytesError), + #[error(transparent)] + Infallible(#[from] Infallible), + #[error(transparent)] + EntryError(#[from] EntryError), + #[error(transparent)] + Wasm(#[from] WasmError), + #[error(transparent)] + HoloHashError(#[from] HoloHashError), + #[error("Internal Error. Error: {0}")] + InternalError(&'static str), + #[error("No common ancestor found")] + NoCommonAncestorFound, + #[error("No did found")] + NoDidFound, +} + +pub type SocialContextResult = Result; diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/inputs.rs b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/inputs.rs new file mode 100644 index 000000000..403cc7f92 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/inputs.rs @@ -0,0 +1,29 @@ +use hdk::prelude::*; +use perspective_diff_sync_integrity::PerspectiveExpression; + +use crate::Hash; + +#[derive(Serialize, Deserialize, Clone, SerializedBytes, Debug, PartialEq, Eq, Hash)] +pub struct ExpressionProof { + pub signature: String, + pub key: String, +} + +#[derive(Serialize, Deserialize, Clone, SerializedBytes, Debug, PartialEq, Eq, Hash)] +pub struct Triple { + pub source: Option, + pub target: Option, + pub predicate: Option, +} + +#[derive(Serialize, Deserialize, Clone, SerializedBytes, Debug)] +pub struct SignalData { + pub remote_agent_did: String, + pub payload: PerspectiveExpression, +} + +#[derive(Serialize, Deserialize, Clone, SerializedBytes, Debug)] +pub struct PullArguments { + pub hash: Hash, + pub is_scribe: bool, +} diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/lib.rs b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/lib.rs new file mode 100644 index 000000000..e837a592b --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/lib.rs @@ -0,0 +1,195 @@ +#[macro_use] +extern crate lazy_static; + +use hdk::prelude::*; +use inputs::PullArguments; +use lazy_static::lazy_static; + +use perspective_diff_sync_integrity::{ + HashBroadcast, OnlineAgent, OnlineAgentAndAction, Perspective, PerspectiveDiff, + PerspectiveExpression, PullResult, +}; + +mod errors; +mod inputs; +mod link_adapter; +mod retriever; +mod telepresence; +mod utils; + +#[macro_use] +extern crate maplit; + +pub type Hash = HoloHash; + +#[hdk_extern] +fn init(_: ()) -> ExternResult { + let mut functions = BTreeSet::new(); + functions.insert((zome_info()?.name, "get_online_status".into())); + //TODO; is this next function needed? + functions.insert((zome_info()?.name, "recv_remote_signal".into())); + + let functions: GrantedFunctions = GrantedFunctions::Listed(functions); + + create_cap_grant(CapGrantEntry { + tag: "".into(), + // empty access converts to unrestricted + access: ().into(), + functions, + })?; + link_adapter::commit::add_active_agent_link::() + .map_err(|error| utils::err(&format!("{}", error)))?; + Ok(InitCallbackResult::Pass) +} + +/// LinkLanguage implementation + +#[hdk_extern] +pub fn commit(diff: PerspectiveDiff) -> ExternResult { + link_adapter::commit::commit::(diff) + .map_err(|error| utils::err(&format!("{}", error))) +} + +#[hdk_extern] +pub fn current_revision(_: ()) -> ExternResult> { + link_adapter::revisions::current_revision::() + .map_err(|error| utils::err(&format!("{}", error))) + .map(|val| val.map(|val| val.hash)) +} + +#[hdk_extern] +pub fn sync(_: ()) -> ExternResult> { + link_adapter::commit::broadcast_current::() + .map_err(|error| utils::err(&format!("{}", error))) +} + +#[hdk_extern] +pub fn get_broadcast_payload(_: ()) -> ExternResult> { + link_adapter::commit::get_broadcast_payload::() + .map_err(|error| utils::err(&format!("{}", error))) +} + +#[hdk_extern] +pub fn pull(args: PullArguments) -> ExternResult { + link_adapter::pull::pull::(true, args.hash, args.is_scribe) + .map_err(|error| utils::err(&format!("{}", error))) +} + +#[hdk_extern] +pub fn render(_: ()) -> ExternResult { + link_adapter::render::render::() + .map_err(|error| utils::err(&format!("{}", error))) +} + +#[hdk_extern] +pub fn update_current_revision(_hash: Hash) -> ExternResult<()> { + #[cfg(feature = "test")] + { + link_adapter::revisions::update_current_revision::( + _hash, + utils::get_now().unwrap(), + ) + .map_err(|err| utils::err(&format!("{}", err)))?; + } + Ok(()) +} + +/// Signal handling + +#[hdk_extern] +fn recv_remote_signal(signal: SerializedBytes) -> ExternResult<()> { + //Check if its a normal diff expression signal + match HashBroadcast::try_from(signal.clone()) { + Ok(broadcast) => { + debug!("Received broadcast: {:?} in HOLOCHAIN", broadcast); + link_adapter::pull::handle_broadcast::(broadcast) + .map_err(|err| utils::err(&format!("{}", err)))?; + } + //Check if its a broadcast message + Err(_) => match PerspectiveExpression::try_from(signal.clone()) { + Ok(sig) => emit_signal(sig)?, + //Check if its an online ping + Err(_) => return Err(utils::err(&format!("Signal not recognized: {:?}", signal))), + }, + }; + Ok(()) +} + +#[hdk_extern] +pub fn handle_broadcast(broadcast: HashBroadcast) -> ExternResult<()> { + link_adapter::pull::handle_broadcast::(broadcast) + .map_err(|err| utils::err(&format!("{}", err)))?; + Ok(()) +} + +// Telepresence implementation + +#[hdk_extern] +pub fn set_online_status(status: PerspectiveExpression) -> ExternResult<()> { + telepresence::status::set_online_status(status) + .map_err(|error| utils::err(&format!("{}", error)))?; + Ok(()) +} + +#[hdk_extern] +pub fn create_did_pub_key_link(did: String) -> ExternResult<()> { + telepresence::status::create_did_pub_key_link(did) + .map_err(|error| utils::err(&format!("{}", error)))?; + Ok(()) +} + +#[hdk_extern] +pub fn get_online_agents(_: ()) -> ExternResult> { + let res = telepresence::status::get_online_agents() + .map_err(|error| utils::err(&format!("{}", error)))?; + Ok(res) +} + +#[hdk_extern] +pub fn get_online_status(_: ()) -> ExternResult { + let res = telepresence::status::get_online_status() + .map_err(|error| utils::err(&format!("{}", error)))?; + Ok(res) +} + +#[hdk_extern] +pub fn get_agents_status(agent: AgentPubKey) -> ExternResult> { + let res = telepresence::status::get_agents_status(agent); + Ok(res) +} + +#[hdk_extern] +pub fn send_signal(signal_data: inputs::SignalData) -> ExternResult { + let res = telepresence::signal::send_signal(signal_data) + .map_err(|error| utils::err(&format!("{}", error)))?; + Ok(res) +} + +#[hdk_extern] +pub fn send_broadcast(data: PerspectiveExpression) -> ExternResult { + let res = telepresence::signal::send_broadcast(data) + .map_err(|error| utils::err(&format!("{}", error)))?; + Ok(res) +} + +#[hdk_extern] +pub fn get_active_agents(_: ()) -> ExternResult> { + let res = retriever::holochain::get_active_agents() + .map_err(|error| utils::err(&format!("{}", error)))?; + Ok(res) +} + +#[hdk_extern] +pub fn get_others(_: ()) -> ExternResult> { + let res = + telepresence::status::get_others().map_err(|error| utils::err(&format!("{}", error)))?; + Ok(res) +} + +//not loading from DNA properies since dna zome properties is always null for some reason +lazy_static! { + pub static ref ACTIVE_AGENT_DURATION: chrono::Duration = chrono::Duration::seconds(3600); + pub static ref ENABLE_SIGNALS: bool = true; + pub static ref SNAPSHOT_INTERVAL: usize = 100; + pub static ref CHUNK_SIZE: u16 = 10000; +} diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/chunked_diffs.rs b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/chunked_diffs.rs new file mode 100644 index 000000000..5a6912dc2 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/chunked_diffs.rs @@ -0,0 +1,207 @@ +use hdk::prelude::*; +use perspective_diff_sync_integrity::{ + EntryTypes, LinkExpression, PerspectiveDiff, +}; + +use crate::{Hash, CHUNK_SIZE}; +use crate::errors::{SocialContextResult}; +use crate::retriever::{PerspectiveDiffRetreiver}; + +#[derive(Clone)] +pub struct ChunkedDiffs { + max_changes_per_chunk: u16, + pub chunks: Vec +} + +impl ChunkedDiffs { + pub fn new(max: u16) -> Self { + Self { + max_changes_per_chunk: max, + chunks: vec![PerspectiveDiff::new()], + } + } + + pub fn add_additions(&mut self, links: Vec) { + let mut reverse_links = links.into_iter().rev().collect::>(); + while reverse_links.len() > 0 { + let len = self.chunks.len(); + let current_chunk = self.chunks.get_mut(len-1).expect("must have at least one"); + + while current_chunk.total_diff_number() < self.max_changes_per_chunk.into() && reverse_links.len() > 0 { + current_chunk.additions.push(reverse_links.pop().unwrap()); + } + + if reverse_links.len() > 0 { + self.chunks.push(PerspectiveDiff::new()) + } + } + } + + pub fn add_removals(&mut self, links: Vec) { + let mut reverse_links = links.into_iter().rev().collect::>(); + while reverse_links.len() > 0 { + let len = self.chunks.len(); + let current_chunk = self.chunks.get_mut(len-1).expect("must have at least one"); + + while current_chunk.total_diff_number() < self.max_changes_per_chunk.into() && reverse_links.len() > 0 { + current_chunk.removals.push(reverse_links.pop().unwrap()); + } + + if reverse_links.len() > 0 { + self.chunks.push(PerspectiveDiff::new()) + } + } + } + + pub fn into_entries(self) -> SocialContextResult> { + debug!("ChunkedDiffs.into_entries()"); + self.chunks + .into_iter() + .map(|chunk_diff| { + debug!("ChunkedDiffs writing chunk of size: {}", chunk_diff.total_diff_number()); + Retreiver::create_entry(EntryTypes::PerspectiveDiff(chunk_diff)) + }) + .collect() + } + + pub fn from_entries(hashes: Vec) -> SocialContextResult { + let mut diffs = Vec::new(); + for hash in hashes.into_iter() { + diffs.push(Retreiver::get::(hash)?); + } + + Ok(ChunkedDiffs { + max_changes_per_chunk: *CHUNK_SIZE, + chunks: diffs, + }) + } + + pub fn into_aggregated_diff(self) -> PerspectiveDiff { + self.chunks.into_iter().reduce(|accum, item| { + let mut temp = accum.clone(); + temp.additions.append(&mut item.additions.clone()); + temp.removals.append(&mut item.removals.clone()); + temp + }) + .unwrap_or(PerspectiveDiff::new()) + } +} + + +#[cfg(test)] +mod tests { + use super::ChunkedDiffs; + use crate::utils::create_link_expression; + use crate::retriever::{GLOBAL_MOCKED_GRAPH, MockPerspectiveGraph}; + + #[test] + fn can_chunk() { + let mut chunks = ChunkedDiffs::new(5); + + chunks.add_additions(vec![ + create_link_expression("a", "1"), + create_link_expression("a", "2"), + create_link_expression("a", "3"), + ]); + + assert_eq!(chunks.chunks.len(), 1); + + chunks.add_additions(vec![ + create_link_expression("a", "4"), + create_link_expression("a", "5"), + create_link_expression("a", "6"), + ]); + + assert_eq!(chunks.chunks.len(), 2); + + chunks.add_removals(vec![ + create_link_expression("a", "1"), + create_link_expression("a", "2"), + create_link_expression("a", "3"), + create_link_expression("a", "4"), + create_link_expression("a", "5"), + create_link_expression("a", "6"), + ]); + + assert_eq!(chunks.chunks.len(), 3); + } + + #[test] + fn can_aggregate() { + let mut chunks = ChunkedDiffs::new(5); + + let _a1 = create_link_expression("a", "1"); + let _a2 = create_link_expression("a", "2"); + let _r1 = create_link_expression("r", "1"); + let _r2 = create_link_expression("r", "2"); + let _r3 = create_link_expression("r", "3"); + let _r4 = create_link_expression("r", "4"); + + + chunks.add_additions(vec![_a1.clone()]); + chunks.add_additions(vec![_a2.clone()]); + chunks.add_removals(vec![_r1.clone(),_r2.clone(),_r3.clone(),_r4.clone()]); + + assert_eq!(chunks.chunks.len(), 2); + + let diff = chunks.into_aggregated_diff(); + + assert_eq!(diff.additions, vec![_a1,_a2]); + assert_eq!(diff.removals, vec![_r1,_r2,_r3,_r4]); + } + + #[test] + fn can_chunk_big_diffs() { + let mut chunks = ChunkedDiffs::new(500); + + let mut big_diff_add = Vec::new(); + for i in 0..5000 { + big_diff_add.push(create_link_expression("a", &format!("{}", i))); + } + chunks.add_additions(big_diff_add); + + let mut big_diff_remove = Vec::new(); + for i in 0..800 { + big_diff_remove.push(create_link_expression("a", &format!("{}", i))); + } + chunks.add_removals(big_diff_remove); + + let mut big_diff_add = Vec::new(); + for i in 0..213 { + big_diff_add.push(create_link_expression("a", &format!("{}", i))); + } + chunks.add_additions(big_diff_add); + + assert_eq!(chunks.chunks.len(), 13); + for i in 0..12 { + assert_eq!(chunks.chunks[i].total_diff_number(), 500); + } + assert_eq!(chunks.chunks[12].total_diff_number(), 13); + } + + #[test] + fn can_write_and_read_entries() { + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::from_dot("digraph{}").expect("can create mock graph from empty dot"); + } + update(); + + let mut chunks = ChunkedDiffs::new(500); + + let mut big_diff_add = Vec::new(); + for i in 0..5000 { + big_diff_add.push(create_link_expression("a", &format!("{}", i))); + } + chunks.add_additions(big_diff_add); + + assert_eq!(chunks.chunks.len(), 10); + + let chunks_clone = chunks.clone(); + let hashes = chunks.into_entries::().expect("into_entries does not error"); + let read_chunks = ChunkedDiffs::from_entries::(hashes).expect("from_entries does not error"); + + assert_eq!(read_chunks.chunks.len(), 10); + assert_eq!(format!("{:?}", read_chunks.chunks), format!("{:?}", chunks_clone.chunks)); + } +} diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/commit.rs b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/commit.rs new file mode 100644 index 000000000..6dd6f9392 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/commit.rs @@ -0,0 +1,171 @@ +//use chrono::Timelike; +use hdk::prelude::*; +use perspective_diff_sync_integrity::{ + EntryTypes, HashBroadcast, LinkTypes, PerspectiveDiff, PerspectiveDiffEntryReference, +}; + +use crate::errors::SocialContextResult; +use crate::link_adapter::revisions::{current_revision, update_current_revision}; +use crate::link_adapter::snapshots::generate_snapshot; +use crate::retriever::holochain::{get_active_agent_anchor, get_active_agents}; +use crate::retriever::PerspectiveDiffRetreiver; +use crate::telepresence::status::get_my_did; +use crate::utils::get_now; +use crate::{Hash, ENABLE_SIGNALS, SNAPSHOT_INTERVAL}; + +pub fn commit( + diff: PerspectiveDiff, +) -> SocialContextResult> { + debug!("===PerspectiveDiffSync.commit(): Function start"); + let now_fn_start = get_now()?.time(); + let current_revision = current_revision::()?; + + let mut entries_since_snapshot = 0; + if current_revision.is_some() { + let current = Retriever::get::( + current_revision.clone().unwrap().hash, + )?; + entries_since_snapshot = current.diffs_since_snapshot; + }; + debug!( + "===PerspectiveDiffSync.commit(): Entries since snapshot: {:#?}", + entries_since_snapshot + ); + //Add one since we are comitting an entry here + entries_since_snapshot += 1; + + let create_snapshot_here = if entries_since_snapshot >= *SNAPSHOT_INTERVAL { + entries_since_snapshot = 0; + true + } else { + false + }; + + let now = get_now()?.time(); + let diff_entry_create = Retriever::create_entry(EntryTypes::PerspectiveDiff(diff.clone()))?; + let diff_entry_ref_entry = PerspectiveDiffEntryReference { + diff: diff_entry_create.clone(), + parents: current_revision.map(|val| vec![val.hash]), + diffs_since_snapshot: entries_since_snapshot, + }; + let diff_entry_reference = Retriever::create_entry(EntryTypes::PerspectiveDiffEntryReference( + diff_entry_ref_entry.clone(), + ))?; + let after = get_now()?.time(); + // debug!( + // "===PerspectiveDiffSync.commit(): Created diff entry ref: {:#?}", + // diff_entry_reference + // ); + debug!( + "===PerspectiveDiffSync.commit() - Profiling: Took {} to create a PerspectiveDiff", + (after - now).num_milliseconds() + ); + + if create_snapshot_here { + //fetch all the diff's, we need a new function which will traverse graph and then return + diffs + next found snapshot + //create new snapshot linked from above diff_entry_reference + let snapshot = generate_snapshot(diff_entry_reference.clone())?; + + let now = get_now()?.time(); + Retriever::create_entry(EntryTypes::Snapshot(snapshot.clone()))?; + create_link( + hash_entry(diff_entry_ref_entry.clone())?, + hash_entry(snapshot)?, + LinkTypes::Snapshot, + LinkTag::new("snapshot"), + )?; + let after = get_now()?.time(); + debug!("===PerspectiveDiffSync.commit() - Profiling: Took {} to create snapshot entry and link", (after - now).num_milliseconds()); + }; + + let now = get_now()?; + let now_profile = get_now()?.time(); + //update_latest_revision::(diff_entry_reference.clone(), now.clone())?; + let after = get_now()?.time(); + debug!( + "===PerspectiveDiffSync.commit() - Profiling: Took {} to update the latest revision", + (after - now_profile).num_milliseconds() + ); + update_current_revision::(diff_entry_reference.clone(), now)?; + + // if *ENABLE_SIGNALS { + // // let signal_data = PerspectiveDiffReference { + // // diff, + // // reference: diff_entry_ref_entry, + // // reference_hash: diff_entry_reference.clone(), + // // }; + // // send_revision_signal(signal_data)?; + // broadcast_current::()?; + // }; + + let after_fn_end = get_now()?.time(); + debug!( + "===PerspectiveDiffSync.commit() - Profiling: Took {} to complete whole commit function", + (after_fn_end - now_fn_start).num_milliseconds() + ); + Ok(diff_entry_reference) +} + +pub fn add_active_agent_link() -> SocialContextResult<()> { + debug!("===PerspectiveDiffSync.add_active_agent_link(): Function start"); + let now_fn_start = get_now()?.time(); + let agent_root_entry = get_active_agent_anchor(); + let _agent_root_entry_action = + Retriever::create_entry(EntryTypes::Anchor(agent_root_entry.clone()))?; + + let agent = agent_info()?.agent_initial_pubkey; + create_link( + hash_entry(agent_root_entry)?, + agent, + LinkTypes::Index, + LinkTag::new("active_agent"), + )?; + let after_fn_end = get_now()?.time(); + debug!("===PerspectiveDiffSync.add_active_agent_link() - Profiling: Took {} to complete whole add_active_agent_link()", (after_fn_end - now_fn_start).num_milliseconds()); + Ok(()) +} + +pub fn broadcast_current() -> SocialContextResult> +{ + //debug!("Running broadcast_current"); + let current = current_revision::()?; + //debug!("Current revision: {:#?}", current); + + if current.is_some() { + let current_revision = current.clone().unwrap(); + let entry_ref = + Retriever::get::(current_revision.hash.clone())?; + let diff = Retriever::get::(entry_ref.diff.clone())?; + + let signal_data = HashBroadcast { + reference: entry_ref, + reference_hash: current_revision.hash.clone(), + diff, + broadcast_author: get_my_did()?.unwrap(), + }; + + let recent_agents = get_active_agents()?; + //debug!("Recent agents: {:#?}", recent_agents); + remote_signal(signal_data.get_sb()?, recent_agents.clone())?; + }; + Ok(current.map(|rev| rev.hash)) +} + +pub fn get_broadcast_payload() -> SocialContextResult> { + match current_revision::()? { + Some(current) => { + let current_revision = current; + let entry_ref = + Retriever::get::(current_revision.hash.clone())?; + let diff = Retriever::get::(entry_ref.diff.clone())?; + + Ok(Some(HashBroadcast { + reference: entry_ref, + reference_hash: current_revision.hash.clone(), + diff, + broadcast_author: get_my_did()?.unwrap(), + })) + }, + None => Ok(None) + } +} diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/mod.rs b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/mod.rs new file mode 100644 index 000000000..385f55db2 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/mod.rs @@ -0,0 +1,10 @@ +pub(crate) mod chunked_diffs; +pub(crate) mod commit; +pub(crate) mod pull; +pub(crate) mod render; +pub(crate) mod revisions; +pub(crate) mod snapshots; +pub(crate) mod test_graphs; +pub(crate) mod tests; +pub(crate) mod topo_sort; +pub(crate) mod workspace; diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/pull.rs b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/pull.rs new file mode 100644 index 000000000..9059b9b32 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/pull.rs @@ -0,0 +1,846 @@ +use hdk::prelude::*; +use perspective_diff_sync_integrity::{ + EntryTypes, HashBroadcast, PerspectiveDiff, PerspectiveDiffEntryReference, PullResult, +}; + +use crate::errors::SocialContextResult; +use crate::link_adapter::revisions::{current_revision, update_current_revision}; +use crate::link_adapter::workspace::{Workspace, NULL_NODE}; +use crate::retriever::PerspectiveDiffRetreiver; +use crate::utils::get_now; +use crate::Hash; + +fn merge( + latest: Hash, + current: Hash, +) -> SocialContextResult { + debug!("===PerspectiveDiffSync.merge(): Function start"); + let fn_start = get_now()?.time(); + + let latest_diff = Retriever::get::(latest.clone())?; + let current_diff = Retriever::get::(current.clone())?; + //Create the merge diff + let merge_diff = PerspectiveDiff { + additions: vec![], + removals: vec![], + }; + let merge_entry_hash = + Retriever::create_entry(EntryTypes::PerspectiveDiff(merge_diff.clone()))?; + + //Create the merge entry reference + let merge_entry_reference = PerspectiveDiffEntryReference { + parents: Some(vec![latest, current]), + diff: merge_entry_hash.clone(), + diffs_since_snapshot: latest_diff.diffs_since_snapshot + + current_diff.diffs_since_snapshot + + 1, + }; + let merge_entry_reference_hash = Retriever::create_entry( + EntryTypes::PerspectiveDiffEntryReference(merge_entry_reference.clone()), + )?; + debug!( + "===PerspectiveDiffSync.merge(): Commited merge entry: {:#?}", + merge_entry_reference_hash + ); + + let now = get_now()?; + update_current_revision::(merge_entry_reference_hash.clone(), now)?; + + let fn_end = get_now()?.time(); + debug!( + "===PerspectiveDiffSync.merge() - Profiling: Took: {} to complete merge() function", + (fn_end - fn_start).num_milliseconds() + ); + Ok(merge_entry_reference_hash) +} + +pub fn pull( + emit: bool, + theirs: Hash, + is_scribe: bool, +) -> SocialContextResult { + debug!("===PerspectiveDiffSync.pull(): Function start"); + let fn_start = get_now()?.time(); + + let current = current_revision::()?; + let current_hash = current.clone().map(|val| val.hash); + debug!( + "===PerspectiveDiffSync.pull(): Pull made with theirs: {:#?} and current: {:#?}", + theirs, current + ); + + let theirs_hash = theirs.clone(); + + if Some(theirs_hash) == current_hash { + return Ok(PullResult { + diff: PerspectiveDiff::default(), + current_revision: current_hash, + }); + } + + let mut workspace = Workspace::new(); + + if current.is_none() { + workspace.collect_only_from_latest::(theirs.clone())?; + let diff = workspace.squashed_diff::()?; + update_current_revision::(theirs, get_now()?)?; + emit_signal(diff.clone())?; + return Ok(PullResult { + diff: PerspectiveDiff::default(), + current_revision: None, + }); + } + + let current = current.expect("current missing handled above"); + + workspace.build_diffs::(theirs.clone(), current.hash.clone())?; + + // First check if we are actually ahead of them -> we don't have to do anything + // they will have to merge with / or fast-forward to our current + if workspace.all_ancestors(¤t.hash)?.contains(&theirs) { + return Ok(PullResult { + diff: PerspectiveDiff::default(), + current_revision: Some(current.hash), + }); + } + + let fast_forward_possible = workspace.all_ancestors(&theirs)?.contains(¤t.hash); + + // If we can't fast forward, we have to merge + // but if we are not a scribe, we can't merge + // so in that case, we can't do anything + if !fast_forward_possible && !is_scribe { + debug!("===PerspectiveDiffSync.pull(): Have to merge but I'm not a scribe. Exiting without change..."); + return Ok(PullResult { + diff: PerspectiveDiff::default(), + current_revision: Some(current.hash), + }); + } + + //Get all the diffs which exist between current and the last ancestor that we got + let seen_diffs = workspace.all_ancestors(¤t.hash)?; + // println!("SEEN DIFFS: {:#?}", seen_diffs); + + //Get all the diffs in the graph which we havent seen + let unseen_diffs = if seen_diffs.len() > 0 { + let diffs = workspace + .sorted_diffs + .clone() + .expect("should be unseen diffs after build_diffs() call") + .into_iter() + .filter(|val| { + if val.0 == NULL_NODE() { + return false; + }; + if val.0 == current.hash { + return false; + }; + if seen_diffs.contains(&val.0) { + return false; + }; + true + }) + .collect::>(); + diffs + } else { + workspace + .sorted_diffs + .expect("should be unseen diffs after build_diffs() call") + .into_iter() + .filter(|val| val.0 != NULL_NODE() && val.0 != current.hash) + .collect::>() + }; + + let (diffs, current_revision) = if fast_forward_possible { + debug!("===PerspectiveDiffSync.pull(): There are paths between current and latest, lets fast forward the changes we have missed!"); + let mut out = PerspectiveDiff { + additions: vec![], + removals: vec![], + }; + for diff in unseen_diffs { + let diff_entry = Retriever::get::(diff.1.diff.clone())?; + out.additions.append(&mut diff_entry.additions.clone()); + out.removals.append(&mut diff_entry.removals.clone()); + } + update_current_revision::(theirs.clone(), get_now()?)?; + let fn_end = get_now()?.time(); + debug!( + "===PerspectiveDiffSync.pull() - Profiling: Took: {} to complete pull() function", + (fn_end - fn_start).num_milliseconds() + ); + (out, theirs) + } else if is_scribe { + debug!("===PerspectiveDiffSync.pull():There are no paths between current and latest, we must merge current and latest"); + //Get the entries we missed from unseen diff + let mut out = PerspectiveDiff { + additions: vec![], + removals: vec![], + }; + for diff in unseen_diffs { + let diff_entry = Retriever::get::(diff.1.diff.clone())?; + out.additions.append(&mut diff_entry.additions.clone()); + out.removals.append(&mut diff_entry.removals.clone()); + } + + let merge_hash = merge::(theirs, current.hash)?; + let fn_end = get_now()?.time(); + debug!( + "===PerspectiveDiffSync.pull() - Profiling: Took: {} to complete pull() function", + (fn_end - fn_start).num_milliseconds() + ); + (out, merge_hash) + } else { + ( + PerspectiveDiff { + additions: vec![], + removals: vec![], + }, + current.hash, + ) + }; + + //Emit the signal in case the client connection has a timeout during the zome call + if emit { + if diffs.additions.len() > 0 || diffs.removals.len() > 0 { + emit_signal(diffs.clone())?; + } + } + Ok(PullResult { + diff: diffs, + current_revision: Some(current_revision), + }) +} + +pub fn handle_broadcast( + broadcast: HashBroadcast, +) -> SocialContextResult<()> { + // debug!("===PerspectiveDiffSync.fast_forward_signal(): Function start"); + // let fn_start = get_now()?.time(); + let diff_reference = broadcast.reference.clone(); + let revision = broadcast.reference_hash.clone(); + + let current_revision = current_revision::()?; + + if current_revision.is_some() { + let current_revision = current_revision.unwrap(); + if revision == current_revision.hash { + // debug!("===PerspectiveDiffSync.fast_forward_signal(): Revision is the same as current"); + }; + if diff_reference.parents == Some(vec![current_revision.hash]) { + // debug!("===PerspectiveDiffSync.fast_forward_signal(): Revisions parent is the same as current, we can fast forward our current"); + update_current_revision::(revision, get_now()?)?; + emit_signal(broadcast.diff.clone())?; + }; + }; + //emit_signal(broadcast)?; + // let fn_end = get_now()?.time(); + // debug!("===PerspectiveDiffSync.fast_forward_signal() - Profiling: Took: {} to complete fast_forward_signal() function", (fn_end - fn_start).num_milliseconds()); + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::pull; + use crate::retriever::{ + create_node_id_link_expression, create_node_id_vec, node_id_hash, MockPerspectiveGraph, + PerspectiveDiffRetreiver, GLOBAL_MOCKED_GRAPH, + }; + use crate::utils::create_link_expression; + use dot_structures; + + #[test] + fn test_fast_forward_merge() { + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::from_dot( + r#"digraph { + 0 [ label = "0" ] + 1 [ label = "1" ] + 2 [ label = "2" ] + 3 [ label = "3" ] + + 1 -> 0 + 2 -> 0 + 3 -> 1 + 3 -> 2 + + }"#, + ) + .unwrap(); + } + update(); + + let latest_node_hash = node_id_hash(&dot_structures::Id::Plain(String::from("3"))); + + let current_node_hash = node_id_hash(&dot_structures::Id::Plain(String::from("2"))); + let update_current = + MockPerspectiveGraph::update_current_revision(current_node_hash, chrono::Utc::now()); + assert!(update_current.is_ok()); + + let pull_res = pull::(false, latest_node_hash, true); + assert!(pull_res.is_ok()); + let pull_res = pull_res.unwrap(); + + let node_1 = &node_id_hash(&dot_structures::Id::Plain(String::from("1"))).to_string(); + let node_3 = &node_id_hash(&dot_structures::Id::Plain(String::from("3"))).to_string(); + let expected_additions = vec![ + create_link_expression(node_1, node_1), + create_link_expression(node_3, node_3), + ]; + + assert!(pull_res + .diff + .additions + .iter() + .all(|item| expected_additions.contains(item))); + } + + #[test] + fn test_complex_merge() { + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::from_dot( + r#"digraph { + 1 [ label = "1" ] + 2 [ label = "2" ] + 3 [ label = "3" ] + 4 [ label = "4" ] + 5 [ label = "5" ] + 6 [ label = "6" ] + + 3 -> 2 + 4 -> 2 + 5 -> 3 + 5 -> 4 + 6 -> 5 + }"#, + ) + .unwrap(); + } + update(); + + let latest_node_hash = node_id_hash(&dot_structures::Id::Plain(String::from("6"))); + + let current_node_hash = node_id_hash(&dot_structures::Id::Plain(String::from("1"))); + let update_current = + MockPerspectiveGraph::update_current_revision(current_node_hash, chrono::Utc::now()); + assert!(update_current.is_ok()); + + let pull_res = pull::(false, latest_node_hash.clone(), true); + assert!(pull_res.is_ok()); + let pull_res = pull_res.unwrap(); + + let node_2 = &node_id_hash(&dot_structures::Id::Plain(String::from("2"))).to_string(); + let node_3 = &node_id_hash(&dot_structures::Id::Plain(String::from("3"))).to_string(); + let node_4 = &node_id_hash(&dot_structures::Id::Plain(String::from("4"))).to_string(); + let node_5 = &node_id_hash(&dot_structures::Id::Plain(String::from("5"))).to_string(); + let node_6 = &node_id_hash(&dot_structures::Id::Plain(String::from("6"))).to_string(); + let expected_additions = vec![ + create_link_expression(node_2, node_2), + create_link_expression(node_3, node_3), + create_link_expression(node_4, node_4), + create_link_expression(node_5, node_5), + create_link_expression(node_6, node_6), + ]; + + assert!(pull_res + .diff + .additions + .iter() + .all(|item| expected_additions.contains(item))); + + //Test that a merge actually happened and current was updated + let new_current = MockPerspectiveGraph::current_revision(); + assert!(new_current.is_ok()); + let new_current = new_current.unwrap(); + + assert!(new_current.unwrap().hash != latest_node_hash); + } + + #[test] + fn test_complex_fast_forward() { + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::from_dot( + r#"digraph { + 1 [ label = "1" ] + 2 [ label = "2" ] + 3 [ label = "3" ] + 4 [ label = "4" ] + 5 [ label = "5" ] + 6 [ label = "6" ] + + 3 -> 2 + 4 -> 2 + 5 -> 3 + 5 -> 4 + 6 -> 5 + }"#, + ) + .unwrap(); + } + update(); + + let latest_node_hash = node_id_hash(&dot_structures::Id::Plain(String::from("6"))); + + let current_node_hash = node_id_hash(&dot_structures::Id::Plain(String::from("4"))); + let update_current = + MockPerspectiveGraph::update_current_revision(current_node_hash, chrono::Utc::now()); + assert!(update_current.is_ok()); + + let pull_res = pull::(false, latest_node_hash, true); + assert!(pull_res.is_ok()); + let pull_res = pull_res.unwrap(); + + let node_3 = &node_id_hash(&dot_structures::Id::Plain(String::from("3"))).to_string(); + let node_5 = &node_id_hash(&dot_structures::Id::Plain(String::from("5"))).to_string(); + let node_6 = &node_id_hash(&dot_structures::Id::Plain(String::from("6"))).to_string(); + let expected_additions = vec![ + create_link_expression(node_3, node_3), + create_link_expression(node_5, node_5), + create_link_expression(node_6, node_6), + ]; + + assert!(pull_res + .diff + .additions + .iter() + .all(|item| expected_additions.contains(item))); + } + + #[test] + fn test_fast_forward_after_merge() { + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::from_dot( + r#"digraph { + 1 [ label = "1" ] + 2 [ label = "2" ] + 3 [ label = "3" ] + 4 [ label = "4" ] + 5 [ label = "5" ] + 6 [ label = "6" ] + 7 [ label = "7" ] + + 3 -> 2 + 4 -> 2 + 5 -> 3 + 5 -> 4 + 6 -> 5 + 7 -> 1 + 7 -> 6 + }"#, + ) + .unwrap(); + } + update(); + + let latest_node_hash = node_id_hash(&dot_structures::Id::Plain(String::from("7"))); + + let current_node_hash = node_id_hash(&dot_structures::Id::Plain(String::from("6"))); + let update_current = + MockPerspectiveGraph::update_current_revision(current_node_hash, chrono::Utc::now()); + assert!(update_current.is_ok()); + + let pull_res = pull::(false, latest_node_hash, true); + assert!(pull_res.is_ok()); + let pull_res = pull_res.unwrap(); + + let node_1 = &node_id_hash(&dot_structures::Id::Plain(String::from("1"))).to_string(); + let node_7 = &node_id_hash(&dot_structures::Id::Plain(String::from("7"))).to_string(); + let expected_additions = vec![ + create_link_expression(node_1, node_1), + create_link_expression(node_7, node_7), + ]; + + assert!(pull_res + .diff + .additions + .iter() + .all(|item| expected_additions.contains(item))); + } + + #[test] + fn test_pull_complex_merge_implicit_zero() { + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::from_dot( + r#"digraph { + 1 [ label = "1" ] + 2 [ label = "2" ] + 3 [ label = "3" ] + 4 [ label = "4" ] + 5 [ label = "5" ] + 6 [ label = "6" ] + 4 -> 2 [ label = "()" ] + 5 -> 4 [ label = "()" ] + 5 -> 3 [ label = "()" ] + 6 -> 5 [ label = "()" ] + }"#, + ) + .unwrap(); + } + update(); + + let node_1 = node_id_hash(&dot_structures::Id::Plain(String::from("1"))); + let node_6 = node_id_hash(&dot_structures::Id::Plain(String::from("6"))); + + let latest_node_hash = node_1; + + let current_node_hash = node_6; + let update_current = MockPerspectiveGraph::update_current_revision( + current_node_hash.clone(), + chrono::Utc::now(), + ); + assert!(update_current.is_ok()); + + let node_1 = &node_id_hash(&dot_structures::Id::Plain(String::from("1"))).to_string(); + let expected_additions = vec![create_link_expression(node_1, node_1)]; + + let pull_res = pull::(false, latest_node_hash.clone(), true); + assert!(pull_res.is_ok()); + assert!(pull_res + .unwrap() + .diff + .additions + .iter() + .all(|item| expected_additions.contains(item))); + + //ensure that merge was created and thus current revision got updated + let current = MockPerspectiveGraph::current_revision(); + assert!(current.unwrap().unwrap().hash != current_node_hash); + } + + #[test] + fn test_pull_complex_merge_implicit_zero_reversed() { + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::from_dot( + r#"digraph { + 1 [ label = "1" ] + 2 [ label = "2" ] + 3 [ label = "3" ] + 4 [ label = "4" ] + 5 [ label = "5" ] + 6 [ label = "6" ] + 4 -> 2 [ label = "()" ] + 5 -> 4 [ label = "()" ] + 5 -> 3 [ label = "()" ] + 6 -> 5 [ label = "()" ] + }"#, + ) + .unwrap(); + } + update(); + + let node_1 = node_id_hash(&dot_structures::Id::Plain(String::from("1"))); + let node_6 = node_id_hash(&dot_structures::Id::Plain(String::from("6"))); + + let latest_node_hash = node_6; + + let current_node_hash = node_1; + let update_current = MockPerspectiveGraph::update_current_revision( + current_node_hash.clone(), + chrono::Utc::now(), + ); + assert!(update_current.is_ok()); + + let node_6 = &node_id_hash(&dot_structures::Id::Plain(String::from("6"))).to_string(); + let node_5 = &node_id_hash(&dot_structures::Id::Plain(String::from("5"))).to_string(); + let node_4 = &node_id_hash(&dot_structures::Id::Plain(String::from("4"))).to_string(); + let node_3 = &node_id_hash(&dot_structures::Id::Plain(String::from("3"))).to_string(); + let node_2 = &node_id_hash(&dot_structures::Id::Plain(String::from("2"))).to_string(); + let expected_additions = vec![ + create_link_expression(node_6, node_6), + create_link_expression(node_5, node_5), + create_link_expression(node_4, node_4), + create_link_expression(node_3, node_3), + create_link_expression(node_2, node_2), + ]; + + let pull_res = pull::(false, latest_node_hash.clone(), true); + assert!(pull_res.is_ok()); + assert!(pull_res + .unwrap() + .diff + .additions + .iter() + .all(|item| expected_additions.contains(item))); + + //ensure that merge was created and thus current revision got updated + let current = MockPerspectiveGraph::current_revision(); + assert!(current.unwrap().unwrap().hash != current_node_hash); + } + + #[test] + fn test_three_null_parents() { + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::from_dot( + r#"digraph { + 1 [ label = "1" ] + 2 [ label = "2" ] + 3 [ label = "3" ] + 4 [ label = "4" ] + 5 [ label = "5" ] + + 4 -> 2 + 4 -> 3 + 5 -> 4 + 5 -> 1 + }"#, + ) + .unwrap(); + } + update(); + + let latest_node_hash = node_id_hash(&dot_structures::Id::Plain(String::from("5"))); + + let current_node_hash = node_id_hash(&dot_structures::Id::Plain(String::from("2"))); + let update_current = MockPerspectiveGraph::update_current_revision( + current_node_hash.clone(), + chrono::Utc::now(), + ); + assert!(update_current.is_ok()); + + let pull_res = pull::(false, latest_node_hash.clone(), true); + assert!(pull_res.is_ok()); + println!("{:#?}", pull_res); + let pull_res = pull_res.unwrap(); + + let node_5 = &node_id_hash(&dot_structures::Id::Plain(String::from("5"))).to_string(); + let node_4 = &node_id_hash(&dot_structures::Id::Plain(String::from("4"))).to_string(); + let node_3 = &node_id_hash(&dot_structures::Id::Plain(String::from("3"))).to_string(); + let node_1 = &node_id_hash(&dot_structures::Id::Plain(String::from("1"))).to_string(); + let expected_additions = vec![ + create_link_expression(node_5, node_5), + create_link_expression(node_4, node_4), + create_link_expression(node_3, node_3), + create_link_expression(node_1, node_1), + ]; + + assert!(pull_res + .diff + .additions + .iter() + .all(|item| expected_additions.contains(item))); + + //ensure that no merge was created + //let latest = MockPerspectiveGraph::latest_revision(); + //assert!(latest.unwrap().unwrap().hash == latest_node_hash); + } + + #[test] + fn test_four_null_parents() { + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::from_dot( + r#"digraph { + 1 [ label = "1" ] + 2 [ label = "2" ] + 3 [ label = "3" ] + 4 [ label = "4" ] + 5 [ label = "5" ] + 6 [ label = "6" ] + + 4 -> 2 + 4 -> 3 + 5 -> 4 + 5 -> 1 + }"#, + ) + .unwrap(); + } + update(); + + let latest_node_hash = node_id_hash(&dot_structures::Id::Plain(String::from("5"))); + + let current_node_hash = node_id_hash(&dot_structures::Id::Plain(String::from("6"))); + let update_current = MockPerspectiveGraph::update_current_revision( + current_node_hash.clone(), + chrono::Utc::now(), + ); + assert!(update_current.is_ok()); + + let pull_res = pull::(false, latest_node_hash.clone(), true); + assert!(pull_res.is_ok()); + println!("{:#?}", pull_res); + let pull_res = pull_res.unwrap(); + + let node_5 = &node_id_hash(&dot_structures::Id::Plain(String::from("5"))).to_string(); + let node_4 = &node_id_hash(&dot_structures::Id::Plain(String::from("4"))).to_string(); + let node_3 = &node_id_hash(&dot_structures::Id::Plain(String::from("3"))).to_string(); + let node_2 = &node_id_hash(&dot_structures::Id::Plain(String::from("2"))).to_string(); + let node_1 = &node_id_hash(&dot_structures::Id::Plain(String::from("1"))).to_string(); + let expected_additions = vec![ + create_link_expression(node_5, node_5), + create_link_expression(node_4, node_4), + create_link_expression(node_3, node_3), + create_link_expression(node_2, node_2), + create_link_expression(node_1, node_1), + ]; + + assert!(pull_res + .diff + .additions + .iter() + .all(|item| expected_additions.contains(item))); + + //ensure that merge was created and thus current revision got updated + let current = MockPerspectiveGraph::current_revision(); + assert!(current.unwrap().unwrap().hash != current_node_hash); + } + + #[test] + fn test_high_complex_graph() { + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::from_dot( + &crate::link_adapter::test_graphs::HIGH_COMPLEX_GRAPH, + ) + .unwrap(); + } + update(); + + let latest_node_hash = node_id_hash(&dot_structures::Id::Plain(String::from("52"))); + + let current_node_hash = node_id_hash(&dot_structures::Id::Plain(String::from("55"))); + let update_current = MockPerspectiveGraph::update_current_revision( + current_node_hash.clone(), + chrono::Utc::now(), + ); + assert!(update_current.is_ok()); + + let pull_res = pull::(false, latest_node_hash.clone(), true); + assert!(pull_res.is_ok()); + //println!("{:#?}", pull_res); + let pull_res = pull_res.unwrap(); + + let mut expected_additions = create_node_id_vec(23, 52); + expected_additions.push(create_node_id_link_expression(20)); + expected_additions.push(create_node_id_link_expression(21)); + + for addition in expected_additions.clone() { + assert!(pull_res.diff.additions.contains(&addition)); + } + assert!(pull_res + .diff + .additions + .iter() + .all(|item| expected_additions.contains(item))); + + //ensure that merge was created and thus current revision got updated + let current = MockPerspectiveGraph::current_revision(); + assert!(current.unwrap().unwrap().hash != current_node_hash); + } + + #[test] + fn test_late_join() { + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::from_dot(&crate::link_adapter::test_graphs::LATE_JOIN) + .unwrap(); + } + update(); + + let latest_node_hash = node_id_hash(&dot_structures::Id::Plain(String::from("314"))); + + let current_node_hash = node_id_hash(&dot_structures::Id::Plain(String::from("313"))); + let update_current = MockPerspectiveGraph::update_current_revision( + current_node_hash.clone(), + chrono::Utc::now(), + ); + assert!(update_current.is_ok()); + + let pull_res = pull::(false, latest_node_hash.clone(), true); + assert!(pull_res.is_ok()); + //println!("{:#?}", pull_res); + let pull_res = pull_res.unwrap(); + + let expected_additions = vec![create_node_id_link_expression(314)]; + + assert!(pull_res + .diff + .additions + .iter() + .all(|item| expected_additions.contains(item))); + + //ensure that merge was created and thus current revision got updated + let current = MockPerspectiveGraph::current_revision(); + assert!(current.unwrap().unwrap().hash != current_node_hash); + } + + #[test] + fn test_late_join_from_syncd() { + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::from_dot(&crate::link_adapter::test_graphs::LATE_JOIN2) + .unwrap(); + } + update(); + + let latest_node_hash = node_id_hash(&dot_structures::Id::Plain(String::from("304"))); + + let current_node_hash = node_id_hash(&dot_structures::Id::Plain(String::from("301"))); + let update_current = MockPerspectiveGraph::update_current_revision( + current_node_hash.clone(), + chrono::Utc::now(), + ); + assert!(update_current.is_ok()); + + let pull_res = pull::(false, latest_node_hash.clone(), true); + assert!(pull_res.is_ok()); + let pull_res = pull_res.unwrap(); + + let expected_additions = vec![ + create_node_id_link_expression(304), + create_node_id_link_expression(303), + create_node_id_link_expression(302), + ]; + + assert!(pull_res + .diff + .additions + .iter() + .all(|item| expected_additions.contains(item))); + + //ensure that merge was created and thus current revision got updated + let current = MockPerspectiveGraph::current_revision(); + assert!(current.unwrap().unwrap().hash != current_node_hash); + } + + #[test] + fn test_late_join_from_unsyncd() { + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::from_dot(&crate::link_adapter::test_graphs::LATE_JOIN2) + .unwrap(); + } + update(); + + let latest_node_hash = node_id_hash(&dot_structures::Id::Plain(String::from("301"))); + + let current_node_hash = node_id_hash(&dot_structures::Id::Plain(String::from("304"))); + let update_current = MockPerspectiveGraph::update_current_revision( + current_node_hash.clone(), + chrono::Utc::now(), + ); + assert!(update_current.is_ok()); + + let pull_res = pull::(false, latest_node_hash.clone(), true); + assert!(pull_res.is_ok()); + let pull_res = pull_res.unwrap(); + + let expected_additions = create_node_id_vec(1, 301); + + assert!(pull_res + .diff + .additions + .iter() + .all(|item| expected_additions.contains(item))); + + //ensure that merge was created and thus current revision got updated + let current = MockPerspectiveGraph::current_revision(); + assert!(current.unwrap().unwrap().hash != current_node_hash); + } +} diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/render.rs b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/render.rs new file mode 100644 index 000000000..1b41a886d --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/render.rs @@ -0,0 +1,42 @@ +use hdk::prelude::*; +use perspective_diff_sync_integrity::PerspectiveDiff; + +use crate::errors::{SocialContextError, SocialContextResult}; +use crate::link_adapter::revisions::current_revision; +use crate::link_adapter::workspace::Workspace; +use crate::retriever::PerspectiveDiffRetreiver; +use crate::utils::get_now; +use crate::Perspective; + +pub fn render() -> SocialContextResult { + debug!("===PerspectiveDiffSync.render(): Function start"); + let fn_start = get_now()?.time(); + + let current = current_revision::()?.ok_or(SocialContextError::InternalError( + "Can't render when we have no current revision", + ))?; + + debug!("===PerspectiveDiffSync.render(): current: {:?}", current); + + let mut workspace = Workspace::new(); + workspace.collect_only_from_latest::(current.hash)?; + + let mut perspective = Perspective { links: vec![] }; + for diff_node in workspace.entry_map { + let diff_entry = Retriever::get::(diff_node.1.diff.clone())?; + + for addition in diff_entry.additions { + perspective.links.push(addition); + } + for removal in diff_entry.removals { + perspective.links.retain(|l| l != &removal); + } + } + + let fn_end = get_now()?.time(); + debug!( + "===PerspectiveDiffSync.render() - Profiling: Took: {} to complete render() function", + (fn_end - fn_start).num_milliseconds() + ); + Ok(perspective) +} diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/revisions.rs b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/revisions.rs new file mode 100644 index 000000000..e0a7cd09f --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/revisions.rs @@ -0,0 +1,32 @@ +use chrono::{DateTime, Utc}; +use hdk::prelude::debug; +use perspective_diff_sync_integrity::LocalHashReference; + +use crate::errors::SocialContextResult; +use crate::retriever::PerspectiveDiffRetreiver; +use crate::utils::get_now; +use crate::Hash; + +pub fn update_current_revision( + hash: Hash, + timestamp: DateTime, +) -> SocialContextResult<()> { + debug!("===PerspectiveDiffSync.update_current_revision(): Function start"); + let now = get_now()?.time(); + let res = Retriever::update_current_revision(hash, timestamp); + let after = get_now()?.time(); + debug!("===PerspectiveDiffSync.update_current_revision() - Profiling: Took: {} to update current_revision", (after - now).num_milliseconds()); + res +} + +//Latest revision as seen from our local state +pub fn current_revision( +) -> SocialContextResult> { + //debug!("===PerspectiveDiffSync.current_revision(): Function start"); + //let now = get_now()?.time(); + let rev = Retriever::current_revision()?; + // debug!("===PerspectiveDiffSync.current_revision(): rev = {:?}", rev); + //let after = get_now()?.time(); + //debug!("===PerspectiveDiffSync.current_revision() - Profiling: Took: {} to get the current_revision", (after - now).num_milliseconds()); + Ok(rev) +} diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/snapshots.rs b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/snapshots.rs new file mode 100644 index 000000000..e366c16a5 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/snapshots.rs @@ -0,0 +1,264 @@ +use hdk::prelude::*; +use perspective_diff_sync_integrity::{ + LinkExpression, LinkTypes, PerspectiveDiff, PerspectiveDiffEntryReference, Snapshot, +}; + +use crate::errors::{SocialContextError, SocialContextResult}; +use crate::link_adapter::chunked_diffs::ChunkedDiffs; +use crate::retriever::HolochainRetreiver; +use crate::utils::get_now; +use crate::{Hash, CHUNK_SIZE}; + +struct SearchPosition { + hash: Hash, + is_unseen: bool, +} + +pub fn generate_snapshot( + latest: HoloHash, +) -> SocialContextResult { + debug!("===PerspectiveDiffSync.generate_snapshot(): Function start"); + let fn_start = get_now()?.time(); + let mut search_position = SearchPosition { + hash: latest.clone(), + is_unseen: false, + }; + let mut seen: HashSet = HashSet::new(); + let mut unseen_parents = vec![]; + + let mut all_additions = BTreeSet::new(); + let mut all_removals = BTreeSet::new(); + + loop { + let diff = get(search_position.hash.clone(), GetOptions::latest())? + .ok_or(SocialContextError::InternalError( + "generate_snapshot(): Could not find entry while populating search", + ))? + .entry() + .to_app_option::()? + .ok_or(SocialContextError::InternalError( + "Expected element to contain app entry data", + ))?; + if diff.diffs_since_snapshot == 0 && search_position.hash != latest { + let now = get_now()?.time(); + // let input = GetLinksInputBuilder::try_new( + // hash_entry(&diff)?, + // LinkTypes::Snapshot + // ) + // .unwrap() + // .tag_prefix(LinkTag::new("snapshot")) + // .build(); + let mut snapshot_links = get_links(hash_entry(&diff)?, LinkTypes::Snapshot, Some(LinkTag::new("snapshot")))?; + let after = get_now()?.time(); + debug!("===PerspectiveDiffSync.generate_snapshot() - Profiling: Took {} to get the snapshot links", (after - now).num_milliseconds()); + if snapshot_links.len() == 0 { + debug!("===PerspectiveDiffSync.generate_snapshot() - ERROR: Did not find snapshot link where we expected to!"); + let should_break = handle_parents( + diff, + &mut search_position, + &mut seen, + &mut unseen_parents, + &mut all_additions, + &mut all_removals, + )?; + if should_break { + break; + } + } else { + let now = get_now()?.time(); + //get snapshot and add elements to out + let snapshot = get( + snapshot_links + .remove(0) + .target + .into_entry_hash() + .expect("Could not get entry_hash"), + GetOptions::latest(), + )? + .ok_or(SocialContextError::InternalError( + "Could not find diff entry for given diff entry reference", + ))? + .entry() + .to_app_option::()? + .ok_or(SocialContextError::InternalError( + "Expected element to contain app entry data", + ))?; + let after = get_now()?.time(); + debug!("===PerspectiveDiffSync.generate_snapshot() - Profiling: Took {} to get the snapshot entry", (after - now).num_milliseconds()); + + let diff = ChunkedDiffs::from_entries::(snapshot.diff_chunks)? + .into_aggregated_diff(); + for addition in diff.additions.iter() { + all_additions.insert(addition.clone()); + } + for removal in diff.removals.iter() { + all_removals.insert(removal.clone()); + } + for hash in snapshot.included_diffs.iter() { + seen.insert(hash.clone()); + } + //Be careful with break here where there are still unseen parents + if unseen_parents.len() == 0 { + // debug!("No more unseen parents within snapshot block"); + break; + } else { + search_position = unseen_parents.remove(0); + } + }; + } else { + let should_break = handle_parents( + diff, + &mut search_position, + &mut seen, + &mut unseen_parents, + &mut all_additions, + &mut all_removals, + )?; + if should_break { + break; + } + } + } + + let mut chunked_diffs = ChunkedDiffs::new(*CHUNK_SIZE); + + chunked_diffs.add_additions(all_additions.into_iter().collect()); + chunked_diffs.add_removals(all_removals.into_iter().collect()); + + let snapshot = Snapshot { + diff_chunks: chunked_diffs.into_entries::()?, + included_diffs: seen.into_iter().collect(), + }; + + let fn_end = get_now()?.time(); + debug!("===PerspectiveDiffSync.generate_snapshot() - Profiling: Took: {} to complete generate_snapshot function", (fn_end - fn_start).num_milliseconds()); + Ok(snapshot) +} + +fn handle_parents( + diff: PerspectiveDiffEntryReference, + search_position: &mut SearchPosition, + seen: &mut HashSet, + unseen_parents: &mut Vec, + all_additions: &mut BTreeSet, + all_removals: &mut BTreeSet, +) -> SocialContextResult { + //Check if entry is already in graph + if !seen.contains(&search_position.hash) { + seen.insert(search_position.hash.clone()); + let diff_entry = get(diff.diff.clone(), GetOptions::latest())? + .ok_or(SocialContextError::InternalError( + "Could not find diff entry for given diff entry reference", + ))? + .entry() + .to_app_option::()? + .ok_or(SocialContextError::InternalError( + "Expected element to contain app entry data", + ))?; + + for addition in diff_entry.additions.iter() { + all_additions.insert(addition.clone()); + } + for removal in diff_entry.removals.iter() { + all_removals.insert(removal.clone()); + } + + if diff.parents.is_none() { + //No parents, we have reached the end of the chain + //Now move onto traversing unseen parents, or break if we dont have any other paths to search + if unseen_parents.len() == 0 { + // debug!("No more unseen items within parent block"); + Ok(true) + } else { + // debug!("Moving onto unseen fork items within parent block"); + *search_position = unseen_parents.remove(0); + Ok(false) + } + } else { + //Do the fork traversals + let mut parents = diff.parents.unwrap(); + //Check if all parents have already been seen, if so then break or move onto next unseen parents + //TODO; we should use a seen set here versus array iter + if parents.iter().all(|val| seen.contains(val)) { + if unseen_parents.len() == 0 { + // debug!("Parents of item seen and unseen 0"); + return Ok(true); + } else { + // debug!("last moving onto unseen"); + *search_position = unseen_parents.remove(0); + Ok(false) + } + } else { + *search_position = SearchPosition { + hash: parents.remove(0), + is_unseen: false, + }; + // debug!("Appending parents to look up"); + unseen_parents.append( + &mut parents + .into_iter() + .map(|val| SearchPosition { + hash: val, + is_unseen: true, + }) + .collect(), + ); + Ok(false) + } + } + } else if search_position.is_unseen { + //The parent for this branch is already seen so likely already explored and we are part of the main branch + if unseen_parents.len() == 0 { + // debug!("No more unseen items within parent block"); + Ok(true) + } else { + // debug!("Moving onto unseen fork items within parent block"); + *search_position = unseen_parents.remove(0); + Ok(false) + } + } else { + if diff.parents.is_none() { + //No parents, we have reached the end of the chain + //Now move onto traversing unseen parents, or break if we dont have any other paths to search + if unseen_parents.len() == 0 { + // debug!("No more unseen items within parent block"); + Ok(true) + } else { + // debug!("Moving onto unseen fork items within parent block"); + *search_position = unseen_parents.remove(0); + Ok(false) + } + } else { + //Do the fork traversals + let mut parents = diff.parents.unwrap(); + //Check if all parents have already been seen, if so then break or move onto next unseen parents + //TODO; we should use a seen set here versus array iter + if parents.iter().all(|val| seen.contains(val)) { + if unseen_parents.len() == 0 { + // debug!("Parents of item seen and unseen 0"); + Ok(true) + } else { + // debug!("last moving onto unseen"); + *search_position = unseen_parents.remove(0); + Ok(false) + } + } else { + *search_position = SearchPosition { + hash: parents.remove(0), + is_unseen: false, + }; + // debug!("Appending parents to look up"); + unseen_parents.append( + &mut parents + .into_iter() + .map(|val| SearchPosition { + hash: val, + is_unseen: true, + }) + .collect(), + ); + Ok(false) + } + } + } +} diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/test_graphs.rs b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/test_graphs.rs new file mode 100644 index 000000000..fea27288c --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/test_graphs.rs @@ -0,0 +1,1495 @@ +lazy_static! { + pub static ref LATE_JOIN: String = String::from(r#"digraph { + 1 [ label = "1" ] + 2 [ label = "2" ] + 3 [ label = "3" ] + 4 [ label = "4" ] + 5 [ label = "5" ] + 6 [ label = "6" ] + 7 [ label = "7" ] + 8 [ label = "8" ] + 9 [ label = "9" ] + 10 [ label = "10" ] + 11 [ label = "11" ] + 12 [ label = "12" ] + 13 [ label = "13" ] + 14 [ label = "14" ] + 15 [ label = "15" ] + 16 [ label = "16" ] + 17 [ label = "17" ] + 18 [ label = "18" ] + 19 [ label = "19" ] + 20 [ label = "20" ] + 21 [ label = "21" ] + 22 [ label = "22" ] + 23 [ label = "23" ] + 24 [ label = "24" ] + 25 [ label = "25" ] + 26 [ label = "26" ] + 27 [ label = "27" ] + 28 [ label = "28" ] + 29 [ label = "29" ] + 30 [ label = "30" ] + 31 [ label = "31" ] + 32 [ label = "32" ] + 33 [ label = "33" ] + 34 [ label = "34" ] + 35 [ label = "35" ] + 36 [ label = "36" ] + 37 [ label = "37" ] + 38 [ label = "38" ] + 39 [ label = "39" ] + 40 [ label = "40" ] + 41 [ label = "41" ] + 42 [ label = "42" ] + 43 [ label = "43" ] + 44 [ label = "44" ] + 45 [ label = "45" ] + 46 [ label = "46" ] + 47 [ label = "47" ] + 48 [ label = "48" ] + 49 [ label = "49" ] + 50 [ label = "50" ] + 51 [ label = "51" ] + 52 [ label = "52" ] + 53 [ label = "53" ] + 54 [ label = "54" ] + 55 [ label = "55" ] + 56 [ label = "56" ] + 57 [ label = "57" ] + 58 [ label = "58" ] + 59 [ label = "59" ] + 60 [ label = "60" ] + 61 [ label = "61" ] + 62 [ label = "62" ] + 63 [ label = "63" ] + 64 [ label = "64" ] + 65 [ label = "65" ] + 66 [ label = "66" ] + 67 [ label = "67" ] + 68 [ label = "68" ] + 69 [ label = "69" ] + 70 [ label = "70" ] + 71 [ label = "71" ] + 72 [ label = "72" ] + 73 [ label = "73" ] + 74 [ label = "74" ] + 75 [ label = "75" ] + 76 [ label = "76" ] + 77 [ label = "77" ] + 78 [ label = "78" ] + 79 [ label = "79" ] + 80 [ label = "80" ] + 81 [ label = "81" ] + 82 [ label = "82" ] + 83 [ label = "83" ] + 84 [ label = "84" ] + 85 [ label = "85" ] + 86 [ label = "86" ] + 87 [ label = "87" ] + 88 [ label = "88" ] + 89 [ label = "89" ] + 90 [ label = "90" ] + 91 [ label = "91" ] + 92 [ label = "92" ] + 93 [ label = "93" ] + 94 [ label = "94" ] + 95 [ label = "95" ] + 96 [ label = "96" ] + 97 [ label = "97" ] + 98 [ label = "98" ] + 99 [ label = "99" ] + 100 [ label = "100" ] + 101 [ label = "101" ] + 102 [ label = "102" ] + 103 [ label = "103" ] + 104 [ label = "104" ] + 105 [ label = "105" ] + 106 [ label = "106" ] + 107 [ label = "107" ] + 108 [ label = "108" ] + 109 [ label = "109" ] + 110 [ label = "110" ] + 111 [ label = "111" ] + 112 [ label = "112" ] + 113 [ label = "113" ] + 114 [ label = "114" ] + 115 [ label = "115" ] + 116 [ label = "116" ] + 117 [ label = "117" ] + 118 [ label = "118" ] + 119 [ label = "119" ] + 120 [ label = "120" ] + 121 [ label = "121" ] + 122 [ label = "122" ] + 123 [ label = "123" ] + 124 [ label = "124" ] + 125 [ label = "125" ] + 126 [ label = "126" ] + 127 [ label = "127" ] + 128 [ label = "128" ] + 129 [ label = "129" ] + 130 [ label = "130" ] + 131 [ label = "131" ] + 132 [ label = "132" ] + 133 [ label = "133" ] + 134 [ label = "134" ] + 135 [ label = "135" ] + 136 [ label = "136" ] + 137 [ label = "137" ] + 138 [ label = "138" ] + 139 [ label = "139" ] + 140 [ label = "140" ] + 141 [ label = "141" ] + 142 [ label = "142" ] + 143 [ label = "143" ] + 144 [ label = "144" ] + 145 [ label = "145" ] + 146 [ label = "146" ] + 147 [ label = "147" ] + 148 [ label = "148" ] + 149 [ label = "149" ] + 150 [ label = "150" ] + 151 [ label = "151" ] + 152 [ label = "152" ] + 153 [ label = "153" ] + 154 [ label = "154" ] + 155 [ label = "155" ] + 156 [ label = "156" ] + 157 [ label = "157" ] + 158 [ label = "158" ] + 159 [ label = "159" ] + 160 [ label = "160" ] + 161 [ label = "161" ] + 162 [ label = "162" ] + 163 [ label = "163" ] + 164 [ label = "164" ] + 165 [ label = "165" ] + 166 [ label = "166" ] + 167 [ label = "167" ] + 168 [ label = "168" ] + 169 [ label = "169" ] + 170 [ label = "170" ] + 171 [ label = "171" ] + 172 [ label = "172" ] + 173 [ label = "173" ] + 174 [ label = "174" ] + 175 [ label = "175" ] + 176 [ label = "176" ] + 177 [ label = "177" ] + 178 [ label = "178" ] + 179 [ label = "179" ] + 180 [ label = "180" ] + 181 [ label = "181" ] + 182 [ label = "182" ] + 183 [ label = "183" ] + 184 [ label = "184" ] + 185 [ label = "185" ] + 186 [ label = "186" ] + 187 [ label = "187" ] + 188 [ label = "188" ] + 189 [ label = "189" ] + 190 [ label = "190" ] + 191 [ label = "191" ] + 192 [ label = "192" ] + 193 [ label = "193" ] + 194 [ label = "194" ] + 195 [ label = "195" ] + 196 [ label = "196" ] + 197 [ label = "197" ] + 198 [ label = "198" ] + 199 [ label = "199" ] + 200 [ label = "200" ] + 201 [ label = "201" ] + 202 [ label = "202" ] + 203 [ label = "203" ] + 204 [ label = "204" ] + 205 [ label = "205" ] + 206 [ label = "206" ] + 207 [ label = "207" ] + 208 [ label = "208" ] + 209 [ label = "209" ] + 210 [ label = "210" ] + 211 [ label = "211" ] + 212 [ label = "212" ] + 213 [ label = "213" ] + 214 [ label = "214" ] + 215 [ label = "215" ] + 216 [ label = "216" ] + 217 [ label = "217" ] + 218 [ label = "218" ] + 219 [ label = "219" ] + 220 [ label = "220" ] + 221 [ label = "221" ] + 222 [ label = "222" ] + 223 [ label = "223" ] + 224 [ label = "224" ] + 225 [ label = "225" ] + 226 [ label = "226" ] + 227 [ label = "227" ] + 228 [ label = "228" ] + 229 [ label = "229" ] + 230 [ label = "230" ] + 231 [ label = "231" ] + 232 [ label = "232" ] + 233 [ label = "233" ] + 234 [ label = "234" ] + 235 [ label = "235" ] + 236 [ label = "236" ] + 237 [ label = "237" ] + 238 [ label = "238" ] + 239 [ label = "239" ] + 240 [ label = "240" ] + 241 [ label = "241" ] + 242 [ label = "242" ] + 243 [ label = "243" ] + 244 [ label = "244" ] + 245 [ label = "245" ] + 246 [ label = "246" ] + 247 [ label = "247" ] + 248 [ label = "248" ] + 249 [ label = "249" ] + 250 [ label = "250" ] + 251 [ label = "251" ] + 252 [ label = "252" ] + 253 [ label = "253" ] + 254 [ label = "254" ] + 255 [ label = "255" ] + 256 [ label = "256" ] + 257 [ label = "257" ] + 258 [ label = "258" ] + 259 [ label = "259" ] + 260 [ label = "260" ] + 261 [ label = "261" ] + 262 [ label = "262" ] + 263 [ label = "263" ] + 264 [ label = "264" ] + 265 [ label = "265" ] + 266 [ label = "266" ] + 267 [ label = "267" ] + 268 [ label = "268" ] + 269 [ label = "269" ] + 270 [ label = "270" ] + 271 [ label = "271" ] + 272 [ label = "272" ] + 273 [ label = "273" ] + 274 [ label = "274" ] + 275 [ label = "275" ] + 276 [ label = "276" ] + 277 [ label = "277" ] + 278 [ label = "278" ] + 279 [ label = "279" ] + 280 [ label = "280" ] + 281 [ label = "281" ] + 282 [ label = "282" ] + 283 [ label = "283" ] + 284 [ label = "284" ] + 285 [ label = "285" ] + 286 [ label = "286" ] + 287 [ label = "287" ] + 288 [ label = "288" ] + 289 [ label = "289" ] + 290 [ label = "290" ] + 291 [ label = "291" ] + 292 [ label = "292" ] + 293 [ label = "293" ] + 294 [ label = "294" ] + 295 [ label = "295" ] + 296 [ label = "296" ] + 297 [ label = "297" ] + 298 [ label = "298" ] + 299 [ label = "299" ] + 300 [ label = "300" ] + 301 [ label = "301" ] + 302 [ label = "302" ] + 303 [ label = "303" ] + 304 [ label = "304" ] + 305 [ label = "305" ] + 306 [ label = "306" ] + 307 [ label = "307" ] + 308 [ label = "308" ] + 309 [ label = "309" ] + 310 [ label = "310" ] + 311 [ label = "311" ] + 312 [ label = "312" ] + 313 [ label = "313" ] + 314 [ label = "314" ] + 3 -> 2 [ label = "()" ] + 4 -> 3 [ label = "()" ] + 5 -> 4 [ label = "()" ] + 6 -> 5 [ label = "()" ] + 7 -> 6 [ label = "()" ] + 8 -> 7 [ label = "()" ] + 9 -> 8 [ label = "()" ] + 11 -> 10 [ label = "()" ] + 11 -> 9 [ label = "()" ] + 12 -> 10 [ label = "()" ] + 13 -> 12 [ label = "()" ] + 14 -> 13 [ label = "()" ] + 14 -> 11 [ label = "()" ] + 15 -> 14 [ label = "()" ] + 16 -> 15 [ label = "()" ] + 17 -> 16 [ label = "()" ] + 18 -> 17 [ label = "()" ] + 19 -> 18 [ label = "()" ] + 20 -> 19 [ label = "()" ] + 21 -> 16 [ label = "()" ] + 22 -> 21 [ label = "()" ] + 23 -> 20 [ label = "()" ] + 23 -> 22 [ label = "()" ] + 24 -> 23 [ label = "()" ] + 25 -> 24 [ label = "()" ] + 26 -> 25 [ label = "()" ] + 27 -> 26 [ label = "()" ] + 28 -> 25 [ label = "()" ] + 29 -> 28 [ label = "()" ] + 30 -> 29 [ label = "()" ] + 30 -> 27 [ label = "()" ] + 32 -> 31 [ label = "()" ] + 32 -> 30 [ label = "()" ] + 33 -> 32 [ label = "()" ] + 34 -> 32 [ label = "()" ] + 35 -> 34 [ label = "()" ] + 35 -> 33 [ label = "()" ] + 36 -> 35 [ label = "()" ] + 37 -> 36 [ label = "()" ] + 38 -> 37 [ label = "()" ] + 39 -> 38 [ label = "()" ] + 40 -> 35 [ label = "()" ] + 41 -> 40 [ label = "()" ] + 42 -> 39 [ label = "()" ] + 42 -> 41 [ label = "()" ] + 43 -> 42 [ label = "()" ] + 44 -> 43 [ label = "()" ] + 45 -> 44 [ label = "()" ] + 46 -> 45 [ label = "()" ] + 47 -> 46 [ label = "()" ] + 48 -> 47 [ label = "()" ] + 49 -> 48 [ label = "()" ] + 50 -> 49 [ label = "()" ] + 51 -> 50 [ label = "()" ] + 52 -> 51 [ label = "()" ] + 53 -> 52 [ label = "()" ] + 54 -> 53 [ label = "()" ] + 55 -> 54 [ label = "()" ] + 56 -> 55 [ label = "()" ] + 57 -> 56 [ label = "()" ] + 58 -> 57 [ label = "()" ] + 59 -> 58 [ label = "()" ] + 60 -> 59 [ label = "()" ] + 61 -> 60 [ label = "()" ] + 62 -> 61 [ label = "()" ] + 63 -> 62 [ label = "()" ] + 64 -> 63 [ label = "()" ] + 65 -> 64 [ label = "()" ] + 66 -> 65 [ label = "()" ] + 67 -> 66 [ label = "()" ] + 68 -> 67 [ label = "()" ] + 69 -> 68 [ label = "()" ] + 70 -> 69 [ label = "()" ] + 71 -> 70 [ label = "()" ] + 72 -> 71 [ label = "()" ] + 73 -> 72 [ label = "()" ] + 74 -> 73 [ label = "()" ] + 75 -> 74 [ label = "()" ] + 76 -> 75 [ label = "()" ] + 77 -> 76 [ label = "()" ] + 78 -> 77 [ label = "()" ] + 79 -> 78 [ label = "()" ] + 80 -> 79 [ label = "()" ] + 81 -> 80 [ label = "()" ] + 82 -> 81 [ label = "()" ] + 83 -> 82 [ label = "()" ] + 84 -> 83 [ label = "()" ] + 85 -> 84 [ label = "()" ] + 86 -> 85 [ label = "()" ] + 87 -> 86 [ label = "()" ] + 88 -> 87 [ label = "()" ] + 89 -> 88 [ label = "()" ] + 90 -> 89 [ label = "()" ] + 91 -> 90 [ label = "()" ] + 92 -> 91 [ label = "()" ] + 93 -> 92 [ label = "()" ] + 94 -> 93 [ label = "()" ] + 95 -> 94 [ label = "()" ] + 96 -> 95 [ label = "()" ] + 97 -> 96 [ label = "()" ] + 98 -> 97 [ label = "()" ] + 99 -> 98 [ label = "()" ] + 100 -> 99 [ label = "()" ] + 101 -> 100 [ label = "()" ] + 102 -> 101 [ label = "()" ] + 103 -> 102 [ label = "()" ] + 104 -> 103 [ label = "()" ] + 105 -> 104 [ label = "()" ] + 106 -> 105 [ label = "()" ] + 107 -> 106 [ label = "()" ] + 108 -> 107 [ label = "()" ] + 109 -> 108 [ label = "()" ] + 110 -> 81 [ label = "()" ] + 111 -> 110 [ label = "()" ] + 112 -> 111 [ label = "()" ] + 113 -> 100 [ label = "()" ] + 113 -> 112 [ label = "()" ] + 114 -> 109 [ label = "()" ] + 114 -> 113 [ label = "()" ] + 115 -> 1 [ label = "()" ] + 115 -> 114 [ label = "()" ] + 116 -> 1 [ label = "()" ] + 116 -> 114 [ label = "()" ] + 117 -> 115 [ label = "()" ] + 117 -> 116 [ label = "()" ] + 118 -> 117 [ label = "()" ] + 119 -> 118 [ label = "()" ] + 120 -> 119 [ label = "()" ] + 121 -> 120 [ label = "()" ] + 122 -> 121 [ label = "()" ] + 123 -> 122 [ label = "()" ] + 124 -> 123 [ label = "()" ] + 125 -> 124 [ label = "()" ] + 126 -> 125 [ label = "()" ] + 127 -> 126 [ label = "()" ] + 128 -> 127 [ label = "()" ] + 129 -> 128 [ label = "()" ] + 130 -> 129 [ label = "()" ] + 131 -> 130 [ label = "()" ] + 132 -> 131 [ label = "()" ] + 133 -> 132 [ label = "()" ] + 134 -> 133 [ label = "()" ] + 135 -> 134 [ label = "()" ] + 136 -> 135 [ label = "()" ] + 137 -> 136 [ label = "()" ] + 138 -> 115 [ label = "()" ] + 138 -> 116 [ label = "()" ] + 139 -> 138 [ label = "()" ] + 140 -> 127 [ label = "()" ] + 140 -> 139 [ label = "()" ] + 141 -> 139 [ label = "()" ] + 142 -> 137 [ label = "()" ] + 142 -> 141 [ label = "()" ] + 143 -> 142 [ label = "()" ] + 143 -> 140 [ label = "()" ] + 144 -> 143 [ label = "()" ] + 145 -> 144 [ label = "()" ] + 146 -> 145 [ label = "()" ] + 147 -> 146 [ label = "()" ] + 148 -> 147 [ label = "()" ] + 149 -> 148 [ label = "()" ] + 150 -> 149 [ label = "()" ] + 151 -> 150 [ label = "()" ] + 152 -> 151 [ label = "()" ] + 153 -> 152 [ label = "()" ] + 154 -> 153 [ label = "()" ] + 155 -> 154 [ label = "()" ] + 156 -> 155 [ label = "()" ] + 157 -> 156 [ label = "()" ] + 158 -> 157 [ label = "()" ] + 159 -> 158 [ label = "()" ] + 160 -> 159 [ label = "()" ] + 161 -> 160 [ label = "()" ] + 162 -> 161 [ label = "()" ] + 163 -> 162 [ label = "()" ] + 164 -> 163 [ label = "()" ] + 165 -> 164 [ label = "()" ] + 166 -> 165 [ label = "()" ] + 167 -> 166 [ label = "()" ] + 168 -> 167 [ label = "()" ] + 169 -> 168 [ label = "()" ] + 170 -> 169 [ label = "()" ] + 171 -> 170 [ label = "()" ] + 172 -> 171 [ label = "()" ] + 173 -> 172 [ label = "()" ] + 174 -> 173 [ label = "()" ] + 175 -> 174 [ label = "()" ] + 176 -> 175 [ label = "()" ] + 177 -> 176 [ label = "()" ] + 178 -> 177 [ label = "()" ] + 179 -> 178 [ label = "()" ] + 180 -> 179 [ label = "()" ] + 181 -> 180 [ label = "()" ] + 182 -> 181 [ label = "()" ] + 183 -> 182 [ label = "()" ] + 184 -> 183 [ label = "()" ] + 185 -> 184 [ label = "()" ] + 186 -> 185 [ label = "()" ] + 187 -> 186 [ label = "()" ] + 188 -> 187 [ label = "()" ] + 189 -> 188 [ label = "()" ] + 190 -> 189 [ label = "()" ] + 191 -> 190 [ label = "()" ] + 192 -> 191 [ label = "()" ] + 193 -> 192 [ label = "()" ] + 194 -> 193 [ label = "()" ] + 195 -> 192 [ label = "()" ] + 196 -> 195 [ label = "()" ] + 197 -> 192 [ label = "()" ] + 198 -> 197 [ label = "()" ] + 199 -> 198 [ label = "()" ] + 199 -> 196 [ label = "()" ] + 200 -> 199 [ label = "()" ] + 200 -> 194 [ label = "()" ] + 201 -> 200 [ label = "()" ] + 202 -> 201 [ label = "()" ] + 203 -> 202 [ label = "()" ] + 204 -> 203 [ label = "()" ] + 205 -> 204 [ label = "()" ] + 206 -> 205 [ label = "()" ] + 207 -> 206 [ label = "()" ] + 208 -> 207 [ label = "()" ] + 209 -> 208 [ label = "()" ] + 210 -> 209 [ label = "()" ] + 211 -> 210 [ label = "()" ] + 212 -> 211 [ label = "()" ] + 213 -> 212 [ label = "()" ] + 214 -> 213 [ label = "()" ] + 215 -> 214 [ label = "()" ] + 216 -> 215 [ label = "()" ] + 217 -> 216 [ label = "()" ] + 218 -> 217 [ label = "()" ] + 219 -> 218 [ label = "()" ] + 220 -> 219 [ label = "()" ] + 221 -> 220 [ label = "()" ] + 222 -> 221 [ label = "()" ] + 223 -> 222 [ label = "()" ] + 224 -> 223 [ label = "()" ] + 225 -> 224 [ label = "()" ] + 226 -> 225 [ label = "()" ] + 227 -> 226 [ label = "()" ] + 228 -> 227 [ label = "()" ] + 229 -> 228 [ label = "()" ] + 230 -> 229 [ label = "()" ] + 231 -> 230 [ label = "()" ] + 232 -> 231 [ label = "()" ] + 233 -> 232 [ label = "()" ] + 234 -> 233 [ label = "()" ] + 235 -> 231 [ label = "()" ] + 236 -> 235 [ label = "()" ] + 237 -> 236 [ label = "()" ] + 238 -> 237 [ label = "()" ] + 239 -> 236 [ label = "()" ] + 240 -> 239 [ label = "()" ] + 240 -> 238 [ label = "()" ] + 241 -> 236 [ label = "()" ] + 242 -> 238 [ label = "()" ] + 242 -> 241 [ label = "()" ] + 243 -> 239 [ label = "()" ] + 243 -> 242 [ label = "()" ] + 244 -> 243 [ label = "()" ] + 245 -> 234 [ label = "()" ] + 245 -> 244 [ label = "()" ] + 246 -> 245 [ label = "()" ] + 247 -> 245 [ label = "()" ] + 247 -> 240 [ label = "()" ] + 248 -> 246 [ label = "()" ] + 248 -> 247 [ label = "()" ] + 249 -> 248 [ label = "()" ] + 250 -> 249 [ label = "()" ] + 251 -> 248 [ label = "()" ] + 252 -> 250 [ label = "()" ] + 252 -> 251 [ label = "()" ] + 253 -> 250 [ label = "()" ] + 253 -> 251 [ label = "()" ] + 254 -> 253 [ label = "()" ] + 254 -> 252 [ label = "()" ] + 255 -> 254 [ label = "()" ] + 256 -> 255 [ label = "()" ] + 257 -> 256 [ label = "()" ] + 258 -> 255 [ label = "()" ] + 259 -> 258 [ label = "()" ] + 259 -> 256 [ label = "()" ] + 260 -> 258 [ label = "()" ] + 261 -> 260 [ label = "()" ] + 262 -> 260 [ label = "()" ] + 262 -> 259 [ label = "()" ] + 263 -> 261 [ label = "()" ] + 263 -> 262 [ label = "()" ] + 264 -> 263 [ label = "()" ] + 264 -> 257 [ label = "()" ] + 265 -> 264 [ label = "()" ] + 266 -> 265 [ label = "()" ] + 267 -> 266 [ label = "()" ] + 268 -> 265 [ label = "()" ] + 269 -> 268 [ label = "()" ] + 269 -> 267 [ label = "()" ] + 270 -> 269 [ label = "()" ] + 271 -> 270 [ label = "()" ] + 272 -> 271 [ label = "()" ] + 273 -> 272 [ label = "()" ] + 274 -> 273 [ label = "()" ] + 275 -> 274 [ label = "()" ] + 276 -> 275 [ label = "()" ] + 277 -> 276 [ label = "()" ] + 278 -> 277 [ label = "()" ] + 279 -> 278 [ label = "()" ] + 280 -> 279 [ label = "()" ] + 281 -> 280 [ label = "()" ] + 282 -> 281 [ label = "()" ] + 283 -> 282 [ label = "()" ] + 284 -> 283 [ label = "()" ] + 285 -> 284 [ label = "()" ] + 286 -> 285 [ label = "()" ] + 287 -> 285 [ label = "()" ] + 288 -> 286 [ label = "()" ] + 288 -> 287 [ label = "()" ] + 289 -> 288 [ label = "()" ] + 290 -> 289 [ label = "()" ] + 291 -> 290 [ label = "()" ] + 292 -> 291 [ label = "()" ] + 293 -> 292 [ label = "()" ] + 294 -> 293 [ label = "()" ] + 295 -> 294 [ label = "()" ] + 296 -> 295 [ label = "()" ] + 297 -> 296 [ label = "()" ] + 298 -> 297 [ label = "()" ] + 299 -> 298 [ label = "()" ] + 300 -> 299 [ label = "()" ] + 301 -> 300 [ label = "()" ] + 302 -> 301 [ label = "()" ] + 303 -> 300 [ label = "()" ] + 304 -> 301 [ label = "()" ] + 304 -> 303 [ label = "()" ] + 305 -> 304 [ label = "()" ] + 305 -> 302 [ label = "()" ] + 306 -> 305 [ label = "()" ] + 307 -> 306 [ label = "()" ] + 308 -> 307 [ label = "()" ] + 309 -> 308 [ label = "()" ] + 310 -> 309 [ label = "()" ] + 311 -> 310 [ label = "()" ] + 312 -> 311 [ label = "()" ] + 313 -> 312 [ label = "()" ] + }"#); + pub static ref LATE_JOIN2: String = String::from(r#"digraph { + 1 [ label = "1" ] + 2 [ label = "2" ] + 3 [ label = "3" ] + 4 [ label = "4" ] + 5 [ label = "5" ] + 6 [ label = "6" ] + 7 [ label = "7" ] + 8 [ label = "8" ] + 9 [ label = "9" ] + 10 [ label = "10" ] + 11 [ label = "11" ] + 12 [ label = "12" ] + 13 [ label = "13" ] + 14 [ label = "14" ] + 15 [ label = "15" ] + 16 [ label = "16" ] + 17 [ label = "17" ] + 18 [ label = "18" ] + 19 [ label = "19" ] + 20 [ label = "20" ] + 21 [ label = "21" ] + 22 [ label = "22" ] + 23 [ label = "23" ] + 24 [ label = "24" ] + 25 [ label = "25" ] + 26 [ label = "26" ] + 27 [ label = "27" ] + 28 [ label = "28" ] + 29 [ label = "29" ] + 30 [ label = "30" ] + 31 [ label = "31" ] + 32 [ label = "32" ] + 33 [ label = "33" ] + 34 [ label = "34" ] + 35 [ label = "35" ] + 36 [ label = "36" ] + 37 [ label = "37" ] + 38 [ label = "38" ] + 39 [ label = "39" ] + 40 [ label = "40" ] + 41 [ label = "41" ] + 42 [ label = "42" ] + 43 [ label = "43" ] + 44 [ label = "44" ] + 45 [ label = "45" ] + 46 [ label = "46" ] + 47 [ label = "47" ] + 48 [ label = "48" ] + 49 [ label = "49" ] + 50 [ label = "50" ] + 51 [ label = "51" ] + 52 [ label = "52" ] + 53 [ label = "53" ] + 54 [ label = "54" ] + 55 [ label = "55" ] + 56 [ label = "56" ] + 57 [ label = "57" ] + 58 [ label = "58" ] + 59 [ label = "59" ] + 60 [ label = "60" ] + 61 [ label = "61" ] + 62 [ label = "62" ] + 63 [ label = "63" ] + 64 [ label = "64" ] + 65 [ label = "65" ] + 66 [ label = "66" ] + 67 [ label = "67" ] + 68 [ label = "68" ] + 69 [ label = "69" ] + 70 [ label = "70" ] + 71 [ label = "71" ] + 72 [ label = "72" ] + 73 [ label = "73" ] + 74 [ label = "74" ] + 75 [ label = "75" ] + 76 [ label = "76" ] + 77 [ label = "77" ] + 78 [ label = "78" ] + 79 [ label = "79" ] + 80 [ label = "80" ] + 81 [ label = "81" ] + 82 [ label = "82" ] + 83 [ label = "83" ] + 84 [ label = "84" ] + 85 [ label = "85" ] + 86 [ label = "86" ] + 87 [ label = "87" ] + 88 [ label = "88" ] + 89 [ label = "89" ] + 90 [ label = "90" ] + 91 [ label = "91" ] + 92 [ label = "92" ] + 93 [ label = "93" ] + 94 [ label = "94" ] + 95 [ label = "95" ] + 96 [ label = "96" ] + 97 [ label = "97" ] + 98 [ label = "98" ] + 99 [ label = "99" ] + 100 [ label = "100" ] + 101 [ label = "101" ] + 102 [ label = "102" ] + 103 [ label = "103" ] + 104 [ label = "104" ] + 105 [ label = "105" ] + 106 [ label = "106" ] + 107 [ label = "107" ] + 108 [ label = "108" ] + 109 [ label = "109" ] + 110 [ label = "110" ] + 111 [ label = "111" ] + 112 [ label = "112" ] + 113 [ label = "113" ] + 114 [ label = "114" ] + 115 [ label = "115" ] + 116 [ label = "116" ] + 117 [ label = "117" ] + 118 [ label = "118" ] + 119 [ label = "119" ] + 120 [ label = "120" ] + 121 [ label = "121" ] + 122 [ label = "122" ] + 123 [ label = "123" ] + 124 [ label = "124" ] + 125 [ label = "125" ] + 126 [ label = "126" ] + 127 [ label = "127" ] + 128 [ label = "128" ] + 129 [ label = "129" ] + 130 [ label = "130" ] + 131 [ label = "131" ] + 132 [ label = "132" ] + 133 [ label = "133" ] + 134 [ label = "134" ] + 135 [ label = "135" ] + 136 [ label = "136" ] + 137 [ label = "137" ] + 138 [ label = "138" ] + 139 [ label = "139" ] + 140 [ label = "140" ] + 141 [ label = "141" ] + 142 [ label = "142" ] + 143 [ label = "143" ] + 144 [ label = "144" ] + 145 [ label = "145" ] + 146 [ label = "146" ] + 147 [ label = "147" ] + 148 [ label = "148" ] + 149 [ label = "149" ] + 150 [ label = "150" ] + 151 [ label = "151" ] + 152 [ label = "152" ] + 153 [ label = "153" ] + 154 [ label = "154" ] + 155 [ label = "155" ] + 156 [ label = "156" ] + 157 [ label = "157" ] + 158 [ label = "158" ] + 159 [ label = "159" ] + 160 [ label = "160" ] + 161 [ label = "161" ] + 162 [ label = "162" ] + 163 [ label = "163" ] + 164 [ label = "164" ] + 165 [ label = "165" ] + 166 [ label = "166" ] + 167 [ label = "167" ] + 168 [ label = "168" ] + 169 [ label = "169" ] + 170 [ label = "170" ] + 171 [ label = "171" ] + 172 [ label = "172" ] + 173 [ label = "173" ] + 174 [ label = "174" ] + 175 [ label = "175" ] + 176 [ label = "176" ] + 177 [ label = "177" ] + 178 [ label = "178" ] + 179 [ label = "179" ] + 180 [ label = "180" ] + 181 [ label = "181" ] + 182 [ label = "182" ] + 183 [ label = "183" ] + 184 [ label = "184" ] + 185 [ label = "185" ] + 186 [ label = "186" ] + 187 [ label = "187" ] + 188 [ label = "188" ] + 189 [ label = "189" ] + 190 [ label = "190" ] + 191 [ label = "191" ] + 192 [ label = "192" ] + 193 [ label = "193" ] + 194 [ label = "194" ] + 195 [ label = "195" ] + 196 [ label = "196" ] + 197 [ label = "197" ] + 198 [ label = "198" ] + 199 [ label = "199" ] + 200 [ label = "200" ] + 201 [ label = "201" ] + 202 [ label = "202" ] + 203 [ label = "203" ] + 204 [ label = "204" ] + 205 [ label = "205" ] + 206 [ label = "206" ] + 207 [ label = "207" ] + 208 [ label = "208" ] + 209 [ label = "209" ] + 210 [ label = "210" ] + 211 [ label = "211" ] + 212 [ label = "212" ] + 213 [ label = "213" ] + 214 [ label = "214" ] + 215 [ label = "215" ] + 216 [ label = "216" ] + 217 [ label = "217" ] + 218 [ label = "218" ] + 219 [ label = "219" ] + 220 [ label = "220" ] + 221 [ label = "221" ] + 222 [ label = "222" ] + 223 [ label = "223" ] + 224 [ label = "224" ] + 225 [ label = "225" ] + 226 [ label = "226" ] + 227 [ label = "227" ] + 228 [ label = "228" ] + 229 [ label = "229" ] + 230 [ label = "230" ] + 231 [ label = "231" ] + 232 [ label = "232" ] + 233 [ label = "233" ] + 234 [ label = "234" ] + 235 [ label = "235" ] + 236 [ label = "236" ] + 237 [ label = "237" ] + 238 [ label = "238" ] + 239 [ label = "239" ] + 240 [ label = "240" ] + 241 [ label = "241" ] + 242 [ label = "242" ] + 243 [ label = "243" ] + 244 [ label = "244" ] + 245 [ label = "245" ] + 246 [ label = "246" ] + 247 [ label = "247" ] + 248 [ label = "248" ] + 249 [ label = "249" ] + 250 [ label = "250" ] + 251 [ label = "251" ] + 252 [ label = "252" ] + 253 [ label = "253" ] + 254 [ label = "254" ] + 255 [ label = "255" ] + 256 [ label = "256" ] + 257 [ label = "257" ] + 258 [ label = "258" ] + 259 [ label = "259" ] + 260 [ label = "260" ] + 261 [ label = "261" ] + 262 [ label = "262" ] + 263 [ label = "263" ] + 264 [ label = "264" ] + 265 [ label = "265" ] + 266 [ label = "266" ] + 267 [ label = "267" ] + 268 [ label = "268" ] + 269 [ label = "269" ] + 270 [ label = "270" ] + 271 [ label = "271" ] + 272 [ label = "272" ] + 273 [ label = "273" ] + 274 [ label = "274" ] + 275 [ label = "275" ] + 276 [ label = "276" ] + 277 [ label = "277" ] + 278 [ label = "278" ] + 279 [ label = "279" ] + 280 [ label = "280" ] + 281 [ label = "281" ] + 282 [ label = "282" ] + 283 [ label = "283" ] + 284 [ label = "284" ] + 285 [ label = "285" ] + 286 [ label = "286" ] + 287 [ label = "287" ] + 288 [ label = "288" ] + 289 [ label = "289" ] + 290 [ label = "290" ] + 291 [ label = "291" ] + 292 [ label = "292" ] + 293 [ label = "293" ] + 294 [ label = "294" ] + 295 [ label = "295" ] + 296 [ label = "296" ] + 297 [ label = "297" ] + 298 [ label = "298" ] + 299 [ label = "299" ] + 300 [ label = "300" ] + 301 [ label = "301" ] + 302 [ label = "302" ] + 303 [ label = "303" ] + 304 [ label = "304" ] + 6 -> 5 [ label = "()" ] + 7 -> 6 [ label = "()" ] + 8 -> 7 [ label = "()" ] + 9 -> 8 [ label = "()" ] + 10 -> 9 [ label = "()" ] + 11 -> 10 [ label = "()" ] + 12 -> 11 [ label = "()" ] + 13 -> 12 [ label = "()" ] + 14 -> 3 [ label = "()" ] + 14 -> 13 [ label = "()" ] + 15 -> 14 [ label = "()" ] + 16 -> 15 [ label = "()" ] + 17 -> 16 [ label = "()" ] + 18 -> 17 [ label = "()" ] + 19 -> 18 [ label = "()" ] + 20 -> 19 [ label = "()" ] + 21 -> 20 [ label = "()" ] + 22 -> 2 [ label = "()" ] + 22 -> 18 [ label = "()" ] + 23 -> 22 [ label = "()" ] + 24 -> 23 [ label = "()" ] + 25 -> 24 [ label = "()" ] + 26 -> 25 [ label = "()" ] + 26 -> 21 [ label = "()" ] + 27 -> 22 [ label = "()" ] + 28 -> 24 [ label = "()" ] + 28 -> 27 [ label = "()" ] + 29 -> 28 [ label = "()" ] + 30 -> 29 [ label = "()" ] + 31 -> 30 [ label = "()" ] + 32 -> 31 [ label = "()" ] + 33 -> 32 [ label = "()" ] + 33 -> 25 [ label = "()" ] + 34 -> 32 [ label = "()" ] + 34 -> 26 [ label = "()" ] + 35 -> 34 [ label = "()" ] + 36 -> 35 [ label = "()" ] + 37 -> 36 [ label = "()" ] + 38 -> 37 [ label = "()" ] + 39 -> 38 [ label = "()" ] + 40 -> 39 [ label = "()" ] + 41 -> 40 [ label = "()" ] + 42 -> 41 [ label = "()" ] + 43 -> 42 [ label = "()" ] + 44 -> 43 [ label = "()" ] + 45 -> 34 [ label = "()" ] + 45 -> 33 [ label = "()" ] + 46 -> 41 [ label = "()" ] + 46 -> 45 [ label = "()" ] + 47 -> 44 [ label = "()" ] + 47 -> 46 [ label = "()" ] + 48 -> 45 [ label = "()" ] + 48 -> 4 [ label = "()" ] + 49 -> 41 [ label = "()" ] + 49 -> 45 [ label = "()" ] + 50 -> 44 [ label = "()" ] + 50 -> 49 [ label = "()" ] + 51 -> 47 [ label = "()" ] + 51 -> 50 [ label = "()" ] + 52 -> 48 [ label = "()" ] + 52 -> 51 [ label = "()" ] + 53 -> 52 [ label = "()" ] + 53 -> 51 [ label = "()" ] + 54 -> 52 [ label = "()" ] + 55 -> 54 [ label = "()" ] + 56 -> 52 [ label = "()" ] + 57 -> 56 [ label = "()" ] + 58 -> 57 [ label = "()" ] + 59 -> 58 [ label = "()" ] + 60 -> 59 [ label = "()" ] + 61 -> 60 [ label = "()" ] + 62 -> 61 [ label = "()" ] + 63 -> 62 [ label = "()" ] + 64 -> 63 [ label = "()" ] + 65 -> 64 [ label = "()" ] + 66 -> 48 [ label = "()" ] + 66 -> 51 [ label = "()" ] + 67 -> 53 [ label = "()" ] + 67 -> 66 [ label = "()" ] + 68 -> 67 [ label = "()" ] + 68 -> 65 [ label = "()" ] + 69 -> 68 [ label = "()" ] + 70 -> 55 [ label = "()" ] + 70 -> 69 [ label = "()" ] + 71 -> 55 [ label = "()" ] + 71 -> 68 [ label = "()" ] + 72 -> 71 [ label = "()" ] + 72 -> 70 [ label = "()" ] + 74 -> 73 [ label = "()" ] + 75 -> 74 [ label = "()" ] + 75 -> 71 [ label = "()" ] + 76 -> 74 [ label = "()" ] + 77 -> 73 [ label = "()" ] + 77 -> 55 [ label = "()" ] + 78 -> 77 [ label = "()" ] + 78 -> 72 [ label = "()" ] + 79 -> 77 [ label = "()" ] + 80 -> 79 [ label = "()" ] + 80 -> 78 [ label = "()" ] + 81 -> 79 [ label = "()" ] + 82 -> 81 [ label = "()" ] + 83 -> 82 [ label = "()" ] + 84 -> 83 [ label = "()" ] + 85 -> 84 [ label = "()" ] + 85 -> 80 [ label = "()" ] + 86 -> 84 [ label = "()" ] + 87 -> 86 [ label = "()" ] + 88 -> 87 [ label = "()" ] + 89 -> 88 [ label = "()" ] + 90 -> 89 [ label = "()" ] + 90 -> 85 [ label = "()" ] + 91 -> 89 [ label = "()" ] + 92 -> 91 [ label = "()" ] + 93 -> 92 [ label = "()" ] + 94 -> 93 [ label = "()" ] + 95 -> 94 [ label = "()" ] + 96 -> 95 [ label = "()" ] + 97 -> 96 [ label = "()" ] + 98 -> 97 [ label = "()" ] + 99 -> 98 [ label = "()" ] + 100 -> 99 [ label = "()" ] + 101 -> 100 [ label = "()" ] + 102 -> 101 [ label = "()" ] + 103 -> 102 [ label = "()" ] + 103 -> 68 [ label = "()" ] + 104 -> 93 [ label = "()" ] + 104 -> 90 [ label = "()" ] + 105 -> 102 [ label = "()" ] + 105 -> 104 [ label = "()" ] + 106 -> 103 [ label = "()" ] + 106 -> 105 [ label = "()" ] + 107 -> 1 [ label = "()" ] + 107 -> 106 [ label = "()" ] + 108 -> 107 [ label = "()" ] + 108 -> 106 [ label = "()" ] + 109 -> 108 [ label = "()" ] + 110 -> 108 [ label = "()" ] + 111 -> 109 [ label = "()" ] + 111 -> 110 [ label = "()" ] + 112 -> 110 [ label = "()" ] + 113 -> 74 [ label = "()" ] + 113 -> 112 [ label = "()" ] + 114 -> 112 [ label = "()" ] + 114 -> 111 [ label = "()" ] + 115 -> 74 [ label = "()" ] + 115 -> 114 [ label = "()" ] + 116 -> 74 [ label = "()" ] + 116 -> 114 [ label = "()" ] + 117 -> 116 [ label = "()" ] + 117 -> 115 [ label = "()" ] + 118 -> 117 [ label = "()" ] + 118 -> 113 [ label = "()" ] + 119 -> 113 [ label = "()" ] + 119 -> 116 [ label = "()" ] + 120 -> 117 [ label = "()" ] + 120 -> 119 [ label = "()" ] + 121 -> 120 [ label = "()" ] + 121 -> 75 [ label = "()" ] + 122 -> 121 [ label = "()" ] + 122 -> 118 [ label = "()" ] + 123 -> 122 [ label = "()" ] + 123 -> 113 [ label = "()" ] + 124 -> 123 [ label = "()" ] + 125 -> 124 [ label = "()" ] + 126 -> 124 [ label = "()" ] + 127 -> 125 [ label = "()" ] + 127 -> 126 [ label = "()" ] + 128 -> 127 [ label = "()" ] + 129 -> 123 [ label = "()" ] + 130 -> 129 [ label = "()" ] + 131 -> 130 [ label = "()" ] + 132 -> 131 [ label = "()" ] + 133 -> 132 [ label = "()" ] + 134 -> 133 [ label = "()" ] + 135 -> 134 [ label = "()" ] + 136 -> 135 [ label = "()" ] + 137 -> 136 [ label = "()" ] + 138 -> 137 [ label = "()" ] + 139 -> 138 [ label = "()" ] + 140 -> 139 [ label = "()" ] + 141 -> 140 [ label = "()" ] + 142 -> 141 [ label = "()" ] + 143 -> 142 [ label = "()" ] + 144 -> 143 [ label = "()" ] + 145 -> 144 [ label = "()" ] + 146 -> 145 [ label = "()" ] + 147 -> 146 [ label = "()" ] + 148 -> 147 [ label = "()" ] + 149 -> 148 [ label = "()" ] + 150 -> 149 [ label = "()" ] + 151 -> 150 [ label = "()" ] + 152 -> 151 [ label = "()" ] + 153 -> 152 [ label = "()" ] + 154 -> 153 [ label = "()" ] + 155 -> 154 [ label = "()" ] + 156 -> 155 [ label = "()" ] + 157 -> 156 [ label = "()" ] + 158 -> 157 [ label = "()" ] + 159 -> 158 [ label = "()" ] + 160 -> 159 [ label = "()" ] + 161 -> 129 [ label = "()" ] + 161 -> 128 [ label = "()" ] + 162 -> 161 [ label = "()" ] + 162 -> 128 [ label = "()" ] + 163 -> 162 [ label = "()" ] + 163 -> 128 [ label = "()" ] + 164 -> 163 [ label = "()" ] + 165 -> 164 [ label = "()" ] + 166 -> 130 [ label = "()" ] + 166 -> 165 [ label = "()" ] + 167 -> 165 [ label = "()" ] + 168 -> 167 [ label = "()" ] + 169 -> 168 [ label = "()" ] + 170 -> 166 [ label = "()" ] + 170 -> 169 [ label = "()" ] + 171 -> 170 [ label = "()" ] + 172 -> 171 [ label = "()" ] + 173 -> 172 [ label = "()" ] + 174 -> 168 [ label = "()" ] + 175 -> 171 [ label = "()" ] + 175 -> 174 [ label = "()" ] + 176 -> 175 [ label = "()" ] + 177 -> 176 [ label = "()" ] + 178 -> 172 [ label = "()" ] + 178 -> 177 [ label = "()" ] + 179 -> 173 [ label = "()" ] + 179 -> 178 [ label = "()" ] + 180 -> 179 [ label = "()" ] + 180 -> 177 [ label = "()" ] + 181 -> 76 [ label = "()" ] + 181 -> 180 [ label = "()" ] + 182 -> 181 [ label = "()" ] + 182 -> 180 [ label = "()" ] + 183 -> 181 [ label = "()" ] + 183 -> 180 [ label = "()" ] + 184 -> 183 [ label = "()" ] + 184 -> 180 [ label = "()" ] + 185 -> 184 [ label = "()" ] + 185 -> 182 [ label = "()" ] + 186 -> 185 [ label = "()" ] + 187 -> 186 [ label = "()" ] + 188 -> 187 [ label = "()" ] + 189 -> 188 [ label = "()" ] + 190 -> 189 [ label = "()" ] + 191 -> 190 [ label = "()" ] + 192 -> 191 [ label = "()" ] + 193 -> 192 [ label = "()" ] + 194 -> 134 [ label = "()" ] + 194 -> 193 [ label = "()" ] + 195 -> 134 [ label = "()" ] + 195 -> 191 [ label = "()" ] + 196 -> 195 [ label = "()" ] + 196 -> 193 [ label = "()" ] + 197 -> 195 [ label = "()" ] + 197 -> 193 [ label = "()" ] + 198 -> 197 [ label = "()" ] + 198 -> 194 [ label = "()" ] + 199 -> 198 [ label = "()" ] + 200 -> 198 [ label = "()" ] + 200 -> 196 [ label = "()" ] + 201 -> 199 [ label = "()" ] + 201 -> 200 [ label = "()" ] + 202 -> 201 [ label = "()" ] + 203 -> 202 [ label = "()" ] + 204 -> 201 [ label = "()" ] + 204 -> 200 [ label = "()" ] + 205 -> 203 [ label = "()" ] + 205 -> 204 [ label = "()" ] + 206 -> 205 [ label = "()" ] + 206 -> 204 [ label = "()" ] + 207 -> 206 [ label = "()" ] + 208 -> 206 [ label = "()" ] + 208 -> 204 [ label = "()" ] + 209 -> 185 [ label = "()" ] + 210 -> 209 [ label = "()" ] + 211 -> 195 [ label = "()" ] + 211 -> 210 [ label = "()" ] + 212 -> 201 [ label = "()" ] + 212 -> 211 [ label = "()" ] + 213 -> 212 [ label = "()" ] + 213 -> 206 [ label = "()" ] + 214 -> 213 [ label = "()" ] + 214 -> 208 [ label = "()" ] + 215 -> 214 [ label = "()" ] + 215 -> 208 [ label = "()" ] + 216 -> 212 [ label = "()" ] + 216 -> 207 [ label = "()" ] + 217 -> 215 [ label = "()" ] + 217 -> 216 [ label = "()" ] + 218 -> 214 [ label = "()" ] + 218 -> 216 [ label = "()" ] + 219 -> 218 [ label = "()" ] + 219 -> 217 [ label = "()" ] + 220 -> 219 [ label = "()" ] + 220 -> 215 [ label = "()" ] + 221 -> 220 [ label = "()" ] + 221 -> 215 [ label = "()" ] + 222 -> 221 [ label = "()" ] + 222 -> 218 [ label = "()" ] + 223 -> 221 [ label = "()" ] + 223 -> 217 [ label = "()" ] + 224 -> 222 [ label = "()" ] + 224 -> 223 [ label = "()" ] + 225 -> 224 [ label = "()" ] + 225 -> 223 [ label = "()" ] + 226 -> 225 [ label = "()" ] + 227 -> 225 [ label = "()" ] + 228 -> 227 [ label = "()" ] + 229 -> 228 [ label = "()" ] + 230 -> 227 [ label = "()" ] + 230 -> 226 [ label = "()" ] + 231 -> 230 [ label = "()" ] + 231 -> 229 [ label = "()" ] + 232 -> 231 [ label = "()" ] + 232 -> 228 [ label = "()" ] + 233 -> 232 [ label = "()" ] + 233 -> 229 [ label = "()" ] + 234 -> 232 [ label = "()" ] + 234 -> 229 [ label = "()" ] + 235 -> 234 [ label = "()" ] + 235 -> 233 [ label = "()" ] + 236 -> 235 [ label = "()" ] + 237 -> 236 [ label = "()" ] + 238 -> 237 [ label = "()" ] + 239 -> 238 [ label = "()" ] + 240 -> 239 [ label = "()" ] + 241 -> 240 [ label = "()" ] + 242 -> 241 [ label = "()" ] + 243 -> 242 [ label = "()" ] + 244 -> 243 [ label = "()" ] + 245 -> 244 [ label = "()" ] + 246 -> 245 [ label = "()" ] + 247 -> 246 [ label = "()" ] + 248 -> 246 [ label = "()" ] + 249 -> 248 [ label = "()" ] + 249 -> 247 [ label = "()" ] + 250 -> 249 [ label = "()" ] + 250 -> 247 [ label = "()" ] + 251 -> 250 [ label = "()" ] + 252 -> 250 [ label = "()" ] + 253 -> 252 [ label = "()" ] + 254 -> 251 [ label = "()" ] + 254 -> 253 [ label = "()" ] + 255 -> 254 [ label = "()" ] + 256 -> 255 [ label = "()" ] + 257 -> 256 [ label = "()" ] + 258 -> 257 [ label = "()" ] + 259 -> 258 [ label = "()" ] + 260 -> 259 [ label = "()" ] + 261 -> 260 [ label = "()" ] + 262 -> 261 [ label = "()" ] + 263 -> 262 [ label = "()" ] + 264 -> 263 [ label = "()" ] + 265 -> 264 [ label = "()" ] + 266 -> 265 [ label = "()" ] + 267 -> 263 [ label = "()" ] + 268 -> 267 [ label = "()" ] + 268 -> 266 [ label = "()" ] + 269 -> 250 [ label = "()" ] + 270 -> 269 [ label = "()" ] + 270 -> 268 [ label = "()" ] + 271 -> 137 [ label = "()" ] + 271 -> 270 [ label = "()" ] + 272 -> 139 [ label = "()" ] + 272 -> 271 [ label = "()" ] + 273 -> 272 [ label = "()" ] + 274 -> 273 [ label = "()" ] + 275 -> 274 [ label = "()" ] + 276 -> 275 [ label = "()" ] + 277 -> 276 [ label = "()" ] + 278 -> 270 [ label = "()" ] + 278 -> 268 [ label = "()" ] + 279 -> 278 [ label = "()" ] + 279 -> 268 [ label = "()" ] + 280 -> 279 [ label = "()" ] + 281 -> 280 [ label = "()" ] + 282 -> 281 [ label = "()" ] + 283 -> 282 [ label = "()" ] + 284 -> 283 [ label = "()" ] + 285 -> 284 [ label = "()" ] + 286 -> 285 [ label = "()" ] + 287 -> 278 [ label = "()" ] + 287 -> 268 [ label = "()" ] + 288 -> 286 [ label = "()" ] + 288 -> 287 [ label = "()" ] + 289 -> 288 [ label = "()" ] + 289 -> 279 [ label = "()" ] + 290 -> 154 [ label = "()" ] + 290 -> 289 [ label = "()" ] + 291 -> 160 [ label = "()" ] + 291 -> 290 [ label = "()" ] + 292 -> 289 [ label = "()" ] + 293 -> 292 [ label = "()" ] + 294 -> 293 [ label = "()" ] + 295 -> 294 [ label = "()" ] + 296 -> 269 [ label = "()" ] + 297 -> 296 [ label = "()" ] + 298 -> 297 [ label = "()" ] + 299 -> 298 [ label = "()" ] + 300 -> 299 [ label = "()" ] + 300 -> 295 [ label = "()" ] + 301 -> 291 [ label = "()" ] + 301 -> 300 [ label = "()" ] + + 304 -> 303 [ label = "()" ] + 303 -> 302 [ label = "()" ] + }"#); + pub static ref HIGH_COMPLEX_GRAPH: String = String::from(r#"digraph { + 1 [ label = "1" ] + 2 [ label = "2" ] + 3 [ label = "3" ] + 4 [ label = "4" ] + 5 [ label = "5" ] + 6 [ label = "6" ] + 7 [ label = "7" ] + 8 [ label = "8" ] + 9 [ label = "9" ] + 10 [ label = "10" ] + 11 [ label = "11" ] + 12 [ label = "12" ] + 13 [ label = "13" ] + 14 [ label = "14" ] + 15 [ label = "15" ] + 16 [ label = "16" ] + 17 [ label = "17" ] + 18 [ label = "18" ] + 19 [ label = "19" ] + 20 [ label = "20" ] + 21 [ label = "21" ] + 22 [ label = "22" ] + 23 [ label = "23" ] + 24 [ label = "24" ] + 25 [ label = "25" ] + 26 [ label = "26" ] + 27 [ label = "27" ] + 28 [ label = "28" ] + 29 [ label = "29" ] + 30 [ label = "30" ] + 31 [ label = "31" ] + 32 [ label = "32" ] + 33 [ label = "33" ] + 34 [ label = "34" ] + 35 [ label = "35" ] + 36 [ label = "36" ] + 37 [ label = "37" ] + 38 [ label = "38" ] + 39 [ label = "39" ] + 40 [ label = "40" ] + 41 [ label = "41" ] + 42 [ label = "42" ] + 43 [ label = "43" ] + 44 [ label = "44" ] + 45 [ label = "45" ] + 46 [ label = "46" ] + 47 [ label = "47" ] + 48 [ label = "48" ] + 49 [ label = "49" ] + 50 [ label = "50" ] + 51 [ label = "51" ] + 52 [ label = "52" ] + 53 [ label = "53" ] + 54 [ label = "54" ] + 55 [ label = "55" ] + 2 -> 1 [ label = "()" ] + 5 -> 4 [ label = "()" ] + 6 -> 5 [ label = "()" ] + 7 -> 6 [ label = "()" ] + 8 -> 7 [ label = "()" ] + 9 -> 8 [ label = "()" ] + 10 -> 9 [ label = "()" ] + 11 -> 10 [ label = "()" ] + 12 -> 11 [ label = "()" ] + 13 -> 3 [ label = "()" ] + 13 -> 12 [ label = "()" ] + 14 -> 13 [ label = "()" ] + 15 -> 14 [ label = "()" ] + 16 -> 15 [ label = "()" ] + 18 -> 17 [ label = "()" ] + 18 -> 16 [ label = "()" ] + 19 -> 18 [ label = "()" ] + 20 -> 19 [ label = "()" ] + 21 -> 20 [ label = "()" ] + 22 -> 2 [ label = "()" ] + 22 -> 19 [ label = "()" ] + 23 -> 22 [ label = "()" ] + 23 -> 21 [ label = "()" ] + 24 -> 23 [ label = "()" ] + 25 -> 24 [ label = "()" ] + 26 -> 25 [ label = "()" ] + 27 -> 26 [ label = "()" ] + 28 -> 27 [ label = "()" ] + 29 -> 28 [ label = "()" ] + 30 -> 29 [ label = "()" ] + 31 -> 30 [ label = "()" ] + 32 -> 31 [ label = "()" ] + 33 -> 32 [ label = "()" ] + 34 -> 33 [ label = "()" ] + 35 -> 33 [ label = "()" ] + 36 -> 34 [ label = "()" ] + 36 -> 35 [ label = "()" ] + 37 -> 36 [ label = "()" ] + 38 -> 37 [ label = "()" ] + 39 -> 38 [ label = "()" ] + 40 -> 39 [ label = "()" ] + 42 -> 41 [ label = "()" ] + 42 -> 40 [ label = "()" ] + 43 -> 42 [ label = "()" ] + 44 -> 41 [ label = "()" ] + 44 -> 40 [ label = "()" ] + 45 -> 41 [ label = "()" ] + 45 -> 40 [ label = "()" ] + 46 -> 43 [ label = "()" ] + 46 -> 45 [ label = "()" ] + 47 -> 44 [ label = "()" ] + 47 -> 46 [ label = "()" ] + 48 -> 44 [ label = "()" ] + 48 -> 46 [ label = "()" ] + 49 -> 46 [ label = "()" ] + 50 -> 49 [ label = "()" ] + 50 -> 47 [ label = "()" ] + 51 -> 49 [ label = "()" ] + 51 -> 48 [ label = "()" ] + 52 -> 51 [ label = "()" ] + 52 -> 50 [ label = "()" ] + 54 -> 53 [ label = "()" ] + 55 -> 54 [ label = "()" ] + 55 -> 22 [ label = "()" ] + }"#); +} \ No newline at end of file diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/tests.rs b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/tests.rs new file mode 100644 index 000000000..809291288 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/tests.rs @@ -0,0 +1,103 @@ +#[test] +pub fn test_merge_fast_forward() { + use hdk::prelude::*; + + use crate::link_adapter::workspace::Workspace; + use crate::retriever::{Associations, GraphInput, MockPerspectiveGraph, GLOBAL_MOCKED_GRAPH}; + + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::new(GraphInput { + nodes: 6, + associations: vec![ + Associations { + node_source: 1, + node_targets: vec![0], + }, + Associations { + node_source: 2, + node_targets: vec![0], + }, + Associations { + node_source: 3, + node_targets: vec![1], + }, + Associations { + node_source: 4, + node_targets: vec![2], + }, + Associations { + node_source: 5, + node_targets: vec![3, 4], + }, + ], + }); + } + update(); + + let mut workspace = Workspace::new(); + let res = workspace.collect_until_common_ancestor::( + ActionHash::from_raw_36(vec![5; 36]), + ActionHash::from_raw_36(vec![4; 36]), + ); + assert!(res.is_ok()); + assert_eq!(res.unwrap(), ActionHash::from_raw_36(vec![0; 36])); +} + +#[test] +pub fn test_fork_with_none_source() { + use hdk::prelude::*; + + use crate::link_adapter::workspace::Workspace; + use crate::retriever::{GraphInput, MockPerspectiveGraph, GLOBAL_MOCKED_GRAPH}; + + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::new(GraphInput { + nodes: 2, + associations: vec![], + }); + } + update(); + + let mut workspace = Workspace::new(); + let res = workspace.collect_until_common_ancestor::( + ActionHash::from_raw_36(vec![0; 36]), + ActionHash::from_raw_36(vec![1; 36]), + ); + assert!(res.is_ok()); + //TODO; this is a problem since our pull code is not expecting to find a common ancestor, since both tips are forks + //but in the case below where we have a merge entry we need to register the None node as a common ancestor so we can traverse the "their" branch back until the root + //and not break the traversal with common ancestor as the "ours" node as was happening before + // + //So what do we actually need to return here? + assert_eq!(res.unwrap(), ActionHash::from_raw_36(vec![0xdb; 36])); +} + +#[test] +pub fn test_merge_fast_forward_none_source() { + use hdk::prelude::*; + + use crate::link_adapter::workspace::Workspace; + use crate::retriever::{Associations, GraphInput, MockPerspectiveGraph, GLOBAL_MOCKED_GRAPH}; + + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::new(GraphInput { + nodes: 3, + associations: vec![Associations { + node_source: 2, + node_targets: vec![0, 1], + }], + }); + } + update(); + + let mut workspace = Workspace::new(); + let res = workspace.collect_until_common_ancestor::( + ActionHash::from_raw_36(vec![2; 36]), + ActionHash::from_raw_36(vec![1; 36]), + ); + assert!(res.is_ok()); + assert_eq!(res.unwrap(), ActionHash::from_raw_36(vec![0xdb; 36])); +} diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/topo_sort.rs b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/topo_sort.rs new file mode 100644 index 000000000..d33b5f015 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/topo_sort.rs @@ -0,0 +1,143 @@ +use crate::errors::{SocialContextError, SocialContextResult}; +use hdk::prelude::*; +use perspective_diff_sync_integrity::PerspectiveDiffEntryReference; +use std::collections::BTreeSet; + +// Applies Kahn's algorithm for topologically sorting a graph +pub fn topo_sort_diff_references( + arr: &Vec<( + HoloHash, + PerspectiveDiffEntryReference, + )>, +) -> SocialContextResult< + Vec<( + HoloHash, + PerspectiveDiffEntryReference, + )>, +> { + type Hash = HoloHash; + let mut result = Vec::<(Hash, PerspectiveDiffEntryReference)>::new(); + + // first collect orphaned nodes (=without parent) as starting points: + let mut orphaned_nodes: Vec<(Hash, PerspectiveDiffEntryReference)> = arr + .iter() + .filter(|&e| e.1.parents == None) + .cloned() + .collect(); + + if orphaned_nodes.len() == 0 { + debug!("No orphans found! Length: {}, list: {:?}", arr.len(), arr); + return Err(SocialContextError::InternalError( + "Can't topologically sort list without orphan!", + )); + } + + let mut edges = BTreeSet::new(); + for i in 0..arr.len() { + if let Some(parents) = &arr[i].1.parents { + for p in 0..parents.len() { + let child = arr[i].0.clone(); + let parent = parents[p].clone(); + edges.insert((child, parent)); + } + } + } + + // Starting from the nodes without parents... + while let Some(n) = orphaned_nodes.pop() { + //.. we put them into the result list. + result.push(n.clone()); + + println!("Added orphan {:?}", n); + + // and then we look for any nodes that have it as parent + // (using the edges set) + let edges_with_n_as_parent = edges + .iter() + .filter(|&e| e.1 == n.0) + .cloned() + .collect::>(); + + println!("Edges with orphan as parent {:?}", edges_with_n_as_parent); + + // So for every parent relationship with n as parent... + for edge in &edges_with_n_as_parent { + println!("Removing edge {:?}", edge); + // we remove that edge + edges.remove(edge); + + // and then check if that child of n has any other parents... + let child = edge.0.clone(); + + println!("Found child {:?}", child); + let edges_with_child_as_child = edges + .iter() + .filter(|&e| e.0 == child) + .cloned() + .collect::>(); + + println!("Edges with child as child {:?}", edges_with_child_as_child); + + // if the child does not have any other parents (left unprocessed) + if edges_with_child_as_child.len() == 0 { + // we're good to add the child to the results as well. + let child_item = arr.iter().find(|&e| e.0 == child).ok_or(SocialContextError::InternalError("Topological sort couldn't find child in input vector, which was mentioned in an edge. This can only be an error in the topological sorting code.."))?; + println!("Adding newly orphaned child {:?}", child_item); + orphaned_nodes.push((child.clone(), child_item.1.clone())); + } + } + } + + if edges.len() > 0 { + debug!( + "Unresolved parent links after topologically sorting: {:?}", + edges + ); + + debug!("Number of unresolved parent links {:?}", edges.len()); + debug!("Number of items to sort: {:?}", arr.len()); + Err(SocialContextError::InternalError( + "Cycle or missing nodes detected. Unresolved parent links after topologically sorting.", + )) + //Ok(result) + } else { + Ok(result) + } +} + +#[cfg(test)] +mod tests { + use super::topo_sort_diff_references; + use hdk::prelude::*; + use perspective_diff_sync_integrity::PerspectiveDiffEntryReference; + + #[test] + fn test_topo_sort_diff_references() { + let h1 = HoloHash::::from_raw_36(vec![1; 36]); + let h2 = HoloHash::::from_raw_36(vec![2; 36]); + let h3 = HoloHash::::from_raw_36(vec![3; 36]); + let h4 = HoloHash::::from_raw_36(vec![4; 36]); + + let r1 = PerspectiveDiffEntryReference::new(h1.clone(), Some(vec![h2.clone(), h3.clone()])); + let r2 = PerspectiveDiffEntryReference::new(h2.clone(), Some(vec![h4.clone()])); + let r3 = PerspectiveDiffEntryReference::new(h3.clone(), Some(vec![h4.clone()])); + let r4 = PerspectiveDiffEntryReference::new(h4.clone(), None); + + let e1 = (h1, r1); + let e2 = (h2, r2); + let e3 = (h3, r3); + let e4 = (h4, r4); + + assert_eq!(e1.0, e1.1.diff); + assert_eq!(e2.0, e2.1.diff); + assert_eq!(e3.0, e3.1.diff); + assert_eq!(e4.0, e4.1.diff); + + let test_vec = vec![e1.clone(), e2.clone(), e3.clone(), e4.clone()]; + let expected = vec![e4, e3, e2, e1]; + + let result = topo_sort_diff_references(&test_vec).expect("topo sort to not error"); + + assert_eq!(result, expected); + } +} diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/workspace.rs b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/workspace.rs new file mode 100644 index 000000000..296e1f004 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/link_adapter/workspace.rs @@ -0,0 +1,1427 @@ +use hdk::prelude::*; +use itertools::Itertools; +use perspective_diff_sync_integrity::{ + LinkTypes, PerspectiveDiff, PerspectiveDiffEntryReference, Snapshot, +}; +use petgraph::{ + algo::dominators::simple_fast, + dot::{Config, Dot}, + graph::{DiGraph, Graph, NodeIndex, UnGraph}, +}; +use std::cell::RefCell; +use std::collections::{BTreeMap, VecDeque}; + +use crate::errors::{SocialContextError, SocialContextResult}; +use crate::link_adapter::topo_sort::topo_sort_diff_references; +use crate::retriever::{hash_to_node_id, PerspectiveDiffRetreiver}; +use crate::utils::get_now; +use crate::Hash; + +pub struct Workspace { + pub graph: DiGraph, + pub undirected_graph: UnGraph, + pub node_index_map: BTreeMap>, + pub entry_map: BTreeMap, + pub sorted_diffs: Option>, + pub common_ancestors: Vec, + pub diffs: BTreeMap, + pub back_links: BTreeMap>, + unexplored_side_branches: BTreeSet, +} + +#[derive(Clone)] +struct BfsSearch { + pub found_ancestors: RefCell>, + pub bfs_branches: RefCell>, + pub reached_end: bool, +} + +#[allow(non_snake_case)] +pub fn NULL_NODE() -> ActionHash { + ActionHash::from_raw_36(vec![0xdb; 36]) +} + +impl BfsSearch { + pub fn new(start: Hash) -> BfsSearch { + let branches = RefCell::new(Vec::from([start])); + BfsSearch { + found_ancestors: RefCell::new(Vec::new()), + bfs_branches: branches, + reached_end: false, + } + } +} + +impl std::fmt::Debug for BfsSearch { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if cfg!(test) { + let ancestors: Vec<_> = self + .found_ancestors + .borrow() + .clone() + .into_iter() + .map(|val| hash_to_node_id(val)) + .collect(); + let branches: Vec<_> = self + .bfs_branches + .borrow() + .clone() + .into_iter() + .map(|val| hash_to_node_id(val)) + .collect(); + write!( + f, + "BfsSearch {{ found_ancestors: {:?},\n bfs_branches: {:?},\n reached_end: {:?} }}", + ancestors, branches, self.reached_end + ) + } else { + write!( + f, + "BfsSearch {{ found_ancestors: {:?},\n bfs_branches: {:?},\n reached_end: {:?} }}", + self.found_ancestors, self.bfs_branches, self.reached_end + ) + } + } +} + +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)] +enum SearchSide { + Theirs, + Ours, +} + +fn other_side(side: &SearchSide) -> SearchSide { + match side { + SearchSide::Theirs => SearchSide::Ours, + SearchSide::Ours => SearchSide::Theirs, + } +} + +impl Workspace { + pub fn new() -> Workspace { + Workspace { + graph: Graph::new(), + undirected_graph: Graph::new_undirected(), + node_index_map: BTreeMap::new(), + entry_map: BTreeMap::new(), + sorted_diffs: None, + common_ancestors: vec![], + diffs: BTreeMap::new(), + back_links: BTreeMap::new(), + unexplored_side_branches: BTreeSet::new(), + } + } + + // This is the easy case when we only build from one hash. + // (either latest or our current hash, like in render). + // We don't have to check for forks, we just deep search from the given + // diff and terminate at leafs and snapshots. + // Since we don't have to detect and handle forks, we don't need + // to unroll snapshots and just treat them as leafs. + pub fn collect_only_from_latest( + &mut self, + latest: Hash, + ) -> SocialContextResult<()> { + debug!("===Workspace.collect_only_from_latest(): Function start"); + let fn_start = get_now()?.time(); + + // Initializing with only one branch starting from the given hash. + let mut unprocessed_branches = VecDeque::new(); + unprocessed_branches.push_back(latest); + + let mut snapshot_seen = vec![]; + + while !unprocessed_branches.is_empty() { + let current_hash = unprocessed_branches[0].clone(); + + if self.entry_map.contains_key(¤t_hash) && !snapshot_seen.contains(¤t_hash) + { + debug!("===Workspace.collect_only_from_latest(): CIRCLE DETECTED! Closing current branch..."); + unprocessed_branches.pop_front(); + continue; + } + + let current_diff = Self::get_p_diff_reference::(current_hash.clone())?; + + if current_diff.diffs_since_snapshot == 0 { + debug!("===Workspace.collect_only_from_latest(): Found a perspective diff reference containing a snapshot!"); + let snapshot = Self::get_snapshot(current_diff.clone())?; + + if snapshot.is_none() { + debug!("===Workspace.collect_only_from_latest(): ERROR: Expected to find snapshot link on current_diff where diffs_since_snapshot was 0"); + self.handle_parents(current_diff, current_hash, &mut unprocessed_branches); + } else { + let mut snapshot = snapshot.unwrap(); + + let mut last_diff = None; + for i in 0..snapshot.diff_chunks.len() { + let diff_chunk = &snapshot.diff_chunks[i]; + self.entry_map.insert( + diff_chunk.clone(), + PerspectiveDiffEntryReference::new( + diff_chunk.clone(), + last_diff.clone(), + ), + ); + last_diff = Some(vec![diff_chunk.clone()]); + } + + self.entry_map.insert( + current_hash.clone(), + PerspectiveDiffEntryReference::new(current_diff.diff, last_diff.clone()), + ); + + snapshot_seen.append(&mut snapshot.included_diffs); + + // Snapshot terminates like an orphan. + // So we can close this branch and potentially continue + // with other unprocessed branches, if they exist. + unprocessed_branches.pop_front(); + }; + } else { + self.handle_parents(current_diff, current_hash, &mut unprocessed_branches); + } + } + + let fn_end = get_now()?.time(); + debug!("===Workspace.collect_only_from_latest() - Profiling: Took: {} to complete collect_only_from_latest() function", (fn_end - fn_start).num_milliseconds()); + + Ok(()) + } + + fn handle_parents( + &mut self, + current_diff: PerspectiveDiffEntryReference, + current_hash: Hash, + unprocessed_branches: &mut VecDeque, + ) { + if let Some(parents) = ¤t_diff.parents { + for i in 0..parents.len() { + // Depth-first search: + // We are replacing our search position (==current_hash==unprocessed_branches[0]) + // with the first parent. + // Other parents are pushed on the vec as new branches to search later.. + if i == 0 { + unprocessed_branches[0] = parents[i].clone(); + } else { + unprocessed_branches.push_back(parents[i].clone()) + } + } + } else { + // We arrived at a leaf/orphan (no parents). + // So we can close this branch and potentially continue + // with other unprocessed branches, if they exist. + unprocessed_branches.pop_front(); + } + + self.entry_map.insert(current_hash, current_diff); + } + + pub fn sort_graph(&mut self) -> SocialContextResult<()> { + //debug!("===Workspace.sort_graph(): Function start"); + //let fn_start = get_now()?.time(); + + let common_ancestor = self.common_ancestors.last().unwrap(); + + //TODO; this should probably be a Map but tests break when it is a map + let mut sorted: Vec<(Hash, PerspectiveDiffEntryReference)> = Vec::new(); + let mut visited: HashSet = HashSet::new(); + let mut next: VecDeque = VecDeque::new(); + self.unexplored_side_branches = BTreeSet::new(); + //let mut inner_iter = 0; + + next.push_back(common_ancestor.clone()); + + while !next.is_empty() { + let current = next.pop_front().expect("must be Ok since next !is_empty()"); + if !visited.contains(¤t) { + //inner_iter += 1; + //println!("current: {:?}", hash_to_node_id(current.clone())); + match self.back_links.get(¤t) { + Some(children) => { + //println!("--> has {} children, checking the children to see if there is a missing parent link", children.len()); + //println!("Children are: {:#?}", children.clone().into_iter().map(|child| hash_to_node_id(child)).collect::>()); + for child in children.iter() { + let diff = self.diffs.get(&child).expect("Should child must exist"); + if diff.parents.is_some() { + for parent in diff.parents.as_ref().unwrap() { + if parent != ¤t { + //println!("Found missing parent: {:?}", hash_to_node_id(parent.clone())); + self.unexplored_side_branches.insert(parent.clone()); + } + } + } + } + let mut unseen_children = children + .to_owned() + .into_iter() + .filter(|child| !next.contains(child)) + .collect::>(); + next.append(&mut unseen_children); + } + None => {} + }; + let current_diff = self.diffs.get(¤t).expect("diffs should be populated"); + sorted.push((current.clone(), current_diff.clone())); + if self.entry_map.get(¤t).is_none() { + self.entry_map.insert(current.clone(), current_diff.clone()); + }; + visited.insert(current); + } + } + //debug!( + // "===Workspace.sort_graph(): Made {:?} total iterations", + // inner_iter + //); + + self.unexplored_side_branches = self + .unexplored_side_branches + .iter() + .filter(|b| !sorted.iter().find(|s| s.0 == **b).is_some()) + .cloned() + .collect(); + + // println!("SortGraph iter: Unexplored side branches: {:?}", self.unexplored_side_branches.clone().into_iter().map(|child| hash_to_node_id(child)).collect::>()); + + //println!("Sorted is: {:?}", sorted.clone().into_iter().map(|val| hash_to_node_id(val.0)).collect::>()); + self.sorted_diffs = Some(sorted.into_iter().unique().collect()); + + //let fn_end = get_now()?.time(); + //debug!( + // "===Workspace.sort_graph() - Profiling: Took: {} to complete sort_graph() function", + // (fn_end - fn_start).num_milliseconds() + //); + + Ok(()) + } + + pub fn build_diffs( + &mut self, + theirs: Hash, + ours: Hash, + ) -> SocialContextResult<()> { + debug!("===Workspace.build_diffs(): Function start"); + let fn_start = get_now()?.time(); + + let common_ancestor = self.collect_until_common_ancestor::(theirs, ours)?; + self.common_ancestors.push(common_ancestor); + + //println!("===PerspectiveDiffSunc.build_diffs(): Got diffs: {:?}", self.diffs.iter().map(|x| hash_to_node_id(x.0.to_owned())).collect::>()); + //println!("===PerspectiveDiffSunc.build_diffs(): Got back_links: {:?}", self.back_links.iter().map(|x| hash_to_node_id(x.0.to_owned())).collect::>()); + + self.sort_graph()?; + //println!("===PerspectiveDiffSunc.build_diffs(): Got unexplored side branches parent: {:#?}", self.unexplored_side_branches.iter().map(|x| hash_to_node_id(x.to_owned())).collect::>()); + + while self.unexplored_side_branches.len() > 0 { + let unexplored_side_branch = self + .unexplored_side_branches + .iter() + .next_back() + .unwrap() + .to_owned(); + let ours = self + .common_ancestors + .last() + .expect("There should have been a common ancestor above") + .to_owned(); + //println!("===Workspace.build_diffs(): making an explored side branch iteration: {:?} and ours: {:?}", hash_to_node_id(unexplored_side_branch.clone()), hash_to_node_id(ours.clone())); + let common_ancestor = + self.collect_until_common_ancestor::(unexplored_side_branch, ours)?; + self.common_ancestors.push(common_ancestor.clone()); + self.sort_graph()?; + //println!("===PerspectiveDiffSync.build_diffs(): Got common ancestor: {:?}", hash_to_node_id(common_ancestor)); + } + + let sorted_diffs = self.sorted_diffs.as_mut().unwrap(); + sorted_diffs.get_mut(0).unwrap().1.parents = None; + self.sorted_diffs = Some(topo_sort_diff_references(sorted_diffs)?); + // println!("===PerspectiveDiffSunc.build_diffs(): Got sorted diffs: {:#?}", self.sorted_diffs); + + self.build_graph()?; + self.print_graph_debug(); + + let fn_end = get_now()?.time(); + debug!( + "===Workspace.build_diffs() - Profiling: Took: {} to complete build_diffs() function", + (fn_end - fn_start).num_milliseconds() + ); + + Ok(()) + } + + fn terminate_with_null_node( + &mut self, + current_hash: Hash, + side: SearchSide, + searches: &mut BTreeMap, + ) -> SocialContextResult<()> { + let search_clone = searches.clone(); + let other = search_clone + .get(&other_side(&side)) + .ok_or(SocialContextError::InternalError("search side not found"))?; + let search = searches + .get_mut(&side) + .ok_or(SocialContextError::InternalError("search side not found"))?; + + if !search.found_ancestors.borrow().contains(&NULL_NODE()) { + search.found_ancestors.get_mut().push(NULL_NODE()); + }; + if !other.found_ancestors.borrow().contains(&NULL_NODE()) { + let other_mut = searches + .get_mut(&other_side(&side)) + .ok_or(SocialContextError::InternalError("search side not found"))?; + other_mut.found_ancestors.get_mut().push(NULL_NODE()); + }; + if self.diffs.get(&NULL_NODE()).is_none() { + let current_diff = PerspectiveDiffEntryReference::new(NULL_NODE(), None); + self.diffs.insert(NULL_NODE(), current_diff.clone()); + }; + + let mut set = if let Some(nodes_back_links) = self.back_links.get(&NULL_NODE()) { + let mut nodes_back_links = nodes_back_links.clone(); + if let Some(other_last) = other.found_ancestors.borrow().last().clone() { + if other_last != &NULL_NODE() { + nodes_back_links.insert(other_last.clone()); + } + } + nodes_back_links.clone() + } else { + let mut set = BTreeSet::new(); + if let Some(other_last) = other.found_ancestors.borrow().last().clone() { + if other_last != &NULL_NODE() { + set.insert(other_last.clone()); + } + } + set + }; + if current_hash != NULL_NODE() { + set.insert(current_hash); + }; + self.back_links.insert(NULL_NODE(), set); + Ok(()) + } + + pub fn collect_until_common_ancestor( + &mut self, + theirs: Hash, + ours: Hash, + ) -> SocialContextResult { + //debug!("===Workspace.collect_until_common_ancestor(): Function start"); + let fn_start = get_now()?.time(); + + let mut common_ancestor: Option = None; + + let mut searches = btreemap! { + SearchSide::Theirs => BfsSearch::new(theirs), + SearchSide::Ours => BfsSearch::new(ours), + }; + + while common_ancestor.is_none() { + // println!("===Workspace.collect_until_common_ancestor(): collect_until_common_ancestor 2: {:#?}", searches.get(&SearchSide::Theirs).unwrap().bfs_branches.borrow()); + // println!("===Workspace.collect_until_common_ancestor(): collect_until_common_ancestor 2: {:#?}", searches.get(&SearchSide::Ours).unwrap().bfs_branches.borrow()); + // do the same BFS for theirs_branches and ours_branches.. + for side in vec![SearchSide::Theirs, SearchSide::Ours] { + println!("Checking side: {:#?}", side); + let search_clone = searches.clone(); + let other = search_clone.get(&other_side(&side)).ok_or( + SocialContextError::InternalError("other search side not found"), + )?; + let search = searches + .get_mut(&side) + .ok_or(SocialContextError::InternalError("search side not found"))?; + let branches = search.bfs_branches.get_mut(); + branches.dedup(); + + for branch_index in 0..branches.len() { + println!("===Workspace.collect_until_common_ancestor(): collect_until_common_ancestor 2.1"); + let current_hash = branches[branch_index].clone(); + println!( + "Checking current hash: {:#?}", + hash_to_node_id(current_hash.clone()) + ); + + let already_visited = search.found_ancestors.borrow().contains(¤t_hash); + let seen_on_other_side = other.found_ancestors.borrow().contains(¤t_hash) + || other.bfs_branches.borrow().contains(¤t_hash); + + if already_visited { + println!("===Workspace.collect_until_common_ancestor(): collect_until_common_ancestor 2.2 ALREADY VISITED"); + // We've seen this diff on this side, so we are at the end of a branch. + // Just ignore this hash and close the branch. + branches.remove(branch_index); + break; + } + + if seen_on_other_side { + println!("===Workspace.collect_until_common_ancestor(): collect_until_common_ancestor 2.2 SEEN ON OTHER SIDE"); + + //Add the diff to both searches if it is not there + if !search.found_ancestors.borrow().contains(¤t_hash) { + search.found_ancestors.get_mut().push(current_hash.clone()); + }; + if !other.found_ancestors.borrow().contains(¤t_hash) { + searches + .get_mut(&other_side(&side)) + .ok_or(SocialContextError::InternalError( + "other search side not found", + ))? + .found_ancestors + .get_mut() + .push(current_hash.clone()); + }; + if self.diffs.get(¤t_hash).is_none() && current_hash != NULL_NODE() { + let current_diff = + Self::get_p_diff_reference::(current_hash.clone())?; + self.diffs + .insert(current_hash.clone(), current_diff.clone()); + }; + // current hash is already in, so it must be our common ancestor! + common_ancestor = Some(current_hash); + break; + } + + //println!("===Workspace.collect_until_common_ancestor(): collect_until_common_ancestor 2.3"); + search.found_ancestors.get_mut().push(current_hash.clone()); + + if current_hash == NULL_NODE() { + branches.remove(branch_index); + search.reached_end = true; + if common_ancestor.is_none() && other.reached_end == true { + common_ancestor = Some(NULL_NODE()); + self.terminate_with_null_node(current_hash, side, &mut searches)?; + }; + + break; + } + + //TODO; this should have caching builtin, since on some iterations we will get the same P reference multiple times + let current_diff = + Self::get_p_diff_reference::(current_hash.clone())?; + self.diffs + .insert(current_hash.clone(), current_diff.clone()); + + match ¤t_diff.parents { + None => { + // We arrived at a leaf/orphan (no parents). + // So we can close this branch and potentially continue + // with other unprocessed branches, if they exist. + println!("===Workspace.collect_until_common_ancestor(): collect_until_common_ancestor 2.4, no more parents"); + branches.remove(branch_index); + //If there are no more branches and we have truly reached the end + search.reached_end = true; + //NOTE: this if block is the code that breaks the test_latest_join tests, with it removed the tests pass, but test three null parents fails + if common_ancestor.is_none() && other.reached_end == true { + common_ancestor = Some(NULL_NODE()); + self.terminate_with_null_node(current_hash, side, &mut searches)?; + }; + // We have to break out of loop to avoid having branch_index run out of bounds + break; + } + Some(parents) => { + // println!("===Workspace.collect_until_common_ancestor(): collect_until_common_ancestor 2.4, more parents: {:#?}", parents); + for parent_index in 0..parents.len() { + println!("===Workspace.collect_until_common_ancestor(): collect_until_common_ancestor 2.5, more parents after filter"); + let parent = parents[parent_index].clone(); + if let Some(links) = self.back_links.get_mut(&parent) { + links.insert(current_hash.clone()); + } else { + let mut set = BTreeSet::new(); + set.insert(current_hash.clone()); + self.back_links.insert(parent.clone(), set); + } + // The first parent is taken as the successor for the current branch. + // If there are multiple parents (i.e. merge commit), we create a new branch.. + if parent_index == 0 { + println!("Adding new parent to existing branch index"); + let _ = std::mem::replace( + &mut branches[branch_index], + parent.clone(), + ); + } else { + let already_visited = + search.found_ancestors.borrow().contains(&parent) + || other.bfs_branches.borrow().contains(&parent); + let seen_on_other_side = + other.found_ancestors.borrow().contains(&parent); + if !already_visited && !seen_on_other_side { + println!("===Workspace.collect_until_common_ancestor(): Adding a new branch"); + branches.push(parent.clone()) + } + } + } + } + }; + + //println!("===Workspace.collect_until_common_ancestor(): collect_until_common_ancestor 2.7"); + } + } + } + + let fn_end = get_now()?.time(); + let ms_spent = (fn_end - fn_start).num_milliseconds(); + if ms_spent > 1000 { + debug!("===Workspace.collect_until_common_ancestor() - Profiling: Took: {} to complete collect_until_common_ancestor() function", ms_spent); + } + + if common_ancestor.is_none() { + return Err(SocialContextError::NoCommonAncestorFound); + }; + + // println!("===Workspace.collect_until_common_ancestor(): collect_until_common_ancestor 3: {:#?} and common ancestor is: {:#?}", searches, hash_to_node_id(common_ancestor.clone().unwrap())); + + Ok(common_ancestor.unwrap()) + } + + // pub fn topo_sort_graph(&mut self) -> SocialContextResult<()> { + // debug!("===Workspace.topo_sort_graph(): Function start"); + // let fn_start = get_now()?.time(); + + // let entry_vec = self.entry_map + // .clone() + // .into_iter() + // .collect::>(); + + // let mut dot = Vec::::new(); + + // dot.push("digraph {".to_string()); + // for entry in entry_vec.iter() { + // dot.push(format!("{}", entry.0.clone())); + // if let Some(parents) = &entry.1.parents { + // for p in parents.iter() { + // dot.push(format!("{} -> {}", entry.0, p)); + // } + // } + // } + // dot.push("}".to_string()); + + // println!("{}", dot.join("\n")); + + // self.sorted_diffs = Some(topo_sort_diff_references(&entry_vec)?); + + // let fn_end = get_now()?.time(); + // debug!("===Workspace.topo_sort_graph() - Profiling: Took: {} to complete topo_sort_graph() function", (fn_end - fn_start).num_milliseconds()); + // Ok(()) + // } + + pub fn build_graph(&mut self) -> SocialContextResult<()> { + debug!("===Workspace.build_graph(): Function start"); + let fn_start = get_now()?.time(); + + match self.sorted_diffs.clone() { + None => Err(SocialContextError::InternalError( + "Need to 1. collect diffs and then 2. sort them before building the graph", + )), + Some(sorted_diffs) => { + //Add root node + if self.get_node_index(&NULL_NODE()).is_none() { + self.add_node(None, NULL_NODE()); + }; + + for diff in sorted_diffs { + if diff.0 != NULL_NODE() { + if diff.1.parents.is_some() { + let mut parents = vec![]; + for parent in diff.1.parents.as_ref().unwrap() { + let parent = self.get_node_index(&parent).ok_or( + SocialContextError::InternalError("Did not find parent"), + )?; + parents.push(parent.clone()); + } + self.add_node(Some(parents), diff.0.clone()); + } else { + self.add_node(Some(vec![NodeIndex::from(0)]), diff.0.clone()); + } + } + } + + let fn_end = get_now()?.time(); + debug!("===Workspace.build_graph() - Profiling: Took: {} to complete build_graph() function", (fn_end - fn_start).num_milliseconds()); + + Ok(()) + } + } + } + + pub fn get_p_diff_reference( + address: Hash, + ) -> SocialContextResult { + Retriever::get(address) + } + + fn get_snapshot( + address: PerspectiveDiffEntryReference, + ) -> SocialContextResult> { + debug!("===Workspace.get_snapshot(): Function start"); + let fn_start = get_now()?.time(); + + // let input = GetLinksInputBuilder::try_new( + // hash_entry(address)?, + // LinkTypes::Snapshot + // ) + // .unwrap() + // .tag_prefix(LinkTag::new("snapshot")) + // .build(); + let mut snapshot_links = get_links(hash_entry(address)?, LinkTypes::Snapshot, Some(LinkTag::new("snapshot")))?; + + if snapshot_links.len() > 0 { + let snapshot = get( + snapshot_links + .remove(0) + .target + .into_entry_hash() + .expect("Could not get entry hash"), + GetOptions::latest(), + )? + .ok_or(SocialContextError::InternalError( + "Workspace::get_snapshot: Could not find entry while populating search", + ))? + .entry() + .to_app_option::()? + .ok_or(SocialContextError::InternalError( + "Expected element to contain app entry data", + ))?; + + let fn_end = get_now()?.time(); + debug!("===Workspace.get_snapshot() - Profiling: Took: {} to complete get_snapshot() function", (fn_end - fn_start).num_milliseconds()); + + Ok(Some(snapshot)) + } else { + let fn_end = get_now()?.time(); + debug!("===Workspace.get_snapshot() - Profiling: Took: {} to complete get_snapshot() function", (fn_end - fn_start).num_milliseconds()); + + Ok(None) + } + } + + fn add_node(&mut self, parents: Option>>, diff: Hash) -> NodeIndex { + let index = self.graph.add_node(diff.clone()); + self.undirected_graph.add_node(diff.clone()); + self.node_index_map.insert(diff, index); + if parents.is_some() { + for parent in parents.unwrap() { + self.graph.add_edge(index, parent, ()); + self.undirected_graph.add_edge(index, parent, ()); + } + } + index + } + + pub fn get_node_index(&self, node: &Hash) -> Option<&NodeIndex> { + self.node_index_map.get(node) + } + + // pub fn get_paths( + // &self, + // child: &Hash, + // ancestor: &Hash, + // ) -> SocialContextResult>> { + // debug!("===Workspace.get_paths(): Function start"); + // let fn_start = get_now()?.time(); + + // let child_node = self.get_node_index(child).expect("Could not get child node index"); + // let ancestor_node = self.get_node_index(ancestor).expect("Could not get ancestor node index"); + // let paths = all_simple_paths::, _>(&self.graph, *child_node, *ancestor_node, 0, None) + // .collect::>(); + + // let fn_end = get_now()?.time(); + // debug!("===Workspace.get_paths() - Profiling: Took: {} to complete get_paths() function", (fn_end - fn_start).num_milliseconds()); + + // Ok(paths) + // } + + pub fn _find_common_ancestor( + &self, + root: NodeIndex, + second: NodeIndex, + ) -> Option { + let imm = simple_fast(&self.undirected_graph, root); + let imm = imm.dominators(second); + let mut index: Option = None; + match imm { + Some(imm_iter) => { + for dom in imm_iter { + match index { + Some(current_index) => { + if current_index.index() > dom.index() { + index = Some(dom) + } + } + None => index = Some(dom), + }; + } + } + None => {} + }; + index + } + + pub fn squashed_diff( + &self, + ) -> SocialContextResult { + debug!("===Workspace.squashed_diff(): Function start"); + let fn_start = get_now()?.time(); + + let mut out = PerspectiveDiff { + additions: vec![], + removals: vec![], + }; + for (_key, value) in self.entry_map.iter() { + if value.diff == NULL_NODE() { + continue; + } + let diff_entry = Retriever::get::(value.diff.clone())?; + out.additions.append(&mut diff_entry.additions.clone()); + out.removals.append(&mut diff_entry.removals.clone()); + } + + let fn_end = get_now()?.time(); + debug!("===Workspace.squashed_diff() - Profiling: Took: {} to complete squashed_diff() function", (fn_end - fn_start).num_milliseconds()); + + Ok(out) + } + + // pub fn squashed_fast_forward_from(&self, base: Hash) -> SocialContextResult { + // match &self.sorted_diffs { + // None => Err(SocialContextError::InternalError("Need to sort first for this fast-forward optimzed squash")), + // Some(sorted_diffs) => { + // let mut base_found = false; + // let mut out = PerspectiveDiff { + // additions: vec![], + // removals: vec![], + // }; + // for i in 0..sorted_diffs.len() { + // let current = &sorted_diffs[i]; + // if !base_found { + // if current.0 == base { + // base_found = true; + // } + // } else { + // let diff_entry = get(current.1.diff.clone(), GetOptions::latest())? + // .ok_or(SocialContextError::InternalError( + // "Could not find diff entry for given diff entry reference", + // ))? + // .entry() + // .to_app_option::()? + // .ok_or(SocialContextError::InternalError( + // "Expected element to contain app entry data", + // ))?; + // out.additions.append(&mut diff_entry.additions.clone()); + // out.removals.append(&mut diff_entry.removals.clone()); + // } + // } + // Ok(out) + // } + // } + // } + + pub fn print_graph_debug(&self) { + if cfg!(test) { + println!( + "Directed: {:?}\n", + Dot::with_config( + &self.graph.map( + |_node_index, node| { crate::retriever::hash_to_node_id(node.to_owned()) }, + |_edge_index, _edge| {} + ), + &[] + ) + ); + println!( + "Undirected: {:?}\n", + Dot::with_config( + &self.undirected_graph.map( + |_node_index, node| { crate::retriever::hash_to_node_id(node.to_owned()) }, + |_edge_index, _edge| {} + ), + &[] + ) + ); + } else { + debug!( + "Directed: {:?}\n", + Dot::with_config(&self.graph, &[Config::NodeIndexLabel]) + ); + debug!( + "Undirected: {:?}\n", + Dot::with_config(&self.undirected_graph, &[]) + ); + } + } + + pub fn all_ancestors(&self, child: &Hash) -> SocialContextResult> { + debug!("===Workspace.all_ancestors(): Function start"); + let fn_start = get_now()?.time(); + + let child_node = self + .get_node_index(child) + .expect("Could not get child node index"); + let mut ancestors = vec![]; + let mut visited = HashSet::new(); + let mut stack = vec![*child_node]; + while !stack.is_empty() { + let current = stack.pop().unwrap(); + if visited.contains(¤t) { + continue; + } + visited.insert(current); + let mut parents = self + .graph + .neighbors_directed(current, petgraph::Direction::Outgoing); + while let Some(parent) = parents.next() { + stack.push(parent); + } + ancestors.push(self.graph.node_weight(current).unwrap().to_owned()); + } + + let fn_end = get_now()?.time(); + debug!("===Workspace.all_ancestors() - Profiling: Took: {} to complete all_ancestors() function", (fn_end - fn_start).num_milliseconds()); + + Ok(ancestors) + } +} + +#[cfg(test)] +mod tests { + use super::NULL_NODE; + use crate::link_adapter::workspace::Workspace; + use crate::retriever::{node_id_hash, MockPerspectiveGraph, GLOBAL_MOCKED_GRAPH}; + use dot_structures; + + #[test] + fn test_collect_until_common_ancestor_forked() { + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::from_dot( + "digraph { + 0 [ label = \"0\" ] + 1 [ label = \"1\" ] + 2 [ label = \"2\" ] + 3 [ label = \"3\" ] + 4 [ label = \"4\" ] + 5 [ label = \"5\" ] + 6 [ label = \"6\" ] + 7 [ label = \"7\" ] + 8 [ label = \"8\" ] + 9 [ label = \"9\" ] + 10 [ label = \"10\" ] + 11 [ label = \"11\" ] + 12 [ label = \"12\" ] + 1 -> 0 [ label = \"()\" ] + 2 -> 1 [ label = \"()\" ] + 3 -> 2 [ label = \"()\" ] + 4 -> 3 [ label = \"()\" ] + 5 -> 4 [ label = \"()\" ] + 6 -> 5 [ label = \"()\" ] + 7 -> 1 [ label = \"()\" ] + 8 -> 7 [ label = \"()\" ] + 9 -> 8 [ label = \"()\" ] + 10 -> 9 [ label = \"()\" ] + 11 -> 10 [ label = \"()\" ] + 12 -> 11 [ label = \"()\" ] + }", + ) + .unwrap(); + } + update(); + + let node_1 = node_id_hash(&dot_structures::Id::Plain(String::from("1"))); + let node_6 = node_id_hash(&dot_structures::Id::Plain(String::from("6"))); + let node_12 = node_id_hash(&dot_structures::Id::Plain(String::from("12"))); + + let mut workspace = Workspace::new(); + let res = workspace.build_diffs::(node_12.clone(), node_6.clone()); + assert!(res.is_ok()); + + assert!(workspace.common_ancestors.len() == 1); + assert_eq!(workspace.common_ancestors.first().unwrap(), &node_1); + + assert_eq!(workspace.entry_map.len(), 12); + + let node_2 = node_id_hash(&dot_structures::Id::Plain(String::from("2"))); + let node_3 = node_id_hash(&dot_structures::Id::Plain(String::from("3"))); + let node_4 = node_id_hash(&dot_structures::Id::Plain(String::from("4"))); + let node_5 = node_id_hash(&dot_structures::Id::Plain(String::from("5"))); + let node_7 = node_id_hash(&dot_structures::Id::Plain(String::from("7"))); + let node_8 = node_id_hash(&dot_structures::Id::Plain(String::from("8"))); + let node_9 = node_id_hash(&dot_structures::Id::Plain(String::from("9"))); + let node_10 = node_id_hash(&dot_structures::Id::Plain(String::from("10"))); + let node_11 = node_id_hash(&dot_structures::Id::Plain(String::from("11"))); + + assert!(workspace.entry_map.get(&node_1).is_some()); + assert!(workspace.entry_map.get(&node_2).is_some()); + assert!(workspace.entry_map.get(&node_3).is_some()); + assert!(workspace.entry_map.get(&node_4).is_some()); + assert!(workspace.entry_map.get(&node_5).is_some()); + assert!(workspace.entry_map.get(&node_6).is_some()); + assert!(workspace.entry_map.get(&node_7).is_some()); + assert!(workspace.entry_map.get(&node_8).is_some()); + assert!(workspace.entry_map.get(&node_9).is_some()); + assert!(workspace.entry_map.get(&node_10).is_some()); + assert!(workspace.entry_map.get(&node_11).is_some()); + assert!(workspace.entry_map.get(&node_12).is_some()); + } + + #[test] + fn test_collect_until_common_ancestor_forward_to_merge_commit() { + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::from_dot( + "digraph { + 0 [ label = \"0\" ] + 1 [ label = \"1\" ] + 2 [ label = \"2\" ] + 3 [ label = \"3\" ] + 4 [ label = \"4\" ] + 5 [ label = \"5\" ] + 6 [ label = \"6\" ] + 7 [ label = \"7\" ] + 8 [ label = \"8\" ] + 9 [ label = \"9\" ] + 10 [ label = \"10\" ] + 11 [ label = \"11\" ] + 12 [ label = \"12\" ] + 13 [ label = \"12\" ] + + 1 -> 0 [ label = \"()\" ] + 2 -> 1 [ label = \"()\" ] + 3 -> 2 [ label = \"()\" ] + 4 -> 3 [ label = \"()\" ] + 5 -> 4 [ label = \"()\" ] + 6 -> 5 [ label = \"()\" ] + + 7 -> 1 [ label = \"()\" ] + 8 -> 7 [ label = \"()\" ] + 9 -> 8 [ label = \"()\" ] + 10 -> 9 [ label = \"()\" ] + 11 -> 10 [ label = \"()\" ] + + 12 -> 11 [ label = \"()\" ] + 12 -> 6 [ label = \"()\" ] + + 13 -> 12 [ label = \"()\" ] + + }", + ) + .unwrap(); + } + update(); + + let node_1 = node_id_hash(&dot_structures::Id::Plain(String::from("1"))); + let node_6 = node_id_hash(&dot_structures::Id::Plain(String::from("6"))); + let node_12 = node_id_hash(&dot_structures::Id::Plain(String::from("12"))); + let node_13 = node_id_hash(&dot_structures::Id::Plain(String::from("13"))); + + let mut workspace = Workspace::new(); + let res = workspace.build_diffs::(node_13.clone(), node_6.clone()); + assert!(res.is_ok()); + + assert!(workspace.common_ancestors.len() == 1); + assert_eq!(workspace.common_ancestors.first().unwrap(), &node_1); + assert_eq!(workspace.entry_map.len(), 13); + + let node_2 = node_id_hash(&dot_structures::Id::Plain(String::from("2"))); + let node_3 = node_id_hash(&dot_structures::Id::Plain(String::from("3"))); + let node_4 = node_id_hash(&dot_structures::Id::Plain(String::from("4"))); + let node_5 = node_id_hash(&dot_structures::Id::Plain(String::from("5"))); + let node_7 = node_id_hash(&dot_structures::Id::Plain(String::from("7"))); + let node_8 = node_id_hash(&dot_structures::Id::Plain(String::from("8"))); + let node_9 = node_id_hash(&dot_structures::Id::Plain(String::from("9"))); + let node_10 = node_id_hash(&dot_structures::Id::Plain(String::from("10"))); + let node_11 = node_id_hash(&dot_structures::Id::Plain(String::from("11"))); + + assert!(workspace.entry_map.get(&node_1).is_some()); + assert!(workspace.entry_map.get(&node_2).is_some()); + assert!(workspace.entry_map.get(&node_3).is_some()); + assert!(workspace.entry_map.get(&node_4).is_some()); + assert!(workspace.entry_map.get(&node_5).is_some()); + assert!(workspace.entry_map.get(&node_6).is_some()); + assert!(workspace.entry_map.get(&node_7).is_some()); + assert!(workspace.entry_map.get(&node_8).is_some()); + assert!(workspace.entry_map.get(&node_9).is_some()); + assert!(workspace.entry_map.get(&node_10).is_some()); + assert!(workspace.entry_map.get(&node_11).is_some()); + assert!(workspace.entry_map.get(&node_12).is_some()); + assert!(workspace.entry_map.get(&node_13).is_some()); + } + + #[test] + fn test_collect_until_common_ancestor_multi_fork() { + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::from_dot( + r#"digraph { + 0 [ label = "0" ] + 1 [ label = "1" ] + 2 [ label = "2" ] + 3 [ label = "3" ] + 4 [ label = "4" ] + 5 [ label = "5" ] + + 1 -> 0 [ label = "()" ] + 2 -> 1 [ label = "()" ] + + 3 -> 0 [ label = "()" ] + + 4 -> 0 [ label = "()" ] + 5 -> 4 [ label = "()" ] + }"#, + ) + .unwrap(); + } + update(); + + let node_0 = node_id_hash(&dot_structures::Id::Plain(String::from("0"))); + let node_1 = node_id_hash(&dot_structures::Id::Plain(String::from("1"))); + let node_2 = node_id_hash(&dot_structures::Id::Plain(String::from("2"))); + let node_3 = node_id_hash(&dot_structures::Id::Plain(String::from("3"))); + //let node_4 = node_id_hash(&dot_structures::Id::Plain(String::from("4"))); + //let node_5 = node_id_hash(&dot_structures::Id::Plain(String::from("5"))); + + let mut workspace = Workspace::new(); + let res = workspace.build_diffs::(node_3.clone(), node_2.clone()); + assert!(res.is_ok()); + + assert!(workspace.common_ancestors.len() == 1); + assert_eq!(workspace.common_ancestors.first().unwrap(), &node_0); + assert_eq!(workspace.entry_map.len(), 4); + + assert!(workspace.entry_map.get(&node_0).is_some()); + assert!(workspace.entry_map.get(&node_1).is_some()); + assert!(workspace.entry_map.get(&node_2).is_some()); + assert!(workspace.entry_map.get(&node_3).is_some()); + } + + #[test] + fn test_collect_until_common_ancestor_fork_on_top_of_merge() { + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::from_dot( + r#"digraph { + 0 [ label = "0" ] + 1 [ label = "1" ] + 2 [ label = "2" ] + 3 [ label = "3" ] + 4 [ label = "4" ] + 5 [ label = "5" ] + + 1 -> 0 + 2 -> 1 + 3 -> 2 + 4 -> 3 + 5 -> 4 + + 6 + 7 + 8 + 9 + 10 + + 7 -> 6 + 8 -> 7 + 9 -> 8 + 10 -> 9 + + 8 -> 0 + + }"#, + ) + .unwrap(); + } + update(); + + let node_0 = node_id_hash(&dot_structures::Id::Plain(String::from("0"))); + let node_1 = node_id_hash(&dot_structures::Id::Plain(String::from("1"))); + let node_2 = node_id_hash(&dot_structures::Id::Plain(String::from("2"))); + let node_3 = node_id_hash(&dot_structures::Id::Plain(String::from("3"))); + let node_4 = node_id_hash(&dot_structures::Id::Plain(String::from("4"))); + let node_5 = node_id_hash(&dot_structures::Id::Plain(String::from("5"))); + //let node_6 = node_id_hash(&dot_structures::Id::Plain(String::from("6"))); + //let node_7 = node_id_hash(&dot_structures::Id::Plain(String::from("7"))); + let node_8 = node_id_hash(&dot_structures::Id::Plain(String::from("8"))); + let node_9 = node_id_hash(&dot_structures::Id::Plain(String::from("9"))); + let node_10 = node_id_hash(&dot_structures::Id::Plain(String::from("10"))); + + let mut workspace = Workspace::new(); + let res = workspace.build_diffs::(node_5.clone(), node_10.clone()); + println!("Got result: {:#?}", res); + assert!(res.is_ok()); + + assert!(workspace.common_ancestors.len() == 2); + assert_eq!(workspace.common_ancestors.first().unwrap(), &node_0); + assert_eq!(workspace.common_ancestors.last().unwrap(), &NULL_NODE()); + assert_eq!(workspace.entry_map.len(), 12); + + assert!(workspace.entry_map.get(&node_0).is_some()); + assert!(workspace.entry_map.get(&node_1).is_some()); + assert!(workspace.entry_map.get(&node_2).is_some()); + assert!(workspace.entry_map.get(&node_3).is_some()); + assert!(workspace.entry_map.get(&node_4).is_some()); + assert!(workspace.entry_map.get(&node_5).is_some()); + //assert!(workspace.entry_map.get(&node_7).is_some()); + assert!(workspace.entry_map.get(&node_8).is_some()); + assert!(workspace.entry_map.get(&node_9).is_some()); + assert!(workspace.entry_map.get(&node_10).is_some()); + } + + #[test] + fn test_collect_until_common_ancestor_unconnected_fork() { + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::from_dot( + r#"digraph { + 0 [ label = "0" ] + 1 [ label = "1" ] + 2 [ label = "2" ] + 3 [ label = "3" ] + 4 [ label = "4" ] + 5 [ label = "5" ] + + 1 -> 0 + 2 -> 1 + 3 -> 2 + 4 -> 3 + 5 -> 4 + + 6 + 7 + 8 + 9 + 10 + + 7 -> 6 + 8 -> 7 + 9 -> 8 + 10 -> 9 + }"#, + ) + .unwrap(); + } + update(); + + let node_0 = node_id_hash(&dot_structures::Id::Plain(String::from("0"))); + let node_1 = node_id_hash(&dot_structures::Id::Plain(String::from("1"))); + let node_2 = node_id_hash(&dot_structures::Id::Plain(String::from("2"))); + let node_3 = node_id_hash(&dot_structures::Id::Plain(String::from("3"))); + let node_4 = node_id_hash(&dot_structures::Id::Plain(String::from("4"))); + let node_5 = node_id_hash(&dot_structures::Id::Plain(String::from("5"))); + let node_6 = node_id_hash(&dot_structures::Id::Plain(String::from("6"))); + let node_7 = node_id_hash(&dot_structures::Id::Plain(String::from("7"))); + let node_8 = node_id_hash(&dot_structures::Id::Plain(String::from("8"))); + let node_9 = node_id_hash(&dot_structures::Id::Plain(String::from("9"))); + let node_10 = node_id_hash(&dot_structures::Id::Plain(String::from("10"))); + + let mut workspace = Workspace::new(); + let res = workspace.build_diffs::(node_5.clone(), node_10.clone()); + println!("Got result: {:#?}", res); + assert!(res.is_ok()); + + assert!(workspace.common_ancestors.len() == 1); + assert_eq!(workspace.common_ancestors.first().unwrap(), &NULL_NODE()); + assert_eq!(workspace.entry_map.len(), 12); + + assert!(workspace.entry_map.get(&NULL_NODE()).is_some()); + assert!(workspace.entry_map.get(&node_0).is_some()); + assert!(workspace.entry_map.get(&node_1).is_some()); + assert!(workspace.entry_map.get(&node_2).is_some()); + assert!(workspace.entry_map.get(&node_3).is_some()); + assert!(workspace.entry_map.get(&node_4).is_some()); + assert!(workspace.entry_map.get(&node_5).is_some()); + assert!(workspace.entry_map.get(&node_6).is_some()); + assert!(workspace.entry_map.get(&node_7).is_some()); + assert!(workspace.entry_map.get(&node_8).is_some()); + assert!(workspace.entry_map.get(&node_9).is_some()); + assert!(workspace.entry_map.get(&node_10).is_some()); + } + + #[test] + fn test_collect_until_common_ancestor_ff_to_merge() { + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::from_dot( + r#"digraph { + 0 [ label = "0" ] + 1 [ label = "1" ] + 2 [ label = "2" ] + 3 [ label = "3" ] + + 1 -> 0 + 2 -> 0 + 3 -> 1 + 3 -> 2 + + }"#, + ) + .unwrap(); + } + update(); + + let node_0 = node_id_hash(&dot_structures::Id::Plain(String::from("0"))); + let node_1 = node_id_hash(&dot_structures::Id::Plain(String::from("1"))); + let node_2 = node_id_hash(&dot_structures::Id::Plain(String::from("2"))); + let node_3 = node_id_hash(&dot_structures::Id::Plain(String::from("3"))); + + let mut workspace = Workspace::new(); + let res = workspace.build_diffs::(node_1.clone(), node_3.clone()); + println!("Got result: {:#?}", res); + assert!(res.is_ok()); + + println!("common ancestors: {:?}", workspace.common_ancestors); + assert_eq!(workspace.common_ancestors.len(), 2); + assert_eq!(workspace.common_ancestors.first().unwrap(), &node_1); + assert_eq!(workspace.common_ancestors.last().unwrap(), &node_0); + assert_eq!(workspace.entry_map.len(), 4); + + assert!(workspace.entry_map.get(&node_0).is_some()); + assert!(workspace.entry_map.get(&node_1).is_some()); + assert!(workspace.entry_map.get(&node_2).is_some()); + assert!(workspace.entry_map.get(&node_3).is_some()); + } + + #[test] + fn test_collect_until_common_ancestor_complex_merge() { + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::from_dot( + r#"digraph { + 0 [ label = "0" ] + 1 [ label = "1" ] + 2 [ label = "2" ] + 3 [ label = "3" ] + 4 [ label = "4" ] + 5 [ label = "5" ] + 6 [ label = "6" ] + 1 -> 0 [ label = "()" ] + 2 -> 0 [ label = "()" ] + 3 -> 0 [ label = "()" ] + 4 -> 2 [ label = "()" ] + 5 -> 4 [ label = "()" ] + 5 -> 3 [ label = "()" ] + 6 -> 5 [ label = "()" ] + }"#, + ) + .unwrap(); + } + update(); + + let node_0 = node_id_hash(&dot_structures::Id::Plain(String::from("0"))); + let node_1 = node_id_hash(&dot_structures::Id::Plain(String::from("1"))); + let node_2 = node_id_hash(&dot_structures::Id::Plain(String::from("2"))); + let node_3 = node_id_hash(&dot_structures::Id::Plain(String::from("3"))); + let node_4 = node_id_hash(&dot_structures::Id::Plain(String::from("4"))); + let node_5 = node_id_hash(&dot_structures::Id::Plain(String::from("5"))); + let node_6 = node_id_hash(&dot_structures::Id::Plain(String::from("6"))); + + let mut workspace = Workspace::new(); + let res = workspace.build_diffs::(node_1.clone(), node_6.clone()); + println!("Got result: {:#?}", res); + assert!(res.is_ok()); + + println!("common ancestors: {:?}", workspace.common_ancestors); + assert_eq!(workspace.common_ancestors.len(), 1); + assert_eq!(workspace.common_ancestors.last().unwrap(), &node_0); + assert_eq!(workspace.entry_map.len(), 7); + + assert!(workspace.entry_map.get(&node_0).is_some()); + assert!(workspace.entry_map.get(&node_1).is_some()); + assert!(workspace.entry_map.get(&node_2).is_some()); + assert!(workspace.entry_map.get(&node_3).is_some()); + assert!(workspace.entry_map.get(&node_4).is_some()); + assert!(workspace.entry_map.get(&node_5).is_some()); + assert!(workspace.entry_map.get(&node_6).is_some()); + } + + #[test] + fn test_collect_until_common_ancestor_complex_merge_implicit_zero() { + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::from_dot( + r#"digraph { + 1 [ label = "1" ] + 2 [ label = "2" ] + 3 [ label = "3" ] + 4 [ label = "4" ] + 5 [ label = "5" ] + 6 [ label = "6" ] + 4 -> 2 [ label = "()" ] + 5 -> 4 [ label = "()" ] + 5 -> 3 [ label = "()" ] + 6 -> 5 [ label = "()" ] + }"#, + ) + .unwrap(); + } + update(); + + let node_1 = node_id_hash(&dot_structures::Id::Plain(String::from("1"))); + let node_6 = node_id_hash(&dot_structures::Id::Plain(String::from("6"))); + + let mut workspace = Workspace::new(); + let res = workspace.build_diffs::(node_1.clone(), node_6.clone()); + println!("Got result: {:#?}", res); + assert!(res.is_ok()); + assert_eq!(workspace.common_ancestors.len(), 2); + assert_eq!(workspace.common_ancestors.last().unwrap(), &NULL_NODE()); + } + + #[test] + fn real_world_graph() { + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::from_dot( + r#"digraph { + 0 [ label = "0" ] + 1 [ label = "1" ] + 2 [ label = "2" ] + 3 [ label = "3" ] + 4 [ label = "4" ] + 5 [ label = "5" ] + 6 [ label = "6" ] + 7 [ label = "7" ] + 8 [ label = "8" ] + 9 [ label = "9" ] + 10 [ label = "10" ] + 11 [ label = "11" ] + 12 [ label = "12" ] + 13 [ label = "13" ] + 14 [ label = "14" ] + 15 [ label = "15" ] + 16 [ label = "16" ] + 1 -> 0 [ label = "()" ] + 2 -> 1 [ label = "()" ] + 3 -> 2 [ label = "()" ] + 4 -> 3 [ label = "()" ] + 5 -> 4 [ label = "()" ] + 6 -> 5 [ label = "()" ] + 7 -> 6 [ label = "()" ] + 8 -> 7 [ label = "()" ] + 9 -> 8 [ label = "()" ] + 10 -> 9 [ label = "()" ] + 11 -> 1 [ label = "()" ] + 12 -> 2 [ label = "()" ] + 12 -> 11 [ label = "()" ] + 13 -> 3 [ label = "()" ] + 13 -> 12 [ label = "()" ] + 14 -> 6 [ label = "()" ] + 14 -> 13 [ label = "()" ] + 15 -> 7 [ label = "()" ] + 15 -> 14 [ label = "()" ] + 16 -> 8 [ label = "()" ] + 16 -> 15 [ label = "()" ] + }"#, + ) + .unwrap(); + } + update(); + + let node_10 = node_id_hash(&dot_structures::Id::Plain(String::from("10"))); + let node_16 = node_id_hash(&dot_structures::Id::Plain(String::from("16"))); + let node_8 = node_id_hash(&dot_structures::Id::Plain(String::from("8"))); + + let mut workspace = Workspace::new(); + let res = workspace.build_diffs::(node_16.clone(), node_10.clone()); + assert!(res.is_ok()); + assert_eq!(workspace.common_ancestors.len(), 6); + assert_eq!(workspace.common_ancestors.first().unwrap(), &node_8); + println!("Got result: {:#?}", res); + } +} diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/retriever.rs b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/retriever.rs new file mode 100644 index 000000000..e1b404571 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/retriever.rs @@ -0,0 +1,35 @@ +use crate::Hash; +use crate::errors::SocialContextResult; +use hdk::prelude::*; +use chrono::{DateTime, Utc}; + +pub mod holochain; +pub mod mock; + +pub use holochain::HolochainRetreiver; +pub use mock::*; +use perspective_diff_sync_integrity::{LocalHashReference, HashReference}; + +pub trait PerspectiveDiffRetreiver { + fn get(hash: Hash) -> SocialContextResult + where + T: TryFrom; + + fn get_with_timestamp(hash: Hash) -> SocialContextResult<(T, DateTime)> + where + T: TryFrom; + + fn create_entry(entry: I) -> SocialContextResult + where + ScopedEntryDefIndex: for<'a> TryFrom<&'a I, Error = E2>, + EntryVisibility: for<'a> From<&'a I>, + Entry: TryFrom, + WasmError: From, + WasmError: From; + fn current_revision() -> SocialContextResult>; + fn latest_revision() -> SocialContextResult>; + fn update_current_revision(hash: Hash, timestamp: DateTime) -> SocialContextResult<()>; + fn update_latest_revision(hash: Hash, timestamp: DateTime) -> SocialContextResult<()>; +} + + diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/retriever/holochain.rs b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/retriever/holochain.rs new file mode 100644 index 000000000..c97a7f3bd --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/retriever/holochain.rs @@ -0,0 +1,199 @@ +use std::str::FromStr; + +use chrono::{DateTime, NaiveDateTime, Utc}; +use hdk::prelude::*; +use perspective_diff_sync_integrity::{ + Anchor, EntryTypes, HashReference, LinkTypes, LocalHashReference, +}; + +use super::PerspectiveDiffRetreiver; +use crate::errors::{SocialContextError, SocialContextResult}; +use crate::utils::dedup; +use crate::Hash; + +pub struct HolochainRetreiver; + +impl PerspectiveDiffRetreiver for HolochainRetreiver { + fn get(hash: Hash) -> SocialContextResult + where + T: TryFrom, + { + get(hash, GetOptions::latest())? + .ok_or(SocialContextError::InternalError( + "HolochainRetreiver: Could not find entry", + ))? + .entry() + .to_app_option::()? + .ok_or(SocialContextError::InternalError( + "Expected element to contain app entry data", + )) + } + + fn get_with_timestamp(hash: Hash) -> SocialContextResult<(T, DateTime)> + where + T: TryFrom, + { + let element = get(hash, GetOptions::latest())?; + let element = element.ok_or(SocialContextError::InternalError( + "HolochainRetreiver: Could not find entry", + ))?; + let entry = element.entry(); + let timestamp = element.action().timestamp().0 as u64; + let duration = std::time::Duration::from_micros(timestamp); + let timestamp = DateTime::::from_utc( + NaiveDateTime::from_timestamp(duration.as_secs() as i64, duration.subsec_nanos()), + Utc, + ); + let entry = entry + .to_app_option::()? + .ok_or(SocialContextError::InternalError( + "Expected element to contain app entry data", + ))?; + Ok((entry, timestamp)) + } + + fn create_entry(entry: I) -> SocialContextResult + where + ScopedEntryDefIndex: for<'a> TryFrom<&'a I, Error = E2>, + EntryVisibility: for<'a> From<&'a I>, + Entry: TryFrom, + WasmError: From, + WasmError: From, + { + create_entry::(entry).map_err(|e| SocialContextError::Wasm(e)) + } + + fn current_revision() -> SocialContextResult> { + let query = query( + QueryFilter::new() + .entry_type(EntryType::App(AppEntryDef { + entry_index: 4.into(), + zome_index: 0.into(), + visibility: EntryVisibility::Private, + })) + .include_entries(true) + .descending(), + ); + + let revision = match query { + Ok(records) => { + if records.len() == 0 { + None + } else { + let record = records[0].clone(); + let entry = record + .entry + .to_app_option::() + .unwrap() + .unwrap(); + Some(entry) + } + } + Err(e) => { + debug!("PerspectiveDiffSync.current_revision(): Error when getting current revision: {:?}", e); + None + } + }; + Ok(revision) + } + + fn latest_revision() -> SocialContextResult> { + let latest_root_entry = get_latest_revision_anchor(); + let latest_root_entry_hash = hash_entry(latest_root_entry.clone())?; + // let input = GetLinksInputBuilder::try_new( + // latest_root_entry_hash, + // LinkTypes::Index + // ) + // .unwrap() + // .build(); + let mut latest_revision_links = get_links(latest_root_entry_hash, LinkTypes::Index, None)?; + + latest_revision_links.sort_by(|link_a, link_b| { + let link_a_str = std::str::from_utf8(&link_a.tag.0).unwrap(); + let link_b_str = std::str::from_utf8(&link_b.tag.0).unwrap(); + let link_a = DateTime::::from_str(link_a_str).unwrap(); + let link_b = DateTime::::from_str(link_b_str).unwrap(); + link_a.cmp(&link_b) + }); + + let mut latest_hash_revisions = latest_revision_links + .into_iter() + .map(|link| { + let hash = + link.target + .into_action_hash() + .ok_or(SocialContextError::InternalError( + "Could not convert link target to hash", + ))?; + let timestamp = std::str::from_utf8(&link.tag.0) + .map_err(|_| SocialContextError::InternalError("Could not tag to string"))?; + + let timestamp = DateTime::::from_str(timestamp).map_err(|_| { + SocialContextError::InternalError("Could not convert string to timestamp") + })?; + Ok(HashReference { hash, timestamp }) + }) + .collect::>>()?; + + Ok(latest_hash_revisions.pop()) + } + + fn update_current_revision(hash: Hash, timestamp: DateTime) -> SocialContextResult<()> { + let hash_ref = LocalHashReference { hash, timestamp }; + create_entry(EntryTypes::LocalHashReference(hash_ref.clone()))?; + Ok(()) + } + + fn update_latest_revision(hash: Hash, timestamp: DateTime) -> SocialContextResult<()> { + let latest_root_entry = get_latest_revision_anchor(); + let _latest_root_entry_action = + self::create_entry(EntryTypes::Anchor(latest_root_entry.clone()))?; + + create_link( + hash_entry(latest_root_entry)?, + hash, + LinkTypes::Index, + LinkTag::new(timestamp.to_string()), + )?; + + Ok(()) + } +} + +fn get_latest_revision_anchor() -> Anchor { + Anchor("latest_revision".to_string()) +} + +pub fn get_active_agent_anchor() -> Anchor { + Anchor("active_agent".to_string()) +} + +pub fn get_active_agents() -> SocialContextResult> { + // let input = GetLinksInputBuilder::try_new( + // hash_entry(get_active_agent_anchor())?, + // LinkTypes::Index + // ) + // .unwrap() + // .tag_prefix(LinkTag::new("active_agent")) + // .build(); + let recent_agents = get_links(hash_entry(get_active_agent_anchor())?, LinkTypes::Index, Some(LinkTag::new("active_agent")))?; + + let recent_agents = recent_agents + .into_iter() + .map(|val| { + let entry: EntryHash = val.target.try_into().unwrap(); + AgentPubKey::from(entry) + }) + .collect(); + + //Dedup the agents + let mut recent_agents = dedup(&recent_agents); + //Remove ourself from the agents + let me = agent_info()?.agent_latest_pubkey; + let index = recent_agents.iter().position(|x| *x == me); + if let Some(index) = index { + recent_agents.remove(index); + }; + + Ok(recent_agents) +} diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/retriever/mock.rs b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/retriever/mock.rs new file mode 100644 index 000000000..ca83bcc29 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/retriever/mock.rs @@ -0,0 +1,530 @@ +use chrono::{DateTime, Utc}; +use dot_structures; +use graphviz_rust; +use hdk::prelude::*; +use perspective_diff_sync_integrity::{ + HashReference, LinkExpression, LocalHashReference, PerspectiveDiff, + PerspectiveDiffEntryReference, +}; +use sha2::{Digest, Sha256}; +use std::collections::BTreeMap; +use std::sync::Mutex; + +use super::PerspectiveDiffRetreiver; +use crate::errors::{SocialContextError, SocialContextResult}; +use crate::link_adapter::workspace::NULL_NODE; +use crate::utils::create_link_expression; +use crate::Hash; + +#[derive(Debug)] +pub struct MockPerspectiveGraph { + pub graph_map: BTreeMap, +} + +impl PerspectiveDiffRetreiver for MockPerspectiveGraph { + fn get(hash: Hash) -> SocialContextResult + where + T: TryFrom, + { + let value = &GLOBAL_MOCKED_GRAPH + .lock() + .expect("Could not get lock on graph map") + .graph_map + .get(&hash) + .expect("Could not find entry in map") + .to_owned(); + Ok(T::try_from(value.to_owned())?) + } + + fn get_with_timestamp(hash: Hash) -> SocialContextResult<(T, DateTime)> + where + T: TryFrom, + { + let value = &GLOBAL_MOCKED_GRAPH + .lock() + .expect("Could not get lock on graph map") + .graph_map + .get(&hash) + .expect("Could not find entry in map") + .to_owned(); + Ok((T::try_from(value.to_owned())?, Utc::now())) + } + + fn create_entry(entry: I) -> SocialContextResult + where + ScopedEntryDefIndex: for<'a> TryFrom<&'a I, Error = E2>, + EntryVisibility: for<'a> From<&'a I>, + Entry: TryFrom, + WasmError: From, + WasmError: From, + { + let mut object_store = GLOBAL_MOCKED_GRAPH + .lock() + .expect("Could not get lock on OBJECT_STORE"); + + let entry: Entry = entry.try_into().expect("Could not get Entry"); + let sb = match entry { + Entry::App(bytes) => bytes, + _ => panic!("Should not get any entry except app"), + }; + let bytes = sb.bytes(); + + let mut hasher = Sha256::new(); + hasher.update(bytes); + let mut result = hasher.finalize().as_slice().to_owned(); + result.append(&mut vec![0xdb, 0xdb, 0xdb, 0xdb]); + + let hash = ActionHash::from_raw_36(result); + object_store.graph_map.insert(hash.clone(), sb.0); + Ok(hash) + } + + fn current_revision() -> SocialContextResult> { + let revision = CURRENT_REVISION + .lock() + .expect("Could not get lock on CURRENT_REVISION"); + Ok(revision.clone().map(|val| LocalHashReference { + hash: val, + timestamp: Utc::now(), + })) + } + + fn latest_revision() -> SocialContextResult> { + let revision = LATEST_REVISION + .lock() + .expect("Could not get lock on LATEST_REVISION"); + Ok(revision.clone().map(|val| HashReference { + hash: val, + timestamp: Utc::now(), + })) + } + + fn update_current_revision(hash: Hash, _timestamp: DateTime) -> SocialContextResult<()> { + let mut revision = CURRENT_REVISION + .lock() + .expect("Could not get lock on CURRENT_REVISION"); + *revision = Some(hash); + Ok(()) + } + + fn update_latest_revision(hash: Hash, _timestamp: DateTime) -> SocialContextResult<()> { + let mut revision = LATEST_REVISION + .lock() + .expect("Could not get lock on LATEST_REVISION"); + *revision = Some(hash); + Ok(()) + } +} + +pub struct GraphInput { + pub nodes: u8, + pub associations: Vec, +} + +pub struct Associations { + pub node_source: u8, + pub node_targets: Vec, +} + +#[allow(dead_code)] +pub fn node_id_hash(id: &dot_structures::Id) -> Hash { + let mut string = match id { + dot_structures::Id::Html(s) => s, + dot_structures::Id::Escaped(s) => s, + dot_structures::Id::Plain(s) => s, + dot_structures::Id::Anonymous(s) => s, + } + .clone(); + if string.len() > 36 { + let _ = string.split_off(36); + } else { + while string.len() < 36 { + string.push_str("x"); + } + } + ActionHash::from_raw_36(string.into_bytes()) +} + +#[allow(dead_code)] +pub fn hash_to_node_id(hash: ActionHash) -> String { + if hash == NULL_NODE() { + return String::from("NULL_NODE"); + }; + let hash_bytes = hash.get_raw_36(); + + match std::str::from_utf8(hash_bytes) { + Ok(node_id_string) => { + let string_split = node_id_string + .split("x") + .collect::>() + .first() + .unwrap() + .to_owned(); + string_split.to_string() + } + Err(_err) => hash.to_string(), + } +} + +// #[allow(dead_code)] +// pub fn string_to_node_id(mut hash: String) -> String { +// if hash == NULL_NODE().to_string() { +// return String::from("NULL_NODE") +// }; +// if hash.len() > 36 { +// let _ = hash.split_off(36); +// }; +// let hash = ActionHash::from_raw_36(hash.into_bytes()); +// let hash = hash.get_raw_36(); +// let node_id_string = std::str::from_utf8(hash).expect("could not get string from hash array"); +// let string_split = node_id_string.split("x").collect::>().first().unwrap().to_owned(); +// string_split.to_string() +// } + +#[allow(dead_code)] +pub fn create_node_id_link_expression(node_id: u32) -> LinkExpression { + let node_id = node_id.to_string(); + let node_id = dot_structures::Id::Plain(node_id); + let node = &node_id_hash(&node_id).to_string(); + create_link_expression(node, node) +} + +#[allow(dead_code)] +pub fn create_node_id_vec(range_start: u32, range_end: u32) -> Vec { + let mut out = vec![]; + for n in range_start..=range_end { + out.push(create_node_id_link_expression(n)); + } + out +} + +// #[allow(dead_code)] +// pub fn link_expression_to_node_id(links: &mut Vec) { +// links.iter_mut().for_each(|link| { +// if link.data.source.is_some() { +// link.data.source = Some(string_to_node_id(link.data.source.clone().unwrap())); +// } +// if link.data.target.is_some() { +// link.data.target = Some(string_to_node_id(link.data.target.clone().unwrap())); +// } +// }) +// } + +#[allow(dead_code)] +fn unwrap_vertex(v: dot_structures::Vertex) -> Option { + match v { + dot_structures::Vertex::N(id) => Some(id), + _ => None, + } +} + +#[allow(dead_code)] +fn unwrap_edge( + edge: dot_structures::Edge, +) -> Option<(dot_structures::NodeId, dot_structures::NodeId)> { + match edge.ty { + dot_structures::EdgeTy::Pair(a, b) => { + let au = unwrap_vertex(a); + let ab = unwrap_vertex(b); + if au.is_some() && ab.is_some() { + Some((au.unwrap(), ab.unwrap())) + } else { + None + } + } + _ => None, + } +} + +impl MockPerspectiveGraph { + pub fn new(graph_input: GraphInput) -> MockPerspectiveGraph { + let mut graph = MockPerspectiveGraph { + graph_map: BTreeMap::new(), + }; + + for n in 0..graph_input.nodes { + let mocked_hash = ActionHash::from_raw_36(vec![n; 36]); + let associations: Vec<&Associations> = graph_input + .associations + .iter() + .filter(|association| association.node_source == n) + .collect(); + let parents = if associations.len() > 0 { + let mut temp = vec![]; + for association in associations.clone() { + for targets in association.node_targets.clone() { + temp.push(ActionHash::from_raw_36(vec![targets; 36])) + } + } + Some(temp) + } else { + None + }; + let mocked_diff = PerspectiveDiffEntryReference::new(mocked_hash.clone(), parents); + let sb = mocked_diff + .try_into() + .expect("Could not create serialized bytes for mocked_diff"); + graph.graph_map.insert(mocked_hash, sb); + } + + graph + } + + #[allow(dead_code)] + pub fn from_dot(source: &str) -> SocialContextResult { + match graphviz_rust::parse(source) + .map_err(|_| SocialContextError::InternalError("Can't parse as DOT string"))? + { + dot_structures::Graph::Graph { .. } => Err(SocialContextError::InternalError( + "Can't work with undirected DOT graphs", + )), + dot_structures::Graph::DiGraph { stmts, .. } => { + let mut graph = MockPerspectiveGraph { + graph_map: BTreeMap::new(), + }; + + let mut hashes = Vec::::new(); + let mut parents: BTreeMap> = BTreeMap::new(); + + for s in stmts.iter() { + match s { + dot_structures::Stmt::Node(node) => hashes.push(node_id_hash(&node.id.0)), + dot_structures::Stmt::Edge(edge) => { + if let Some(e) = unwrap_edge(edge.clone()) { + let id_0 = e.0 .0; + let id_1 = e.1 .0; + let child = node_id_hash(&id_0); + let parent = node_id_hash(&id_1); + //println!("Edge: {} -> {}", id_0, id_1); + //println!("Edge: {} -> {}", child, parent); + match parents.remove(&child) { + None => parents.insert(child, vec![parent]), + Some(mut prev) => { + prev.push(parent); + parents.insert(child, prev) + } + }; + } + } + _ => {} + } + } + + for ref_hash in hashes.iter() { + //Create a mock diff + let diff = PerspectiveDiff { + additions: vec![create_link_expression( + &ref_hash.to_string(), + &ref_hash.to_string(), + )], + removals: vec![], + }; + + //Create a mock hash for the fake diff + let ref_sb = SerializedBytes::try_from(diff.clone())?; + let mut hasher = Sha256::new(); + hasher.update(ref_sb.bytes()); + let mut result = hasher.finalize().as_slice().to_owned(); + result.append(&mut vec![0xdb, 0xdb, 0xdb, 0xdb]); + let diff_hash = ActionHash::from_raw_36(result); + + //Create the diff reference + let diff_ref = PerspectiveDiffEntryReference::new( + diff_hash.clone(), + parents.get(ref_hash).as_ref().cloned().cloned(), + ); + //Insert the diff reference into the map + let diff_ref_sb = diff_ref + .try_into() + .expect("Could not create serialized bytes for mocked_diff"); + graph.graph_map.insert(ref_hash.clone(), diff_ref_sb); + + //Insert the diff into the map + graph.graph_map.insert(diff_hash, ref_sb); + } + + Ok(graph) + } + } + } +} + +lazy_static! { + pub static ref GLOBAL_MOCKED_GRAPH: Mutex = + Mutex::new(MockPerspectiveGraph::new(GraphInput { + nodes: 1, + associations: vec![] + })); + pub static ref CURRENT_REVISION: Mutex> = Mutex::new(None); + pub static ref LATEST_REVISION: Mutex> = Mutex::new(None); +} + +#[test] +fn can_create_graph() { + let test = MockPerspectiveGraph::new(GraphInput { + nodes: 6, + associations: vec![ + Associations { + node_source: 1, + node_targets: vec![0], + }, + Associations { + node_source: 2, + node_targets: vec![0], + }, + Associations { + node_source: 3, + node_targets: vec![1], + }, + Associations { + node_source: 4, + node_targets: vec![2], + }, + Associations { + node_source: 5, + node_targets: vec![3, 4], + }, + ], + }); + assert_eq!(test.graph_map.keys().len(), 6); + println!("Got graph: {:#?}", test.graph_map); +} + +#[test] +fn can_create_graph_from_dot() { + let dot = "digraph { + 0 [ label = \"0\" ] + 1 [ label = \"1\" ] + 2 [ label = \"2\" ] + 3 [ label = \"3\" ] + 4 [ label = \"4\" ] + 5 [ label = \"5\" ] + 6 [ label = \"6\" ] + 7 [ label = \"7\" ] + 8 [ label = \"8\" ] + 9 [ label = \"9\" ] + 10 [ label = \"10\" ] + 11 [ label = \"11\" ] + 12 [ label = \"12\" ] + 1 -> 0 [ label = \"()\" ] + 2 -> 1 [ label = \"()\" ] + 3 -> 2 [ label = \"()\" ] + 4 -> 3 [ label = \"()\" ] + 5 -> 4 [ label = \"()\" ] + 6 -> 5 [ label = \"()\" ] + 7 -> 1 [ label = \"()\" ] + 8 -> 7 [ label = \"()\" ] + 9 -> 8 [ label = \"()\" ] + 10 -> 9 [ label = \"()\" ] + 11 -> 10 [ label = \"()\" ] + 12 -> 11 [ label = \"()\" ] + 12 -> 10 [ label = \"()\" ] + }"; + + let graph = MockPerspectiveGraph::from_dot(dot).expect("from_dot not to return error"); + //26 since there is a diffref & diff for each node + assert_eq!(graph.graph_map.keys().len(), 26); + + let node_12 = node_id_hash(&dot_structures::Id::Plain(String::from("12"))); + let node_11 = node_id_hash(&dot_structures::Id::Plain(String::from("11"))); + let node_10 = node_id_hash(&dot_structures::Id::Plain(String::from("10"))); + + let diff_12 = graph.graph_map.get(&node_12).unwrap(); + let diff_12 = PerspectiveDiffEntryReference::try_from(diff_12.to_owned()).unwrap(); + assert_eq!(diff_12.parents, Some(vec![node_11, node_10])); +} + +#[test] +fn example_test() { + use crate::link_adapter::workspace::Workspace; + + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + *graph = MockPerspectiveGraph::new(GraphInput { + nodes: 6, + associations: vec![ + Associations { + node_source: 1, + node_targets: vec![0], + }, + Associations { + node_source: 2, + node_targets: vec![0], + }, + Associations { + node_source: 3, + node_targets: vec![1], + }, + Associations { + node_source: 4, + node_targets: vec![2], + }, + Associations { + node_source: 5, + node_targets: vec![3, 4], + }, + ], + }); + } + update(); + + let mut workspace = Workspace::new(); + let res = workspace.collect_until_common_ancestor::( + ActionHash::from_raw_36(vec![5; 36]), + ActionHash::from_raw_36(vec![4; 36]), + ); + println!("Got result: {:#?}", res); +} + +#[test] +fn can_get_and_create_mocked_holochain_objects() { + fn update() { + let mut graph = GLOBAL_MOCKED_GRAPH.lock().unwrap(); + let dot = "digraph { + 0 [ label = \"0\" ] + 1 [ label = \"1\" ] + 2 [ label = \"2\" ] + 3 [ label = \"3\" ] + 4 [ label = \"4\" ] + 5 [ label = \"5\" ] + 6 [ label = \"6\" ] + 7 [ label = \"7\" ] + 8 [ label = \"8\" ] + 9 [ label = \"9\" ] + 10 [ label = \"10\" ] + 11 [ label = \"11\" ] + 12 [ label = \"12\" ] + 1 -> 0 [ label = \"()\" ] + 2 -> 1 [ label = \"()\" ] + 3 -> 2 [ label = \"()\" ] + 4 -> 3 [ label = \"()\" ] + 5 -> 4 [ label = \"()\" ] + 6 -> 5 [ label = \"()\" ] + 7 -> 1 [ label = \"()\" ] + 8 -> 7 [ label = \"()\" ] + 9 -> 8 [ label = \"()\" ] + 10 -> 9 [ label = \"()\" ] + 11 -> 10 [ label = \"()\" ] + 12 -> 11 [ label = \"()\" ] + 12 -> 10 [ label = \"()\" ] + }"; + *graph = MockPerspectiveGraph::from_dot(dot).expect("Could not create graph"); + } + update(); + let diff_ref = MockPerspectiveGraph::get::(node_id_hash( + &dot_structures::Id::Plain(String::from("1")), + )); + assert!(diff_ref.is_ok()); + + use perspective_diff_sync_integrity::{ + EntryTypes, PerspectiveDiff, PerspectiveDiffEntryReference, + }; + let commit = MockPerspectiveGraph::create_entry(EntryTypes::PerspectiveDiff(PerspectiveDiff { + additions: vec![], + removals: vec![], + })); + assert!(commit.is_ok()); + + let get_commit = MockPerspectiveGraph::get::(commit.unwrap()); + assert!(get_commit.is_ok()); +} diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/telepresence/mod.rs b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/telepresence/mod.rs new file mode 100644 index 000000000..9da170613 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/telepresence/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod signal; +pub(crate) mod status; diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/telepresence/signal.rs b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/telepresence/signal.rs new file mode 100644 index 000000000..3fa833b36 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/telepresence/signal.rs @@ -0,0 +1,30 @@ +use hdk::prelude::*; +use perspective_diff_sync_integrity::PerspectiveExpression; + +use super::status::get_dids_agent_key; +use crate::retriever::holochain::get_active_agents; +use crate::{errors::SocialContextResult, inputs::SignalData}; + +pub fn send_signal(signal_data: SignalData) -> SocialContextResult { + let agent = get_dids_agent_key(signal_data.remote_agent_did.clone())?; + // debug!( + // "PerspectiveDiffSync.send_signal() to DID: {:?} / HC: {:?}", + // signal_data.remote_agent_did, agent + // ); + match agent { + Some(agent) => remote_signal(signal_data.payload.clone().get_sb()?, vec![agent])?, + None => { + debug!("PerspectiveDiffSync.send_signal(): Could not send signal since we could not get the agents pub key from did"); + } + } + Ok(signal_data.payload) +} + +pub fn send_broadcast(data: PerspectiveExpression) -> SocialContextResult { + let active_agents = get_active_agents()?; + + //debug!("PerspectiveDiffSync.send_broadcast() to: {:?}", active_agents); + remote_signal(data.clone().get_sb()?, active_agents)?; + + Ok(data) +} diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/telepresence/status.rs b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/telepresence/status.rs new file mode 100644 index 000000000..eba6ab08b --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/telepresence/status.rs @@ -0,0 +1,232 @@ +use hdk::prelude::*; + +use perspective_diff_sync_integrity::{ + Anchor, EntryTypes, LinkTypes, OnlineAgent, OnlineAgentAndAction, PerspectiveExpression, +}; + +use crate::errors::{SocialContextError, SocialContextResult}; +use crate::retriever::holochain::get_active_agents; + +pub fn set_online_status(status: PerspectiveExpression) -> SocialContextResult<()> { + let entry = EntryTypes::PrivateOnlineStatus(status); + create_entry(&entry)?; + Ok(()) +} + +pub fn get_online_status() -> SocialContextResult { + //Try and get my did + let my_did = get_my_did()?.ok_or(SocialContextError::NoDidFound)?; + + //Try and get my online status + let query = query( + QueryFilter::new() + .entry_type(EntryType::App(AppEntryDef { + entry_index: 7.into(), + zome_index: 0.into(), + visibility: EntryVisibility::Private, + })) + .include_entries(true) + .descending(), + ); + + let status = match query { + Ok(records) => { + if records.len() == 0 { + None + } else { + let record = records[0].clone(); + let entry = record + .entry + .to_app_option::() + .unwrap() + .unwrap(); + Some((entry, record.action_address().to_owned())) + } + } + Err(e) => { + debug!( + "PerspectiveDiffSync.current_revision(): Error when getting current revision: {:?}", + e + ); + None + } + }; + + let online_status = OnlineAgentAndAction { + did: my_did, + status: status.clone().map(|status| status.0), + status_action: status.map(|status| status.1), + }; + Ok(online_status) +} + +pub fn create_did_pub_key_link(did: String) -> SocialContextResult<()> { + debug!("PerspectiveDiffSync.create_did_pub_key_link({:?})", did); + let agent_key = agent_info()?.agent_latest_pubkey; + debug!("PerspectiveDiffSync.create_did_pub_key_link() agent_key: {:?}", agent_key); + //let input = GetLinksInputBuilder::try_new(agent_key.clone(), LinkTypes::DidLink).unwrap().build(); + let did_links = get_links(agent_key.clone(), LinkTypes::DidLink, None)?; + debug!("PerspectiveDiffSync.create_did_pub_key_link() did_links: {:?}", did_links); + if did_links.len() == 0 { + + let entry = EntryTypes::Anchor(Anchor(did)); + let _did_entry = create_entry(&entry)?; + let did_entry_hash = hash_entry(entry)?; + create_link( + agent_key.clone(), + did_entry_hash.clone(), + LinkTypes::DidLink, + LinkTag::new("did_link"), + )?; + create_link( + did_entry_hash, + agent_key, + LinkTypes::DidLink, + LinkTag::new("did_link"), + )?; + } + Ok(()) +} + +pub fn get_my_did() -> SocialContextResult> { + // let input = GetLinksInputBuilder::try_new( + // agent_info()?.agent_latest_pubkey, + // LinkTypes::DidLink + // ) + // .unwrap() + // .build(); + let mut did_links = get_links(agent_info()?.agent_latest_pubkey, LinkTypes::DidLink, None)?; + if did_links.len() > 0 { + let did = get( + did_links + .remove(0) + .target + .into_entry_hash() + .expect("Could not get entry_hash"), + GetOptions::latest(), + )? + .ok_or(SocialContextError::InternalError( + "Could not find did entry for given did entry reference", + ))? + .entry() + .to_app_option::()? + .ok_or(SocialContextError::InternalError( + "Expected element to contain app entry data", + ))?; + Ok(Some(did.0)) + } else { + Ok(None) + } +} + +pub fn get_dids_agent_key(did: String) -> SocialContextResult> { + let did_entry = Anchor(did); + let did_entry_hash = hash_entry(EntryTypes::Anchor(did_entry.clone()))?; + // let input = GetLinksInputBuilder::try_new( + // did_entry_hash, + // LinkTypes::DidLink + // ) + // .unwrap() + // .build(); + let did_links = get_links(did_entry_hash, LinkTypes::DidLink, None)?; + debug!("PerspectiveDiffSync.get_dids_agent_key() did_links: {:?}", did_links); + if did_links.len() > 0 { + let entry: EntryHash = did_links[0].target.clone().try_into().unwrap(); + Ok(Some(AgentPubKey::from(entry))) + } else { + Ok(None) + } +} + +pub fn get_agents_did_key(agent: AgentPubKey) -> SocialContextResult> { + // let input = GetLinksInputBuilder::try_new( + // agent, + // LinkTypes::DidLink + // ) + // .unwrap() + // .build(); + let mut did_links = get_links(agent, LinkTypes::DidLink, None)?; + if did_links.len() > 0 { + let did = get( + did_links + .remove(0) + .target + .into_entry_hash() + .expect("Could not get entry_hash"), + GetOptions::latest(), + )? + .ok_or(SocialContextError::InternalError( + "Could not find did entry for given did entry reference", + ))? + .entry() + .to_app_option::()? + .ok_or(SocialContextError::InternalError( + "Expected element to contain app entry data", + ))?; + Ok(Some(did.0)) + } else { + Ok(None) + } +} + +pub fn get_others() -> SocialContextResult> { + let active_agents = get_active_agents()?; + let mut others = Vec::new(); + for active_agent in active_agents { + let did_key = get_agents_did_key(active_agent)?; + if did_key.is_some() { + others.push(did_key.unwrap()); + } + } + Ok(others) +} + +pub fn get_online_agents() -> SocialContextResult> { + let active_agents = get_active_agents()?; + let mut online_agents = Vec::new(); + for active_agent in active_agents { + let online_agent_status = get_agents_status(active_agent); + if online_agent_status.is_some() { + online_agents.push(online_agent_status.unwrap()); + } + } + Ok(online_agents) +} + +pub fn get_agents_status(agent: AgentPubKey) -> Option { + let online_agent_status = call_remote( + agent.clone(), + "perspective_diff_sync", + "get_online_status".into(), + None, + {}, + ); + if online_agent_status.is_ok() { + let online_agent_response = online_agent_status.unwrap(); + match online_agent_response { + ZomeCallResponse::Ok(online_agent) => { + let online_agent = online_agent + .decode::() + .expect("Could not decode online agent"); + Some(OnlineAgent { + did: online_agent.did, + status: online_agent.status, + }) + } + ZomeCallResponse::Unauthorized(..) => { + debug!("Unauthorized to call agent {}", agent.clone()); + None + } + ZomeCallResponse::NetworkError(..) => { + debug!("Agent {} is offline", agent.clone()); + None + } + ZomeCallResponse::CountersigningSession(_) => { + debug!("Agent {} had countersigning session error", agent); + None + } + } + } else { + None + } +} diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/utils.rs b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/utils.rs new file mode 100644 index 000000000..6f5ccf2c5 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync/src/utils.rs @@ -0,0 +1,46 @@ +use chrono::{DateTime, NaiveDateTime, Utc}; +use hdk::prelude::*; +use std::hash::Hash; + +use crate::errors::SocialContextResult; +use perspective_diff_sync_integrity::{ExpressionProof, LinkExpression, Triple}; + +pub fn get_now() -> SocialContextResult> { + match sys_time() { + Ok(time) => { + let now = time.as_seconds_and_nanos(); + Ok(DateTime::::from_utc( + NaiveDateTime::from_timestamp(now.0, now.1), + Utc, + )) + } + Err(_err) => Ok(Utc::now()), + } +} + +pub fn dedup(vs: &Vec) -> Vec { + let hs = vs.iter().cloned().collect::>(); + + hs.into_iter().collect() +} + +pub(crate) fn err(reason: &str) -> WasmError { + wasm_error!(WasmErrorInner::Host(String::from(reason))) +} + +#[allow(dead_code)] +pub fn create_link_expression(source: &str, target: &str) -> LinkExpression { + LinkExpression { + author: String::from("Test author"), + data: Triple { + source: Some(String::from(source)), + predicate: None, + target: Some(String::from(target)), + }, + timestamp: DateTime::::from_utc(NaiveDateTime::from_timestamp(0, 0), Utc), + proof: ExpressionProof { + signature: String::from("sig"), + key: String::from("key"), + }, + } +} diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync_integrity/Cargo.toml b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync_integrity/Cargo.toml new file mode 100644 index 000000000..c40215be7 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync_integrity/Cargo.toml @@ -0,0 +1,18 @@ +[package] +authors = ["josh@junto.foundation"] +edition = "2018" +name = "perspective_diff_sync_integrity" +version = "0.0.1" + +[lib] +crate-type = ["cdylib", "rlib"] +name = "perspective_diff_sync_integrity" + +[dependencies] +derive_more = "0" +serde = "1" +chrono = { version = "0.4.22", default-features = false, features = ["clock", "std", "oldtime", "serde"] } + +holo_hash = "0.2.2" +hdi = "0.3.2" +hdk = "0.2.2" \ No newline at end of file diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync_integrity/src/impls.rs b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync_integrity/src/impls.rs new file mode 100644 index 000000000..f6b11084e --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync_integrity/src/impls.rs @@ -0,0 +1,68 @@ +use std::cmp::Ordering; + +use hdk::prelude::*; + +use crate::{ + Anchor, HashBroadcast, OnlineAgent, PerspectiveDiff, PerspectiveDiffEntryReference, + PerspectiveExpression, +}; + +impl PerspectiveDiff { + pub fn get_sb(self) -> ExternResult { + self.try_into() + .map_err(|error| wasm_error!(WasmErrorInner::Host(String::from(error)))) + } +} + +impl Anchor { + pub fn get_sb(self) -> ExternResult { + self.try_into() + .map_err(|error| wasm_error!(WasmErrorInner::Host(String::from(error)))) + } +} + +impl PerspectiveExpression { + pub fn get_sb(self) -> ExternResult { + self.try_into() + .map_err(|error| wasm_error!(WasmErrorInner::Host(String::from(error)))) + } +} + +impl OnlineAgent { + pub fn get_sb(self) -> ExternResult { + self.try_into() + .map_err(|error| wasm_error!(WasmErrorInner::Host(String::from(error)))) + } +} + +impl HashBroadcast { + pub fn get_sb(self) -> ExternResult { + self.try_into() + .map_err(|error| wasm_error!(WasmErrorInner::Host(String::from(error)))) + } +} + +impl PerspectiveDiffEntryReference { + pub fn new( + diff: HoloHash, + parents: Option>>, + ) -> Self { + Self { + diff: diff, + parents: parents, + diffs_since_snapshot: 0, + } + } +} + +impl PartialOrd for PerspectiveDiffEntryReference { + fn partial_cmp(&self, other: &Self) -> Option { + self.diff.partial_cmp(&other.diff) + } +} + +impl Ord for PerspectiveDiffEntryReference { + fn cmp(&self, other: &Self) -> Ordering { + self.diff.cmp(&other.diff) + } +} diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync_integrity/src/lib.rs b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync_integrity/src/lib.rs new file mode 100644 index 000000000..f565e84cd --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/perspective_diff_sync_integrity/src/lib.rs @@ -0,0 +1,169 @@ +use chrono::{DateTime, Utc}; +use hdi::prelude::*; + +pub mod impls; + +#[derive( + Serialize, Deserialize, Clone, SerializedBytes, Debug, PartialEq, Eq, Hash, Ord, PartialOrd, +)] +pub struct ExpressionProof { + pub signature: String, + pub key: String, +} + +#[derive( + Serialize, Deserialize, Clone, SerializedBytes, Debug, PartialEq, Eq, Hash, Ord, PartialOrd, +)] +pub struct Triple { + pub source: Option, + pub target: Option, + pub predicate: Option, +} + +#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] +pub struct LinkExpression { + pub author: String, + pub data: Triple, + pub timestamp: DateTime, + pub proof: ExpressionProof, +} + +#[derive(Clone, Debug, Serialize, Deserialize, SerializedBytes, Default)] +pub struct PerspectiveDiff { + pub additions: Vec, + pub removals: Vec, +} + +///The reference that is sent to other agents, denotes the position in the DAG as well as the data at that position +#[derive(Clone, Debug, Serialize, Deserialize, SerializedBytes)] +pub struct HashBroadcast { + pub reference_hash: HoloHash, + pub reference: PerspectiveDiffEntryReference, + pub diff: PerspectiveDiff, + pub broadcast_author: String, +} + +impl PerspectiveDiff { + pub fn new() -> Self { + Self { + additions: Vec::new(), + removals: Vec::new(), + } + } + pub fn total_diff_number(&self) -> usize { + self.additions.len() + self.removals.len() + } +} + +app_entry!(PerspectiveDiff); + +#[derive(Clone, Debug, Serialize, Deserialize, SerializedBytes)] +pub struct Snapshot { + pub diff_chunks: Vec>, + pub included_diffs: Vec>, +} + +app_entry!(Snapshot); + +#[derive(Clone, Debug, Serialize, Deserialize, SerializedBytes, PartialEq, Eq, Hash)] +pub struct PerspectiveDiffEntryReference { + pub diff: HoloHash, + pub parents: Option>>, + pub diffs_since_snapshot: usize, +} + +app_entry!(PerspectiveDiffEntryReference); + +#[derive(Clone, Serialize, Deserialize, Debug)] +pub struct Perspective { + pub links: Vec, +} + +//TODO: this can likely be removed and instead just reference the PerspectiveDiffEntry/MergeEntry directly? +#[derive(Clone, Debug, Serialize, Deserialize, SerializedBytes)] +pub struct HashReference { + pub hash: HoloHash, + pub timestamp: DateTime, +} + +app_entry!(HashReference); + +#[derive(Clone, Debug, Serialize, Deserialize, SerializedBytes)] +pub struct LocalHashReference { + pub hash: HoloHash, + pub timestamp: DateTime, +} + +app_entry!(LocalHashReference); + +#[derive(Clone, Debug, Serialize, Deserialize, SerializedBytes)] +pub struct LocalTimestampReference { + pub timestamp_reference: DateTime, +} + +app_entry!(LocalTimestampReference); + +#[derive(Clone, Debug, Serialize, Deserialize, SerializedBytes)] +pub struct Anchor(pub String); + +app_entry!(Anchor); + +#[derive(Clone, Debug, Serialize, Deserialize, SerializedBytes)] +pub struct PerspectiveExpression { + pub author: String, + pub data: Perspective, + pub timestamp: DateTime, + pub proof: ExpressionProof, +} + +app_entry!(PerspectiveExpression); + +#[derive(Clone, Debug, Serialize, Deserialize, SerializedBytes)] +pub struct OnlineAgent { + pub did: String, + pub status: Option, +} + +#[derive(Clone, Debug, Serialize, Deserialize, SerializedBytes)] +pub struct OnlineAgentAndAction { + pub did: String, + pub status: Option, + pub status_action: Option, +} + +#[derive(Debug, Serialize, Deserialize, SerializedBytes)] +pub struct PullResult { + pub diff: PerspectiveDiff, + pub current_revision: Option>, +} + +#[hdk_entry_defs] +#[unit_enum(UnitEntryTypes)] +pub enum EntryTypes { + #[entry_def(visibility = "public")] + PerspectiveDiff(PerspectiveDiff), + #[entry_def(visibility = "public")] + Snapshot(Snapshot), + #[entry_def(visibility = "public")] + HashReference(HashReference), + #[entry_def(visibility = "public")] + PerspectiveDiffEntryReference(PerspectiveDiffEntryReference), + #[entry_def(visibility = "private")] + LocalHashReference(LocalHashReference), + #[entry_def(visibility = "private")] + LocalTimestampReference(LocalTimestampReference), + #[entry_def(visibility = "public")] + Anchor(Anchor), + #[entry_def(visibility = "private")] + PrivateOnlineStatus(PerspectiveExpression), +} + +#[hdk_link_types] +pub enum LinkTypes { + Snapshot, + ActiveAgent, + HashRef, + TimePath, + Index, + DidLink, +} diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/common.ts b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/common.ts new file mode 100644 index 000000000..d93421ff6 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/common.ts @@ -0,0 +1,6 @@ +import path from "path"; +import {Dna} from "@holochain/tryorama"; + +const dnas: Dna[] = [{ source: {path: path.join("../../workdir/perspective-diff-sync.dna")} }]; + +export { dnas }; \ No newline at end of file diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/download-hc-binaries.sh b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/download-hc-binaries.sh new file mode 100755 index 000000000..e78e813ec --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/download-hc-binaries.sh @@ -0,0 +1,14 @@ +#!/bin/bash +[ ! -d "./temp/binary" ] && mkdir -p "./temp/binary" + +if [ ! -f "./hc" ]; then + wget https://github.com/perspect3vism/ad4m/releases/download/binary-deps-0.1.0/hc-linux-0.1.0 + mv hc-linux-0.1.0 ./hc + chmod +x ./hc +fi + +if [ ! -f "./holochain" ]; then + wget https://github.com/perspect3vism/ad4m/releases/download/binary-deps-0.1.0/holochain-linux-0.1.0 + mv holochain-linux-0.1.0 ./holochain + chmod +x ./holochain +fi \ No newline at end of file diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/index.ts b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/index.ts new file mode 100644 index 000000000..1544f6e95 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/index.ts @@ -0,0 +1,49 @@ +import { render, renderMerges } from "./render"; +import { unSyncFetch, mergeFetch, mergeFetchDeep } from "./pull"; +import { testRevisionUpdates } from "./revisions"; +import { stressTest } from "./stress" +import { signals } from "./signals"; +import { testTelepresence } from "./telepresence"; + +import test from "tape-promise/tape.js"; + +test("unsynced fetch", async (t) => { + await unSyncFetch(t); +}) + +test("merge fetch", async (t) => { + await mergeFetch(t); +}) + +test("merge fetch deep", async (t) => { + await mergeFetchDeep(t); +}) + +//test("stress", async (t) => { +// await stressTest(t); +//}) + + +//test("complex merge", async (t) => { +// await complexMerge(t); +//}) + +test("test revision updates", async (t) => { + await testRevisionUpdates(t); +}) + +test("render", async (t) => { + await render(t) +}) + +test("render merges", async (t) => { + await renderMerges(t) +}) + +test("signals", async (t) => { + await signals(t) +}) + +test("telepresence", async (t) => { + await testTelepresence(t) +}) diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/package.json b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/package.json new file mode 100644 index 000000000..8c0170b0d --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/package.json @@ -0,0 +1,40 @@ +{ + "name": "perspective-diff-sync-tests", + "version": "0.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "PATH=$PATH:$(pwd) TRYORAMA_LOG_LEVEL=debug WASM_LOG=debug,wasmer_compiler_cranelift=error,holochain::conductor::manager=warn,holochain::core::workflow::publish_dht_ops_workflow::publish_query=warn,publish_dht_ops_workflow=error,kitsune_p2p_types::metrics=error,kitsune_p2p::gossip::sharded_gossip=error,wasm_trace=debug,app_validation_workflow=error RUST_BACKTRACE=1 node --loader ts-node/esm --experimental-specifier-resolution=node index.ts", + "build-test": "cd ../../ && CARGO_TARGET_DIR=target cargo build --release --target wasm32-unknown-unknown --features test && hc dna pack workdir && cd zomes/tests && npm test", + "build": "cd ../../ && CARGO_TARGET_DIR=target cargo build --release --target wasm32-unknown-unknown --features test && hc dna pack workdir && cd zomes/tests", + "build-ci": "cd ../../ && CARGO_TARGET_DIR=target cargo build --release --target wasm32-unknown-unknown --features test && ./zomes/tests/hc dna pack workdir && cd zomes/tests", + "test-pull": "PATH=$PATH:$(pwd) TRYORAMA_LOG_LEVEL=debug WASM_LOG=debug,wasmer_compiler_cranelift=error,holochain::conductor::manager=warn,holochain::core::workflow::publish_dht_ops_workflow::publish_query=warn,publish_dht_ops_workflow=error,kitsune_p2p_types::metrics=error,kitsune_p2p::gossip::sharded_gossip=error,wasm_trace=debug,app_validation_workflow=error RUST_BACKTRACE=1 node --loader ts-node/esm --experimental-specifier-resolution=node pull.ts", + "test-render": "PATH=$PATH:$(pwd) TRYORAMA_LOG_LEVEL=debug WASM_LOG=debug,wasmer_compiler_cranelift=error,holochain::conductor::manager=warn,holochain::core::workflow::publish_dht_ops_workflow::publish_query=warn,publish_dht_ops_workflow=error,kitsune_p2p_types::metrics=error,kitsune_p2p::gossip::sharded_gossip=error,wasm_trace=debug,app_validation_workflow=error RUST_BACKTRACE=1 node --loader ts-node/esm --experimental-specifier-resolution=node render.ts", + "test-revisions": "PATH=$PATH:$(pwd) TRYORAMA_LOG_LEVEL=debug WASM_LOG=debug,wasmer_compiler_cranelift=error,holochain::conductor::manager=warn,holochain::core::workflow::publish_dht_ops_workflow::publish_query=warn,publish_dht_ops_workflow=error,kitsune_p2p_types::metrics=error,kitsune_p2p::gossip::sharded_gossip=error,wasm_trace=debug,app_validation_workflow=error RUST_BACKTRACE=1 node --loader ts-node/esm --experimental-specifier-resolution=node revisions.ts", + "test-signals": "PATH=$PATH:$(pwd) TRYORAMA_LOG_LEVEL=debug WASM_LOG=debug,wasmer_compiler_cranelift=error,holochain::conductor::manager=warn,holochain::core::workflow::publish_dht_ops_workflow::publish_query=warn,publish_dht_ops_workflow=error,kitsune_p2p_types::metrics=error,kitsune_p2p::gossip::sharded_gossip=error,wasm_trace=debug,app_validation_workflow=error RUST_BACKTRACE=1 node --loader ts-node/esm --experimental-specifier-resolution=node signals.ts", + "test-stress": "PATH=$PATH:$(pwd) TRYORAMA_LOG_LEVEL=debug WASM_LOG=debug,wasmer_compiler_cranelift=error,holochain::conductor::manager=warn,holochain::core::workflow::publish_dht_ops_workflow::publish_query=warn,publish_dht_ops_workflow=error,kitsune_p2p_types::metrics=error,kitsune_p2p::gossip::sharded_gossip=error,wasm_trace=debug,app_validation_workflow=error RUST_BACKTRACE=1 node --loader ts-node/esm --experimental-specifier-resolution=node stress.ts", + "test-telepresence": "PATH=$PATH:$(pwd) TRYORAMA_LOG_LEVEL=debug WASM_LOG=debug,wasmer_compiler_cranelift=error,holochain::conductor::manager=warn,holochain::core::workflow::publish_dht_ops_workflow::publish_query=warn,publish_dht_ops_workflow=error,kitsune_p2p_types::metrics=error,kitsune_p2p::gossip::sharded_gossip=error,wasm_trace=debug,app_validation_workflow=error RUST_BACKTRACE=1 node --loader ts-node/esm --experimental-specifier-resolution=node telepresence.ts" + }, + "author": "", + "license": "ISC", + "dependencies": { + "@holochain/client": "0.16.1", + "@holochain/tryorama": "0.15.0", + "@perspect3vism/ad4m": "^0.2.12", + "@types/lodash": "^4.14.158", + "@types/node": "^18.0.0", + "blake2b": "^2.1.3", + "divide-bigint": "^1.0.4", + "faker": "5.5.3", + "lodash": "^4.17.19", + "tape-promise": "^4.0.0", + "ts-node": "^10.8.0", + "typescript": "^4.2.4" + }, + "devDependencies": { + "@types/faker": "^5.5.3", + "@types/tape-promise": "^4.0.1", + "tape": "^5.5.3" + }, + "type": "module" +} diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/pull.ts b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/pull.ts new file mode 100644 index 000000000..8db065701 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/pull.ts @@ -0,0 +1,273 @@ +import { addAllAgentsToAllConductors, cleanAllConductors } from "@holochain/tryorama"; +import { call, sleep, generate_link_expression, createConductors, create_link_expression} from "./utils"; +import test from "tape-promise/tape.js"; + +// //@ts-ignore +// export async function unSyncFetch(t) { +// let installs = await createConductors(2); +// let aliceHapps = installs[0].agent_happ; +// let conductor1 = installs[0].conductor; +// let bobHapps = installs[1].agent_happ; +// let conductor2 = installs[1].conductor; +// await addAllAgentsToAllConductors([conductor1, conductor2]); + +// //Create did/pub key link for alice and bob +// await aliceHapps.cells[0].callZome({ +// zome_name: "perspective_diff_sync", +// fn_name: "create_did_pub_key_link", +// payload: "did:test:alice" +// }); +// await bobHapps.cells[0].callZome({ +// zome_name: "perspective_diff_sync", +// fn_name: "create_did_pub_key_link", +// payload: "did:test:bob" +// }); + +// let commit = await aliceHapps.cells[0].callZome({ +// zome_name: "perspective_diff_sync", +// fn_name: "commit", +// payload: {additions: [generate_link_expression("alice")], removals: []} +// }); +// console.warn("\ncommit", commit); + +// // need to for gossip to have commit be seen by bob +// await sleep(5000) + +// const pull_bob = await bobHapps.cells[0].callZome({ +// zome_name: "perspective_diff_sync", +// fn_name: "pull", +// payload: { hash: commit, is_scribe: false } +// }); +// //@ts-ignore +// t.equal(pull_bob.diff.additions.length, 1); + +// await conductor1.shutDown(); +// await conductor2.shutDown(); +// await cleanAllConductors(); +// }; + +//@ts-ignore +export async function mergeFetchDeep(t) { + let installs = await createConductors(2); + let aliceHapps = installs[0].agent_happ; + let aliceConductor = installs[0].conductor; + let bobHapps = installs[1].agent_happ; + let bobConductor = installs[1].conductor; + + //Create new commit whilst bob is not connected + let create = await create_link_expression(aliceHapps.cells[0], "alice"); + let create2 = await create_link_expression(aliceHapps.cells[0], "alice"); + let create3 = await create_link_expression(aliceHapps.cells[0], "alice"); + await create_link_expression(aliceHapps.cells[0], "alice"); + await create_link_expression(aliceHapps.cells[0], "alice"); + await create_link_expression(aliceHapps.cells[0], "alice"); + await create_link_expression(aliceHapps.cells[0], "alice"); + + //Pull from bob and make sure he does not have the latest state + let pull_bob = await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "pull" + }); + //@ts-ignore + t.isEqual(pull_bob.diff.additions.length, 0); + + //Bob to commit his data, and update the latest revision, causing a fork + let bob_create = await create_link_expression(bobHapps.cells[0], "bob"); + let bob_create2 = await create_link_expression(bobHapps.cells[0], "bob"); + let bob_create3 = await create_link_expression(bobHapps.cells[0], "bob"); + let bob_create4 = await create_link_expression(bobHapps.cells[0], "bob"); + await create_link_expression(bobHapps.cells[0], "bob"); + await create_link_expression(bobHapps.cells[0], "bob"); + await create_link_expression(bobHapps.cells[0], "bob"); + + let pull_bob2 = await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "pull" + }); + //@ts-ignore + t.isEqual(pull_bob2.diff.additions.length, 0); + + //Connect nodes togther + await addAllAgentsToAllConductors([aliceConductor, bobConductor]); + //note; running this test on some machines may require more than 200ms wait + await sleep(500) + + //Alice tries to merge + let merge_alice = await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "pull" + }); + //@ts-ignore + t.isEqual(merge_alice.diff.additions.length, 7); + //@ts-ignore + t.isEqual(JSON.stringify(merge_alice.additions[0]), JSON.stringify(bob_create.data)); + + //note; running this test on some machines may require more than 200ms wait + await sleep(2000) + + let pull_bob3 = await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "pull" + }); + console.warn("bob pull3", pull_bob3); + //@ts-ignore + t.isEqual(pull_bob3.diff.additions.length, 7); + //@ts-ignore + console.log(pull_bob3.diff.additions[0].data); + //@ts-ignore + t.isEqual(JSON.stringify(pull_bob3.diff.additions[0]), JSON.stringify(create.data)); + //@ts-ignore + t.isEqual(JSON.stringify(pull_bob3.diff.additions[1]), JSON.stringify(create2.data)); + + //Shutdown alice conductor + await aliceConductor.shutDown(); + + //Have bob write three links + await create_link_expression(bobHapps.cells[0], "bob"); + await create_link_expression(bobHapps.cells[0], "bob"); + await create_link_expression(bobHapps.cells[0], "bob"); + + //shutdown bobs conductor + await bobConductor.shutDown(); + + //Have alice write three links + await aliceConductor.startUp(); + await create_link_expression(aliceHapps.cells[0], "alice"); + await create_link_expression(aliceHapps.cells[0], "alice"); + await create_link_expression(aliceHapps.cells[0], "alice"); + + //start bobs conductor and pull to see if merge happens correctly + await bobConductor.startUp(); + let pull_bob4 = await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "pull" + }); + console.warn("bob pull4", pull_bob4); + //@ts-ignore + t.isEqual(pull_bob4.diff.additions.length, 3); + //@ts-ignore + console.log(pull_bob4.diff.additions[0].data); + //@ts-ignore + t.isEqual(JSON.stringify(pull_bob4.additions[0]), JSON.stringify(create.data)); + //@ts-ignore + t.isEqual(JSON.stringify(pull_bob4.additions[1]), JSON.stringify(create2.data)); + + await cleanAllConductors(); +} + +//@ts-ignore +export async function mergeFetch(t) { + let installs = await createConductors(2); + let aliceHapps = installs[0].agent_happ; + let aliceConductor = installs[0].conductor; + let bobHapps = installs[1].agent_happ; + let bobConductor = installs[1].conductor; + + //Create did/pub key link for alice and bob + await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "create_did_pub_key_link", + payload: "did:test:alice" + }); + await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "create_did_pub_key_link", + payload: "did:test:bob" + }); + + //Create new commit whilst bob is not connected + let link_data = generate_link_expression("alice"); + console.log("Alice posting link data", link_data); + let commit = await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "commit", + payload: {additions: [link_data], removals: []} + }); + //@ts-ignore + console.warn("\ncommit", commit.toString("base64")); + + await sleep(1000) + + let bob_pull_failed = false + try{ + // Pull from bob who is not connected to alice yet + // to show that this will fail (because `commit` could not be found) + await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "pull", + payload: { hash: commit, is_scribe: false } + }); + } catch(e) { + bob_pull_failed = true + } + + t.assert(bob_pull_failed) + + + //Bob to commit his data, and update the latest revision, causing a fork + let bob_link_data = generate_link_expression("bob"); + console.log("Bob posting link data", bob_link_data); + let commit_bob = await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "commit", + payload: {additions: [bob_link_data], removals: []} + }); + //@ts-ignore + console.warn("\ncommit_bob", commit_bob.toString("base64")); + + //Connect nodes togther + await addAllAgentsToAllConductors([aliceConductor, bobConductor]); + //note; running this test on some machines may require more than 200ms wait + await sleep(1000) + + //Alice tries to merge + let merge_alice = await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "pull", + payload: { hash: commit_bob, is_scribe: true } + }); + //@ts-ignore + t.isEqual(merge_alice.diff.additions.length, 1); + //@ts-ignore + t.isEqual(JSON.stringify(merge_alice.diff.additions[0].data), JSON.stringify(bob_link_data.data)); + + const alice_merge_commit = await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "current_revision", + }); + + //note; running this test on some machines may require more than 200ms wait + await sleep(2000) + + let pull_bob3 = await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "pull", + payload: { hash: alice_merge_commit, is_scribe: false } + }); + console.warn("bob pull3", pull_bob3); + //@ts-ignore + t.isEqual(pull_bob3.diff.additions.length, 1); + //@ts-ignore + console.log(pull_bob3.diff.additions[0].data); + //@ts-ignore + t.isEqual(JSON.stringify(pull_bob3.diff.additions[0].data), JSON.stringify(link_data.data)); + + await aliceConductor.shutDown(); + await bobConductor.shutDown(); +} + + +test("pull", async (t) => { + //t.plan(20) + try { + //await unSyncFetch(t); + await mergeFetch(t); + } catch(e) { + console.error("Pull test failed with error", e); + //@ts-ignore + t.fail(e) + } finally { + t.end() + process.exit(0) + } +}) diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/queue.ts b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/queue.ts new file mode 100644 index 000000000..005dd13fe --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/queue.ts @@ -0,0 +1,82 @@ +class Queue { + #queue: T[]; + + constructor() { + this.#queue = []; + } + + enqueue(func: T) { + this.#queue.push(func); + } + + dequeue() { + return this.#queue.shift(); + } + + get size(): number { + return this.#queue.length; + } +} + +export class AsyncQueue { + #queue = new Queue<() => any>(); + #pendingCount = 0; + + private next() { + this.#pendingCount--; + this.startAnotherFunc(); + } + + private startAnotherFunc(): boolean { + if (this.#queue.size === 0) { + return false; + } + + if (this.#pendingCount === 0) { + const func = this.#queue.dequeue(); + + if (!func) { + return false; + } + + func(); + + return true; + } + + return false; + } + + async add(func: () => void) { + return new Promise((resolve, reject) => { + const job = async () => { + this.#pendingCount++; + + try { + const result = await func(); + resolve(result); + } catch(error) { + reject(error); + } + + this.next(); + } + + this.#queue.enqueue(job); + this.startAnotherFunc(); + }); + } + + async addAll(funcs: Array<() => void>) { + return Promise.all(funcs.map(async func => this.add(func))) + } + + get pendingCount(): number { + return this.#pendingCount; + } + + clear() { + this.#queue = new Queue<() => any>(); + this.#pendingCount = 0; + } +} \ No newline at end of file diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/render.ts b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/render.ts new file mode 100644 index 000000000..987309c93 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/render.ts @@ -0,0 +1,270 @@ +import { addAllAgentsToAllConductors, cleanAllConductors } from "@holochain/tryorama"; +import { call, sleep, generate_link_expression, createConductors} from "./utils"; +import test from "tape-promise/tape.js"; + +//NOTE; these tests are dependant on the SNAPSHOT_INTERVAL in lib.rs being set to 2 +//@ts-ignore +export async function render(t) { + let installs = await createConductors(2); + let aliceHapps = installs[0].agent_happ; + let conductor1 = installs[0].conductor; + let bobHapps = installs[1].agent_happ; + let conductor2 = installs[1].conductor; + await addAllAgentsToAllConductors([conductor1, conductor2]); + + //Create did/pub key link for alice and bob + await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "create_did_pub_key_link", + payload: "did:test:alice" + }); + await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "create_did_pub_key_link", + payload: "did:test:bob" + }); + + console.log("RENDER 1") + let commit = await call(aliceHapps, "commit", { + additions: [generate_link_expression("alice1")], + removals: [] + }); + console.warn("\ncommit", commit); + + await call(aliceHapps, "update_current_revision", commit); + + let commit2 = await call(aliceHapps, "commit", { + additions: [generate_link_expression("alice2")], + removals: [] + }); + console.warn("\ncommit", commit2); + + console.log("RENDER 2") + + await call(aliceHapps, "update_current_revision", commit2); + + let alice_rendered = await call(aliceHapps, "render"); + //@ts-ignore + t.equal(alice_rendered.links.length, 2) + + await sleep(5000); + + console.log("RENDER 3") + + // Bob hasn't pulled yet, so render on Bob should fail + let firstRenderFailed = false + try { + let bob_render = await call(bobHapps, "render"); + } catch(e) { + firstRenderFailed = true + } + + t.assert(firstRenderFailed) + + await call(bobHapps, "pull", { hash: commit2, is_scribe: false }) + + console.log("Bob has pulled") + + let bob_render = await call(bobHapps, "render"); + + + console.log("RENDER 4") + console.warn("bob rendered with", bob_render); + //@ts-ignore + t.deepEqual(bob_render.links.length, 2); + + await call(bobHapps, "update_current_revision", commit2); + + let commit4 = await call(bobHapps, "commit", { + additions: [generate_link_expression("bob3")], + removals: [] + }); + console.warn("\ncommit", commit4); + + await call(bobHapps, "update_current_revision", commit4); + + + let commit5 = await call(bobHapps, "commit", { + additions: [generate_link_expression("bob4")], + removals: [] + }); + console.warn("\ncommit", commit5); + + await call(bobHapps, "update_current_revision", commit5); + + await sleep(1000); + + console.log("RENDER 5") + await call(aliceHapps, "pull", { hash: commit5, is_scribe: true }); + let alice_render = await call(aliceHapps, "render"); + console.warn("Alice rendered with", alice_render); + //@ts-ignore + t.deepEqual(alice_render.links.length, 4); + + await conductor1.shutDown(); + await conductor2.shutDown(); + await cleanAllConductors(); +}; + +//@ts-ignore +export async function renderMerges(t) { + let installs = await createConductors(2); + let aliceHapps = installs[0].agent_happ; + let conductor1 = installs[0].conductor; + let bobHapps = installs[1].agent_happ; + let conductor2 = installs[1].conductor; + + //Create did/pub key link for alice and bob + await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "create_did_pub_key_link", + payload: "did:test:alice" + }); + await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "create_did_pub_key_link", + payload: "did:test:bob" + }); + + console.log("commit1"); + let commit = await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "commit", + payload: {additions: [generate_link_expression("alice1")], removals: []} + }); + console.warn("\ncommit", commit); + + await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "update_current_revision", + payload: commit + }); + + console.log("commit2"); + let commit2 = await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "commit", + payload: {additions: [generate_link_expression("alice2")], removals: []} + }); + console.warn("\ncommit", commit2); + + await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "update_current_revision", + payload: commit2 + }); + + console.log("commit3"); + let commit3 = await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "commit", + payload: {additions: [generate_link_expression("bob1")], removals: []} + }); + console.warn("\ncommit", commit3); + + await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "update_current_revision", + payload: commit3 + }); + + console.log("commit4"); + let commit4 = await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "commit", + payload: {additions: [generate_link_expression("bob2")], removals: []} + }); + console.warn("\ncommit", commit4); + + await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "update_current_revision", + payload: commit4 + }); + + console.log("bob render"); + let bob_render = await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "render" + }); + console.warn("bob rendered with", bob_render); + //@ts-ignore + t.isEqual(bob_render.links.length, 2); + + console.log("alice render"); + let alice_render = await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "render" + }); + console.warn("Alice rendered with", alice_render); + //@ts-ignore + t.isEqual(alice_render.links.length, 2); + + await addAllAgentsToAllConductors([conductor1, conductor2]); + await sleep(500); + + //Test getting revision, should return bob's revision since that is the latest entry + + //Alice commit which will create a merge and another entry + console.log("commit5"); + let commit5 = await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "commit", + payload: {additions: [generate_link_expression("alice3")], removals: []} + }); + console.warn("\ncommit5", commit5); + + await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "update_current_revision", + payload: commit5 + }); + + //Alice commit which should not create another snapshot + console.log("commit6"); + let commit6 = await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "commit", + payload: {additions: [generate_link_expression("alice4")], removals: []} + }); + console.warn("\ncommit6", commit6); + + await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "update_current_revision", + payload: commit6 + }); + await sleep(2000) + + console.log("bob pull"); + await call(bobHapps, "pull", { hash: commit6, is_scribe: true }) + + console.log("bob render"); + let bob_render2 = await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "render" + }); + console.warn("bob rendered with", bob_render2); + //@ts-ignore + t.isEqual(bob_render2.links.length, 6); + + console.log("alice render"); + let alice_render2 = await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "render" + }); + console.warn("Alice rendered with", alice_render2); + //@ts-ignore + t.isEqual(alice_render2.links.length, 4); + + await conductor1.shutDown(); + await conductor2.shutDown(); + await cleanAllConductors(); +} + +test("render", async (t) => { + await render(t) + await renderMerges(t) + t.end() + process.exit(0); +}) \ No newline at end of file diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/revisions.ts b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/revisions.ts new file mode 100644 index 000000000..75b274839 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/revisions.ts @@ -0,0 +1,92 @@ +import { addAllAgentsToAllConductors, cleanAllConductors } from "@holochain/tryorama"; +import { sleep, createConductors, create_link_expression } from "./utils"; +import test from "tape-promise/tape.js"; + +//@ts-ignore +export async function testRevisionUpdates(t) { + let installs = await createConductors(2); + let aliceHapps = installs[0].agent_happ; + let aliceConductor = installs[0].conductor; + let bobHapps = installs[1].agent_happ; + let bobConductor = installs[1].conductor; + + await addAllAgentsToAllConductors([aliceConductor, bobConductor]); + + //Create did/pub key link for alice and bob + await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "create_did_pub_key_link", + payload: "did:test:alice" + }); + await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "create_did_pub_key_link", + payload: "did:test:bob" + }); + + let current_revision = await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "current_revision" + }); + console.warn("current_revision", current_revision); + + let commit = await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "commit", + payload: {additions: [], removals: []} + }); + console.warn("\ncommit", commit); + + let current_revision2 = await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "current_revision" + }); + console.warn("current_revision2", current_revision2); + //@ts-ignore + t.isEqual(commit.toString(), current_revision2.toString()) + + await sleep(1000) + + //test bobs current revision is not updated + let bob_current_revision = await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "current_revision" + }); + console.warn("bob_current_revision", bob_current_revision); + //@ts-ignore + t.isEqual(null, bob_current_revision); + + let commit2 = await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "commit", + payload: {additions: [], removals: []} + }); + //@ts-ignore + console.warn("\ncommit2", commit2); + + let current_revision3 = await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "current_revision" + }); + console.warn("current_revision3", current_revision3); + //@ts-ignore + t.isEqual(current_revision3.toString(), commit2.toString()); + + let current_revision4 = await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "current_revision" + }); + console.warn("current_revision4", current_revision4); + //@ts-ignore + t.isEqual(commit2.toString(), current_revision4.toString()) + + await aliceConductor.shutDown(); + await bobConductor.shutDown(); + await cleanAllConductors(); +} + +test("test revision updates", async (t) => { + await testRevisionUpdates(t); + t.end() + process.exit(0) +}) \ No newline at end of file diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/signals.ts b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/signals.ts new file mode 100644 index 000000000..7bb262780 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/signals.ts @@ -0,0 +1,106 @@ +import { Scenario } from "@holochain/tryorama"; +import { sleep, generate_link_expression } from "./utils"; +import { dnas } from "./common"; +import test from "tape-promise/tape.js"; +import { resolve } from "path"; + +//@ts-ignore +export async function signals(t) { + const scenario = new Scenario(); + let aliceSignalCount = 0; + let bobSignalCount = 0; + + const aliceHapps = await scenario.addPlayerWithApp( + { + bundle: { + manifest: { + manifest_version: "1", + name: "perspective-diff-sync", + roles: [{ + name: "main", + dna: { + //@ts-ignore + path: resolve(dnas[0].source.path) + } + }] + }, + resources: {} + }, + } + ); + const portAlice = await aliceHapps.conductor.attachAppInterface(); + const appWs = await aliceHapps.conductor.connectAppWs(portAlice); + appWs.on("signal", (signal) => { + console.log("Alice Received Signal:",signal) + aliceSignalCount += 1; + }); + const bobHapps = await scenario.addPlayerWithApp( + { + bundle: { + manifest: { + manifest_version: "1", + name: "perspective-diff-sync", + roles: [{ + name: "main", + dna: { + //@ts-ignore + path: resolve(dnas[0].source.path) + } + }] + }, + resources: {} + } + } + ); + const portBob = await bobHapps.conductor.attachAppInterface(); + const appWsBob = await bobHapps.conductor.connectAppWs(portBob); + appWsBob.on("signal", (signal) => { + console.log("Bob Received Signal:",signal) + bobSignalCount += 1; + }) + + await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "create_did_pub_key_link", + payload: "did:test:alice" + }); + await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "create_did_pub_key_link", + payload: "did:test:bob" + }); + + + await scenario.shareAllAgents(); + + //Sleep to give time for bob active agent link to arrive at alice + await sleep(2000) + + //Test case where subject object and predicate are given + let bob_link_data = generate_link_expression("bob"); + await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "commit", + payload: {additions: [bob_link_data], removals: []} + }); + + //Test case where subject object and predicate are given + let link_data = generate_link_expression("alice"); + await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "commit", + payload: {additions: [link_data], removals: []} + }); + //Sleep to give time for signals to arrive + await sleep(1000) + + t.deepEqual(bobSignalCount, 1); + + await scenario.cleanUp(); +} + +test("signals", async (t) => { + await signals(t) + t.end() + process.exit(0) +}) \ No newline at end of file diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/stress.ts b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/stress.ts new file mode 100644 index 000000000..31765bcc0 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/stress.ts @@ -0,0 +1,355 @@ +import { AgentApp, addAllAgentsToAllConductors, cleanAllConductors, Conductor, Scenario } from "@holochain/tryorama"; +import { call, sleep, createConductors, create_link_expression, generate_link_expression} from "./utils"; +import ad4m, { DID, HolochainLanguageDelegate, LinkExpression, Perspective } from "@perspect3vism/ad4m" +import test from "tape-promise/tape.js"; +import { hrtime } from 'node:process'; +//@ts-ignore +import divide from 'divide-bigint' +import { AsyncQueue } from "./queue"; +import { resolve } from "path"; +import { dnas } from "./common"; +let createdLinks = new Map>() + +class PeerInfo { + currentRevision: Buffer | null = null; + lastSeen: Date = new Date(); +}; + +let aliceRevision: Buffer | null = null; +let bobRevision: Buffer | null = null; +let aliceDid = ""; +let bobDid = ""; + +async function createLinks(happ: AgentApp, agentName: string, count: number, queue?: AsyncQueue) { + if(!createdLinks.get(agentName)) createdLinks.set(agentName, []) + for(let i=0; i < count; i++) { + if (queue) { + await queue.add(async () => { + let { commitRaw, data } = await create_link_expression(happ.cells[0], agentName); + if (agentName === "alice") { + aliceRevision = commitRaw; + } else if (agentName === "bob") { + bobRevision = commitRaw; + } + createdLinks.get(agentName)!.push(data) + }).catch((e) => { + console.log("Error in create links queue", e); + }) + } else { + let { data } = await create_link_expression(happ.cells[0], agentName); + createdLinks.get(agentName)!.push(data) + } + } +} + +//@ts-ignore +export async function latestRevisionStress(t) { + let installs = await createConductors(2); + let aliceHapps = installs[0].agent_happ; + let aliceConductor = installs[0].conductor; + let bobHapps = installs[1].agent_happ; + let bobConductor = installs[1].conductor; + + await addAllAgentsToAllConductors([aliceConductor, bobConductor]); + + let link_data = generate_link_expression("alice"); + let commit = await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "commit", + payload: {additions: [link_data], removals: []} + }); + + for (let i = 0; i < 1000; i++) { + console.log("Latest update revision", i); + let now = performance.now(); + let create = await aliceHapps.cells[0].callZome({zome_name: "perspective_diff_sync", fn_name: "update_latest_revision", payload: commit}); + let after = performance.now(); + console.log(" Create execution took: ", after - now); + let fetch = await aliceHapps.cells[0].callZome({zome_name: "perspective_diff_sync", fn_name: "latest_revision"}); + let after2 = performance.now(); + console.log("Fetch execution took: ", after2 - after); + } +} + +async function gossip(peers: Map, me: DID, hcDna: HolochainLanguageDelegate) { + console.log("GOSSIP for ", me) + //@ts-ignore + await hcDna.call("DNA_NICK", "ZOME_NAME", "sync", null); + let lostPeers: DID[] = []; + + peers.forEach( (peerInfo, peer) => { + if (peerInfo.lastSeen.getTime() + 10000 < new Date().getTime()) { + lostPeers.push(peer); + } + }); + + for (const peer of lostPeers) { + peers.delete(peer); + } + + // flatten the map into an array of peers + let allPeers = Array.from(peers.keys()) + allPeers.push(me); + // Lexically sort the peers + allPeers.sort(); + + // If we are the first peer, we are the scribe + let is_scribe = (allPeers[0] == me); + + console.log("IS SCRIBE", is_scribe, me) + + // Get a deduped set of all peer's current revisions + let revisions = new Set(); + for(const peerInfo of peers.values()) { + if (peerInfo.currentRevision) revisions.add(peerInfo.currentRevision); + } + + console.log(` + ====== + GOSSIP + -- + me: ${me} + is scribe: ${is_scribe} + -- + ${Array.from(peers.entries()).map( ([peer, peerInfo]) => { + //@ts-ignore + return `${peer}: ${peerInfo.currentRevision.toString('base64')} ${peerInfo.lastSeen.toISOString()}\n` + })} + -- + revisions: ${Array.from(revisions).map( (hash) => { + //@ts-ignore + return hash.toString('base64') + })} + `); + + revisions.forEach( async (hash) => { + console.log("PULLING", hash, is_scribe, aliceRevision, bobRevision) + if(!hash) return + if (me === aliceDid) { + if (hash === aliceRevision) { + console.log("Alice skipping pull since we already sync'd on this gossip loop"); + return + } + } + if (me === bobDid) { + if (hash === bobRevision) { + console.log("Bob skipping pull since we already sync'd on this gossip loop"); + return + } + } + let pullResult = await hcDna.call("DNA_NICK", "ZOME_NAME", "pull", { + hash, + is_scribe + }); + if (pullResult) { + let myRevision = pullResult.current_revision; + if (me === aliceDid) aliceRevision = myRevision; + if (me === bobDid) bobRevision = myRevision; + } + }) + } + +//@ts-ignore +export async function stressTest(t) { + const aliceQueue = new AsyncQueue(); + const bobQueue = new AsyncQueue(); + + const scenario = new Scenario(); + const aliceHapps = await scenario.addPlayerWithApp( + { + bundle: { + manifest: { + manifest_version: "1", + name: "perspective-diff-sync", + roles: [{ + name: "main", + dna: { + //@ts-ignore + path: resolve(dnas[0].source.path) + } + }] + }, + resources: {} + }, + } + ); + const alicePeersList: Map = new Map(); + const portAlice = await aliceHapps.conductor.attachAppInterface(); + const appWs = await aliceHapps.conductor.connectAppWs(portAlice); + appWs.on("signal", (signal) => { + //console.log("Alice Received Signal:",signal); + const { diff, reference_hash, reference, broadcast_author } = signal.payload; + if (diff && reference_hash && reference && broadcast_author) { + console.log(`PerspectiveDiffSync.handleHolochainSignal: + diff: ${JSON.stringify(diff)} + reference_hash: ${reference_hash.toString('base64')} + reference: { + diff: ${reference.diff?.toString('base64')} + parents: ${reference.parents ? reference.parents.map( (parent: Buffer) => parent ? parent.toString('base64') : 'null').join(', '):'none'} + diffs_since_snapshot: ${reference?.diffs_since_snapshot} + } + broadcast_author: ${broadcast_author} + `) + alicePeersList.set(broadcast_author, { currentRevision: reference_hash, lastSeen: new Date() }); + } else { + console.log("PerspectiveDiffSync.handleHolochainSignal: got other signal:", signal.payload) + } + }); + const bobHapps = await scenario.addPlayerWithApp( + { + bundle: { + manifest: { + manifest_version: "1", + name: "perspective-diff-sync", + roles: [{ + name: "main", + dna: { + //@ts-ignore + path: resolve(dnas[0].source.path) + } + }] + }, + resources: {} + } + } + ); + const bobPeersList: Map = new Map(); + const portBob = await bobHapps.conductor.attachAppInterface(); + const appWsBob = await bobHapps.conductor.connectAppWs(portBob); + appWsBob.on("signal", (signal) => { + console.log("Bob Received Signal:",signal) + const { diff, reference_hash, reference, broadcast_author } = signal.payload; + if (diff && reference_hash && reference && broadcast_author) { + bobPeersList.set(broadcast_author, { currentRevision: reference_hash, lastSeen: new Date() }); + } + }) + + //Create did/pub key link for alice and bob + await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "create_did_pub_key_link", + payload: "did:test:alice" + }); + aliceDid = "did:test:alice"; + await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "create_did_pub_key_link", + payload: "did:test:bob" + }); + bobDid = "did:test:bob"; + + let done = false; + async function processGossip() { + await Promise.all([gossip(alicePeersList, "did:test:alice", { + call: async (nick, zome, fn_name, payload) => { + await aliceQueue.add( async () => { + try{ + await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name, + payload + }) + } catch(e) { + console.log("ERROR during alice zome call", e) + } + + }) + } + } as HolochainLanguageDelegate), + gossip(bobPeersList, "did:test:bob", { + call: async (nick, zome, fn_name, payload) => { + await bobQueue.add( async () => { + try { + await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name, + payload + }) + } catch(e) { + console.log("ERROR during bob zome call", e) + } + + }) + } + } as HolochainLanguageDelegate)]) + await sleep(1000) + if(!done) { + processGossip() + } + + } + + processGossip() + + let aliceConductor = aliceHapps.conductor + let bobConductor = bobHapps.conductor; + let hash = Buffer.from((await aliceConductor.adminWs().listDnas())[0]); + + await addAllAgentsToAllConductors([aliceConductor, bobConductor]); + + console.log("==============================================") + console.log("=================START========================") + console.log("==============================================") + for(let i=0; i < 10; i++) { + console.log("-------------------------"); + console.log("Iteration: ", i) + console.log("-------------------------"); + const start = hrtime.bigint(); + await Promise.all([ + createLinks(aliceHapps, "alice", 20, aliceQueue), + createLinks(bobHapps, "bob", 20, bobQueue) + ]) + const end = hrtime.bigint(); + console.log(`Creating links took ${divide(end - start, 1000000)} ms`); + + console.log("-------------------------"); + console.log("Created 20 links each (Alice and Bob)"); + console.log("waiting a second"); + console.log("-------------------------"); + + await sleep(1000) + + console.log("-------------------------"); + console.log("All good :)))))))))))))))"); + console.log("-------------------------"); + + } + + // Wait for gossip of latest_revision, needed for render + await sleep(15000) + + done = true; + aliceQueue.clear(); + bobQueue.clear() + + const startRenderA = hrtime.bigint(); + let alice_rendered = await call(aliceHapps, "render") as Perspective + const endRenderA = hrtime.bigint(); + console.log(`Alice render took ${divide(endRenderA - startRenderA, 1000000)} ms`); + + const startRenderB = hrtime.bigint(); + let bob_rendered = await call(bobHapps, "render") as Perspective + const endRenderB = hrtime.bigint(); + console.log(`Bob render took ${divide(endRenderB - startRenderB, 1000000)} ms`); + + t.isEqual(alice_rendered.links.length, bob_rendered.links.length) + + function includes(perspective: Perspective, link: LinkExpression) { + return perspective.links.find(l => ad4m.linkEqual(l,link)) + } + + for(let link of createdLinks.get("alice")!) { + t.assert(includes(alice_rendered, link)) + t.assert(includes(bob_rendered, link)) + } + + await aliceConductor.shutDown(); + await bobConductor.shutDown(); + await cleanAllConductors(); +} + +test("stress", async (t) => { + await stressTest(t); + t.end() + process.exit(0) +}) diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/telepresence.ts b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/telepresence.ts new file mode 100644 index 000000000..72391d3a0 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/telepresence.ts @@ -0,0 +1,172 @@ +import { addAllAgentsToAllConductors, Scenario } from "@holochain/tryorama"; +import { sleep, generate_link_expression, sortedObject } from "./utils"; +import test from "tape-promise/tape.js"; +import { resolve } from "path"; +import { dnas } from "./common"; +import { PerspectiveExpression } from "@perspect3vism/ad4m"; + +function generate_perspective_expression(author: string, linkContent: string): PerspectiveExpression { + return { + author: author, + timestamp: new Date().toISOString(), + data: { + links: [generate_link_expression(linkContent)] + }, + proof: {signature: "sig", key: "key"}, + }; +} +//@ts-ignore +export async function testTelepresence(t) { + const scenario = new Scenario(); + let aliceSignalCount = 0; + let bobSignalCount = 0; + + const aliceHapps = await scenario.addPlayerWithApp( + { + bundle: { + manifest: { + manifest_version: "1", + name: "perspective-diff-sync", + roles: [{ + name: "main", + dna: { + //@ts-ignore + path: resolve(dnas[0].source.path) + } + }] + }, + resources: {} + }, + } + ); + const portAlice = await aliceHapps.conductor.attachAppInterface(); + const appWs = await aliceHapps.conductor.connectAppWs(portAlice); + appWs.on("signal", (signal) => { + console.log("Alice Received Signal:",signal) + aliceSignalCount += 1; + }); + const bobHapps = await scenario.addPlayerWithApp( + { + bundle: { + manifest: { + manifest_version: "1", + name: "perspective-diff-sync", + roles: [{ + name: "main", + dna: { + //@ts-ignore + path: resolve(dnas[0].source.path) + } + }] + }, + resources: {} + } + } + ); + const portBob = await bobHapps.conductor.attachAppInterface(); + const appWsBob = await bobHapps.conductor.connectAppWs(portBob); + appWsBob.on("signal", (signal) => { + console.log("Bob Received Signal:",signal) + bobSignalCount += 1; + }) + + await scenario.shareAllAgents(); + await addAllAgentsToAllConductors([aliceHapps.conductor, bobHapps.conductor]); + + const bobDid = "did:key:bob"; + const aliceDid = "did:key:alice"; + + //Create did/pub key link for alice and bob + await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "create_did_pub_key_link", + payload: aliceDid + }); + await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "create_did_pub_key_link", + payload: bobDid + }); + console.log("Set did pub key links"); + + //Sleep to give time for gossip + await sleep(2000) + + //Test setting and getting agent status + let perspectiveExpression = generate_perspective_expression(aliceDid, "alice"); + await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "set_online_status", + payload: perspectiveExpression + }); + console.log("Set online status"); + + let bobSeenStatus = await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "get_online_agents", + }); + //@ts-ignore + t.isEqual(bobSeenStatus.length, 1); + //@ts-ignore + t.equal(JSON.stringify(sortedObject(bobSeenStatus[0].status)), JSON.stringify(sortedObject(perspectiveExpression))); + //@ts-ignore + t.equal(JSON.stringify(sortedObject(bobSeenStatus[0].status.data.links[0])), JSON.stringify(sortedObject(perspectiveExpression.data.links[0]))); + + //Test that if alice updates her online status that bob sees the update, and does not get duplicates + perspectiveExpression = generate_perspective_expression(aliceDid, "alice2"); + + await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "set_online_status", + payload: perspectiveExpression + }); + bobSeenStatus = await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "get_online_agents", + }); + //@ts-ignore + t.isEqual(bobSeenStatus.length, 1); + //@ts-ignore + t.equal(JSON.stringify(sortedObject(bobSeenStatus[0].status)), JSON.stringify(sortedObject(perspectiveExpression))); + //@ts-ignore + t.equal(JSON.stringify(sortedObject(bobSeenStatus[0].status.data.links[0])), JSON.stringify(sortedObject(perspectiveExpression.data.links[0]))); + + //Test sending signal to single agent + await aliceHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "send_signal", + payload: {remote_agent_did: "did:key:bob", payload: perspectiveExpression} + }); + //Sleep to give time for signals to arrive + await sleep(1000) + //@ts-ignore + t.isEqual(bobSignalCount, 1); + + + //Test sending broadcast + await bobHapps.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name: "send_broadcast", + payload: perspectiveExpression + }); + //Sleep to give time for signals to arrive + await sleep(1000) + //@ts-ignore + t.isEqual(aliceSignalCount, 1); + + await scenario.cleanUp(); +}; + +test("telepresence", async (t) => { + //t.plan(20) + try { + await testTelepresence(t); + } catch(e) { + console.error("telepresence test failed with error", e); + //@ts-ignore + t.fail(e) + } finally { + t.end() + process.exit(0) + } +}) diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/tsconfig.json b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/tsconfig.json new file mode 100644 index 000000000..0a629b1e4 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "module": "ESNext", + "target": "ESNext", + "moduleResolution": "Node", + "sourceMap": true, + "declaration": true, + "forceConsistentCasingInFileNames": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "strict": true + }, + "include": [ + "ts/**/*" + ] +} \ No newline at end of file diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/utils.ts b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/utils.ts new file mode 100644 index 000000000..54744eb99 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/utils.ts @@ -0,0 +1,86 @@ +import { AgentApp, CallableCell, Conductor, NetworkType, enableAndGetAgentApp, runLocalServices } from "@holochain/tryorama"; +import faker from "faker"; +import { dnas } from './common'; +import { createConductor } from "@holochain/tryorama"; +import { resolve } from "path"; + +export async function call(happ: AgentApp, fn_name: string, payload?: any) { + return await happ.cells[0].callZome({ + zome_name: "perspective_diff_sync", + fn_name, + payload + }, 60000); +} + +export function generate_link_expression(agent: string) { + return { + data: {source: faker.name.findName(), target: faker.name.findName(), predicate: faker.name.findName()}, + author: agent, + timestamp: new Date().toISOString(), + proof: {signature: "sig", key: "key"}, + } +} + +export async function create_link_expression(cell: CallableCell, agent: string): Promise<{commit: string, data: any, commitRaw: Buffer}> { + let link_data = generate_link_expression(agent); + let commit = await cell.callZome({ + zome_name: "perspective_diff_sync", + fn_name: "commit", + payload: {additions: [link_data], removals: []} + }, 60000); + //@ts-ignore + return {commit: commit.toString("base64"), data: link_data, commitRaw: commit} +} + +export function sleep(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +export async function createConductors(num: number): Promise<{agent_happ: AgentApp, conductor: Conductor}[]> { + let out = [] as {agent_happ: AgentApp, conductor: Conductor}[]; + + const localServices = await runLocalServices(); + + for (let n of Array(num).keys()) { + let conductor = await createConductor(localServices.signalingServerUrl, {networkType: NetworkType.WebRtc, bootstrapServerUrl: localServices.bootstrapServerUrl}); + let port = await conductor.attachAppInterface(); + let appWs = await conductor.connectAppWs(port); + try { + let app = await conductor.installApp({ + bundle: { + manifest: { + manifest_version: "1", + name: "perspective-diff-sync", + roles: [{ + name: "main", + dna: { + //@ts-ignore + path: resolve(dnas[0].source.path) + } + }] + }, + resources: {} + } + }); + const agentApp = await enableAndGetAgentApp(conductor.adminWs(), appWs, app); + out.push({ + agent_happ: agentApp, + conductor + }) + } catch (e) { + console.error(e); + } + } + return out +} + +//@ts-ignore +export function sortedObject(unordered) { + if(typeof unordered !== "object") return unordered; + return Object.keys(unordered).sort().reduce( + (obj, key) => { + //@ts-ignore + obj[key] = sortedObject(unordered[key]); + return obj; + }, {}); +} \ No newline at end of file diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/yarn.lock b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/yarn.lock new file mode 100644 index 000000000..00d1b3687 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/hc-dna/zomes/tests/yarn.lock @@ -0,0 +1,1833 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@apollo/client@3.6.9": + version "3.6.9" + resolved "https://registry.npmjs.org/@apollo/client/-/client-3.6.9.tgz" + integrity sha512-Y1yu8qa2YeaCUBVuw08x8NHenFi0sw2I3KCu7Kw9mDSu86HmmtHJkCAifKVrN2iPgDTW/BbP3EpSV8/EQCcxZA== + dependencies: + "@graphql-typed-document-node/core" "^3.1.1" + "@wry/context" "^0.6.0" + "@wry/equality" "^0.5.0" + "@wry/trie" "^0.3.0" + graphql-tag "^2.12.6" + hoist-non-react-statics "^3.3.2" + optimism "^0.16.1" + prop-types "^15.7.2" + symbol-observable "^4.0.0" + ts-invariant "^0.10.3" + tslib "^2.3.0" + zen-observable-ts "^1.2.5" + +"@colors/colors@1.5.0": + version "1.5.0" + resolved "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz" + integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== + +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + +"@dabh/diagnostics@^2.0.2": + version "2.0.3" + resolved "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz" + integrity sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA== + dependencies: + colorspace "1.1.x" + enabled "2.0.x" + kuler "^2.0.0" + +"@graphql-typed-document-node/core@^3.1.1": + version "3.1.1" + resolved "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.1.tgz" + integrity sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg== + +"@holochain/client@0.12.0": + version "0.12.0" + resolved "https://registry.npmjs.org/@holochain/client/-/client-0.12.0.tgz" + integrity sha512-pvrB6Gdc6488iR3VZXoq5QKzoAPTGi0y69Ktrtgr/IZEvtSSHBqHeMhyEjXCa7iS8b1gXsL/HAvq47rs8mu50A== + dependencies: + "@holochain/serialization" "^0.1.0-beta-rc.3" + "@msgpack/msgpack" "^2.7.2" + "@tauri-apps/api" "^1.2.0" + emittery "^1.0.1" + isomorphic-ws "^5.0.0" + js-base64 "^3.7.3" + lodash-es "^4.17.21" + tweetnacl "^1.0.3" + +"@holochain/client@0.16.1", "@holochain/client@^0.16.0": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@holochain/client/-/client-0.16.1.tgz#3cdb110a5d4ab9bf51f31def289f0d082baa77ba" + integrity sha512-jfbrSZz3Yqr/hb3NwzfLSWpR6Cnt82hiHUZP5R1MrGpFQV8JVI2uq94CMVasBspNsWX3lMpT9LNz5Duvq7zF8Q== + dependencies: + "@holochain/serialization" "^0.1.0-beta-rc.3" + "@msgpack/msgpack" "^2.7.2" + "@noble/ed25519" "^2.0.0" + "@tauri-apps/api" "^1.2.0" + emittery "^1.0.1" + isomorphic-ws "^5.0.0" + js-base64 "^3.7.3" + libsodium-wrappers "^0.7.11" + lodash-es "^4.17.21" + ws "^8.13.0" + +"@holochain/serialization@^0.1.0-beta-rc.3": + version "0.1.0-beta-rc.3" + resolved "https://registry.npmjs.org/@holochain/serialization/-/serialization-0.1.0-beta-rc.3.tgz" + integrity sha512-DJx4V2KXHVLciyOGjOYKTM/JLBpBEZ3RsPIRCgf7qmwhQdxXvhi2p+oFFRD51yUT5uC1/MzIVeJCl/R60PwFbw== + +"@holochain/tryorama@0.15.0": + version "0.15.0" + resolved "https://registry.yarnpkg.com/@holochain/tryorama/-/tryorama-0.15.0.tgz#726dbd33159edf8866de7aa5cf6afdb2230aec74" + integrity sha512-GWsiheb6AFkPkT1ho+dJeFRB2jVboIm/Gp+7v1LshKbDZrgY7oDEopyQPWmy4SkQQYItuscGaIdaOUJIQJuGKQ== + dependencies: + "@holochain/client" "^0.16.0" + get-port "^6.1.2" + lodash "^4.17.21" + uuid "^8.3.2" + winston "^3.8.2" + ws "^8.11.0" + +"@jest/types@^26.6.2": + version "26.6.2" + resolved "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz" + integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^15.0.0" + chalk "^4.0.0" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.0" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.14" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@msgpack/msgpack@^2.7.2": + version "2.7.2" + resolved "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-2.7.2.tgz" + integrity sha512-rYEi46+gIzufyYUAoHDnRzkWGxajpD9vVXFQ3g1vbjrBm6P7MBmm+s/fqPa46sxa+8FOUdEuRQKaugo5a4JWpw== + +"@noble/ed25519@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@noble/ed25519/-/ed25519-2.0.0.tgz#5964c8190a4b4b804985717ca566113b93379e43" + integrity sha512-/extjhkwFupyopDrt80OMWKdLgP429qLZj+z6sYJz90rF2Iz0gjZh2ArMKPImUl13Kx+0EXI2hN9T/KJV0/Zng== + +"@perspect3vism/ad4m@^0.2.12": + version "0.2.15" + resolved "https://registry.npmjs.org/@perspect3vism/ad4m/-/ad4m-0.2.15.tgz" + integrity sha512-hIJV5j064SQyxJXiMoHzZGQ5QowA+bxDuXsWGcfAXBN6EpxpFSoqvRuYqGR7VjENg5CV9hL9gjOVUYdhFdRt4Q== + dependencies: + "@apollo/client" "3.6.9" + "@holochain/client" "0.12.0" + "@types/jest" "^26.0.14" + class-validator "^0.13.1" + express "^4.18.1" + graphql "^15.7.2" + reflect-metadata "^0.1.13" + type-graphql "^1.1.1" + +"@tauri-apps/api@^1.2.0": + version "1.2.0" + resolved "https://registry.npmjs.org/@tauri-apps/api/-/api-1.2.0.tgz" + integrity sha512-lsI54KI6HGf7VImuf/T9pnoejfgkNoXveP14pVV7XarrQ46rOejIVJLFqHI9sRReJMGdh2YuCoI3cc/yCWCsrw== + +"@tsconfig/node10@^1.0.7": + version "1.0.9" + resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz" + integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.3" + resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz" + integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== + +"@types/faker@^5.5.3": + version "5.5.9" + resolved "https://registry.npmjs.org/@types/faker/-/faker-5.5.9.tgz" + integrity sha512-uCx6mP3UY5SIO14XlspxsGjgaemrxpssJI0Ol+GfhxtcKpv9pgRZYsS4eeKeHVLje6Qtc8lGszuBI461+gVZBA== + +"@types/glob@^7.1.3": + version "7.2.0" + resolved "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz" + integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== + dependencies: + "@types/minimatch" "*" + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": + version "2.0.4" + resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz" + integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^26.0.14": + version "26.0.24" + resolved "https://registry.npmjs.org/@types/jest/-/jest-26.0.24.tgz" + integrity sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w== + dependencies: + jest-diff "^26.0.0" + pretty-format "^26.0.0" + +"@types/lodash@^4.14.158": + version "4.14.182" + resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz" + integrity sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q== + +"@types/minimatch@*": + version "3.0.5" + resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz" + integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== + +"@types/node@*": + version "14.18.22" + resolved "https://registry.npmjs.org/@types/node/-/node-14.18.22.tgz" + integrity sha512-qzaYbXVzin6EPjghf/hTdIbnVW1ErMx8rPzwRNJhlbyJhu2SyqlvjGOY/tbUt6VFyzg56lROcOeSQRInpt63Yw== + +"@types/node@^14.11.2": + version "14.18.61" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.61.tgz#752097010d85f6279b3069811bf0e99eba996096" + integrity sha512-1mFT4DqS4/s9tlZbdkwEB/EnSykA9MDeDLIk3FHApGvIMGY//qgstB2gu9GKGESWyW/qiRUO+jhlLJ9bBJ8j+Q== + +"@types/node@^18.0.0": + version "18.17.17" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.17.17.tgz#53cc07ce582c9d7c5850702a3c2cb0af0d7b0ca1" + integrity sha512-cOxcXsQ2sxiwkykdJqvyFS+MLQPLvIdwh5l6gNg8qF6s+C7XSkEWOZjK+XhUZd+mYvHV/180g2cnCcIl4l06Pw== + +"@types/semver@^7.3.3": + version "7.3.12" + resolved "https://registry.npmjs.org/@types/semver/-/semver-7.3.12.tgz" + integrity sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A== + +"@types/tape-promise@^4.0.1": + version "4.0.1" + resolved "https://registry.npmjs.org/@types/tape-promise/-/tape-promise-4.0.1.tgz" + integrity sha512-1yBeq9y0EmJ2RpxfXMPrFeD3yMetBapY9zArTexp/wCRdBToJac/y//rtcZZjmiArgodTqz0RrK0VxxySoKyVg== + dependencies: + "@types/tape" "*" + +"@types/tape@*": + version "4.13.2" + resolved "https://registry.npmjs.org/@types/tape/-/tape-4.13.2.tgz" + integrity sha512-V1ez/RtYRGN9cNYApw5xf27DpMkTB0033X6a2i3KUmKhSojBfbWN0i3EgZxboUG96WJLHLdOyZ01aiZwVW5aSA== + dependencies: + "@types/node" "*" + +"@types/triple-beam@^1.3.2": + version "1.3.2" + resolved "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.2.tgz" + integrity sha512-txGIh+0eDFzKGC25zORnswy+br1Ha7hj5cMVwKIU7+s0U2AxxJru/jZSMU6OC9MJWP6+pc/hc6ZjyZShpsyY2g== + +"@types/yargs-parser@*": + version "21.0.0" + resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz" + integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== + +"@types/yargs@^15.0.0": + version "15.0.15" + resolved "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.15.tgz" + integrity sha512-IziEYMU9XoVj8hWg7k+UJrXALkGFjWJhn5QFEv9q4p+v40oZhSuC135M38st8XPjICL7Ey4TV64ferBGUoJhBg== + dependencies: + "@types/yargs-parser" "*" + +"@wry/context@^0.6.0": + version "0.6.1" + resolved "https://registry.npmjs.org/@wry/context/-/context-0.6.1.tgz" + integrity sha512-LOmVnY1iTU2D8tv4Xf6MVMZZ+juIJ87Kt/plMijjN20NMAXGmH4u8bS1t0uT74cZ5gwpocYueV58YwyI8y+GKw== + dependencies: + tslib "^2.3.0" + +"@wry/equality@^0.5.0": + version "0.5.3" + resolved "https://registry.npmjs.org/@wry/equality/-/equality-0.5.3.tgz" + integrity sha512-avR+UXdSrsF2v8vIqIgmeTY0UR91UT+IyablCyKe/uk22uOJ8fusKZnH9JH9e1/EtLeNJBtagNmL3eJdnOV53g== + dependencies: + tslib "^2.3.0" + +"@wry/trie@^0.3.0": + version "0.3.2" + resolved "https://registry.npmjs.org/@wry/trie/-/trie-0.3.2.tgz" + integrity sha512-yRTyhWSls2OY/pYLfwff867r8ekooZ4UI+/gxot5Wj8EFwSf2rG+n+Mo/6LoLQm1TKA4GRj2+LCpbfS937dClQ== + dependencies: + tslib "^2.3.0" + +accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +acorn-walk@^8.1.1: + version "8.2.0" + resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + +acorn@^8.4.1: + version "8.8.0" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz" + integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== + +ansi-regex@^5.0.0: + version "5.0.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + +array.prototype.every@^1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/array.prototype.every/-/array.prototype.every-1.1.3.tgz" + integrity sha512-vWnriJI//SOMOWtXbU/VXhJ/InfnNHPF6BLKn5WfY8xXy+NWql0fUy20GO3sdqBhCAO+qw8S/E5nJiZX+QFdCA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + is-string "^1.0.7" + +async@^3.2.3: + version "3.2.4" + resolved "https://registry.npmjs.org/async/-/async-3.2.4.tgz" + integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== + +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + +b4a@^1.0.1: + version "1.6.0" + resolved "https://registry.npmjs.org/b4a/-/b4a-1.6.0.tgz" + integrity sha512-fsTxXxj1081Yq5MOQ06gZ5+e2QcSyP2U6NofdOWyq+lrNI4IjkZ+fLVmoQ6uUCiNg1NWePMMVq93vOTdbJmErw== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +blake2b-wasm@^2.4.0: + version "2.4.0" + resolved "https://registry.npmjs.org/blake2b-wasm/-/blake2b-wasm-2.4.0.tgz" + integrity sha512-S1kwmW2ZhZFFFOghcx73+ZajEfKBqhP82JMssxtLVMxlaPea1p9uoLiUZ5WYyHn0KddwbLc+0vh4wR0KBNoT5w== + dependencies: + b4a "^1.0.1" + nanoassert "^2.0.0" + +blake2b@^2.1.3: + version "2.1.4" + resolved "https://registry.npmjs.org/blake2b/-/blake2b-2.1.4.tgz" + integrity sha512-AyBuuJNI64gIvwx13qiICz6H6hpmjvYS5DGkG6jbXMOT8Z3WUJ3V1X0FlhIoT1b/5JtHE3ki+xjtMvu1nn+t9A== + dependencies: + blake2b-wasm "^2.4.0" + nanoassert "^2.0.0" + +body-parser@1.20.0: + version "1.20.0" + resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz" + integrity sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg== + dependencies: + bytes "3.1.2" + content-type "~1.0.4" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.10.3" + raw-body "2.5.1" + type-is "~1.6.18" + unpipe "1.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +class-validator@^0.13.1: + version "0.13.2" + resolved "https://registry.npmjs.org/class-validator/-/class-validator-0.13.2.tgz" + integrity sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw== + dependencies: + libphonenumber-js "^1.9.43" + validator "^13.7.0" + +color-convert@^1.9.3: + version "1.9.3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@^1.0.0, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-string@^1.6.0: + version "1.9.1" + resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz" + integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^3.1.3: + version "3.2.1" + resolved "https://registry.npmjs.org/color/-/color-3.2.1.tgz" + integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== + dependencies: + color-convert "^1.9.3" + color-string "^1.6.0" + +colorspace@1.1.x: + version "1.1.4" + resolved "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz" + integrity sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w== + dependencies: + color "^3.1.3" + text-hex "1.0.x" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.5.0: + version "0.5.0" + resolved "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz" + integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +deep-equal@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.5.tgz" + integrity sha512-nPiRgmbAtm1a3JsnLCf6/SLfXcjyN5v8L1TXzdCmHrXJ4hx+gW/w1YCcn7z8gJtSiDArZCgYtbao3QqLm/N1Sw== + dependencies: + call-bind "^1.0.0" + es-get-iterator "^1.1.1" + get-intrinsic "^1.0.1" + is-arguments "^1.0.4" + is-date-object "^1.0.2" + is-regex "^1.1.1" + isarray "^2.0.5" + object-is "^1.1.4" + object-keys "^1.1.1" + object.assign "^4.1.2" + regexp.prototype.flags "^1.3.0" + side-channel "^1.0.3" + which-boxed-primitive "^1.0.1" + which-collection "^1.0.1" + which-typed-array "^1.1.2" + +define-properties@^1.1.3, define-properties@^1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz" + integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== + dependencies: + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +defined@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz" + integrity sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ== + +depd@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + +diff-sequences@^26.6.2: + version "26.6.2" + resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz" + integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +divide-bigint@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/divide-bigint/-/divide-bigint-1.0.4.tgz" + integrity sha512-4BuHUgA1+iICOm6JZlourP3Zo/EQHh42/cSHP2hhoVGmgp6Pd1eJ8wt9c8v4gGfy8vBUFhQoO+BrZ90vuaugyg== + +dotignore@^0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/dotignore/-/dotignore-0.1.2.tgz" + integrity sha512-UGGGWfSauusaVJC+8fgV+NVvBXkCTmVv7sk6nojDZZvuOUNGUy0Zk4UpHQD6EDjS0jpBwcACvH4eofvyzBcRDw== + dependencies: + minimatch "^3.0.4" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +emittery@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/emittery/-/emittery-1.0.1.tgz" + integrity sha512-2ID6FdrMD9KDLldGesP6317G78K7km/kMcwItRtVFva7I/cSEOIaLpewaUb+YLXVwdAp3Ctfxh/V5zIl1sj7dQ== + +enabled@2.0.x: + version "2.0.0" + resolved "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz" + integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +es-abstract@^1.19.0, es-abstract@^1.19.5, es-abstract@^1.20.0: + version "1.20.1" + resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz" + integrity sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + function.prototype.name "^1.1.5" + get-intrinsic "^1.1.1" + get-symbol-description "^1.0.0" + has "^1.0.3" + has-property-descriptors "^1.0.0" + has-symbols "^1.0.3" + internal-slot "^1.0.3" + is-callable "^1.2.4" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-weakref "^1.0.2" + object-inspect "^1.12.0" + object-keys "^1.1.1" + object.assign "^4.1.2" + regexp.prototype.flags "^1.4.3" + string.prototype.trimend "^1.0.5" + string.prototype.trimstart "^1.0.5" + unbox-primitive "^1.0.2" + +es-get-iterator@^1.1.1: + version "1.1.2" + resolved "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz" + integrity sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.0" + has-symbols "^1.0.1" + is-arguments "^1.1.0" + is-map "^2.0.2" + is-set "^2.0.2" + is-string "^1.0.5" + isarray "^2.0.5" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +express@^4.18.1: + version "4.18.1" + resolved "https://registry.npmjs.org/express/-/express-4.18.1.tgz" + integrity sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.0" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.5.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.2.0" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.10.3" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.18.0" + serve-static "1.15.0" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +faker@5.5.3: + version "5.5.3" + resolved "https://registry.npmjs.org/faker/-/faker-5.5.3.tgz" + integrity sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g== + +fecha@^4.2.0: + version "4.2.3" + resolved "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz" + integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== + +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + +fn.name@1.x.x: + version "1.1.0" + resolved "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz" + integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== + +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +function.prototype.name@^1.1.5: + version "1.1.5" + resolved "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz" + integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + functions-have-names "^1.2.2" + +functions-have-names@^1.2.2: + version "1.2.3" + resolved "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + +get-intrinsic@^1.0.1, get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: + version "1.1.2" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz" + integrity sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.3" + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-port@^6.1.2: + version "6.1.2" + resolved "https://registry.npmjs.org/get-port/-/get-port-6.1.2.tgz" + integrity sha512-BrGGraKm2uPqurfGVj/z97/zv8dPleC6x9JBNRTrDNtCkkRF4rPwrQXFgL7+I+q8QSdU4ntLQX2D7KIxSy8nGw== + +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +glob@^7.1.6, glob@^7.2.0: + version "7.2.3" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +graphql-query-complexity@^0.7.0: + version "0.7.2" + resolved "https://registry.npmjs.org/graphql-query-complexity/-/graphql-query-complexity-0.7.2.tgz" + integrity sha512-+VgmrfxGEjHI3zuojWOR8bsz7Ycz/BZjNjxnlUieTz5DsB92WoIrYCSZdWG7UWZ3rfcA1Gb2Nf+wB80GsaZWuQ== + dependencies: + lodash.get "^4.4.2" + +graphql-subscriptions@^1.1.0: + version "1.2.1" + resolved "https://registry.npmjs.org/graphql-subscriptions/-/graphql-subscriptions-1.2.1.tgz" + integrity sha512-95yD/tKi24q8xYa7Q9rhQN16AYj5wPbrb8tmHGM3WRc9EBmWrG/0kkMl+tQG8wcEuE9ibR4zyOM31p5Sdr2v4g== + dependencies: + iterall "^1.3.0" + +graphql-tag@^2.12.6: + version "2.12.6" + resolved "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.6.tgz" + integrity sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg== + dependencies: + tslib "^2.1.0" + +graphql@^15.7.2: + version "15.8.0" + resolved "https://registry.npmjs.org/graphql/-/graphql-15.8.0.tgz" + integrity sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw== + +has-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + +has-dynamic-import@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/has-dynamic-import/-/has-dynamic-import-2.0.1.tgz" + integrity sha512-X3fbtsZmwb6W7fJGR9o7x65fZoodygCrZ3TVycvghP62yYQfS0t4RS0Qcz+j5tQYUKeSWS09tHkWW6WhFV3XhQ== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz" + integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== + dependencies: + get-intrinsic "^1.1.1" + +has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hoist-non-react-statics@^3.3.2: + version "3.3.2" + resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4: + version "2.0.4" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +internal-slot@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz" + integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== + dependencies: + get-intrinsic "^1.1.0" + has "^1.0.3" + side-channel "^1.0.4" + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-arguments@^1.0.4, is-arguments@^1.1.0: + version "1.1.1" + resolved "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.4: + version "1.2.4" + resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz" + integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== + +is-core-module@^2.9.0: + version "2.9.0" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz" + integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== + dependencies: + has "^1.0.3" + +is-date-object@^1.0.1, is-date-object@^1.0.2: + version "1.0.5" + resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-map@^2.0.1, is-map@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz" + integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== + +is-negative-zero@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + +is-promise@^2.1.0: + version "2.2.2" + resolved "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz" + integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== + +is-regex@^1.1.1, is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-set@^2.0.1, is-set@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz" + integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== + +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typed-array@^1.1.9: + version "1.1.9" + resolved "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.9.tgz" + integrity sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-abstract "^1.20.0" + for-each "^0.3.3" + has-tostringtag "^1.0.0" + +is-weakmap@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz" + integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== + +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +is-weakset@^2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz" + integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + +isomorphic-ws@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz" + integrity sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw== + +iterall@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz" + integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg== + +jest-diff@^26.0.0: + version "26.6.2" + resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz" + integrity sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA== + dependencies: + chalk "^4.0.0" + diff-sequences "^26.6.2" + jest-get-type "^26.3.0" + pretty-format "^26.6.2" + +jest-get-type@^26.3.0: + version "26.3.0" + resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz" + integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== + +js-base64@^3.7.3: + version "3.7.5" + resolved "https://registry.npmjs.org/js-base64/-/js-base64-3.7.5.tgz" + integrity sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA== + +"js-tokens@^3.0.0 || ^4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +kuler@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz" + integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== + +libphonenumber-js@^1.9.43: + version "1.10.13" + resolved "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.13.tgz" + integrity sha512-b74iyWmwb4GprAUPjPkJ11GTC7KX4Pd3onpJfKxYyY8y9Rbb4ERY47LvCMEDM09WD3thiLDMXtkfDK/AX+zT7Q== + +libsodium-wrappers@^0.7.11: + version "0.7.13" + resolved "https://registry.yarnpkg.com/libsodium-wrappers/-/libsodium-wrappers-0.7.13.tgz#83299e06ee1466057ba0e64e532777d2929b90d3" + integrity sha512-kasvDsEi/r1fMzKouIDv7B8I6vNmknXwGiYodErGuESoFTohGSKZplFtVxZqHaoQ217AynyIFgnOVRitpHs0Qw== + dependencies: + libsodium "^0.7.13" + +libsodium@^0.7.13: + version "0.7.13" + resolved "https://registry.yarnpkg.com/libsodium/-/libsodium-0.7.13.tgz#230712ec0b7447c57b39489c48a4af01985fb393" + integrity sha512-mK8ju0fnrKXXfleL53vtp9xiPq5hKM0zbDQtcxQIsSmxNgSxqCj6R7Hl9PkrNe2j29T4yoDaF7DJLK9/i5iWUw== + +lodash-es@^4.17.21: + version "4.17.21" + resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz" + integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== + +lodash.get@^4.4.2: + version "4.4.2" + resolved "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz" + integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== + +lodash@^4.17.19, lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +logform@^2.3.2, logform@^2.4.0: + version "2.5.1" + resolved "https://registry.npmjs.org/logform/-/logform-2.5.1.tgz" + integrity sha512-9FyqAm9o9NKKfiAKfZoYo9bGXXuwMkxQiQttkT4YjjVtQVIQtK6LmVtlxmCaFswo6N4AfEkHqZTV0taDtPotNg== + dependencies: + "@colors/colors" "1.5.0" + "@types/triple-beam" "^1.3.2" + fecha "^4.2.0" + ms "^2.1.1" + safe-stable-stringify "^2.3.1" + triple-beam "^1.3.0" + +loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz" + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz" + integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== + +minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.6: + version "1.2.6" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.3, ms@^2.1.1: + version "2.1.3" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nanoassert@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/nanoassert/-/nanoassert-2.0.0.tgz" + integrity sha512-7vO7n28+aYO4J+8w96AzhmU8G+Y/xpPDJz/se19ICsqj/momRbb9mh9ZUtkoJ5X3nTnPdhEJyc0qnM6yAsHBaA== + +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-inspect@^1.12.0, object-inspect@^1.9.0: + version "1.12.2" + resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz" + integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== + +object-is@^1.1.4, object-is@^1.1.5: + version "1.1.5" + resolved "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.2: + version "4.1.2" + resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + has-symbols "^1.0.1" + object-keys "^1.1.1" + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +one-time@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz" + integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g== + dependencies: + fn.name "1.x.x" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz" + integrity sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ== + dependencies: + mimic-fn "^1.0.0" + +optimism@^0.16.1: + version "0.16.1" + resolved "https://registry.npmjs.org/optimism/-/optimism-0.16.1.tgz" + integrity sha512-64i+Uw3otrndfq5kaoGNoY7pvOhSsjFEN4bdEFh80MWVk/dbgJfMv7VFDeCT8LxNAlEVhQmdVEbfE7X2nWNIIg== + dependencies: + "@wry/context" "^0.6.0" + "@wry/trie" "^0.3.0" + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz" + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== + +pretty-format@^26.0.0, pretty-format@^26.6.2: + version "26.6.2" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz" + integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg== + dependencies: + "@jest/types" "^26.6.2" + ansi-regex "^5.0.0" + ansi-styles "^4.0.0" + react-is "^17.0.1" + +prop-types@^15.7.2: + version "15.8.1" + resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +qs@6.10.3: + version "6.10.3" + resolved "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz" + integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ== + dependencies: + side-channel "^1.0.4" + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.1: + version "2.5.1" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz" + integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +react-is@^16.13.1, react-is@^16.7.0: + version "16.13.1" + resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react-is@^17.0.1: + version "17.0.2" + resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + +readable-stream@^3.4.0, readable-stream@^3.6.0: + version "3.6.1" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.1.tgz" + integrity sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +reflect-metadata@^0.1.13: + version "0.1.13" + resolved "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz" + integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== + +regexp.prototype.flags@^1.3.0, regexp.prototype.flags@^1.4.3: + version "1.4.3" + resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz" + integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + functions-have-names "^1.2.2" + +resolve@^2.0.0-next.3: + version "2.0.0-next.4" + resolved "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz" + integrity sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +resumer@^0.0.0: + version "0.0.0" + resolved "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz" + integrity sha512-Fn9X8rX8yYF4m81rZCK/5VmrmsSbqS/i3rDLl6ZZHAXgC2nTAx3dhwG8q8odP/RmdLa2YrybDJaAMg+X1ajY3w== + dependencies: + through "~2.3.4" + +safe-buffer@5.2.1, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-stable-stringify@^2.3.1: + version "2.4.2" + resolved "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz" + integrity sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA== + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +semver@^7.3.2: + version "7.3.7" + resolved "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== + dependencies: + lru-cache "^6.0.0" + +send@0.18.0: + version "0.18.0" + resolved "https://registry.npmjs.org/send/-/send-0.18.0.tgz" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.18.0" + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +side-channel@^1.0.3, side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz" + integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== + dependencies: + is-arrayish "^0.3.1" + +stack-trace@0.0.x: + version "0.0.10" + resolved "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz" + integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +string.prototype.trim@^1.2.5: + version "1.2.6" + resolved "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.6.tgz" + integrity sha512-8lMR2m+U0VJTPp6JjvJTtGyc4FIGq9CdRt7O9p6T0e6K4vjU+OP+SQJpbe/SBmRcCUIvNUnjsbmY6lnMp8MhsQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.19.5" + +string.prototype.trimend@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz" + integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.19.5" + +string.prototype.trimstart@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz" + integrity sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.19.5" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +symbol-observable@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz" + integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ== + +tape-promise@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/tape-promise/-/tape-promise-4.0.0.tgz" + integrity sha512-mNi5yhWAKDuNgZCfFKeZbsXvraVOf+I8UZG+lf+aoRrzX4+jd4mpNBjYh16/VcpEMUtS0iFndBgnfxxZbtyLFw== + dependencies: + is-promise "^2.1.0" + onetime "^2.0.0" + +tape@^5.5.3: + version "5.5.3" + resolved "https://registry.npmjs.org/tape/-/tape-5.5.3.tgz" + integrity sha512-hPBJZBL9S7bH9vECg/KSM24slGYV589jJr4dmtiJrLD71AL66+8o4b9HdZazXZyvnilqA7eE8z5/flKiy0KsBg== + dependencies: + array.prototype.every "^1.1.3" + call-bind "^1.0.2" + deep-equal "^2.0.5" + defined "^1.0.0" + dotignore "^0.1.2" + for-each "^0.3.3" + get-package-type "^0.1.0" + glob "^7.2.0" + has "^1.0.3" + has-dynamic-import "^2.0.1" + inherits "^2.0.4" + is-regex "^1.1.4" + minimist "^1.2.6" + object-inspect "^1.12.0" + object-is "^1.1.5" + object-keys "^1.1.1" + object.assign "^4.1.2" + resolve "^2.0.0-next.3" + resumer "^0.0.0" + string.prototype.trim "^1.2.5" + through "^2.3.8" + +text-hex@1.0.x: + version "1.0.0" + resolved "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz" + integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== + +through@^2.3.8, through@~2.3.4: + version "2.3.8" + resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +triple-beam@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz" + integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw== + +ts-invariant@^0.10.3: + version "0.10.3" + resolved "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.10.3.tgz" + integrity sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ== + dependencies: + tslib "^2.1.0" + +ts-node@^10.8.0: + version "10.9.1" + resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz" + integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + +tslib@^2.0.1, tslib@^2.1.0, tslib@^2.3.0: + version "2.4.0" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + +tweetnacl@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz" + integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== + +type-graphql@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/type-graphql/-/type-graphql-1.1.1.tgz" + integrity sha512-iOOWVn0ehCYMukmnXStbkRwFE9dcjt7/oDcBS1JyQZo9CbhlIll4lHHps54HMEk4A4c8bUPd+DjK8w1/ZrxB4A== + dependencies: + "@types/glob" "^7.1.3" + "@types/node" "^14.11.2" + "@types/semver" "^7.3.3" + glob "^7.1.6" + graphql-query-complexity "^0.7.0" + graphql-subscriptions "^1.1.0" + semver "^7.3.2" + tslib "^2.0.1" + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typescript@^4.2.4: + version "4.7.4" + resolved "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz" + integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== + +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + +validator@^13.7.0: + version "13.7.0" + resolved "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz" + integrity sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw== + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +which-boxed-primitive@^1.0.1, which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-collection@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz" + integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== + dependencies: + is-map "^2.0.1" + is-set "^2.0.1" + is-weakmap "^2.0.1" + is-weakset "^2.0.1" + +which-typed-array@^1.1.2: + version "1.1.8" + resolved "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.8.tgz" + integrity sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-abstract "^1.20.0" + for-each "^0.3.3" + has-tostringtag "^1.0.0" + is-typed-array "^1.1.9" + +winston-transport@^4.5.0: + version "4.5.0" + resolved "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz" + integrity sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q== + dependencies: + logform "^2.3.2" + readable-stream "^3.6.0" + triple-beam "^1.3.0" + +winston@^3.8.2: + version "3.8.2" + resolved "https://registry.npmjs.org/winston/-/winston-3.8.2.tgz" + integrity sha512-MsE1gRx1m5jdTTO9Ld/vND4krP2To+lgDoMEHGGa4HIlAUyXJtfc7CxQcGXVyz2IBpw5hbFkj2b/AtUdQwyRew== + dependencies: + "@colors/colors" "1.5.0" + "@dabh/diagnostics" "^2.0.2" + async "^3.2.3" + is-stream "^2.0.0" + logform "^2.4.0" + one-time "^1.0.0" + readable-stream "^3.4.0" + safe-stable-stringify "^2.3.1" + stack-trace "0.0.x" + triple-beam "^1.3.0" + winston-transport "^4.5.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +ws@^8.11.0: + version "8.12.1" + resolved "https://registry.npmjs.org/ws/-/ws-8.12.1.tgz" + integrity sha512-1qo+M9Ba+xNhPB+YTWUlK6M17brTut5EXbcBaMRN5pH5dFrXz7lzz1ChFSUq3bOUl8yEvSenhHmYUNJxFzdJew== + +ws@^8.13.0: + version "8.14.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.14.1.tgz#4b9586b4f70f9e6534c7bb1d3dc0baa8b8cf01e0" + integrity sha512-4OOseMUq8AzRBI/7SLMUwO+FEDnguetSk7KMb1sHwvF2w2Wv5Hoj0nlifx8vtGsftE/jWHojPy8sMMzYLJ2G/A== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +zen-observable-ts@^1.2.5: + version "1.2.5" + resolved "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.2.5.tgz" + integrity sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg== + dependencies: + zen-observable "0.8.15" + +zen-observable@0.8.15: + version "0.8.15" + resolved "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz" + integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/index.ts b/bootstrap-languages/p-diff-sync-socket-signaling/index.ts new file mode 100644 index 000000000..92625a1d5 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/index.ts @@ -0,0 +1,59 @@ +import type { Address, Language, Interaction, HolochainLanguageDelegate, LanguageContext, AgentService } from "https://esm.sh/@perspect3vism/ad4m@0.5.0"; +import { LinkAdapter } from "./linksAdapter.ts"; +import { TelepresenceAdapterImplementation } from "./telepresenceAdapter.ts"; +import { DNA, DNA_NICK, ZOME_NAME } from "./build/dna.js"; + +function interactions(expression: Address): Interaction[] { + return []; +} + +//!@ad4m-template-variable +const name = "perspective-diff-sync"; + +//!@ad4m-template-variable +const uid = "perspective-diff-sync-uuid"; + +export default async function create(context: LanguageContext): Promise { + const Holochain = context.Holochain as HolochainLanguageDelegate; + const agent = context.agent as AgentService; + + const linksAdapter = new LinkAdapter(context, uid); + const telepresenceAdapter = new TelepresenceAdapterImplementation(context); + + await Holochain.registerDNAs( + //@ts-ignore + [{ file: DNA, nick: DNA_NICK, zomeCalls: + [ + [ZOME_NAME, "current_revision"], + [ZOME_NAME, "sync"], + [ZOME_NAME, "render"], + [ZOME_NAME, "commit"], + [ZOME_NAME, "fast_forward_signal"], + [ZOME_NAME, "get_others"], + [ZOME_NAME, "add_active_agent_link"], + [ZOME_NAME, "create_did_pub_key_link"], + ] + }], + async (signal) => { + //@ts-ignore + if (signal.payload.diff || (signal.payload.additions && signal.payload.removals)) { + await linksAdapter.handleHolochainSignal(signal) + } else { + for (const callback of telepresenceAdapter.signalCallbacks) { + await callback(signal.payload); + } + } + } + ); + + //Setup the link between did and agent pub key + await Holochain.call(DNA_NICK, ZOME_NAME, "create_did_pub_key_link", agent.did); + + //@ts-ignore + return { + name, + linksAdapter, + interactions, + telepresenceAdapter + } as Language; +} diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/integration-test.js b/bootstrap-languages/p-diff-sync-socket-signaling/integration-test.js new file mode 100644 index 000000000..a8b36a0bd --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/integration-test.js @@ -0,0 +1,20 @@ +const { spawnLinkAgent } = require("@perspect3vism/ad4m-test/helpers"); + +describe("Link", () => { + it("Create Link", async () => { + const agent = await spawnLinkAgent(); + + const all = await agent.queryLinks({}); + + expect(all.length).toBe(0) + + const link = await agent.addLink({source:"root", predicate: "soic://test", target:"QmYVsrMpiFmV9S7bTWNAkUzSqjRJskQ8g4TWKKwKrHAPqL://QmSsCCtXMDAZXMpyiNLzwjGEU4hLmhG7fphidhEEodQ4Wy"}) + + const all1 = await agent.queryLinks({}); + + expect(all1.length).toBe(1) + expect(all1[0].data.source).toBe(link.data.source) + expect(all1[0].data.predicate).toBe(link.data.predicate) + expect(all1[0].data.target).toBe(link.data.target) + }); +}) \ No newline at end of file diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/linksAdapter.ts b/bootstrap-languages/p-diff-sync-socket-signaling/linksAdapter.ts new file mode 100644 index 000000000..3701d6607 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/linksAdapter.ts @@ -0,0 +1,378 @@ +import { LinkSyncAdapter, PerspectiveDiffObserver, HolochainLanguageDelegate, LanguageContext, PerspectiveDiff, + LinkExpression, DID, Perspective, PerspectiveState } from "https://esm.sh/@perspect3vism/ad4m@0.5.0"; +import type { SyncStateChangeObserver } from "https://esm.sh/@perspect3vism/ad4m@0.5.0"; +import { Mutex, withTimeout } from "https://esm.sh/async-mutex@0.4.0"; +import { DNA_NICK, ZOME_NAME } from "./build/dna.js"; +import { io } from "https://esm.sh/socket.io-client@4.7.2"; + +class PeerInfo { + //@ts-ignore + currentRevision: Buffer; + //@ts-ignore + lastSeen: Date; +}; + +export class LinkAdapter implements LinkSyncAdapter { + hcDna: HolochainLanguageDelegate; + linkCallback?: PerspectiveDiffObserver + syncStateChangeCallback?: SyncStateChangeObserver + peers: Map = new Map(); + generalMutex: Mutex = withTimeout(new Mutex(), 10000, new Error('PerspectiveDiffSync: generalMutex timeout')); + me: DID + gossipLogCount: number = 0; + myCurrentRevision: Buffer | null = null; + languageName: String | null = null; + socket: any; + + constructor(context: LanguageContext, name: String) { + //@ts-ignore + this.hcDna = context.Holochain as HolochainLanguageDelegate; + this.me = context.agent.did; + this.languageName = name; + this.socket = io("https://socket.ad4m.dev", { transports: ['websocket', 'polling'], autoConnect: true }); + console.log("Created socket connection"); + this.socket.on('error', (error: any) => { + console.error('Error:', error); + }); + this.socket.on('connect', () => { + console.log('Connected to the server'); + try { + this.socket.emit("join-room", this.languageName); + console.log("Sent the join-room signal"); + } catch (e) { + console.error("Error in socket connection: ", e); + } + }); + this.socket.on("signal", (signal: any) => { + this.handleHolochainSignal(signal); + }); + this.socket.on('disconnect', () => { + console.log('Disconnected from the server'); + }); + this.socket.on('connect_error', (error) => { + console.error('Connection Error:', error); + }); + this.socket.on('reconnect_attempt', () => { + console.log('Trying to reconnect...'); + }); + } + + writable(): boolean { + return true; + } + + public(): boolean { + return false; + } + + async others(): Promise { + //@ts-ignore + return await this.hcDna.call(DNA_NICK, ZOME_NAME, "get_others", null); + } + + async currentRevision(): Promise { + //@ts-ignore + let res = await this.hcDna.call(DNA_NICK, ZOME_NAME, "current_revision", null); + return res as string; + } + + async sync(): Promise { + //console.log("PerspectiveDiffSync.sync(); Getting lock"); + const release = await this.generalMutex.acquire(); + //console.log("PerspectiveDiffSync.sync(); Got lock"); + try { + //@ts-ignore + let broadcast_payload = await this.hcDna.call(DNA_NICK, ZOME_NAME, "get_broadcast_payload", null); + if (broadcast_payload) { + if (broadcast_payload.reference_hash && Buffer.isBuffer(broadcast_payload.reference_hash)) { + this.myCurrentRevision = broadcast_payload.reference_hash; + } + //Use client to send to socketIO + broadcast_payload.reference_hash = Buffer.from(broadcast_payload.reference_hash).toString('base64'); + broadcast_payload.reference.diff = Buffer.from(broadcast_payload.reference.diff).toString('base64'); + if (broadcast_payload.reference.parents) { + broadcast_payload.reference.parents = broadcast_payload.reference.parents.map( (parent: Buffer) => parent ? Buffer.from(parent).toString('base64') : 'null'); + }; + // console.log("sync(); sending referenceh hash", broadcast_payload.reference_hash); + // console.log("sync(); sending broadcast payload"); + // console.log(JSON.stringify(broadcast_payload)); + this.socket.emit("broadcast", {roomId: this.languageName, signal: broadcast_payload}); + } + } catch (e) { + console.error("PerspectiveDiffSync.sync(); got error", e); + } finally { + release(); + } + await this.gossip(); + return new PerspectiveDiff() + } + + async gossip() { + this.gossipLogCount += 1; + let lostPeers: DID[] = []; + + const release = await this.generalMutex.acquire(); + try { + this.peers.forEach( (peerInfo, peer) => { + if (peerInfo.lastSeen.getTime() + 10000 < new Date().getTime()) { + lostPeers.push(peer); + } + }); + + for (const peer of lostPeers) { + this.peers.delete(peer); + } + + // flatten the map into an array of peers + let peers = Array.from(this.peers.keys()); + peers.push(this.me); + + // Lexically sort the peers + peers.sort(); + + // If we are the first peer, we are the scribe + let is_scribe = peers[0] == this.me; + + // Get a deduped set of all peer's current revisions + let revisions = new Set(); + for(const peerInfo of this.peers.values()) { + if (peerInfo.currentRevision) revisions.add(peerInfo.currentRevision); + } + + //Do checking on incoming gossip revisions and see if we have the same hash as the majority of the peers + //Get a copied array of revisions that are the same as mine + let sameRevisions; + //Get a copied array of revisions that are different than mine + let differentRevisions; + + function generateRevisionStates(myCurrentRevision: Buffer) { + sameRevisions = revisions.size == 0 ? [] : Array.from(revisions).filter( (revision) => { + return myCurrentRevision && revision.equals(myCurrentRevision); + }); + if (myCurrentRevision) { + sameRevisions.push(myCurrentRevision); + }; + differentRevisions = revisions.size == 0 ? [] : Array.from(revisions).filter( (revision) => { + return myCurrentRevision && !revision.equals(myCurrentRevision); + }); + } + + async function checkSyncState(callback: SyncStateChangeObserver) { + if (sameRevisions.length > 0 || differentRevisions.length > 0) { + if (sameRevisions.length <= differentRevisions.length) { + await callback(PerspectiveState.LinkLanguageInstalledButNotSynced); + } else { + await callback(PerspectiveState.Synced); + }; + } + } + + //@ts-ignore + generateRevisionStates(this.myCurrentRevision); + + //@ts-ignore + await checkSyncState(this.syncStateChangeCallback); + + for (const hash of Array.from(revisions)) { + if(!hash) continue + if (this.myCurrentRevision && hash.equals(this.myCurrentRevision)) continue + console.log("Pulling with hash", hash); + let pullResult = await this.hcDna.call(DNA_NICK, ZOME_NAME, "pull", { + hash, + is_scribe + }); + if (pullResult) { + if (pullResult.current_revision && Buffer.isBuffer(pullResult.current_revision)) { + let myRevision = pullResult.current_revision; + this.myCurrentRevision = myRevision; + + //@ts-ignore + generateRevisionStates(this.myCurrentRevision); + //@ts-ignore + await checkSyncState(this.syncStateChangeCallback); + } + } + } + + //Only show the gossip log every 10th iteration + if (this.gossipLogCount == 10) { + console.log(` + ====== + GOSSIP + -- + me: ${this.me} + is scribe: ${is_scribe} + -- + ${Array.from(this.peers.entries()).map( ([peer, peerInfo]) => { + //@ts-ignore + return `${peer}: ${peerInfo.currentRevision.toString('base64')} ${peerInfo.lastSeen.toISOString()}\n` + })} + -- + revisions: ${Array.from(revisions).map( (hash) => { + //@ts-ignore + return hash.toString('base64') + })} + `); + this.gossipLogCount = 0; + } + } catch (e) { + console.error("PerspectiveDiffSync.gossip(); got error", e); + } finally { + release(); + } + } + + async render(): Promise { + //@ts-ignore + let res = await this.hcDna.call(DNA_NICK, ZOME_NAME, "render", null); + return new Perspective(res.links); + } + + async commit(diff: PerspectiveDiff): Promise { + //console.log("PerspectiveDiffSync.commit(); Getting lock"); + const release = await this.generalMutex.acquire(); + try { + //console.log("PerspectiveDiffSync.commit(); Got lock"); + let prep_diff = { + additions: diff.additions.map((diff) => prepareLinkExpression(diff)), + removals: diff.removals.map((diff) => prepareLinkExpression(diff)) + } + let res = await this.hcDna.call(DNA_NICK, ZOME_NAME, "commit", prep_diff); + if (res && Buffer.isBuffer(res)) { + this.myCurrentRevision = res; + } + let broadcast_payload = await this.hcDna.call(DNA_NICK, ZOME_NAME, "get_broadcast_payload", null); + // console.log('commit got broadcast payload', broadcast_payload.referencence_hash); + // console.log("which has type", typeof broadcast_payload.reference_hash); + if (broadcast_payload) { + broadcast_payload.reference_hash = Buffer.from(broadcast_payload.reference_hash).toString('base64'); + broadcast_payload.reference.diff = Buffer.from(broadcast_payload.reference.diff).toString('base64'); + if (broadcast_payload.reference.parents) { + broadcast_payload.reference.parents = broadcast_payload.reference.parents.map( (parent: Buffer) => parent ? Buffer.from(parent).toString('base64') : 'null'); + }; + //console.log("commit sending referenceh hash", broadcast_payload.reference_hash); + this.socket.emit("broadcast", {roomId: this.languageName, signal: broadcast_payload}); + } + return res as string; + } catch (e) { + console.error("PerspectiveDiffSync.commit(); got error", e); + } finally { + release(); + } + } + + addCallback(callback: PerspectiveDiffObserver): number { + this.linkCallback = callback; + return 1; + } + + addSyncStateChangeCallback(callback: SyncStateChangeObserver): number { + this.syncStateChangeCallback = callback; + return 1; + } + + async handleHolochainSignal(signal: any): Promise { + let diff; + let reference_hash; + let reference; + let broadcast_author; + if (signal.payload) { + ({ diff, reference_hash, reference, broadcast_author } = signal.payload); + } else { + ({ diff, reference_hash, reference, broadcast_author } = signal); + } + // console.log("Setting a peer hash to", reference_hash); + // console.log(JSON.stringify(diff)); + // console.log("Reference", JSON.stringify(reference)); + // console.log(broadcast_author); + //Check if this signal came from another agent & contains a diff and reference_hash + if (diff && reference_hash && reference && broadcast_author) { + // console.log(`PerspectiveDiffSync.handleHolochainSignal: + // diff: ${JSON.stringify(diff)} + // reference_hash: ${reference_hash.toString('base64')} + // reference: { + // diff: ${reference.diff?.toString('base64')} + // parents: ${reference.parents ? reference.parents.map( (parent: Buffer) => parent ? parent.toString('base64') : 'null').join(', '):'none'} + // diffs_since_snapshot: ${reference?.diffs_since_snapshot} + // } + // broadcast_author: ${broadcast_author} + // `) + try { + //console.log("PerspectiveDiffSync.handleHolochainSignal: Getting lock"); + + //console.log("PerspectiveDiffSync.handleHolochainSignal: Got lock"); + //const parsed = JSON.parse(reference_hash); + // console.log("Handle holochain signal parsed ref hash"); + // console.log(JSON.stringify({ + // diff, + // reference_hash, + // reference, + // broadcast_author + // })); + if (!Buffer.isBuffer(reference_hash)) { + reference_hash = Buffer.from(reference_hash, 'base64'); + } + if (!Buffer.isBuffer(reference.diff)) { + reference.diff = Buffer.from(reference.diff, 'base64'); + } + if (reference.parents) { + reference.parents = reference.parents.map( (parent: string) => parent == 'null' ? null : Buffer.from(parent, 'base64')); + } + + await this.hcDna.call(DNA_NICK, ZOME_NAME, "handle_broadcast", { + diff, + reference_hash, + reference, + broadcast_author + }); + this.peers.set(broadcast_author, { currentRevision: reference_hash, lastSeen: new Date() }); + } catch (e) { + console.error("PerspectiveDiffSync.handleHolochainSignal: got error", e); + } + } else { + console.log("PerspectiveDiffSync.handleHolochainSignal: received a signals from ourselves in fast_forward_signal or in a pull: ", JSON.stringify(signal.payload)); + //This signal only contains link data and no reference, and therefore came from us in a pull in fast_forward_signal + if (this.linkCallback) { + console.log("PerspectiveDiffSync.handleHolochainSignal: calling linkCallback"); + await this.linkCallback(signal.payload); + } + } + } + + async addActiveAgentLink(hcDna: HolochainLanguageDelegate): Promise { + if (hcDna == undefined) { + console.warn("===Perspective-diff-sync: Error tried to add an active agent link but received no hcDna to add the link onto"); + } else { + return await hcDna.call( + DNA_NICK, + ZOME_NAME, + "add_active_agent_link", + //@ts-ignore + null + ); + } + } +} + +function prepareLinkExpression(link: LinkExpression): object { + const data = Object.assign(link); + if (data.data.source == "") { + data.data.source = null; + } + if (data.data.target == "") { + data.data.target = null; + } + if (data.data.predicate == "") { + data.data.predicate = null; + } + if (data.data.source == undefined) { + data.data.source = null; + } + if (data.data.target == undefined) { + data.data.target = null; + } + if (data.data.predicate == undefined) { + data.data.predicate = null; + } + return data; +} diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/package.json b/bootstrap-languages/p-diff-sync-socket-signaling/package.json new file mode 100644 index 000000000..b615f2717 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/package.json @@ -0,0 +1,43 @@ +{ + "name": "@perspect3vism/perspective-diff-sync-socket-signaling", + "version": "0.6.0", + "description": "An AD4M language for syncing mutations to a share perspective", + "main": "index.js", + "scripts": { + "build-dna": "cd hc-dna && ./build.sh && cd ..", + "build": "run-script-os", + "build:linux": "yarn run build-dna && yarn run build-common", + "build:macos": "yarn run build-dna && yarn run build-common", + "build:windows": "cd hc-dna && powershell -ExecutionPolicy Bypass -File ./build.ps1 && cd .. && yarn run build-common", + "rollup-dna": "rollup -c rollup.config.hc-dna.js", + "build-common": "yarn run rollup-dna && deno run --allow-all esbuild.ts", + "integration-test": "node ../../test-runner/build/cli.js --test ./integration-test.js --bundle \"./build/bundle.js\" --meta '{\"name\":\"p-diff-sync\",\"description\":\"Holochain based language for sharing Perspectives\",\"sourceCodeLink\":\"https://github.com/perspect3vism/perspective-diff-sync\",\"possibleTemplateParams\":[\"uid\",\"name\"]}'" + }, + "author": "", + "license": "ISC", + "dependencies": { + "@perspect3vism/ad4m": "*", + "@perspect3vism/ad4m-test": "*", + "@perspect3vism/rollup-plugin-dna": "^0.0.2", + "@rollup/plugin-commonjs": "^14.0.0", + "@rollup/plugin-json": "^4.1.0", + "@rollup/plugin-node-resolve": "^8.0.0", + "@rollup/plugin-typescript": "^4.0.0", + "@tsconfig/svelte": "^1.0.0", + "@types/node": "^18.0.0", + "faker": "^5.5.3", + "rollup": "^2.3.4", + "rollup-plugin-postcss": "^3.1.8", + "rollup-plugin-string": "^3.0.0", + "rollup-plugin-svelte": "^6.0.0", + "rollup-plugin-terser": "^7.0.0", + "svelte": "^3.0.0", + "svelte-check": "^1.0.0", + "svelte-preprocess": "^4.0.0", + "tslib": "^2.0.0", + "typescript": "^4.5.5" + }, + "devDependencies": { + "run-script-os": "^1.1.6" + } +} diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/rollup.config.hc-dna.js b/bootstrap-languages/p-diff-sync-socket-signaling/rollup.config.hc-dna.js new file mode 100644 index 000000000..a1c1e1bbf --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/rollup.config.hc-dna.js @@ -0,0 +1,71 @@ +import svelte from "rollup-plugin-svelte"; +import resolve from "@rollup/plugin-node-resolve"; +import commonjs from "@rollup/plugin-commonjs"; +//import { terser } from 'rollup-plugin-terser'; +import sveltePreprocess from "svelte-preprocess"; +import postcss from "rollup-plugin-postcss"; +import { string } from "rollup-plugin-string"; +import json from "@rollup/plugin-json"; +import dna from "@perspect3vism/rollup-plugin-dna"; + +const production = !process.env.ROLLUP_WATCH; + +export default { + input: "dna.js", + external: [], + output: { + sourcemap: true, + format: "esm", + name: "PDiffSyncLanguage", + file: "build/dna.js", + interop: "esModule", + globals: {}, + }, + external: [], + plugins: [ + string({ + include: "build/*.js", + }), + svelte({ + // enable run-time checks when not in production + dev: !production, + // we'll extract any component CSS out into + // a separate file - better for performance + //css: css => { + // css.write('bundle.css'); + //}, + preprocess: sveltePreprocess(), + }), + // copy({ + // assets: ['package.unbundled.json'] + // }), + + // If you have external dependencies installed from + // npm, you'll most likely need these plugins. In + // some cases you'll need additional configuration - + // consult the documentation for details: + // https://github.com/rollup/plugins/tree/master/packages/commonjs + resolve({ + browser: true, + dedupe: ["svelte"], + }), + commonjs(), + postcss({ + extract: true, + minimize: true, + use: [ + [ + "sass", + { + includePaths: ["./src/ui/theme", "./node_modules"], + }, + ], + ], + }), + json(), + dna(), + ], + watch: { + clearScreen: false, + }, +}; diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/telepresenceAdapter.ts b/bootstrap-languages/p-diff-sync-socket-signaling/telepresenceAdapter.ts new file mode 100644 index 000000000..9ae096da6 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/telepresenceAdapter.ts @@ -0,0 +1,39 @@ +import type { TelepresenceAdapter, OnlineAgent, PerspectiveExpression, TelepresenceSignalCallback, HolochainLanguageDelegate, LanguageContext } from "https://esm.sh/@perspect3vism/ad4m@0.5.0";; +import { DNA_NICK, ZOME_NAME } from "./build/dna.js"; + +export class TelepresenceAdapterImplementation implements TelepresenceAdapter { + hcDna: HolochainLanguageDelegate; + signalCallbacks: TelepresenceSignalCallback[] = []; + + constructor(context: LanguageContext) { + this.hcDna = context.Holochain as HolochainLanguageDelegate; + } + + async setOnlineStatus(status: PerspectiveExpression): Promise { + await this.hcDna.call(DNA_NICK, ZOME_NAME, "set_online_status", status); + } + + async getOnlineAgents(): Promise { + //@ts-ignore + const getActiveAgents = await this.hcDna.call(DNA_NICK, ZOME_NAME, "get_active_agents", null); + let calls = []; + for (const activeAgent of getActiveAgents) { + calls.push({dnaNick: DNA_NICK, zomeName: ZOME_NAME, fnName: "get_agents_status", params: activeAgent}); + }; + return await this.hcDna.callAsync(calls, 1000) as OnlineAgent[]; + } + + async sendSignal(remoteAgentDid: string, payload: PerspectiveExpression): Promise { + let res = await this.hcDna.call(DNA_NICK, ZOME_NAME, "send_signal", {remote_agent_did: remoteAgentDid, payload}); + return res; + } + + async sendBroadcast(payload: PerspectiveExpression): Promise { + let res = await this.hcDna.call(DNA_NICK, ZOME_NAME, "send_broadcast", payload); + return res; + } + + async registerSignalCallback(callback: TelepresenceSignalCallback): Promise { + this.signalCallbacks.push(callback); + } +} \ No newline at end of file diff --git a/bootstrap-languages/p-diff-sync-socket-signaling/tsconfig.json b/bootstrap-languages/p-diff-sync-socket-signaling/tsconfig.json new file mode 100644 index 000000000..132461b20 --- /dev/null +++ b/bootstrap-languages/p-diff-sync-socket-signaling/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "types": ["node"], + }, + "include": ["*.ts"], + "exclude": ["node_modules/*", "__sapper__/*", "public/*"], +} \ No newline at end of file diff --git a/bootstrap-languages/p-diff-sync/esbuild.ts b/bootstrap-languages/p-diff-sync/esbuild.ts index e479a51dd..6f3bce43c 100644 --- a/bootstrap-languages/p-diff-sync/esbuild.ts +++ b/bootstrap-languages/p-diff-sync/esbuild.ts @@ -4,26 +4,9 @@ import * as esbuild from "https://deno.land/x/esbuild@v0.17.18/mod.js"; // import * as esbuild from "https://deno.land/x/esbuild@v0.17.18/wasm.js"; import { denoPlugins } from "https://deno.land/x/esbuild_deno_loader@0.7.0/mod.ts"; -import { loadSource, resolveUrl } from "./customHttpDownloader.js"; const result = await esbuild.build({ - plugins: [ - { - name: `buffer-alias`, - setup(build) { - build.onResolve({ filter: new RegExp(`^buffer$`) }, (args) => { - return { path: `https://deno.land/std@0.177.0/node/buffer.ts`, namespace: 'imports' }; - }); - - build.onResolve({filter: /.*/, namespace: 'imports'}, resolveUrl) - - build.onLoad({filter: /.*/, namespace: 'imports'}, (args) => { - return loadSource(args) - }) - }, - }, - ...denoPlugins() - ], + plugins: [...denoPlugins()], entryPoints: ['index.ts'], outfile: 'build/bundle.js', bundle: true, diff --git a/bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/lib.rs b/bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/lib.rs index e837a592b..7e03bab91 100644 --- a/bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/lib.rs +++ b/bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/lib.rs @@ -63,12 +63,6 @@ pub fn sync(_: ()) -> ExternResult> { .map_err(|error| utils::err(&format!("{}", error))) } -#[hdk_extern] -pub fn get_broadcast_payload(_: ()) -> ExternResult> { - link_adapter::commit::get_broadcast_payload::() - .map_err(|error| utils::err(&format!("{}", error))) -} - #[hdk_extern] pub fn pull(args: PullArguments) -> ExternResult { link_adapter::pull::pull::(true, args.hash, args.is_scribe) @@ -101,7 +95,6 @@ fn recv_remote_signal(signal: SerializedBytes) -> ExternResult<()> { //Check if its a normal diff expression signal match HashBroadcast::try_from(signal.clone()) { Ok(broadcast) => { - debug!("Received broadcast: {:?} in HOLOCHAIN", broadcast); link_adapter::pull::handle_broadcast::(broadcast) .map_err(|err| utils::err(&format!("{}", err)))?; } @@ -115,13 +108,6 @@ fn recv_remote_signal(signal: SerializedBytes) -> ExternResult<()> { Ok(()) } -#[hdk_extern] -pub fn handle_broadcast(broadcast: HashBroadcast) -> ExternResult<()> { - link_adapter::pull::handle_broadcast::(broadcast) - .map_err(|err| utils::err(&format!("{}", err)))?; - Ok(()) -} - // Telepresence implementation #[hdk_extern] diff --git a/bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/link_adapter/commit.rs b/bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/link_adapter/commit.rs index 6dd6f9392..e9897391c 100644 --- a/bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/link_adapter/commit.rs +++ b/bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/link_adapter/commit.rs @@ -88,15 +88,15 @@ pub fn commit( ); update_current_revision::(diff_entry_reference.clone(), now)?; - // if *ENABLE_SIGNALS { - // // let signal_data = PerspectiveDiffReference { - // // diff, - // // reference: diff_entry_ref_entry, - // // reference_hash: diff_entry_reference.clone(), - // // }; - // // send_revision_signal(signal_data)?; - // broadcast_current::()?; - // }; + if *ENABLE_SIGNALS { + // let signal_data = PerspectiveDiffReference { + // diff, + // reference: diff_entry_ref_entry, + // reference_hash: diff_entry_reference.clone(), + // }; + // send_revision_signal(signal_data)?; + broadcast_current::()?; + }; let after_fn_end = get_now()?.time(); debug!( @@ -150,22 +150,3 @@ pub fn broadcast_current() -> SocialContext }; Ok(current.map(|rev| rev.hash)) } - -pub fn get_broadcast_payload() -> SocialContextResult> { - match current_revision::()? { - Some(current) => { - let current_revision = current; - let entry_ref = - Retriever::get::(current_revision.hash.clone())?; - let diff = Retriever::get::(entry_ref.diff.clone())?; - - Ok(Some(HashBroadcast { - reference: entry_ref, - reference_hash: current_revision.hash.clone(), - diff, - broadcast_author: get_my_did()?.unwrap(), - })) - }, - None => Ok(None) - } -} diff --git a/bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/link_adapter/pull.rs b/bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/link_adapter/pull.rs index 9059b9b32..5897c3435 100644 --- a/bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/link_adapter/pull.rs +++ b/bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/link_adapter/pull.rs @@ -232,7 +232,7 @@ pub fn handle_broadcast( emit_signal(broadcast.diff.clone())?; }; }; - //emit_signal(broadcast)?; + emit_signal(broadcast)?; // let fn_end = get_now()?.time(); // debug!("===PerspectiveDiffSync.fast_forward_signal() - Profiling: Took: {} to complete fast_forward_signal() function", (fn_end - fn_start).num_milliseconds()); Ok(()) diff --git a/bootstrap-languages/p-diff-sync/index.ts b/bootstrap-languages/p-diff-sync/index.ts index 92625a1d5..1f57856ad 100644 --- a/bootstrap-languages/p-diff-sync/index.ts +++ b/bootstrap-languages/p-diff-sync/index.ts @@ -10,14 +10,11 @@ function interactions(expression: Address): Interaction[] { //!@ad4m-template-variable const name = "perspective-diff-sync"; -//!@ad4m-template-variable -const uid = "perspective-diff-sync-uuid"; - export default async function create(context: LanguageContext): Promise { const Holochain = context.Holochain as HolochainLanguageDelegate; const agent = context.agent as AgentService; - const linksAdapter = new LinkAdapter(context, uid); + const linksAdapter = new LinkAdapter(context); const telepresenceAdapter = new TelepresenceAdapterImplementation(context); await Holochain.registerDNAs( diff --git a/bootstrap-languages/p-diff-sync/linksAdapter.ts b/bootstrap-languages/p-diff-sync/linksAdapter.ts index 3701d6607..62e09db15 100644 --- a/bootstrap-languages/p-diff-sync/linksAdapter.ts +++ b/bootstrap-languages/p-diff-sync/linksAdapter.ts @@ -3,7 +3,6 @@ import { LinkSyncAdapter, PerspectiveDiffObserver, HolochainLanguageDelegate, La import type { SyncStateChangeObserver } from "https://esm.sh/@perspect3vism/ad4m@0.5.0"; import { Mutex, withTimeout } from "https://esm.sh/async-mutex@0.4.0"; import { DNA_NICK, ZOME_NAME } from "./build/dna.js"; -import { io } from "https://esm.sh/socket.io-client@4.7.2"; class PeerInfo { //@ts-ignore @@ -21,40 +20,11 @@ export class LinkAdapter implements LinkSyncAdapter { me: DID gossipLogCount: number = 0; myCurrentRevision: Buffer | null = null; - languageName: String | null = null; - socket: any; - constructor(context: LanguageContext, name: String) { + constructor(context: LanguageContext) { //@ts-ignore this.hcDna = context.Holochain as HolochainLanguageDelegate; this.me = context.agent.did; - this.languageName = name; - this.socket = io("https://socket.ad4m.dev", { transports: ['websocket', 'polling'], autoConnect: true }); - console.log("Created socket connection"); - this.socket.on('error', (error: any) => { - console.error('Error:', error); - }); - this.socket.on('connect', () => { - console.log('Connected to the server'); - try { - this.socket.emit("join-room", this.languageName); - console.log("Sent the join-room signal"); - } catch (e) { - console.error("Error in socket connection: ", e); - } - }); - this.socket.on("signal", (signal: any) => { - this.handleHolochainSignal(signal); - }); - this.socket.on('disconnect', () => { - console.log('Disconnected from the server'); - }); - this.socket.on('connect_error', (error) => { - console.error('Connection Error:', error); - }); - this.socket.on('reconnect_attempt', () => { - console.log('Trying to reconnect...'); - }); } writable(): boolean { @@ -82,21 +52,9 @@ export class LinkAdapter implements LinkSyncAdapter { //console.log("PerspectiveDiffSync.sync(); Got lock"); try { //@ts-ignore - let broadcast_payload = await this.hcDna.call(DNA_NICK, ZOME_NAME, "get_broadcast_payload", null); - if (broadcast_payload) { - if (broadcast_payload.reference_hash && Buffer.isBuffer(broadcast_payload.reference_hash)) { - this.myCurrentRevision = broadcast_payload.reference_hash; - } - //Use client to send to socketIO - broadcast_payload.reference_hash = Buffer.from(broadcast_payload.reference_hash).toString('base64'); - broadcast_payload.reference.diff = Buffer.from(broadcast_payload.reference.diff).toString('base64'); - if (broadcast_payload.reference.parents) { - broadcast_payload.reference.parents = broadcast_payload.reference.parents.map( (parent: Buffer) => parent ? Buffer.from(parent).toString('base64') : 'null'); - }; - // console.log("sync(); sending referenceh hash", broadcast_payload.reference_hash); - // console.log("sync(); sending broadcast payload"); - // console.log(JSON.stringify(broadcast_payload)); - this.socket.emit("broadcast", {roomId: this.languageName, signal: broadcast_payload}); + let current_revision = await this.hcDna.call(DNA_NICK, ZOME_NAME, "sync", null); + if (current_revision && Buffer.isBuffer(current_revision)) { + this.myCurrentRevision = current_revision; } } catch (e) { console.error("PerspectiveDiffSync.sync(); got error", e); @@ -176,7 +134,6 @@ export class LinkAdapter implements LinkSyncAdapter { for (const hash of Array.from(revisions)) { if(!hash) continue if (this.myCurrentRevision && hash.equals(this.myCurrentRevision)) continue - console.log("Pulling with hash", hash); let pullResult = await this.hcDna.call(DNA_NICK, ZOME_NAME, "pull", { hash, is_scribe @@ -241,18 +198,6 @@ export class LinkAdapter implements LinkSyncAdapter { if (res && Buffer.isBuffer(res)) { this.myCurrentRevision = res; } - let broadcast_payload = await this.hcDna.call(DNA_NICK, ZOME_NAME, "get_broadcast_payload", null); - // console.log('commit got broadcast payload', broadcast_payload.referencence_hash); - // console.log("which has type", typeof broadcast_payload.reference_hash); - if (broadcast_payload) { - broadcast_payload.reference_hash = Buffer.from(broadcast_payload.reference_hash).toString('base64'); - broadcast_payload.reference.diff = Buffer.from(broadcast_payload.reference.diff).toString('base64'); - if (broadcast_payload.reference.parents) { - broadcast_payload.reference.parents = broadcast_payload.reference.parents.map( (parent: Buffer) => parent ? Buffer.from(parent).toString('base64') : 'null'); - }; - //console.log("commit sending referenceh hash", broadcast_payload.reference_hash); - this.socket.emit("broadcast", {roomId: this.languageName, signal: broadcast_payload}); - } return res as string; } catch (e) { console.error("PerspectiveDiffSync.commit(); got error", e); @@ -272,19 +217,7 @@ export class LinkAdapter implements LinkSyncAdapter { } async handleHolochainSignal(signal: any): Promise { - let diff; - let reference_hash; - let reference; - let broadcast_author; - if (signal.payload) { - ({ diff, reference_hash, reference, broadcast_author } = signal.payload); - } else { - ({ diff, reference_hash, reference, broadcast_author } = signal); - } - // console.log("Setting a peer hash to", reference_hash); - // console.log(JSON.stringify(diff)); - // console.log("Reference", JSON.stringify(reference)); - // console.log(broadcast_author); + const { diff, reference_hash, reference, broadcast_author } = signal.payload; //Check if this signal came from another agent & contains a diff and reference_hash if (diff && reference_hash && reference && broadcast_author) { // console.log(`PerspectiveDiffSync.handleHolochainSignal: @@ -301,39 +234,14 @@ export class LinkAdapter implements LinkSyncAdapter { //console.log("PerspectiveDiffSync.handleHolochainSignal: Getting lock"); //console.log("PerspectiveDiffSync.handleHolochainSignal: Got lock"); - //const parsed = JSON.parse(reference_hash); - // console.log("Handle holochain signal parsed ref hash"); - // console.log(JSON.stringify({ - // diff, - // reference_hash, - // reference, - // broadcast_author - // })); - if (!Buffer.isBuffer(reference_hash)) { - reference_hash = Buffer.from(reference_hash, 'base64'); - } - if (!Buffer.isBuffer(reference.diff)) { - reference.diff = Buffer.from(reference.diff, 'base64'); - } - if (reference.parents) { - reference.parents = reference.parents.map( (parent: string) => parent == 'null' ? null : Buffer.from(parent, 'base64')); - } - - await this.hcDna.call(DNA_NICK, ZOME_NAME, "handle_broadcast", { - diff, - reference_hash, - reference, - broadcast_author - }); this.peers.set(broadcast_author, { currentRevision: reference_hash, lastSeen: new Date() }); } catch (e) { console.error("PerspectiveDiffSync.handleHolochainSignal: got error", e); } } else { - console.log("PerspectiveDiffSync.handleHolochainSignal: received a signals from ourselves in fast_forward_signal or in a pull: ", JSON.stringify(signal.payload)); + //console.log("PerspectiveDiffSync.handleHolochainSignal: received a signals from ourselves in fast_forward_signal or in a pull: ", signal.payload); //This signal only contains link data and no reference, and therefore came from us in a pull in fast_forward_signal if (this.linkCallback) { - console.log("PerspectiveDiffSync.handleHolochainSignal: calling linkCallback"); await this.linkCallback(signal.payload); } } diff --git a/bootstrap-languages/p-diff-sync/package.json b/bootstrap-languages/p-diff-sync/package.json index e10f1e6c7..b5c18527e 100644 --- a/bootstrap-languages/p-diff-sync/package.json +++ b/bootstrap-languages/p-diff-sync/package.json @@ -1,6 +1,6 @@ { "name": "@perspect3vism/perspective-diff-sync", - "version": "0.6.0", + "version": "0.6.1-prerelease", "description": "An AD4M language for syncing mutations to a share perspective", "main": "index.js", "scripts": { diff --git a/cli/seed_proto.json b/cli/seed_proto.json index e261ea2c2..a158a5c9d 100644 --- a/cli/seed_proto.json +++ b/cli/seed_proto.json @@ -4,11 +4,20 @@ { "meta": { "name": "perspectiveDiffSync", - "description": "Holochain based Perspective link sharing language, with revision signals sent with socket.io", + "description": "Holochain based Perspective link sharing language", "sourceCodeLink": "https://github.com/perspect3vism/perspective-diff-sync", "possibleTemplateParams": ["uid", "name", "description"] }, "resource": "../bootstrap-languages/p-diff-sync/build/bundle.js" + }, + { + "meta": { + "name": "perspectiveDiffSync", + "description": "Holochain based Perspective link sharing language, with revision signals sent with socket.io", + "sourceCodeLink": "https://github.com/perspect3vism/perspective-diff-sync", + "possibleTemplateParams": ["uid", "name", "description"] + }, + "resource": "../bootstrap-languages/p-diff-sync-socket-signaling/build/bundle.js" } ], "agentLanguage": { diff --git a/turbo.json b/turbo.json index 7047c342d..31955bc8a 100644 --- a/turbo.json +++ b/turbo.json @@ -13,7 +13,7 @@ "dependsOn": ["@perspect3vism/perspective-diff-sync#build", "@perspect3vism/agent-language#build", "@perspect3vism/direct-message-language#build", "@perspect3vism/perspective-language#build", "@perspect3vism/language-language#build", "@perspect3vism/neighbourhood-language#build", - "@perspect3vism/file-storage#build"], + "@perspect3vism/file-storage#build", "@perspect3vism/perspective-diff-sync-socket-signaling#build"], "outputs": ["dist/**", "lib/**", "build/**"] },