From 0bbce25d397707260cc6a876d2084da154ecb5fa Mon Sep 17 00:00:00 2001 From: Tony Klink Date: Tue, 23 Jan 2024 10:30:47 -0600 Subject: [PATCH] Add pubkey ban support Temporary use nostr-db as a db backend due to breaking API change in the library --- Cargo.lock | 715 +++++------------------------- Cargo.toml | 7 +- src/bussy/mod.rs | 16 +- src/noose/db.rs | 6 +- src/noose/mod.rs | 28 +- src/noose/nostr_db.rs | 111 +++++ src/noose/sled.rs | 294 +++++------- src/relay/ws.rs | 45 +- src/utils/config.rs | 33 +- src/utils/mod.rs | 2 +- src/utils/nostr_filter_helpers.rs | 216 +++++---- src/utils/structs.rs | 5 +- 12 files changed, 561 insertions(+), 917 deletions(-) create mode 100644 src/noose/nostr_db.rs diff --git a/Cargo.lock b/Cargo.lock index 3a4412b..632b141 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,7 +35,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" dependencies = [ "cfg-if", - "getrandom", "once_cell", "version_check", ] @@ -99,15 +98,6 @@ dependencies = [ "syn 2.0.28", ] -[[package]] -name = "atoi" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" -dependencies = [ - "num-traits", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -211,9 +201,6 @@ name = "bitflags" version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" -dependencies = [ - "serde", -] [[package]] name = "blake2" @@ -319,12 +306,6 @@ dependencies = [ "inout", ] -[[package]] -name = "const-oid" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" - [[package]] name = "core-foundation-sys" version = "0.8.4" @@ -340,21 +321,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crc" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" - [[package]] name = "crc32fast" version = "1.3.2" @@ -417,14 +383,45 @@ dependencies = [ ] [[package]] -name = "der" -version = "0.7.8" +name = "deadpool" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +checksum = "421fe0f90f2ab22016f32a9881be5134fdd71c65298917084b0c7477cbc3856e" dependencies = [ - "const-oid", - "pem-rfc7468", - "zeroize", + "async-trait", + "deadpool-runtime", + "num_cpus", + "retain_mut", + "tokio", +] + +[[package]] +name = "deadpool-runtime" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63dfa964fe2a66f3fde91fc70b267fe193d822c7e603e2a675a49a7f46ad3f49" +dependencies = [ + "tokio", +] + +[[package]] +name = "deadpool-sqlite" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e026821eaacbce25ff0d54405e4421d71656fcae3e4a9323461280fcda6dbc7d" +dependencies = [ + "deadpool", + "deadpool-sync", + "rusqlite", +] + +[[package]] +name = "deadpool-sync" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8db70494c13cae4ce67b4b4dafdaf828cf0df7237ab5b9e2fcabee4965d0a0a" +dependencies = [ + "deadpool-runtime", ] [[package]] @@ -434,25 +431,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", - "const-oid", "crypto-common", "subtle", ] -[[package]] -name = "dotenvy" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" - [[package]] name = "either" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" -dependencies = [ - "serde", -] [[package]] name = "encoding_rs" @@ -491,27 +478,16 @@ dependencies = [ ] [[package]] -name = "etcetera" -version = "0.8.0" +name = "fallible-iterator" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" -dependencies = [ - "cfg-if", - "home", - "windows-sys", -] +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] -name = "event-listener" -version = "2.5.3" +name = "fallible-streaming-iterator" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - -[[package]] -name = "fastrand" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" [[package]] name = "filetime" @@ -526,10 +502,14 @@ dependencies = [ ] [[package]] -name = "finl_unicode" -version = "1.2.0" +name = "flatbuffers" +version = "23.5.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" +checksum = "4dac53e22462d78c16d64a1cd22371b54cc3fe94aa15e7886a2fa6e5d1ab8640" +dependencies = [ + "bitflags 1.3.2", + "rustc_version", +] [[package]] name = "flate2" @@ -573,17 +553,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "flume" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" -dependencies = [ - "futures-core", - "futures-sink", - "spin 0.9.8", -] - [[package]] name = "fnv" version = "1.0.7" @@ -625,34 +594,6 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" -[[package]] -name = "futures-executor" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-intrusive" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" -dependencies = [ - "futures-core", - "lock_api", - "parking_lot 0.12.1", -] - -[[package]] -name = "futures-io" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" - [[package]] name = "futures-macro" version = "0.3.28" @@ -683,11 +624,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-core", - "futures-io", "futures-macro", "futures-sink", "futures-task", - "memchr", "pin-project-lite", "pin-utils", "slab", @@ -811,9 +750,6 @@ name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -dependencies = [ - "unicode-segmentation", -] [[package]] name = "hermit-abi" @@ -821,36 +757,12 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - [[package]] name = "hex_lit" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" -[[package]] -name = "hkdf" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" -dependencies = [ - "hmac", -] - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - [[package]] name = "home" version = "0.5.5" @@ -1041,15 +953,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.9" @@ -1076,9 +979,6 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -dependencies = [ - "spin 0.5.2", -] [[package]] name = "libc" @@ -1086,17 +986,11 @@ version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" -[[package]] -name = "libm" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" - [[package]] name = "libsqlite3-sys" -version = "0.26.0" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326" +checksum = "29f835d03d717946d28b1d1ed632eb6f0e24a299388ee623d0c23118d3e8a7fa" dependencies = [ "cc", "pkg-config", @@ -1125,16 +1019,6 @@ version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" -[[package]] -name = "md-5" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" -dependencies = [ - "cfg-if", - "digest", -] - [[package]] name = "memchr" version = "2.6.3" @@ -1166,12 +1050,6 @@ dependencies = [ "unicase", ] -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "miniz_oxide" version = "0.7.1" @@ -1216,21 +1094,11 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e664971378a3987224f7a0e10059782035e89899ae403718ee07de85bec42afe" -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - [[package]] name = "nostr" -version = "0.26.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72adfa99eb5f1e5afa3f1fe6503c89989b7b0b61c4e5ec23c5b839967cd54da1" +checksum = "3e47228d958fd65ef3e04650a3b1dd80f16f10f0243c80ed969556dead0f48c8" dependencies = [ "aes", "base64 0.21.2", @@ -1240,6 +1108,7 @@ dependencies = [ "chacha20", "getrandom", "instant", + "js-sys", "negentropy", "once_cell", "reqwest", @@ -1247,6 +1116,39 @@ dependencies = [ "serde_json", "tracing", "url-fork", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "nostr-database" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa0550256c8d4f0aaf74891ac986bd5ba46b2957c2c7e20f51838fa5819285f8" +dependencies = [ + "async-trait", + "flatbuffers", + "nostr", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "nostr-sqlite" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f0d3672bf705c0b1f1b1dc6682e397eafd8df4b379170136bbb52280ab76fd7" +dependencies = [ + "async-trait", + "deadpool-sqlite", + "nostr", + "nostr-database", + "rusqlite", + "thiserror", + "tokio", + "tracing", ] [[package]] @@ -1258,44 +1160,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "num-bigint-dig" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" -dependencies = [ - "byteorder", - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand", - "smallvec", - "zeroize", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.16" @@ -1303,7 +1167,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", - "libm", ] [[package]] @@ -1348,9 +1211,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "parking_lot" @@ -1411,21 +1274,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "paste" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" - -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] - [[package]] name = "percent-encoding" version = "2.3.0" @@ -1464,27 +1312,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pkcs1" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" -dependencies = [ - "der", - "pkcs8", - "spki", -] - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - [[package]] name = "pkg-config" version = "0.3.27" @@ -1662,10 +1489,16 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.22.6", + "webpki-roots", "winreg", ] +[[package]] +name = "retain_mut" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4389f1d5789befaf6029ebd9f7dac4af7f7e3d61b69d4f30e2ac02b57e7712b0" + [[package]] name = "ring" version = "0.16.20" @@ -1682,25 +1515,17 @@ dependencies = [ ] [[package]] -name = "rsa" -version = "0.9.2" +name = "rusqlite" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ab43bb47d23c1a631b4b680199a45255dce26fa9ab2fa902581f624ff13e6a8" +checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a" dependencies = [ - "byteorder", - "const-oid", - "digest", - "num-bigint-dig", - "num-integer", - "num-iter", - "num-traits", - "pkcs1", - "pkcs8", - "rand_core", - "signature", - "spki", - "subtle", - "zeroize", + "bitflags 1.3.2", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", ] [[package]] @@ -1709,6 +1534,15 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.6" @@ -1841,16 +1675,6 @@ dependencies = [ "sea-query-derive", ] -[[package]] -name = "sea-query-binder" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36bbb68df92e820e4d5aeb17b4acd5cc8b5d18b2c36a4dd6f4626aabfa7ab1b9" -dependencies = [ - "sea-query", - "sqlx", -] - [[package]] name = "sea-query-derive" version = "0.4.1" @@ -1885,6 +1709,12 @@ dependencies = [ "cc", ] +[[package]] +name = "semver" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" + [[package]] name = "serde" version = "1.0.181" @@ -1911,6 +1741,7 @@ version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" dependencies = [ + "indexmap 2.0.0", "itoa", "ryu", "serde", @@ -1948,17 +1779,6 @@ dependencies = [ "digest", ] -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -1968,16 +1788,6 @@ dependencies = [ "libc", ] -[[package]] -name = "signature" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" -dependencies = [ - "digest", - "rand_core", -] - [[package]] name = "slab" version = "0.4.8" @@ -2023,15 +1833,14 @@ dependencies = [ "lazy_static", "log", "nostr", + "nostr-sqlite", "regex", "rustls 0.21.6", "sailfish", "sea-query", - "sea-query-binder", "serde", "serde_json", "sled", - "sqlx", "thiserror", "tokio", "tokio-stream", @@ -2061,238 +1870,6 @@ name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] - -[[package]] -name = "spki" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "sqlformat" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b7b278788e7be4d0d29c0f39497a0eef3fba6bbc8e70d8bf7fde46edeaa9e85" -dependencies = [ - "itertools", - "nom", - "unicode_categories", -] - -[[package]] -name = "sqlx" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e50c216e3624ec8e7ecd14c6a6a6370aad6ee5d8cfc3ab30b5162eeeef2ed33" -dependencies = [ - "sqlx-core", - "sqlx-macros", - "sqlx-mysql", - "sqlx-postgres", - "sqlx-sqlite", -] - -[[package]] -name = "sqlx-core" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d6753e460c998bbd4cd8c6f0ed9a64346fcca0723d6e75e52fdc351c5d2169d" -dependencies = [ - "ahash", - "atoi", - "byteorder", - "bytes", - "crc", - "crossbeam-queue", - "dotenvy", - "either", - "event-listener", - "futures-channel", - "futures-core", - "futures-intrusive", - "futures-io", - "futures-util", - "hashlink", - "hex", - "indexmap 2.0.0", - "log", - "memchr", - "once_cell", - "paste", - "percent-encoding", - "rustls 0.21.6", - "rustls-pemfile", - "serde", - "serde_json", - "sha2", - "smallvec", - "sqlformat", - "thiserror", - "tokio", - "tokio-stream", - "tracing", - "url", - "webpki-roots 0.24.0", -] - -[[package]] -name = "sqlx-macros" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a793bb3ba331ec8359c1853bd39eed32cdd7baaf22c35ccf5c92a7e8d1189ec" -dependencies = [ - "proc-macro2", - "quote", - "sqlx-core", - "sqlx-macros-core", - "syn 1.0.109", -] - -[[package]] -name = "sqlx-macros-core" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4ee1e104e00dedb6aa5ffdd1343107b0a4702e862a84320ee7cc74782d96fc" -dependencies = [ - "dotenvy", - "either", - "heck", - "hex", - "once_cell", - "proc-macro2", - "quote", - "serde", - "serde_json", - "sha2", - "sqlx-core", - "sqlx-mysql", - "sqlx-sqlite", - "syn 1.0.109", - "tempfile", - "tokio", - "url", -] - -[[package]] -name = "sqlx-mysql" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "864b869fdf56263f4c95c45483191ea0af340f9f3e3e7b4d57a61c7c87a970db" -dependencies = [ - "atoi", - "base64 0.21.2", - "bitflags 2.3.3", - "byteorder", - "bytes", - "crc", - "digest", - "dotenvy", - "either", - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "generic-array", - "hex", - "hkdf", - "hmac", - "itoa", - "log", - "md-5", - "memchr", - "once_cell", - "percent-encoding", - "rand", - "rsa", - "serde", - "sha1", - "sha2", - "smallvec", - "sqlx-core", - "stringprep", - "thiserror", - "tracing", - "whoami", -] - -[[package]] -name = "sqlx-postgres" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb7ae0e6a97fb3ba33b23ac2671a5ce6e3cabe003f451abd5a56e7951d975624" -dependencies = [ - "atoi", - "base64 0.21.2", - "bitflags 2.3.3", - "byteorder", - "crc", - "dotenvy", - "etcetera", - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "hex", - "hkdf", - "hmac", - "home", - "itoa", - "log", - "md-5", - "memchr", - "once_cell", - "rand", - "serde", - "serde_json", - "sha1", - "sha2", - "smallvec", - "sqlx-core", - "stringprep", - "thiserror", - "tracing", - "whoami", -] - -[[package]] -name = "sqlx-sqlite" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59dc83cf45d89c555a577694534fcd1b55c545a816c816ce51f20bbe56a4f3f" -dependencies = [ - "atoi", - "flume", - "futures-channel", - "futures-core", - "futures-executor", - "futures-intrusive", - "futures-util", - "libsqlite3-sys", - "log", - "percent-encoding", - "serde", - "sqlx-core", - "tracing", - "url", -] - -[[package]] -name = "stringprep" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" -dependencies = [ - "finl_unicode", - "unicode-bidi", - "unicode-normalization", -] [[package]] name = "subtle" @@ -2322,19 +1899,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "tempfile" -version = "3.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" -dependencies = [ - "cfg-if", - "fastrand", - "redox_syscall 0.3.5", - "rustix", - "windows-sys", -] - [[package]] name = "thiserror" version = "1.0.48" @@ -2605,18 +2169,6 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-segmentation" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" - -[[package]] -name = "unicode_categories" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" - [[package]] name = "untrusted" version = "0.7.1" @@ -2859,21 +2411,6 @@ dependencies = [ "webpki", ] -[[package]] -name = "webpki-roots" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b291546d5d9d1eab74f069c77749f2cb8504a12caa20f0f2de93ddbf6f411888" -dependencies = [ - "rustls-webpki", -] - -[[package]] -name = "whoami" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" - [[package]] name = "winapi" version = "0.3.9" @@ -2988,9 +2525,3 @@ checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi", ] - -[[package]] -name = "zeroize" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" diff --git a/Cargo.toml b/Cargo.toml index 2060a8c..0ab54d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,15 +17,16 @@ futures-util = "0.3.28" rustls = "0.21" anyhow = "1.0" sled = "0.34.7" -sqlx = { version = "0.7", features = [ "runtime-tokio", "tls-rustls", "sqlite", "migrate", "macros"] } +# sqlx = { version = "0.7", features = [ "runtime-tokio", "tls-rustls", "sqlite", "migrate", "macros"] } flexi_logger = { version = "0.27.3", features = [ "async", "compress" ] } lazy_static = "1.4.0" log = "0.4" -nostr = "0.26.0" +nostr = "0.27.0" +nostr-sqlite = "0.27.0" regex = "1.9.5" sailfish = "0.7.0" sea-query = { version = "0.30.4", features = ["backend-sqlite", "thread-safe"] } -sea-query-binder = { version = "0.5.0", features = ["sqlx-sqlite"] } +# sea-query-binder = { version = "0.5.0", features = ["sqlx-sqlite"] } serde = "1.0" serde_json = "1.0" thiserror = "1.0.48" diff --git a/src/bussy/mod.rs b/src/bussy/mod.rs index 4ec2f0b..5fdfb72 100644 --- a/src/bussy/mod.rs +++ b/src/bussy/mod.rs @@ -1,5 +1,6 @@ use crate::{ noose::user::{User, UserRow}, + noose::sled::BanInfo, utils::{error::Error, structs::Subscription}, }; use nostr::secp256k1::XOnlyPublicKey; @@ -11,6 +12,7 @@ pub mod channels { pub static MSG_NIP05: &str = "MSG_NIP05"; pub static MSG_RELAY: &str = "MSG_RELAY"; pub static MSG_PIPELINE: &str = "MSG_PIPELINE"; + pub static MSG_SLED: &str = "MSG_SLED"; } #[derive(Debug, Clone, PartialEq)] @@ -19,6 +21,7 @@ pub enum Command { DbReqWriteEvent(/* client_id */ uuid::Uuid, Box), DbReqFindEvent(/* client_id*/ uuid::Uuid, Subscription), DbReqDeleteEvents(/* client_id*/ uuid::Uuid, Box), + DbReqEventCounts(/* client_id*/ uuid::Uuid, Subscription), // Old messages DbReqInsertUser(UserRow), @@ -27,15 +30,16 @@ pub enum Command { DbReqGetAccount(String), DbReqClear, // DbResponse - DbResRelayMessage( + DbResRelayMessages( /* client_id*/ uuid::Uuid, - /* Vec */ Vec, + /* Vec */ Vec, ), DbResInfo, DbResOk, DbResOkWithStatus(/* client_id */ uuid::Uuid, nostr::RelayMessage), DbResAccount, // TODO: Add Account DTO as a param DbResUser(UserRow), + DbResEventCounts(/* client_id */ uuid::Uuid, nostr::RelayMessage), // Event Pipeline PipelineReqEvent(/* client_id */ uuid::Uuid, Box), PipelineResRelayMessageOk(/* client_id */ uuid::Uuid, nostr::RelayMessage), @@ -43,6 +47,14 @@ pub enum Command { PipelineResOk, // Subscription Errors ClientSubscriptionError(/* error message */ String), + // Sled + SledReqBanUser(Box), + SledReqBanInfo(/* pubkey */ String), + SledReqUnbanUser(/* pubkey */ String), + SledReqGetBans, + SledResBan(Option), + SledResBans(Vec), + SledResSuccess(bool), // Other Str(String), ServiceError(Error), diff --git a/src/noose/db.rs b/src/noose/db.rs index a14abd6..cb56a8a 100644 --- a/src/noose/db.rs +++ b/src/noose/db.rs @@ -9,11 +9,9 @@ use std::sync::Arc; pub trait Noose: Send + Sync { async fn start(&mut self, pubsub: Arc) -> Result<(), Error>; - async fn migration_up(&self); - async fn write_event(&self, event: Box) -> Result; - async fn delete_events(&self, event_ids: Box) -> Result; + async fn find_event(&self, subscription: Subscription) -> Result, Error>; - async fn find_event(&self, subscription: Subscription) -> Result, Error>; + async fn counts(&self, subscription: Subscription) -> Result; } diff --git a/src/noose/mod.rs b/src/noose/mod.rs index 6b7df86..d76f6f9 100644 --- a/src/noose/mod.rs +++ b/src/noose/mod.rs @@ -1,13 +1,12 @@ use crate::utils::structs::Context; -use tokio::runtime; - use db::Noose; use pipeline::Pipeline; - +use tokio::runtime; pub mod db; +mod nostr_db; pub mod pipeline; -// mod sled; -mod sqlite; +pub mod sled; +// mod sqlite; pub mod user; pub fn start(context: Context) { @@ -16,19 +15,32 @@ pub fn start(context: Context) { rt.block_on(async move { let pipeline_pubsub = context.pubsub.clone(); let pipeline_config = context.config.clone(); + + let db_config = context.config.clone(); let db_pubsub = context.pubsub.clone(); + let sled_pubsub = context.pubsub.clone(); let pipeline_handle = tokio::task::spawn(async move { let mut pipeline = Pipeline::new(pipeline_pubsub, pipeline_config); pipeline.start().await.unwrap(); }); - let sqlite_writer_handle = tokio::task::spawn(async move { - let mut db_writer = sqlite::SqliteDb::new().await; + let sled_handle = tokio::task::spawn(async move { + let mut sled_writer = sled::SledDb::new(); + sled_writer.start(sled_pubsub).await.unwrap(); + }); + + let nostr_db_writer_handle = tokio::task::spawn(async move { + let mut db_writer = nostr_db::NostrDb::new(db_config).await; db_writer.start(db_pubsub).await.unwrap(); }); - sqlite_writer_handle.await.unwrap(); + // let sqlite_writer_handle = tokio::task::spawn(async move { + // let mut db_writer = sqlite::SqliteDb::new().await; + // db_writer.start(db_pubsub).await.unwrap(); + // }); + + // sqlite_writer_handle.await.unwrap(); pipeline_handle.await.unwrap(); }); } diff --git a/src/noose/nostr_db.rs b/src/noose/nostr_db.rs new file mode 100644 index 0000000..8bf22be --- /dev/null +++ b/src/noose/nostr_db.rs @@ -0,0 +1,111 @@ +use crate::{ + bussy::{channels, Command, Message, PubSub}, + noose::Noose, + utils::{config::Config, error::Error, structs::Subscription}, +}; +use nostr_sqlite::{database::NostrDatabase, SQLiteDatabase}; +use std::sync::Arc; + +pub struct NostrDb { + db: SQLiteDatabase, +} + +impl NostrDb { + pub async fn new(config: Arc) -> Self { + let db_path = config.get_db_path(); + if let Ok(db) = SQLiteDatabase::open(db_path).await { + return Self { db }; + } + + panic!("[NostrDb] Failed to initialize database"); + } +} + +impl Noose for NostrDb { + async fn start(&mut self, pubsub: Arc) -> Result<(), Error> { + let mut subscriber = pubsub.subscribe(channels::MSG_NOOSE).await; + + while let Ok(message) = subscriber.recv().await { + log::info!("[Noose] received message: {:?}", message); + let command = match message.content { + Command::DbReqWriteEvent(client_id, event) => match self.write_event(event).await { + Ok(status) => Command::DbResOkWithStatus(client_id, status), + Err(e) => Command::ServiceError(e), + }, + Command::DbReqFindEvent(client_id, subscriptioin) => { + match self.find_event(subscriptioin).await { + Ok(relay_messages) => { + Command::DbResRelayMessages(client_id, relay_messages) + } + Err(e) => Command::ServiceError(e), + } + } + Command::DbReqEventCounts(client_id, subscriptioin) => { + match self.counts(subscriptioin).await { + Ok(relay_message) => Command::DbResEventCounts(client_id, relay_message), + Err(e) => Command::ServiceError(e), + } + } + _ => Command::Noop, + }; + if command != Command::Noop { + let channel = message.source; + let message = Message { + source: channels::MSG_NOOSE, + content: command, + }; + + log::info!( + "[Noose] publishing new message: {:?} to channel {}", + message, + channel + ); + + pubsub.publish(channel, message).await; + } + } + + Ok(()) + } + + async fn write_event(&self, event: Box) -> Result { + // TODO: Maybe do event validation and admin deletions here + match self.db.save_event(&event).await { + Ok(status) => { + let relay_message = nostr::RelayMessage::ok(event.id, status, ""); + Ok(relay_message) + } + Err(err) => Err(Error::bad_request(err.to_string())), + } + } + + async fn find_event( + &self, + subscription: Subscription, + ) -> Result, Error> { + match self + .db + .query(subscription.filters, nostr_sqlite::database::Order::Desc) + .await + { + Ok(events) => { + let relay_messages = events + .into_iter() + .map(|event| nostr::RelayMessage::event(subscription.id.clone(), event)) + .collect(); + Ok(relay_messages) + } + Err(err) => Err(Error::bad_request(err.to_string())), + } + } + + async fn counts(&self, subscription: Subscription) -> Result { + match self.db.count(subscription.filters).await { + Ok(counts) => { + let relay_message = nostr::RelayMessage::count(subscription.id, counts); + Ok(relay_message) + } + Err(err) => Err(Error::internal_with_message(err.to_string())), + } + } +} diff --git a/src/noose/sled.rs b/src/noose/sled.rs index d48785f..d6b9401 100644 --- a/src/noose/sled.rs +++ b/src/noose/sled.rs @@ -1,234 +1,138 @@ -use super::db::Noose; +use std::sync::Arc; use crate::bussy::{channels, Command, Message, PubSub}; use crate::utils::error::Error; -use crate::utils::structs::Subscription; -use async_trait::async_trait; -use nostr::Event; -use serde::Serialize; -use std::sync::Arc; -use super::user::{User, UserRow}; +#[derive(Debug, Clone, PartialEq)] +pub struct BanInfo { + pub pubkey: String, + pub reason: String, +} // Db Interface pub struct SledDb { db: sled::Db, - events: sled::Tree, - nip05s: sled::Tree, - pub users: sled::Tree, - - index: sled::Db, + banned_pubkeys: sled::Tree, } impl SledDb { pub fn new() -> Self { let db = sled::open("/tmp/sled_db").unwrap(); - let events = db.open_tree("events").unwrap(); - let nip05s = db.open_tree("identifiers").unwrap(); - let accounts = db.open_tree("accounts").unwrap(); - - let index = sled::open("/tmp/sled_index").unwrap(); - + let banned_pubkeys = db.open_tree("banned_pubkeys").unwrap(); Self { db, - events, - nip05s, - users: accounts, - index, + banned_pubkeys } } + pub async fn start(&mut self, pubsub: Arc) -> Result<(), Error> { + let mut subscriber = pubsub.subscribe(channels::MSG_NOOSE).await; + + while let Ok(message) = subscriber.recv().await { + log::info!("[Noose] received message: {:?}", message); + let command = match message.content { + Command::SledReqBanUser(ban_info) => match self.ban_user(ban_info).await { + Ok(status) => Command::SledResSuccess(status), + Err(e) => Command::ServiceError(e), + }, + Command::SledReqUnbanUser(pubkey) => match self.unban_user(&pubkey).await { + Ok(status) => Command::SledResSuccess(status), + Err(e) => Command::ServiceError(e), + }, + Command::SledReqGetBans => match self.get_bans().await { + Ok(bans) => Command::SledResBans(bans), + Err(e) => Command::ServiceError(e), + }, + Command::SledReqBanInfo(pubkey) => match self.get_ban_by_pubkey(&pubkey).await { + Ok(ban_info) => Command::SledResBan(ban_info), + Err(e) => Command::ServiceError(e), + }, + _ => Command::Noop, + }; + if command != Command::Noop { + let channel = message.source; + let message = Message { + source: channels::MSG_SLED, + content: command, + }; + + log::info!( + "[Sled] publishing new message: {:?} to channel {}", + message, + channel + ); + + pubsub.publish(channel, message).await; + } + } + + Ok(()) + } + fn clear_db(&self) -> Result<(), sled::Error> { self.db.clear() } - fn clear_index(&self) -> Result<(), sled::Error> { - self.index.clear() - } - - async fn insert_user(&self, user: UserRow) -> Result<(), Error> { - let pubkey = user.pubkey.clone(); - let username = user.username.clone(); - - if let Ok(Some(_)) = self.nip05s.get(&username) { - return Err(Error::internal_with_message("User already exists")); + async fn ban_user(&self, ban_info: Box) -> Result { + if let Ok(Some(_)) = self.banned_pubkeys.insert(ban_info.pubkey, ban_info.reason.as_bytes()) { + return Ok(true) } - let mut user_buff = flexbuffers::FlexbufferSerializer::new(); - user.serialize(&mut user_buff).unwrap(); - - self.nip05s.insert(&username, user_buff.view()).unwrap(); - - let prefix = "nip05:"; - let key = format!("{}{}", prefix, pubkey); - self.index.insert(key, username.as_bytes()).unwrap(); - - Ok(()) + Ok(false) } - async fn get_user(&self, user: User) -> Result { - let mut user_row = None; - if let Some(username) = user.name { - if let Ok(Some(buff)) = self.nip05s.get(username) { - let b = flexbuffers::from_slice::(&buff).unwrap(); - user_row = Some(b); + fn is_banned(&self, pubkey: &String) -> bool{ + if let Ok(Some(banned)) = self.banned_pubkeys.get(pubkey) { + return true + } + false + } + + async fn unban_user(&self, pubkey: &String) -> Result { + if self.is_banned(pubkey) { + self.banned_pubkeys.remove(pubkey).unwrap(); + + return Ok(true); + } + + Ok(false) + } + + async fn get_bans(&self) -> Result, Error> { + let bans: Vec = self.banned_pubkeys.iter().filter_map(|row| { + if let Ok((k, v)) = row { + let ban_info = BanInfo { + pubkey: String::from_utf8(k.to_vec()).unwrap(), + reason: String::from_utf8(v.to_vec()).unwrap(), + }; + + Some(ban_info) + } else { + None } - } else if let Some(pubkey) = user.pubkey { - let prefix = "nip05:"; - let reference = format!("{}{}", prefix, pubkey); - if let Ok(Some(row)) = self.index.get(reference) { - let key = String::from_utf8(row.to_vec()).unwrap(); + }).collect(); - if let Ok(Some(buff)) = self.nip05s.get(key) { - let b = flexbuffers::from_slice::(&buff).unwrap(); + Ok(bans) + } - user_row = Some(b); - } + async fn get_ban_by_pubkey(&self, pubkey: &String) -> Result, Error> { + if self.is_banned(pubkey) { + if let Ok(Some(reason)) = self.banned_pubkeys.get(pubkey) { + let ban_info = BanInfo { + pubkey: pubkey.to_owned(), + reason: String::from_utf8(reason.to_vec()).unwrap() + }; + + return Ok(Some(ban_info)); } - } - match user_row { - Some(user) => Ok(user), - None => Err(Error::internal_with_message("User not found")), - } - } -} -#[async_trait] -impl Noose for SledDb { - async fn start(&mut self, pubsub: Arc) -> Result<(), Error> { - let mut subscriber = pubsub.subscribe(channels::MSG_NOOSE).await; - - while let Ok(message) = subscriber.recv().await { - log::info!("noose subscriber received: {:?}", message); - let command = match message.content { - Command::DbReqInsertUser(user) => match self.insert_user(user).await { - Ok(_) => Command::DbResOk, - Err(e) => Command::ServiceError(e), - }, - Command::DbReqGetUser(user) => match self.get_user(user).await { - Ok(user) => Command::DbResUser(user), - Err(e) => Command::ServiceError(e), - }, - Command::DbReqWriteEvent(event) => match self.write_event(event).await { - Ok(_) => Command::DbResOk, - Err(e) => Command::ServiceError(e), - }, - _ => Command::Noop, - }; - if command != Command::Noop { - log::info!("Publishing new message"); - let channel = message.source; - - pubsub - .publish( - channel, - Message { - source: channels::MSG_NOOSE, - content: command, - }, - ) - .await; - } + return Ok(None); } - Ok(()) - } - - async fn migration_up(&self) {} - - async fn write_event(&self, event: Box) -> Result { - let mut event_buff = flexbuffers::FlexbufferSerializer::new(); - event.serialize(&mut event_buff).unwrap(); - - self.events.insert(event.id, event_buff.view()).unwrap(); - { - // Timestamp - let key = format!("created_at:{}|#e:{}", event.created_at, event.id); - self.index.insert(key, event.id.as_bytes()).unwrap(); - } - - { - // Author, pubkeys #p - let key = format!("#author:{}|#e:{}", event.pubkey, event.id); - self.index.insert(key, event.id.as_bytes()).unwrap(); - // self.index.scan_prefix( - } - - { - // Kinds - let key = format!("#k:{}|#e:{}", event.kind, event.id); - self.index.insert(key, event.id.as_bytes()).unwrap(); - // self.index.scan_prefix( - } - - { - // Tags - event.tags.iter().for_each(|tag| { - if let Some(key) = match tag { - // #e tag - nostr::Tag::Event(event_id, _, _) => Some(format!("#e:{}", event_id)), - // #p tag - nostr::Tag::PubKey(pubkey, _) => Some(format!("#p:{}|#e:{}", pubkey, event.id)), - // #t tag - nostr::Tag::Hashtag(hashtag) => Some(format!("#t:{}|#e:{}", hashtag, event.id)), - // #a tag - nostr::Tag::A { - kind, - public_key, - identifier, - relay_url, - } => Some(format!( - "#a:kind:{}|#a:pubkey:{}#a:identifier:{}|#e:{}", - kind, public_key, identifier, event.id - )), - _ => None, - } { - self.index.insert(key, event.id.as_bytes()).unwrap(); - } - }); - - // let key = format!("#t:{}|#e:{}", event.kind, event.id); - // self.index.insert(key, event.id.as_bytes()).unwrap(); - // self.index.scan_prefix( - } - - let message = format!("[\"OK\", \"{}\", true, \"\"]", event.id.to_string()); - Ok(message) - } - - async fn find_event(&self, subscription: Subscription) -> Result, Error> { - todo!() + Ok(None) } } #[cfg(test)] mod tests { - use super::SledDb; - use crate::{ - bussy::PubSub, - noose::user::{User, UserRow}, - }; - use std::sync::Arc; - #[tokio::test] - async fn get_db_names() { - let pubsub = Arc::new(PubSub::new()); - - let db = SledDb::new(); - - let pk = "npub1p3ya99jfdafnqlk87p6wfd36d2nme5mkld769rhd9pkht6hmqlaq6mzxdu".to_string(); - let username = "klink".to_string(); - let user = UserRow::new(pk, username, false); - let result = db.insert_user(user).await; - - let pubkey = "npub1p3ya99jfdafnqlk87p6wfd36d2nme5mkld769rhd9pkht6hmqlaq6mzxdu".to_string(); - let username = "klink".to_string(); - let user = User { - name: None, - pubkey: Some(pubkey), - }; - let user = db.get_user(user).await; - - db.clear_db().unwrap(); - db.clear_index().unwrap(); - } } diff --git a/src/relay/ws.rs b/src/relay/ws.rs index be8d512..7401f21 100644 --- a/src/relay/ws.rs +++ b/src/relay/ws.rs @@ -67,17 +67,26 @@ pub async fn client_connection( } // } } - crate::bussy::Command::DbResRelayMessage(client_id, events) => { + crate::bussy::Command::DbResRelayMessages(client_id, relay_messages) => { if client.client_id == client_id { if let Some(sender) = &client.client_connection { if !sender.is_closed() { - for event in events { - sender.send(Ok(Message::text(event))).unwrap(); + for message in relay_messages { + sender.send(Ok(Message::text(message.as_json()))).unwrap(); } } } } } + crate::bussy::Command::DbResEventCounts(client_id, relay_message) => { + if client.client_id == client_id { + if let Some(sender) = &client.client_connection { + if !sender.is_closed() { + sender.send(Ok(Message::text(relay_message.as_json()))).unwrap(); + } + } + } + } crate::bussy::Command::DbResOkWithStatus(client_id, status) => { if client.client_id == client_id { if let Some(sender) = &client.client_connection { @@ -177,7 +186,7 @@ async fn socket_on_message(context: &Context, client: &mut Client, msg: Message) Err(e) => { log::error!("error while parsing client message request: {}", e); - let response = nostr::RelayMessage::new_notice("Invalid message"); + let response = nostr::RelayMessage::notice("Invalid message"); let message = Message::text(response.as_json()); send(client, message); @@ -212,7 +221,7 @@ async fn handle_msg(context: &Context, client: &mut Client, client_message: Clie ClientMessage::Count { subscription_id, filters, - } => handle_count(client, subscription_id, filters).await, + } => handle_count(context, client, subscription_id, filters).await, ClientMessage::Close(subscription_id) => handle_close(client, subscription_id).await, ClientMessage::Auth(event) => handle_auth(client, event).await, _ => (), @@ -224,7 +233,7 @@ async fn handle_event(context: &Context, client: &Client, event: Box) { if let Err(err) = event.verify() { let relay_message = - nostr::RelayMessage::new_ok(event.id, false, "Failed to verify event signature"); + nostr::RelayMessage::ok(event.id, false, "Failed to verify event signature"); let message = crate::bussy::Message { source: channels::MSG_RELAY, content: crate::bussy::Command::PipelineResRelayMessageOk( @@ -253,7 +262,7 @@ async fn handle_req( client: &mut Client, subscription_id: SubscriptionId, filters: Vec, -) { +) { let subscription = Subscription::new(subscription_id.clone(), filters); let needs_historical_events = subscription.needs_historical_events(); @@ -263,6 +272,7 @@ async fn handle_req( client.ip(), &subscription_error.message ); + let message = format!( "[\"CLOSED\", \"{}\", \"{}\"]", subscription_id, subscription_error.message @@ -282,6 +292,7 @@ async fn handle_req( return; }; + log::info!("[SUBSCRIPTION] needs historical events"); if needs_historical_events { context .pubsub @@ -296,12 +307,24 @@ async fn handle_req( } } -async fn handle_count(client: &Client, subscription_id: SubscriptionId, filters: Vec) { - // context.pubsub.send(new nostr event) then handle possible errors +async fn handle_count( + context: &Context, + client: &Client, + subscription_id: SubscriptionId, + filters: Vec, +) { let subscription = Subscription::new(subscription_id, filters); - let message = Message::text("COUNT not implemented"); - send(client, message); + context + .pubsub + .publish( + channels::MSG_NOOSE, + crate::bussy::Message { + source: channels::MSG_RELAY, + content: crate::bussy::Command::DbReqEventCounts(client.client_id, subscription), + }, + ) + .await } async fn handle_close(client: &mut Client, subscription_id: SubscriptionId) { diff --git a/src/utils/config.rs b/src/utils/config.rs index 662ac4d..3efac9e 100644 --- a/src/utils/config.rs +++ b/src/utils/config.rs @@ -1,8 +1,11 @@ +use std::path::PathBuf; + use nostr::{key::FromPkStr, secp256k1::XOnlyPublicKey}; #[derive(Clone, Debug)] pub struct Config { admin_pubkey: XOnlyPublicKey, + db_path: PathBuf, } impl Default for Config { @@ -13,26 +16,30 @@ impl Default for Config { impl Config { pub fn new() -> Self { - if let Ok(env_admin_pk) = std::env::var("ADMIN_PUBKEY") { - match nostr::Keys::from_pk_str(&env_admin_pk) { - Ok(admin_keys) => { - return Self { - admin_pubkey: admin_keys.public_key(), - }; - } - Err(e) => { - panic!("Unable to parse ADMIN_PUBKEY: {}", e); - } - } - } + let admin_pubkey = std::env::var("ADMIN_PUBKEY") + .map(|env_pk| nostr::Keys::from_pk_str(&env_pk)) + .and_then(|result| result.map_err(|err| panic!("{}", err))) + .unwrap() + .public_key(); - panic!("Environment variable ADMIN_PUBKEY not defined"); + let db_path = std::env::var("DATABASE_URL") + .map(PathBuf::from) + .unwrap(); + + Self { + admin_pubkey, + db_path, + } } pub fn get_admin_pubkey(&self) -> &XOnlyPublicKey { &self.admin_pubkey } + pub fn get_db_path(&self) -> PathBuf { + self.db_path.clone() + } + pub fn get_relay_config_json(&self) -> serde_json::Value { serde_json::json!({ "contact": "klink@zhitno.st", diff --git a/src/utils/mod.rs b/src/utils/mod.rs index f94bbcf..87a5861 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,7 +1,7 @@ pub mod crypto; pub mod error; pub mod filter; -// mod nostr_filter_helpers; +mod nostr_filter_helpers; pub mod config; pub mod rejection_handler; pub mod response; diff --git a/src/utils/nostr_filter_helpers.rs b/src/utils/nostr_filter_helpers.rs index 3b4a2de..a001dc9 100644 --- a/src/utils/nostr_filter_helpers.rs +++ b/src/utils/nostr_filter_helpers.rs @@ -1,27 +1,27 @@ -use nostr::{Event, Filter, Kind, Tag}; +use nostr::{key::FromPkStr, Event, Filter, Kind}; fn ids_match(filter: &Filter, event: &Event) -> bool { if filter.ids.is_empty() { - println!("[FILTER][IDS] skipped"); + log::info!("[FILTER][ids_match] skipped"); return true; } - println!( - "[FILTER][IDS] matched: {:?}", - filter.ids.iter().any(|id| id == &event.id.to_string()) + log::info!( + "[FILTER][ids_match] matched: {:?}", + filter.ids.iter().any(|id| id == &event.id) ); - filter.ids.iter().any(|id| id == &event.id.to_string()) + filter.ids.iter().any(|id| id == &event.id) } fn kind_match(filter: &Filter, kind: Kind) -> bool { if filter.kinds.is_empty() { - println!("[FILTER][KINDS] skipped"); + log::debug!("[FILTER][kind_match] skipped"); return true; } - println!( - "[FILTER][KIND] matched: {:?}", + log::debug!( + "[FILTER][kind_match] matched: {:?}", filter.kinds.iter().any(|k| k == &kind) ); @@ -29,122 +29,142 @@ fn kind_match(filter: &Filter, kind: Kind) -> bool { } fn pubkeys_match(filter: &Filter, event: &Event) -> bool { - if filter.pubkeys.is_empty() { - println!("[FILTER][PUBKEYS] skipped"); - return true; + log::debug!( + "[FILTER][pubkeys_match] matched: {:?}", + if let Some((p_tag, p_set)) = filter.generic_tags.get_key_value(&nostr::Alphabet::P) { + if p_set.is_empty() { + log::debug!("[FILTER][PUBKEYS] skipped"); + return true; + } + + return p_set.iter().any(|pk| match pk { + nostr::GenericTagValue::Pubkey(pk) => pk == &event.pubkey, + _ => false, + }); + } + ); + if let Some((p_tag, p_set)) = filter.generic_tags.get_key_value(&nostr::Alphabet::P) { + if p_set.is_empty() { + log::debug!("[FILTER][PUBKEYS] skipped"); + return true; + } + + return p_set.iter().any(|pk| match pk { + nostr::GenericTagValue::Pubkey(pk) => pk == &event.pubkey, + _ => false, + }); } - println!( - "[FILTER][PUBKEYS] matched: {:?}", - filter.pubkeys.iter().any(|pk| pk == &event.pubkey) - ); - filter.pubkeys.iter().any(|pk| pk == &event.pubkey) + false } fn authors_match(filter: &Filter, event: &Event) -> bool { - dbg!(filter); if filter.authors.is_empty() { - println!("[FILTER][AUTHORS] skipped"); + log::debug!("[FILTER][authors_match] skipped"); return true; } - println!( - "[FILTER][AUTHORS] matched: {:?}", - filter - .authors - .iter() - .any(|author| author == &event.pubkey.to_string()) + log::debug!( + "[FILTER][authors_match] matched: {:?}", + filter.authors.iter().any(|author| author == &event.pubkey) ); - filter - .authors - .iter() - .any(|author| author == &event.pubkey.to_string()) + filter.authors.iter().any(|author| author == &event.pubkey) } fn delegated_authors_match(filter: &Filter, event: &Event) -> bool { - // Optional implementation - - // let delegated_authors_match = filter.authors.iter().any(|author| { - // event.tags.iter().any(|tag| match tag { - // Tag::Delegation { - // delegator_pk, - // conditions, - // sig, - // } => filter - // .authors - // .iter() - // .any(|author| author == &delegator_pk.to_string()), - // _ => false, - // }) - // }); - println!( - "[FILTER][DELEGATED_AUTHORS] matched: {:?}", - event.tags.iter().any(|tag| match tag { - Tag::Delegation { - delegator_pk, - conditions, - sig, - } => filter - .authors - .iter() - .any(|author| author == &delegator_pk.to_string()), - _ => false, + log::debug!( + "[FILTER][delegated_authors_match] matched: {:?}", + event.tags.iter().any(|tag| { + if tag.kind() == nostr::TagKind::Delegation { + let tag = tag.as_vec(); + if let Ok(event_pubkey) = nostr::Keys::from_pk_str(&tag[1]) { + let pk = event_pubkey.public_key(); + return filter.authors.iter().any(|author| author == &pk); + } + return false; + } + false }) ); - event.tags.iter().any(|tag| match tag { - Tag::Delegation { - delegator_pk, - conditions, - sig, - } => filter - .authors - .iter() - .any(|author| author == &delegator_pk.to_string()), - _ => true, + event.tags.iter().any(|tag| { + if tag.kind() == nostr::TagKind::Delegation { + let tag = tag.as_vec(); + if let Ok(event_pubkey) = nostr::Keys::from_pk_str(&tag[1]) { + let pk = event_pubkey.public_key(); + return filter.authors.iter().any(|author| author == &pk); + } + return false; + } + false }) } fn tag_match(filter: &Filter, event: &Event) -> bool { - println!( - "[FILTER][TAG] matched: {:?}", - filter.generic_tags.iter().any(|(key, value)| { - event.tags.iter().any(|tag| { - let kv = tag.as_vec(); - key.to_string() == kv[0] && value.iter().any(|vv| vv == &kv[1]) + if filter.generic_tags.is_empty() && event.tags.is_empty() { + return true; + } + log::debug!( + "[FILTER][tag_match] matched: {:?}", + filter + .generic_tags + .iter() + .any(|(filter_tag_key, filter_tag_value)| { + event.tags.iter().any(|event_tag| { + let event_tag = event_tag.as_vec(); + let event_tag_key = event_tag[0].clone(); + let event_tag_value = event_tag[1].clone(); + + if filter_tag_key.to_string() == event_tag_key { + return filter_tag_value + .iter() + .any(|f_tag_val| f_tag_val.to_string() == event_tag_value); + }; + + false + }) + }) + ); + + filter + .generic_tags + .iter() + .any(|(filter_tag_key, filter_tag_value)| { + event.tags.iter().any(|event_tag| { + let event_tag = event_tag.as_vec(); + let event_tag_key = event_tag[0].clone(); + let event_tag_value = event_tag[1].clone(); + + if filter_tag_key.to_string() == event_tag_key { + return filter_tag_value + .iter() + .any(|f_tag_val| f_tag_val.to_string() == event_tag_value); + }; + + false }) }) - ); - - filter.generic_tags.iter().any(|(key, value)| { - event.tags.iter().any(|tag| { - let kv = tag.as_vec(); - key.to_string() == kv[0] && value.iter().any(|vv| vv == &kv[1]) - }) - }); - - true // TODO: Fix delegated authors check } pub fn interested_in_event(filter: &Filter, event: &Event) -> bool { ids_match(filter, event) && filter.since.map_or( { - println!("[FILTER][SINCE][default] matched: {:?}", true); + log::info!("[FILTER][SINCE][default] matched: {:?}", true); true }, |t| { - println!("[FILTER][SINCE] matched: {:?}", event.created_at >= t); + log::info!("[FILTER][SINCE] matched: {:?}", event.created_at >= t); event.created_at >= t }, ) && filter.until.map_or( { - println!("[FILTER][UNTIL][default] matched: {:?}", true); + log::info!("[FILTER][UNTIL][default] matched: {:?}", true); true }, |t| { - println!("[FILTER][UNTIL] matched: {:?}", event.created_at <= t); + log::info!("[FILTER][UNTIL] matched: {:?}", event.created_at <= t); event.created_at <= t }, ) @@ -154,3 +174,27 @@ pub fn interested_in_event(filter: &Filter, event: &Event) -> bool { || delegated_authors_match(filter, event)) && tag_match(filter, event) } + +#[cfg(test)] +mod tests { + use crate::utils::nostr_filter_helpers::interested_in_event; + + #[test] + fn check_simple_match() { + let my_keys = nostr::Keys::generate(); + let event = nostr::EventBuilder::text_note("hello", []) + .to_event(&my_keys) + .unwrap(); + + let k = nostr::Kind::TextNote; + let filter = nostr::Filter::new() + .kinds(vec![k]) + .authors(vec![event.pubkey]); + + let res = interested_in_event(&filter, &event); + + dbg!(&res); + + assert!(res); + } +} diff --git a/src/utils/structs.rs b/src/utils/structs.rs index 790292d..e2b91a2 100644 --- a/src/utils/structs.rs +++ b/src/utils/structs.rs @@ -1,5 +1,5 @@ use super::{config::Config, error::Error}; -// use super::nostr_filter_helpers; +use crate::utils::nostr_filter_helpers; use crate::PubSub; use nostr::{Event, Filter, SubscriptionId}; @@ -34,11 +34,12 @@ impl Subscription { pub fn interested_in_event(&self, event: &Event) -> bool { log::info!("[Subscription] Checking if client is interested in the new event"); for filter in &self.filters { - if filter.match_event(event) { + if nostr_filter_helpers::interested_in_event(filter, event) { log::info!("[Subscription] found filter that matches the event"); return true; } } + false } }