Forced stream double connection problem fixed

This commit is contained in:
euzu
2025-07-17 09:15:41 +02:00
parent 74d3e2ec5f
commit a075452ffb
17 changed files with 323 additions and 167 deletions
Generated
+187 -92
View File
@@ -149,9 +149,9 @@ dependencies = [
[[package]]
name = "async-compression"
version = "0.4.25"
version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40f6024f3f856663b45fd0c9b6f2024034a702f453549449e0d84a305900dad4"
checksum = "ddb939d66e4ae03cee6091612804ba446b12878410cfa17f785f4dd67d4014e8"
dependencies = [
"brotli",
"flate2",
@@ -238,7 +238,7 @@ checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -371,9 +371,9 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.18.1"
version = "3.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee"
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
[[package]]
name = "bytes"
@@ -389,9 +389,9 @@ checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6"
[[package]]
name = "cc"
version = "1.2.27"
version = "1.2.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc"
checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362"
dependencies = [
"jobserver",
"libc",
@@ -426,9 +426,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.40"
version = "4.5.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f"
checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9"
dependencies = [
"clap_builder",
"clap_derive",
@@ -436,9 +436,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.40"
version = "4.5.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e"
checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d"
dependencies = [
"anstream",
"anstyle",
@@ -448,14 +448,14 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.5.40"
version = "4.5.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce"
checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -522,9 +522,9 @@ dependencies = [
[[package]]
name = "crc32fast"
version = "1.4.2"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
dependencies = [
"cfg-if",
]
@@ -586,7 +586,7 @@ dependencies = [
"openssl-probe",
"openssl-sys",
"schannel",
"socket2",
"socket2 0.5.10",
"windows-sys 0.59.0",
]
@@ -627,7 +627,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -638,7 +638,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
dependencies = [
"darling_core",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -682,7 +682,7 @@ dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -692,7 +692,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
dependencies = [
"derive_builder_core",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -725,7 +725,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -769,7 +769,7 @@ checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -803,12 +803,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "errno"
version = "0.3.12"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
dependencies = [
"libc",
"windows-sys 0.59.0",
"windows-sys 0.60.2",
]
[[package]]
@@ -1004,7 +1004,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -1077,7 +1077,7 @@ checksum = "913dce4c5f06c2ea40fc178c06f777ac89fc6b1383e90c254fafb1abe4ba3c82"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
"uuid",
]
@@ -1540,7 +1540,7 @@ dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -1568,9 +1568,9 @@ dependencies = [
[[package]]
name = "h2"
version = "0.4.10"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5"
checksum = "17da50a276f1e01e0ba6c029e47b7100754904ee8a278f886546e98575380785"
dependencies = [
"atomic-waker",
"bytes",
@@ -1728,9 +1728,9 @@ dependencies = [
[[package]]
name = "hyper-util"
version = "0.1.14"
version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb"
checksum = "7f66d5bd4c6f02bf0542fad85d626775bab9258cf795a4256dcaf3161114d1df"
dependencies = [
"base64 0.22.1",
"bytes",
@@ -1744,7 +1744,7 @@ dependencies = [
"libc",
"percent-encoding",
"pin-project-lite",
"socket2",
"socket2 0.5.10",
"system-configuration",
"tokio",
"tower-service",
@@ -1915,14 +1915,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "699c1b6d335e63d0ba5c1e1c7f647371ce989c3bcbe1f7ed2b85fa56e3bd1a21"
dependencies = [
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
name = "indexmap"
version = "2.9.0"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
dependencies = [
"equivalent",
"hashbrown 0.15.4",
@@ -1957,6 +1957,17 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "io-uring"
version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013"
dependencies = [
"bitflags 2.9.1",
"cfg-if",
"libc",
]
[[package]]
name = "ipnet"
version = "2.11.0"
@@ -2044,7 +2055,7 @@ checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -2126,9 +2137,9 @@ dependencies = [
[[package]]
name = "libredox"
version = "0.1.3"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638"
dependencies = [
"bitflags 2.9.1",
"libc",
@@ -2292,12 +2303,11 @@ checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21"
[[package]]
name = "notify"
version = "8.0.0"
version = "8.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fee8403b3d66ac7b26aee6e40a897d85dc5ce26f44da36b8b73e987cc52e943"
checksum = "3163f59cd3fa0e9ef8c32f242966a7b9994fd7378366099593e0e73077cd8c97"
dependencies = [
"bitflags 2.9.1",
"filetime",
"fsevent-sys",
"inotify",
"kqueue",
@@ -2306,7 +2316,7 @@ dependencies = [
"mio",
"notify-types",
"walkdir",
"windows-sys 0.59.0",
"windows-sys 0.60.2",
]
[[package]]
@@ -2412,7 +2422,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -2423,9 +2433,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
[[package]]
name = "openssl-src"
version = "300.5.0+3.5.0"
version = "300.5.1+3.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8ce546f549326b0e6052b649198487d91320875da901e7bd11a06d1ee3f9c2f"
checksum = "735230c832b28c000e3bc117119e6466a663ec73506bc0a9907ea4187508e42a"
dependencies = [
"cc",
]
@@ -2531,7 +2541,7 @@ dependencies = [
"pest_meta",
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -2561,7 +2571,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -2650,12 +2660,12 @@ dependencies = [
[[package]]
name = "prettyplease"
version = "0.2.34"
version = "0.2.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6837b9e10d61f45f987d50808f83d1ee3d206c66acf650c3e4ae2e1f6ddedf55"
checksum = "061c1221631e079b26479d25bbf2275bfe5917ae8419cd7e34f13bfc2aa7539a"
dependencies = [
"proc-macro2",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -2738,7 +2748,7 @@ dependencies = [
"itertools",
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -2778,7 +2788,7 @@ dependencies = [
"quinn-udp",
"rustc-hash",
"rustls",
"socket2",
"socket2 0.5.10",
"thiserror 2.0.12",
"tokio",
"tracing",
@@ -2815,7 +2825,7 @@ dependencies = [
"cfg_aliases",
"libc",
"once_cell",
"socket2",
"socket2 0.5.10",
"tracing",
"windows-sys 0.59.0",
]
@@ -2942,9 +2952,9 @@ dependencies = [
[[package]]
name = "reqwest"
version = "0.12.20"
version = "0.12.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813"
checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531"
dependencies = [
"base64 0.22.1",
"bytes",
@@ -3082,22 +3092,22 @@ dependencies = [
[[package]]
name = "rustix"
version = "1.0.7"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8"
dependencies = [
"bitflags 2.9.1",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.59.0",
"windows-sys 0.60.2",
]
[[package]]
name = "rustls"
version = "0.23.28"
version = "0.23.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643"
checksum = "2491382039b29b9b11ff08b76ff6c97cf287671dbb74f0be44bda389fffe9bd1"
dependencies = [
"once_cell",
"ring",
@@ -3119,9 +3129,9 @@ dependencies = [
[[package]]
name = "rustls-webpki"
version = "0.103.3"
version = "0.103.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435"
checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc"
dependencies = [
"ring",
"rustls-pki-types",
@@ -3235,7 +3245,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -3369,6 +3379,16 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "socket2"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807"
dependencies = [
"libc",
"windows-sys 0.59.0",
]
[[package]]
name = "spinning_top"
version = "0.3.0"
@@ -3408,9 +3428,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.103"
version = "2.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8"
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
dependencies = [
"proc-macro2",
"quote",
@@ -3434,7 +3454,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -3497,7 +3517,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -3508,7 +3528,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -3571,17 +3591,19 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.45.1"
version = "1.46.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779"
checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17"
dependencies = [
"backtrace",
"bytes",
"io-uring",
"libc",
"mio",
"parking_lot",
"pin-project-lite",
"socket2",
"slab",
"socket2 0.5.10",
"tokio-macros",
"windows-sys 0.52.0",
]
@@ -3594,7 +3616,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -3753,7 +3775,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -3828,7 +3850,7 @@ dependencies = [
"serde_json",
"serde_yaml",
"shared",
"socket2",
"socket2 0.6.0",
"strsim",
"tempfile",
"tokio",
@@ -4036,7 +4058,7 @@ dependencies = [
"log",
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
"wasm-bindgen-shared",
]
@@ -4071,7 +4093,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -4106,7 +4128,7 @@ checksum = "17d5042cc5fa009658f9a7333ef24291b1291a25b6382dd68862a7f3b969f69b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -4155,9 +4177,9 @@ dependencies = [
[[package]]
name = "webpki-roots"
version = "1.0.0"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb"
checksum = "8782dd5a41a24eed3a4f40b606249b3e236ca61adf1f25ea4d45c73de122b502"
dependencies = [
"rustls-pki-types",
]
@@ -4214,7 +4236,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -4225,7 +4247,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -4236,9 +4258,9 @@ checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
[[package]]
name = "windows-registry"
version = "0.5.2"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3bab093bdd303a1240bb99b8aba8ea8a69ee19d34c9e2ef9594e708a4878820"
checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e"
dependencies = [
"windows-link",
"windows-result",
@@ -4290,6 +4312,15 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-sys"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
"windows-targets 0.53.2",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
@@ -4314,13 +4345,29 @@ dependencies = [
"windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.6",
"windows_i686_gnullvm",
"windows_i686_gnullvm 0.52.6",
"windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc 0.52.6",
]
[[package]]
name = "windows-targets"
version = "0.53.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef"
dependencies = [
"windows_aarch64_gnullvm 0.53.0",
"windows_aarch64_msvc 0.53.0",
"windows_i686_gnu 0.53.0",
"windows_i686_gnullvm 0.53.0",
"windows_i686_msvc 0.53.0",
"windows_x86_64_gnu 0.53.0",
"windows_x86_64_gnullvm 0.53.0",
"windows_x86_64_msvc 0.53.0",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
@@ -4333,6 +4380,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
@@ -4345,6 +4398,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_aarch64_msvc"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
@@ -4357,12 +4416,24 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnu"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_gnullvm"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
@@ -4375,6 +4446,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_i686_msvc"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
@@ -4387,6 +4464,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnu"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
@@ -4399,6 +4482,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
@@ -4411,6 +4500,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "windows_x86_64_msvc"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
[[package]]
name = "winnow"
version = "0.5.40"
@@ -4507,7 +4602,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -4537,7 +4632,7 @@ checksum = "42bfd190a07ca8cfde7cd4c52b3ac463803dc07323db8c34daa697e86365978c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -4560,7 +4655,7 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
"synstructure",
]
@@ -4581,7 +4676,7 @@ checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@@ -4601,7 +4696,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
"synstructure",
]
@@ -4641,7 +4736,7 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
+1 -1
View File
@@ -57,7 +57,7 @@ arc-swap = "1"
dashmap = "6"
hyper = "1"
hyper-util = "0"
socket2 = "0"
socket2 = { version = "0", features = ["all"] }
#[cfg(target_os = "macos")]
libc = "0"
#[cfg(target_os = "windows")]
+16 -21
View File
@@ -296,14 +296,14 @@ async fn resolve_streaming_strategy(app_state: &AppState, stream_url: &str, inpu
};
let stream_response_params = match &*provider_connection_guard {
ProviderAllocation::Exhausted => {
debug!("Input {} is exhausted. No connections allowed.", input.name);
debug!("Input {} is exhausted. No connections allowed.", input.name);
let stream = create_provider_connections_exhausted_stream(&app_state.app_config, &[]);
ProviderStreamState::Custom(stream)
}
ProviderAllocation::Available(ref provider)
| ProviderAllocation::GracePeriod(ref provider) => {
// force_stream_provider means we keep the url and the provider.
// If force_stream_provider or the input is the same as the config we dont need to get new url
// If force_stream_provider or the input is the same as the config we don't need to get new url
let (provider, url) = if force_provider.is_some() || provider.id == input.id {
(input.name.to_string(), stream_url.to_string())
} else {
@@ -348,7 +348,7 @@ async fn create_stream_response_details(app_state: &AppState,
.and_then(|r| r.stream.as_ref()).map_or_else(default_grace_period_millis, |s| s.grace_period_millis);
let grace_period_millis = get_grace_period_millis(connection_permission, &streaming_strategy.provider_stream_state, config_grace_period_millis);
match streaming_strategy.provider_stream_state {
// custom stream means we display our own stream like connection exhausted, channel unavailable...
// custom stream means we display our own stream like connection exhausted, channel-unavailable...
ProviderStreamState::Custom(provider_stream) => {
let (stream, stream_info) = provider_stream;
StreamDetails {
@@ -377,7 +377,7 @@ async fn create_stream_response_details(app_state: &AppState,
((None, None), None)
};
// if we have no stream we should release the provider
// if we have no stream, we should release the provider
if stream.is_none() {
if let Some(guard) = streaming_strategy.provider_connection_guard.take() {
drop(guard);
@@ -433,7 +433,7 @@ where
|| extract_extension_from_url(url).map_or_else(String::new, std::string::ToString::to_string),
std::string::ToString::to_string);
// if there is a action_path (like for timeshift duration/start) it will be added in front of the stream_id
// if there is an action_path (like for timeshift duration/start), it will be added in front of the stream_id
if self.action_path.is_empty() {
format!("{provider_id}{extension}")
} else {
@@ -468,7 +468,7 @@ where
if redirect_request {
// handle redirect for series but why ?
// handle redirect for series but why?
if params.cluster == XtreamCluster::Series {
let ext = params.stream_ext.unwrap_or_default();
let url = params.input.url.as_str();
@@ -525,13 +525,13 @@ fn prepare_body_stream(app_state: &AppState, item_type: PlaylistItemType, stream
}
/// # Panics
pub async fn force_provider_stream_response(app_state: &AppState,
pub async fn force_provider_stream_response(addr: &str,
app_state: &AppState,
user_session: &UserSession,
item_type: PlaylistItemType,
req_headers: &HeaderMap,
input: &ConfigInput,
user: &ProxyUserCredentials,
addr: &str) -> impl IntoResponse + Send {
user: &ProxyUserCredentials) -> impl IntoResponse + Send {
let stream_options = get_stream_options(app_state);
let share_stream = false;
let connection_permission = UserConnectionPermission::Allowed;
@@ -541,6 +541,7 @@ pub async fn force_provider_stream_response(app_state: &AppState,
if stream_details.has_stream() {
let provider_response = stream_details.stream_info.as_ref().map(|(h, sc, url)| (h.clone(), *sc, url.clone()));
app_state.active_users.update_session_addr(&user.username, &user_session.token, addr).await;
let stream = ActiveClientStream::new(stream_details, app_state, user, connection_permission, addr).await;
let (status_code, header_map) = get_stream_response_with_headers(provider_response.map(|(h, s, _)| (h, s)));
@@ -566,17 +567,11 @@ pub async fn force_provider_stream_response(app_state: &AppState,
/// # Panics
#[allow(clippy::too_many_arguments)]
pub async fn stream_response(app_state: &AppState,
session_token: &str,
virtual_id: u32,
item_type: PlaylistItemType,
stream_url: &str,
req_headers: &HeaderMap,
input: &ConfigInput,
target: &ConfigTarget,
user: &ProxyUserCredentials,
connection_permission: UserConnectionPermission,
addr: &str) -> impl IntoResponse + Send {
pub async fn stream_response(addr: &str,
app_state: &AppState, session_token: &str, virtual_id: u32,
item_type: PlaylistItemType, stream_url: &str, req_headers: &HeaderMap,
input: &ConfigInput, target: &ConfigTarget, user: &ProxyUserCredentials,
connection_permission: UserConnectionPermission) -> impl IntoResponse + Send {
if log_enabled!(log::Level::Trace) { trace!("Try to open stream {}", sanitize_sensitive_info(stream_url)); }
if connection_permission == UserConnectionPermission::Exhausted {
@@ -632,7 +627,7 @@ pub async fn stream_response(app_state: &AppState,
if let Some(provider) = provider_name {
if matches!(item_type, PlaylistItemType::LiveHls | PlaylistItemType::LiveDash | PlaylistItemType::Video | PlaylistItemType::Series | PlaylistItemType::Catchup) {
let _ = app_state.active_users.create_user_session(user, session_token, virtual_id, &provider, &session_url, connection_permission).await;
let _ = app_state.active_users.create_user_session(user, session_token, virtual_id, &provider, &session_url, addr, connection_permission).await;
}
}
+3 -2
View File
@@ -10,7 +10,7 @@ use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::sync::{Arc};
use tokio_util::sync::CancellationToken;
use shared::model::ConfigPaths;
use shared::model::{ConfigPaths};
enum ConfigFile {
Config,
@@ -73,7 +73,8 @@ impl ConfigFile {
async fn load_sources(app_state: &Arc<AppState>) -> Result<(), TuliproxError> {
let paths = app_state.app_config.paths.load();
let sources_file = paths.sources_file_path.as_str();
let sources_dto = read_sources_file(sources_file, true, true)?;
let config = &app_state.app_config.config.load();
let sources_dto = read_sources_file(sources_file, true, true, config.get_hdhr_device_overview().as_ref())?;
let sources: SourcesConfig = SourcesConfig::try_from(sources_dto)?;
info!("Loaded sources file {sources_file}");
update_app_state_sources(app_state, sources).await
+5 -5
View File
@@ -35,7 +35,7 @@ fn hls_response(hls_content: String) -> impl IntoResponse + Send {
#[allow(clippy::too_many_arguments)]
pub(in crate::api) async fn handle_hls_stream_request(
fingerprint: &str,
fingerprint: &str, addr: &str,
app_state: &Arc<AppState>,
user: &ProxyUserCredentials,
user_session: Option<&UserSession>,
@@ -61,7 +61,7 @@ pub(in crate::api) async fn handle_hls_stream_request(
Some(provider_cfg) => {
let stream_url = get_stream_alternative_url(&url, input, &provider_cfg);
let user_session_token = format!("{fingerprint}{virtual_id}");
let session_token= app_state.active_users.create_user_session(user, &user_session_token, virtual_id, &provider_cfg.name, &stream_url, connection_permission).await;
let session_token= app_state.active_users.create_user_session(user, &user_session_token, virtual_id, &provider_cfg.name, &stream_url, addr, connection_permission).await;
(stream_url, session_token)
},
None => (url, None),
@@ -128,7 +128,7 @@ async fn hls_api_stream(
if session.virtual_id == virtual_id {
if is_seek_request(XtreamCluster::Live, &req_headers).await {
// partial request means we are in reverse proxy mode, seek happened
return force_provider_stream_response(&app_state, session, PlaylistItemType::LiveHls, &req_headers, &input, &user, &addr).await.into_response()
return force_provider_stream_response(&addr, &app_state, session, PlaylistItemType::LiveHls, &req_headers, &input, &user).await.into_response()
}
} else {
return axum::http::StatusCode::BAD_REQUEST.into_response();
@@ -140,10 +140,10 @@ async fn hls_api_stream(
}
if is_hls_url(&session.stream_url) {
return handle_hls_stream_request(&fingerprint, &app_state, &user, Some(session), &session.stream_url, virtual_id, &input, connection_permission).await.into_response();
return handle_hls_stream_request(&fingerprint, &addr, &app_state, &user, Some(session), &session.stream_url, virtual_id, &input, connection_permission).await.into_response();
}
force_provider_stream_response(&app_state, session, PlaylistItemType::LiveHls, &req_headers, &input, &user, &addr).await.into_response()
force_provider_stream_response(&addr, &app_state, session, PlaylistItemType::LiveHls, &req_headers, &input, &user).await.into_response()
} else {
axum::http::StatusCode::BAD_REQUEST.into_response()
}
+3 -3
View File
@@ -98,7 +98,7 @@ async fn m3u_api_stream(
}
if session.virtual_id == virtual_id && is_seek_request(cluster, req_headers).await {
// partial request means we are in reverse proxy mode, seek happened
return force_provider_stream_response(app_state, session, pli.item_type, req_headers, &input, &user, addr).await.into_response();
return force_provider_stream_response(addr, app_state, session, pli.item_type, req_headers, &input, &user).await.into_response();
}
session.stream_url.as_str()
} else {
@@ -135,10 +135,10 @@ async fn m3u_api_stream(
let is_hls_request = pli.item_type == PlaylistItemType::LiveHls || pli.item_type == PlaylistItemType::LiveDash || extension == HLS_EXT;
// Reverse proxy mode
if is_hls_request {
return handle_hls_stream_request(fingerprint, app_state, &user, user_session.as_ref(), &pli.url, pli.virtual_id, &input, connection_permission).await.into_response();
return handle_hls_stream_request(fingerprint, addr, app_state, &user, user_session.as_ref(), &pli.url, pli.virtual_id, &input, connection_permission).await.into_response();
}
stream_response(app_state, &session_key, pli.virtual_id, pli.item_type, session_url, req_headers, &input, &target, &user, connection_permission, addr).await.into_response()
stream_response(addr, app_state, &session_key, pli.virtual_id, pli.item_type, session_url, req_headers, &input, &target, &user, connection_permission).await.into_response()
}
async fn m3u_api_resource(
+5 -5
View File
@@ -214,7 +214,7 @@ async fn xtream_player_api_stream(
if session.virtual_id == virtual_id && is_seek_request(cluster, req_headers).await {
// partial request means we are in reverse proxy mode, seek happened
return force_provider_stream_response(app_state, session, item_type, req_headers, &input, &user, addr).await.into_response();
return force_provider_stream_response(addr, app_state, session, item_type, req_headers, &input, &user).await.into_response();
}
session.stream_url.as_str()
@@ -260,10 +260,10 @@ async fn xtream_player_api_stream(
let is_hls_request = item_type == PlaylistItemType::LiveHls || item_type == PlaylistItemType::LiveDash || extension == HLS_EXT;
// Reverse proxy mode
if is_hls_request {
return handle_hls_stream_request(fingerprint, app_state, &user, user_session.as_ref(), &stream_url, pli.virtual_id, &input, connection_permission).await.into_response();
return handle_hls_stream_request(fingerprint, addr, app_state, &user, user_session.as_ref(), &stream_url, pli.virtual_id, &input, connection_permission).await.into_response();
}
stream_response(app_state, session_key.as_str(), pli.virtual_id, item_type, &stream_url, req_headers, &input, &target, &user, connection_permission, addr).await.into_response()
stream_response(addr, app_state, session_key.as_str(), pli.virtual_id, item_type, &stream_url, req_headers, &input, &target, &user, connection_permission).await.into_response()
}
// Used by webui
@@ -312,7 +312,7 @@ async fn xtream_player_api_stream_with_token(
// Reverse proxy mode
if is_hls_request {
return handle_hls_stream_request(fingerprint, app_state, &user, None, &pli.url, pli.virtual_id, &input, UserConnectionPermission::Allowed).await.into_response();
return handle_hls_stream_request(fingerprint, addr, app_state, &user, None, &pli.url, pli.virtual_id, &input, UserConnectionPermission::Allowed).await.into_response();
}
let extension = stream_ext.unwrap_or_else(
@@ -330,7 +330,7 @@ async fn xtream_player_api_stream_with_token(
stream_req.context));
trace_if_enabled!("Streaming stream request from {}", sanitize_sensitive_info(&stream_url));
stream_response(app_state, session_key.as_str(), pli.virtual_id, pli.item_type, &stream_url, req_headers, &input, &target, &user, UserConnectionPermission::Allowed, addr).await.into_response()
stream_response(addr, app_state, session_key.as_str(), pli.virtual_id, pli.item_type, &stream_url, req_headers, &input, &target, &user, UserConnectionPermission::Allowed).await.into_response()
} else {
axum::http::StatusCode::BAD_REQUEST.into_response()
}
+32 -6
View File
@@ -76,7 +76,6 @@ impl ConnectionGuardUserManager {
fn is_log_user_enabled(&self)-> bool {
self.log_active_user
}
}
pub struct UserConnectionGuard {
@@ -100,6 +99,7 @@ pub struct UserSession {
pub virtual_id: u32,
pub provider: String,
pub stream_url: String,
pub addr: String,
pub ts: u64,
pub permission: UserConnectionPermission,
}
@@ -142,13 +142,14 @@ pub struct ActiveUserManager {
user: Arc<RwLock<HashMap<String, UserConnectionData>>>,
user_by_addr: Arc<RwLock<HashMap<String, String>>>,
gc_ts: Option<AtomicU64>,
close_signal_tx: tokio::sync::broadcast::Sender<String>,
}
impl ActiveUserManager {
pub fn new(config: &Config) -> Self {
let log_active_user = config.log.as_ref().is_some_and(|l| l.log_active_user);
let (grace_period_millis, grace_period_timeout_secs) = get_grace_options(config);
let (close_signal_tx, _) = tokio::sync::broadcast::channel(10);
Self {
grace_period_millis : AtomicU64::new(grace_period_millis),
grace_period_timeout_secs: AtomicU64::new(grace_period_timeout_secs),
@@ -156,6 +157,7 @@ impl ActiveUserManager {
user: Arc::new(RwLock::new(HashMap::new())),
user_by_addr: Arc::new(RwLock::new(HashMap::new())),
gc_ts: Some(AtomicU64::new(current_time_secs())),
close_signal_tx
}
}
@@ -271,19 +273,23 @@ impl ActiveUserManager {
sessions.iter().find(|&session| session.token.eq(token))
}
fn new_user_session(session_token: &str, virtual_id: u32, provider: &str, stream_url: &str, connection_permission: UserConnectionPermission) -> UserSession {
fn new_user_session(session_token: &str, virtual_id: u32, provider: &str, stream_url: &str, addr: &str,
connection_permission: UserConnectionPermission) -> UserSession {
UserSession {
token: session_token.to_string(),
virtual_id,
provider: provider.to_string(),
stream_url: stream_url.to_string(),
addr: addr.to_string(),
ts: current_time_secs(),
permission: connection_permission,
}
}
#[allow(clippy::too_many_arguments)]
pub async fn create_user_session(&self, user: &ProxyUserCredentials, session_token: &str, virtual_id: u32,
provider: &str, stream_url: &str, connection_permission: UserConnectionPermission) -> Option<String> {
provider: &str, stream_url: &str, addr: &str,
connection_permission: UserConnectionPermission) -> Option<String> {
self.gc().await;
let mut lock = self.user.write().await;
if let Some(connection_data) = lock.get_mut(&user.username) {
@@ -305,14 +311,14 @@ impl ActiveUserManager {
// no session creates new one
debug!("Creating session for user {} with token {session_token} {}", user.username, sanitize_sensitive_info(stream_url));
let session = Self::new_user_session(session_token, virtual_id, provider, stream_url, connection_permission);
let session = Self::new_user_session(session_token, virtual_id, provider, stream_url, addr, connection_permission);
let token = session.token.clone();
connection_data.add_session(session);
Some(token)
} else {
debug!("Creating session for user {} with token {session_token} {}", user.username, sanitize_sensitive_info(stream_url));
let mut connection_data = UserConnectionData::new(0, user.max_connections);
let session = Self::new_user_session(session_token, virtual_id, provider, stream_url, connection_permission);
let session = Self::new_user_session(session_token, virtual_id, provider, stream_url, addr, connection_permission);
let token = session.token.clone();
connection_data.add_session(session);
lock.insert(user.username.to_string(), connection_data);
@@ -320,6 +326,26 @@ impl ActiveUserManager {
}
}
pub async fn update_session_addr(&self, username: &str, token: &str, addr: &str) {
let mut lock = self.user.write().await;
if let Some(connection_data) = lock.get_mut(username) {
for session in &mut connection_data.sessions {
if session.token.eq(token) {
self.drop_connection(&session.addr);
session.addr = addr.to_string();
}
}
}
}
fn drop_connection(&self, addr: &str) {
let _ = self.close_signal_tx.send(addr.to_string());
}
pub fn get_close_connection_channel(&self) -> tokio::sync::broadcast::Receiver<String> {
self.close_signal_tx.subscribe()
}
pub async fn get_user_session(&self, username: &str, token: &str) -> Option<UserSession> {
self.update_user_session(username, token).await
}
+1 -1
View File
@@ -29,7 +29,7 @@ pub fn get_stream_response_with_headers(custom: Option<(Vec<(String, String)>, S
let default_headers = vec![
("content-type", "application/octet-stream"),
("connection", "keep-alive"),
//("connection", "keep-alive"),
];
for (key, value) in default_headers {
+13 -9
View File
@@ -6,7 +6,7 @@ use hyper::body::Incoming;
use hyper_util::rt::{TokioExecutor, TokioIo};
use hyper_util::server::conn::auto::Builder;
use hyper_util::service::TowerToHyperService;
use log::{error, info, trace};
use log::{debug, error, trace};
use socket2::{SockRef, TcpKeepalive};
use std::convert::Infallible;
use std::fmt::Debug;
@@ -43,7 +43,6 @@ pub async fn serve(listener: tokio::net::TcpListener,
cancel_token: Option<CancellationToken>,
user_manager: Arc<ActiveUserManager>) {
let (signal_tx, _signal_rx) = watch::channel(());
let (_close_tx, close_rx) = watch::channel(());
let mut make_service = router.into_make_service_with_connect_info::<SocketAddr>();
match cancel_token {
@@ -55,7 +54,7 @@ pub async fn serve(listener: tokio::net::TcpListener,
}
accept_result = listener.accept() => {
let Ok((socket, remote_addr)) = accept_result else { continue };
handle_connection(&mut make_service, &signal_tx, &close_rx, socket, remote_addr, Arc::clone(&user_manager)).await;
handle_connection(&mut make_service, &signal_tx, socket, remote_addr, Arc::clone(&user_manager)).await;
}
}
}
@@ -63,7 +62,7 @@ pub async fn serve(listener: tokio::net::TcpListener,
None => {
loop {
let Ok((socket, remote_addr)) = listener.accept().await else { continue };
handle_connection(&mut make_service, &signal_tx, &close_rx, socket, remote_addr, Arc::clone(&user_manager)).await;
handle_connection(&mut make_service, &signal_tx, socket, remote_addr, Arc::clone(&user_manager)).await;
}
}
}
@@ -73,7 +72,6 @@ pub async fn serve(listener: tokio::net::TcpListener,
async fn handle_connection<M, S>(
make_service: &mut M,
signal_tx: &watch::Sender<()>,
close_rx: &watch::Receiver<()>,
socket: tokio::net::TcpStream,
remote_addr: SocketAddr,
user_manager: Arc<ActiveUserManager>,
@@ -127,7 +125,7 @@ where
let hyper_service = TowerToHyperService::new(tower_service);
let signal_tx = signal_tx.clone();
let close_rx = close_rx.clone();
let addr_str = remote_addr.to_string();
tokio::spawn(async move {
#[allow(unused_mut)]
@@ -136,8 +134,9 @@ where
let mut signal_closed = pin!(signal_tx.closed().fuse());
let user_manager_clone = Arc::clone(&user_manager);
let mut addr_close_rx = user_manager_clone.get_close_connection_channel();
let connection_closed = async move || {
info!("Connection closed: {remote_addr}");
debug!("Connection closed: {remote_addr}");
let addr = remote_addr.to_string();
user_manager_clone.remove_connection(&addr).await;
};
@@ -156,9 +155,14 @@ where
trace!("signal received in task, starting graceful shutdown");
conn.as_mut().graceful_shutdown();
}
Ok(msg) = addr_close_rx.recv() => {
if msg == addr_str {
debug!("Forced client disconnect {msg}");
conn.as_mut().graceful_shutdown();
break;
}
}
}
}
drop(close_rx);
});
}
+9 -1
View File
@@ -2,7 +2,7 @@ use std::path::{Path, PathBuf};
use log::{error, info};
use path_clean::PathClean;
use shared::error::{TuliproxError};
use shared::model::ConfigDto;
use shared::model::{ConfigDto, HdHomeRunDeviceOverview};
use shared::utils::set_sanitize_sensitive_info;
use crate::model::{macros, ConfigApi, ReverseProxyConfig, ScheduleConfig};
use crate::model::{HdHomeRunConfig, IpCheckConfig, LogConfig, MessagingConfig, ProxyConfig, VideoConfig, WebUiConfig};
@@ -101,6 +101,14 @@ impl Config {
create_directories(self, &temp_path);
let _ = tempfile::env::override_temp_dir(&temp_path);
}
pub fn get_hdhr_device_overview(&self) -> Option<HdHomeRunDeviceOverview> {
self.hdhomerun.as_ref().map(|hdhr|
HdHomeRunDeviceOverview {
enabled: hdhr.enabled,
devices: hdhr.devices.iter().map(|d| d.name.to_string()).collect::<Vec<String>>(),
})
}
}
macros::from_impl!(Config);
+1 -1
View File
@@ -56,4 +56,4 @@ impl From<&HdHomeRunConfigDto> for HdHomeRunConfig {
devices: dto.devices.iter().map(Into::into).collect(),
}
}
}
}
+6 -6
View File
@@ -9,7 +9,7 @@ use chrono::Local;
use log::{error, info, warn};
use serde::Serialize;
use shared::error::{create_tuliprox_error, info_err, to_io_error, TuliproxError, TuliproxErrorKind};
use shared::model::{ApiProxyConfigDto, AppConfigDto, ConfigDto, ConfigPaths, SourcesConfigDto};
use shared::model::{ApiProxyConfigDto, AppConfigDto, ConfigDto, ConfigPaths, HdHomeRunDeviceOverview, SourcesConfigDto};
use shared::utils::{CONSTANTS};
use std::env;
use std::fs::File;
@@ -61,14 +61,14 @@ pub fn read_api_proxy_config(config: &AppConfig, resolve_env: bool) -> Result<Op
}
}
pub fn read_sources_file(sources_file: &str, resolve_env: bool, include_computed: bool) -> Result<SourcesConfigDto, TuliproxError> {
pub fn read_sources_file(sources_file: &str, resolve_env: bool, include_computed: bool, hdhr_config: Option<&HdHomeRunDeviceOverview>) -> Result<SourcesConfigDto, TuliproxError> {
match open_file(&std::path::PathBuf::from(sources_file)) {
Ok(file) => {
let maybe_sources: Result<SourcesConfigDto, _> = serde_yaml::from_reader(config_file_reader(file, resolve_env));
match maybe_sources {
Ok(mut sources) => {
if resolve_env {
if let Err(err) = sources.prepare(include_computed) {
if let Err(err) = sources.prepare(include_computed, hdhr_config) {
return Err(info_err!(format!("Can't read the sources-config file: {sources_file}: {err}")));
}
}
@@ -106,8 +106,8 @@ pub fn read_app_config_dto(paths: &ConfigPaths,
let sources_file = paths.sources_file_path.as_str();
let api_proxy_file = paths.api_proxy_file_path.as_str();
let sources = read_sources_file(sources_file, resolve_env, include_computed)?;
let config = read_config_file(config_file, resolve_env)?;
let sources = read_sources_file(sources_file, resolve_env, include_computed, config.get_hdhr_device_overview().as_ref())?;
let mappings = if let Some(mappings_file) = paths.mapping_file_path.as_ref() {
read_mappings_file(mappings_file, resolve_env).unwrap_or(None)
} else {
@@ -133,9 +133,9 @@ pub fn read_initial_app_config(paths: &mut ConfigPaths,
let config_file = paths.config_file_path.as_str();
let sources_file = paths.sources_file_path.as_str();
let sources_dto = read_sources_file(sources_file, resolve_env, include_computed)?;
let sources: SourcesConfig = SourcesConfig::try_from(sources_dto)?;
let config_dto = read_config_file(config_file, resolve_env)?;
let sources_dto = read_sources_file(sources_file, resolve_env, include_computed, config_dto.get_hdhr_device_overview().as_ref())?;
let sources: SourcesConfig = SourcesConfig::try_from(sources_dto)?;
let mut config: Config = Config::from(config_dto);
config.prepare(config_path)?;
config.update_runtime();
+18 -5
View File
@@ -1,6 +1,8 @@
use crate::error::{TuliproxError, TuliproxErrorKind};
use crate::model::{WebUiConfigDto, MessagingConfigDto, IpCheckConfigDto, HdHomeRunConfigDto, VideoConfigDto, ScheduleConfigDto, LogConfigDto, ReverseProxyConfigDto, ProxyConfigDto, ConfigApiDto};
use crate::utils::{default_connect_timeout_secs};
use crate::model::{ConfigApiDto, HdHomeRunConfigDto, IpCheckConfigDto, LogConfigDto,
MessagingConfigDto, ProxyConfigDto, ReverseProxyConfigDto, ScheduleConfigDto,
VideoConfigDto, WebUiConfigDto};
use crate::utils::default_connect_timeout_secs;
pub const DEFAULT_USER_AGENT: &str = "VLC/3.0.16 LibVLC/3.0.16";
@@ -50,8 +52,12 @@ pub struct ConfigDto {
pub ipcheck: Option<IpCheckConfigDto>,
}
impl ConfigDto {
pub struct HdHomeRunDeviceOverview {
pub enabled: bool,
pub devices: Vec<String>,
}
impl ConfigDto {
pub fn prepare(&mut self) -> Result<(), TuliproxError> {
if let Some(mins) = self.sleep_timer_mins {
if mins == 0 {
@@ -85,8 +91,7 @@ impl ConfigDto {
}
fn prepare_hdhomerun(&mut self) -> Result<(), TuliproxError> {
if let Some(old_hdhomerun) = &self.hdhomerun {
let mut hdhomerun = (*old_hdhomerun).clone();
if let Some(hdhomerun) = &mut self.hdhomerun {
if hdhomerun.enabled {
hdhomerun.prepare(self.api.port)?;
}
@@ -132,4 +137,12 @@ impl ConfigDto {
}
true
}
pub fn get_hdhr_device_overview(&self) -> Option<HdHomeRunDeviceOverview> {
self.hdhomerun.as_ref().map(|hdhr|
HdHomeRunDeviceOverview {
enabled: hdhr.enabled,
devices: hdhr.devices.iter().map(|d| d.name.to_string()).collect::<Vec<String>>(),
})
}
}
+6 -6
View File
@@ -2,7 +2,7 @@ use std::collections::HashSet;
use crate::create_tuliprox_error_result;
use crate::error::{handle_tuliprox_error_result_list, TuliproxError, TuliproxErrorKind};
use crate::foundation::filter::prepare_templates;
use crate::model::{ConfigInputDto, PatternTemplate};
use crate::model::{ConfigInputDto, HdHomeRunDeviceOverview, PatternTemplate};
use crate::model::config::target::ConfigTargetDto;
use crate::utils::default_as_default;
@@ -40,14 +40,14 @@ pub struct SourcesConfigDto {
}
impl SourcesConfigDto {
pub fn prepare(&mut self, include_computed: bool) -> Result<(), TuliproxError> {
pub fn prepare(&mut self, include_computed: bool, hdhr_config: Option<&HdHomeRunDeviceOverview>) -> Result<(), TuliproxError> {
self.prepare_templates()?;
self.prepare_sources(include_computed)?;
self.prepare_sources(include_computed, hdhr_config)?;
self.check_unique_target_names()?;
Ok(())
}
fn prepare_sources(&mut self, include_computed: bool) -> Result<(), TuliproxError> {
fn prepare_sources(&mut self, include_computed: bool, hdhr_config: Option<&HdHomeRunDeviceOverview>) -> Result<(), TuliproxError> {
// prepare sources and set id's
let mut source_index: u16 = 0;
let mut target_index: u16 = 1;
@@ -56,8 +56,8 @@ impl SourcesConfigDto {
for target in &mut source.targets {
// prepare target templates
let prepare_result = match &self.templates {
Some(templ) => target.prepare(target_index, Some(templ)),
_ => target.prepare(target_index, None)
Some(templ) => target.prepare(target_index, Some(templ), hdhr_config),
_ => target.prepare(target_index, None, hdhr_config)
};
prepare_result?;
target_index += 1;
+14 -2
View File
@@ -1,7 +1,8 @@
use log::warn;
use crate::error::{TuliproxError, TuliproxErrorKind};
use crate::{create_tuliprox_error_result, handle_tuliprox_error_result_list, info_err};
use crate::foundation::filter::{get_filter, Filter};
use crate::model::{ClusterFlags, ConfigRenameDto, ConfigSortDto, PatternTemplate, ProcessingOrder, StrmExportStyle, TargetType, TraktConfigDto};
use crate::model::{ClusterFlags, ConfigRenameDto, ConfigSortDto, HdHomeRunDeviceOverview, PatternTemplate, ProcessingOrder, StrmExportStyle, TargetType, TraktConfigDto};
use crate::utils::{default_as_true, default_resolve_delay_secs, default_as_default};
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default, PartialEq)]
#[serde(deny_unknown_fields)]
@@ -150,7 +151,7 @@ pub struct ConfigTargetDto {
impl ConfigTargetDto {
#[allow(clippy::too_many_lines)]
pub fn prepare(&mut self, id: u16, templates: Option<&Vec<PatternTemplate>>) -> Result<(), TuliproxError> {
pub fn prepare(&mut self, id: u16, templates: Option<&Vec<PatternTemplate>>, hdhr_config: Option<&HdHomeRunDeviceOverview>) -> Result<(), TuliproxError> {
self.id = id;
if self.output.is_empty() {
return Err(info_err!(format!("Missing output format for {}", self.name)));
@@ -226,6 +227,11 @@ impl ConfigTargetDto {
_ => return create_tuliprox_error_result!(TuliproxErrorKind::Info, "HdHomeRun output option `use_output` only accepts `m3u` or `xtream` for target: {}", self.name),
}
}
if let Some(hdhr_devices) = hdhr_config {
if !hdhr_devices.devices.contains(&hdhomerun_output.device) {
return create_tuliprox_error_result!(TuliproxErrorKind::Info, "HdHomeRun output device is not defined: {}", hdhomerun_output.device);
}
}
}
}
}
@@ -248,6 +254,12 @@ impl ConfigTargetDto {
if hdhomerun_needs_xtream && xtream_cnt == 0 {
return create_tuliprox_error_result!(TuliproxErrorKind::Info, "HdHomeRun output has `use_output=xtream` but no `xtream` output defined: {}", self.name);
}
if let Some(hdhr_devices) = hdhr_config {
if !hdhr_devices.enabled {
warn!("You have defined an HDHomeRun output, but HDHomeRun devices are disabled.");
}
}
}
if let Some(watch) = &self.watch {
+3 -1
View File
@@ -154,10 +154,12 @@
--menu-button-hover-color: #ffffff;
--menu-button-hover-background-color: #202733;
--menu-button-warn-hover-color: #dd7573;
--menu-button-warn-hover-background-color: #4c3434;
--text-button-border-radius: var(--border-radius);
--text-button-hover-background-color: #0d6efd;
--scrollbar-track-color: #838383;
--scrollbar-handle-color: #505050;