Compare commits
2 commits
main
...
matrix-ses
Author | SHA1 | Date | |
---|---|---|---|
3b9d40cd97 | |||
b19cafc2b2 |
11 changed files with 278 additions and 152 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,3 +1,3 @@
|
|||
/target
|
||||
config.json
|
||||
matrix-meshtastic-bridge.db*
|
||||
/state
|
||||
|
|
79
Cargo.lock
generated
79
Cargo.lock
generated
|
@ -11,7 +11,7 @@ dependencies = [
|
|||
"macroific",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -129,9 +129,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.91"
|
||||
version = "1.0.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8"
|
||||
checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6"
|
||||
|
||||
[[package]]
|
||||
name = "anymap2"
|
||||
|
@ -150,7 +150,7 @@ dependencies = [
|
|||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -211,7 +211,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -222,7 +222,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -658,7 +658,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -762,7 +762,7 @@ dependencies = [
|
|||
"macroific",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -786,7 +786,7 @@ checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -809,7 +809,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -995,7 +995,7 @@ dependencies = [
|
|||
"macroific",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1130,7 +1130,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1708,7 +1708,7 @@ dependencies = [
|
|||
"cfg-if",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1719,7 +1719,7 @@ checksum = "13198c120864097a565ccb3ff947672d969932b7975ebd4085732c9f09435e55"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1732,7 +1732,7 @@ dependencies = [
|
|||
"macroific_core",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1747,6 +1747,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"env_logger",
|
||||
"futures",
|
||||
"log",
|
||||
"matrix-sdk",
|
||||
"meshtastic",
|
||||
|
@ -1776,7 +1777,7 @@ dependencies = [
|
|||
"proc-macro-error2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2297,7 +2298,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2621,7 +2622,7 @@ dependencies = [
|
|||
"itertools 0.12.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2989,7 +2990,7 @@ dependencies = [
|
|||
"quote",
|
||||
"ruma-identifiers-validation",
|
||||
"serde",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
"toml",
|
||||
]
|
||||
|
||||
|
@ -3105,9 +3106,9 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.213"
|
||||
version = "1.0.210"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1"
|
||||
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
@ -3146,13 +3147,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.213"
|
||||
version = "1.0.210"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5"
|
||||
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3170,9 +3171,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.129"
|
||||
version = "1.0.128"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6dbcf9b78a125ee667ae19388837dd12294b858d101fdd393cb9d5501ef09eb2"
|
||||
checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
|
@ -3558,9 +3559,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.82"
|
||||
version = "2.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021"
|
||||
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -3624,7 +3625,7 @@ checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3654,9 +3655,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
|||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.41.0"
|
||||
version = "1.40.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb"
|
||||
checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
|
@ -3678,7 +3679,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3811,7 +3812,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4060,7 +4061,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
|
@ -4094,7 +4095,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
@ -4227,7 +4228,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4238,7 +4239,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4473,7 +4474,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4493,5 +4494,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.82",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
|
|
@ -6,10 +6,11 @@ edition = "2021"
|
|||
[dependencies]
|
||||
anyhow = "1.0.89"
|
||||
env_logger = "0.11.5"
|
||||
futures = "0.3.31"
|
||||
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"
|
||||
tokio = { version = "1.40.0", features = ["full"] }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM library/rust:1.82 AS build
|
||||
FROM library/rust:1.81 AS build
|
||||
# not clear what this is used for
|
||||
RUN apt-get update && apt-get install -y libdbus-1-dev pkg-config
|
||||
COPY . /src
|
||||
|
|
|
@ -13,3 +13,9 @@ CREATE TABLE remote_user (
|
|||
node_name VARCHAR(100) NOT NULL,
|
||||
room VARCHAR(100) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE matrix_state (
|
||||
id INTEGER PRIMARY KEY NOT NULL,
|
||||
key TEXT UNIQUE NOT NULL,
|
||||
value TEXT NOT NULL
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use matrix_sdk::config::SyncSettings;
|
||||
use meshtastic::api::StreamApi;
|
||||
use meshtastic::utils;
|
||||
use tokio::sync::mpsc::UnboundedReceiver;
|
||||
|
||||
use crate::{config, db, matrix};
|
||||
|
@ -23,11 +22,16 @@ impl Bridge {
|
|||
|
||||
// setup meshtastic connection
|
||||
let stream_api = StreamApi::new();
|
||||
let tcp_stream = utils::stream::build_tcp_stream(config.meshtastic.address).await?;
|
||||
let (meshtastic_listener, meshtastic_stream_api) = stream_api.connect(tcp_stream).await;
|
||||
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)
|
||||
let matrix_client = matrix::build(config.matrix, &db)
|
||||
.await
|
||||
.expect("error logging into matrix");
|
||||
matrix_client.sync_once(SyncSettings::default()).await?;
|
||||
|
|
|
@ -13,23 +13,26 @@ pub(crate) struct MatrixConfig {
|
|||
pub(crate) username: String,
|
||||
#[serde(default = "get_matrix_password")]
|
||||
pub(crate) password: String,
|
||||
#[serde(default = "get_device_name")]
|
||||
#[serde(default = "get_matrix_device_name")]
|
||||
pub(crate) device_name: String,
|
||||
pub(crate) room: String,
|
||||
#[serde(default = "get_matrix_state_dir")]
|
||||
pub(crate) state_dir: String,
|
||||
#[serde(default = "get_matrix_state_passphrase")]
|
||||
pub(crate) state_passphrase: String,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug)]
|
||||
pub(crate) struct MeshtasticConfig {
|
||||
#[serde(default = "get_meshtastic_address")]
|
||||
pub(crate) address: String, // expected format is host:port
|
||||
pub(crate) device: String,
|
||||
}
|
||||
|
||||
fn get_device_name() -> String {
|
||||
fn get_matrix_device_name() -> String {
|
||||
"meshtastic-bridge".to_string()
|
||||
}
|
||||
|
||||
fn get_db_uri() -> String {
|
||||
"sqlite://matrix-meshtastic-bridge.db".to_string()
|
||||
"sqlite://state/matrix-meshtastic-bridge.db".to_string()
|
||||
}
|
||||
|
||||
fn get_matrix_password() -> String {
|
||||
|
@ -39,10 +42,14 @@ fn get_matrix_password() -> String {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_meshtastic_address() -> String {
|
||||
match std::env::var("MESHTASTIC_ADDRESS") {
|
||||
fn get_matrix_state_dir() -> String {
|
||||
"state".to_string()
|
||||
}
|
||||
|
||||
fn get_matrix_state_passphrase() -> String {
|
||||
match std::env::var("MATRIX_STATE_PASSPHRASE") {
|
||||
Ok(p) => p,
|
||||
Err(_) => "meshtastic.local".to_string(),
|
||||
Err(_) => "a".to_string(), // I'm sorry but encryption at rest is dumb if the decryption key is stored in the same place as the encrypted data
|
||||
}
|
||||
}
|
||||
|
||||
|
|
73
src/db.rs
73
src/db.rs
|
@ -1,9 +1,6 @@
|
|||
use meshtastic::protobufs::MyNodeInfo;
|
||||
use sqlx::{
|
||||
migrate::{MigrateDatabase, Migrator},
|
||||
sqlite::SqlitePool,
|
||||
Executor, Pool, Sqlite,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
use sqlx::{migrate::MigrateDatabase, sqlite::SqlitePool, Pool, Sqlite};
|
||||
|
||||
#[derive(Debug, sqlx::FromRow)]
|
||||
pub(crate) struct Device {
|
||||
|
@ -24,11 +21,17 @@ pub(crate) struct RemoteUser {
|
|||
pub(crate) room: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, sqlx::FromRow)]
|
||||
struct MatrixState {
|
||||
key: String,
|
||||
value: String,
|
||||
}
|
||||
|
||||
pub(crate) struct DB {
|
||||
pool: Pool<Sqlite>,
|
||||
}
|
||||
|
||||
pub(crate) async fn setup(db_url: String) -> Result<DB, Box<dyn std::error::Error>> {
|
||||
pub(crate) async fn setup(db_url: String) -> anyhow::Result<Arc<DB>> {
|
||||
if !Sqlite::database_exists(&db_url).await.unwrap_or(false) {
|
||||
log::debug!("Creating database {}", &db_url);
|
||||
match Sqlite::create_database(&db_url).await {
|
||||
|
@ -46,12 +49,12 @@ pub(crate) async fn setup(db_url: String) -> Result<DB, Box<dyn std::error::Erro
|
|||
.await
|
||||
.expect("error running db migrations");
|
||||
|
||||
Ok(DB { pool: pool })
|
||||
Ok(Arc::new(DB { pool: pool }))
|
||||
}
|
||||
|
||||
impl DB {
|
||||
pub async fn get_device(
|
||||
self: DB,
|
||||
self: &DB,
|
||||
node_num: i32,
|
||||
) -> Result<Option<Device>, Box<dyn std::error::Error>> {
|
||||
let query = sqlx::query_as::<_, Device>("SELECT * FROM devices WHERE node_num = ? LIMIT 1");
|
||||
|
@ -72,7 +75,57 @@ impl DB {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn close(self: DB) {
|
||||
pub async fn get_matrix_session(
|
||||
self: &DB,
|
||||
) -> Result<Option<matrix_sdk::matrix_auth::MatrixSession>, Box<dyn std::error::Error>> {
|
||||
let session = match self.get_matrix_state("session".to_string()).await? {
|
||||
Some(session_json) => serde_json::from_str(&session_json)?,
|
||||
None => None,
|
||||
};
|
||||
|
||||
Ok(session)
|
||||
}
|
||||
|
||||
pub async fn set_matrix_session(
|
||||
self: &DB,
|
||||
session: matrix_sdk::matrix_auth::MatrixSession,
|
||||
) -> anyhow::Result<()> {
|
||||
let session_json = serde_json::to_string(&session)?;
|
||||
|
||||
self.set_matrix_state("session".to_string(), session_json)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_matrix_sync_token(self: &DB) -> anyhow::Result<Option<String>> {
|
||||
self.get_matrix_state("session_store".to_string()).await
|
||||
}
|
||||
|
||||
pub async fn set_matrix_sync_token(self: &DB, token: String) -> anyhow::Result<()> {
|
||||
self.set_matrix_state("session_store".to_string(), token)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn set_matrix_state(self: &DB, key: String, value: String) -> anyhow::Result<()> {
|
||||
let query = sqlx::query("INSERT INTO matrix_state (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value=excluded.value");
|
||||
|
||||
query.bind(key).bind(value).execute(&self.pool).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_matrix_state(self: &DB, key: String) -> anyhow::Result<Option<String>> {
|
||||
let query = sqlx::query_as::<_, MatrixState>(
|
||||
"SELECT value FROM matrix_state WHERE 'key' = ? LIMIT 1",
|
||||
);
|
||||
let result = match query.bind(key).fetch_optional(&self.pool).await.unwrap() {
|
||||
Some(row) => Some(row.value),
|
||||
None => None,
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn close(self: &DB) {
|
||||
self.pool.close().await
|
||||
}
|
||||
}
|
||||
|
|
47
src/main.rs
47
src/main.rs
|
@ -1,4 +1,4 @@
|
|||
use matrix_sdk::{config::SyncSettings, ruma::RoomId};
|
||||
use matrix_sdk::ruma::RoomId;
|
||||
use tokio::signal;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
|
@ -8,51 +8,38 @@ mod db;
|
|||
mod matrix;
|
||||
mod meshtastic;
|
||||
|
||||
// #[tokio::main]
|
||||
// async fn main() -> anyhow::Result<()> {
|
||||
// env_logger::init();
|
||||
|
||||
// let config = config::read_config().await;
|
||||
|
||||
// let bridge = bridge::Bridge::setup(config).await.unwrap();
|
||||
|
||||
// bridge.run().await.unwrap();
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
env_logger::init();
|
||||
|
||||
let config = config::read_config().await;
|
||||
|
||||
let pool = db::setup(config.db).await.expect("error connecting to db");
|
||||
let db = 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");
|
||||
log::debug!("matrix room: {:?}", room_id);
|
||||
|
||||
let matrix_client = matrix::build(config.matrix)
|
||||
let matrix_client = matrix::build(config.matrix, &db)
|
||||
.await
|
||||
.expect("error logging into matrix");
|
||||
|
||||
matrix_client.sync_once(SyncSettings::default()).await?;
|
||||
|
||||
let meshtastic_client = meshtastic::build(config.meshtastic)
|
||||
.await
|
||||
.expect("error connecting to meshtastic");
|
||||
|
||||
tokio::spawn(async {
|
||||
meshtastic_client
|
||||
.receive(matrix_tx)
|
||||
.await
|
||||
.expect("error receiving message from meshtastic");
|
||||
});
|
||||
log::info!("matrix and meshtatic clients ready, spawning threads");
|
||||
|
||||
tokio::spawn(matrix::sender(matrix_client.clone(), matrix_rx, room_id));
|
||||
tokio::spawn(matrix::sync(matrix_client.clone()));
|
||||
let mut tasks = vec![];
|
||||
|
||||
tasks.push(tokio::spawn(matrix::sender(
|
||||
matrix_client,
|
||||
matrix_rx,
|
||||
room_id,
|
||||
)));
|
||||
tasks.push(tokio::spawn(matrix::sync(matrix_client, db)));
|
||||
tasks.push(tokio::spawn(meshtastic_client.receive(matrix_tx)));
|
||||
|
||||
match signal::ctrl_c().await {
|
||||
Ok(()) => {}
|
||||
|
@ -61,8 +48,14 @@ async fn main() -> anyhow::Result<()> {
|
|||
}
|
||||
}
|
||||
|
||||
log::info!("shutting down tasks");
|
||||
|
||||
meshtastic_client.close().await;
|
||||
|
||||
futures::future::join_all(tasks).await;
|
||||
|
||||
log::debug!("shutting down database connection");
|
||||
pool.close().await;
|
||||
db.close().await;
|
||||
log::debug!("db connection closed");
|
||||
|
||||
Ok(())
|
||||
|
|
101
src/matrix.rs
101
src/matrix.rs
|
@ -1,35 +1,60 @@
|
|||
use crate::config;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{config, db};
|
||||
use log;
|
||||
use matrix_sdk::{
|
||||
config::SyncSettings,
|
||||
ruma::{
|
||||
api::client::filter::FilterDefinition,
|
||||
events::room::{
|
||||
member::StrippedRoomMemberEvent,
|
||||
message::{RoomMessageEventContent, SyncRoomMessageEvent},
|
||||
},
|
||||
OwnedRoomId, TransactionId, UserId,
|
||||
},
|
||||
Client, Room,
|
||||
Client, Error, LoopCtrl, Room,
|
||||
};
|
||||
use tokio::sync::mpsc::Receiver;
|
||||
use tokio::time::{sleep, Duration};
|
||||
|
||||
pub(crate) async fn build(
|
||||
config: config::MatrixConfig,
|
||||
db: &db::DB,
|
||||
) -> Result<matrix_sdk::Client, anyhow::Error> {
|
||||
log::debug!("creating matrix client");
|
||||
let user = UserId::parse(config.username)
|
||||
.expect("invalid matrix username - should be a full mxid with server");
|
||||
|
||||
log::debug!("storing matrix client state in {}", config.state_dir);
|
||||
let client = Client::builder()
|
||||
.server_name(user.server_name())
|
||||
.sqlite_store(config.state_dir, Some(&config.state_passphrase))
|
||||
.build()
|
||||
.await?;
|
||||
|
||||
client
|
||||
.matrix_auth()
|
||||
.login_username(user, &config.password)
|
||||
.initial_device_display_name(&config.device_name)
|
||||
.send()
|
||||
.await?;
|
||||
log::debug!("checking if there's an existing session");
|
||||
match db.get_matrix_session().await.unwrap() {
|
||||
Some(session) => {
|
||||
log::debug!("restoring session from database");
|
||||
client.restore_session(session).await?;
|
||||
}
|
||||
None => {
|
||||
log::debug!("no existing session. Logging in");
|
||||
let matrix_auth = client.matrix_auth();
|
||||
matrix_auth
|
||||
.login_username(user, &config.password)
|
||||
.initial_device_display_name(&config.device_name)
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
log::debug!("creating new session");
|
||||
let session = matrix_auth
|
||||
.session()
|
||||
.expect("A logged-in matrix client should have a session");
|
||||
|
||||
db.set_matrix_session(session).await.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
client.add_event_handler(|ev: SyncRoomMessageEvent| async move {
|
||||
log::debug!("[matrix] Received a message {:?}", ev);
|
||||
|
@ -37,7 +62,11 @@ pub(crate) async fn build(
|
|||
|
||||
client.add_event_handler(on_stripped_state_member);
|
||||
|
||||
log::debug!("connected to matrix");
|
||||
log::debug!("connected to matrix, syncing");
|
||||
|
||||
client.sync_once(SyncSettings::default()).await?;
|
||||
|
||||
log::info!("connected to matrix server and synchronized state, ready to continue startup");
|
||||
|
||||
return Ok(client);
|
||||
}
|
||||
|
@ -92,7 +121,7 @@ pub(crate) async fn sender(
|
|||
client: Client,
|
||||
mut rx: Receiver<RoomMessageEventContent>,
|
||||
room_id: OwnedRoomId,
|
||||
) {
|
||||
) -> anyhow::Result<()> {
|
||||
let room = match client.get_room(&room_id) {
|
||||
Some(room) => room,
|
||||
None => panic!("requested matrix room not found"),
|
||||
|
@ -104,11 +133,61 @@ pub(crate) async fn sender(
|
|||
Ok(response) => log::debug!("sent message to matrix: {:?}", response),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn sync(client: Client) {
|
||||
pub(crate) async fn sync(client: Client, db: Arc<db::DB>) -> anyhow::Result<()> {
|
||||
let filter = FilterDefinition::with_lazy_loading();
|
||||
let mut sync_settings = SyncSettings::default().filter(filter.into());
|
||||
|
||||
if let Some(token) = db
|
||||
.get_matrix_sync_token()
|
||||
.await
|
||||
.map_err(|err| Error::UnknownError(err.into()))?
|
||||
{
|
||||
sync_settings = sync_settings.token(token);
|
||||
}
|
||||
|
||||
client
|
||||
.sync(SyncSettings::default())
|
||||
.await
|
||||
.expect("error syncing matrix");
|
||||
|
||||
loop {
|
||||
match client.sync_once(sync_settings.clone()).await {
|
||||
Ok(response) => {
|
||||
// This is the last time we need to provide this token, the sync method after
|
||||
// will handle it on its own.
|
||||
sync_settings = sync_settings.token(response.next_batch.clone());
|
||||
db.set_matrix_sync_token(response.next_batch).await?;
|
||||
break;
|
||||
}
|
||||
Err(error) => {
|
||||
log::error!("An error occurred during initial sync: {error}");
|
||||
log::error!("Trying again…");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log::info!("The client is ready! Listening to new messages…");
|
||||
|
||||
// Now that we've synced, let's attach a handler for incoming room messages.
|
||||
// client.add_event_handler(on_room_message);
|
||||
|
||||
// This loops until we kill the program or an error happens.
|
||||
client
|
||||
.sync_with_result_callback(sync_settings, |sync_result| async move {
|
||||
let response = sync_result?;
|
||||
|
||||
// We persist the token each time to be able to restore our session
|
||||
db.set_matrix_sync_token(response.next_batch)
|
||||
.await
|
||||
.map_err(|err| Error::UnknownError(err.into()))?;
|
||||
|
||||
Ok(LoopCtrl::Continue)
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use matrix_sdk::ruma::events::room::message::RoomMessageEventContent;
|
||||
use meshtastic::api::state::Connected;
|
||||
use meshtastic::api::{ConnectedStreamApi, StreamApi};
|
||||
|
@ -18,9 +20,8 @@ pub(crate) async fn build(
|
|||
config: config::MeshtasticConfig,
|
||||
) -> Result<MeshtasticClient, Box<dyn std::error::Error>> {
|
||||
let stream_api = StreamApi::new();
|
||||
|
||||
let tcp_stream = utils::stream::build_tcp_stream(config.address).await?;
|
||||
let (decoded_listener, stream_api) = stream_api.connect(tcp_stream).await;
|
||||
let serial_stream = utils::stream::build_serial_stream(config.device, None, None, None)?;
|
||||
let (decoded_listener, stream_api) = stream_api.connect(serial_stream).await;
|
||||
|
||||
log::info!("connected to meshtastic device");
|
||||
|
||||
|
@ -34,7 +35,7 @@ impl MeshtasticClient {
|
|||
pub async fn receive(
|
||||
mut self: MeshtasticClient,
|
||||
matrix_sender: Sender<RoomMessageEventContent>,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
) -> anyhow::Result<()> {
|
||||
// let config_id = utils::generate_rand_id();
|
||||
// let stream_api = stream_api.configure(config_id).await?;
|
||||
|
||||
|
@ -57,7 +58,7 @@ impl MeshtasticClient {
|
|||
|
||||
match payload_variant {
|
||||
PayloadVariant::Packet(packet) => {
|
||||
let payload_variant = match &packet.payload_variant {
|
||||
let payload_variant = match packet.payload_variant {
|
||||
Some(payload_variant) => payload_variant,
|
||||
None => {
|
||||
log::debug!(
|
||||
|
@ -69,7 +70,7 @@ impl MeshtasticClient {
|
|||
|
||||
match payload_variant {
|
||||
mesh_packet::PayloadVariant::Decoded(decoded) => {
|
||||
handle_decoded_packet(&matrix_sender, &packet, decoded).await?;
|
||||
handle_decoded_packet(&matrix_sender, decoded).await?;
|
||||
}
|
||||
mesh_packet::PayloadVariant::Encrypted(encrypted) => {
|
||||
log::debug!(
|
||||
|
@ -98,61 +99,42 @@ impl MeshtasticClient {
|
|||
PayloadVariant::Channel(channel) => {
|
||||
log::debug!("Channel: {:?}", channel);
|
||||
}
|
||||
PayloadVariant::Config(config) => {
|
||||
log::debug!("config: {:?}", config);
|
||||
}
|
||||
PayloadVariant::ConfigCompleteId(config_complete_id) => {
|
||||
log::debug!("config complete ID: {:?}", config_complete_id);
|
||||
}
|
||||
PayloadVariant::NodeInfo(node_info) => {
|
||||
log::debug!("node info: {:?}", node_info);
|
||||
}
|
||||
PayloadVariant::Rebooted(rebooted) => {
|
||||
log::debug!("rebooted: {:?}", rebooted);
|
||||
}
|
||||
PayloadVariant::ModuleConfig(module_config) => {
|
||||
log::debug!("module config: {:?}", module_config);
|
||||
}
|
||||
PayloadVariant::QueueStatus(queue_status) => {
|
||||
log::debug!("queue status: {:?}", queue_status);
|
||||
}
|
||||
PayloadVariant::XmodemPacket(xmodem_packet) => {
|
||||
log::debug!("xmodem packet: {:?}", xmodem_packet);
|
||||
}
|
||||
PayloadVariant::Metadata(metadata) => {
|
||||
log::debug!("metadata message: {:?}", metadata);
|
||||
}
|
||||
PayloadVariant::MqttClientProxyMessage(mqtt_client_proxy_message) => {
|
||||
log::debug!("mqtt client proxy message: {:?}", mqtt_client_proxy_message);
|
||||
}
|
||||
// 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(())
|
||||
}
|
||||
|
||||
pub async fn close(self: &mut MeshtasticClient) -> anyhow::Result<()> {
|
||||
self.decoded_listener.close();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_decoded_packet(
|
||||
matrix_sender: &Sender<RoomMessageEventContent>,
|
||||
packet: &meshtastic::protobufs::MeshPacket,
|
||||
decoded: &Data,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
// packet: MeshPacket,
|
||||
decoded: Data,
|
||||
) -> anyhow::Result<()> {
|
||||
match decoded.portnum() {
|
||||
meshtastic::protobufs::PortNum::TextMessageApp => {
|
||||
log::debug!("posting packet to matrix: {:?}", packet);
|
||||
log::debug!("decoded: {:?}", decoded);
|
||||
|
||||
let message = format!(
|
||||
"text from {:02x}: {} (snr: {}, rssi: {}, hop limit: {}, hop start: {})",
|
||||
packet.from,
|
||||
std::str::from_utf8(&decoded.payload)?,
|
||||
packet.rx_snr,
|
||||
packet.rx_rssi,
|
||||
packet.hop_limit,
|
||||
packet.hop_start
|
||||
);
|
||||
|
||||
debug_message(&matrix_sender, message).await?;
|
||||
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 ({})",
|
||||
|
|
Loading…
Reference in a new issue