Compare commits

...

4 commits

Author SHA1 Message Date
sinavir 63208ed6a6 feat: package 2024-05-22 16:59:36 +02:00
sinavir 435a85732c chore: clippy 2024-05-22 16:59:36 +02:00
sinavir a98da9d47c feat: Add retry for signal socket connection 2024-05-18 20:46:29 +02:00
sinavir a13272684d feat: Refactor config system 2024-05-18 20:46:29 +02:00
11 changed files with 607 additions and 69 deletions

2
.gitignore vendored
View file

@ -1,6 +1,8 @@
.config
/www
config.toml
# Added by cargo

394
Cargo.lock generated
View file

@ -79,6 +79,12 @@ dependencies = [
"rustc-demangle",
]
[[package]]
name = "base64"
version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
name = "beef"
version = "0.5.2"
@ -88,6 +94,15 @@ dependencies = [
"serde",
]
[[package]]
name = "bimap"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7"
dependencies = [
"serde",
]
[[package]]
name = "bitflags"
version = "1.3.2"
@ -99,6 +114,18 @@ name = "bitflags"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
dependencies = [
"serde",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "bumpalo"
@ -136,6 +163,55 @@ dependencies = [
"windows-targets 0.52.5",
]
[[package]]
name = "config"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7328b20597b53c2454f0b1919720c25c7339051c02b72b7e05409e00b14132be"
dependencies = [
"async-trait",
"convert_case",
"json5",
"lazy_static",
"nom",
"pathdiff",
"ron",
"rust-ini",
"serde",
"serde_json",
"toml 0.8.12",
"yaml-rust",
]
[[package]]
name = "const-random"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359"
dependencies = [
"const-random-macro",
]
[[package]]
name = "const-random-macro"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
dependencies = [
"getrandom",
"once_cell",
"tiny-keccak",
]
[[package]]
name = "convert_case"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "core-foundation"
version = "0.9.4"
@ -152,6 +228,50 @@ version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
[[package]]
name = "cpufeatures"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
dependencies = [
"libc",
]
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "dlv-list"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f"
dependencies = [
"const-random",
]
[[package]]
name = "encoding"
version = "0.2.33"
@ -361,12 +481,39 @@ dependencies = [
"slab",
]
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "gimli"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
[[package]]
name = "hashbrown"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
[[package]]
name = "hashbrown"
version = "0.14.3"
@ -421,7 +568,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
dependencies = [
"equivalent",
"hashbrown",
"hashbrown 0.14.3",
]
[[package]]
@ -445,7 +592,7 @@ dependencies = [
"tokio-native-tls",
"tokio-stream",
"tokio-util",
"toml",
"toml 0.7.8",
]
[[package]]
@ -487,6 +634,17 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "json5"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1"
dependencies = [
"pest",
"pest_derive",
"serde",
]
[[package]]
name = "jsonrpsee"
version = "0.22.4"
@ -559,6 +717,12 @@ version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "linked-hash-map"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]]
name = "linux-raw-sys"
version = "0.4.13"
@ -587,6 +751,12 @@ version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
[[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.2"
@ -625,6 +795,16 @@ dependencies = [
"tempfile",
]
[[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 = "num-traits"
version = "0.2.18"
@ -703,6 +883,16 @@ dependencies = [
"vcpkg",
]
[[package]]
name = "ordered-multimap"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ed8acf08e98e744e5384c8bc63ceb0364e68a6854187221c18df61c4797690e"
dependencies = [
"dlv-list",
"hashbrown 0.13.2",
]
[[package]]
name = "parking_lot"
version = "0.12.1"
@ -726,6 +916,57 @@ dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "pathdiff"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
[[package]]
name = "pest"
version = "2.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8"
dependencies = [
"memchr",
"thiserror",
"ucd-trie",
]
[[package]]
name = "pest_derive"
version = "2.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459"
dependencies = [
"pest",
"pest_generator",
]
[[package]]
name = "pest_generator"
version = "2.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687"
dependencies = [
"pest",
"pest_meta",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "pest_meta"
version = "2.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd"
dependencies = [
"once_cell",
"pest",
"sha2",
]
[[package]]
name = "pin-project"
version = "1.1.5"
@ -839,6 +1080,28 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
[[package]]
name = "ron"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94"
dependencies = [
"base64",
"bitflags 2.5.0",
"serde",
"serde_derive",
]
[[package]]
name = "rust-ini"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e2a3bcec1f113553ef1c88aae6c020a369d03d55b58de9869a0908930385091"
dependencies = [
"cfg-if",
"ordered-multimap",
]
[[package]]
name = "rustc-demangle"
version = "0.1.23"
@ -910,18 +1173,27 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.199"
version = "1.0.202"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a"
checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.199"
name = "serde-toml-merge"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc"
checksum = "e75a6b6c577215161d30ba4e13fb493c435a8b4140c442e590b61b4b2a27a226"
dependencies = [
"toml 0.8.12",
]
[[package]]
name = "serde_derive"
version = "1.0.202"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
dependencies = [
"proc-macro2",
"quote",
@ -948,6 +1220,17 @@ dependencies = [
"serde",
]
[[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"
@ -961,7 +1244,9 @@ dependencies = [
name = "signal-irc-bridge"
version = "0.1.0"
dependencies = [
"bimap",
"bytes",
"config",
"futures",
"futures-util",
"irc",
@ -969,11 +1254,13 @@ dependencies = [
"log",
"pretty_env_logger",
"serde",
"serde_derive",
"serde_json",
"thiserror",
"tokio",
"tokio-stream",
"tokio-util",
"toml-env",
]
[[package]]
@ -1053,6 +1340,15 @@ dependencies = [
"syn",
]
[[package]]
name = "tiny-keccak"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
dependencies = [
"crunchy",
]
[[package]]
name = "tokio"
version = "1.37.0"
@ -1130,6 +1426,31 @@ dependencies = [
"toml_edit 0.19.15",
]
[[package]]
name = "toml"
version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit 0.22.12",
]
[[package]]
name = "toml-env"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a740df0c7ded7632d527f5e4015c28c19803c9b8d6e87cc7ae72ae4d68d6f4b0"
dependencies = [
"log",
"serde",
"serde-toml-merge",
"thiserror",
"toml 0.8.12",
]
[[package]]
name = "toml_datetime"
version = "0.6.5"
@ -1149,7 +1470,7 @@ dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
"winnow 0.5.40",
]
[[package]]
@ -1160,7 +1481,20 @@ checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
dependencies = [
"indexmap",
"toml_datetime",
"winnow",
"winnow 0.5.40",
]
[[package]]
name = "toml_edit"
version = "0.22.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"winnow 0.6.8",
]
[[package]]
@ -1194,18 +1528,42 @@ dependencies = [
"once_cell",
]
[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "ucd-trie"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-segmentation"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
@ -1431,3 +1789,21 @@ checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
dependencies = [
"memchr",
]
[[package]]
name = "winnow"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d"
dependencies = [
"memchr",
]
[[package]]
name = "yaml-rust"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]

View file

@ -6,16 +6,20 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
bimap = { version = "0.6.3", features = ["serde"] }
bytes = "1.6.0"
config = { version = "0.14.0", features = ["toml"] }
futures = "0.3.30"
futures-util = "0.3.30"
irc = "1.0.0"
jsonrpsee = { version = "0.22.4", features = ["macros", "async-client"] }
log = "0.4.21"
pretty_env_logger = "0.5.0"
serde = "1.0.199"
serde = { version = "1.0.199", features = ["std", "alloc", "derive", "serde_derive"] }
serde_derive = "1.0.202"
serde_json = "1.0.116"
thiserror = "1.0.59"
tokio = { version = "1.37.0", features = ["full"] }
tokio-stream = "0.1.15"
tokio-util = "0.7.10"
toml-env = { version = "1.2.0", features = ["log"] }

4
default.nix Normal file
View file

@ -0,0 +1,4 @@
{
pkgs ? import (import ./npins).nixpkgs { },
}:
pkgs.callPackage ./package.nix {}

0
launch-signal-cli.sh Normal file → Executable file
View file

82
module.nix Normal file
View file

@ -0,0 +1,82 @@
{ pkgs, config, lib, ... }:
let
cfg = config.services.signal-irc-bridge;
mkSystemdRunOptions = opts: lib.escapeShellArgs (lib.mapAttrsToList (k: v: "-p${k}=${builtins.toString v}") opts);
commonServiceOptions = {
DynamicUser = true;
User = "signal-irc-client";
StateDirectory = "signal-cli";
RuntimeDirectory = "signal-cli";
PrivateDevices=true;
PrivateTmp=true;
ProtectControlGroups=true;
ProtectKernelTunables=true;
RestrictSUIDSGID=true;
ProtectSystem="strict";
ProtectKernelLogs=true;
ProtectProc="invisible";
PrivateUsers=true;
ProtectHome=true;
UMask="0077";
RuntimeDirectoryMode="0750";
StateDirectoryMode="0750";
};
signal-cli-bridge-wrapper = pkgs.writeShellApplication {
name = "signal-cli-bridge-wrapper";
text = ''
systemd-run ${mkSystemdRunOptions commonServiceOptions} --pty --pipe --unit="signal-cli-bridge" ${lib.getExe pkgs.signal-cli} --config "\''${STATE_DIRECTORY}"/signal-cli-config/ "$@"
'';
};
in {
options = {
services.signal-irc-bridge = {
enable = lib.mkEnableOption "signal-irc bridge";
package = lib.mkOption {
type = lib.types.package;
default = pkgs.signal-irc-bridge;
};
configFile = lib.mkOption {
type = lib.types.path;
description = "Path to the toml config file";
};
};
};
config = {
nixpkgs.overlays = [
(import ./overlay.nix)
];
systemd.services = lib.mkIf cfg.enable {
signal-irc-bridge = {
environment = {
CONFIG_PATH = cfg.configFile;
};
unitConfig = {
BindsTo = [ "signal-irc-bridge-signal-cli.service" ];
After = [ "signal-irc-bridge-signal-cli.service" ];
};
serviceConfig = commonServiceOptions // {
ExecStart = "${lib.getExe cfg.package}";
Restart = "always";
RestartSec= "5s";
StateDirectory = "signal-irc";
RuntimeDirectory = "signal-irc";
};
};
signal-irc-bridge-signal-cli = {
serviceConfig = commonServiceOptions // {
ExecStart = "${lib.getExe pkgs.signal-cli} --config \"\${STATE_DIRECTORY}\"/signal-cli-config/ daemon --socket \"\${RUNTIME_DIRECTORY}\"/socket --receive-mode=manual";
Restart = "always";
RestartSec= "5s";
};
};
};
environment.systemPackages = lib.mkIf cfg.enable [
signal-cli-bridge-wrapper
];
};
}

3
overlay.nix Normal file
View file

@ -0,0 +1,3 @@
final: prev: {
signal-irc-bridge = final.callPackage ./package.nix {};
}

25
package.nix Normal file
View file

@ -0,0 +1,25 @@
{ lib, openssl, pkg-config, rustPlatform }:
rustPlatform.buildRustPackage rec {
pname = "signal-irc-bridge";
version = "0.1";
src =
with lib.fileset;
toSource {
root = ./.;
fileset =
intersection (gitTracked ./.) (fileFilter (file: !file.hasExt "nix") ./.);
};
nativeBuildInputs = [
pkg-config
];
buildInputs = [
openssl
];
cargoHash = "sha256-J7+o6krHuK3CwwOIcDfm0s6F0cmviFQhSHpdKpXsa/g=";
}

39
src/config.rs Normal file
View file

@ -0,0 +1,39 @@
use std::env;
use std::path::Path;
use bimap::BiMap;
use irc::client::prelude::Config as IrcConfig;
use serde::{Deserialize, Serialize};
use toml_env::{initialize, Args, AutoMapEnvArgs, Logging};
#[derive(Debug, Deserialize, Serialize)]
pub struct BridgeConfig {
pub irc: IrcConfig,
pub signal: SignalConfig,
pub mapping: BiMap<String, String>,
}
impl BridgeConfig {
pub fn load() -> Result<BridgeConfig, String> {
initialize(Args {
config_path: env::var("CONFIG_PATH").ok().as_ref().map(Path::new),
logging: Logging::StdOut,
auto_map_env: Some(AutoMapEnvArgs {
divider: "__",
prefix: Some("BRIDGE"),
transform: Box::new(|name| name.to_lowercase()),
}),
..Args::default()
})
.map_err(|e| format!("failed to deserialize config: {e}"))
.map(|e| e.unwrap())
}
}
#[derive(Debug, Deserialize, Serialize)]
pub struct SignalConfig {
pub media_dir: Box<Path>,
pub signal_cli_dir: Box<Path>,
pub socket: Box<Path>,
pub url_root: String,
}

View file

@ -1,7 +1,7 @@
mod jsonrpc;
mod transform;
mod transports;
use std::path::Path;
mod config;
use futures::future::try_join;
use futures::prelude::*;
@ -9,28 +9,33 @@ use irc::client::prelude::*;
use irc::client::ClientStream;
use jsonrpsee::core::client::{Subscription, SubscriptionClientT};
use serde_json::Value;
use tokio::time::sleep;
use core::time::Duration;
use transform::Bridge;
use {log, pretty_env_logger};
use crate::jsonrpc::RpcClient;
use crate::config::BridgeConfig;
#[tokio::main]
async fn main() -> Result<(), String> {
pretty_env_logger::init();
log::info!("Starting...");
let config = Config::load("./config.toml").map_err(|e| format!("Error while loading config: {e}"))?;
check_config(&config);
let config = BridgeConfig::load()?;
// Initialisation of components. TODO separate module
let init_irc = async {
let mut client = Client::from_config(config.clone()).await.unwrap();
client.identify().unwrap();
let mut client = Client::from_config(config.irc.clone()).await.unwrap();
client
.identify()
.map_err(|e| format!("Error while initializing irc client: {e}"))?;
let sender = client.sender();
let mut stream = client.stream().unwrap();
let mut stream = client
.stream()
.map_err(|e| format!("Error while initializing irc stream: {e}"))?;
log::debug!("Initializing IRC");
while client.list_channels().is_some_and(|x| x.len() == 0) {
while client.list_channels().is_some_and(|x| x.is_empty()) {
stream
.next()
.await
@ -42,22 +47,34 @@ async fn main() -> Result<(), String> {
};
let init_signal = async {
log::debug!("Initializing Signal");
let signal_client = (async {
for i in 0..10 {
match jsonrpc::connect_unix(&config.signal.socket).await {
Ok(client) => {
return Ok(client);
}, Err(e) => {
log::info!("failed attempt {} connect to signal-cli socket: {:?}. Retrying", i, e);
},
}
sleep(Duration::from_secs(1)).await;
};
Err("Trying too many times to open socket")
let signal_client = jsonrpc::connect_unix(config.options.get("socket").unwrap())
}).await.map_err(|e| format!("failed to connect to signal socket: {e}"))?;
let signal_stream = signal_client
.subscribe_receive(None)
.await
.map_err(|e| format!("failed to connect to signal socket: {e}"))?;
let signal_stream = signal_client.subscribe_receive(None).await.unwrap();
.map_err(|e| format!("failed to subscribe to signal msg: {e}"))?;
log::debug!("Initialized Signal");
Ok((signal_stream, signal_client))
};
let ((sender, mut stream), (mut signal_stream, signal_client)) =
try_join(init_irc, init_signal).await?;
let bridge = Bridge::new(
&Path::new(config.options.get("media_dir").unwrap()),
&Path::new(config.options.get("signal_cli_dir").unwrap()),
&config.options.get("url_root").unwrap(),
&config.options.get("groupid").unwrap(),
&config.channels[0],
&config.signal.media_dir,
&config.signal.signal_cli_dir,
&config.signal.url_root,
&config.mapping,
);
// Run !!
@ -144,14 +161,3 @@ async fn handle_signal(
}
}
}
fn check_config(config: &Config) -> bool {
let keys = vec![
"groupid",
"media_dir",
"signal_cli_dir",
"socket",
"url_root",
];
keys.into_iter().fold(config.channels.len() >= 1, |b, k| b && config.options.contains_key(k))
}

View file

@ -1,40 +1,39 @@
use std::path::Path;
use bimap::BiMap;
use irc::client::prelude::*;
use serde_json::{Map, Value};
use tokio::fs::copy;
#[derive(Default)]
struct SignalMessageBuilder {
struct SignalMessageBuilder<'a> {
from: Option<String>,
message: Option<String>,
attachments_urls: Vec<String>,
valid: bool,
target: Option<&'a String>,
}
impl SignalMessageBuilder {
pub fn message(self: &mut Self, message: String) {
impl<'b> SignalMessageBuilder<'b> {
pub fn message(&mut self, message: String) {
self.message = Some(message);
}
pub fn from(self: &mut Self, from: String) {
pub fn from(&mut self, from: String) {
self.from = Some(from);
}
pub fn attach(self: &mut Self, attach: Vec<String>) {
pub fn attach(&mut self, attach: Vec<String>) {
self.attachments_urls.extend_from_slice(&attach);
}
pub fn valid(self: &mut Self, v: bool) {
self.valid = v;
pub fn target(&mut self, channel: Option<&'b String>) {
self.target = channel;
}
pub fn build(self: &Self) -> Option<String> {
if !self.valid {
return None;
}
pub fn build(self) -> Option<(&'b String, String)>
{
let attachments_text = self.attachments_urls.join(", ");
match (&self.message, attachments_text.len()) {
(match (&self.message, attachments_text.len()) {
(None, 0) => None,
(None, _) => self
.from
@ -45,7 +44,7 @@ impl SignalMessageBuilder {
.from
.as_ref()
.map(|from| format!("<{from}>: {m} ({attachments_text})")),
}
}).and_then(|m| self.target.map(|e| (e, m)))
}
}
@ -53,8 +52,7 @@ pub struct Bridge<'a> {
media_dir: &'a Path,
signalcli_dir: &'a Path,
url_root: &'a str,
groupid: &'a str,
irc_channel: &'a str,
mapping: &'a BiMap<String, String>,
}
impl<'a> Bridge<'a> {
@ -62,19 +60,17 @@ impl<'a> Bridge<'a> {
media_dir: &'a Path,
signalcli_dir: &'a Path,
url_root: &'a str,
groupid: &'a str,
irc_channel: &'a str,
mapping: &'a BiMap<String, String>,
) -> Self {
Self {
media_dir,
signalcli_dir,
url_root,
groupid,
irc_channel,
mapping,
}
}
async fn handle_attachment(self: &Self, attachment: &Value) -> Option<String> {
async fn handle_attachment(&self, attachment: &Value) -> Option<String> {
if let Value::Object(a) = attachment {
if let Some(Value::String(fname)) = a.get("id") {
match copy(
@ -98,9 +94,9 @@ impl<'a> Bridge<'a> {
}
async fn process_signal(
self: &Self,
&self,
message: &Map<String, Value>,
result: &mut SignalMessageBuilder,
result: &mut SignalMessageBuilder<'a>,
) {
if let Some(Value::Array(attachments)) = message.get("attachments") {
let mut attachments_urls = Vec::with_capacity(attachments.len());
@ -118,12 +114,12 @@ impl<'a> Bridge<'a> {
}
if let Some(Value::Object(group_info)) = message.get("groupInfo") {
if let Some(Value::String(groupid)) = group_info.get("groupId") {
result.valid(groupid == self.groupid);
result.target(self.mapping.get_by_right(groupid));
}
}
}
pub async fn signal2irc(self: &Self, signal: Value) -> Option<(&str, String)> {
pub async fn signal2irc(&self, signal: Value) -> Option<(&String, String)> {
let mut result: SignalMessageBuilder = SignalMessageBuilder::default();
if let Value::Object(map) = signal {
if let Some(Value::Object(envelope)) = map.get("envelope") {
@ -140,18 +136,19 @@ impl<'a> Bridge<'a> {
}
}
}
result.build().map(|e| (self.irc_channel, e))
result.build()
}
pub fn irc2signal(self: &Self, message: Message) -> Option<(&str, String)> {
pub fn irc2signal(&self, message: Message) -> Option<(&String, String)> {
match (message.prefix, message.command) {
(Some(Prefix::Nickname(from, _, _)), Command::PRIVMSG(_, message)) => {
Some(format!("<{from}>: {message}"))
(Some(Prefix::Nickname(from, _, _)), Command::PRIVMSG(channel, message)) => {
Some((channel, format!("<{from}>: {message}")))
}
(Some(Prefix::Nickname(from, _, _)), Command::NOTICE(_, message)) => {
Some(format!("📜 {from} {message}"))
(Some(Prefix::Nickname(from, _, _)), Command::NOTICE(channel, message)) => {
Some((channel, format!("📜 {from} {message}")))
}
_ => None,
}.map(|e| (self.groupid, e))
}
.and_then(|(channel, e)| self.mapping.get_by_left(&channel).map(|c| (c, e)))
}
}