mirror of
https://git.sr.ht/~ashkeel/sourcehut-mirror-bridge
synced 2024-11-21 21:22:20 +00:00
MVP!
This commit is contained in:
parent
031feef434
commit
7058bf90b2
6 changed files with 366 additions and 173 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
/target
|
||||
.env
|
296
Cargo.lock
generated
296
Cargo.lock
generated
|
@ -68,6 +68,15 @@ dependencies = [
|
|||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aliasable"
|
||||
version = "0.1.3"
|
||||
|
@ -177,7 +186,7 @@ dependencies = [
|
|||
"log",
|
||||
"parking",
|
||||
"polling",
|
||||
"rustix",
|
||||
"rustix 0.37.27",
|
||||
"slab",
|
||||
"socket2",
|
||||
"waker-fn",
|
||||
|
@ -271,6 +280,12 @@ version = "1.3.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.9.0"
|
||||
|
@ -360,18 +375,6 @@ dependencies = [
|
|||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.15.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8"
|
||||
dependencies = [
|
||||
"encode_unicode",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const_fn"
|
||||
version = "0.4.9"
|
||||
|
@ -456,6 +459,16 @@ dependencies = [
|
|||
"cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctrlc"
|
||||
version = "3.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82e95fbd621905b854affdc67943b043a0fbb6ed7385fd5a25650d19a8a6cfdf"
|
||||
dependencies = [
|
||||
"nix",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cynic"
|
||||
version = "3.2.2"
|
||||
|
@ -550,6 +563,12 @@ version = "1.0.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
|
||||
|
||||
[[package]]
|
||||
name = "dotenvy"
|
||||
version = "0.15.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.9.0"
|
||||
|
@ -557,10 +576,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||
|
||||
[[package]]
|
||||
name = "encode_unicode"
|
||||
version = "0.3.6"
|
||||
name = "env_logger"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||
checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece"
|
||||
dependencies = [
|
||||
"humantime",
|
||||
"is-terminal",
|
||||
"log",
|
||||
"regex",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "envy"
|
||||
|
@ -578,7 +604,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "7c18ee0ed65a5f1f81cac6b1d213b69c35fa47d4252ad41f1486dbd8226fe36e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -826,6 +852,12 @@ version = "1.0.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
|
@ -848,19 +880,6 @@ version = "0.2.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac"
|
||||
|
||||
[[package]]
|
||||
name = "insta"
|
||||
version = "1.34.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d64600be34b2fcfc267740a243fa7744441bb4947a619ac4e5bb6507f35fbfc"
|
||||
dependencies = [
|
||||
"console",
|
||||
"lazy_static",
|
||||
"linked-hash-map",
|
||||
"similar",
|
||||
"yaml-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
|
@ -878,7 +897,18 @@ checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
|
|||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"rustix 0.38.21",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -905,30 +935,24 @@ dependencies = [
|
|||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.150"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.20"
|
||||
|
@ -969,6 +993,17 @@ dependencies = [
|
|||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.27.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.17"
|
||||
|
@ -1055,13 +1090,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"cfg-if",
|
||||
"concurrent-queue",
|
||||
"libc",
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1220,6 +1255,35 @@ dependencies = [
|
|||
"syn 2.0.39",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.5"
|
||||
|
@ -1231,7 +1295,7 @@ dependencies = [
|
|||
"libc",
|
||||
"spin",
|
||||
"untrusted",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1249,12 +1313,25 @@ version = "0.37.27"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"errno",
|
||||
"io-lifetimes",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.48.0",
|
||||
"linux-raw-sys 0.3.8",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.11",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1398,12 +1475,6 @@ dependencies = [
|
|||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "similar"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2aeaf503862c419d66959f5d7ca015337d864e9c49485d771b732e2a20453597"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.9"
|
||||
|
@ -1429,10 +1500,14 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"argh",
|
||||
"base64 0.21.5",
|
||||
"ctrlc",
|
||||
"cynic",
|
||||
"cynic-codegen",
|
||||
"dotenvy",
|
||||
"env_logger",
|
||||
"envy",
|
||||
"insta",
|
||||
"log",
|
||||
"semver 1.0.20",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
@ -1564,6 +1639,15 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.50"
|
||||
|
@ -1890,43 +1974,28 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.45.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
||||
dependencies = [
|
||||
"windows-targets 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.42.2",
|
||||
"windows_aarch64_msvc 0.42.2",
|
||||
"windows_i686_gnu 0.42.2",
|
||||
"windows_i686_msvc 0.42.2",
|
||||
"windows_x86_64_gnu 0.42.2",
|
||||
"windows_x86_64_gnullvm 0.42.2",
|
||||
"windows_x86_64_msvc 0.42.2",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1935,104 +2004,53 @@ version = "0.48.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.48.5",
|
||||
"windows_aarch64_msvc 0.48.5",
|
||||
"windows_i686_gnu 0.48.5",
|
||||
"windows_i686_msvc 0.48.5",
|
||||
"windows_x86_64_gnu 0.48.5",
|
||||
"windows_x86_64_gnullvm 0.48.5",
|
||||
"windows_x86_64_msvc 0.48.5",
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
||||
dependencies = [
|
||||
"linked-hash-map",
|
||||
]
|
||||
|
|
|
@ -7,14 +7,18 @@ license = "AGPL-3.0-only"
|
|||
[dependencies]
|
||||
anyhow = "1"
|
||||
argh = "0.1"
|
||||
base64 = "0.21.5"
|
||||
ctrlc = { version = "3", features = ["termination"] }
|
||||
cynic = { version = "3", features = ["http-surf"] }
|
||||
dotenvy = "0.15"
|
||||
envy = "0.4"
|
||||
semver = "1"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
tiny_http = "0.12"
|
||||
log = "0.4"
|
||||
env_logger = "0.10"
|
||||
ureq = { version = "2", features = ["json"] }
|
||||
|
||||
[build-dependencies]
|
||||
cynic-codegen = { version = "3" }
|
||||
insta = "1"
|
||||
|
|
49
src/gitea.rs
Normal file
49
src/gitea.rs
Normal file
|
@ -0,0 +1,49 @@
|
|||
use anyhow::Result;
|
||||
use base64::{engine::general_purpose, Engine as _};
|
||||
use log::debug;
|
||||
|
||||
pub struct GiteaAPI {
|
||||
api_endpoint: String,
|
||||
auth: String,
|
||||
}
|
||||
|
||||
impl GiteaAPI {
|
||||
pub fn new(api_endpoint: &str, auth: &str) -> Self {
|
||||
Self {
|
||||
api_endpoint: api_endpoint.to_string(),
|
||||
auth: basic_auth(auth),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_repositories(&self, project_ids: &[&str]) -> Result<()> {
|
||||
for repo in project_ids {
|
||||
let api_url = format!("{}/v1/repos/{}", self.api_endpoint, repo);
|
||||
let res = ureq::get(&api_url)
|
||||
.set("Authorization", &self.auth)
|
||||
.call()?;
|
||||
if res.status() != 200 {
|
||||
let body = res.into_string()?;
|
||||
return Err(anyhow::anyhow!(
|
||||
"Error fetching repository {}: {}",
|
||||
repo,
|
||||
body
|
||||
));
|
||||
}
|
||||
debug!("Repository {} exists", repo);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn sync(&self, project_id: &str) -> Result<()> {
|
||||
let api_url = format!("{}/v1/repos/{}/mirror-sync", &self.api_endpoint, project_id);
|
||||
ureq::post(&api_url)
|
||||
.set("Authorization", &self.auth)
|
||||
.call()?;
|
||||
debug!("Synced repository {}", project_id);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn basic_auth(auth: &str) -> String {
|
||||
format!("Basic {}", general_purpose::STANDARD.encode(auth))
|
||||
}
|
109
src/main.rs
109
src/main.rs
|
@ -1,8 +1,14 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use gitea::GiteaAPI;
|
||||
use log::{debug, error, info};
|
||||
use serde::Deserialize;
|
||||
use tiny_http::{Header, Server};
|
||||
use std::{collections::HashMap, process::exit, sync::Arc};
|
||||
use tiny_http::{Request, Response, Server};
|
||||
|
||||
mod webhook;
|
||||
use crate::sourcehut::SourcehutAPI;
|
||||
|
||||
mod gitea;
|
||||
mod sourcehut;
|
||||
|
||||
fn default_bind() -> String {
|
||||
"0.0.0.0:8000".to_string()
|
||||
|
@ -14,33 +20,120 @@ fn default_sourcehut_api() -> String {
|
|||
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct Config {
|
||||
/// Bind address
|
||||
#[serde(default = "default_bind")]
|
||||
bind: String,
|
||||
|
||||
/// Sourcehut API endpoint
|
||||
#[serde(default = "default_sourcehut_api")]
|
||||
sourcehut_api: String,
|
||||
|
||||
/// Sourcehut API token (from https://meta.sr.ht/oauth2, needs `git.sr.ht/REPOSITORY` grant)
|
||||
#[serde(default = "default_sourcehut_api")]
|
||||
sourcehut_token: String,
|
||||
|
||||
/// Base URL for Gitea API (without the /v1)
|
||||
gitea_api_base: String,
|
||||
/// username:password for basic auth
|
||||
gitea_auth: String,
|
||||
|
||||
/// URL to set as sourcehut webhook target where this service is reacheable
|
||||
url: String,
|
||||
|
||||
/// Comma separated list of repository map from sourcehut to Gitea e.g. "sourcehutrepo:owner/gitearepo"
|
||||
repositories: String,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let _ = dotenvy::dotenv();
|
||||
|
||||
env_logger::init();
|
||||
|
||||
let config = envy::prefixed("MIRROR_").from_env::<Config>()?;
|
||||
|
||||
// Parse repository mapping into a hashmap
|
||||
let repository_map: HashMap<&str, &str> = config
|
||||
.repositories
|
||||
.split(",")
|
||||
.map(|s| s.split_once(":").unwrap())
|
||||
.collect();
|
||||
|
||||
if repository_map.is_empty() {
|
||||
return Err(anyhow!("No repositories provided"));
|
||||
}
|
||||
|
||||
debug!("Repository map: {:?}", repository_map);
|
||||
|
||||
// Set up Gitea API and check that provided repositories exist
|
||||
let gitea = GiteaAPI::new(&config.gitea_api_base, &config.gitea_auth);
|
||||
let repositories = repository_map.values().map(|&s| s).collect::<Vec<_>>();
|
||||
gitea.check_repositories(&repositories)?;
|
||||
|
||||
// Set up webhooks via GQL API to sourcehut
|
||||
let mut srht_api = webhook::SourceHutAPI::new(&config.sourcehut_api, &config.sourcehut_token);
|
||||
srht_api.init_webhook(&config.url)?;
|
||||
let mut srht = SourcehutAPI::new(&config.sourcehut_api, &config.sourcehut_token);
|
||||
srht.init_webhook(&config.url)?;
|
||||
|
||||
let api = Arc::new(srht);
|
||||
let r = api.clone();
|
||||
|
||||
// Set up termination handler to delete webhook
|
||||
ctrlc::set_handler(move || {
|
||||
_ = r.delete_webhook();
|
||||
exit(0)
|
||||
})
|
||||
.expect("Error setting termination handler");
|
||||
|
||||
// Listen for webhooks and handle them
|
||||
let server = Server::http(config.bind).map_err(|err| anyhow!(err))?;
|
||||
|
||||
let json = Header::from_bytes(&b"Content-Type"[..], &b"application/json"[..]).unwrap();
|
||||
|
||||
for request in server.incoming_requests() {}
|
||||
for request in server.incoming_requests() {
|
||||
debug!("Received request from {:?}", request.remote_addr());
|
||||
match handle_request(request) {
|
||||
Ok(Some(repository)) => {
|
||||
// Get mapped repository, if it exists
|
||||
if let Some(mapped) = repository_map.get(repository.as_str()) {
|
||||
info!("Syncing repository {}", mapped);
|
||||
if let Err(err) = gitea.sync(&mapped) {
|
||||
error!("Error syncing repository: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Error handling webhook: {}", err);
|
||||
}
|
||||
_ => {
|
||||
// Invalid request, ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_request(mut request: Request) -> Result<Option<String>> {
|
||||
// Make sure the content type is JSON
|
||||
let is_json = request
|
||||
.headers()
|
||||
.iter()
|
||||
.find(|h| h.field.as_str() == "Content-Type" && h.value == "application/json")
|
||||
.ok_or_else(|| anyhow!("Invalid Content-Type header"));
|
||||
|
||||
match is_json {
|
||||
Ok(_) => {
|
||||
let mut content = String::new();
|
||||
request.as_reader().read_to_string(&mut content)?;
|
||||
let repository = SourcehutAPI::read_webhook_payload(&content)?;
|
||||
request.respond(Response::empty(204))?;
|
||||
|
||||
return Ok(Some(repository.name));
|
||||
}
|
||||
Err(err) => {
|
||||
debug!(
|
||||
"Rejecting request because of invalid Content-Type header: {}",
|
||||
err
|
||||
);
|
||||
request.respond(Response::from_string(err.to_string()).with_status_code(400))?
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use anyhow::Result;
|
||||
use cynic::{GraphQlResponse, MutationBuilder};
|
||||
use log::error;
|
||||
|
||||
#[cynic::schema("sourcehut")]
|
||||
mod schema {}
|
||||
|
@ -14,13 +15,9 @@ struct CreateWebhookVariables {
|
|||
struct CreateWebhook {
|
||||
#[arguments(config: { events: ["REPO_UPDATE"], query: r#"query {
|
||||
webhook {
|
||||
uuid
|
||||
event
|
||||
date
|
||||
... on RepositoryEvent {
|
||||
repository {
|
||||
name
|
||||
updated
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,18 +39,44 @@ struct DeleteWebhookVariables {
|
|||
#[cynic(graphql_type = "Mutation", variables = "DeleteWebhookVariables")]
|
||||
struct DeleteWebhook {
|
||||
#[arguments(id: $id)]
|
||||
#[allow(dead_code)]
|
||||
delete_user_webhook: WebhookSubscription,
|
||||
}
|
||||
|
||||
pub struct SourceHutAPI {
|
||||
#[derive(cynic::QueryFragment, Debug)]
|
||||
struct RepositoryEvent {
|
||||
repository: Repository,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment, Debug)]
|
||||
pub struct Repository {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug)]
|
||||
struct WebhookEventReceived {
|
||||
webhook: RepositoryEvent,
|
||||
}
|
||||
|
||||
#[derive(cynic::Enum, Clone, Copy, Debug)]
|
||||
enum WebhookEvent {
|
||||
RepoCreated,
|
||||
RepoUpdate,
|
||||
RepoDeleted,
|
||||
}
|
||||
|
||||
#[derive(cynic::Scalar, Debug, Clone)]
|
||||
pub struct Time(pub String);
|
||||
|
||||
pub struct SourcehutAPI {
|
||||
api_endpoint: String,
|
||||
token: String,
|
||||
webhook_id: Option<i32>,
|
||||
}
|
||||
|
||||
fn parse_gql_response(response: GraphQlResponse<WebhookSubscription>) -> Result<i32> {
|
||||
fn parse_gql_response<T>(response: GraphQlResponse<T>) -> Result<T> {
|
||||
match response.data {
|
||||
Some(data) => Ok(data.id),
|
||||
Some(data) => Ok(data),
|
||||
None => {
|
||||
// Check for errors
|
||||
match response.errors {
|
||||
|
@ -68,7 +91,7 @@ fn parse_gql_response(response: GraphQlResponse<WebhookSubscription>) -> Result<
|
|||
}
|
||||
}
|
||||
|
||||
impl SourceHutAPI {
|
||||
impl SourcehutAPI {
|
||||
pub fn new(api_endpoint: &str, token: &str) -> Self {
|
||||
Self {
|
||||
api_endpoint: api_endpoint.to_string(),
|
||||
|
@ -83,32 +106,37 @@ impl SourceHutAPI {
|
|||
});
|
||||
let response = ureq::post(&self.api_endpoint)
|
||||
.set("Authorization", &format!("Bearer {}", &self.token))
|
||||
.send_json(&operation)?
|
||||
.into_json::<GraphQlResponse<WebhookSubscription>>()?;
|
||||
|
||||
let webhook_id = parse_gql_response(response)?;
|
||||
self.webhook_id = Some(webhook_id);
|
||||
.send_json(operation)?
|
||||
.into_json::<GraphQlResponse<CreateWebhook>>()?;
|
||||
|
||||
let webhook_ev = parse_gql_response(response)?;
|
||||
self.webhook_id = Some(webhook_ev.create_user_webhook.id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn delete_webhook(&self, id: i32) -> Result<i32> {
|
||||
pub fn delete_webhook(&self) -> Result<()> {
|
||||
if let Some(id) = self.webhook_id {
|
||||
let operation = DeleteWebhook::build(DeleteWebhookVariables { id });
|
||||
let response = ureq::post(&self.api_endpoint)
|
||||
.set("Authorization", &format!("Bearer {}", &self.token))
|
||||
.send_json(&operation)?
|
||||
.into_json::<GraphQlResponse<WebhookSubscription>>()?;
|
||||
.send_json(operation)?
|
||||
.into_json::<GraphQlResponse<DeleteWebhook>>()?;
|
||||
|
||||
parse_gql_response(response)
|
||||
parse_gql_response(response)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_webhook_payload(data: &str) -> Result<Repository> {
|
||||
let data = serde_json::from_str::<GraphQlResponse<WebhookEventReceived>>(data)?;
|
||||
parse_gql_response(data).map(|ev| ev.webhook.repository)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for SourceHutAPI {
|
||||
impl Drop for SourcehutAPI {
|
||||
fn drop(&mut self) {
|
||||
if let Some(id) = self.webhook_id {
|
||||
if let Err(e) = self.delete_webhook(id) {
|
||||
println!("Failed to delete webhook: {}", e);
|
||||
}
|
||||
if let Err(e) = self.delete_webhook() {
|
||||
error!("Failed to delete webhook: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue