Compare commits
2 commits
421e85cb0b
...
ea5e8ba430
Author | SHA1 | Date | |
---|---|---|---|
ea5e8ba430 | |||
43d939b890 |
25 changed files with 570 additions and 121 deletions
273
Cargo.lock
generated
273
Cargo.lock
generated
|
@ -81,7 +81,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"getrandom",
|
"getrandom 0.2.14",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"version_check",
|
"version_check",
|
||||||
"zerocopy",
|
"zerocopy",
|
||||||
|
@ -102,6 +102,21 @@ version = "0.2.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
|
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "android-tzdata"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "android_system_properties"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.6.13"
|
version = "0.6.13"
|
||||||
|
@ -162,6 +177,18 @@ version = "1.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arrayref"
|
||||||
|
version = "0.3.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arrayvec"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayvec"
|
name = "arrayvec"
|
||||||
version = "0.7.4"
|
version = "0.7.4"
|
||||||
|
@ -224,6 +251,12 @@ dependencies = [
|
||||||
"rustc-demangle",
|
"rustc-demangle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.21.7"
|
version = "0.21.7"
|
||||||
|
@ -248,6 +281,23 @@ version = "2.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
|
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "blake2b_simd"
|
||||||
|
version = "0.5.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587"
|
||||||
|
dependencies = [
|
||||||
|
"arrayref",
|
||||||
|
"arrayvec 0.5.2",
|
||||||
|
"constant_time_eq",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block-buffer"
|
name = "block-buffer"
|
||||||
version = "0.10.4"
|
version = "0.10.4"
|
||||||
|
@ -304,6 +354,20 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.38"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
|
||||||
|
dependencies = [
|
||||||
|
"android-tzdata",
|
||||||
|
"iana-time-zone",
|
||||||
|
"js-sys",
|
||||||
|
"num-traits",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows-targets 0.52.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chumsky"
|
name = "chumsky"
|
||||||
version = "0.9.3"
|
version = "0.9.3"
|
||||||
|
@ -393,6 +457,12 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "constant_time_eq"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
|
@ -512,6 +582,16 @@ version = "2.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2"
|
checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dbus"
|
||||||
|
version = "0.6.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48b5f0f36f1eebe901b0e6bee369a77ed3396334bf3f09abd46454a576f71819"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"libdbus-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deranged"
|
name = "deranged"
|
||||||
version = "0.3.11"
|
version = "0.3.11"
|
||||||
|
@ -570,6 +650,17 @@ dependencies = [
|
||||||
"subtle",
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dirs"
|
||||||
|
version = "1.0.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"redox_users",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "doc-comment"
|
name = "doc-comment"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
|
@ -805,6 +896,17 @@ dependencies = [
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.1.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi 0.9.0+wasi-snapshot-preview1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
|
@ -814,7 +916,7 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -856,6 +958,7 @@ dependencies = [
|
||||||
"kxio",
|
"kxio",
|
||||||
"lettre",
|
"lettre",
|
||||||
"mockall",
|
"mockall",
|
||||||
|
"notifica",
|
||||||
"notify",
|
"notify",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"rand",
|
"rand",
|
||||||
|
@ -2138,6 +2241,29 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone"
|
||||||
|
version = "0.1.60"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
|
||||||
|
dependencies = [
|
||||||
|
"android_system_properties",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"iana-time-zone-haiku",
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone-haiku"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
@ -2332,6 +2458,15 @@ version = "0.2.154"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
|
checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libdbus-sys"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06085512b750d640299b79be4bad3d2fa90a9c00b1fd9e1b46364f66f0485c72"
|
||||||
|
dependencies = [
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.4.13"
|
version = "0.4.13"
|
||||||
|
@ -2354,6 +2489,27 @@ version = "0.4.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mac-notification-sys"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3dfb6b71a9a89cd38b395d994214297447e8e63b1ba5708a9a2b0b1048ceda76"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"chrono",
|
||||||
|
"dirs",
|
||||||
|
"objc-foundation",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "malloc_buf"
|
||||||
|
version = "0.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matchers"
|
name = "matchers"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -2428,7 +2584,7 @@ checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"wasi",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2504,6 +2660,17 @@ dependencies = [
|
||||||
"minimal-lexical",
|
"minimal-lexical",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "notifica"
|
||||||
|
version = "3.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4e81fcdf9755383979b66adf525a66a8f621b55882a820552b201839b0ce3f7"
|
||||||
|
dependencies = [
|
||||||
|
"mac-notification-sys",
|
||||||
|
"notify-rust",
|
||||||
|
"winrt",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "notify"
|
name = "notify"
|
||||||
version = "6.1.1"
|
version = "6.1.1"
|
||||||
|
@ -2523,6 +2690,16 @@ dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "notify-rust"
|
||||||
|
version = "3.6.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8da29142be3f71b2165a6b3991c26045b674edbf04cdfc42f323094fc3e4b5a"
|
||||||
|
dependencies = [
|
||||||
|
"dbus",
|
||||||
|
"mac-notification-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-ansi-term"
|
name = "nu-ansi-term"
|
||||||
version = "0.46.0"
|
version = "0.46.0"
|
||||||
|
@ -2539,6 +2716,15 @@ version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_cpus"
|
name = "num_cpus"
|
||||||
version = "1.16.0"
|
version = "1.16.0"
|
||||||
|
@ -2558,6 +2744,35 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc"
|
||||||
|
version = "0.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
|
||||||
|
dependencies = [
|
||||||
|
"malloc_buf",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc-foundation"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
|
||||||
|
dependencies = [
|
||||||
|
"block",
|
||||||
|
"objc",
|
||||||
|
"objc_id",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc_id"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
|
||||||
|
dependencies = [
|
||||||
|
"objc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "object"
|
name = "object"
|
||||||
version = "0.32.2"
|
version = "0.32.2"
|
||||||
|
@ -2832,7 +3047,7 @@ version = "0.6.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom 0.2.14",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2855,6 +3070,12 @@ dependencies = [
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.1.57"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
|
@ -2873,6 +3094,17 @@ dependencies = [
|
||||||
"bitflags 2.5.0",
|
"bitflags 2.5.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_users"
|
||||||
|
version = "0.3.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.1.16",
|
||||||
|
"redox_syscall 0.1.57",
|
||||||
|
"rust-argon2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.10.4"
|
version = "1.10.4"
|
||||||
|
@ -2973,13 +3205,25 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"getrandom",
|
"getrandom 0.2.14",
|
||||||
"libc",
|
"libc",
|
||||||
"spin",
|
"spin",
|
||||||
"untrusted",
|
"untrusted",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rust-argon2"
|
||||||
|
version = "0.8.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.13.1",
|
||||||
|
"blake2b_simd",
|
||||||
|
"constant_time_eq",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "rustc-demangle"
|
||||||
version = "0.1.23"
|
version = "0.1.23"
|
||||||
|
@ -3770,7 +4014,7 @@ version = "1.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "34778c17965aa2a08913b57e1f34db9b4a63f5de31768b55bf20d2795f921259"
|
checksum = "34778c17965aa2a08913b57e1f34db9b4a63f5de31768b55bf20d2795f921259"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom 0.2.14",
|
||||||
"rand",
|
"rand",
|
||||||
"web-time",
|
"web-time",
|
||||||
]
|
]
|
||||||
|
@ -3781,7 +4025,7 @@ version = "3.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7c8a2469e56e6e5095c82ccd3afb98dad95f7af7929aab6d8ba8d6e0f73657da"
|
checksum = "7c8a2469e56e6e5095c82ccd3afb98dad95f7af7929aab6d8ba8d6e0f73657da"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec 0.7.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3921,6 +4165,12 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.9.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
@ -4230,6 +4480,15 @@ dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winrt"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c248f437add7df81d305a345e9d143c8c0a9de00a51e46b42453c337181d16c9"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xml-rs"
|
name = "xml-rs"
|
||||||
version = "0.8.20"
|
version = "0.8.20"
|
||||||
|
|
|
@ -96,6 +96,9 @@ tokio = { version = "1.37", features = ["rt", "macros"] }
|
||||||
lettre = "0.11"
|
lettre = "0.11"
|
||||||
sendmail = "2.0"
|
sendmail = "2.0"
|
||||||
|
|
||||||
|
# desktop notifications
|
||||||
|
notifica = "3.0"
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
assert2 = "0.3"
|
assert2 = "0.3"
|
||||||
pretty_assertions = "1.4"
|
pretty_assertions = "1.4"
|
||||||
|
|
|
@ -70,6 +70,9 @@ notify = { workspace = true }
|
||||||
lettre = { workspace = true }
|
lettre = { workspace = true }
|
||||||
sendmail = { workspace = true }
|
sendmail = { workspace = true }
|
||||||
|
|
||||||
|
# desktop notifications
|
||||||
|
notifica = { workspace = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
# Testing
|
# Testing
|
||||||
assert2 = { workspace = true }
|
assert2 = { workspace = true }
|
||||||
|
|
|
@ -29,6 +29,8 @@ See [Behaviour](#behaviour) to learn how we do this.
|
||||||
- Rust 1.76.0 or later - https://www.rust-lang.org
|
- Rust 1.76.0 or later - https://www.rust-lang.org
|
||||||
- pgk-config
|
- pgk-config
|
||||||
- libssl-dev
|
- libssl-dev
|
||||||
|
- libdbus-1-dev (ubuntu/debian)
|
||||||
|
- dbus-devel (fedora)
|
||||||
|
|
||||||
### x86_64-unknown-linux-gnu
|
### x86_64-unknown-linux-gnu
|
||||||
|
|
||||||
|
@ -125,6 +127,9 @@ forge is running on.
|
||||||
The server should be able to notify the user when manual intervention is required.
|
The server should be able to notify the user when manual intervention is required.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
|
[shoult]
|
||||||
|
desktop = true
|
||||||
|
|
||||||
[shout.webhook]
|
[shout.webhook]
|
||||||
url = "https//localhost:9090"
|
url = "https//localhost:9090"
|
||||||
secret = "secret-password"
|
secret = "secret-password"
|
||||||
|
@ -139,6 +144,10 @@ username = "git-next@example.com"
|
||||||
password = "MySecretEmailPassword42"
|
password = "MySecretEmailPassword42"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
##### desktop
|
||||||
|
|
||||||
|
When specified as `true`, desktop notifications will be sent for some events.
|
||||||
|
|
||||||
##### webhook
|
##### webhook
|
||||||
|
|
||||||
Will send a POST request for some events.
|
Will send a POST request for some events.
|
||||||
|
|
9
crates/cli/src/alerts/desktop.rs
Normal file
9
crates/cli/src/alerts/desktop.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
//
|
||||||
|
use crate::alerts::{messages::NotifyUser, short_message};
|
||||||
|
|
||||||
|
pub(super) fn send_desktop_notification(msg: &NotifyUser) {
|
||||||
|
let message = short_message(msg);
|
||||||
|
if let Err(err) = notifica::notify("git-next", &message) {
|
||||||
|
tracing::warn!(?err, "failed to send desktop notification");
|
||||||
|
}
|
||||||
|
}
|
68
crates/cli/src/alerts/email.rs
Normal file
68
crates/cli/src/alerts/email.rs
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
//
|
||||||
|
use git_next_core::server::{EmailConfig, SmtpConfig};
|
||||||
|
|
||||||
|
use crate::alerts::{full_message, messages::NotifyUser, short_message};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct EmailMessage {
|
||||||
|
from: String,
|
||||||
|
to: String,
|
||||||
|
subject: String,
|
||||||
|
body: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn send_email(msg: &NotifyUser, email_config: &EmailConfig) {
|
||||||
|
let email_message = EmailMessage {
|
||||||
|
from: email_config.from().to_string(),
|
||||||
|
to: email_config.to().to_string(),
|
||||||
|
subject: short_message(msg),
|
||||||
|
body: full_message(msg),
|
||||||
|
};
|
||||||
|
match email_config.smtp() {
|
||||||
|
Some(smtp) => send_email_smtp(email_message, smtp),
|
||||||
|
None => send_email_sendmail(email_message),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_email_sendmail(email_message: EmailMessage) {
|
||||||
|
use sendmail::email;
|
||||||
|
match email::send(
|
||||||
|
&email_message.from,
|
||||||
|
[email_message.to.as_ref()],
|
||||||
|
&email_message.subject,
|
||||||
|
&email_message.body,
|
||||||
|
) {
|
||||||
|
Ok(_) => tracing::info!("Email sent successfully!"),
|
||||||
|
Err(e) => tracing::warn!("Could not send email: {:?}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_email_smtp(email_message: EmailMessage, smtp: &SmtpConfig) {
|
||||||
|
if let Err(err) = do_send_email_smtp(email_message, smtp) {
|
||||||
|
tracing::warn!(?err, "sending email");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_send_email_smtp(email_message: EmailMessage, smtp: &SmtpConfig) -> Result<(), anyhow::Error> {
|
||||||
|
use lettre::{transport::smtp::authentication::Credentials, Message, SmtpTransport, Transport};
|
||||||
|
let email = Message::builder()
|
||||||
|
.from(email_message.from.parse()?)
|
||||||
|
.to(email_message.to.parse()?)
|
||||||
|
.subject(email_message.subject)
|
||||||
|
.body(email_message.body)?;
|
||||||
|
let creds = Credentials::new(smtp.username().to_string(), smtp.password().to_string());
|
||||||
|
let mailer = SmtpTransport::relay(smtp.hostname())?
|
||||||
|
.credentials(creds)
|
||||||
|
.build();
|
||||||
|
Ok(mailer
|
||||||
|
.send(&email)
|
||||||
|
.map(|response| {
|
||||||
|
response
|
||||||
|
.message()
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
})
|
||||||
|
.map(|response| {
|
||||||
|
tracing::info!(?response, "email sent via smtp");
|
||||||
|
})?)
|
||||||
|
}
|
2
crates/cli/src/alerts/handlers/mod.rs
Normal file
2
crates/cli/src/alerts/handlers/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
mod notify_user;
|
||||||
|
mod update_shout;
|
36
crates/cli/src/alerts/handlers/notify_user.rs
Normal file
36
crates/cli/src/alerts/handlers/notify_user.rs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
//
|
||||||
|
use actix::prelude::*;
|
||||||
|
use tracing::{info, instrument, Instrument as _};
|
||||||
|
|
||||||
|
use crate::alerts::{
|
||||||
|
desktop::send_desktop_notification, email::send_email, messages::NotifyUser,
|
||||||
|
webhook::send_webhook, AlertsActor,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl Handler<NotifyUser> for AlertsActor {
|
||||||
|
type Result = ();
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
|
fn handle(&mut self, msg: NotifyUser, ctx: &mut Self::Context) -> Self::Result {
|
||||||
|
let Some(shout) = &self.shout else {
|
||||||
|
info!("No shout config available");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let net = self.net.clone();
|
||||||
|
let shout = shout.clone();
|
||||||
|
async move {
|
||||||
|
if let Some(webhook_config) = shout.webhook() {
|
||||||
|
send_webhook(&msg, webhook_config, &net).await;
|
||||||
|
}
|
||||||
|
if let Some(email_config) = shout.email() {
|
||||||
|
send_email(&msg, email_config);
|
||||||
|
}
|
||||||
|
if shout.desktop() {
|
||||||
|
send_desktop_notification(&msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.in_current_span()
|
||||||
|
.into_actor(self)
|
||||||
|
.wait(ctx);
|
||||||
|
}
|
||||||
|
}
|
12
crates/cli/src/alerts/handlers/update_shout.rs
Normal file
12
crates/cli/src/alerts/handlers/update_shout.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
//
|
||||||
|
use actix::prelude::*;
|
||||||
|
|
||||||
|
use crate::alerts::{messages::UpdateShout, AlertsActor};
|
||||||
|
|
||||||
|
impl Handler<UpdateShout> for AlertsActor {
|
||||||
|
type Result = ();
|
||||||
|
|
||||||
|
fn handle(&mut self, msg: UpdateShout, _ctx: &mut Self::Context) -> Self::Result {
|
||||||
|
self.shout.replace(msg.unwrap());
|
||||||
|
}
|
||||||
|
}
|
2
crates/cli/src/alerts/history.rs
Normal file
2
crates/cli/src/alerts/history.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct History {}
|
86
crates/cli/src/alerts/messages.rs
Normal file
86
crates/cli/src/alerts/messages.rs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
//
|
||||||
|
use derive_more::Deref as _;
|
||||||
|
use git_next_core::{git::UserNotification, message, server::Shout};
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
|
message!(UpdateShout: Shout: "Updated Shout configuration");
|
||||||
|
|
||||||
|
message!(NotifyUser: UserNotification: "Request to send the message payload to the notification webhook");
|
||||||
|
impl NotifyUser {
|
||||||
|
pub fn as_json(&self, timestamp: time::OffsetDateTime) -> serde_json::Value {
|
||||||
|
let timestamp = timestamp.unix_timestamp().to_string();
|
||||||
|
match self.deref() {
|
||||||
|
UserNotification::CICheckFailed {
|
||||||
|
forge_alias,
|
||||||
|
repo_alias,
|
||||||
|
commit,
|
||||||
|
} => json!({
|
||||||
|
"type": "cicheck.failed",
|
||||||
|
"timestamp": timestamp,
|
||||||
|
"data": {
|
||||||
|
"forge_alias": forge_alias,
|
||||||
|
"repo_alias": repo_alias,
|
||||||
|
"commit": {
|
||||||
|
"sha": commit.sha(),
|
||||||
|
"message": commit.message()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
UserNotification::RepoConfigLoadFailure {
|
||||||
|
forge_alias,
|
||||||
|
repo_alias,
|
||||||
|
reason,
|
||||||
|
} => json!({
|
||||||
|
"type": "config.load.failed",
|
||||||
|
"timestamp": timestamp,
|
||||||
|
"data": {
|
||||||
|
"forge_alias": forge_alias,
|
||||||
|
"repo_alias": repo_alias,
|
||||||
|
"reason": reason
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
UserNotification::WebhookRegistration {
|
||||||
|
forge_alias,
|
||||||
|
repo_alias,
|
||||||
|
reason,
|
||||||
|
} => json!({
|
||||||
|
"type": "webhook.registration.failed",
|
||||||
|
"timestamp": timestamp,
|
||||||
|
"data": {
|
||||||
|
"forge_alias": forge_alias,
|
||||||
|
"repo_alias": repo_alias,
|
||||||
|
"reason": reason
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
UserNotification::DevNotBasedOnMain {
|
||||||
|
forge_alias,
|
||||||
|
repo_alias,
|
||||||
|
dev_branch,
|
||||||
|
main_branch,
|
||||||
|
dev_commit,
|
||||||
|
main_commit,
|
||||||
|
} => json!({
|
||||||
|
"type": "branch.dev.not-on-main",
|
||||||
|
"timestamp": timestamp,
|
||||||
|
"data": {
|
||||||
|
"forge_alias": forge_alias,
|
||||||
|
"repo_alias": repo_alias,
|
||||||
|
"branches": {
|
||||||
|
"dev": dev_branch,
|
||||||
|
"main": main_branch
|
||||||
|
},
|
||||||
|
"commits": {
|
||||||
|
"dev": {
|
||||||
|
"sha": dev_commit.sha(),
|
||||||
|
"message": dev_commit.message()
|
||||||
|
},
|
||||||
|
"main": {
|
||||||
|
"sha": main_commit.sha(),
|
||||||
|
"message": main_commit.message()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,77 +1,35 @@
|
||||||
use std::ops::Deref as _;
|
use std::ops::Deref as _;
|
||||||
|
|
||||||
use git_next_core::{
|
//
|
||||||
git::UserNotification,
|
use actix::prelude::*;
|
||||||
server::{EmailConfig, SmtpConfig},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::repo::messages::NotifyUser;
|
use derive_more::derive::Constructor;
|
||||||
|
|
||||||
#[derive(Debug)]
|
use git_next_core::{git::UserNotification, server::Shout};
|
||||||
struct EmailMessage {
|
|
||||||
from: String,
|
pub use history::History;
|
||||||
to: String,
|
use messages::NotifyUser;
|
||||||
subject: String,
|
|
||||||
body: String,
|
mod desktop;
|
||||||
|
mod email;
|
||||||
|
mod handlers;
|
||||||
|
mod history;
|
||||||
|
pub mod messages;
|
||||||
|
mod webhook;
|
||||||
|
|
||||||
|
#[derive(Debug, Constructor)]
|
||||||
|
pub struct AlertsActor {
|
||||||
|
shout: Option<Shout>, // config for sending alerts to users
|
||||||
|
#[allow(dead_code)] // TODO (#128) Prevent duplicate user notifications
|
||||||
|
history: History, // record of alerts sent recently (e.g. 24 hours)
|
||||||
|
net: kxio::network::Network,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn send_email(msg: &NotifyUser, email_config: &EmailConfig) {
|
impl Actor for AlertsActor {
|
||||||
let email_message = EmailMessage {
|
type Context = Context<Self>;
|
||||||
from: email_config.from().to_string(),
|
|
||||||
to: email_config.to().to_string(),
|
|
||||||
subject: email_subject(msg),
|
|
||||||
body: email_body(msg),
|
|
||||||
};
|
|
||||||
match email_config.smtp() {
|
|
||||||
Some(smtp) => send_email_smtp(email_message, smtp),
|
|
||||||
None => send_email_sendmail(email_message),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_email_sendmail(email_message: EmailMessage) {
|
fn short_message(msg: &NotifyUser) -> String {
|
||||||
use sendmail::email;
|
|
||||||
match email::send(
|
|
||||||
&email_message.from,
|
|
||||||
[email_message.to.as_ref()],
|
|
||||||
&email_message.subject,
|
|
||||||
&email_message.body,
|
|
||||||
) {
|
|
||||||
Ok(_) => tracing::info!("Email sent successfully!"),
|
|
||||||
Err(e) => tracing::warn!("Could not send email: {:?}", e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send_email_smtp(email_message: EmailMessage, smtp: &SmtpConfig) {
|
|
||||||
if let Err(err) = do_send_email_smtp(email_message, smtp) {
|
|
||||||
tracing::warn!(?err, "sending email");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_send_email_smtp(email_message: EmailMessage, smtp: &SmtpConfig) -> Result<(), anyhow::Error> {
|
|
||||||
use lettre::{transport::smtp::authentication::Credentials, Message, SmtpTransport, Transport};
|
|
||||||
let email = Message::builder()
|
|
||||||
.from(email_message.from.parse()?)
|
|
||||||
.to(email_message.to.parse()?)
|
|
||||||
.subject(email_message.subject)
|
|
||||||
.body(email_message.body)?;
|
|
||||||
let creds = Credentials::new(smtp.username().to_string(), smtp.password().to_string());
|
|
||||||
let mailer = SmtpTransport::relay(smtp.hostname())?
|
|
||||||
.credentials(creds)
|
|
||||||
.build();
|
|
||||||
Ok(mailer
|
|
||||||
.send(&email)
|
|
||||||
.map(|response| {
|
|
||||||
response
|
|
||||||
.message()
|
|
||||||
.map(|s| s.to_string())
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
})
|
|
||||||
.map(|response| {
|
|
||||||
tracing::info!(?response, "email sent via smtp");
|
|
||||||
})?)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn email_subject(msg: &NotifyUser) -> String {
|
|
||||||
let tail = match msg.deref() {
|
let tail = match msg.deref() {
|
||||||
UserNotification::CICheckFailed {
|
UserNotification::CICheckFailed {
|
||||||
forge_alias,
|
forge_alias,
|
||||||
|
@ -100,7 +58,7 @@ fn email_subject(msg: &NotifyUser) -> String {
|
||||||
format!("[git-next] {tail}")
|
format!("[git-next] {tail}")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn email_body(msg: &NotifyUser) -> String {
|
fn full_message(msg: &NotifyUser) -> String {
|
||||||
match msg.deref() {
|
match msg.deref() {
|
||||||
UserNotification::CICheckFailed {
|
UserNotification::CICheckFailed {
|
||||||
forge_alias,
|
forge_alias,
|
|
@ -3,7 +3,7 @@ use git_next_core::server::OutboundWebhook;
|
||||||
use secrecy::ExposeSecret as _;
|
use secrecy::ExposeSecret as _;
|
||||||
use standardwebhooks::Webhook;
|
use standardwebhooks::Webhook;
|
||||||
|
|
||||||
use crate::repo::messages::NotifyUser;
|
use crate::alerts::messages::NotifyUser;
|
||||||
|
|
||||||
pub(super) async fn send_webhook(
|
pub(super) async fn send_webhook(
|
||||||
msg: &NotifyUser,
|
msg: &NotifyUser,
|
|
@ -1,4 +1,5 @@
|
||||||
//
|
//
|
||||||
|
mod alerts;
|
||||||
mod file_watcher;
|
mod file_watcher;
|
||||||
mod forge;
|
mod forge;
|
||||||
mod init;
|
mod init;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
//
|
//
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
|
|
||||||
|
use crate::alerts::messages::NotifyUser;
|
||||||
use derive_more::Deref;
|
use derive_more::Deref;
|
||||||
use kxio::network::Network;
|
use kxio::network::Network;
|
||||||
use messages::NotifyUser;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tracing::{info, warn, Instrument};
|
use tracing::{info, warn, Instrument};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
mod file_updated;
|
mod file_updated;
|
||||||
mod notify_user;
|
|
||||||
mod receive_server_config;
|
mod receive_server_config;
|
||||||
mod receive_valid_server_config;
|
mod receive_valid_server_config;
|
||||||
mod shutdown;
|
mod shutdown;
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
//
|
|
||||||
mod email;
|
|
||||||
mod webhook;
|
|
||||||
|
|
||||||
use actix::prelude::*;
|
|
||||||
|
|
||||||
use email::send_email;
|
|
||||||
use tracing::Instrument;
|
|
||||||
use webhook::send_webhook;
|
|
||||||
|
|
||||||
use crate::{repo::messages::NotifyUser, server::actor::ServerActor};
|
|
||||||
|
|
||||||
impl Handler<NotifyUser> for ServerActor {
|
|
||||||
type Result = ();
|
|
||||||
|
|
||||||
fn handle(&mut self, msg: NotifyUser, ctx: &mut Self::Context) -> Self::Result {
|
|
||||||
let Some(server_config) = &self.server_config else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let shout_config = server_config.shout().clone();
|
|
||||||
let net = self.net.clone();
|
|
||||||
async move {
|
|
||||||
if let Some(webhook_config) = shout_config.webhook() {
|
|
||||||
send_webhook(&msg, webhook_config, &net).await;
|
|
||||||
}
|
|
||||||
if let Some(email_config) = shout_config.email() {
|
|
||||||
send_email(&msg, email_config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.in_current_span()
|
|
||||||
.into_actor(self)
|
|
||||||
.wait(ctx);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,6 +4,7 @@ use actix::prelude::*;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
alerts::messages::UpdateShout,
|
||||||
server::actor::{
|
server::actor::{
|
||||||
messages::{ReceiveValidServerConfig, ValidServerConfig},
|
messages::{ReceiveValidServerConfig, ValidServerConfig},
|
||||||
ServerActor,
|
ServerActor,
|
||||||
|
@ -18,7 +19,7 @@ use crate::{
|
||||||
impl Handler<ReceiveValidServerConfig> for ServerActor {
|
impl Handler<ReceiveValidServerConfig> for ServerActor {
|
||||||
type Result = ();
|
type Result = ();
|
||||||
|
|
||||||
fn handle(&mut self, msg: ReceiveValidServerConfig, ctx: &mut Self::Context) -> Self::Result {
|
fn handle(&mut self, msg: ReceiveValidServerConfig, _ctx: &mut Self::Context) -> Self::Result {
|
||||||
let ValidServerConfig {
|
let ValidServerConfig {
|
||||||
server_config,
|
server_config,
|
||||||
socket_address,
|
socket_address,
|
||||||
|
@ -33,6 +34,7 @@ impl Handler<ReceiveValidServerConfig> for ServerActor {
|
||||||
info!("Starting Webhook Server...");
|
info!("Starting Webhook Server...");
|
||||||
let webhook_router = WebhookRouter::default().start();
|
let webhook_router = WebhookRouter::default().start();
|
||||||
let listen_url = server_config.listen().url();
|
let listen_url = server_config.listen().url();
|
||||||
|
let alerts = self.alerts.clone();
|
||||||
// Forge Actors
|
// Forge Actors
|
||||||
for (forge_alias, forge_config) in server_config.forges() {
|
for (forge_alias, forge_config) in server_config.forges() {
|
||||||
let repo_actors = self
|
let repo_actors = self
|
||||||
|
@ -41,7 +43,7 @@ impl Handler<ReceiveValidServerConfig> for ServerActor {
|
||||||
forge_alias.clone(),
|
forge_alias.clone(),
|
||||||
&server_storage,
|
&server_storage,
|
||||||
listen_url,
|
listen_url,
|
||||||
ctx.address().recipient(),
|
alerts.clone().recipient(),
|
||||||
)
|
)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|a| self.start_actor(a))
|
.map(|a| self.start_actor(a))
|
||||||
|
@ -64,6 +66,8 @@ impl Handler<ReceiveValidServerConfig> for ServerActor {
|
||||||
let webhook_actor_addr =
|
let webhook_actor_addr =
|
||||||
WebhookActor::new(socket_address, webhook_router.recipient()).start();
|
WebhookActor::new(socket_address, webhook_router.recipient()).start();
|
||||||
self.webhook_actor_addr.replace(webhook_actor_addr);
|
self.webhook_actor_addr.replace(webhook_actor_addr);
|
||||||
|
let shout = server_config.shout().clone();
|
||||||
self.server_config.replace(server_config);
|
self.server_config.replace(server_config);
|
||||||
|
self.alerts.do_send(UpdateShout::new(shout));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,10 @@ mod handlers;
|
||||||
pub mod messages;
|
pub mod messages;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
alerts::messages::NotifyUser,
|
||||||
|
alerts::AlertsActor,
|
||||||
forge::Forge,
|
forge::Forge,
|
||||||
repo::{
|
repo::{messages::CloneRepo, RepoActor},
|
||||||
messages::{CloneRepo, NotifyUser},
|
|
||||||
RepoActor,
|
|
||||||
},
|
|
||||||
webhook::WebhookActor,
|
webhook::WebhookActor,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -56,6 +55,7 @@ pub struct ServerActor {
|
||||||
webhook_actor_addr: Option<Addr<WebhookActor>>,
|
webhook_actor_addr: Option<Addr<WebhookActor>>,
|
||||||
fs: FileSystem,
|
fs: FileSystem,
|
||||||
net: Network,
|
net: Network,
|
||||||
|
alerts: Addr<AlertsActor>,
|
||||||
repository_factory: Box<dyn RepositoryFactory>,
|
repository_factory: Box<dyn RepositoryFactory>,
|
||||||
sleep_duration: std::time::Duration,
|
sleep_duration: std::time::Duration,
|
||||||
repo_actors: BTreeMap<(ForgeAlias, RepoAlias), Addr<RepoActor>>,
|
repo_actors: BTreeMap<(ForgeAlias, RepoAlias), Addr<RepoActor>>,
|
||||||
|
@ -71,6 +71,7 @@ impl ServerActor {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
fs: FileSystem,
|
fs: FileSystem,
|
||||||
net: Network,
|
net: Network,
|
||||||
|
alerts: Addr<AlertsActor>,
|
||||||
repo: Box<dyn RepositoryFactory>,
|
repo: Box<dyn RepositoryFactory>,
|
||||||
sleep_duration: std::time::Duration,
|
sleep_duration: std::time::Duration,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -81,6 +82,7 @@ impl ServerActor {
|
||||||
webhook_actor_addr: None,
|
webhook_actor_addr: None,
|
||||||
fs,
|
fs,
|
||||||
net,
|
net,
|
||||||
|
alerts,
|
||||||
repository_factory: repo,
|
repository_factory: repo,
|
||||||
sleep_duration,
|
sleep_duration,
|
||||||
repo_actors: BTreeMap::new(),
|
repo_actors: BTreeMap::new(),
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
use actix::prelude::*;
|
||||||
|
|
||||||
|
use crate::alerts::{AlertsActor, History};
|
||||||
|
|
||||||
|
//
|
||||||
pub fn a_filesystem() -> kxio::fs::FileSystem {
|
pub fn a_filesystem() -> kxio::fs::FileSystem {
|
||||||
kxio::fs::temp().unwrap_or_else(|e| panic!("{}", e))
|
kxio::fs::temp().unwrap_or_else(|e| panic!("{}", e))
|
||||||
}
|
}
|
||||||
|
@ -5,3 +10,7 @@ pub fn a_filesystem() -> kxio::fs::FileSystem {
|
||||||
pub fn a_network() -> kxio::network::MockNetwork {
|
pub fn a_network() -> kxio::network::MockNetwork {
|
||||||
kxio::network::MockNetwork::new()
|
kxio::network::MockNetwork::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn an_alerts_actor(net: kxio::network::Network) -> Addr<AlertsActor> {
|
||||||
|
AlertsActor::new(None, History::default(), net).start()
|
||||||
|
}
|
||||||
|
|
|
@ -18,11 +18,12 @@ async fn when_webhook_url_has_trailing_slash_should_not_send() {
|
||||||
// parameters
|
// parameters
|
||||||
let fs = given::a_filesystem();
|
let fs = given::a_filesystem();
|
||||||
let net = given::a_network();
|
let net = given::a_network();
|
||||||
|
let alerts = given::an_alerts_actor(net.clone().into());
|
||||||
let repo = git::repository::factory::mock();
|
let repo = git::repository::factory::mock();
|
||||||
let duration = std::time::Duration::from_millis(1);
|
let duration = std::time::Duration::from_millis(1);
|
||||||
|
|
||||||
// sut
|
// sut
|
||||||
let server = ServerActor::new(fs.clone(), net.into(), repo, duration);
|
let server = ServerActor::new(fs.clone(), net.into(), alerts, repo, duration);
|
||||||
|
|
||||||
// collaborators
|
// collaborators
|
||||||
let listen = Listen::new(
|
let listen = Listen::new(
|
||||||
|
|
|
@ -6,7 +6,10 @@ mod tests;
|
||||||
|
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
|
|
||||||
use crate::file_watcher::{watch_file, FileUpdated};
|
use crate::{
|
||||||
|
alerts::{AlertsActor, History},
|
||||||
|
file_watcher::{watch_file, FileUpdated},
|
||||||
|
};
|
||||||
use actor::ServerActor;
|
use actor::ServerActor;
|
||||||
use git_next_core::git::RepositoryFactory;
|
use git_next_core::git::RepositoryFactory;
|
||||||
|
|
||||||
|
@ -41,8 +44,18 @@ pub fn start(
|
||||||
init_logging();
|
init_logging();
|
||||||
|
|
||||||
let execution = async move {
|
let execution = async move {
|
||||||
|
info!("Starting Alert Dispatcher...");
|
||||||
|
let alerts_addr = AlertsActor::new(None, History::default(), net.clone()).start();
|
||||||
|
|
||||||
info!("Starting Server...");
|
info!("Starting Server...");
|
||||||
let server = ServerActor::new(fs.clone(), net.clone(), repo, sleep_duration).start();
|
let server = ServerActor::new(
|
||||||
|
fs.clone(),
|
||||||
|
net.clone(),
|
||||||
|
alerts_addr.clone(),
|
||||||
|
repo,
|
||||||
|
sleep_duration,
|
||||||
|
)
|
||||||
|
.start();
|
||||||
server.do_send(FileUpdated);
|
server.do_send(FileUpdated);
|
||||||
|
|
||||||
info!("Starting File Watcher...");
|
info!("Starting File Watcher...");
|
||||||
|
|
|
@ -8,6 +8,7 @@ url = "https://localhost:8080" # don't include any query path or a trailing slas
|
||||||
|
|
||||||
[shout] # where updates from git-next should be sent to alert the user
|
[shout] # where updates from git-next should be sent to alert the user
|
||||||
# webhook = { url = "https//localhost:9090", secret = "secret-password" }
|
# webhook = { url = "https//localhost:9090", secret = "secret-password" }
|
||||||
|
# desktop = true # enable desktop notifications
|
||||||
|
|
||||||
# [shout.email]
|
# [shout.email]
|
||||||
# from = "git-next@example.com"
|
# from = "git-next@example.com"
|
||||||
|
|
|
@ -209,6 +209,7 @@ impl ServerStorage {
|
||||||
pub struct Shout {
|
pub struct Shout {
|
||||||
webhook: Option<OutboundWebhook>,
|
webhook: Option<OutboundWebhook>,
|
||||||
email: Option<EmailConfig>,
|
email: Option<EmailConfig>,
|
||||||
|
desktop: bool,
|
||||||
}
|
}
|
||||||
impl Shout {
|
impl Shout {
|
||||||
pub const fn webhook(&self) -> Option<&OutboundWebhook> {
|
pub const fn webhook(&self) -> Option<&OutboundWebhook> {
|
||||||
|
@ -226,6 +227,10 @@ impl Shout {
|
||||||
pub const fn email(&self) -> Option<&EmailConfig> {
|
pub const fn email(&self) -> Option<&EmailConfig> {
|
||||||
self.email.as_ref()
|
self.email.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const fn desktop(&self) -> bool {
|
||||||
|
self.desktop
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
|
|
|
@ -527,6 +527,7 @@ url = "{listen_url}"
|
||||||
|
|
||||||
[shout]
|
[shout]
|
||||||
webhook = {{ url = "{shout_webhook_url}", secret = "{shout_webhook_secret}" }}
|
webhook = {{ url = "{shout_webhook_url}", secret = "{shout_webhook_secret}" }}
|
||||||
|
desktop = true
|
||||||
|
|
||||||
[shout.email]
|
[shout.email]
|
||||||
from = "{shout_email_from}"
|
from = "{shout_email_from}"
|
||||||
|
@ -773,7 +774,7 @@ mod given {
|
||||||
ServerStorage::new(a_name().into())
|
ServerStorage::new(a_name().into())
|
||||||
}
|
}
|
||||||
pub fn a_shout() -> Shout {
|
pub fn a_shout() -> Shout {
|
||||||
Shout::new(Some(an_outbound_webhook()), Some(an_email_config()))
|
Shout::new(Some(an_outbound_webhook()), Some(an_email_config()), true)
|
||||||
}
|
}
|
||||||
pub fn some_forge_configs() -> BTreeMap<String, ForgeConfig> {
|
pub fn some_forge_configs() -> BTreeMap<String, ForgeConfig> {
|
||||||
[(a_name(), a_forge_config())].into()
|
[(a_name(), a_forge_config())].into()
|
||||||
|
|
Loading…
Reference in a new issue