Compare commits
5 Commits
f7af1ac020
...
f74409c9eb
Author | SHA1 | Date | |
---|---|---|---|
f74409c9eb | |||
bcc332bd7b | |||
3eab1ae216 | |||
517889f875 | |||
7530ce3aae |
2
.editorconfig
Normal file
2
.editorconfig
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[*.rs]
|
||||||
|
indent_size = 4
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
/target
|
/target
|
||||||
|
config.yaml
|
||||||
config.json
|
config.json
|
410
Cargo.lock
generated
410
Cargo.lock
generated
@ -2,6 +2,15 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[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 = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@ -14,18 +23,114 @@ version = "1.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bumpalo"
|
||||||
|
version = "3.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
|
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.79"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.0"
|
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.23"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f"
|
||||||
|
dependencies = [
|
||||||
|
"iana-time-zone",
|
||||||
|
"js-sys",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
"time",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "codespan-reporting"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
|
||||||
|
dependencies = [
|
||||||
|
"termcolor",
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation-sys"
|
||||||
|
version = "0.8.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cxx"
|
||||||
|
version = "1.0.89"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bc831ee6a32dd495436e317595e639a587aa9907bef96fe6e6abc290ab6204e9"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"cxxbridge-flags",
|
||||||
|
"cxxbridge-macro",
|
||||||
|
"link-cplusplus",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cxx-build"
|
||||||
|
version = "1.0.89"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "94331d54f1b1a8895cd81049f7eaaaef9d05a7dcb4d1fd08bf3ff0806246789d"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"codespan-reporting",
|
||||||
|
"once_cell",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"scratch",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cxxbridge-flags"
|
||||||
|
version = "1.0.89"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48dcd35ba14ca9b40d6e4b4b39961f23d835dbb8eed74565ded361d93e1feb8a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cxxbridge-macro"
|
||||||
|
version = "1.0.89"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "81bbeb29798b407ccd82a3324ade1a7286e0d29851475990b612670f6f5124d2"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fern"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3bdd7b0849075e79ee9a1836df22c717d1eba30451796fdc631b04565dd11e2a"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures"
|
name = "futures"
|
||||||
version = "0.3.21"
|
version = "0.3.21"
|
||||||
@ -123,14 +228,14 @@ checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.11.2"
|
version = "0.12.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
@ -142,10 +247,34 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "iana-time-zone"
|
||||||
version = "1.8.0"
|
version = "0.1.53"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
|
checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765"
|
||||||
|
dependencies = [
|
||||||
|
"android_system_properties",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"iana-time-zone-haiku",
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone-haiku"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca"
|
||||||
|
dependencies = [
|
||||||
|
"cxx",
|
||||||
|
"cxx-build",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "1.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
@ -158,16 +287,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "js-sys"
|
||||||
version = "0.2.121"
|
version = "0.3.61"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f"
|
checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730"
|
||||||
|
dependencies = [
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linked-hash-map"
|
name = "libc"
|
||||||
version = "0.5.4"
|
version = "0.2.139"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
|
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "link-cplusplus"
|
||||||
|
version = "1.0.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
@ -180,9 +321,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.14"
|
version = "0.4.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
@ -195,34 +336,33 @@ checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "0.8.2"
|
version = "0.8.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9"
|
checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"miow",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
"ntapi",
|
"windows-sys 0.36.1",
|
||||||
"wasi",
|
|
||||||
"winapi",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miow"
|
name = "num-integer"
|
||||||
version = "0.3.7"
|
version = "0.1.45"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
|
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi",
|
"autocfg",
|
||||||
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ntapi"
|
name = "num-traits"
|
||||||
version = "0.3.7"
|
version = "0.2.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f"
|
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -237,9 +377,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.10.0"
|
version = "1.17.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
|
checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
@ -261,7 +401,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"windows-sys",
|
"windows-sys 0.32.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -284,11 +424,11 @@ checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.36"
|
version = "1.0.43"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
|
checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-xid",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -341,9 +481,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustocat"
|
name = "rustocat"
|
||||||
version = "0.0.3"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"fern",
|
||||||
"futures",
|
"futures",
|
||||||
|
"log",
|
||||||
"rand",
|
"rand",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@ -365,19 +508,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "scratch"
|
||||||
version = "1.0.136"
|
version = "1.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
|
checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.144"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.136"
|
version = "1.0.144"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
|
checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -397,14 +546,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_yaml"
|
name = "serde_yaml"
|
||||||
version = "0.8.23"
|
version = "0.9.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a4a521f2940385c165a24ee286aa8599633d162077a54bdcae2a6fd5a7bfa7a0"
|
checksum = "8613d593412a0deb7bbd8de9d908efff5a0cb9ccd8f62c641e7b2ed2f57291d1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
"serde",
|
"serde",
|
||||||
"yaml-rust",
|
"unsafe-libyaml",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -446,21 +596,42 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.89"
|
version = "1.0.100"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54"
|
checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"unicode-xid",
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termcolor"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time"
|
||||||
|
version = "0.1.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||||
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.17.0"
|
version = "1.21.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee"
|
checksum = "0020c875007ad96677dcc890298f4b942882c5d4eb7cc8f439fc3bf813dc9c95"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
"bytes",
|
"bytes",
|
||||||
"libc",
|
"libc",
|
||||||
"memchr",
|
"memchr",
|
||||||
@ -487,10 +658,28 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-ident"
|
||||||
version = "0.2.2"
|
version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unsafe-libyaml"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c1e5fa573d8ac5f1a856f8d7be41d390ee973daf97c806b2c1a465e4e1406e68"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.10.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
@ -498,6 +687,60 @@ version = "0.11.0+wasi-snapshot-preview1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen"
|
||||||
|
version = "0.2.84"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"wasm-bindgen-macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-backend"
|
||||||
|
version = "0.2.84"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9"
|
||||||
|
dependencies = [
|
||||||
|
"bumpalo",
|
||||||
|
"log",
|
||||||
|
"once_cell",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"wasm-bindgen-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-macro"
|
||||||
|
version = "0.2.84"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"wasm-bindgen-macro-support",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-macro-support"
|
||||||
|
version = "0.2.84"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"wasm-bindgen-backend",
|
||||||
|
"wasm-bindgen-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-shared"
|
||||||
|
version = "0.2.84"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
@ -514,6 +757,15 @@ version = "0.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-util"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@ -526,11 +778,24 @@ version = "0.32.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6"
|
checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows_aarch64_msvc",
|
"windows_aarch64_msvc 0.32.0",
|
||||||
"windows_i686_gnu",
|
"windows_i686_gnu 0.32.0",
|
||||||
"windows_i686_msvc",
|
"windows_i686_msvc 0.32.0",
|
||||||
"windows_x86_64_gnu",
|
"windows_x86_64_gnu 0.32.0",
|
||||||
"windows_x86_64_msvc",
|
"windows_x86_64_msvc 0.32.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.36.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_msvc 0.36.1",
|
||||||
|
"windows_i686_gnu 0.36.1",
|
||||||
|
"windows_i686_msvc 0.36.1",
|
||||||
|
"windows_x86_64_gnu 0.36.1",
|
||||||
|
"windows_x86_64_msvc 0.36.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -539,24 +804,48 @@ version = "0.32.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5"
|
checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.36.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.32.0"
|
version = "0.32.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615"
|
checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.36.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.32.0"
|
version = "0.32.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172"
|
checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.36.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.32.0"
|
version = "0.32.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc"
|
checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.36.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.32.0"
|
version = "0.32.0"
|
||||||
@ -564,10 +853,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316"
|
checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yaml-rust"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.4.5"
|
version = "0.36.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
|
||||||
dependencies = [
|
|
||||||
"linked-hash-map",
|
|
||||||
]
|
|
||||||
|
17
Cargo.toml
17
Cargo.toml
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rustocat"
|
name = "rustocat"
|
||||||
version = "0.0.3"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "Socat in rust with many less features and a configuration file"
|
description = "Socat in rust with many less features and a configuration file"
|
||||||
license = "ISC"
|
license = "ISC"
|
||||||
@ -8,17 +8,20 @@ license = "ISC"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tokio = { version = "1.17.0", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
futures = "0.3.21"
|
futures = "0.3.21"
|
||||||
serde = { version = "1.0.136", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1.0.79"
|
serde_json = "1"
|
||||||
serde_yaml = "0.8.23"
|
serde_yaml = "0.9.13"
|
||||||
simple-error = "0.2.3"
|
simple-error = "0.2.3"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
log = "0.4.17"
|
||||||
|
fern = "0.6.1"
|
||||||
|
chrono = "0.4.23"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = 3 # Optimize for size.
|
opt-level = 3 # Optimize for size.
|
||||||
lto = true # Enable Link Time Optimization
|
lto = true # Enable Link Time Optimization
|
||||||
codegen-units = 1 # Reduce number of codegen units to increase optimizations.
|
codegen-units = 1 # Reduce number of codegen units to increase optimizations.
|
||||||
panic = 'abort' # Abort on panic
|
panic = 'abort' # Abort on panic
|
||||||
strip = true # Strip symbols from binary*
|
strip = true # Strip symbols from binary*
|
||||||
|
@ -7,12 +7,13 @@ Rustocat is a simple socat alternative with way less features, but it has a conf
|
|||||||
Configs can be either yaml or json and can be located in /etc/rustocat.{yaml|json} or in the current working directory as config.{yaml|json}.
|
Configs can be either yaml or json and can be located in /etc/rustocat.{yaml|json} or in the current working directory as config.{yaml|json}.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
tcp:
|
mappings:
|
||||||
- source: 0.0.0.0:2222
|
- udp: false
|
||||||
|
source: 0.0.0.0:2222
|
||||||
targets: [127.0.0.1:22]
|
targets: [127.0.0.1:22]
|
||||||
```
|
```
|
||||||
|
|
||||||
Currently only TCP is supported, UDP/Unix Socket support might be added later.
|
There is support for UDP and TCP sockets. Each socket can have multiple targets.
|
||||||
|
|
||||||
When multiple targets are set, it will randomly pick one of them.
|
When multiple targets are set, it will randomly pick one of them.
|
||||||
|
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
tcp:
|
|
||||||
- source: 127.0.0.1:4422
|
|
||||||
targets: [127.0.0.1:22, fury.infra.stamm.me:22]
|
|
||||||
- source: 127.0.0.1:4423
|
|
||||||
targets: [127.0.0.1:22, fury.infra.stamm.me:22]
|
|
@ -1,9 +1,9 @@
|
|||||||
use crate::shutdown::Shutdown;
|
use crate::shutdown::ShutdownReceiver;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
pub(crate) struct Listener {
|
pub(crate) struct Listener {
|
||||||
pub(crate) shutdown: Shutdown,
|
pub(crate) shutdown: ShutdownReceiver,
|
||||||
pub(crate) source: String,
|
pub(crate) source: String,
|
||||||
pub(crate) targets: Arc<RwLock<Vec<String>>>,
|
pub(crate) targets: Arc<RwLock<Vec<String>>>,
|
||||||
}
|
}
|
||||||
|
102
src/main.rs
102
src/main.rs
@ -1,7 +1,9 @@
|
|||||||
mod listener;
|
mod listener;
|
||||||
mod shutdown;
|
mod shutdown;
|
||||||
mod tcp;
|
mod tcp;
|
||||||
|
mod udp;
|
||||||
|
|
||||||
|
use log::{debug, error, info, warn};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use simple_error::bail;
|
use simple_error::bail;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
@ -12,33 +14,35 @@ use std::sync::Arc;
|
|||||||
use tokio::signal::unix::{signal, SignalKind};
|
use tokio::signal::unix::{signal, SignalKind};
|
||||||
use tokio::sync::{broadcast, RwLock};
|
use tokio::sync::{broadcast, RwLock};
|
||||||
|
|
||||||
|
pub type Result<T> = std::result::Result<T, Box<dyn Error>>;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct Target {
|
struct Target {
|
||||||
|
udp: Option<bool>,
|
||||||
source: String,
|
source: String,
|
||||||
targets: Vec<String>,
|
targets: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct Config {
|
struct Config {
|
||||||
tcp: Vec<Target>,
|
mappings: Vec<Target>,
|
||||||
// udp: Vec<Target>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_yaml(path: &Path) -> Result<Config, Box<dyn Error>> {
|
fn load_yaml(path: &Path) -> Result<Config> {
|
||||||
let file = File::open(path)?;
|
let file = File::open(path)?;
|
||||||
let config: Config = serde_yaml::from_reader(file).expect("Failed to parse!"); //TODO: Print path
|
let config: Config = serde_yaml::from_reader(file).expect("Failed to parse!"); //TODO: Print path
|
||||||
|
|
||||||
return Ok(config);
|
return Ok(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_json(path: &Path) -> Result<Config, Box<dyn Error>> {
|
fn load_json(path: &Path) -> Result<Config> {
|
||||||
let file = File::open(path)?;
|
let file = File::open(path)?;
|
||||||
let config: Config = serde_json::from_reader(file).expect("Failed to parse!"); //TODO: Print path
|
let config: Config = serde_json::from_reader(file).expect("Failed to parse!"); //TODO: Print path
|
||||||
|
|
||||||
return Ok(config);
|
return Ok(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_config() -> Result<Config, Box<dyn Error>> {
|
fn load_config() -> Result<Config> {
|
||||||
for path in [
|
for path in [
|
||||||
"config.yaml",
|
"config.yaml",
|
||||||
"config.json",
|
"config.json",
|
||||||
@ -67,7 +71,23 @@ struct ActiveListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
async fn main() -> Result<()> {
|
||||||
|
fern::Dispatch::new()
|
||||||
|
.format(|out, message, record| {
|
||||||
|
out.finish(format_args!(
|
||||||
|
"{}[{}][{}] {}",
|
||||||
|
chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
|
||||||
|
record.target(),
|
||||||
|
record.level(),
|
||||||
|
message
|
||||||
|
))
|
||||||
|
})
|
||||||
|
// Add blanket level filter -
|
||||||
|
.level(log::LevelFilter::Info)
|
||||||
|
.level_for("rustocat", log::LevelFilter::Trace)
|
||||||
|
.chain(std::io::stdout())
|
||||||
|
.apply()?;
|
||||||
|
|
||||||
let mut listeners: HashMap<String, ActiveListener> = HashMap::new();
|
let mut listeners: HashMap<String, ActiveListener> = HashMap::new();
|
||||||
let mut sighup_stream = signal(SignalKind::hangup())?;
|
let mut sighup_stream = signal(SignalKind::hangup())?;
|
||||||
|
|
||||||
@ -75,31 +95,38 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let config = load_config().expect("config not found");
|
let config = load_config().expect("config not found");
|
||||||
let mut required_listeners: HashSet<String> = HashSet::new();
|
let mut required_listeners: HashSet<String> = HashSet::new();
|
||||||
|
|
||||||
for target in config.tcp {
|
for target in config.mappings {
|
||||||
required_listeners.insert(target.source.clone());
|
let mut source_str = "".to_owned();
|
||||||
if let Some(listener) = listeners.get(&target.source) {
|
if target.udp == None || target.udp == Some(false) {
|
||||||
|
source_str.push_str("udp:");
|
||||||
|
} else {
|
||||||
|
source_str.push_str("tcp:");
|
||||||
|
}
|
||||||
|
source_str.push_str(&target.source);
|
||||||
|
|
||||||
|
required_listeners.insert(source_str.clone());
|
||||||
|
if let Some(listener) = listeners.get(&source_str) {
|
||||||
let mut invalid = false;
|
let mut invalid = false;
|
||||||
{
|
|
||||||
let targets = listener.targets.read().await;
|
let targets = listener.targets.read().await;
|
||||||
for t in &target.targets {
|
for t in &target.targets {
|
||||||
if !targets.iter().any(|e| *e == *t) {
|
if !targets.iter().any(|e| *e == *t) {
|
||||||
|
invalid = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !invalid {
|
||||||
|
for t in targets.iter() {
|
||||||
|
if !target.targets.iter().any(|e| *e == *t) {
|
||||||
invalid = true;
|
invalid = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !invalid {
|
|
||||||
for t in targets.iter() {
|
|
||||||
if !target.targets.iter().any(|e| *e == *t) {
|
|
||||||
invalid = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if invalid {
|
if invalid {
|
||||||
println!("Found invalid targets! Adjusting!");
|
warn!("Found invalid targets! Adjusting!");
|
||||||
let mut w = listener.targets.write().await;
|
let mut w = listener.targets.write().await;
|
||||||
*w = target.targets;
|
*w = target.targets;
|
||||||
}
|
}
|
||||||
@ -112,18 +139,24 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let l = listener::Listener {
|
let l = listener::Listener {
|
||||||
shutdown: shutdown::Shutdown::new(listener.notify_shutdown.subscribe()),
|
shutdown: shutdown::ShutdownReceiver::new(listener.notify_shutdown.subscribe()),
|
||||||
source: target.source.clone(),
|
source: target.source.clone(),
|
||||||
targets: listener.targets.clone(),
|
targets: listener.targets.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
if let Err(err) = tcp::start_tcp_listener(l).await {
|
if target.udp == None || target.udp == Some(false) {
|
||||||
println!("listener error: {}", err);
|
if let Err(err) = tcp::start_tcp_listener(l).await {
|
||||||
|
error!("tcp listener error: {}", err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let Err(err) = udp::start_udp_listener(l).await {
|
||||||
|
error!("udp listener error: {}", err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
listeners.insert(target.source, listener);
|
listeners.insert(source_str, listener);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,13 +168,22 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
|
|
||||||
for del_key in to_delete {
|
for del_key in to_delete {
|
||||||
if let Some(listener) = listeners.get(&del_key) {
|
if let Some(listener) = listeners.get(&del_key) {
|
||||||
let _ = listener.notify_shutdown.send(()); //Errors are irrelevant here. I guess....
|
let res = listener.notify_shutdown.send(()); //Errors are irrelevant here. I guess....
|
||||||
println!("Removing listener!");
|
match res {
|
||||||
|
Ok(_) => {
|
||||||
|
info!("Sent shutdown signal!");
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
warn!("Failed to send shutdown signal!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Removing listener!");
|
||||||
listeners.remove(&del_key);
|
listeners.remove(&del_key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sighup_stream.recv().await;
|
sighup_stream.recv().await;
|
||||||
println!("Recevied SIGHUP!");
|
info!("Recevied SIGHUP, reloading config!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,49 +1,62 @@
|
|||||||
use tokio::sync::broadcast;
|
use tokio::sync::broadcast;
|
||||||
|
|
||||||
/// Listens for the server shutdown signal.
|
|
||||||
///
|
|
||||||
/// Shutdown is signalled using a `broadcast::Receiver`. Only a single value is
|
|
||||||
/// ever sent. Once a value has been sent via the broadcast channel, the server
|
|
||||||
/// should shutdown.
|
|
||||||
///
|
|
||||||
/// The `Shutdown` struct listens for the signal and tracks that the signal has
|
|
||||||
/// been received. Callers may query for whether the shutdown signal has been
|
|
||||||
/// received or not.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) struct Shutdown {
|
pub(crate) struct Shutdown {
|
||||||
/// `true` if the shutdown signal has been received
|
shutdown: bool,
|
||||||
shutdown: bool,
|
notify: broadcast::Receiver<()>,
|
||||||
|
sender: broadcast::Sender<()>,
|
||||||
/// The receive half of the channel used to listen for shutdown.
|
|
||||||
notify: broadcast::Receiver<()>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Shutdown {
|
impl Shutdown {
|
||||||
/// Create a new `Shutdown` backed by the given `broadcast::Receiver`.
|
pub(crate) fn new() -> Shutdown {
|
||||||
pub(crate) fn new(notify: broadcast::Receiver<()>) -> Shutdown {
|
let (sender, notify) = broadcast::channel(1);
|
||||||
Shutdown {
|
Shutdown {
|
||||||
shutdown: false,
|
shutdown: false,
|
||||||
notify,
|
notify,
|
||||||
}
|
sender,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns `true` if the shutdown signal has been received.
|
pub(crate) fn shutdown(&mut self) {
|
||||||
// pub(crate) fn is_shutdown(&self) -> bool {
|
if self.shutdown {
|
||||||
// self.shutdown
|
return;
|
||||||
// }
|
}
|
||||||
|
let _ = self.sender.send(());
|
||||||
|
self.shutdown = true;
|
||||||
|
}
|
||||||
|
|
||||||
/// Receive the shutdown notice, waiting if necessary.
|
pub(crate) fn receiver(&self) -> ShutdownReceiver {
|
||||||
pub(crate) async fn recv(&mut self) {
|
ShutdownReceiver::new(self.notify.resubscribe())
|
||||||
// If the shutdown signal has already been received, then return
|
}
|
||||||
// immediately.
|
}
|
||||||
if self.shutdown {
|
|
||||||
return;
|
#[derive(Debug)]
|
||||||
}
|
pub(crate) struct ShutdownReceiver {
|
||||||
|
shutdown: bool,
|
||||||
// Cannot receive a "lag error" as only one value is ever sent.
|
notify: broadcast::Receiver<()>,
|
||||||
let _ = self.notify.recv().await;
|
}
|
||||||
|
|
||||||
// Remember that the signal has been received.
|
impl ShutdownReceiver {
|
||||||
self.shutdown = true;
|
pub(crate) fn new(notify: broadcast::Receiver<()>) -> ShutdownReceiver {
|
||||||
}
|
ShutdownReceiver {
|
||||||
|
shutdown: false,
|
||||||
|
notify,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn recv(&mut self) {
|
||||||
|
if self.shutdown {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let _ = self.notify.recv().await;
|
||||||
|
self.shutdown = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for ShutdownReceiver {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
ShutdownReceiver {
|
||||||
|
shutdown: self.shutdown,
|
||||||
|
notify: self.notify.resubscribe(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
75
src/tcp.rs
75
src/tcp.rs
@ -1,58 +1,59 @@
|
|||||||
use crate::listener::Listener;
|
use crate::listener::Listener;
|
||||||
|
use log::{info, trace, warn};
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use tokio::net::{TcpListener, TcpStream};
|
use tokio::net::{TcpListener, TcpStream};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct TcpHandler {
|
struct TcpHandler {
|
||||||
stream: TcpStream,
|
stream: TcpStream,
|
||||||
target: String,
|
target: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TcpHandler {
|
impl TcpHandler {
|
||||||
async fn run(&mut self) -> Result<(), Box<dyn Error>> {
|
async fn run(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
let mut stream = TcpStream::connect(&self.target).await?;
|
let mut stream = TcpStream::connect(&self.target).await?;
|
||||||
|
|
||||||
tokio::io::copy_bidirectional(&mut self.stream, &mut stream).await?;
|
tokio::io::copy_bidirectional(&mut self.stream, &mut stream).await?;
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn start_tcp_listener(
|
pub(crate) async fn start_tcp_listener(
|
||||||
mut listener_config: Listener,
|
mut listener_config: Listener,
|
||||||
) -> Result<(), Box<dyn Error>> {
|
) -> Result<(), Box<dyn Error>> {
|
||||||
println!("start listening on {}", &listener_config.source);
|
info!("start listening on {}", &listener_config.source);
|
||||||
let listener = TcpListener::bind(&listener_config.source).await?;
|
let listener = TcpListener::bind(&listener_config.source).await?;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let (next_socket, _) = tokio::select! {
|
let (next_socket, _) = tokio::select! {
|
||||||
res = listener.accept() => res?,
|
res = listener.accept() => res?,
|
||||||
_ = listener_config.shutdown.recv() => {
|
_ = listener_config.shutdown.recv() => {
|
||||||
println!("Exiting listener!");
|
info!("Exiting listener!");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let targets = listener_config.targets.read().await;
|
let targets = listener_config.targets.read().await;
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
let selected_target = targets.choose(&mut rng).unwrap();
|
let selected_target = targets.choose(&mut rng).unwrap();
|
||||||
|
|
||||||
println!(
|
trace!(
|
||||||
"new connection from {} forwarding to {}",
|
"new connection from {} forwarding to {}",
|
||||||
next_socket.peer_addr()?,
|
next_socket.peer_addr()?,
|
||||||
&selected_target
|
&selected_target
|
||||||
);
|
);
|
||||||
let mut handler = TcpHandler {
|
let mut handler = TcpHandler {
|
||||||
stream: next_socket,
|
stream: next_socket,
|
||||||
target: selected_target.clone(),
|
target: selected_target.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
// Process the connection. If an error is encountered, log it.
|
// Process the connection. If an error is encountered, log it.
|
||||||
if let Err(err) = handler.run().await {
|
if let Err(err) = handler.run().await {
|
||||||
println!("connection error {}", err);
|
warn!("connection error {}", err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
226
src/udp.rs
226
src/udp.rs
@ -1,2 +1,224 @@
|
|||||||
// For UDP to work, there is some magic required with matches the returning packets
|
use std::collections::HashMap;
|
||||||
// back to the original sender. Idk. how to do that right now, but maybe some day.
|
use std::sync::atomic::AtomicI32;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use log::{debug, error, info, trace};
|
||||||
|
use rand::seq::SliceRandom;
|
||||||
|
|
||||||
|
use tokio::net::UdpSocket;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
use crate::listener::Listener;
|
||||||
|
use crate::shutdown::{Shutdown, ShutdownReceiver};
|
||||||
|
use crate::Result;
|
||||||
|
|
||||||
|
const CONNECTION_TIMEOUT: i32 = 5;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct UDPMultiSender {
|
||||||
|
socket: Arc<UdpSocket>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UDPMultiSender {
|
||||||
|
fn new(socket: UdpSocket) -> Self {
|
||||||
|
return Self {
|
||||||
|
socket: Arc::new(socket),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send(&self, buf: &[u8]) -> Result<()> {
|
||||||
|
self.socket.send(buf).await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_to(&self, buf: &[u8], dest: &str) -> Result<()> {
|
||||||
|
self.socket.send_to(buf, dest).await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn splitted_udp_socket(bind_addr: &str) -> Result<(UdpSocket, UDPMultiSender)> {
|
||||||
|
let listener_std = std::net::UdpSocket::bind(bind_addr)?;
|
||||||
|
let responder_std = listener_std.try_clone()?;
|
||||||
|
listener_std.set_nonblocking(true)?;
|
||||||
|
responder_std.set_nonblocking(true)?;
|
||||||
|
let listener = UdpSocket::from_std(listener_std)?;
|
||||||
|
let responder = UDPMultiSender::new(UdpSocket::from_std(responder_std)?);
|
||||||
|
|
||||||
|
return Ok((listener, responder));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct UDPChannel {
|
||||||
|
last_packet: Arc<AtomicI32>,
|
||||||
|
sender: UDPMultiSender,
|
||||||
|
shutdown: Shutdown,
|
||||||
|
from: String,
|
||||||
|
upstream: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UDPChannel {
|
||||||
|
async fn start(
|
||||||
|
upstream: String,
|
||||||
|
responder: UDPMultiSender,
|
||||||
|
source_addr: String,
|
||||||
|
) -> Result<Self> {
|
||||||
|
let (upstream_listener, upstream_responder) = splitted_udp_socket("0.0.0.0:0").await?;
|
||||||
|
upstream_listener.connect(upstream.clone()).await?;
|
||||||
|
|
||||||
|
let shutdown = Shutdown::new();
|
||||||
|
let mut shutdown_receiver = shutdown.receiver();
|
||||||
|
|
||||||
|
let channel = Self {
|
||||||
|
last_packet: Arc::new(AtomicI32::new(CONNECTION_TIMEOUT)),
|
||||||
|
sender: upstream_responder,
|
||||||
|
shutdown,
|
||||||
|
from: source_addr.clone(),
|
||||||
|
upstream: upstream.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let last_packet = channel.last_packet.clone();
|
||||||
|
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let mut buf = [0; 64 * 1024];
|
||||||
|
loop {
|
||||||
|
let num_bytes = tokio::select! {
|
||||||
|
res = upstream_listener.recv(&mut buf) => res.unwrap(),
|
||||||
|
_ = shutdown_receiver.recv() => {
|
||||||
|
info!("Exiting");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
trace!("[{}] <- [{}] ...", source_addr, upstream);
|
||||||
|
last_packet.store(CONNECTION_TIMEOUT, std::sync::atomic::Ordering::Relaxed);
|
||||||
|
|
||||||
|
match responder.send_to(&buf[..num_bytes], &source_addr).await {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to send packet: {}", e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
trace!("[{}] <- [{}] ---", source_addr, upstream);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Ok(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn close(&mut self) {
|
||||||
|
self.shutdown.shutdown();
|
||||||
|
debug!("Closing connection from {}", self.from);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle(&self, data: &[u8]) {
|
||||||
|
trace!("[{}] -> [{}] ...", self.from, self.upstream);
|
||||||
|
self.last_packet
|
||||||
|
.store(CONNECTION_TIMEOUT, std::sync::atomic::Ordering::Relaxed);
|
||||||
|
match self.sender.send(data).await {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to send packet: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trace!("[{}] -> [{}] ---", self.from, self.upstream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_stale_check(
|
||||||
|
connections: Arc<Mutex<HashMap<String, UDPChannel>>>,
|
||||||
|
mut shutdown: ShutdownReceiver,
|
||||||
|
) {
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let mut interval = tokio::time::interval(std::time::Duration::from_secs(1));
|
||||||
|
loop {
|
||||||
|
tokio::select! {
|
||||||
|
_ = interval.tick() => {}
|
||||||
|
_ = shutdown.recv() => {
|
||||||
|
info!("Exiting listener!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trace!("Checking for stale connections");
|
||||||
|
trace!("Waiting for connections lock");
|
||||||
|
let mut connections = connections.lock().await;
|
||||||
|
trace!("Got connections lock");
|
||||||
|
let mut to_remove: Vec<String> = Vec::new();
|
||||||
|
for (source_addr, channel) in connections.iter() {
|
||||||
|
let last = channel
|
||||||
|
.last_packet
|
||||||
|
.fetch_sub(1, std::sync::atomic::Ordering::Relaxed);
|
||||||
|
|
||||||
|
if last <= 0 {
|
||||||
|
to_remove.push(source_addr.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for source_addr in to_remove {
|
||||||
|
debug!("Closing connection from {}", source_addr);
|
||||||
|
let mut channel = connections.remove(&source_addr).unwrap();
|
||||||
|
channel.close().await;
|
||||||
|
}
|
||||||
|
trace!("Checking for stale connections - done");
|
||||||
|
drop(connections);
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("Exiting stale check");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn start_udp_listener(mut listener_config: Listener) -> Result<()> {
|
||||||
|
info!("start listening on {}", &listener_config.source);
|
||||||
|
let (listener, responder) = splitted_udp_socket(&listener_config.source).await?;
|
||||||
|
let connections = Arc::new(Mutex::new(HashMap::<String, UDPChannel>::new()));
|
||||||
|
|
||||||
|
start_stale_check(connections.clone(), listener_config.shutdown.clone());
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let mut buf = vec![0; 1024 * 64];
|
||||||
|
trace!("Waiting for packet or shutdown");
|
||||||
|
let (num_bytes, src_addr) = tokio::select! {
|
||||||
|
res = listener.recv_from(&mut buf) => res?,
|
||||||
|
_ = listener_config.shutdown.recv() => {
|
||||||
|
info!("Exiting listener!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let data = buf[0..num_bytes].to_vec();
|
||||||
|
let source_addr = src_addr.to_string();
|
||||||
|
|
||||||
|
let mut connections = connections.lock().await;
|
||||||
|
|
||||||
|
let handler_opt = connections.get_mut(&source_addr);
|
||||||
|
let handler = match handler_opt {
|
||||||
|
Some(handler) => handler,
|
||||||
|
None => {
|
||||||
|
debug!("New connection from {}", source_addr);
|
||||||
|
let targets = listener_config.targets.read().await;
|
||||||
|
let upstream = {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
targets.choose(&mut rng).unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
let handler =
|
||||||
|
UDPChannel::start(upstream.to_string(), responder.clone(), source_addr.clone())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
connections.insert(source_addr.clone(), handler);
|
||||||
|
connections.get_mut(&source_addr).unwrap()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handler.handle(&data).await;
|
||||||
|
trace!("Handled packet");
|
||||||
|
drop(connections);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (_, handler) in connections.lock().await.iter_mut() {
|
||||||
|
handler.close().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user