full functionality and first polish
This commit is contained in:
parent
e5f784abf9
commit
9ec99dc0be
|
@ -92,14 +92,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "async-global-executor"
|
||||
version = "2.0.4"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c290043c9a95b05d45e952fb6383c67bcb61471f60cfa21e890dba6654234f43"
|
||||
checksum = "5262ed948da60dd8956c6c5aca4d4163593dddb7b32d73267c93dab7b2e98940"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-executor",
|
||||
"async-io",
|
||||
"async-mutex",
|
||||
"async-lock",
|
||||
"blocking",
|
||||
"futures-lite",
|
||||
"num_cpus",
|
||||
|
@ -108,9 +108,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "async-io"
|
||||
version = "1.6.0"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a811e6a479f2439f0c04038796b5cfb3d2ad56c230e0f2d3f7b04d68cfee607b"
|
||||
checksum = "e5e18f61464ae81cde0a23e713ae8fd299580c54d697a35820cfd0625b8b0e07"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"futures-lite",
|
||||
|
@ -134,15 +134,6 @@ dependencies = [
|
|||
"event-listener",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-mutex"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-process"
|
||||
version = "1.4.0"
|
||||
|
@ -162,9 +153,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "async-std"
|
||||
version = "1.11.0"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52580991739c5cdb36cde8b2a516371c0a3b70dda36d916cc08b82372916808c"
|
||||
checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d"
|
||||
dependencies = [
|
||||
"async-attributes",
|
||||
"async-channel",
|
||||
|
@ -181,7 +172,6 @@ dependencies = [
|
|||
"kv-log-macro",
|
||||
"log",
|
||||
"memchr",
|
||||
"num_cpus",
|
||||
"once_cell",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
|
@ -239,9 +229,9 @@ checksum = "30696a84d817107fc028e049980e09d5e140e8da8f1caeb17e8e950658a3cea9"
|
|||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.53"
|
||||
version = "0.1.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600"
|
||||
checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -368,9 +358,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.9.1"
|
||||
version = "3.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
|
||||
checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"
|
||||
|
||||
[[package]]
|
||||
name = "byte-tools"
|
||||
|
@ -429,7 +419,7 @@ dependencies = [
|
|||
"libc",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"time 0.1.43",
|
||||
"time 0.1.44",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
|
@ -487,7 +477,7 @@ dependencies = [
|
|||
"rand",
|
||||
"sha2",
|
||||
"subtle",
|
||||
"time 0.3.9",
|
||||
"time 0.3.11",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
|
@ -511,26 +501,26 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.8"
|
||||
version = "0.9.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c"
|
||||
checksum = "07db9d94cbd326813772c968ccd25999e5f8ae22f4f8d1b11effa37ef6ce281d"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if 1.0.0",
|
||||
"crossbeam-utils",
|
||||
"lazy_static",
|
||||
"memoffset",
|
||||
"once_cell",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.8"
|
||||
version = "0.8.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
|
||||
checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"lazy_static",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -631,6 +621,15 @@ dependencies = [
|
|||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "4.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.3.7"
|
||||
|
@ -943,13 +942,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.6"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
|
||||
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"wasi 0.10.2+wasi-snapshot-preview1",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -970,9 +969,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
|||
|
||||
[[package]]
|
||||
name = "globset"
|
||||
version = "0.4.8"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10463d9ff00a2a068db14231982f5132edebad0d7660cd956a1c30292dbcbfbd"
|
||||
checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"bstr",
|
||||
|
@ -1006,7 +1005,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "golgi"
|
||||
version = "0.1.1"
|
||||
version = "0.2.4"
|
||||
source = "git+https://git.coopcloud.tech/golgi-ssb/golgi.git#9981b64bb23e1dbb95e31cfa1c545d23bb4f40d2"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"async-stream 0.3.3",
|
||||
|
@ -1016,6 +1016,7 @@ dependencies = [
|
|||
"kuska-handshake",
|
||||
"kuska-sodiumoxide",
|
||||
"kuska-ssb",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
|
@ -1036,15 +1037,15 @@ dependencies = [
|
|||
"indexmap",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util 0.7.1",
|
||||
"tokio-util 0.7.3",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.11.2"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
||||
checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
|
@ -1081,9 +1082,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.7"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff8670570af52249509a86f5e3e18a08c60b177071826898fde8997cf5f6bfbb"
|
||||
checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
|
@ -1092,9 +1093,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "http-body"
|
||||
version = "0.4.4"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6"
|
||||
checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http",
|
||||
|
@ -1127,9 +1128,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
|||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.18"
|
||||
version = "0.14.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2"
|
||||
checksum = "42dc3c131584288d375f2d07f822b0cb012d8c6fb899a5b9fdb3cb7eb9b6004f"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
|
@ -1169,9 +1170,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.8.1"
|
||||
version = "1.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
|
||||
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
|
@ -1224,15 +1225,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.1"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
||||
checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.57"
|
||||
version = "0.3.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397"
|
||||
checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
@ -1273,13 +1274,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "kuska-ssb"
|
||||
version = "0.4.0"
|
||||
source = "git+https://github.com/Kuska-ssb/ssb#fb7062de606e7c9cae8dd4df402a122db46c1b77"
|
||||
version = "0.4.1"
|
||||
source = "git+https://github.com/Kuska-ssb/ssb#315c7e31aa6255d5657665ce9357034113d2b552"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"async-stream 0.2.1",
|
||||
"base64 0.11.0",
|
||||
"dirs",
|
||||
"dirs 2.0.2",
|
||||
"futures",
|
||||
"get_if_addrs",
|
||||
"hex",
|
||||
|
@ -1316,9 +1317,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.125"
|
||||
version = "0.2.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b"
|
||||
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
||||
|
||||
[[package]]
|
||||
name = "libsodium-sys"
|
||||
|
@ -1354,9 +1355,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "loom"
|
||||
version = "0.5.4"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edc5c7d328e32cc4954e8e01193d7f0ef5ab257b5090b70a964e099a36034309"
|
||||
checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"generator",
|
||||
|
@ -1383,6 +1384,8 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"sled",
|
||||
"uri_encode",
|
||||
"xdg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1442,9 +1445,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "713d550d9b44d89174e066b7a6217ae06234c10cb47819a88290d2b353c31799"
|
||||
checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
|
@ -1492,7 +1495,7 @@ dependencies = [
|
|||
"mime",
|
||||
"spin",
|
||||
"tokio",
|
||||
"tokio-util 0.6.9",
|
||||
"tokio-util 0.6.10",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
|
@ -1574,9 +1577,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.10.0"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
|
||||
checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
|
@ -1609,9 +1612,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.0"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58"
|
||||
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core 0.9.3",
|
||||
|
@ -1815,11 +1818,11 @@ checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.38"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9027b48e9d4c9175fa2218adf3557f91c1137021739951d4932f5f8268ac48aa"
|
||||
checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1837,9 +1840,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.18"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
|
||||
checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
@ -1916,9 +1919,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.5.5"
|
||||
version = "1.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
|
||||
checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
@ -1936,9 +1939,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.25"
|
||||
version = "0.6.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||
checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
|
@ -1969,7 +1972,7 @@ dependencies = [
|
|||
"memchr",
|
||||
"multer",
|
||||
"num_cpus",
|
||||
"parking_lot 0.12.0",
|
||||
"parking_lot 0.12.1",
|
||||
"pin-project-lite",
|
||||
"rand",
|
||||
"ref-cast",
|
||||
|
@ -1978,10 +1981,10 @@ dependencies = [
|
|||
"serde",
|
||||
"state",
|
||||
"tempfile",
|
||||
"time 0.3.9",
|
||||
"time 0.3.11",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-util 0.7.1",
|
||||
"tokio-util 0.7.3",
|
||||
"ubyte",
|
||||
"version_check",
|
||||
"yansi",
|
||||
|
@ -2005,16 +2008,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rocket_dyn_templates"
|
||||
version = "0.1.0-rc.1"
|
||||
version = "0.1.0-rc.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c83f1287ad8fa034410928297a91db37518d5c46d7cc7e1e1b4a77aec0cd8807"
|
||||
checksum = "bab13df598440527c200f46fb944dc55d8d67a1818b617eb5a3981dcd8b63fd2"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"normpath",
|
||||
"notify",
|
||||
"rocket",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tera",
|
||||
]
|
||||
|
||||
|
@ -2040,22 +2041,22 @@ dependencies = [
|
|||
"smallvec",
|
||||
"stable-pattern",
|
||||
"state",
|
||||
"time 0.3.9",
|
||||
"time 0.3.11",
|
||||
"tokio",
|
||||
"uncased",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.6"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
|
||||
checksum = "a0a5f7c728f5d284929a1cccb5bc19884422bfe6ef4d6c409da2c41838983fcf"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.9"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
|
||||
checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
|
@ -2144,9 +2145,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.13"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "647c97df271007dcea485bb74ffdb57f2e683f1306c854f468a0c244badabf2d"
|
||||
checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
|
@ -2200,9 +2201,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.8.0"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
|
||||
checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
|
@ -2246,13 +2247,13 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.92"
|
||||
version = "1.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ff7c592601f11445996a06f8ad0c27f094a58857c2f89e97974ab9235b92c52"
|
||||
checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2271,9 +2272,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tera"
|
||||
version = "1.15.0"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3cac831b615c25bcef632d1cabf864fa05813baad3d526829db18eb70e8b58d"
|
||||
checksum = "7c9783d6ff395ae80cf17ed9a25360e7ba37742a79fa8fddabb073c5c7c8856d"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"chrono-tz",
|
||||
|
@ -2331,19 +2332,20 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.43"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
|
||||
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.9"
|
||||
version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd"
|
||||
checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"libc",
|
||||
|
@ -2359,14 +2361,14 @@ checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792"
|
|||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.18.2"
|
||||
version = "1.19.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4903bf0427cf68dddd5aa6a93220756f8be0c34fcfa9f5e6191e103e15a31395"
|
||||
checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"libc",
|
||||
"memchr",
|
||||
"mio 0.8.3",
|
||||
"mio 0.8.4",
|
||||
"num_cpus",
|
||||
"once_cell",
|
||||
"pin-project-lite",
|
||||
|
@ -2378,9 +2380,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "1.7.0"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7"
|
||||
checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -2389,9 +2391,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.8"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3"
|
||||
checksum = "df54d54117d6fdc4e4fea40fe1e4e566b3505700e148a6827e59b34b0d2600d9"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
|
@ -2400,9 +2402,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.6.9"
|
||||
version = "0.6.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0"
|
||||
checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
|
@ -2414,9 +2416,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.1"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0edfdeb067411dba2044da6d1cb2df793dd35add7888d73c16e3381ded401764"
|
||||
checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
|
@ -2437,15 +2439,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tower-service"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
|
||||
checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.34"
|
||||
version = "0.1.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09"
|
||||
checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"pin-project-lite",
|
||||
|
@ -2466,11 +2468,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.26"
|
||||
version = "0.1.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f"
|
||||
checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"once_cell",
|
||||
"valuable",
|
||||
]
|
||||
|
||||
|
@ -2517,9 +2519,9 @@ checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
|
|||
|
||||
[[package]]
|
||||
name = "ubyte"
|
||||
version = "0.10.1"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42756bb9e708855de2f8a98195643dff31a97f0485d90d8467b39dc24be9e8fe"
|
||||
checksum = "a58e29f263341a29bb79e14ad7fda5f63b1c7e48929bad4c685d7876b1d04e94"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
@ -2532,9 +2534,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
|
|||
|
||||
[[package]]
|
||||
name = "uncased"
|
||||
version = "0.9.6"
|
||||
version = "0.9.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5baeed7327e25054889b9bd4f975f32e5f4c5d434042d59ab6cd4142c0a76ed0"
|
||||
checksum = "09b01702b0fd0b3fadcf98e098780badda8742d4f4a7676615cad90e8ac73622"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"version_check",
|
||||
|
@ -2590,6 +2592,12 @@ dependencies = [
|
|||
"unic-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.3"
|
||||
|
@ -2606,6 +2614,12 @@ dependencies = [
|
|||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uri_encode"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34acb51c736f8784bdbca2692c3cc57213bfc1b329fd6eb7668d5e4af8f87ceb"
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.0"
|
||||
|
@ -2657,9 +2671,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.2+wasi-snapshot-preview1"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
|
@ -2669,9 +2683,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.80"
|
||||
version = "0.2.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad"
|
||||
checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"wasm-bindgen-macro",
|
||||
|
@ -2679,9 +2693,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.80"
|
||||
version = "0.2.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4"
|
||||
checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
|
@ -2694,9 +2708,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.30"
|
||||
version = "0.4.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f741de44b75e14c35df886aff5f1eb73aa114fa5d4d00dcd37b5e01259bf3b2"
|
||||
checksum = "de9a9cec1733468a8c657e57fa2413d2ae2c0129b95e87c5b72b8ace4d13f31f"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"js-sys",
|
||||
|
@ -2706,9 +2720,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.80"
|
||||
version = "0.2.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5"
|
||||
checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
|
@ -2716,9 +2730,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.80"
|
||||
version = "0.2.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b"
|
||||
checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -2729,15 +2743,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.80"
|
||||
version = "0.2.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744"
|
||||
checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.57"
|
||||
version = "0.3.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283"
|
||||
checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
|
@ -2848,6 +2862,15 @@ dependencies = [
|
|||
"winapi-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xdg"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c4583db5cbd4c4c0303df2d15af80f0539db703fa1c68802d4cbbd2dd0f88f6"
|
||||
dependencies = [
|
||||
"dirs 4.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "0.5.1"
|
||||
|
|
10
Cargo.toml
10
Cargo.toml
|
@ -2,18 +2,24 @@
|
|||
name = "lykin"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors = ["glyph <glyph@mycelial.technology>"]
|
||||
readme = "README.md"
|
||||
description = "Symbiosis of SSB, key-value store and web server."
|
||||
repository = "https://git.coopcloud.tech/glyph/lykin"
|
||||
keywords = ["scuttlebutt", "ssb", "decentralized", "peer-for-peer", "p4p"]
|
||||
|
||||
[dependencies]
|
||||
async-std = "1.10"
|
||||
bincode = "1.3"
|
||||
chrono = "0.4"
|
||||
uri_encode = "1"
|
||||
env_logger = "0.9"
|
||||
futures = "0.3"
|
||||
#golgi = { git = "https://git.coopcloud.tech/golgi-ssb/golgi.git" }
|
||||
golgi = { path = "../golgi" }
|
||||
golgi = { git = "https://git.coopcloud.tech/golgi-ssb/golgi.git" }
|
||||
log = "0.4"
|
||||
rocket = "0.5.0-rc.1"
|
||||
rocket_dyn_templates = { version = "0.1.0-rc.1", features = ["tera"] }
|
||||
serde = "1"
|
||||
serde_json = "1"
|
||||
sled = "0.34"
|
||||
xdg = "2.4.1"
|
||||
|
|
131
src/db.rs
131
src/db.rs
|
@ -15,22 +15,65 @@ use log::{debug, info};
|
|||
use serde::{Deserialize, Serialize};
|
||||
use sled::{Batch, Db, IVec, Result, Tree};
|
||||
|
||||
/// The latest sequence number of a Scuttlebutt peer.
|
||||
/// Scuttlebutt peer data.
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct Peer {
|
||||
/// The public key of the peer, also known as an SSB ID.
|
||||
pub public_key: String,
|
||||
/// The sequence number of the most recent post stored for this peer.
|
||||
pub latest_sequence: u64,
|
||||
//pub name: String,
|
||||
//pub posts: u16,
|
||||
/// The name of the peer.
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
impl Peer {
|
||||
/// Create a new instance of the Peer struct using the given public
|
||||
/// key. Default values are set for latest_sequence and name.
|
||||
pub fn new(public_key: &str) -> Peer {
|
||||
Peer {
|
||||
public_key: public_key.to_string(),
|
||||
latest_sequence: 0,
|
||||
name: "".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Modify the name field of an instance of the Peer struct, leaving
|
||||
/// the other values unchanged.
|
||||
pub fn set_name(self, name: &str) -> Peer {
|
||||
Self {
|
||||
name: name.to_string(),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
/// Modify the latest_sequence field of an instance of the Peer struct,
|
||||
/// leaving the other values unchanged.
|
||||
pub fn set_latest_sequence(self, latest_sequence: u64) -> Peer {
|
||||
Self {
|
||||
latest_sequence,
|
||||
..self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The text and metadata of a Scuttlebutt root post.
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct Post {
|
||||
/// The key of the post-type message, also known as a message reference.
|
||||
pub key: String,
|
||||
/// The text of the post (may be formatted as markdown).
|
||||
pub text: String,
|
||||
/// The date the post was published (e.g. 17 May 2021).
|
||||
pub date: String,
|
||||
/// The sequence number of the post-type message.
|
||||
pub sequence: u64,
|
||||
/// The read state of the post; true if read, false if unread.
|
||||
pub read: bool,
|
||||
/// The timestamp representing the date the post was published.
|
||||
pub timestamp: i64,
|
||||
/// The subject of the post, represented as the first 53 characters of
|
||||
/// the post text.
|
||||
pub subject: Option<String>,
|
||||
}
|
||||
|
||||
/// Convenience type which facilitates converting an IVec into a String.
|
||||
|
@ -57,13 +100,16 @@ impl From<IVec> for IVecString {
|
|||
}
|
||||
|
||||
/// An instance of the key-value database and relevant trees.
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone)]
|
||||
pub struct Database {
|
||||
/// Stores the sled database instance.
|
||||
/// The sled database instance.
|
||||
db: Db,
|
||||
/// Stores the public keys of all the peers we are subscribed to.
|
||||
/// A database tree containing Peer struct instances for all the peers
|
||||
/// we are subscribed to.
|
||||
peer_tree: Tree,
|
||||
/// Stores the posts (content and metadata) for all the feeds we are subscribed to.
|
||||
/// A database tree containing Post struct instances for all of the posts
|
||||
/// we have downloaded from the peer to whom we subscribe.
|
||||
pub post_tree: Tree,
|
||||
}
|
||||
|
||||
|
@ -74,16 +120,16 @@ impl Database {
|
|||
// Open the database at the given path.
|
||||
// The database will be created if it does not yet exist.
|
||||
// This code will panic if an IO error is encountered.
|
||||
info!("initialising the sled database");
|
||||
let db = sled::open(path).expect("failed to open database");
|
||||
debug!("opening the 'peers' database tree");
|
||||
info!("Initialising sled database");
|
||||
let db = sled::open(path).expect("Failed to open database");
|
||||
debug!("Opening 'peers' database tree");
|
||||
let peer_tree = db
|
||||
.open_tree("peers")
|
||||
.expect("failed to open database peers tree");
|
||||
debug!("opening the 'posts' database tree");
|
||||
.expect("Failed to open database peers tree");
|
||||
debug!("Opening 'posts' database tree");
|
||||
let post_tree = db
|
||||
.open_tree("posts")
|
||||
.expect("failed to open database posts tree");
|
||||
.expect("Failed to open database posts tree");
|
||||
|
||||
Database {
|
||||
db,
|
||||
|
@ -94,8 +140,10 @@ impl Database {
|
|||
|
||||
/// Add a peer to the database by inserting the public key into the peer
|
||||
/// tree.
|
||||
pub fn add_peer(&self, public_key: &str) -> Result<Option<IVec>> {
|
||||
self.peer_tree.insert(&public_key, vec![0])
|
||||
pub fn add_peer(&self, peer: Peer) -> Result<Option<IVec>> {
|
||||
let peer_bytes = bincode::serialize(&peer).unwrap();
|
||||
|
||||
self.peer_tree.insert(&peer.public_key, peer_bytes)
|
||||
}
|
||||
|
||||
/// Remove a peer from the database, as represented by the given public
|
||||
|
@ -104,15 +152,31 @@ impl Database {
|
|||
self.peer_tree.remove(&public_key).map(|_| ())
|
||||
}
|
||||
|
||||
/// Get a list of all peers in the peer tree. The public key of each peer
|
||||
/// is returned.
|
||||
pub fn get_peers(&self) -> Vec<String> {
|
||||
/// Get a single peer from the peer tree, defined by the given public key.
|
||||
/// The byte value for the matching entry, if found, is deserialized from
|
||||
/// bincode into an instance of the Peer struct.
|
||||
pub fn get_peer(&self, public_key: &str) -> Result<Option<Peer>> {
|
||||
let peer = self
|
||||
.peer_tree
|
||||
.get(public_key.as_bytes())
|
||||
.unwrap()
|
||||
.map(|peer| bincode::deserialize(&peer).unwrap());
|
||||
|
||||
Ok(peer)
|
||||
}
|
||||
|
||||
/// Get a list of all peers in the peer tree. The byte value for each
|
||||
/// peer entry is deserialized from bincode into an instance of the Peer
|
||||
/// struct.
|
||||
pub fn get_peers(&self) -> Vec<Peer> {
|
||||
let mut peers = Vec::new();
|
||||
|
||||
self.peer_tree
|
||||
.iter()
|
||||
.keys()
|
||||
.map(|bytes| IVecString::from(bytes.unwrap()))
|
||||
.map(|ivec_string| ivec_string.string)
|
||||
.collect()
|
||||
.map(|peer| peer.unwrap())
|
||||
.for_each(|peer| peers.push(bincode::deserialize(&peer.1).unwrap()));
|
||||
|
||||
peers
|
||||
}
|
||||
|
||||
/// Add a post to the database by inserting an instance of the Post struct
|
||||
|
@ -148,8 +212,9 @@ impl Database {
|
|||
}
|
||||
|
||||
/// Get a list of all posts in the post tree authored by the given public
|
||||
/// key. The byte value for each matching entry is deserialized from
|
||||
/// bincode into an instance of the Post struct.
|
||||
/// key and sort them by timestamp in descending order. The byte value for
|
||||
/// each matching entry is deserialized from bincode into an instance of
|
||||
/// the Post struct.
|
||||
pub fn get_posts(&self, public_key: &str) -> Result<Vec<Post>> {
|
||||
let mut posts = Vec::new();
|
||||
|
||||
|
@ -158,6 +223,8 @@ impl Database {
|
|||
.map(|post| post.unwrap())
|
||||
.for_each(|post| posts.push(bincode::deserialize(&post.1).unwrap()));
|
||||
|
||||
posts.sort_by(|a: &Post, b: &Post| b.timestamp.cmp(&a.timestamp));
|
||||
|
||||
Ok(posts)
|
||||
}
|
||||
|
||||
|
@ -188,4 +255,22 @@ impl Database {
|
|||
// map the Option to ().
|
||||
self.post_tree.remove(post_key.as_bytes()).map(|_| ())
|
||||
}
|
||||
|
||||
/// Sum the total number of unread posts for the peer represented by the
|
||||
/// given public key.
|
||||
pub fn get_unread_post_count(&self, public_key: &str) -> u16 {
|
||||
let mut unread_post_counter = 0;
|
||||
|
||||
self.post_tree
|
||||
.scan_prefix(public_key.as_bytes())
|
||||
.map(|post| post.unwrap())
|
||||
.for_each(|post| {
|
||||
let deserialized_post: Post = bincode::deserialize(&post.1).unwrap();
|
||||
if !deserialized_post.read {
|
||||
unread_post_counter += 1
|
||||
}
|
||||
});
|
||||
|
||||
unread_post_counter
|
||||
}
|
||||
}
|
||||
|
|
35
src/main.rs
35
src/main.rs
|
@ -4,7 +4,7 @@ mod sbot;
|
|||
mod task_loop;
|
||||
mod utils;
|
||||
|
||||
use std::{env, path::Path};
|
||||
use std::env;
|
||||
|
||||
use async_std::channel;
|
||||
use log::info;
|
||||
|
@ -14,6 +14,7 @@ use rocket::{
|
|||
launch, routes,
|
||||
};
|
||||
use rocket_dyn_templates::Template;
|
||||
use xdg::BaseDirectories;
|
||||
|
||||
use crate::{db::Database, routes::*, task_loop::Task};
|
||||
|
||||
|
@ -25,18 +26,30 @@ pub struct WhoAmI {
|
|||
async fn rocket() -> _ {
|
||||
env_logger::init();
|
||||
|
||||
let public_key: String = sbot::whoami().await.expect("whoami sbot call failed");
|
||||
// Retrieve and store the public key of the local sbot.
|
||||
let public_key: String = sbot::whoami()
|
||||
.await
|
||||
.expect("whoami rpc call failed. please ensure the sbot is running before trying again");
|
||||
info!("Public key of the local sbot instance: {}", public_key);
|
||||
let whoami = WhoAmI { public_key };
|
||||
|
||||
let db = Database::init(Path::new("lykin_db"));
|
||||
// Create the key-value database.
|
||||
let xdg_dirs = BaseDirectories::with_prefix("lykin").unwrap();
|
||||
let db_path = xdg_dirs
|
||||
.place_config_file("database")
|
||||
.expect("cannot create database directory");
|
||||
let db = Database::init(&db_path);
|
||||
let db_clone = db.clone();
|
||||
|
||||
// Create a message passing channel.
|
||||
let (tx, rx) = channel::unbounded();
|
||||
let tx_clone = tx.clone();
|
||||
|
||||
task_loop::spawn(rx, db_clone).await;
|
||||
// Spawn the task loop.
|
||||
info!("Spawning task loop");
|
||||
task_loop::spawn(db_clone, rx).await;
|
||||
|
||||
info!("launching the web server");
|
||||
info!("Launching web server");
|
||||
rocket::build()
|
||||
.manage(db)
|
||||
.manage(whoami)
|
||||
|
@ -45,19 +58,21 @@ async fn rocket() -> _ {
|
|||
"/",
|
||||
routes![
|
||||
home,
|
||||
delete_post,
|
||||
download_latest_posts,
|
||||
mark_post_read,
|
||||
mark_post_unread,
|
||||
post,
|
||||
posts,
|
||||
subscribe_form,
|
||||
unsubscribe_form,
|
||||
posts,
|
||||
post,
|
||||
mark_post_read,
|
||||
mark_post_unread
|
||||
],
|
||||
)
|
||||
.mount("/", FileServer::from(relative!("static")))
|
||||
.attach(Template::fairing())
|
||||
.attach(AdHoc::on_shutdown("cancel task loop", |_| {
|
||||
Box::pin(async move {
|
||||
tx_clone.send(Task::Cancel).await;
|
||||
tx_clone.send(Task::Cancel).await.unwrap();
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
|
166
src/routes.rs
166
src/routes.rs
|
@ -1,14 +1,17 @@
|
|||
use async_std::channel::Sender;
|
||||
use log::{debug, warn};
|
||||
use markdown;
|
||||
use rocket::{form::Form, get, post, response::Redirect, uri, FromForm, State};
|
||||
use rocket_dyn_templates::{tera::Context, Template};
|
||||
use uri_encode;
|
||||
|
||||
use crate::{db::Database, sbot, task_loop::Task, utils, WhoAmI};
|
||||
use crate::{
|
||||
db::{Database, Peer},
|
||||
sbot,
|
||||
task_loop::Task,
|
||||
utils, WhoAmI,
|
||||
};
|
||||
|
||||
#[derive(FromForm)]
|
||||
pub struct Peer {
|
||||
pub struct PeerForm {
|
||||
pub public_key: String,
|
||||
}
|
||||
|
||||
|
@ -17,19 +20,44 @@ pub async fn home(db: &State<Database>) -> Template {
|
|||
let peers = db.get_peers();
|
||||
|
||||
let mut context = Context::new();
|
||||
context.insert("peers", &peers);
|
||||
let mut peers_unread = Vec::new();
|
||||
|
||||
for peer in peers {
|
||||
let unread_count = db.get_unread_post_count(&peer.public_key);
|
||||
peers_unread.push((peer, unread_count.to_string()));
|
||||
}
|
||||
|
||||
context.insert("peers", &peers_unread);
|
||||
|
||||
Template::render("base", &context.into_json())
|
||||
}
|
||||
|
||||
#[get("/posts/<public_key>/<msg_id>/delete")]
|
||||
pub async fn delete_post(db: &State<Database>, public_key: &str, msg_id: &str) -> Redirect {
|
||||
// Delete the post from the database. This method cannot panic, so we're
|
||||
// safe to unwrap the result.
|
||||
db.remove_post(public_key, msg_id).unwrap();
|
||||
|
||||
Redirect::to(uri!(posts(public_key)))
|
||||
}
|
||||
|
||||
#[get("/posts/<public_key>")]
|
||||
pub async fn posts(db: &State<Database>, public_key: &str) -> Template {
|
||||
let peers = db.get_peers();
|
||||
let posts = db.get_posts(public_key).unwrap();
|
||||
|
||||
let mut context = Context::new();
|
||||
let mut peers_unread = Vec::new();
|
||||
|
||||
for peer in peers {
|
||||
let unread_count = db.get_unread_post_count(&peer.public_key);
|
||||
peers_unread.push((peer, unread_count.to_string()));
|
||||
}
|
||||
|
||||
context.insert("peers", &peers_unread);
|
||||
|
||||
let posts = db.get_posts(public_key).unwrap();
|
||||
|
||||
context.insert("selected_peer", &public_key);
|
||||
context.insert("peers", &peers);
|
||||
context.insert("posts", &posts);
|
||||
|
||||
Template::render("base", &context.into_json())
|
||||
|
@ -38,10 +66,20 @@ pub async fn posts(db: &State<Database>, public_key: &str) -> Template {
|
|||
#[get("/posts/<public_key>/<msg_id>")]
|
||||
pub async fn post(db: &State<Database>, public_key: &str, msg_id: &str) -> Template {
|
||||
let peers = db.get_peers();
|
||||
|
||||
let mut context = Context::new();
|
||||
let mut peers_unread = Vec::new();
|
||||
|
||||
for peer in peers {
|
||||
let unread_count = db.get_unread_post_count(&peer.public_key);
|
||||
peers_unread.push((peer, unread_count.to_string()));
|
||||
}
|
||||
|
||||
context.insert("peers", &peers_unread);
|
||||
|
||||
let posts = db.get_posts(public_key).unwrap();
|
||||
let post = db.get_post(public_key, msg_id).unwrap();
|
||||
|
||||
let mut context = Context::new();
|
||||
context.insert("selected_peer", &public_key);
|
||||
context.insert(
|
||||
"selected_peer_encoded",
|
||||
|
@ -52,9 +90,7 @@ pub async fn post(db: &State<Database>, public_key: &str, msg_id: &str) -> Templ
|
|||
"selected_post_encoded",
|
||||
&uri_encode::encode_uri_component(msg_id),
|
||||
);
|
||||
context.insert("peers", &peers);
|
||||
context.insert("posts", &posts);
|
||||
// TODO: consider converting markdown to html here
|
||||
context.insert("post", &post);
|
||||
context.insert("post_is_selected", &true);
|
||||
|
||||
|
@ -93,44 +129,76 @@ pub async fn mark_post_unread(db: &State<Database>, public_key: &str, msg_id: &s
|
|||
Redirect::to(uri!(post(public_key, msg_id)))
|
||||
}
|
||||
|
||||
#[get("/posts/download_latest")]
|
||||
pub async fn download_latest_posts(db: &State<Database>, tx: &State<Sender<Task>>) -> Redirect {
|
||||
for peer in db.get_peers() {
|
||||
// Fetch the latest root posts authored by each peer we're
|
||||
// subscribed to. Posts will be added to the key-value database.
|
||||
if let Err(e) = tx
|
||||
.send(Task::FetchLatestPosts(peer.public_key.clone()))
|
||||
.await
|
||||
{
|
||||
warn!("task loop error: {}", e)
|
||||
}
|
||||
|
||||
// Fetch the latest name for each peer we're subscribed to and update
|
||||
// the database.
|
||||
if let Err(e) = tx.send(Task::FetchLatestName(peer.public_key)).await {
|
||||
warn!("task loop error: {}", e)
|
||||
}
|
||||
}
|
||||
|
||||
Redirect::to(uri!(home))
|
||||
}
|
||||
|
||||
#[post("/subscribe", data = "<peer>")]
|
||||
pub async fn subscribe_form(
|
||||
db: &State<Database>,
|
||||
whoami: &State<WhoAmI>,
|
||||
tx: &State<Sender<Task>>,
|
||||
peer: Form<Peer>,
|
||||
peer: Form<PeerForm>,
|
||||
) -> Redirect {
|
||||
if utils::validate_public_key(&peer.public_key).is_ok() {
|
||||
debug!("public key {} is valid", &peer.public_key);
|
||||
// TODO: consider getting the peer name here so we can insert it
|
||||
match db.add_peer(&peer.public_key) {
|
||||
Ok(_) => {
|
||||
debug!("added {} to peer tree in database", &peer.public_key);
|
||||
// TODO: i don't think we actually want to follow...
|
||||
// we might still have the data in our ssb db, even if we don't follow
|
||||
match sbot::is_following(&whoami.public_key, &peer.public_key).await {
|
||||
Ok(status) if status.as_str() == "false" => {
|
||||
match sbot::follow_peer(&peer.public_key).await {
|
||||
Ok(_) => debug!("followed {}", &peer.public_key),
|
||||
Err(e) => warn!("failed to follow {}: {}", &peer.public_key, e),
|
||||
}
|
||||
}
|
||||
Ok(status) if status.as_str() == "true" => {
|
||||
debug!("we already follow {}", &peer.public_key)
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
let peer = peer.public_key.to_string();
|
||||
// Fetch all root posts authored by the peer we're subscribing
|
||||
// to. Posts will be added to the key-value database.
|
||||
if let Err(e) = tx.send(Task::FetchAll(peer)).await {
|
||||
warn!("task loop error: {}", e)
|
||||
}
|
||||
|
||||
// Retrieve the name of the peer to which we are subscribing.
|
||||
let peer_name = match sbot::get_name(&peer.public_key).await {
|
||||
Ok(name) => name,
|
||||
Err(e) => {
|
||||
warn!("failed to fetch name for {}: {}", &peer.public_key, e);
|
||||
String::from("")
|
||||
}
|
||||
Err(_e) => warn!(
|
||||
};
|
||||
let peer_info = Peer::new(&peer.public_key).set_name(&peer_name);
|
||||
|
||||
// Add the peer to the database and then check the follow state.
|
||||
// Follow the peer if our local instance is not already following.
|
||||
if db.add_peer(peer_info).is_ok() {
|
||||
debug!("added {} to peer tree in database", &peer.public_key);
|
||||
match sbot::is_following(&whoami.public_key, &peer.public_key).await {
|
||||
Ok(status) if status.as_str() == "false" => {
|
||||
match sbot::follow_peer(&peer.public_key).await {
|
||||
Ok(_) => debug!("followed {}", &peer.public_key),
|
||||
Err(e) => warn!("failed to follow {}: {}", &peer.public_key, e),
|
||||
}
|
||||
}
|
||||
Ok(status) if status.as_str() == "true" => {
|
||||
debug!("we already follow {}", &peer.public_key)
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let peer_id = peer.public_key.to_string();
|
||||
// Fetch all root posts authored by the peer we're subscribing
|
||||
// to. Posts will be added to the key-value database.
|
||||
if let Err(e) = tx.send(Task::FetchAllPosts(peer_id)).await {
|
||||
warn!("task loop error: {}", e)
|
||||
}
|
||||
} else {
|
||||
warn!(
|
||||
"failed to add {} to peer tree in database",
|
||||
&peer.public_key
|
||||
),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
warn!("{} is invalid", &peer.public_key);
|
||||
|
@ -140,20 +208,18 @@ pub async fn subscribe_form(
|
|||
}
|
||||
|
||||
#[post("/unsubscribe", data = "<peer>")]
|
||||
pub fn unsubscribe_form(db: &State<Database>, peer: Form<Peer>) -> Redirect {
|
||||
// validate the public key
|
||||
match utils::validate_public_key(&peer.public_key) {
|
||||
Ok(_) => {
|
||||
debug!("public key {} is valid", &peer.public_key);
|
||||
match db.remove_peer(&peer.public_key) {
|
||||
Ok(_) => debug!("removed {} from peer tree in database", &peer.public_key),
|
||||
Err(_e) => warn!(
|
||||
"failed to remove {} from peer tree in database",
|
||||
&peer.public_key
|
||||
),
|
||||
}
|
||||
pub fn unsubscribe_form(db: &State<Database>, peer: Form<PeerForm>) -> Redirect {
|
||||
if let Err(e) = utils::validate_public_key(&peer.public_key) {
|
||||
warn!("{} is invalid: {}", &peer.public_key, e)
|
||||
} else {
|
||||
debug!("public key {} is valid", &peer.public_key);
|
||||
match db.remove_peer(&peer.public_key) {
|
||||
Ok(_) => debug!("removed {} from peer tree in database", &peer.public_key),
|
||||
Err(_e) => warn!(
|
||||
"failed to remove {} from peer tree in database",
|
||||
&peer.public_key
|
||||
),
|
||||
}
|
||||
Err(e) => warn!("{} is invalid: {}", &peer.public_key, e),
|
||||
}
|
||||
|
||||
Redirect::to(uri!(home))
|
||||
|
|
69
src/sbot.rs
69
src/sbot.rs
|
@ -3,30 +3,39 @@
|
|||
use async_std::stream::StreamExt;
|
||||
use chrono::NaiveDateTime;
|
||||
use golgi::{
|
||||
api::friends::RelationshipQuery,
|
||||
api::{friends::RelationshipQuery, history_stream::CreateHistoryStream},
|
||||
messages::{SsbMessageContentType, SsbMessageKVT},
|
||||
sbot::Keystore,
|
||||
GolgiError, Sbot,
|
||||
};
|
||||
use log::warn;
|
||||
use log::{debug, info, warn};
|
||||
use serde_json::value::Value;
|
||||
|
||||
use crate::db::Post;
|
||||
|
||||
/// Initialise a connection to a Scuttlebutt server.
|
||||
async fn init_sbot() -> Result<Sbot, String> {
|
||||
let keystore = Keystore::GoSbot;
|
||||
let ip_port = Some("127.0.0.1:8021".to_string());
|
||||
let net_id = None;
|
||||
|
||||
debug!("Initialising the sbot connection");
|
||||
Sbot::init(keystore, ip_port, net_id)
|
||||
.await
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
/// Return the public key of the local sbot instance.
|
||||
pub async fn whoami() -> Result<String, String> {
|
||||
let mut sbot = Sbot::init(Keystore::Patchwork, None, None)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
let mut sbot = init_sbot().await?;
|
||||
|
||||
info!("Executing `whoami` call");
|
||||
sbot.whoami().await.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
/// Follow a peer.
|
||||
pub async fn follow_peer(public_key: &str) -> Result<String, String> {
|
||||
let mut sbot = Sbot::init(Keystore::Patchwork, None, None)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
let mut sbot = init_sbot().await?;
|
||||
|
||||
sbot.follow(public_key).await.map_err(|e| e.to_string())
|
||||
}
|
||||
|
@ -35,9 +44,7 @@ pub async fn follow_peer(public_key: &str) -> Result<String, String> {
|
|||
///
|
||||
/// Is peer A (`public_key_a`) following peer B (`public_key_b`)?
|
||||
pub async fn is_following(public_key_a: &str, public_key_b: &str) -> Result<String, String> {
|
||||
let mut sbot = Sbot::init(Keystore::Patchwork, None, None)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
let mut sbot = init_sbot().await?;
|
||||
|
||||
let query = RelationshipQuery {
|
||||
source: public_key_a.to_string(),
|
||||
|
@ -54,17 +61,29 @@ pub async fn is_following(public_key_a: &str, public_key_b: &str) -> Result<Stri
|
|||
/// This returns all messages regardless of type.
|
||||
pub async fn get_message_stream(
|
||||
public_key: &str,
|
||||
sequence_number: u64,
|
||||
) -> impl futures::Stream<Item = Result<SsbMessageKVT, GolgiError>> {
|
||||
let mut sbot = Sbot::init(Keystore::Patchwork, None, None)
|
||||
.await
|
||||
.map_err(|e| e.to_string())
|
||||
.unwrap();
|
||||
let mut sbot = init_sbot().await.unwrap();
|
||||
|
||||
sbot.create_history_stream(public_key.to_string())
|
||||
let history_stream_args = CreateHistoryStream::new(public_key.to_string())
|
||||
.keys_values(true, true)
|
||||
.after_seq(sequence_number);
|
||||
|
||||
sbot.create_history_stream(history_stream_args)
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Return the name (self-identifier) for the peer associated with the given
|
||||
/// public key.
|
||||
///
|
||||
/// The public key of the peer will be returned if a name is not found.
|
||||
pub async fn get_name(public_key: &str) -> Result<String, String> {
|
||||
let mut sbot = init_sbot().await?;
|
||||
|
||||
sbot.get_name(public_key).await.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
/// Filter a stream of messages and return a vector of root posts.
|
||||
///
|
||||
/// Each returned vector element includes the key of the post, the content
|
||||
|
@ -72,7 +91,8 @@ pub async fn get_message_stream(
|
|||
/// and whether it is read or unread.
|
||||
pub async fn get_root_posts(
|
||||
history_stream: impl futures::Stream<Item = Result<SsbMessageKVT, GolgiError>>,
|
||||
) -> Vec<Post> {
|
||||
) -> (u64, Vec<Post>) {
|
||||
let mut latest_sequence = 0;
|
||||
let mut posts = Vec::new();
|
||||
|
||||
futures::pin_mut!(history_stream);
|
||||
|
@ -84,18 +104,23 @@ pub async fn get_root_posts(
|
|||
let content = msg.value.content.to_owned();
|
||||
if let Value::Object(content_map) = content {
|
||||
if !content_map.contains_key("root") {
|
||||
let timestamp_int = msg.value.timestamp.round() as i64 / 1000;
|
||||
let datetime = NaiveDateTime::from_timestamp(timestamp_int, 0);
|
||||
let timestamp = msg.value.timestamp.round() as i64 / 1000;
|
||||
let datetime = NaiveDateTime::from_timestamp(timestamp, 0);
|
||||
let date = datetime.format("%d %b %Y").to_string();
|
||||
|
||||
let text = content_map.get_key_value("text").unwrap();
|
||||
let text = content_map.get_key_value("text").unwrap().1.to_string();
|
||||
let subject = text.get(0..52).map(|s| s.to_string());
|
||||
|
||||
latest_sequence = msg.value.sequence;
|
||||
|
||||
posts.push(Post {
|
||||
key: msg.key.to_owned(),
|
||||
text: text.1.to_string(),
|
||||
text,
|
||||
timestamp,
|
||||
date,
|
||||
sequence: msg.value.sequence,
|
||||
read: false,
|
||||
subject,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -108,5 +133,5 @@ pub async fn get_root_posts(
|
|||
}
|
||||
}
|
||||
|
||||
posts
|
||||
(latest_sequence, posts)
|
||||
}
|
||||
|
|
|
@ -1,42 +1,89 @@
|
|||
use async_std::{channel::Receiver, task};
|
||||
use log::{debug, info, warn};
|
||||
use log::{info, warn};
|
||||
|
||||
use crate::{db::Database, sbot};
|
||||
|
||||
pub enum Task {
|
||||
Cancel,
|
||||
FetchAll(String),
|
||||
//FetchLatest(String),
|
||||
FetchAllPosts(String),
|
||||
FetchLatestPosts(String),
|
||||
FetchLatestName(String),
|
||||
}
|
||||
|
||||
pub async fn spawn(rx: Receiver<Task>, db: Database) {
|
||||
async fn fetch_posts_and_update_db(db: &Database, peer_id: String, after_sequence: u64) {
|
||||
let peer_msgs = sbot::get_message_stream(&peer_id, after_sequence).await;
|
||||
let (latest_sequence, root_posts) = sbot::get_root_posts(peer_msgs).await;
|
||||
|
||||
match db.add_post_batch(&peer_id, root_posts) {
|
||||
Ok(_) => {
|
||||
info!(
|
||||
"Inserted batch of posts into database post tree for peer: {}",
|
||||
&peer_id
|
||||
)
|
||||
}
|
||||
Err(e) => warn!(
|
||||
"Failed to insert batch of posts into database post tree for peer: {}: {}",
|
||||
&peer_id, e
|
||||
),
|
||||
}
|
||||
|
||||
// Update the value of the latest sequence number for
|
||||
// the peer (this is stored in the database).
|
||||
if let Ok(Some(peer)) = db.get_peer(&peer_id) {
|
||||
db.add_peer(peer.set_latest_sequence(latest_sequence))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
async fn fetch_name_and_update_db(db: &Database, peer_id: String) {
|
||||
match sbot::get_name(&peer_id).await {
|
||||
Ok(name) => {
|
||||
if let Ok(Some(peer)) = db.get_peer(&peer_id) {
|
||||
let updated_peer = peer.set_name(&name);
|
||||
match db.add_peer(updated_peer) {
|
||||
Ok(_) => info!("Updated name for peer: {}", &peer_id),
|
||||
Err(e) => {
|
||||
warn!("Failed to update name for peer: {}: {}", &peer_id, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => warn!("Failed to fetch name for {}: {}", &peer_id, e),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn spawn(db: Database, rx: Receiver<Task>) {
|
||||
task::spawn(async move {
|
||||
while let Ok(task) = rx.recv().await {
|
||||
match task {
|
||||
// Fetch all messages authored by the given peer, filter
|
||||
// the root posts and insert them into the peer tree of the
|
||||
// the root posts and insert them into the posts tree of the
|
||||
// database.
|
||||
Task::FetchAll(peer) => {
|
||||
let peer_msgs = sbot::get_message_stream(&peer).await;
|
||||
// TODO: return a tuple from sbot::get_root_posts
|
||||
//let (root_posts, latest_sequence) = sbot::get_root_posts(peer_msgs).await;
|
||||
// TODO: update the sequence number if required
|
||||
//if latest_sequence > db.get_latest_sequence(&peer) {
|
||||
// db.update_sequence(&peer, latest_sequence)
|
||||
//}
|
||||
let root_posts = sbot::get_root_posts(peer_msgs).await;
|
||||
match db.add_post_batch(&peer, root_posts) {
|
||||
Ok(_) => debug!("inserted batch of posts into post tree for {}", &peer),
|
||||
Err(e) => warn!(
|
||||
"failed to insert batch of posts into post tree for {}: {}",
|
||||
&peer, e
|
||||
),
|
||||
Task::FetchAllPosts(peer_id) => {
|
||||
info!("Fetching all posts for peer: {}", peer_id);
|
||||
fetch_posts_and_update_db(&db, peer_id, 0).await;
|
||||
}
|
||||
// Fetch only the latest messages authored by the given peer,
|
||||
// ie. messages with sequence numbers greater than those
|
||||
// which are already stored in the database.
|
||||
//
|
||||
// Retrieve the root posts from those messages and insert them
|
||||
// into the posts tree of the database.
|
||||
Task::FetchLatestPosts(peer_id) => {
|
||||
if let Ok(Some(peer)) = db.get_peer(&peer_id) {
|
||||
info!("Fetching latest posts for peer: {}", peer_id);
|
||||
fetch_posts_and_update_db(&db, peer_id, peer.latest_sequence).await;
|
||||
}
|
||||
}
|
||||
// TODO: fetch all msgs with sequence number > peer.latest_sequence for peer
|
||||
//Task::FetchLatest(peer) => {
|
||||
// Fetch the latest name for the given peer and update the
|
||||
// peer entry in the peers tree of the database.
|
||||
Task::FetchLatestName(peer_id) => {
|
||||
info!("Fetching latest name for peer: {}", peer_id);
|
||||
fetch_name_and_update_db(&db, peer_id).await;
|
||||
}
|
||||
// Break out of the task loop.
|
||||
Task::Cancel => {
|
||||
info!("exiting task loop...");
|
||||
info!("Exiting task loop...");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
10
src/utils.rs
10
src/utils.rs
|
@ -2,26 +2,26 @@
|
|||
///
|
||||
/// Return an error string if the key is invalid.
|
||||
pub fn validate_public_key(public_key: &str) -> Result<(), String> {
|
||||
// ensure the id starts with the correct sigil link
|
||||
// Ensure the ID starts with the correct sigil link.
|
||||
if !public_key.starts_with('@') {
|
||||
return Err("expected '@' sigil as first character".to_string());
|
||||
}
|
||||
|
||||
// find the dot index denoting the start of the algorithm definition tag
|
||||
// Find the dot index denoting the start of the algorithm definition tag.
|
||||
let dot_index = match public_key.rfind('.') {
|
||||
Some(index) => index,
|
||||
None => return Err("no dot index was found".to_string()),
|
||||
};
|
||||
|
||||
// check hashing algorithm (must end with ".ed25519")
|
||||
// Check the hashing algorithm (must end with ".ed25519").
|
||||
if !&public_key.ends_with(".ed25519") {
|
||||
return Err("hashing algorithm must be ed25519".to_string());
|
||||
}
|
||||
|
||||
// obtain the base64 portion (substring) of the public key
|
||||
// Obtain the base64 portion (substring) of the public key.
|
||||
let base64_str = &public_key[1..dot_index];
|
||||
|
||||
// length of a base64 encoded ed25519 public key
|
||||
// Ensure the length of the base64 encoded ed25519 public key is correct.
|
||||
if base64_str.len() != 44 {
|
||||
return Err("base64 data length is incorrect".to_string());
|
||||
}
|
||||
|
|
|
@ -1,34 +1,6 @@
|
|||
.nav {
|
||||
background-color: lightgreen;
|
||||
border: 5px solid #19A974;
|
||||
border-radius: 15px;
|
||||
grid-area: nav;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.peers {
|
||||
background-color: lightblue;
|
||||
border: 5px solid #357EDD;
|
||||
border-radius: 15px;
|
||||
grid-area: peers;
|
||||
}
|
||||
|
||||
.posts {
|
||||
background-color: bisque;
|
||||
border: 5px solid #FF6300;
|
||||
border-radius: 15px;
|
||||
grid-area: posts;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.post > ul {
|
||||
padding-left: 25px;
|
||||
padding-right: 25px;
|
||||
}
|
||||
|
||||
.content {
|
||||
background-color: lightyellow;
|
||||
border: 5px solid #FFD700;
|
||||
border: 5px solid #ffd700;
|
||||
border-radius: 15px;
|
||||
grid-area: content;
|
||||
padding: 1.5rem;
|
||||
|
@ -42,34 +14,9 @@
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
.flex-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
*/
|
||||
|
||||
.grid-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
grid-template-rows: 1fr 3fr 4fr;
|
||||
grid-template-areas:
|
||||
'nav nav nav nav nav'
|
||||
'peers posts posts posts posts'
|
||||
'peers content content content content';
|
||||
grid-gap: 10px;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
padding-top: 5px;
|
||||
overflow: hidden;
|
||||
height: 85vh;
|
||||
}
|
||||
|
||||
.grid-container > div {
|
||||
/* background-color: rgba(255, 255, 255, 0.8); */
|
||||
/* text-align: center; */
|
||||
/* padding: 20px 0; */
|
||||
/* font-size: 30px; */
|
||||
.disabled {
|
||||
opacity: 0.4;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.flex-container {
|
||||
|
@ -82,4 +29,119 @@
|
|||
margin: 5px;
|
||||
}
|
||||
|
||||
a { text-decoration: none; color: black; }
|
||||
.grid-container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: 1fr 1fr 1fr 3fr;
|
||||
grid-template-areas:
|
||||
'nav'
|
||||
'peers'
|
||||
'posts'
|
||||
'content';
|
||||
grid-gap: 10px;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
padding-top: 5px;
|
||||
overflow: hidden;
|
||||
height: 85vh;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 600px) {
|
||||
.grid-container {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
grid-template-rows: 1fr 3fr 4fr;
|
||||
grid-template-areas:
|
||||
'nav nav nav nav nav'
|
||||
'peers posts posts posts posts'
|
||||
'peers content content content content';
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.nav {
|
||||
background-color: lightgreen;
|
||||
border: 5px solid #19a974;
|
||||
border-radius: 15px;
|
||||
grid-area: nav;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.peers {
|
||||
background-color: lightblue;
|
||||
border: 5px solid #357edd;
|
||||
border-radius: 15px;
|
||||
grid-area: peers;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.peers > ul {
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
.peers > ul > li > a {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.peers > ul > li > a > p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.post > ul {
|
||||
padding-left: 25px;
|
||||
padding-right: 25px;
|
||||
}
|
||||
|
||||
.posts {
|
||||
background-color: bisque;
|
||||
border: 5px solid #ff6300;
|
||||
border-radius: 15px;
|
||||
grid-area: posts;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.posts > ul {
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.posts > ul > li > a {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.posts > ul > li > a > p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.selected {
|
||||
background-color: #f9c587;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
}
|
||||
|
||||
code {
|
||||
word-wrap: anywhere;
|
||||
}
|
||||
|
||||
form {
|
||||
margin-left: auto;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 55px;
|
||||
}
|
||||
|
||||
li {
|
||||
list-style: none;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,9 @@
|
|||
<link rel="stylesheet" href="/css/lykin.css">
|
||||
</head>
|
||||
<body class="container">
|
||||
<a href="/"><h1 style="margin-left: 15px;">lykin</h1></a>
|
||||
<a href="/">
|
||||
<h1>lykin</h1>
|
||||
</a>
|
||||
<div class="grid-container">
|
||||
{% include "topbar" %}
|
||||
{% include "peer_list" %}
|
||||
|
|
|
@ -1,9 +1,18 @@
|
|||
<div class="peers" style="text-align: center;">
|
||||
<ul style="padding-left: 0;">
|
||||
<div class="peers">
|
||||
<ul>
|
||||
{% for peer in peers -%}
|
||||
<li style="list-style: none; font-size: 12px;">
|
||||
<a href="/posts/{{ peer | replace(from="/", to="%2F") }}">
|
||||
<code style="word-wrap: anywhere;{% if selected_peer and peer == selected_peer %} font-weight: bold;{% endif %}">{{ peer }}</code>
|
||||
<li>
|
||||
<a class="flex-container" href="/posts/{{ peer.0.public_key | urlencode_strict }}">
|
||||
<code{% if selected_peer and peer.0.public_key == selected_peer %} style="font-weight: bold;"{% endif %}>
|
||||
{% if peer.0.name %}
|
||||
{{ peer.0.name }}
|
||||
{% else %}
|
||||
{{ peer.0.public_key }}
|
||||
{% endif %}
|
||||
</code>
|
||||
<p style="font-weight: bold; padding-right: 1rem;">
|
||||
{% if peer.1 != "0" %}{{ peer.1 }}{% endif %}
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
{%- endfor %}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<div class="posts">
|
||||
{% if posts %}
|
||||
<ul style="padding-left: 25px; padding-right: 25px;">
|
||||
<ul>
|
||||
{% for post in posts -%}
|
||||
<li style="list-style: none; font-size: 12px; margin-bottom: 5px;{% if selected_post and post.key == selected_post %} background-color: #FF6300;{% endif %}">
|
||||
<a class="flex-container" style="justify-content: space-between;{% if not post.read %} font-weight: bold;{% endif %}" href="/posts/{{ selected_peer | urlencode_strict }}/{{ post.key | urlencode_strict }}">
|
||||
<code style="word-wrap: anywhere;">{{ post.key }}</code>
|
||||
<p style="margin: 0;">{{ post.date }}</p>
|
||||
<li{% if selected_post and post.key == selected_post %} class="selected"{% endif %}>
|
||||
<a class="flex-container"{% if not post.read %} style="font-weight: bold;"{% endif %} href="/posts/{{ selected_peer | urlencode_strict }}/{{ post.key | urlencode_strict }}">
|
||||
<code>{% if post.subject %}{{ post.subject | trim_start_matches(pat='"') }}...{% else %}{{ post.text | trim_start_matches(pat='"') | trim_end_matches(pat='"') }}{% endif %}</code>
|
||||
<p>{{ post.date }}</p>
|
||||
</a>
|
||||
</li>
|
||||
{%- endfor %}
|
||||
|
|
|
@ -1,19 +1,44 @@
|
|||
<div class="nav">
|
||||
<div class="flex-container">
|
||||
<a href="/" title="Download latest posts"><img src="/icons/download.png" style="width: 55px;"></a>
|
||||
<a href="/posts/download_latest" title="Download latest posts">
|
||||
<img src="/icons/download.png">
|
||||
</a>
|
||||
{% if post_is_selected %}
|
||||
{% if post.read %}
|
||||
{% set mark_unread_url = "/posts/" ~ selected_peer_encoded ~ "/" ~ selected_post_encoded ~ "/unread" %}
|
||||
<a href={{ mark_unread_url }} style="margin-left: 20px;" title="Mark as unread"><img src="/icons/unread_post.png" style="width: 55px;"></a>
|
||||
<a class="disabled icon" title="Mark as read">
|
||||
<img src="/icons/read_post.png">
|
||||
</a>
|
||||
<a href={{ mark_unread_url }} class="icon" title="Mark as unread">
|
||||
<img src="/icons/unread_post.png">
|
||||
</a>
|
||||
{% else %}
|
||||
{% set mark_read_url = "/posts/" ~ selected_peer_encoded ~ "/" ~ selected_post_encoded ~ "/read" %}
|
||||
<a href={{ mark_read_url }} style="margin-left: 20px;" title="Mark as read"><img src="/icons/read_post.png" style="width: 55px;"></a>
|
||||
<a href={{ mark_read_url }} class="icon" title="Mark as read">
|
||||
<img src="/icons/read_post.png">
|
||||
</a>
|
||||
<a class="disabled icon" title="Mark as unread">
|
||||
<img src="/icons/unread_post.png">
|
||||
</a>
|
||||
{% endif %}
|
||||
<a href="/" style="margin-left: 20px;" title="Delete post"><img src="/icons/delete_post.png" style="width: 55px;"></a>
|
||||
{% set delete_post_url = "/posts/" ~ selected_peer_encoded ~ "/" ~ selected_post_encoded ~ "/delete" %}
|
||||
<a href={{ delete_post_url }} class="icon" title="Delete post">
|
||||
<img src="/icons/delete_post.png">
|
||||
</a>
|
||||
{% else %}
|
||||
<a class="disabled icon" title="Mark as read">
|
||||
<img src="/icons/read_post.png">
|
||||
</a>
|
||||
<a class="disabled icon" title="Mark as unread">
|
||||
<img src="/icons/unread_post.png">
|
||||
</a>
|
||||
<a class="disabled icon" title="Delete post">
|
||||
<img src="/icons/delete_post.png">
|
||||
</a>
|
||||
{% endif %}
|
||||
<form class="flex-container" style="margin-left: auto; margin-right: 10px;" action="/subscribe" method="post">
|
||||
<form class="flex-container" action="/subscribe" method="post">
|
||||
<label for="public_key">Public Key</label>
|
||||
<input type="text" id="public_key" name="public_key" size=50 maxlength=53>
|
||||
<input type="text" id="public_key" name="public_key" maxlength=53>
|
||||
<input type="submit" value="Subscribe">
|
||||
<input type="submit" value="Unsubscribe" formaction="/unsubscribe">
|
||||
</form>
|
||||
|
|
Loading…
Reference in New Issue