diff --git a/.gitignore b/.gitignore index f182a35..bf064a5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target config.json +matrix-meshtastic-bridge.db diff --git a/Cargo.lock b/Cargo.lock index 57d17c6..0b2c00e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,6 +57,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", + "getrandom", "once_cell", "version_check", "zerocopy", @@ -77,6 +78,55 @@ version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anstyle-parse" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + [[package]] name = "anyhow" version = "1.0.89" @@ -175,6 +225,15 @@ dependencies = [ "syn 2.0.79", ] +[[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.4.0" @@ -239,6 +298,9 @@ name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +dependencies = [ + "serde", +] [[package]] name = "bitmaps" @@ -453,6 +515,33 @@ dependencies = [ "zeroize", ] +[[package]] +name = "colog" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c426b7af8d5e0ad79de6713996632ce31f0d68ba84068fb0d654b396e519df0" +dependencies = [ + "colored", + "env_logger", + "log", +] + +[[package]] +name = "colorchoice" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" + +[[package]] +name = "colored" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +dependencies = [ + "lazy_static", + "windows-sys 0.48.0", +] + [[package]] name = "combine" version = "4.6.7" @@ -515,6 +604,30 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crossbeam-queue" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.20" @@ -682,6 +795,7 @@ dependencies = [ "const-oid", "der_derive", "flagset", + "pem-rfc7468", "zeroize", ] @@ -703,6 +817,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", "subtle", ] @@ -718,6 +833,12 @@ dependencies = [ "syn 2.0.79", ] +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + [[package]] name = "ed25519" version = "2.2.3" @@ -749,6 +870,9 @@ name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +dependencies = [ + "serde", +] [[package]] name = "encoding_rs" @@ -759,6 +883,29 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "env_filter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -775,6 +922,23 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + [[package]] name = "event-listener" version = "4.0.3" @@ -879,6 +1043,17 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3ea1ec5f8307826a5b71094dd91fc04d4ae75d5709b20ad351c7fb4815c86ec" +[[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", +] + [[package]] name = "fnv" version = "1.0.7" @@ -951,6 +1126,17 @@ dependencies = [ "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", +] + [[package]] name = "futures-io" version = "0.3.31" @@ -1101,6 +1287,9 @@ 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" @@ -1108,6 +1297,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hkdf" version = "0.12.4" @@ -1169,6 +1364,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" version = "0.14.30" @@ -1324,6 +1525,12 @@ version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itertools" version = "0.10.5" @@ -1342,15 +1549,6 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.11" @@ -1394,9 +1592,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] @@ -1444,6 +1642,9 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] name = "libc" @@ -1460,12 +1661,19 @@ dependencies = [ "pkg-config", ] +[[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.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" dependencies = [ + "cc", "pkg-config", "vcpkg", ] @@ -1559,10 +1767,13 @@ name = "matrix-meshtastic-bridge" version = "0.1.0" dependencies = [ "anyhow", + "colog", + "log", "matrix-sdk", "meshtastic", "serde", "serde_json", + "sqlx", "tokio", ] @@ -1793,6 +2004,16 @@ dependencies = [ "zeroize", ] +[[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.7.4" @@ -1843,6 +2064,12 @@ version = "0.1.53" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "515a63dc9666c865e848b043ab52fe9a5c713ae89cde4b5fbaae67cfd614b93a" +[[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.8.0" @@ -1925,6 +2152,16 @@ dependencies = [ "pin-utils", ] +[[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 = "nu-ansi-term" version = "0.46.0" @@ -1935,6 +2172,43 @@ dependencies = [ "winapi", ] +[[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.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -1942,6 +2216,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -2115,6 +2390,15 @@ dependencies = [ "hmac", ] +[[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.1" @@ -2143,6 +2427,17 @@ 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 = "pkcs7" version = "0.4.1" @@ -2344,7 +2639,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" dependencies = [ "anyhow", - "itertools 0.13.0", + "itertools 0.12.1", "proc-macro2", "quote", "syn 2.0.79", @@ -2572,6 +2867,26 @@ dependencies = [ "serde", ] +[[package]] +name = "rsa" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "ruma" version = "0.9.4" @@ -2924,6 +3239,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha2" version = "0.10.8" @@ -2965,6 +3291,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ + "digest", "rand_core", ] @@ -2993,6 +3320,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +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.3" @@ -3003,12 +3339,227 @@ dependencies = [ "der", ] +[[package]] +name = "sqlformat" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" +dependencies = [ + "nom", + "unicode_categories", +] + +[[package]] +name = "sqlx" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6" +dependencies = [ + "ahash", + "atoi", + "byteorder", + "bytes", + "crc", + "crossbeam-queue", + "either", + "event-listener 2.5.3", + "futures-channel", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashlink", + "hex", + "indexmap", + "log", + "memchr", + "native-tls", + "once_cell", + "paste", + "percent-encoding", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlformat", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "url", +] + +[[package]] +name = "sqlx-macros" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 1.0.109", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" +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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" +dependencies = [ + "atoi", + "base64 0.21.7", + "bitflags 2.6.0", + "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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" +dependencies = [ + "atoi", + "base64 0.21.7", + "bitflags 2.6.0", + "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", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa" +dependencies = [ + "atoi", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "sqlx-core", + "tracing", + "url", + "urlencoding", +] + [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + [[package]] name = "subtle" version = "2.6.1" @@ -3267,6 +3818,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -3372,6 +3924,24 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-properties" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + [[package]] name = "universal-hash" version = "0.5.1" @@ -3399,6 +3969,12 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "uuid" version = "1.10.0" @@ -3478,10 +4054,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] -name = "wasm-bindgen" -version = "0.2.93" +name = "wasite" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", "once_cell", @@ -3490,9 +4072,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", @@ -3505,9 +4087,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.43" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" dependencies = [ "cfg-if", "js-sys", @@ -3517,9 +4099,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3527,9 +4109,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", @@ -3540,9 +4122,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "wasm-streams" @@ -3559,9 +4141,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" dependencies = [ "js-sys", "wasm-bindgen", @@ -3589,6 +4171,16 @@ dependencies = [ "rustix", ] +[[package]] +name = "whoami" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" +dependencies = [ + "redox_syscall", + "wasite", +] + [[package]] name = "wildmatch" version = "2.4.0" diff --git a/Cargo.toml b/Cargo.toml index 8e35c01..009f999 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,8 +5,11 @@ edition = "2021" [dependencies] anyhow = "1.0.89" +colog = "1.3.0" +log = "0.4.22" matrix-sdk = { version = "0.7.1", features = ["anyhow"] } meshtastic = "0.1.6" serde = { version = "1.0.210", features = ["derive"]} serde_json = "1.0.128" +sqlx = { version = "0.7.3", features = ["runtime-tokio-native-tls", "sqlite"] } tokio = "1.40.0" diff --git a/migrations/20241011053437_init.sql b/migrations/20241011053437_init.sql new file mode 100644 index 0000000..e8ed445 --- /dev/null +++ b/migrations/20241011053437_init.sql @@ -0,0 +1,15 @@ +CREATE TABLE device ( + id INTEGER PRIMARY KEY NOT NULL, + node_num INTEGER UNIQUE NOT NULL, -- meshtastic device node number (my_node_num) + space VARCHAR(100) NOT NULL, -- Matrix space to use for this device + control_room VARCHAR(100) NOT NULL -- control room within the space +); + +CREATE TABLE remote_user ( + id INTEGER PRIMARY KEY NOT NULL, + device INTEGER NOT NULL REFERENCES device(id), + node_id INTEGER NOT NULL, + node_short_name VARCHAR(4) NOT NULL, + node_name VARCHAR(100) NOT NULL, + room VARCHAR(100) NOT NULL +); diff --git a/src/bridge.rs b/src/bridge.rs new file mode 100644 index 0000000..aaff398 --- /dev/null +++ b/src/bridge.rs @@ -0,0 +1,55 @@ +use matrix_sdk::config::SyncSettings; +use meshtastic::api::StreamApi; +use tokio::sync::mpsc::UnboundedReceiver; + +use crate::{config, db, matrix}; + +pub(crate) struct Bridge { + db: db::DB, + + meshtastic_listener: UnboundedReceiver, + meshtastic_stream_api: meshtastic::api::ConnectedStreamApi, + + matrix_client: matrix_sdk::Client, +} + +impl Bridge { + pub async fn setup(config: config::Config) -> Result> { + log::info!("starting matrix meshtastic bridge"); + + // setup database + let db = db::setup(config.db).await.expect("error connecting to db"); + + // setup meshtastic connection + let stream_api = StreamApi::new(); + let serial_stream = meshtastic::utils::stream::build_serial_stream( + config.meshtastic.device, + None, + None, + None, + )?; + let (meshtastic_listener, meshtastic_stream_api) = stream_api.connect(serial_stream).await; + + // setup matrix client + let matrix_client = matrix::build(config.matrix) + .await + .expect("error logging into matrix"); + matrix_client.sync_once(SyncSettings::default()).await?; + + Ok(Bridge { + db, + meshtastic_listener, + meshtastic_stream_api, + matrix_client, + }) + } + + pub async fn run(self: Bridge) -> Result<(), Box> { + Ok(()) + } + + pub async fn shutdown(mut self: Bridge) { + self.meshtastic_listener.close(); + self.db.close().await; + } +} diff --git a/src/config.rs b/src/config.rs index 9d5aacf..5198719 100644 --- a/src/config.rs +++ b/src/config.rs @@ -4,6 +4,8 @@ use std::{fs::File, io::BufReader}; pub(crate) struct Config { pub(crate) matrix: MatrixConfig, pub(crate) meshtastic: MeshtasticConfig, + #[serde(default = "get_db_uri")] + pub(crate) db: String, } #[derive(serde::Deserialize, Debug)] @@ -24,6 +26,10 @@ fn get_device_name() -> String { "meshtastic-bridge".to_string() } +fn get_db_uri() -> String { + "sqlite://matrix-meshtastic-bridge.db".to_string() +} + pub(crate) async fn read_config() -> Config { let file = File::open("config.json").expect("failed to read config.json"); let reader = BufReader::new(file); diff --git a/src/db.rs b/src/db.rs new file mode 100644 index 0000000..8faa7c4 --- /dev/null +++ b/src/db.rs @@ -0,0 +1,80 @@ +use meshtastic::protobufs::MyNodeInfo; +use sqlx::{ + migrate::{MigrateDatabase, Migrator}, + sqlite::SqlitePool, + Executor, Pool, Sqlite, +}; + +#[derive(Debug, sqlx::FromRow)] +pub(crate) struct Device { + pub(crate) id: i64, + pub(crate) node_num: u32, + pub(crate) long_name: String, + pub(crate) space: String, + pub(crate) control_room: String, +} + +#[derive(Debug, sqlx::FromRow)] +pub(crate) struct RemoteUser { + pub(crate) id: i64, + pub(crate) device: i64, + pub(crate) node_id: u64, + pub(crate) node_short_name: String, + pub(crate) node_name: String, + pub(crate) room: String, +} + +pub(crate) struct DB { + pool: Pool, +} + +pub(crate) async fn setup(db_url: String) -> Result> { + if !Sqlite::database_exists(&db_url).await.unwrap_or(false) { + log::debug!("Creating database {}", &db_url); + match Sqlite::create_database(&db_url).await { + Ok(_) => log::debug!("Created db successfully"), + Err(error) => panic!("error: {}", error), + } + } + + log::debug!("connecting to database {}", db_url); + let pool = SqlitePool::connect(&db_url).await?; + + log::info!("running migrations"); + sqlx::migrate!("./migrations") + .run(&pool) + .await + .expect("error running db migrations"); + + Ok(DB { pool: pool }) +} + +impl DB { + pub async fn get_device( + self: DB, + node_num: i32, + ) -> Result, Box> { + let query = sqlx::query_as::<_, Device>("SELECT * FROM devices WHERE node_num = ? LIMIT 1"); + + let device = query.bind(node_num).fetch_one(&self.pool).await?; + + Ok(Option::Some(device)) + } + + pub async fn upsert_device(self: DB, device: Device) -> Result<(), Box> { + let query = sqlx::query("INSERT INTO devices (node_num, space, control_room) VALUES (?, ?, ?) ON CONFLICT(node_num) DO UPDATE SET space=excluded.space, control_room=excluded.control_room) WHERE node_num=excluded.node_num;"); + + query + .bind(device.node_num) + .bind(device.space) + .bind(device.control_room) + .execute(&self.pool) + .await?; + + Ok(()) + } + + pub async fn close(self: DB) { + self.pool.close().await + } +} diff --git a/src/main.rs b/src/main.rs index a541b42..e8c3f85 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,18 +1,25 @@ -use matrix_sdk::{config::SyncSettings, crypto::types::events::room, ruma::RoomId}; +use matrix_sdk::{config::SyncSettings, ruma::RoomId}; +use tokio::signal; use tokio::sync::mpsc; +mod bridge; mod config; +mod db; mod matrix; mod meshtastic; #[tokio::main] async fn main() -> anyhow::Result<()> { + colog::init(); + let config = config::read_config().await; + let pool = db::setup(config.db).await.expect("error connecting to db"); + let (matrix_tx, matrix_rx) = mpsc::channel(32); let room_id = RoomId::parse(&config.matrix.room).expect("invalid room id"); - println!("matrix room: {:?}", room_id); + log::debug!("matrix room: {:?}", room_id); let matrix_client = matrix::build(config.matrix) .await @@ -25,14 +32,25 @@ async fn main() -> anyhow::Result<()> { .expect("error connecting to meshtastic"); tokio::spawn(async { - meshtastic_client.receive(matrix_tx).await.expect("error receiving message from meshtastic"); + meshtastic_client + .receive(matrix_tx) + .await + .expect("error receiving message from meshtastic"); }); tokio::spawn(matrix::sender(matrix_client.clone(), matrix_rx, room_id)); + tokio::spawn(matrix::sync(matrix_client.clone())); - // Syncing is important to synchronize the client state with the server. - // This method will never return unless there is an error. - matrix_client.sync(SyncSettings::default()).await?; + match signal::ctrl_c().await { + Ok(()) => {} + Err(err) => { + log::error!("Unable to listen for shutdown signal: {}", err); + } + } + + log::debug!("shutting down database connection"); + pool.close().await; + log::debug!("db connection closed"); Ok(()) } diff --git a/src/matrix.rs b/src/matrix.rs index 01ac37b..2e5fbc9 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -1,17 +1,22 @@ +use crate::config; +use log; use matrix_sdk::{ + config::SyncSettings, ruma::{ events::room::{ member::StrippedRoomMemberEvent, message::{RoomMessageEventContent, SyncRoomMessageEvent}, - }, OwnedRoomId, RoomId, TransactionId, UserId + }, + OwnedRoomId, TransactionId, UserId, }, Client, Room, }; -use tokio::time::{sleep, Duration}; use tokio::sync::mpsc::Receiver; -use crate::config; +use tokio::time::{sleep, Duration}; -pub(crate) async fn build(config: config::MatrixConfig) -> Result { +pub(crate) async fn build( + config: config::MatrixConfig, +) -> Result { let user = UserId::parse(config.username) .expect("invalid matrix username - should be a full mxid with server"); let client = Client::builder() @@ -27,12 +32,12 @@ pub(crate) async fn build(config: config::MatrixConfig) -> Result 3600 { - eprintln!("Can't join room {} ({err:?})", room.room_id()); + log::error!("Can't join room {} ({err:?})", room.room_id()); break; } } - println!("Successfully joined room {}", room.room_id()); + log::debug!("Successfully joined room {}", room.room_id()); let content = RoomMessageEventContent::text_plain("fuck you"); let txn_id = TransactionId::new(); let result = room.send(content).with_transaction_id(&txn_id).await; match result { - Ok(_) => eprintln!("sent hello message"), - Err(err) => eprintln!( + Ok(_) => log::error!("sent hello message"), + Err(err) => log::error!( "Error sending hello message to room {}: {err:?}", room.room_id() ), @@ -83,17 +88,27 @@ async fn on_stripped_state_member( }); } - -pub(crate) async fn sender(client: Client, mut rx: Receiver, room_id: OwnedRoomId) { +pub(crate) async fn sender( + client: Client, + mut rx: Receiver, + room_id: OwnedRoomId, +) { let room = match client.get_room(&room_id) { Some(room) => room, - None => panic!("requested matrix room not found") + None => panic!("requested matrix room not found"), }; while let Some(msg) = rx.recv().await { match room.send(msg).await { - Err(err) => println!("error sending message to matrix: {:?}", err), - Ok(response) => println!("sent message to matrix: {:?}", response), + Err(err) => log::error!("error sending message to matrix: {:?}", err), + Ok(response) => log::debug!("sent message to matrix: {:?}", response), } - }; + } +} + +pub(crate) async fn sync(client: Client) { + client + .sync(SyncSettings::default()) + .await + .expect("error syncing matrix"); } diff --git a/src/meshtastic.rs b/src/meshtastic.rs index fcb2785..60593d8 100644 --- a/src/meshtastic.rs +++ b/src/meshtastic.rs @@ -1,10 +1,11 @@ use matrix_sdk::ruma::events::room::message::RoomMessageEventContent; use meshtastic::api::state::Connected; use meshtastic::api::{ConnectedStreamApi, StreamApi}; -use meshtastic::protobufs::FromRadio; -use meshtastic::utils; +use meshtastic::protobufs::{from_radio::PayloadVariant, FromRadio}; +use meshtastic::protobufs::{mesh_packet, Data}; +use meshtastic::utils::{self, generate_rand_id}; +use tokio::sync::mpsc::error::SendError; use tokio::sync::mpsc::{Sender, UnboundedReceiver}; -use tokio::time::Duration; use crate::config; @@ -20,7 +21,7 @@ pub(crate) async fn build( let serial_stream = utils::stream::build_serial_stream(config.device, None, None, None)?; let (decoded_listener, stream_api) = stream_api.connect(serial_stream).await; - println!("connected to meshtastic device"); + log::info!("connected to meshtastic device"); Ok(MeshtasticClient { decoded_listener: decoded_listener, @@ -39,17 +40,110 @@ impl MeshtasticClient { // This loop can be broken with ctrl+c, or by disconnecting // the attached serial port. - println!("listening for messages from meshtastic"); - while let Some(decoded) = self.decoded_listener.recv().await { - println!("Received: {:?}", decoded); + self.stream_api.configure(generate_rand_id()).await?; - let msg = RoomMessageEventContent::text_plain(format!("{:?}", decoded)); + log::debug!("listening for messages from meshtastic"); + while let Some(packet) = self.decoded_listener.recv().await { + let payload_variant = match packet.payload_variant { + Some(payload_variant) => payload_variant, + None => { + log::debug!( + "Received FromRadio packet with no payload variant, not handling..." + ); + continue; + } + }; - matrix_sender - .send_timeout(msg, Duration::from_secs(10)) - .await?; + match payload_variant { + PayloadVariant::Packet(packet) => { + let payload_variant = match packet.payload_variant { + Some(payload_variant) => payload_variant, + None => { + log::debug!( + "Received MeshPacket with no payload variant, not handling..." + ); + return Ok(()); + } + }; + + match payload_variant { + mesh_packet::PayloadVariant::Decoded(decoded) => { + handle_decoded_packet(&matrix_sender, decoded).await?; + } + mesh_packet::PayloadVariant::Encrypted(encrypted) => { + log::debug!( + "received encrypted packet (decryption not yet supported): {:?}", + encrypted + ); + } + }; + } + PayloadVariant::MyInfo(my_node_info) => { + debug_message( + &matrix_sender, + format!("I'm alive! MyInfo: {:?}", my_node_info), + ) + .await? + } + PayloadVariant::LogRecord(record) => { + log::info!( + "[meshtastic] {} [{}] [{}] {}", + record.level, + record.time, + record.source, + record.message + ) + } + PayloadVariant::Channel(channel) => { + log::debug!("Channel: {:?}", channel); + } + // PayloadVariant::NodeInfo(node_info) => { + // upsert_remote_node(db, node_info).await? + // } + // PayloadVariant::Decoded(decoded) => { + // debug_message(&matrix_sender, format!("Decoded: {:?}", decoded)) + // } + _ => log::debug!("dropping unknown packet"), + } } Ok(()) } } + +async fn handle_decoded_packet( + matrix_sender: &Sender, + // packet: MeshPacket, + decoded: Data, +) -> Result<(), Box> { + match decoded.portnum() { + meshtastic::protobufs::PortNum::TextMessageApp => { + debug_message( + &matrix_sender, + format!( + "Text from {:?}: {}", + decoded.source, + std::str::from_utf8(&decoded.payload)? + ), + ) + .await?; + } + _ => log::debug!( + "dropping packet we havent implemented support for ({})", + decoded.portnum().as_str_name() + ), + } + + Ok(()) +} + +async fn debug_message( + matrix_sender: &Sender, + message: String, +) -> Result<(), SendError> { + log::debug!("[mashtastic]: received {}", message); + + matrix_sender + .send(RoomMessageEventContent::text_plain(message)) + .await +}