basic cli for testing things
This commit is contained in:
parent
575d9a353e
commit
fa07875cca
8 changed files with 681 additions and 78 deletions
383
Cargo.lock
generated
383
Cargo.lock
generated
|
@ -2,6 +2,33 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
|
||||
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.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.2"
|
||||
|
@ -11,6 +38,84 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.7"
|
||||
|
@ -23,6 +128,12 @@ version = "1.6.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
|
@ -45,12 +156,67 @@ dependencies = [
|
|||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||
|
||||
[[package]]
|
||||
name = "const-oid"
|
||||
version = "0.9.6"
|
||||
|
@ -108,11 +274,14 @@ dependencies = [
|
|||
name = "dag-resolve"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
"canonical_json",
|
||||
"clap",
|
||||
"ed25519",
|
||||
"ed25519-dalek",
|
||||
"rand",
|
||||
"rusqlite",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
|
@ -164,6 +333,18 @@ dependencies = [
|
|||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fallible-iterator"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
|
||||
|
||||
[[package]]
|
||||
name = "fallible-streaming-iterator"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||
|
||||
[[package]]
|
||||
name = "fiat-crypto"
|
||||
version = "0.2.6"
|
||||
|
@ -191,6 +372,37 @@ dependencies = [
|
|||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.28.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"allocator-api2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashlink"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
|
@ -209,12 +421,47 @@ version = "0.2.153"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.32.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
|
||||
[[package]]
|
||||
name = "pkcs8"
|
||||
version = "0.10.2"
|
||||
|
@ -225,6 +472,12 @@ dependencies = [
|
|||
"spki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb"
|
||||
|
||||
[[package]]
|
||||
name = "platforms"
|
||||
version = "3.3.0"
|
||||
|
@ -314,6 +567,26 @@ version = "0.8.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "rusqlite"
|
||||
version = "0.30.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a78046161564f5e7cd9008aff3b2990b3850dc8e0349119b98e8f251e099f24d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fallible-iterator",
|
||||
"fallible-streaming-iterator",
|
||||
"hashlink",
|
||||
"libsqlite3-sys",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.0"
|
||||
|
@ -386,6 +659,12 @@ dependencies = [
|
|||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
|
||||
|
||||
[[package]]
|
||||
name = "spki"
|
||||
version = "0.7.3"
|
||||
|
@ -396,6 +675,12 @@ dependencies = [
|
|||
"der",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.5.0"
|
||||
|
@ -445,6 +730,18 @@ version = "1.0.12"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
|
@ -457,6 +754,92 @@ version = "0.11.0+wasi-snapshot-preview1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.7.0"
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
[package]
|
||||
name = "dag-resolve"
|
||||
description = "experiment in directed acyclic graphs and reducers"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = { version = "1.0.79", features = ["backtrace"] }
|
||||
base64 = "0.21.7"
|
||||
canonical_json = "0.5.0"
|
||||
clap = { version = "4.5.0", features = ["derive"] }
|
||||
ed25519 = "2.2.3"
|
||||
ed25519-dalek = { version = "2.1.1", features = ["rand_core"] }
|
||||
rand = "0.8.5"
|
||||
rusqlite = { version = "0.30.0", features = ["bundled"] }
|
||||
serde = { version = "1.0.196", features = ["derive"] }
|
||||
serde_json = "1.0.113"
|
||||
sha2 = "0.10.8"
|
||||
|
|
144
src/bin/dag.rs
Normal file
144
src/bin/dag.rs
Normal file
|
@ -0,0 +1,144 @@
|
|||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use clap::Parser;
|
||||
use dag_resolve::{
|
||||
actor::{ActorId, ActorSecret},
|
||||
event::{CoreContent, HashType, SignatureType},
|
||||
resolvers::kv::{KVEventContent, KVResolver, KVState},
|
||||
room::Room,
|
||||
};
|
||||
use rusqlite::{Connection, OpenFlags};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(version, about)]
|
||||
enum Cli {
|
||||
/// Initialize a new repository
|
||||
Init { repo: PathBuf },
|
||||
|
||||
/// Set a key in a repository
|
||||
Set {
|
||||
repo: PathBuf,
|
||||
key: String,
|
||||
value: String,
|
||||
},
|
||||
}
|
||||
|
||||
type Result<T> = std::result::Result<T, anyhow::Error>;
|
||||
|
||||
struct State {
|
||||
db: Connection,
|
||||
room: Room<KVEventContent, KVState>,
|
||||
secret: ActorSecret,
|
||||
}
|
||||
|
||||
impl State {
|
||||
fn create_event(&mut self, content: CoreContent<KVEventContent>) -> Result<()> {
|
||||
let event = self.room.create_event(content, &self.secret)?;
|
||||
self.db.execute(
|
||||
"INSERT INTO events (id, json) VALUES (?, ?)",
|
||||
(event.id().to_string(), serde_json::to_string(&event)?),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_repo(path: &Path, create: bool) -> Result<State> {
|
||||
match (create, path.try_exists()?) {
|
||||
(true, true) => panic!("repo already exists"),
|
||||
(false, false) => panic!("repo does not exist"),
|
||||
(true, false) => {
|
||||
// create new repo
|
||||
let db = rusqlite::Connection::open(path)?;
|
||||
db.execute_batch(
|
||||
r#"
|
||||
CREATE TABLE IF NOT EXISTS config (
|
||||
key TEXT PRIMARY KEY,
|
||||
value ANY
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS events (
|
||||
id TEXT PRIMARY KEY,
|
||||
json TEXT
|
||||
);
|
||||
"#,
|
||||
)?;
|
||||
let (actor, secret) = ActorId::new(SignatureType::Ed25519);
|
||||
let resolver = Box::new(KVResolver);
|
||||
let room = Room::builder()
|
||||
.with_resolver(resolver)
|
||||
.with_hasher(HashType::Sha256)
|
||||
.with_signer(SignatureType::Ed25519)
|
||||
.create(&secret)?;
|
||||
db.execute(
|
||||
"INSERT INTO config VALUES (?, ?)",
|
||||
("actor_id", actor.to_string()),
|
||||
)?;
|
||||
db.execute(
|
||||
"INSERT INTO config VALUES (?, ?)",
|
||||
("actor_secret", serde_json::to_string(&secret)?),
|
||||
)?;
|
||||
for event in &room.events {
|
||||
db.execute(
|
||||
"INSERT INTO events (id, json) VALUES (?, ?)",
|
||||
(event.id().to_string(), serde_json::to_string(&event)?),
|
||||
)?;
|
||||
}
|
||||
Ok(State { db, room, secret })
|
||||
}
|
||||
(false, true) => {
|
||||
// restore repo
|
||||
let db = rusqlite::Connection::open(path)?;
|
||||
let actor: ActorId =
|
||||
db.query_row("SELECT value FROM config WHERE key='actor_id'", [], |row| {
|
||||
row.get(0).map(|s: String| s.parse())
|
||||
})??;
|
||||
let secret: ActorSecret = db.query_row(
|
||||
"SELECT value FROM config WHERE key='actor_secret'",
|
||||
[],
|
||||
|row| row.get(0).map(|s: String| serde_json::from_str(&s)),
|
||||
)??;
|
||||
dbg!(&actor, &secret);
|
||||
let mut q = db.prepare("SELECT json FROM events")?;
|
||||
let mut rows = q.query([])?;
|
||||
let mut room: Option<Room<KVEventContent, KVState>> = None;
|
||||
while let Some(row) = rows.next()? {
|
||||
let s: String = dbg!(row.get(0)?);
|
||||
let ev = dbg!(serde_json::from_str(&s)?);
|
||||
match &mut room {
|
||||
Some(r) => {
|
||||
r.append_event(ev)?;
|
||||
},
|
||||
None => {
|
||||
let resolver = Box::new(KVResolver);
|
||||
let r = Room::from_root(resolver, ev)?;
|
||||
room = Some(r);
|
||||
},
|
||||
}
|
||||
}
|
||||
drop(rows);
|
||||
drop(q);
|
||||
let room = room.unwrap();
|
||||
dbg!(&room);
|
||||
Ok(State { db, room, secret })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let cli = Cli::parse();
|
||||
match cli {
|
||||
Cli::Init { repo } => {
|
||||
get_repo(&repo, true)?;
|
||||
},
|
||||
Cli::Set { repo, key, value } => {
|
||||
let mut state = get_repo(&repo, false)?;
|
||||
state.create_event(CoreContent::Custom(KVEventContent::Set(key, value)))?;
|
||||
dbg!(&state.room);
|
||||
dbg!(&state.room.get_state());
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
use dag_resolve::{
|
||||
actor::ActorId,
|
||||
event::{CoreContent, HashType, SignatureType},
|
||||
resolvers::kv::{KVEventContent, KVResolver},
|
||||
room::Room,
|
||||
};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let (_actor, secret) = ActorId::new(SignatureType::Ed25519);
|
||||
let resolver = Box::new(KVResolver);
|
||||
let mut room = Room::builder()
|
||||
.with_resolver(resolver)
|
||||
.with_hasher(HashType::Sha256)
|
||||
.with_signer(SignatureType::Ed25519)
|
||||
.create(&secret)?;
|
||||
room.create_event(
|
||||
CoreContent::Custom(KVEventContent::Set("foo".into(), "apple".into())),
|
||||
&secret,
|
||||
)?;
|
||||
room.create_event(
|
||||
CoreContent::Custom(KVEventContent::Set("bar".into(), "banana".into())),
|
||||
&secret,
|
||||
)?;
|
||||
room.create_event(
|
||||
CoreContent::Custom(KVEventContent::Set("baz".into(), "carrot".into())),
|
||||
&secret,
|
||||
)?;
|
||||
dbg!(&room);
|
||||
dbg!(&room.get_state());
|
||||
Ok(())
|
||||
}
|
|
@ -4,13 +4,15 @@ use rand::{distributions::Alphanumeric, Rng};
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::result::Result as StdResult;
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::Error;
|
||||
use crate::{event::SignatureType, Result};
|
||||
|
||||
#[derive(Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct ActorId(ActorIdData);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct ActorSecret(ActorSecretData);
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
|
@ -162,7 +164,30 @@ impl Display for ActorId {
|
|||
ActorIdData::Ed25519(d) => (0x01, d.as_ref()),
|
||||
};
|
||||
let data: Vec<u8> = [prefix].into_iter().chain(bytes.to_vec()).collect();
|
||||
write!(f, "${}", b64engine.encode(data))
|
||||
write!(f, "^{}", b64engine.encode(data))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for ActorId {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self> {
|
||||
let s = s.strip_prefix('^').ok_or(Error::InvalidSigil)?;
|
||||
let bytes = b64engine.decode(s)?;
|
||||
match bytes.first() {
|
||||
Some(0x00) => {
|
||||
let id = String::from_utf8(bytes[1..].to_vec())?;
|
||||
Ok(ActorId(ActorIdData::Debug(id)))
|
||||
}
|
||||
Some(0x01) => Ok(ActorId(ActorIdData::Ed25519(
|
||||
bytes[1..].try_into().map_err(|_| Error::InvalidLength {
|
||||
expected: 32,
|
||||
got: bytes.len() - 1,
|
||||
})?,
|
||||
))),
|
||||
Some(_) => unimplemented!("unsupported signature type"),
|
||||
None => panic!("missing type byte"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,7 +196,7 @@ impl Serialize for ActorId {
|
|||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
serializer.serialize_str(&format!("^{}", self))
|
||||
serializer.serialize_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,30 +208,65 @@ impl<'de> Deserialize<'de> for ActorId {
|
|||
#[derive(Deserialize)]
|
||||
struct Wrapper(String);
|
||||
let wrapped = Wrapper::deserialize(deserializer)?;
|
||||
let bytes = b64engine
|
||||
.decode(wrapped.0)
|
||||
.map_err(serde::de::Error::custom)?;
|
||||
wrapped.0.parse().map_err(serde::de::Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for ActorSecret {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "ActorSecret {{ <redacted> }}")
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for ActorSecret {
|
||||
fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let (prefix, bytes) = match &self.0 {
|
||||
ActorSecretData::Debug(d) => (0x00, d.as_bytes().to_vec()),
|
||||
ActorSecretData::Ed25519(d) => (0x01, d.to_vec()),
|
||||
};
|
||||
let data: Vec<u8> = [prefix].into_iter().chain(bytes).collect();
|
||||
if serializer.is_human_readable() {
|
||||
serializer.serialize_str(&b64engine.encode(data))
|
||||
} else {
|
||||
serializer.serialize_bytes(&data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for ActorSecret {
|
||||
fn deserialize<D>(deserializer: D) -> StdResult<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum Wrapper {
|
||||
Blobby(Vec<u8>),
|
||||
Stringy(String),
|
||||
}
|
||||
let bytes = match Wrapper::deserialize(deserializer)? {
|
||||
Wrapper::Blobby(b) => b,
|
||||
Wrapper::Stringy(s) => b64engine.decode(s).map_err(serde::de::Error::custom)?,
|
||||
};
|
||||
match bytes.first() {
|
||||
Some(0x00) => {
|
||||
let id =
|
||||
String::from_utf8(bytes[1..].to_vec()).map_err(serde::de::Error::custom)?; // TODO: Error::invalid_data
|
||||
Ok(ActorId(ActorIdData::Debug(id)))
|
||||
let sig =
|
||||
String::from_utf8(bytes[1..].to_vec()).map_err(serde::de::Error::custom)?;
|
||||
Ok(ActorSecret(ActorSecretData::Debug(sig)))
|
||||
}
|
||||
Some(0x01) => {
|
||||
let key = bytes[1..].try_into().map_err(serde::de::Error::custom)?;
|
||||
Ok(ActorSecret(ActorSecretData::Ed25519(key)))
|
||||
}
|
||||
Some(0x01) => Ok(ActorId(ActorIdData::Ed25519(
|
||||
bytes[1..].try_into().map_err(serde::de::Error::custom)?, // TODO: Error::invalid_length
|
||||
))),
|
||||
Some(_) => unimplemented!("unsupported signature type"),
|
||||
None => panic!("missing type byte"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl Debug for ActorSecret {
|
||||
// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
// write!(f, "ActorSecret {{ <redacted> }}")
|
||||
// }
|
||||
// }
|
||||
|
||||
impl Debug for ActorSignature {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let (prefix, bytes) = match &self.0 {
|
||||
|
@ -228,7 +288,11 @@ impl Serialize for ActorSignature {
|
|||
ActorSignatureData::Ed25519(d) => (0x01, d.to_bytes().to_vec()),
|
||||
};
|
||||
let data: Vec<u8> = [prefix].into_iter().chain(bytes).collect();
|
||||
serializer.serialize_bytes(&data)
|
||||
if serializer.is_human_readable() {
|
||||
serializer.serialize_str(&b64engine.encode(data))
|
||||
} else {
|
||||
serializer.serialize_bytes(&data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,12 +301,16 @@ impl<'de> Deserialize<'de> for ActorSignature {
|
|||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
#[derive(Deserialize)]
|
||||
struct Wrapper(String);
|
||||
let wrapped = Wrapper::deserialize(deserializer)?;
|
||||
let bytes = b64engine
|
||||
.decode(wrapped.0)
|
||||
.map_err(serde::de::Error::custom)?;
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum Wrapper {
|
||||
Blobby(Vec<u8>),
|
||||
Stringy(String),
|
||||
}
|
||||
let bytes = match Wrapper::deserialize(deserializer)? {
|
||||
Wrapper::Blobby(b) => b,
|
||||
Wrapper::Stringy(s) => b64engine.decode(s).map_err(serde::de::Error::custom)?,
|
||||
};
|
||||
match bytes.first() {
|
||||
Some(0x00) => {
|
||||
let sig =
|
||||
|
|
|
@ -113,7 +113,7 @@ impl<T: Debug + Serialize + Clone> Event<T> {
|
|||
EventBuilder::new(content, actor)
|
||||
}
|
||||
|
||||
pub fn verify<S>(&self, room: &Room<T, S>) -> Result<()> {
|
||||
pub fn verify(&self) -> Result<()> {
|
||||
let mut shallow = EventVerify {
|
||||
id: None,
|
||||
content: self.content.clone(),
|
||||
|
@ -121,10 +121,6 @@ impl<T: Debug + Serialize + Clone> Event<T> {
|
|||
author: self.author.clone(),
|
||||
signature: None,
|
||||
};
|
||||
let room_config = match &room.get_root().content {
|
||||
CoreContent::Create(c) => c,
|
||||
_ => unreachable!("the root should always be a create event"),
|
||||
};
|
||||
|
||||
// verify id hash
|
||||
let value = serde_json::to_value(&shallow)?;
|
||||
|
@ -136,18 +132,37 @@ impl<T: Debug + Serialize + Clone> Event<T> {
|
|||
got: calculated_hash,
|
||||
});
|
||||
}
|
||||
if room_config.hasher != self.id.get_type() {
|
||||
return Err(Error::MismatchedHasher {
|
||||
expected: room_config.hasher,
|
||||
got: self.id.get_type(),
|
||||
});
|
||||
}
|
||||
shallow.id = Some(self.id.clone());
|
||||
|
||||
// verify signature
|
||||
let value = serde_json::to_value(&shallow)?;
|
||||
let data = dbg!(canonical_json::to_string(&value)?);
|
||||
self.author.verify(data.as_bytes(), &self.signature)?;
|
||||
if self.author.get_type() != self.signature.get_type() {
|
||||
return Err(Error::MismatchedSigner {
|
||||
expected: self.author.get_type(),
|
||||
got: self.signature.get_type(),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn verify_room<S>(&self, room: &Room<T, S>) -> Result<()> {
|
||||
self.verify()?;
|
||||
|
||||
let room_config = match &room.get_root().content {
|
||||
CoreContent::Create(c) => c,
|
||||
_ => unreachable!("the root should always be a create event"),
|
||||
};
|
||||
|
||||
if room_config.hasher != self.id.get_type() {
|
||||
return Err(Error::MismatchedHasher {
|
||||
expected: room_config.hasher,
|
||||
got: self.id.get_type(),
|
||||
});
|
||||
}
|
||||
|
||||
if room_config.signer != self.author.get_type()
|
||||
|| room_config.signer != self.signature.get_type()
|
||||
{
|
||||
|
@ -288,7 +303,7 @@ impl TryFrom<&str> for EventId {
|
|||
type Error = Error;
|
||||
|
||||
fn try_from(value: &str) -> Result<Self> {
|
||||
Ok(EventId::from_str(value)?)
|
||||
EventId::from_str(value)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ pub fn sort<T: Debug + Serialize + Clone>(
|
|||
.into_iter()
|
||||
.partition(|candidate| references.iter().any(|(_, child)| child == candidate.id()));
|
||||
unsorted = new_unsorted;
|
||||
children.sort_by(|a, b| tiebreak(a, b).then_with(|| a.id().cmp(&b.id())));
|
||||
children.sort_by(|a, b| tiebreak(a, b).then_with(|| a.id().cmp(b.id())));
|
||||
heads.extend(children);
|
||||
}
|
||||
assert!(unsorted.is_empty());
|
||||
|
|
|
@ -41,6 +41,17 @@ impl<T: Debug + Serialize + Clone, S> Room<T, S> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn from_root(
|
||||
resolver: Box<dyn Resolver<T, S>>,
|
||||
event: Event<T>,
|
||||
) -> Result<Self> {
|
||||
Ok(Self {
|
||||
heads: vec![event.id().clone()],
|
||||
events: vec![event],
|
||||
resolver,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_root(&self) -> &Event<T> {
|
||||
self.events
|
||||
.first()
|
||||
|
@ -58,20 +69,23 @@ impl<T: Debug + Serialize + Clone, S> Room<T, S> {
|
|||
resolver.resolve(&sorted)
|
||||
}
|
||||
|
||||
pub fn create_event(&mut self, event_content: CoreContent<T>, secret: &ActorSecret) -> Result<()> {
|
||||
pub fn create_event(&mut self, event_content: CoreContent<T>, secret: &ActorSecret) -> Result<&Event<T>> {
|
||||
let event = Event::builder(event_content, secret)
|
||||
.with_references(std::mem::take(&mut self.heads))
|
||||
.then_hash()?
|
||||
.and_sign()?;
|
||||
self.append_event(event);
|
||||
Ok(())
|
||||
self.append_event(event)
|
||||
}
|
||||
|
||||
pub fn append_event(&mut self, event: Event<T>) {
|
||||
event.verify(self).expect("event failed verification");
|
||||
let event_id = event.id().clone();
|
||||
pub fn append_event(&mut self, event: Event<T>) -> Result<&Event<T>> {
|
||||
event.verify_room(self).expect("event failed verification");
|
||||
if self.events.iter().any(|p| p == &event) {
|
||||
panic!("already exists");
|
||||
}
|
||||
self.events.push(event);
|
||||
self.heads = vec![event_id];
|
||||
let event_ref = self.events.last().unwrap();
|
||||
self.heads = vec![event_ref.id().clone()];
|
||||
Ok(event_ref)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,14 +95,20 @@ pub struct RoomBuilder<T, S> {
|
|||
signer: Option<SignatureType>,
|
||||
}
|
||||
|
||||
impl<T: Clone + Debug + Serialize, S> RoomBuilder<T, S> {
|
||||
pub fn new() -> Self {
|
||||
impl<T: Clone + Debug + Serialize, S> Default for RoomBuilder<T, S> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
resolver: None,
|
||||
hasher: None,
|
||||
signer: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone + Debug + Serialize, S> RoomBuilder<T, S> {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn with_resolver(mut self, resolver: Box<dyn Resolver<T, S>>) -> Self {
|
||||
self.resolver = Some(resolver);
|
||||
|
|
Loading…
Reference in a new issue