feat: setup for blossom uploads
refactor: move db to crate
This commit is contained in:
parent
0539468a5c
commit
9fdc1defaa
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1,3 @@
|
|||||||
/target
|
**/target
|
||||||
.idea/
|
.idea/
|
||||||
out/
|
out/
|
353
Cargo.lock
generated
353
Cargo.lock
generated
@ -251,6 +251,12 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atomic-waker"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@ -590,7 +596,7 @@ dependencies = [
|
|||||||
"num-traits",
|
"num-traits",
|
||||||
"serde",
|
"serde",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"windows-targets 0.52.4",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -747,6 +753,16 @@ dependencies = [
|
|||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation-sys"
|
name = "core-foundation-sys"
|
||||||
version = "0.8.7"
|
version = "0.8.7"
|
||||||
@ -1106,6 +1122,21 @@ dependencies = [
|
|||||||
"ttf-parser 0.21.1",
|
"ttf-parser 0.21.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||||
|
dependencies = [
|
||||||
|
"foreign-types-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types-shared"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "form_urlencoded"
|
name = "form_urlencoded"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
@ -1290,6 +1321,25 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "h2"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205"
|
||||||
|
dependencies = [
|
||||||
|
"atomic-waker",
|
||||||
|
"bytes",
|
||||||
|
"fnv",
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"http 1.1.0",
|
||||||
|
"indexmap 2.2.5",
|
||||||
|
"slab",
|
||||||
|
"tokio",
|
||||||
|
"tokio-util",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.12.3"
|
version = "0.12.3"
|
||||||
@ -1506,7 +1556,7 @@ dependencies = [
|
|||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"h2",
|
"h2 0.3.26",
|
||||||
"http 0.2.12",
|
"http 0.2.12",
|
||||||
"http-body 0.4.6",
|
"http-body 0.4.6",
|
||||||
"httparse",
|
"httparse",
|
||||||
@ -1529,6 +1579,7 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
|
"h2 0.4.6",
|
||||||
"http 1.1.0",
|
"http 1.1.0",
|
||||||
"http-body 1.0.1",
|
"http-body 1.0.1",
|
||||||
"httparse",
|
"httparse",
|
||||||
@ -1583,6 +1634,22 @@ dependencies = [
|
|||||||
"tokio-io-timeout",
|
"tokio-io-timeout",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper-tls"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"http-body-util",
|
||||||
|
"hyper 1.5.0",
|
||||||
|
"hyper-util",
|
||||||
|
"native-tls",
|
||||||
|
"tokio",
|
||||||
|
"tokio-native-tls",
|
||||||
|
"tower-service",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper-util"
|
name = "hyper-util"
|
||||||
version = "0.1.10"
|
version = "0.1.10"
|
||||||
@ -1807,7 +1874,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
|
checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"windows-targets 0.52.4",
|
"windows-targets 0.48.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1994,6 +2061,23 @@ version = "0.10.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03"
|
checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "native-tls"
|
||||||
|
version = "0.2.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"openssl",
|
||||||
|
"openssl-probe",
|
||||||
|
"openssl-sys",
|
||||||
|
"schannel",
|
||||||
|
"security-framework",
|
||||||
|
"security-framework-sys",
|
||||||
|
"tempfile",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "negentropy"
|
name = "negentropy"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
@ -2194,6 +2278,50 @@ version = "0.3.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
|
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl"
|
||||||
|
version = "0.10.68"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.4.2",
|
||||||
|
"cfg-if",
|
||||||
|
"foreign-types",
|
||||||
|
"libc",
|
||||||
|
"once_cell",
|
||||||
|
"openssl-macros",
|
||||||
|
"openssl-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-macros"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.87",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-probe"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-sys"
|
||||||
|
version = "0.9.104"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
"vcpkg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ordered-multimap"
|
name = "ordered-multimap"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
@ -2230,7 +2358,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"windows-targets 0.52.4",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2656,24 +2784,28 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.12.5"
|
version = "0.12.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37"
|
checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
"encoding_rs",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
|
"h2 0.4.6",
|
||||||
"http 1.1.0",
|
"http 1.1.0",
|
||||||
"http-body 1.0.1",
|
"http-body 1.0.1",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper 1.5.0",
|
"hyper 1.5.0",
|
||||||
"hyper-rustls 0.27.3",
|
"hyper-rustls 0.27.3",
|
||||||
|
"hyper-tls",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"ipnet",
|
"ipnet",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
"mime",
|
"mime",
|
||||||
|
"native-tls",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
@ -2685,16 +2817,20 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
"sync_wrapper 1.0.1",
|
"sync_wrapper 1.0.1",
|
||||||
|
"system-configuration",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tokio-native-tls",
|
||||||
"tokio-rustls 0.26.0",
|
"tokio-rustls 0.26.0",
|
||||||
"tokio-socks",
|
"tokio-socks",
|
||||||
|
"tokio-util",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
"url",
|
"url",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
|
"wasm-streams",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"webpki-roots",
|
"webpki-roots",
|
||||||
"winreg",
|
"windows-registry",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2949,6 +3085,15 @@ dependencies = [
|
|||||||
"cipher",
|
"cipher",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "schannel"
|
||||||
|
version = "0.1.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scoped-tls"
|
name = "scoped-tls"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@ -3004,6 +3149,29 @@ dependencies = [
|
|||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework"
|
||||||
|
version = "2.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"core-foundation",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
"security-framework-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework-sys"
|
||||||
|
version = "2.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "1.0.22"
|
version = "1.0.22"
|
||||||
@ -3537,6 +3705,30 @@ name = "sync_wrapper"
|
|||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
|
checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "system-configuration"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.4.2",
|
||||||
|
"core-foundation",
|
||||||
|
"system-configuration-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "system-configuration-sys"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "take-until"
|
name = "take-until"
|
||||||
@ -3693,6 +3885,16 @@ dependencies = [
|
|||||||
"syn 2.0.87",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-native-tls"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
|
||||||
|
dependencies = [
|
||||||
|
"native-tls",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-rustls"
|
name = "tokio-rustls"
|
||||||
version = "0.24.1"
|
version = "0.24.1"
|
||||||
@ -3825,7 +4027,7 @@ dependencies = [
|
|||||||
"axum",
|
"axum",
|
||||||
"base64 0.21.7",
|
"base64 0.21.7",
|
||||||
"bytes",
|
"bytes",
|
||||||
"h2",
|
"h2 0.3.26",
|
||||||
"http 0.2.12",
|
"http 0.2.12",
|
||||||
"http-body 0.4.6",
|
"http-body 0.4.6",
|
||||||
"hyper 0.14.31",
|
"hyper 0.14.31",
|
||||||
@ -4268,6 +4470,19 @@ version = "0.2.95"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
|
checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-streams"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129"
|
||||||
|
dependencies = [
|
||||||
|
"futures-util",
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"wasm-bindgen-futures",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-sys"
|
name = "web-sys"
|
||||||
version = "0.3.72"
|
version = "0.3.72"
|
||||||
@ -4350,7 +4565,37 @@ version = "0.52.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets 0.52.4",
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-registry"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0"
|
||||||
|
dependencies = [
|
||||||
|
"windows-result",
|
||||||
|
"windows-strings",
|
||||||
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-result"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-strings"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
|
||||||
|
dependencies = [
|
||||||
|
"windows-result",
|
||||||
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4368,7 +4613,16 @@ version = "0.52.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets 0.52.4",
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.59.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4388,17 +4642,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.52.4"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
|
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows_aarch64_gnullvm 0.52.4",
|
"windows_aarch64_gnullvm 0.52.6",
|
||||||
"windows_aarch64_msvc 0.52.4",
|
"windows_aarch64_msvc 0.52.6",
|
||||||
"windows_i686_gnu 0.52.4",
|
"windows_i686_gnu 0.52.6",
|
||||||
"windows_i686_msvc 0.52.4",
|
"windows_i686_gnullvm",
|
||||||
"windows_x86_64_gnu 0.52.4",
|
"windows_i686_msvc 0.52.6",
|
||||||
"windows_x86_64_gnullvm 0.52.4",
|
"windows_x86_64_gnu 0.52.6",
|
||||||
"windows_x86_64_msvc 0.52.4",
|
"windows_x86_64_gnullvm 0.52.6",
|
||||||
|
"windows_x86_64_msvc 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4409,9 +4664,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.52.4"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
|
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
@ -4421,9 +4676,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.52.4"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
|
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
@ -4433,9 +4688,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.52.4"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
|
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
@ -4445,9 +4706,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.52.4"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
|
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
@ -4457,9 +4718,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.52.4"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
|
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
@ -4469,9 +4730,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.52.4"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
|
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
@ -4481,9 +4742,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.52.4"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
@ -4494,16 +4755,6 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winreg"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"windows-sys 0.48.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xmlwriter"
|
name = "xmlwriter"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -4525,6 +4776,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
"base64 0.22.1",
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"config",
|
"config",
|
||||||
@ -4532,6 +4784,7 @@ dependencies = [
|
|||||||
"ffmpeg-rs-raw",
|
"ffmpeg-rs-raw",
|
||||||
"fontdue",
|
"fontdue",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
|
"hex",
|
||||||
"itertools 0.13.0",
|
"itertools 0.13.0",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
@ -4539,10 +4792,11 @@ dependencies = [
|
|||||||
"nostr-sdk",
|
"nostr-sdk",
|
||||||
"pretty_env_logger",
|
"pretty_env_logger",
|
||||||
"rand",
|
"rand",
|
||||||
|
"reqwest",
|
||||||
"resvg",
|
"resvg",
|
||||||
"ringbuf",
|
"ringbuf",
|
||||||
"serde",
|
"serde",
|
||||||
"sqlx",
|
"sha2",
|
||||||
"srt-tokio",
|
"srt-tokio",
|
||||||
"tiny-skia",
|
"tiny-skia",
|
||||||
"tokio",
|
"tokio",
|
||||||
@ -4551,6 +4805,17 @@ dependencies = [
|
|||||||
"usvg",
|
"usvg",
|
||||||
"uuid",
|
"uuid",
|
||||||
"warp",
|
"warp",
|
||||||
|
"zap-stream-db",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zap-stream-db"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"chrono",
|
||||||
|
"log",
|
||||||
|
"sqlx",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
23
Cargo.toml
23
Cargo.toml
@ -10,8 +10,17 @@ path = "src/bin/zap_stream_core.rs"
|
|||||||
[features]
|
[features]
|
||||||
default = ["test-pattern"]
|
default = ["test-pattern"]
|
||||||
srt = ["dep:srt-tokio"]
|
srt = ["dep:srt-tokio"]
|
||||||
zap-stream = ["dep:nostr-sdk", "dep:sqlx", "dep:fedimint-tonic-lnd", "dep:chrono"]
|
zap-stream = [
|
||||||
test-pattern = ["dep:resvg", "dep:usvg", "dep:tiny-skia", "dep:fontdue", "dep:ringbuf"]
|
"dep:nostr-sdk",
|
||||||
|
"dep:zap-stream-db",
|
||||||
|
"dep:fedimint-tonic-lnd",
|
||||||
|
"dep:reqwest",
|
||||||
|
"tokio/fs",
|
||||||
|
"dep:base64",
|
||||||
|
"dep:sha2",
|
||||||
|
"dep:hex"
|
||||||
|
]
|
||||||
|
test-pattern = ["dep:resvg", "dep:usvg", "dep:tiny-skia", "dep:fontdue", "dep:ringbuf", "zap-stream-db/test-pattern"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ffmpeg-rs-raw = { git = "https://git.v0l.io/Kieran/ffmpeg-rs-raw.git", rev = "0abe0c5229adeb64b013d1895c7eba3d917f05a4" }
|
ffmpeg-rs-raw = { git = "https://git.v0l.io/Kieran/ffmpeg-rs-raw.git", rev = "0abe0c5229adeb64b013d1895c7eba3d917f05a4" }
|
||||||
@ -32,6 +41,7 @@ clap = { version = "4.5.16", features = ["derive"] }
|
|||||||
warp = "0.3.7"
|
warp = "0.3.7"
|
||||||
libc = "0.2.162"
|
libc = "0.2.162"
|
||||||
m3u8-rs = "6.0.0"
|
m3u8-rs = "6.0.0"
|
||||||
|
chrono = "^0.4.38"
|
||||||
|
|
||||||
# test-pattern
|
# test-pattern
|
||||||
srt-tokio = { version = "0.4.3", optional = true }
|
srt-tokio = { version = "0.4.3", optional = true }
|
||||||
@ -42,9 +52,10 @@ fontdue = { version = "0.9.2", optional = true }
|
|||||||
ringbuf = { version = "0.4.7", optional = true }
|
ringbuf = { version = "0.4.7", optional = true }
|
||||||
|
|
||||||
# zap-stream
|
# zap-stream
|
||||||
|
zap-stream-db = { path = "zap-stream-db", optional = true }
|
||||||
nostr-sdk = { version = "0.36.0", optional = true }
|
nostr-sdk = { version = "0.36.0", optional = true }
|
||||||
sqlx = { version = "0.8.2", optional = true, features = ["runtime-tokio", "migrate", "mysql", "chrono"] }
|
|
||||||
fedimint-tonic-lnd = { version = "0.2.0", optional = true, default-features = false, features = ["invoicesrpc", "versionrpc"] }
|
fedimint-tonic-lnd = { version = "0.2.0", optional = true, default-features = false, features = ["invoicesrpc", "versionrpc"] }
|
||||||
chrono = { version = "0.4.38", optional = true, features = ["serde"] }
|
reqwest = { version = "0.12.9", optional = true, features = ["stream"] }
|
||||||
|
base64 = { version = "0.22.1", optional = true }
|
||||||
|
sha2 = { version = "0.10.8", optional = true }
|
||||||
|
hex = { version = "0.4.3", optional = true }
|
||||||
|
@ -4,14 +4,26 @@ services:
|
|||||||
image: mariadb
|
image: mariadb
|
||||||
environment:
|
environment:
|
||||||
- "MARIADB_ROOT_PASSWORD=root"
|
- "MARIADB_ROOT_PASSWORD=root"
|
||||||
- "MARIADB_DATABASE=zap-stream"
|
|
||||||
ports:
|
ports:
|
||||||
- "3368:3306"
|
- "3368:3306"
|
||||||
#volumes:
|
volumes:
|
||||||
#- "db:/var/lib/mysql"
|
- "./db.sql:/docker-entrypoint-initdb.d/00-init.sql"
|
||||||
relay:
|
relay:
|
||||||
image: scsibug/nostr-rs-relay
|
image: scsibug/nostr-rs-relay
|
||||||
ports:
|
ports:
|
||||||
- "7766:8080"
|
- "7766:8080"
|
||||||
|
blossom:
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
image: voidic/route96
|
||||||
|
environment:
|
||||||
|
- "RUST_LOG=info"
|
||||||
|
ports:
|
||||||
|
- "8881:8000"
|
||||||
|
volumes:
|
||||||
|
- "blossom:/app/data"
|
||||||
|
- "./route96.toml:/app/config.toml"
|
||||||
volumes:
|
volumes:
|
||||||
db:
|
db:
|
||||||
|
blossom:
|
||||||
|
relay:
|
29
route96.toml
Normal file
29
route96.toml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# Listen address for webserver
|
||||||
|
listen = "127.0.0.1:8000"
|
||||||
|
|
||||||
|
# Database connection string (MYSQL)
|
||||||
|
database = "mysql://root:root@db:3306/route96"
|
||||||
|
|
||||||
|
# Directory to store uploads
|
||||||
|
storage_dir = "./data"
|
||||||
|
|
||||||
|
# Maximum support filesize for uploading
|
||||||
|
max_upload_bytes = 5e+9
|
||||||
|
|
||||||
|
# Public facing url
|
||||||
|
public_url = "http://localhost:8881"
|
||||||
|
|
||||||
|
# Whitelisted pubkeys, leave out to disable
|
||||||
|
# whitelist = ["63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed"]
|
||||||
|
|
||||||
|
# Path for ViT(224) image model (https://huggingface.co/google/vit-base-patch16-224)
|
||||||
|
# vit_model_path = "model.safetennsors"
|
||||||
|
|
||||||
|
# Webhook api endpoint
|
||||||
|
# webhook_url = "https://api.snort.social/api/v1/media/webhook"
|
||||||
|
|
||||||
|
# Analytics support
|
||||||
|
# plausible_url = "https://plausible.com/"
|
||||||
|
|
||||||
|
# Support legacy void
|
||||||
|
# void_cat_database = "postgres://postgres:postgres@localhost:41911/void"
|
93
src/blossom.rs
Normal file
93
src/blossom.rs
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use anyhow::Result;
|
||||||
|
use base64::Engine;
|
||||||
|
use nostr_sdk::{EventBuilder, JsonUtil, Keys, Kind, Tag, Timestamp};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use sha2::{Digest, Sha256};
|
||||||
|
use std::io::SeekFrom;
|
||||||
|
use std::ops::Add;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use tokio::fs::File;
|
||||||
|
use tokio::io::{AsyncReadExt, AsyncSeekExt};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
pub struct Blossom {
|
||||||
|
url: Url,
|
||||||
|
client: reqwest::Client,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct BlobDescriptor {
|
||||||
|
pub url: String,
|
||||||
|
pub sha256: String,
|
||||||
|
pub size: u64,
|
||||||
|
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
|
||||||
|
pub mime_type: Option<String>,
|
||||||
|
pub created: u64,
|
||||||
|
#[serde(rename = "nip94", skip_serializing_if = "Option::is_none")]
|
||||||
|
pub nip94: Option<HashMap<String, String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Blossom {
|
||||||
|
pub fn new(url: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
url: url.parse().unwrap(),
|
||||||
|
client: reqwest::Client::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn hash_file(f: &mut File) -> Result<String> {
|
||||||
|
let mut hash = Sha256::new();
|
||||||
|
let mut buf: [u8; 1024] = [0; 1024];
|
||||||
|
f.seek(SeekFrom::Start(0)).await?;
|
||||||
|
while let Ok(data) = f.read(&mut buf).await {
|
||||||
|
if data == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
hash.update(&buf[..data]);
|
||||||
|
}
|
||||||
|
let hash = hash.finalize();
|
||||||
|
f.seek(SeekFrom::Start(0)).await?;
|
||||||
|
Ok(hex::encode(hash))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn upload(
|
||||||
|
&self,
|
||||||
|
from_file: &PathBuf,
|
||||||
|
keys: &Keys,
|
||||||
|
) -> Result<BlobDescriptor> {
|
||||||
|
let mut f = File::open(from_file).await?;
|
||||||
|
let hash = Self::hash_file(&mut f).await?;
|
||||||
|
let auth_event = EventBuilder::new(
|
||||||
|
Kind::Custom(24242),
|
||||||
|
"Upload blob",
|
||||||
|
[
|
||||||
|
Tag::hashtag("upload"),
|
||||||
|
Tag::parse(&["x", &hash])?,
|
||||||
|
Tag::expiration(Timestamp::now().add(60)),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
let auth_event = auth_event.sign_with_keys(keys)?;
|
||||||
|
|
||||||
|
let rsp: BlobDescriptor = self
|
||||||
|
.client
|
||||||
|
.put(self.url.join("/upload").unwrap())
|
||||||
|
.header("Content-Type", "application/octet-stream")
|
||||||
|
.header(
|
||||||
|
"Authorization",
|
||||||
|
&format!(
|
||||||
|
"Nostr {}",
|
||||||
|
base64::engine::general_purpose::STANDARD
|
||||||
|
.encode(auth_event.as_json().as_bytes())
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.body(f)
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.json()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(rsp)
|
||||||
|
}
|
||||||
|
}
|
@ -5,3 +5,4 @@ pub mod overseer;
|
|||||||
pub mod pipeline;
|
pub mod pipeline;
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
pub mod variant;
|
pub mod variant;
|
||||||
|
mod blossom;
|
||||||
|
@ -19,6 +19,7 @@ use std::sync::Arc;
|
|||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
mod webhook;
|
mod webhook;
|
||||||
|
|
||||||
#[cfg(feature = "zap-stream")]
|
#[cfg(feature = "zap-stream")]
|
||||||
mod zap_stream;
|
mod zap_stream;
|
||||||
|
|
||||||
|
183
src/overseer/zap_stream.rs
Normal file
183
src/overseer/zap_stream.rs
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
use crate::blossom::Blossom;
|
||||||
|
use crate::egress::hls::HlsEgress;
|
||||||
|
use crate::egress::EgressConfig;
|
||||||
|
use crate::ingress::ConnectionInfo;
|
||||||
|
use crate::overseer::{get_default_variants, IngressInfo, Overseer};
|
||||||
|
use crate::pipeline::{EgressType, PipelineConfig};
|
||||||
|
use crate::settings::LndSettings;
|
||||||
|
use crate::variant::StreamMapping;
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use chrono::Utc;
|
||||||
|
use fedimint_tonic_lnd::verrpc::VersionRequest;
|
||||||
|
use log::info;
|
||||||
|
use nostr_sdk::bitcoin::PrivateKey;
|
||||||
|
use nostr_sdk::{Client, Event, EventBuilder, JsonUtil, Keys, Kind, Tag};
|
||||||
|
use std::env::temp_dir;
|
||||||
|
use std::fs::create_dir_all;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use uuid::Uuid;
|
||||||
|
use zap_stream_db::{UserStream, UserStreamState, ZapStreamDb};
|
||||||
|
|
||||||
|
/// zap.stream NIP-53 overseer
|
||||||
|
pub struct ZapStreamOverseer {
|
||||||
|
db: ZapStreamDb,
|
||||||
|
lnd: fedimint_tonic_lnd::Client,
|
||||||
|
client: Client,
|
||||||
|
keys: Keys,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ZapStreamOverseer {
|
||||||
|
pub async fn new(
|
||||||
|
private_key: &str,
|
||||||
|
db: &str,
|
||||||
|
lnd: &LndSettings,
|
||||||
|
relays: &Vec<String>,
|
||||||
|
) -> Result<Self> {
|
||||||
|
let db = ZapStreamDb::new(db).await?;
|
||||||
|
|
||||||
|
let mut lnd = fedimint_tonic_lnd::connect(
|
||||||
|
lnd.address.clone(),
|
||||||
|
PathBuf::from(&lnd.cert),
|
||||||
|
PathBuf::from(&lnd.macaroon),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let version = lnd
|
||||||
|
.versioner()
|
||||||
|
.get_version(VersionRequest::default())
|
||||||
|
.await?;
|
||||||
|
info!("LND connected: v{}", version.into_inner().version);
|
||||||
|
|
||||||
|
let keys = Keys::from_str(private_key)?;
|
||||||
|
let client = nostr_sdk::ClientBuilder::new().signer(keys.clone()).build();
|
||||||
|
for r in relays {
|
||||||
|
client.add_relay(r).await?;
|
||||||
|
}
|
||||||
|
client.connect().await;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
db,
|
||||||
|
lnd,
|
||||||
|
client,
|
||||||
|
keys,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Overseer for ZapStreamOverseer {
|
||||||
|
async fn start_stream(
|
||||||
|
&self,
|
||||||
|
connection: &ConnectionInfo,
|
||||||
|
stream_info: &IngressInfo,
|
||||||
|
) -> Result<PipelineConfig> {
|
||||||
|
let uid = self
|
||||||
|
.db
|
||||||
|
.find_user_stream_key(&connection.key)
|
||||||
|
.await?
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("User not found"))?;
|
||||||
|
|
||||||
|
let out_dir = temp_dir().join("zap-stream");
|
||||||
|
create_dir_all(&out_dir)?;
|
||||||
|
|
||||||
|
let variants = get_default_variants(&stream_info)?;
|
||||||
|
|
||||||
|
let mut egress = vec![];
|
||||||
|
egress.push(EgressType::HLS(EgressConfig {
|
||||||
|
name: "nip94-hls".to_string(),
|
||||||
|
out_dir: out_dir.to_string_lossy().to_string(),
|
||||||
|
variants: variants.iter().map(|v| v.id()).collect(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
// insert new stream record
|
||||||
|
let mut new_stream = UserStream {
|
||||||
|
id: 0,
|
||||||
|
user_id: uid,
|
||||||
|
starts: Utc::now(),
|
||||||
|
state: UserStreamState::Live,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let stream_id = self.db.insert_stream(&new_stream).await?;
|
||||||
|
new_stream.id = stream_id;
|
||||||
|
|
||||||
|
let stream_event = publish_stream_event(&new_stream, &self.client).await?;
|
||||||
|
new_stream.event = Some(stream_event.as_json());
|
||||||
|
self.db.update_stream(&new_stream).await?;
|
||||||
|
|
||||||
|
Ok(PipelineConfig {
|
||||||
|
id: stream_id,
|
||||||
|
variants,
|
||||||
|
egress,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn on_segment(
|
||||||
|
&self,
|
||||||
|
pipeline: &Uuid,
|
||||||
|
variant_id: &Uuid,
|
||||||
|
index: u64,
|
||||||
|
duration: f32,
|
||||||
|
path: &PathBuf,
|
||||||
|
) -> Result<()> {
|
||||||
|
let blossom = Blossom::new("http://localhost:8881/");
|
||||||
|
|
||||||
|
let blob = blossom.upload(path, &self.keys).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn to_event_builder(this: &UserStream) -> Result<EventBuilder> {
|
||||||
|
let mut tags = vec![
|
||||||
|
Tag::parse(&["d".to_string(), this.id.to_string()])?,
|
||||||
|
Tag::parse(&["status".to_string(), this.state.to_string()])?,
|
||||||
|
Tag::parse(&["starts".to_string(), this.starts.timestamp().to_string()])?,
|
||||||
|
];
|
||||||
|
if let Some(ref ends) = this.ends {
|
||||||
|
tags.push(Tag::parse(&[
|
||||||
|
"ends".to_string(),
|
||||||
|
ends.timestamp().to_string(),
|
||||||
|
])?);
|
||||||
|
}
|
||||||
|
if let Some(ref title) = this.title {
|
||||||
|
tags.push(Tag::parse(&["title".to_string(), title.to_string()])?);
|
||||||
|
}
|
||||||
|
if let Some(ref summary) = this.summary {
|
||||||
|
tags.push(Tag::parse(&["summary".to_string(), summary.to_string()])?);
|
||||||
|
}
|
||||||
|
if let Some(ref image) = this.image {
|
||||||
|
tags.push(Tag::parse(&["image".to_string(), image.to_string()])?);
|
||||||
|
}
|
||||||
|
if let Some(ref thumb) = this.thumb {
|
||||||
|
tags.push(Tag::parse(&["thumb".to_string(), thumb.to_string()])?);
|
||||||
|
}
|
||||||
|
if let Some(ref content_warning) = this.content_warning {
|
||||||
|
tags.push(Tag::parse(&[
|
||||||
|
"content_warning".to_string(),
|
||||||
|
content_warning.to_string(),
|
||||||
|
])?);
|
||||||
|
}
|
||||||
|
if let Some(ref goal) = this.goal {
|
||||||
|
tags.push(Tag::parse(&["goal".to_string(), goal.to_string()])?);
|
||||||
|
}
|
||||||
|
if let Some(ref pinned) = this.pinned {
|
||||||
|
tags.push(Tag::parse(&["pinned".to_string(), pinned.to_string()])?);
|
||||||
|
}
|
||||||
|
if let Some(ref tags_csv) = this.tags {
|
||||||
|
for tag in tags_csv.split(',') {
|
||||||
|
tags.push(Tag::parse(&["t".to_string(), tag.to_string()])?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(EventBuilder::new(Kind::from(30_313), "", tags))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) async fn publish_stream_event(this: &UserStream, client: &Client) -> Result<Event> {
|
||||||
|
let ev = to_event_builder(this)?
|
||||||
|
.sign(&client.signer().await?)
|
||||||
|
.await?;
|
||||||
|
client.send_event(ev.clone()).await?;
|
||||||
|
Ok(ev)
|
||||||
|
}
|
@ -1,114 +0,0 @@
|
|||||||
use anyhow::Result;
|
|
||||||
use chrono::{DateTime, Utc};
|
|
||||||
use nostr_sdk::{Client, Event, EventBuilder, Kind, Tag};
|
|
||||||
use sqlx::{FromRow, Type};
|
|
||||||
use std::fmt::{Display, Formatter};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, FromRow)]
|
|
||||||
pub struct User {
|
|
||||||
pub id: u64,
|
|
||||||
pub pubkey: [u8; 32],
|
|
||||||
pub created: DateTime<Utc>,
|
|
||||||
pub balance: i64,
|
|
||||||
pub tos_accepted: DateTime<Utc>,
|
|
||||||
pub stream_key: String,
|
|
||||||
pub is_admin: bool,
|
|
||||||
pub is_blocked: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, Type)]
|
|
||||||
#[repr(u8)]
|
|
||||||
pub enum UserStreamState {
|
|
||||||
#[default]
|
|
||||||
Unknown = 0,
|
|
||||||
Planned = 1,
|
|
||||||
Live = 2,
|
|
||||||
Ended = 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for UserStreamState {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
UserStreamState::Unknown => write!(f, "unknown"),
|
|
||||||
UserStreamState::Planned => write!(f, "planned"),
|
|
||||||
UserStreamState::Live => write!(f, "live"),
|
|
||||||
UserStreamState::Ended => write!(f, "ended"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, FromRow)]
|
|
||||||
pub struct UserStream {
|
|
||||||
pub id: u64,
|
|
||||||
pub user_id: u64,
|
|
||||||
pub starts: DateTime<Utc>,
|
|
||||||
pub ends: Option<DateTime<Utc>>,
|
|
||||||
pub state: UserStreamState,
|
|
||||||
pub title: Option<String>,
|
|
||||||
pub summary: Option<String>,
|
|
||||||
pub image: Option<String>,
|
|
||||||
pub thumb: Option<String>,
|
|
||||||
pub tags: Option<String>,
|
|
||||||
pub content_warning: Option<String>,
|
|
||||||
pub goal: Option<String>,
|
|
||||||
pub pinned: Option<String>,
|
|
||||||
pub cost: u64,
|
|
||||||
pub duration: f32,
|
|
||||||
pub fee: Option<u32>,
|
|
||||||
pub event: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UserStream {
|
|
||||||
pub(crate) fn to_event_builder(&self) -> Result<EventBuilder> {
|
|
||||||
let mut tags = vec![
|
|
||||||
Tag::parse(&["d".to_string(), self.id.to_string()])?,
|
|
||||||
Tag::parse(&["status".to_string(), self.state.to_string()])?,
|
|
||||||
Tag::parse(&["starts".to_string(), self.starts.timestamp().to_string()])?,
|
|
||||||
];
|
|
||||||
if let Some(ref ends) = self.ends {
|
|
||||||
tags.push(Tag::parse(&[
|
|
||||||
"ends".to_string(),
|
|
||||||
ends.timestamp().to_string(),
|
|
||||||
])?);
|
|
||||||
}
|
|
||||||
if let Some(ref title) = self.title {
|
|
||||||
tags.push(Tag::parse(&["title".to_string(), title.to_string()])?);
|
|
||||||
}
|
|
||||||
if let Some(ref summary) = self.summary {
|
|
||||||
tags.push(Tag::parse(&["summary".to_string(), summary.to_string()])?);
|
|
||||||
}
|
|
||||||
if let Some(ref image) = self.image {
|
|
||||||
tags.push(Tag::parse(&["image".to_string(), image.to_string()])?);
|
|
||||||
}
|
|
||||||
if let Some(ref thumb) = self.thumb {
|
|
||||||
tags.push(Tag::parse(&["thumb".to_string(), thumb.to_string()])?);
|
|
||||||
}
|
|
||||||
if let Some(ref content_warning) = self.content_warning {
|
|
||||||
tags.push(Tag::parse(&[
|
|
||||||
"content_warning".to_string(),
|
|
||||||
content_warning.to_string(),
|
|
||||||
])?);
|
|
||||||
}
|
|
||||||
if let Some(ref goal) = self.goal {
|
|
||||||
tags.push(Tag::parse(&["goal".to_string(), goal.to_string()])?);
|
|
||||||
}
|
|
||||||
if let Some(ref pinned) = self.pinned {
|
|
||||||
tags.push(Tag::parse(&["pinned".to_string(), pinned.to_string()])?);
|
|
||||||
}
|
|
||||||
if let Some(ref tags_csv) = self.tags {
|
|
||||||
for tag in tags_csv.split(',') {
|
|
||||||
tags.push(Tag::parse(&["t".to_string(), tag.to_string()])?);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(EventBuilder::new(Kind::from(30_313), "", tags))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) async fn publish_stream_event(&self, client: &Client) -> Result<Event> {
|
|
||||||
let ev = self
|
|
||||||
.to_event_builder()?
|
|
||||||
.sign(&client.signer().await?)
|
|
||||||
.await?;
|
|
||||||
client.send_event(ev.clone()).await?;
|
|
||||||
Ok(ev)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,201 +0,0 @@
|
|||||||
use crate::egress::hls::HlsEgress;
|
|
||||||
use crate::egress::EgressConfig;
|
|
||||||
use crate::ingress::ConnectionInfo;
|
|
||||||
use crate::overseer::zap_stream::db::{UserStream, UserStreamState};
|
|
||||||
use crate::overseer::{get_default_variants, IngressInfo, Overseer};
|
|
||||||
use crate::pipeline::{EgressType, PipelineConfig};
|
|
||||||
use crate::settings::LndSettings;
|
|
||||||
use crate::variant::StreamMapping;
|
|
||||||
use anyhow::{anyhow, Result};
|
|
||||||
use async_trait::async_trait;
|
|
||||||
use chrono::{DateTime, Utc};
|
|
||||||
use fedimint_tonic_lnd::verrpc::VersionRequest;
|
|
||||||
use log::info;
|
|
||||||
use nostr_sdk::bitcoin::PrivateKey;
|
|
||||||
use nostr_sdk::{JsonUtil, Keys};
|
|
||||||
use sqlx::{MySqlPool, Row};
|
|
||||||
use std::env::temp_dir;
|
|
||||||
use std::fs::create_dir_all;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::str::FromStr;
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
mod db;
|
|
||||||
|
|
||||||
/// zap.stream NIP-53 overseer
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct ZapStreamOverseer {
|
|
||||||
db: MySqlPool,
|
|
||||||
lnd: fedimint_tonic_lnd::Client,
|
|
||||||
client: nostr_sdk::Client,
|
|
||||||
keys: Keys,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ZapStreamOverseer {
|
|
||||||
pub async fn new(
|
|
||||||
private_key: &str,
|
|
||||||
db: &str,
|
|
||||||
lnd: &LndSettings,
|
|
||||||
relays: &Vec<String>,
|
|
||||||
) -> Result<Self> {
|
|
||||||
let db = MySqlPool::connect(db).await?;
|
|
||||||
|
|
||||||
info!("Connected to database, running migrations");
|
|
||||||
// automatically run migrations
|
|
||||||
sqlx::migrate!().run(&db).await?;
|
|
||||||
|
|
||||||
let mut lnd = fedimint_tonic_lnd::connect(
|
|
||||||
lnd.address.clone(),
|
|
||||||
PathBuf::from(&lnd.cert),
|
|
||||||
PathBuf::from(&lnd.macaroon),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let version = lnd
|
|
||||||
.versioner()
|
|
||||||
.get_version(VersionRequest::default())
|
|
||||||
.await?;
|
|
||||||
info!("LND connected: v{}", version.into_inner().version);
|
|
||||||
|
|
||||||
let keys = Keys::from_str(private_key)?;
|
|
||||||
let client = nostr_sdk::ClientBuilder::new().signer(keys.clone()).build();
|
|
||||||
for r in relays {
|
|
||||||
client.add_relay(r).await?;
|
|
||||||
}
|
|
||||||
client.connect().await;
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
db,
|
|
||||||
lnd,
|
|
||||||
client,
|
|
||||||
keys,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Find user by stream key, typical first lookup from ingress
|
|
||||||
async fn find_user_stream_key(&self, key: &str) -> Result<Option<u64>> {
|
|
||||||
#[cfg(feature = "test-pattern")]
|
|
||||||
if key == "test-pattern" {
|
|
||||||
// use the 00 pubkey for test sources
|
|
||||||
return Ok(Some(self.upsert_user(&[0; 32]).await?));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(sqlx::query("select id from user where stream_key = ?")
|
|
||||||
.bind(key)
|
|
||||||
.fetch_optional(&self.db)
|
|
||||||
.await?
|
|
||||||
.map(|r| r.try_get(0).unwrap()))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn upsert_user(&self, pubkey: &[u8; 32]) -> Result<u64> {
|
|
||||||
let res = sqlx::query("insert ignore into user(pubkey) values(?) returning id")
|
|
||||||
.bind(pubkey.as_slice())
|
|
||||||
.fetch_optional(&self.db)
|
|
||||||
.await?;
|
|
||||||
match res {
|
|
||||||
None => sqlx::query("select id from user where pubkey = ?")
|
|
||||||
.bind(pubkey.as_slice())
|
|
||||||
.fetch_one(&self.db)
|
|
||||||
.await?
|
|
||||||
.try_get(0)
|
|
||||||
.map_err(anyhow::Error::new),
|
|
||||||
Some(res) => res.try_get(0).map_err(anyhow::Error::new),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn create_stream(&self, user_stream: &UserStream) -> Result<u64> {
|
|
||||||
sqlx::query(
|
|
||||||
"insert into user_stream (user_id, state, starts) values (?, ?, ?) returning id",
|
|
||||||
)
|
|
||||||
.bind(&user_stream.user_id)
|
|
||||||
.bind(&user_stream.state)
|
|
||||||
.bind(&user_stream.starts)
|
|
||||||
.fetch_one(&self.db)
|
|
||||||
.await?
|
|
||||||
.try_get(0)
|
|
||||||
.map_err(anyhow::Error::new)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn update_stream(&self, user_stream: &UserStream) -> Result<()> {
|
|
||||||
sqlx::query(
|
|
||||||
"update user_stream set state = ?, starts = ?, ends = ?, title = ?, summary = ?, image = ?, thumb = ?, tags = ?, content_warning = ?, goal = ?, pinned = ?, fee = ?, event = ? where id = ?",
|
|
||||||
)
|
|
||||||
.bind(&user_stream.state)
|
|
||||||
.bind(&user_stream.starts)
|
|
||||||
.bind(&user_stream.ends)
|
|
||||||
.bind(&user_stream.title)
|
|
||||||
.bind(&user_stream.summary)
|
|
||||||
.bind(&user_stream.image)
|
|
||||||
.bind(&user_stream.thumb)
|
|
||||||
.bind(&user_stream.tags)
|
|
||||||
.bind(&user_stream.content_warning)
|
|
||||||
.bind(&user_stream.goal)
|
|
||||||
.bind(&user_stream.pinned)
|
|
||||||
.bind(&user_stream.fee)
|
|
||||||
.bind(&user_stream.event)
|
|
||||||
.bind(&user_stream.id)
|
|
||||||
.execute(&self.db)
|
|
||||||
.await
|
|
||||||
.map_err(anyhow::Error::new)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl Overseer for ZapStreamOverseer {
|
|
||||||
async fn start_stream(
|
|
||||||
&self,
|
|
||||||
connection: &ConnectionInfo,
|
|
||||||
stream_info: &IngressInfo,
|
|
||||||
) -> Result<PipelineConfig> {
|
|
||||||
let uid = self
|
|
||||||
.find_user_stream_key(&connection.key)
|
|
||||||
.await?
|
|
||||||
.ok_or_else(|| anyhow::anyhow!("User not found"))?;
|
|
||||||
|
|
||||||
let out_dir = temp_dir().join("zap-stream");
|
|
||||||
create_dir_all(&out_dir)?;
|
|
||||||
|
|
||||||
let variants = get_default_variants(&stream_info)?;
|
|
||||||
|
|
||||||
let mut egress = vec![];
|
|
||||||
egress.push(EgressType::HLS(EgressConfig {
|
|
||||||
name: "nip94-hls".to_string(),
|
|
||||||
out_dir: out_dir.to_string_lossy().to_string(),
|
|
||||||
variants: variants.iter().map(|v| v.id()).collect(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
// insert new stream record
|
|
||||||
let mut new_stream = UserStream {
|
|
||||||
id: 0,
|
|
||||||
user_id: uid,
|
|
||||||
starts: Utc::now(),
|
|
||||||
state: UserStreamState::Live,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let stream_id = self.create_stream(&new_stream).await?;
|
|
||||||
new_stream.id = stream_id;
|
|
||||||
|
|
||||||
let stream_event = new_stream.publish_stream_event(&self.client).await?;
|
|
||||||
new_stream.event = Some(stream_event.as_json());
|
|
||||||
self.update_stream(&new_stream).await?;
|
|
||||||
|
|
||||||
Ok(PipelineConfig {
|
|
||||||
id: stream_id,
|
|
||||||
variants,
|
|
||||||
egress,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn on_segment(
|
|
||||||
&self,
|
|
||||||
pipeline: &Uuid,
|
|
||||||
variant_id: &Uuid,
|
|
||||||
index: u64,
|
|
||||||
duration: f32,
|
|
||||||
path: &PathBuf,
|
|
||||||
) -> Result<()> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
2007
zap-stream-db/Cargo.lock
generated
Normal file
2007
zap-stream-db/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
14
zap-stream-db/Cargo.toml
Normal file
14
zap-stream-db/Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[package]
|
||||||
|
name = "zap-stream-db"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = []
|
||||||
|
test-pattern = []
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "^1.0.70"
|
||||||
|
chrono = { version = "0.4.38", features = ["serde"] }
|
||||||
|
sqlx = { version = "0.8.2", features = ["runtime-tokio", "migrate", "mysql", "chrono"] }
|
||||||
|
log = "0.4.22"
|
88
zap-stream-db/src/db.rs
Normal file
88
zap-stream-db/src/db.rs
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
use crate::UserStream;
|
||||||
|
use anyhow::Result;
|
||||||
|
use log::info;
|
||||||
|
use sqlx::{MySqlPool, Row};
|
||||||
|
|
||||||
|
pub struct ZapStreamDb {
|
||||||
|
db: MySqlPool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ZapStreamDb {
|
||||||
|
pub async fn new(db: &str) -> Result<Self> {
|
||||||
|
let db = MySqlPool::connect(db).await?;
|
||||||
|
Ok(ZapStreamDb { db })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn migrate(&self) -> Result<()> {
|
||||||
|
sqlx::migrate!().run(&self.db).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Find user by stream key, typical first lookup from ingress
|
||||||
|
pub async fn find_user_stream_key(&self, key: &str) -> Result<Option<u64>> {
|
||||||
|
#[cfg(feature = "test-pattern")]
|
||||||
|
if key == "test-pattern" {
|
||||||
|
// use the 00 pubkey for test sources
|
||||||
|
return Ok(Some(self.upsert_user(&[0; 32]).await?));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(sqlx::query("select id from user where stream_key = ?")
|
||||||
|
.bind(key)
|
||||||
|
.fetch_optional(&self.db)
|
||||||
|
.await?
|
||||||
|
.map(|r| r.try_get(0).unwrap()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn upsert_user(&self, pubkey: &[u8; 32]) -> Result<u64> {
|
||||||
|
let res = sqlx::query("insert ignore into user(pubkey) values(?) returning id")
|
||||||
|
.bind(pubkey.as_slice())
|
||||||
|
.fetch_optional(&self.db)
|
||||||
|
.await?;
|
||||||
|
match res {
|
||||||
|
None => sqlx::query("select id from user where pubkey = ?")
|
||||||
|
.bind(pubkey.as_slice())
|
||||||
|
.fetch_one(&self.db)
|
||||||
|
.await?
|
||||||
|
.try_get(0)
|
||||||
|
.map_err(anyhow::Error::new),
|
||||||
|
Some(res) => res.try_get(0).map_err(anyhow::Error::new),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn insert_stream(&self, user_stream: &UserStream) -> Result<u64> {
|
||||||
|
sqlx::query(
|
||||||
|
"insert into user_stream (user_id, state, starts) values (?, ?, ?) returning id",
|
||||||
|
)
|
||||||
|
.bind(&user_stream.user_id)
|
||||||
|
.bind(&user_stream.state)
|
||||||
|
.bind(&user_stream.starts)
|
||||||
|
.fetch_one(&self.db)
|
||||||
|
.await?
|
||||||
|
.try_get(0)
|
||||||
|
.map_err(anyhow::Error::new)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn update_stream(&self, user_stream: &UserStream) -> Result<()> {
|
||||||
|
sqlx::query(
|
||||||
|
"update user_stream set state = ?, starts = ?, ends = ?, title = ?, summary = ?, image = ?, thumb = ?, tags = ?, content_warning = ?, goal = ?, pinned = ?, fee = ?, event = ? where id = ?",
|
||||||
|
)
|
||||||
|
.bind(&user_stream.state)
|
||||||
|
.bind(&user_stream.starts)
|
||||||
|
.bind(&user_stream.ends)
|
||||||
|
.bind(&user_stream.title)
|
||||||
|
.bind(&user_stream.summary)
|
||||||
|
.bind(&user_stream.image)
|
||||||
|
.bind(&user_stream.thumb)
|
||||||
|
.bind(&user_stream.tags)
|
||||||
|
.bind(&user_stream.content_warning)
|
||||||
|
.bind(&user_stream.goal)
|
||||||
|
.bind(&user_stream.pinned)
|
||||||
|
.bind(&user_stream.fee)
|
||||||
|
.bind(&user_stream.event)
|
||||||
|
.bind(&user_stream.id)
|
||||||
|
.execute(&self.db)
|
||||||
|
.await
|
||||||
|
.map_err(anyhow::Error::new)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
7
zap-stream-db/src/lib.rs
Normal file
7
zap-stream-db/src/lib.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
mod db;
|
||||||
|
mod model;
|
||||||
|
|
||||||
|
pub use db::*;
|
||||||
|
pub use model::*;
|
||||||
|
|
||||||
|
pub use sqlx;
|
57
zap-stream-db/src/model.rs
Normal file
57
zap-stream-db/src/model.rs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use sqlx::{FromRow, Type};
|
||||||
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, FromRow)]
|
||||||
|
pub struct User {
|
||||||
|
pub id: u64,
|
||||||
|
pub pubkey: [u8; 32],
|
||||||
|
pub created: DateTime<Utc>,
|
||||||
|
pub balance: i64,
|
||||||
|
pub tos_accepted: DateTime<Utc>,
|
||||||
|
pub stream_key: String,
|
||||||
|
pub is_admin: bool,
|
||||||
|
pub is_blocked: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, Type)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum UserStreamState {
|
||||||
|
#[default]
|
||||||
|
Unknown = 0,
|
||||||
|
Planned = 1,
|
||||||
|
Live = 2,
|
||||||
|
Ended = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for UserStreamState {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
UserStreamState::Unknown => write!(f, "unknown"),
|
||||||
|
UserStreamState::Planned => write!(f, "planned"),
|
||||||
|
UserStreamState::Live => write!(f, "live"),
|
||||||
|
UserStreamState::Ended => write!(f, "ended"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default, FromRow)]
|
||||||
|
pub struct UserStream {
|
||||||
|
pub id: u64,
|
||||||
|
pub user_id: u64,
|
||||||
|
pub starts: DateTime<Utc>,
|
||||||
|
pub ends: Option<DateTime<Utc>>,
|
||||||
|
pub state: UserStreamState,
|
||||||
|
pub title: Option<String>,
|
||||||
|
pub summary: Option<String>,
|
||||||
|
pub image: Option<String>,
|
||||||
|
pub thumb: Option<String>,
|
||||||
|
pub tags: Option<String>,
|
||||||
|
pub content_warning: Option<String>,
|
||||||
|
pub goal: Option<String>,
|
||||||
|
pub pinned: Option<String>,
|
||||||
|
pub cost: u64,
|
||||||
|
pub duration: f32,
|
||||||
|
pub fee: Option<u32>,
|
||||||
|
pub event: Option<String>,
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user