feat: add commit, push handler
- add new feature commit changes and push to remote Signed-off-by: Pakin <pakin.t@forth.co.th>
This commit is contained in:
parent
2dd165b451
commit
3043f30012
4 changed files with 667 additions and 231 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,5 +1,5 @@
|
|||
/target
|
||||
.tbcfg
|
||||
.tbcfg*
|
||||
*.txt
|
||||
*.log
|
||||
|
||||
|
|
|
|||
237
Cargo.lock
generated
237
Cargo.lock
generated
|
|
@ -102,6 +102,12 @@ dependencies = [
|
|||
"derive_arbitrary",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arcstr"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03918c3dbd7701a85c6b9887732e2921175f26c350b4563841d0958c21d57e6d"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.89"
|
||||
|
|
@ -177,6 +183,17 @@ dependencies = [
|
|||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum-macros"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
|
|
@ -221,9 +238,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.51"
|
||||
version = "1.2.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203"
|
||||
checksum = "755d2fce177175ffca841e9a06afdb2c4ab0f593d53b4dee48147dfaade85932"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"jobserver",
|
||||
|
|
@ -239,9 +256,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
|||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.42"
|
||||
version = "0.4.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
|
||||
checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118"
|
||||
dependencies = [
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
|
|
@ -266,6 +283,16 @@ version = "1.0.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||
|
||||
[[package]]
|
||||
name = "combine"
|
||||
version = "4.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.3.1"
|
||||
|
|
@ -466,21 +493,20 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
|||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.26"
|
||||
version = "0.2.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed"
|
||||
checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"libredox",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.6"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff"
|
||||
checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db"
|
||||
|
||||
[[package]]
|
||||
name = "fixedbitset"
|
||||
|
|
@ -490,13 +516,13 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
|
|||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.5"
|
||||
version = "1.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb"
|
||||
checksum = "b375d6465b98090a5f25b1c7703f3859783755aa9a80433b36e0379a3ec2f369"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"libz-rs-sys",
|
||||
"miniz_oxide",
|
||||
"zlib-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -505,6 +531,12 @@ version = "1.0.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
|
|
@ -566,6 +598,7 @@ dependencies = [
|
|||
"futures-task",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -580,9 +613,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.16"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
||||
checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
|
|
@ -635,6 +668,15 @@ dependencies = [
|
|||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||
dependencies = [
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.16.1"
|
||||
|
|
@ -928,7 +970,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
"hashbrown 0.16.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1013,9 +1055,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.83"
|
||||
version = "0.3.85"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8"
|
||||
checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
|
|
@ -1029,9 +1071,9 @@ checksum = "2c4a545a15244c7d945065b5d392b2d2d7f21526fba56ce51467b06ed445e8f7"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.179"
|
||||
version = "0.2.180"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5a2d376baa530d1238d133232d15e239abad80d05838b4b59354e5268af431f"
|
||||
checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
|
||||
|
||||
[[package]]
|
||||
name = "libgit2-sys"
|
||||
|
|
@ -1075,7 +1117,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "libtbr"
|
||||
version = "0.1.1"
|
||||
source = "git+https://pakin-inspiron-15-3530.tail110d9.ts.net/pakin/libtbr.git#9ef23af0fd411c1434d5d8fe967a717eca445b96"
|
||||
source = "git+https://pakin-inspiron-15-3530.tail110d9.ts.net/pakin/libtbr.git#2b6b0626642a41a582864052e909e2585886ff89"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"flate2",
|
||||
|
|
@ -1090,15 +1132,6 @@ dependencies = [
|
|||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libz-rs-sys"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c10501e7805cee23da17c7790e59df2870c0d4043ec6d03f67d31e2b53e77415"
|
||||
dependencies = [
|
||||
"zlib-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libz-sys"
|
||||
version = "1.1.23"
|
||||
|
|
@ -1210,12 +1243,31 @@ dependencies = [
|
|||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
|
|
@ -1322,11 +1374,12 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
|||
|
||||
[[package]]
|
||||
name = "petgraph"
|
||||
version = "0.7.1"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772"
|
||||
checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455"
|
||||
dependencies = [
|
||||
"fixedbitset",
|
||||
"hashbrown 0.15.5",
|
||||
"indexmap",
|
||||
]
|
||||
|
||||
|
|
@ -1425,18 +1478,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.105"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost"
|
||||
version = "0.14.1"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d"
|
||||
checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"prost-derive",
|
||||
|
|
@ -1444,15 +1497,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "prost-build"
|
||||
version = "0.14.1"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac6c3320f9abac597dcbc668774ef006702672474aad53c6d596b62e487b40b1"
|
||||
checksum = "343d3bd7056eda839b03204e68deff7d1b13aba7af2b2fd16890697274262ee7"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"itertools",
|
||||
"log",
|
||||
"multimap",
|
||||
"once_cell",
|
||||
"petgraph",
|
||||
"prettyplease",
|
||||
"prost",
|
||||
|
|
@ -1466,9 +1518,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "prost-derive"
|
||||
version = "0.14.1"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425"
|
||||
checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools",
|
||||
|
|
@ -1479,9 +1531,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "prost-types"
|
||||
version = "0.14.1"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9b4db3d6da204ed77bb26ba83b6122a73aeb2e87e25fbf7ad2e84c4ccbf8f72"
|
||||
checksum = "8991c4cbdb8bc5b11f0b074ffe286c30e523de90fee5ba8132f1399f23cb3dd7"
|
||||
dependencies = [
|
||||
"prost",
|
||||
]
|
||||
|
|
@ -1499,9 +1551,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pulldown-cmark-to-cmark"
|
||||
version = "21.1.0"
|
||||
version = "22.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8246feae3db61428fd0bb94285c690b460e4517d83152377543ca802357785f1"
|
||||
checksum = "50793def1b900256624a709439404384204a5dc3a6ec580281bfaac35e882e90"
|
||||
dependencies = [
|
||||
"pulldown-cmark",
|
||||
]
|
||||
|
|
@ -1543,9 +1595,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.3"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||
checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
|
||||
dependencies = [
|
||||
"getrandom 0.3.4",
|
||||
]
|
||||
|
|
@ -1570,6 +1622,24 @@ dependencies = [
|
|||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redis"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5dfe20977fe93830c0e9817a16fbf1ed1cfd8d4bba366087a1841d2c6033c251"
|
||||
dependencies = [
|
||||
"arcstr",
|
||||
"combine",
|
||||
"itoa",
|
||||
"num-bigint",
|
||||
"percent-encoding",
|
||||
"ryu",
|
||||
"sha1_smol",
|
||||
"socket2",
|
||||
"url",
|
||||
"xxhash-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.18"
|
||||
|
|
@ -1665,7 +1735,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
|
|||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"getrandom 0.2.16",
|
||||
"getrandom 0.2.17",
|
||||
"libc",
|
||||
"untrusted",
|
||||
"windows-sys 0.52.0",
|
||||
|
|
@ -1699,18 +1769,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.13.2"
|
||||
version = "1.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282"
|
||||
checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd"
|
||||
dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.103.8"
|
||||
version = "0.103.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52"
|
||||
checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
|
|
@ -1854,6 +1924,12 @@ dependencies = [
|
|||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1_smol"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d"
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.9"
|
||||
|
|
@ -1989,12 +2065,14 @@ name = "tbm-git-repo-service"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"axum-macros",
|
||||
"env_logger",
|
||||
"git2",
|
||||
"libgit2-sys",
|
||||
"libtbr",
|
||||
"log",
|
||||
"prost",
|
||||
"redis",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -2019,22 +2097,22 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.44"
|
||||
version = "0.3.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d"
|
||||
checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"num-conv",
|
||||
"powerfmt",
|
||||
"serde",
|
||||
"serde_core",
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.6"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b"
|
||||
checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca"
|
||||
|
||||
[[package]]
|
||||
name = "tinystr"
|
||||
|
|
@ -2188,9 +2266,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.5.2"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
|
||||
checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
|
|
@ -2360,18 +2438,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
|||
|
||||
[[package]]
|
||||
name = "wasip2"
|
||||
version = "1.0.1+wasi-0.2.4"
|
||||
version = "1.0.2+wasi-0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
|
||||
checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
|
||||
dependencies = [
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.106"
|
||||
version = "0.2.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd"
|
||||
checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
|
|
@ -2382,11 +2460,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.56"
|
||||
version = "0.4.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c"
|
||||
checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"futures-util",
|
||||
"js-sys",
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
|
|
@ -2395,9 +2474,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.106"
|
||||
version = "0.2.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3"
|
||||
checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
|
|
@ -2405,9 +2484,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.106"
|
||||
version = "0.2.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40"
|
||||
checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"proc-macro2",
|
||||
|
|
@ -2418,18 +2497,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.106"
|
||||
version = "0.2.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4"
|
||||
checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.83"
|
||||
version = "0.3.85"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac"
|
||||
checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
|
|
@ -2672,9 +2751,9 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
|||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.46.0"
|
||||
version = "0.51.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
|
||||
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
|
||||
|
||||
[[package]]
|
||||
name = "writeable"
|
||||
|
|
@ -2692,6 +2771,12 @@ dependencies = [
|
|||
"rustix",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xxhash-rust"
|
||||
version = "0.8.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3"
|
||||
|
||||
[[package]]
|
||||
name = "yoke"
|
||||
version = "0.8.1"
|
||||
|
|
@ -2844,9 +2929,9 @@ checksum = "40990edd51aae2c2b6907af74ffb635029d5788228222c4bb811e9351c0caad3"
|
|||
|
||||
[[package]]
|
||||
name = "zmij"
|
||||
version = "1.0.12"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fc5a66a20078bf1251bde995aa2fdcc4b800c70b5d92dd2c62abc5c60f679f8"
|
||||
checksum = "dfcd145825aace48cff44a8844de64bf75feec3080e0aa5cdbde72961ae51a65"
|
||||
|
||||
[[package]]
|
||||
name = "zopfli"
|
||||
|
|
|
|||
|
|
@ -5,12 +5,14 @@ edition = "2024"
|
|||
|
||||
[dependencies]
|
||||
axum = "0.8.7"
|
||||
axum-macros = "0.5.0"
|
||||
env_logger = "0.11.8"
|
||||
git2 = { version = "0.20.3", features = ["https", "ssh"] }
|
||||
libgit2-sys = { version = "0.18.3", features = ["ssh"] }
|
||||
libtbr = { git = "https://pakin-inspiron-15-3530.tail110d9.ts.net/pakin/libtbr.git", version = "0.1.1" }
|
||||
log = "0.4.29"
|
||||
prost = "0.14.1"
|
||||
redis = "1.0.2"
|
||||
reqwest = { version = "0.12.25", features = ["json"] }
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
serde_json = { version = "1.0.145", features = ["preserve_order"] }
|
||||
|
|
|
|||
657
src/app.rs
657
src/app.rs
|
|
@ -1,197 +1,546 @@
|
|||
use std::collections::HashMap;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use axum::{extract::{Query, State}, response::IntoResponse, routing::get, Json, Router};
|
||||
use git2::{Repository, RemoteCallbacks, FetchOptions, Cred};
|
||||
use log::{error, warn};
|
||||
use libtbr::recipe_functions::common;
|
||||
use serde::Deserialize;
|
||||
use serde_json::{json, Value};
|
||||
use axum::{
|
||||
Json, Router,
|
||||
extract::{Query, State},
|
||||
response::IntoResponse,
|
||||
routing::{get, post},
|
||||
};
|
||||
use axum_macros::debug_handler;
|
||||
use git2::{Cred, FetchOptions, PushOptions, RemoteCallbacks, Repository};
|
||||
use libtbr::{models, recipe_functions::common};
|
||||
use log::{error, info, warn};
|
||||
use redis::TypedCommands;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::{Value, json};
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::{gcm, reg};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AppState {
|
||||
cached_country_names: Vec<&'static str>,
|
||||
configures: gcm::Configure
|
||||
// cached_country_names: Vec<&'static str>,
|
||||
configures: gcm::Configure,
|
||||
repo: Arc<Mutex<Repository>>,
|
||||
redis: Arc<Mutex<redis::Client>>,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
pub fn check_country_existed(&self, req: &str) -> bool {
|
||||
self.cached_country_names.contains(&req)
|
||||
}
|
||||
// pub fn check_country_existed(&self, req: &str) -> bool {
|
||||
// self.cached_country_names.contains(&req)
|
||||
// }
|
||||
|
||||
pub fn get_config(&self, config_name: &str) -> Option<&String> {
|
||||
self.configures.get(config_name)
|
||||
}
|
||||
pub fn get_config(&self, config_name: &str) -> Option<&String> {
|
||||
self.configures.get(config_name)
|
||||
}
|
||||
|
||||
pub fn get_all_configures(self) -> gcm::Configure {
|
||||
self.configures.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct CheckoutParams {
|
||||
path: String
|
||||
path: String,
|
||||
}
|
||||
|
||||
async fn checkout_handler(State(state): State<AppState>, Query(param): Query<CheckoutParams>) -> impl IntoResponse {
|
||||
let mut response: HashMap<String, Value> = HashMap::new();
|
||||
async fn checkout_handler(
|
||||
State(state): State<AppState>,
|
||||
Query(param): Query<CheckoutParams>,
|
||||
) -> impl IntoResponse {
|
||||
let mut response: HashMap<String, Value> = HashMap::new();
|
||||
|
||||
let repo_path = state.get_config("GIT_REPO_LOCAL_DEST");
|
||||
if repo_path.is_none() {
|
||||
response.insert("error".to_string(), json!("config repo dest not found".to_string()));
|
||||
return (
|
||||
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!(response))
|
||||
);
|
||||
}
|
||||
|
||||
let legit_path = param.path.as_str();
|
||||
|
||||
// match param.path.as_str() {
|
||||
// legit_path if param.path.contains("/") || state.check_country_existed(param.path.as_str()) || param.path.is_empty() => {
|
||||
|
||||
// }
|
||||
// _ => {
|
||||
// let error_log = "requested path is unexpected";
|
||||
// error!("{error_log}");
|
||||
// response.insert("error".to_string(), json!(error_log));
|
||||
// }
|
||||
// }
|
||||
let rpath = repo_path.unwrap().clone();
|
||||
let repo = match Repository::open_bare(rpath) {
|
||||
Ok(repo) => repo,
|
||||
Err(_) => {
|
||||
let error_log = "unable to open repo as bare";
|
||||
error!("{error_log}");
|
||||
response.insert("error".to_string(), json!(error_log));
|
||||
return (
|
||||
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!(response))
|
||||
);
|
||||
let repo_path = state.get_config("GIT_REPO_LOCAL_DEST");
|
||||
if repo_path.is_none() {
|
||||
response.insert(
|
||||
"error".to_string(),
|
||||
json!("config repo dest not found".to_string()),
|
||||
);
|
||||
return (
|
||||
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!(response)),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let fpath = format!("master:{}", legit_path);
|
||||
let obj = match repo.revparse_single(&fpath){
|
||||
Ok(obj) => obj,
|
||||
Err(e) => {
|
||||
let error_log = format!("unexpected revparse single: {err}", err = e.message());
|
||||
error!("{error_log}");
|
||||
response.insert("error".to_string(), json!(error_log.clone()));
|
||||
return (
|
||||
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!(response))
|
||||
);
|
||||
}
|
||||
};
|
||||
let legit_path = param.path.as_str();
|
||||
|
||||
if let Some(blob) = obj.as_blob() {
|
||||
let content = unsafe {
|
||||
str::from_utf8_unchecked(blob.content())
|
||||
// match param.path.as_str() {
|
||||
// legit_path if param.path.contains("/") || state.check_country_existed(param.path.as_str()) || param.path.is_empty() => {
|
||||
|
||||
// }
|
||||
// _ => {
|
||||
// let error_log = "requested path is unexpected";
|
||||
// error!("{error_log}");
|
||||
// response.insert("error".to_string(), json!(error_log));
|
||||
// }
|
||||
// }
|
||||
let rpath = repo_path.unwrap().clone();
|
||||
let repo = match Repository::open_bare(rpath) {
|
||||
Ok(repo) => repo,
|
||||
Err(_) => {
|
||||
let error_log = "unable to open repo as bare";
|
||||
error!("{error_log}");
|
||||
response.insert("error".to_string(), json!(error_log));
|
||||
return (
|
||||
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!(response)),
|
||||
);
|
||||
}
|
||||
};
|
||||
response.insert("result".to_string(), json!(content.to_string()));
|
||||
} else if let Some(tree) = obj.as_tree() {
|
||||
let dir_list = tree.iter().map(|x| x.name().unwrap_or("").to_string()).collect::<Vec<String>>();
|
||||
response.insert("result".to_string(), json!(dir_list));
|
||||
} else {
|
||||
let error_log = "not obj nor tree";
|
||||
error!("{error_log}");
|
||||
response.insert("error".to_string(), json!(error_log));
|
||||
return (
|
||||
axum::http::StatusCode::BAD_REQUEST,
|
||||
Json(json!(response))
|
||||
)
|
||||
}
|
||||
|
||||
(
|
||||
axum::http::StatusCode::OK,
|
||||
Json(json!(response))
|
||||
)
|
||||
let fpath = format!("master:{}", legit_path);
|
||||
let obj = match repo.revparse_single(&fpath) {
|
||||
Ok(obj) => obj,
|
||||
Err(e) => {
|
||||
let error_log = format!("unexpected revparse single: {err}", err = e.message());
|
||||
error!("{error_log}");
|
||||
response.insert("error".to_string(), json!(error_log.clone()));
|
||||
return (
|
||||
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!(response)),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(blob) = obj.as_blob() {
|
||||
let content = unsafe { str::from_utf8_unchecked(blob.content()) };
|
||||
response.insert("result".to_string(), json!(content.to_string()));
|
||||
} else if let Some(tree) = obj.as_tree() {
|
||||
let dir_list = tree
|
||||
.iter()
|
||||
.map(|x| x.name().unwrap_or("").to_string())
|
||||
.collect::<Vec<String>>();
|
||||
response.insert("result".to_string(), json!(dir_list));
|
||||
} else {
|
||||
let error_log = "not obj nor tree";
|
||||
error!("{error_log}");
|
||||
response.insert("error".to_string(), json!(error_log));
|
||||
return (axum::http::StatusCode::BAD_REQUEST, Json(json!(response)));
|
||||
}
|
||||
|
||||
(axum::http::StatusCode::OK, Json(json!(response)))
|
||||
}
|
||||
|
||||
async fn fetch_handler(State(state): State<AppState>) -> impl IntoResponse {
|
||||
let mut response: HashMap<String, Value> = HashMap::new();
|
||||
if let Some(repo_path) = state.get_config("GIT_REPO_LOCAL_DEST") {
|
||||
let rpath = repo_path.clone();
|
||||
let mut response: HashMap<String, Value> = HashMap::new();
|
||||
if let Some(repo_path) = state.get_config("GIT_REPO_LOCAL_DEST") {
|
||||
let rpath = repo_path.clone();
|
||||
|
||||
let repo = match Repository::open_bare(rpath) {
|
||||
Ok(repo) => repo,
|
||||
Err(_) => {
|
||||
let error_log = "unable to open bare repo";
|
||||
let repo = match Repository::open_bare(rpath) {
|
||||
Ok(repo) => repo,
|
||||
Err(_) => {
|
||||
let error_log = "unable to open bare repo";
|
||||
error!("{error_log}");
|
||||
response.insert("error".to_string(), json!(error_log));
|
||||
return (
|
||||
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!(response)),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let mut remote = match repo.find_remote("origin") {
|
||||
Ok(remote) => remote,
|
||||
Err(e) => {
|
||||
let error_log = format!("unable to find remote, {}", e.message());
|
||||
error!("{error_log}");
|
||||
return (
|
||||
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!(response)),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
if state.get_config("GIT_REPO_USERNAME").is_none()
|
||||
|| state.get_config("GIT_REPO_PASSWORD").is_none()
|
||||
{
|
||||
warn!("username or password not provided may cause fetching fail");
|
||||
}
|
||||
|
||||
let mut callbacks = RemoteCallbacks::new();
|
||||
callbacks.credentials(|_, _, _| {
|
||||
Cred::userpass_plaintext(
|
||||
state
|
||||
.get_config("GIT_REPO_USERNAME")
|
||||
.unwrap_or(&"".to_string()),
|
||||
state
|
||||
.get_config("GIT_REPO_PASSWORD")
|
||||
.unwrap_or(&"".to_string()),
|
||||
)
|
||||
});
|
||||
|
||||
let mut fetch_options = FetchOptions::new();
|
||||
fetch_options.remote_callbacks(callbacks);
|
||||
|
||||
match remote.fetch(&["origin"], Some(&mut fetch_options), None) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
error!("error while fetching {}", e.message());
|
||||
return (
|
||||
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!({"error": format!("error while fetching {}", e.message())})),
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let error_log = "cannot find local repo";
|
||||
error!("{error_log}");
|
||||
response.insert("error".to_string(), json!(error_log));
|
||||
return (
|
||||
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!(response))
|
||||
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!(response)),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let mut remote = match repo.find_remote("origin") {
|
||||
Ok(remote) => remote,
|
||||
Err(e) => {
|
||||
let error_log = format!("unable to find remote, {}", e.message());
|
||||
error!("{error_log}");
|
||||
return (
|
||||
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!(response))
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
if state.get_config("GIT_REPO_USERNAME").is_none() || state.get_config("GIT_REPO_PASSWORD").is_none() {
|
||||
warn!("username or password not provided may cause fetching fail");
|
||||
}
|
||||
|
||||
let mut callbacks = RemoteCallbacks::new();
|
||||
callbacks.credentials(|_, _, _| {
|
||||
Cred::userpass_plaintext(
|
||||
state.get_config("GIT_REPO_USERNAME").unwrap_or(&"".to_string()),
|
||||
state.get_config("GIT_REPO_PASSWORD").unwrap_or(&"".to_string())
|
||||
)
|
||||
});
|
||||
(
|
||||
axum::http::StatusCode::OK,
|
||||
Json(json!({"result": "fetch success"})),
|
||||
)
|
||||
}
|
||||
|
||||
let mut fetch_options = FetchOptions::new();
|
||||
fetch_options.remote_callbacks(callbacks);
|
||||
// { path: "/path/to/file", signature: {
|
||||
// username: "", email: ""
|
||||
// }, patch_key: "edit_id_from_redis"}
|
||||
#[derive(Deserialize)]
|
||||
struct CommitBody {
|
||||
// Actual file path
|
||||
path: String,
|
||||
// Signature of user
|
||||
signature: Signature,
|
||||
// Key to grep content changes from redis
|
||||
patch_key: String,
|
||||
// user message
|
||||
message: Option<String>,
|
||||
#[serde(flatten)]
|
||||
extra: HashMap<String, Value>,
|
||||
}
|
||||
|
||||
match remote.fetch(&["origin"], Some(&mut fetch_options), None) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
error!("error while fetching {}", e.message());
|
||||
return (
|
||||
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!({"error": format!("error while fetching {}", e.message())}))
|
||||
);
|
||||
}
|
||||
#[derive(Deserialize)]
|
||||
struct Signature {
|
||||
username: String,
|
||||
email: String,
|
||||
}
|
||||
|
||||
#[debug_handler]
|
||||
async fn commit_handler(
|
||||
State(state): State<AppState>,
|
||||
// request body
|
||||
Json(payload): Json<CommitBody>,
|
||||
) -> impl IntoResponse {
|
||||
let mut content = match fetch_content_from_redis(state.redis.clone(), &payload.patch_key).await
|
||||
{
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
return (
|
||||
axum::http::StatusCode::BAD_REQUEST,
|
||||
Json(json!({"error": e})),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let is_patch_file = content.starts_with("patch");
|
||||
// do apply patch first
|
||||
if is_patch_file {
|
||||
content = apply_patch_to_file(state.redis.clone(), &payload.path, &mut content).await;
|
||||
}
|
||||
} else {
|
||||
let error_log = "cannot find local repo";
|
||||
error!("{error_log}");
|
||||
response.insert("error".to_string(), json!(error_log));
|
||||
return (
|
||||
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!(response))
|
||||
);
|
||||
}
|
||||
|
||||
(
|
||||
axum::http::StatusCode::OK,
|
||||
Json(json!({"result": "fetch success"}))
|
||||
)
|
||||
let commit_oid = match commit_file_content(
|
||||
state.repo,
|
||||
&payload.path,
|
||||
&content.as_bytes(),
|
||||
payload.signature,
|
||||
&payload.message.unwrap_or("update: from api".to_string()),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(oid) => oid,
|
||||
Err(e) => {
|
||||
return (
|
||||
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!({"error": e.to_string()})),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// save history
|
||||
let redis_pre_lock = state.redis.clone();
|
||||
{
|
||||
if let Ok(mut rl) = redis_pre_lock.try_lock() {
|
||||
let _ = rl.rpush(format!("{}.history", payload.path), payload.patch_key);
|
||||
}
|
||||
}
|
||||
|
||||
(
|
||||
axum::http::StatusCode::OK,
|
||||
Json(json!({"result": format!("{commit_oid}")})),
|
||||
)
|
||||
}
|
||||
|
||||
async fn fetch_content_from_redis(
|
||||
redis: Arc<Mutex<redis::Client>>,
|
||||
key: &str,
|
||||
) -> Result<String, String> {
|
||||
match redis.lock().await.get(key) {
|
||||
Ok(s) => {
|
||||
if let Some(res) = s {
|
||||
Ok(res)
|
||||
} else {
|
||||
Err(format!("result error from key: {key}"))
|
||||
}
|
||||
}
|
||||
Err(e) => Err(format!("redis get failed: {e}")),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_patch_from_str(patch_changes: &str) -> Option<Value> {
|
||||
//
|
||||
|
||||
let pv = patch_changes.replace("patch ", "");
|
||||
|
||||
let change_map: Value = match serde_json::from_str(&pv) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return None,
|
||||
};
|
||||
Some(change_map)
|
||||
}
|
||||
|
||||
fn get_product_code(v: &Value) -> Option<&str> {
|
||||
v.get("productCode")?.as_str()
|
||||
}
|
||||
|
||||
fn diff_apply(target: &mut Value, patch: &Value) -> Result<(), String> {
|
||||
match (target, patch) {
|
||||
(Value::Object(target_map), Value::Object(patch_map)) => {
|
||||
for (k, v_patch) in patch_map {
|
||||
let v_target = target_map
|
||||
.get_mut(k)
|
||||
.ok_or_else(|| format!("Unknown key in patch: {k}"))?;
|
||||
|
||||
diff_apply(v_target, v_patch)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
(Value::Array(target_arr), Value::Array(patch_arr)) => {
|
||||
for patch_elem in patch_arr {
|
||||
// NOTE: support only `Recipe01`
|
||||
let patch_id = get_product_code(patch_elem)
|
||||
.ok_or("Patch array element missing product code")?;
|
||||
let target_elem = target_arr
|
||||
.iter_mut()
|
||||
.find(|e| get_product_code(e) == Some(patch_id))
|
||||
.ok_or_else(|| format!("Unknown id in patch array: {patch_id}"))?;
|
||||
|
||||
diff_apply(target_elem, patch_elem)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
(target_slot, patch_value) => {
|
||||
*target_slot = patch_value.clone();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn apply_patch_to_file(
|
||||
redis: Arc<Mutex<redis::Client>>,
|
||||
path: &str,
|
||||
patch_changes: &mut String,
|
||||
) -> String {
|
||||
use libtbr::*;
|
||||
// expect the path to already has in redis
|
||||
let full_file = match fetch_content_from_redis(redis, path).await {
|
||||
Ok(f) => f,
|
||||
Err(_) => String::new(),
|
||||
};
|
||||
|
||||
if full_file.is_empty() {
|
||||
return full_file;
|
||||
}
|
||||
|
||||
// read into struct
|
||||
//
|
||||
let full_recipe: models::recipe::Recipe = match serde_json::from_str(&full_file) {
|
||||
Ok(f) => f,
|
||||
Err(_) => return String::new(),
|
||||
};
|
||||
|
||||
// read patch
|
||||
let patch_map = read_patch_from_str(patch_changes);
|
||||
let mut current_full_map = match serde_json::to_value(full_recipe.clone()) {
|
||||
Ok(m) => m,
|
||||
Err(_) => return String::new(),
|
||||
};
|
||||
|
||||
if let Some(pm) = patch_map {
|
||||
match diff_apply(&mut current_full_map, &pm) {
|
||||
Ok(_) => {}
|
||||
Err(x) => {
|
||||
error!("error while applied patch: {x}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match serde_json::to_string(¤t_full_map.clone()) {
|
||||
Ok(ss) => ss,
|
||||
Err(_) => String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn commit_file_content(
|
||||
repo: Arc<Mutex<Repository>>,
|
||||
path: &str,
|
||||
content: &[u8],
|
||||
author: Signature,
|
||||
message: &str,
|
||||
) -> Result<git2::Oid, Box<dyn std::error::Error>> {
|
||||
let repo_clone = repo.clone();
|
||||
let blob_oid = repo_clone.lock().await.blob(content)?;
|
||||
info!("blob oid: {blob_oid}");
|
||||
let mut index = repo_clone.lock().await.index()?;
|
||||
info!("index pass");
|
||||
let rlock = repo_clone.try_lock()?;
|
||||
let parent = match rlock.head() {
|
||||
Ok(head) => {
|
||||
let commit = head.peel_to_commit()?;
|
||||
index.read_tree(&commit.tree()?)?;
|
||||
Some(commit.clone())
|
||||
}
|
||||
Err(_) => None,
|
||||
};
|
||||
|
||||
info!("parent pass");
|
||||
|
||||
index.add(&git2::IndexEntry {
|
||||
ctime: git2::IndexTime::new(0, 0),
|
||||
mtime: git2::IndexTime::new(0, 0),
|
||||
dev: 0,
|
||||
ino: 0,
|
||||
mode: 0o100644,
|
||||
uid: 0,
|
||||
gid: 0,
|
||||
file_size: content.len() as u32,
|
||||
id: blob_oid,
|
||||
flags: 0,
|
||||
flags_extended: 0,
|
||||
path: path.as_bytes().to_vec(),
|
||||
})?;
|
||||
|
||||
info!("index added");
|
||||
|
||||
let tree_oid = index.write_tree()?;
|
||||
|
||||
info!("write to tree");
|
||||
// let tlock = repo_clone.try_lock()?;
|
||||
info!("acquire try lock");
|
||||
let tree = rlock.find_tree(tree_oid)?;
|
||||
info!("find tree ok");
|
||||
|
||||
let sig = git2::Signature::now(&author.username, &author.email)?;
|
||||
info!("generated signature");
|
||||
|
||||
let parents: Vec<&git2::Commit> = parent.iter().collect();
|
||||
let oid = rlock.commit(
|
||||
Some("refs/heads/master"),
|
||||
&sig,
|
||||
&sig,
|
||||
message,
|
||||
&tree,
|
||||
&parents,
|
||||
)?;
|
||||
|
||||
info!("commit oid: {oid}");
|
||||
|
||||
Ok(oid)
|
||||
}
|
||||
|
||||
async fn push_handler(State(state): State<AppState>) -> impl IntoResponse {
|
||||
let config = state.clone().get_all_configures();
|
||||
let repo = state.repo.clone();
|
||||
let remote_name = match state.get_config("GIT_REPO_REMOTE") {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
return (
|
||||
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!({"error": "repo remote not existed"})),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let branch = "master";
|
||||
|
||||
if let Err(e) = push(config, repo, remote_name, branch) {
|
||||
return (
|
||||
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!({"error": e.to_string()})),
|
||||
);
|
||||
}
|
||||
|
||||
(
|
||||
axum::http::StatusCode::OK,
|
||||
Json(json!({"result": "push completed"})),
|
||||
)
|
||||
}
|
||||
|
||||
fn push(
|
||||
config: gcm::Configure,
|
||||
repo: Arc<Mutex<Repository>>,
|
||||
remote_name: &str,
|
||||
branch: &str,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
if let Ok(rlock) = repo.try_lock() {
|
||||
let mut rem = rlock.find_remote(remote_name)?;
|
||||
let mut callback = RemoteCallbacks::new();
|
||||
callback.credentials(|_url, _user, _allowed| {
|
||||
Cred::userpass_plaintext(
|
||||
config.get("GIT_REPO_USERNAME").unwrap_or(&"".to_string()),
|
||||
config.get("GIT_REPO_PASSWORD").unwrap_or(&"".to_string()),
|
||||
)
|
||||
});
|
||||
let mut push_opts = PushOptions::new();
|
||||
push_opts.remote_callbacks(callback);
|
||||
let refspec = format!("refs/heads/{0}:refs/heads/{0}", branch);
|
||||
rem.push(&[&refspec], Some(&mut push_opts))?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Err("cannot lock repo".into())
|
||||
}
|
||||
|
||||
pub async fn run(config: gcm::Configure) -> gcm::StandardResult {
|
||||
let state = AppState {
|
||||
cached_country_names: common::valid_country_name(),
|
||||
configures: config.clone()
|
||||
};
|
||||
let state = AppState {
|
||||
// cached_country_names: common::valid_country_name(),
|
||||
configures: config.clone(),
|
||||
repo: Arc::new(Mutex::new(Repository::open_bare(
|
||||
config.get("GIT_REPO_LOCAL_DEST").unwrap_or(&"".to_string()),
|
||||
)?)),
|
||||
redis: Arc::new(Mutex::new(redis::Client::open(format!(
|
||||
"redis://{}:{}",
|
||||
config.get("REDIS_URI").unwrap_or(&"".to_string()),
|
||||
config.get("REDIS_PORT").unwrap_or(&"".to_string())
|
||||
))?)),
|
||||
};
|
||||
|
||||
let app = Router::new()
|
||||
.route("/checkout", get(checkout_handler))
|
||||
.route("/fetch", get(fetch_handler))
|
||||
.route("/healthz", get(reg::health))
|
||||
.with_state(state);
|
||||
let app = Router::new()
|
||||
.route("/checkout", get(checkout_handler))
|
||||
.route("/fetch", get(fetch_handler))
|
||||
.route("/commit", post(commit_handler))
|
||||
.route("/push", get(push_handler))
|
||||
.route("/healthz", get(reg::health))
|
||||
.with_state(state);
|
||||
|
||||
let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{}", config.clone().get("PUBLIC_PORT").unwrap_or(&"36583".to_string()))).await?;
|
||||
let listener = tokio::net::TcpListener::bind(format!(
|
||||
"0.0.0.0:{}",
|
||||
config
|
||||
.clone()
|
||||
.get("PUBLIC_PORT")
|
||||
.unwrap_or(&"36583".to_string())
|
||||
))
|
||||
.await?;
|
||||
|
||||
axum::serve(listener, app).await?;
|
||||
axum::serve(listener, app).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue