From 2a9c8711e6e72f301498ef6cda7b8d43d91f5bee Mon Sep 17 00:00:00 2001 From: euzu Date: Thu, 19 Jun 2025 12:45:55 +0200 Subject: [PATCH 1/9] project shared added --- .gitignore | 1 + Cargo.lock | 119 +- Cargo.toml | 72 +- backend/Cargo.lock | 3752 +++++++++++++++++ backend/Cargo.toml | 71 + build.rs => backend/build.rs | 0 {src => backend/src}/api/api_utils.rs | 2 +- {src => backend/src}/api/config_watch.rs | 0 .../src}/api/endpoints/api_playlist_utils.rs | 3 +- .../src}/api/endpoints/download_api.rs | 0 .../src}/api/endpoints/hdhomerun_api.rs | 3 +- {src => backend/src}/api/endpoints/hls_api.rs | 2 +- {src => backend/src}/api/endpoints/m3u_api.rs | 2 +- {src => backend/src}/api/endpoints/mod.rs | 0 .../src}/api/endpoints/user_api.rs | 2 +- {src => backend/src}/api/endpoints/v1_api.rs | 0 .../src}/api/endpoints/web_index.rs | 0 .../src}/api/endpoints/xmltv_api.rs | 0 .../src}/api/endpoints/xtream_api.rs | 7 +- {src => backend/src}/api/main_api.rs | 0 {src => backend/src}/api/mod.rs | 0 .../src}/api/model/active_provider_manager.rs | 0 .../src}/api/model/active_user_manager.rs | 0 {src => backend/src}/api/model/app_state.rs | 0 {src => backend/src}/api/model/config.rs | 0 {src => backend/src}/api/model/download.rs | 2 +- {src => backend/src}/api/model/mod.rs | 0 {src => backend/src}/api/model/model_utils.rs | 0 .../src}/api/model/provider_config.rs | 0 {src => backend/src}/api/model/request.rs | 0 {src => backend/src}/api/model/stream.rs | 0 .../src}/api/model/stream_error.rs | 0 .../api/model/streams/active_client_stream.rs | 0 .../src}/api/model/streams/buffered_stream.rs | 0 .../src}/api/model/streams/client_stream.rs | 0 .../api/model/streams/custom_video_stream.rs | 0 {src => backend/src}/api/model/streams/mod.rs | 0 .../api/model/streams/persist_pipe_stream.rs | 0 .../src}/api/model/streams/provider_stream.rs | 2 +- .../model/streams/provider_stream_factory.rs | 2 +- .../model/streams/shared_stream_manager.rs | 0 .../api/model/streams/throttled_stream.rs | 0 .../api/model/streams/timed_client_stream.rs | 0 .../model/streams/transport_stream_buffer.rs | 0 {src => backend/src}/api/model/xtream.rs | 0 {src => backend/src}/api/scheduler.rs | 0 {src => backend/src}/api/serve.rs | 0 {src => backend/src}/auth/access_token.rs | 2 +- {src => backend/src}/auth/auth_basic.rs | 0 {src => backend/src}/auth/auth_bearer.rs | 0 {src => backend/src}/auth/authenticator.rs | 0 {src => backend/src}/auth/fingerprint.rs | 0 {src => backend/src}/auth/mod.rs | 0 {src => backend/src}/auth/password.rs | 0 {src => backend/src}/auth/user.rs | 0 {src => backend/src}/foundation/filter.pest | 0 {src => backend/src}/foundation/filter.rs | 4 +- {src => backend/src}/foundation/mapper.pest | 0 {src => backend/src}/foundation/mapper.rs | 0 {src => backend/src}/foundation/mod.rs | 0 {src => backend/src}/main.rs | 0 {src => backend/src}/messaging.rs | 0 {src => backend/src}/model/config.rs | 0 .../src}/model/config_api_proxy.rs | 4 +- {src => backend/src}/model/config_cache.rs | 0 {src => backend/src}/model/config_download.rs | 0 {src => backend/src}/model/config_epg.rs | 0 .../src}/model/config_hdhomerun.rs | 0 .../src}/model/config_healthcheck.rs | 0 {src => backend/src}/model/config_input.rs | 0 {src => backend/src}/model/config_ip_check.rs | 0 {src => backend/src}/model/config_log.rs | 0 .../src}/model/config_messaging.rs | 0 {src => backend/src}/model/config_proxy.rs | 0 {src => backend/src}/model/config_rename.rs | 0 {src => backend/src}/model/config_sort.rs | 0 {src => backend/src}/model/config_source.rs | 0 {src => backend/src}/model/config_target.rs | 25 +- {src => backend/src}/model/config_web_auth.rs | 0 {src => backend/src}/model/config_webui.rs | 0 {src => backend/src}/model/healthcheck.rs | 0 {src => backend/src}/model/mapping.rs | 0 {src => backend/src}/model/mod.rs | 4 - {src => backend/src}/model/playlist.rs | 138 +- .../src}/model/playlist_categories.rs | 0 .../src}/model/processing_order.rs | 0 {src => backend/src}/model/serde_utils.rs | 0 {src => backend/src}/model/stats.rs | 0 {src => backend/src}/model/trakt.rs | 0 {src => backend/src}/model/xmltv.rs | 0 {src => backend/src}/model/xtream.rs | 6 +- {src => backend/src}/model/xtream_const.rs | 0 {src => backend/src}/modules.rs | 0 {src => backend/src}/processing/mod.rs | 0 {src => backend/src}/processing/parser/hls.rs | 0 {src => backend/src}/processing/parser/m3u.rs | 3 +- {src => backend/src}/processing/parser/mod.rs | 0 .../src}/processing/parser/xmltv.rs | 0 .../src}/processing/parser/xtream.rs | 3 +- .../src}/processing/playlist_watch.rs | 0 .../src}/processing/processor/affix.rs | 0 .../src}/processing/processor/epg.rs | 4 +- .../src}/processing/processor/mod.rs | 0 .../src}/processing/processor/playlist.rs | 3 +- .../src}/processing/processor/sort.rs | 0 .../src}/processing/processor/trakt.rs | 3 +- .../src}/processing/processor/xtream.rs | 3 +- .../processing/processor/xtream_series.rs | 3 +- .../src}/processing/processor/xtream_vod.rs | 3 +- {src => backend/src}/repository/bplustree.rs | 0 .../src}/repository/epg_repository.rs | 0 .../src}/repository/indexed_document.rs | 0 .../src}/repository/m3u_playlist_iterator.rs | 3 +- .../src}/repository/m3u_repository.rs | 3 +- {src => backend/src}/repository/mod.rs | 0 .../src}/repository/playlist_repository.rs | 3 +- {src => backend/src}/repository/storage.rs | 45 - .../src}/repository/storage_const.rs | 0 .../src}/repository/strm_repository.rs | 10 +- .../src}/repository/target_id_mapping.rs | 2 +- .../src}/repository/user_repository.rs | 2 +- .../repository/xtream_playlist_iterator.rs | 3 +- .../src}/repository/xtream_repository.rs | 5 +- .../src}/tools/atomic_once_flag.rs | 0 {src => backend/src}/tools/directed_graph.rs | 0 {src => backend/src}/tools/lru_cache.rs | 3 +- {src => backend/src}/tools/mod.rs | 0 {src => backend/src}/tuliprox_error.rs | 0 {src => backend/src}/utils/bincode_utils.rs | 0 .../compression/compressed_file_reader.rs | 0 .../utils/compression/compression_utils.rs | 0 {src => backend/src}/utils/compression/mod.rs | 0 {src => backend/src}/utils/constants.rs | 0 {src => backend/src}/utils/crypto_utils.rs | 0 {src => backend/src}/utils/default_utils.rs | 0 .../src}/utils/file/config_reader.rs | 0 .../src}/utils/file/csv_input_reader.rs | 0 .../src}/utils/file/env_resolving_reader.rs | 0 .../src}/utils/file/file_lock_manager.rs | 0 {src => backend/src}/utils/file/file_utils.rs | 0 .../src}/utils/file/mapping_reader.rs | 0 {src => backend/src}/utils/file/mod.rs | 0 .../src}/utils/file/multi_file_reader.rs | 0 {src => backend/src}/utils/hash_utils.rs | 47 +- {src => backend/src}/utils/json_utils.rs | 0 {src => backend/src}/utils/logging.rs | 0 {src => backend/src}/utils/mod.rs | 0 {src => backend/src}/utils/network/epg.rs | 3 +- .../src}/utils/network/ip_checker.rs | 0 {src => backend/src}/utils/network/m3u.rs | 0 {src => backend/src}/utils/network/mod.rs | 0 {src => backend/src}/utils/network/request.rs | 4 +- {src => backend/src}/utils/network/xtream.rs | 3 +- {src => backend/src}/utils/size_utils.rs | 0 {src => backend/src}/utils/step_measure.rs | 0 {src => backend/src}/utils/string_utils.rs | 0 {src => backend/src}/utils/sys_utils.rs | 0 {src => backend/src}/utils/time_utils.rs | 0 {src => backend/src}/utils/trakt/client.rs | 0 {src => backend/src}/utils/trakt/errors.rs | 0 {src => backend/src}/utils/trakt/mod.rs | 0 bin/build_aarch64.sh | 2 +- bin/build_armv7.sh | 2 +- bin/build_darwin.sh | 2 +- bin/build_github_docker.sh | 2 +- bin/build_github_docker_aarch64.sh | 2 +- bin/build_github_docker_beta.sh | 2 +- bin/build_lin.sh | 2 +- bin/build_lin_static.sh | 2 +- bin/build_win.sh | 2 +- bin/release.sh | 2 +- docker/Dockerfile | 10 +- shared/Cargo.toml | 8 + shared/src/lib.rs | 1 + {src => shared/src}/model/cluster_flags.rs | 0 shared/src/model/mod.rs | 5 + shared/src/model/playlist.rs | 128 + 177 files changed, 4178 insertions(+), 380 deletions(-) create mode 100644 backend/Cargo.lock create mode 100644 backend/Cargo.toml rename build.rs => backend/build.rs (100%) rename {src => backend/src}/api/api_utils.rs (99%) rename {src => backend/src}/api/config_watch.rs (100%) rename {src => backend/src}/api/endpoints/api_playlist_utils.rs (98%) rename {src => backend/src}/api/endpoints/download_api.rs (100%) rename {src => backend/src}/api/endpoints/hdhomerun_api.rs (99%) rename {src => backend/src}/api/endpoints/hls_api.rs (99%) rename {src => backend/src}/api/endpoints/m3u_api.rs (99%) rename {src => backend/src}/api/endpoints/mod.rs (100%) rename {src => backend/src}/api/endpoints/user_api.rs (99%) rename {src => backend/src}/api/endpoints/v1_api.rs (100%) rename {src => backend/src}/api/endpoints/web_index.rs (100%) rename {src => backend/src}/api/endpoints/xmltv_api.rs (100%) rename {src => backend/src}/api/endpoints/xtream_api.rs (99%) rename {src => backend/src}/api/main_api.rs (100%) rename {src => backend/src}/api/mod.rs (100%) rename {src => backend/src}/api/model/active_provider_manager.rs (100%) rename {src => backend/src}/api/model/active_user_manager.rs (100%) rename {src => backend/src}/api/model/app_state.rs (100%) rename {src => backend/src}/api/model/config.rs (100%) rename {src => backend/src}/api/model/download.rs (98%) rename {src => backend/src}/api/model/mod.rs (100%) rename {src => backend/src}/api/model/model_utils.rs (100%) rename {src => backend/src}/api/model/provider_config.rs (100%) rename {src => backend/src}/api/model/request.rs (100%) rename {src => backend/src}/api/model/stream.rs (100%) rename {src => backend/src}/api/model/stream_error.rs (100%) rename {src => backend/src}/api/model/streams/active_client_stream.rs (100%) rename {src => backend/src}/api/model/streams/buffered_stream.rs (100%) rename {src => backend/src}/api/model/streams/client_stream.rs (100%) rename {src => backend/src}/api/model/streams/custom_video_stream.rs (100%) rename {src => backend/src}/api/model/streams/mod.rs (100%) rename {src => backend/src}/api/model/streams/persist_pipe_stream.rs (100%) rename {src => backend/src}/api/model/streams/provider_stream.rs (99%) rename {src => backend/src}/api/model/streams/provider_stream_factory.rs (99%) rename {src => backend/src}/api/model/streams/shared_stream_manager.rs (100%) rename {src => backend/src}/api/model/streams/throttled_stream.rs (100%) rename {src => backend/src}/api/model/streams/timed_client_stream.rs (100%) rename {src => backend/src}/api/model/streams/transport_stream_buffer.rs (100%) rename {src => backend/src}/api/model/xtream.rs (100%) rename {src => backend/src}/api/scheduler.rs (100%) rename {src => backend/src}/api/serve.rs (100%) rename {src => backend/src}/auth/access_token.rs (97%) rename {src => backend/src}/auth/auth_basic.rs (100%) rename {src => backend/src}/auth/auth_bearer.rs (100%) rename {src => backend/src}/auth/authenticator.rs (100%) rename {src => backend/src}/auth/fingerprint.rs (100%) rename {src => backend/src}/auth/mod.rs (100%) rename {src => backend/src}/auth/password.rs (100%) rename {src => backend/src}/auth/user.rs (100%) rename {src => backend/src}/foundation/filter.pest (100%) rename {src => backend/src}/foundation/filter.rs (99%) rename {src => backend/src}/foundation/mapper.pest (100%) rename {src => backend/src}/foundation/mapper.rs (100%) rename {src => backend/src}/foundation/mod.rs (100%) rename {src => backend/src}/main.rs (100%) rename {src => backend/src}/messaging.rs (100%) rename {src => backend/src}/model/config.rs (100%) rename {src => backend/src}/model/config_api_proxy.rs (99%) rename {src => backend/src}/model/config_cache.rs (100%) rename {src => backend/src}/model/config_download.rs (100%) rename {src => backend/src}/model/config_epg.rs (100%) rename {src => backend/src}/model/config_hdhomerun.rs (100%) rename {src => backend/src}/model/config_healthcheck.rs (100%) rename {src => backend/src}/model/config_input.rs (100%) rename {src => backend/src}/model/config_ip_check.rs (100%) rename {src => backend/src}/model/config_log.rs (100%) rename {src => backend/src}/model/config_messaging.rs (100%) rename {src => backend/src}/model/config_proxy.rs (100%) rename {src => backend/src}/model/config_rename.rs (100%) rename {src => backend/src}/model/config_sort.rs (100%) rename {src => backend/src}/model/config_source.rs (100%) rename {src => backend/src}/model/config_target.rs (98%) rename {src => backend/src}/model/config_web_auth.rs (100%) rename {src => backend/src}/model/config_webui.rs (100%) rename {src => backend/src}/model/healthcheck.rs (100%) rename {src => backend/src}/model/mapping.rs (100%) rename {src => backend/src}/model/mod.rs (91%) rename {src => backend/src}/model/playlist.rs (81%) rename {src => backend/src}/model/playlist_categories.rs (100%) rename {src => backend/src}/model/processing_order.rs (100%) rename {src => backend/src}/model/serde_utils.rs (100%) rename {src => backend/src}/model/stats.rs (100%) rename {src => backend/src}/model/trakt.rs (100%) rename {src => backend/src}/model/xmltv.rs (100%) rename {src => backend/src}/model/xtream.rs (99%) rename {src => backend/src}/model/xtream_const.rs (100%) rename {src => backend/src}/modules.rs (100%) rename {src => backend/src}/processing/mod.rs (100%) rename {src => backend/src}/processing/parser/hls.rs (100%) rename {src => backend/src}/processing/parser/m3u.rs (99%) rename {src => backend/src}/processing/parser/mod.rs (100%) rename {src => backend/src}/processing/parser/xmltv.rs (100%) rename {src => backend/src}/processing/parser/xtream.rs (99%) rename {src => backend/src}/processing/playlist_watch.rs (100%) rename {src => backend/src}/processing/processor/affix.rs (100%) rename {src => backend/src}/processing/processor/epg.rs (99%) rename {src => backend/src}/processing/processor/mod.rs (100%) rename {src => backend/src}/processing/processor/playlist.rs (99%) rename {src => backend/src}/processing/processor/sort.rs (100%) rename {src => backend/src}/processing/processor/trakt.rs (98%) rename {src => backend/src}/processing/processor/xtream.rs (97%) rename {src => backend/src}/processing/processor/xtream_series.rs (98%) rename {src => backend/src}/processing/processor/xtream_vod.rs (98%) rename {src => backend/src}/repository/bplustree.rs (100%) rename {src => backend/src}/repository/epg_repository.rs (100%) rename {src => backend/src}/repository/indexed_document.rs (100%) rename {src => backend/src}/repository/m3u_playlist_iterator.rs (98%) rename {src => backend/src}/repository/m3u_repository.rs (98%) rename {src => backend/src}/repository/mod.rs (100%) rename {src => backend/src}/repository/playlist_repository.rs (97%) rename {src => backend/src}/repository/storage.rs (58%) rename {src => backend/src}/repository/storage_const.rs (100%) rename {src => backend/src}/repository/strm_repository.rs (99%) rename {src => backend/src}/repository/target_id_mapping.rs (99%) rename {src => backend/src}/repository/user_repository.rs (99%) rename {src => backend/src}/repository/xtream_playlist_iterator.rs (98%) rename {src => backend/src}/repository/xtream_repository.rs (99%) rename {src => backend/src}/tools/atomic_once_flag.rs (100%) rename {src => backend/src}/tools/directed_graph.rs (100%) rename {src => backend/src}/tools/lru_cache.rs (98%) rename {src => backend/src}/tools/mod.rs (100%) rename {src => backend/src}/tuliprox_error.rs (100%) rename {src => backend/src}/utils/bincode_utils.rs (100%) rename {src => backend/src}/utils/compression/compressed_file_reader.rs (100%) rename {src => backend/src}/utils/compression/compression_utils.rs (100%) rename {src => backend/src}/utils/compression/mod.rs (100%) rename {src => backend/src}/utils/constants.rs (100%) rename {src => backend/src}/utils/crypto_utils.rs (100%) rename {src => backend/src}/utils/default_utils.rs (100%) rename {src => backend/src}/utils/file/config_reader.rs (100%) rename {src => backend/src}/utils/file/csv_input_reader.rs (100%) rename {src => backend/src}/utils/file/env_resolving_reader.rs (100%) rename {src => backend/src}/utils/file/file_lock_manager.rs (100%) rename {src => backend/src}/utils/file/file_utils.rs (100%) rename {src => backend/src}/utils/file/mapping_reader.rs (100%) rename {src => backend/src}/utils/file/mod.rs (100%) rename {src => backend/src}/utils/file/multi_file_reader.rs (100%) rename {src => backend/src}/utils/hash_utils.rs (56%) rename {src => backend/src}/utils/json_utils.rs (100%) rename {src => backend/src}/utils/logging.rs (100%) rename {src => backend/src}/utils/mod.rs (100%) rename {src => backend/src}/utils/network/epg.rs (96%) rename {src => backend/src}/utils/network/ip_checker.rs (100%) rename {src => backend/src}/utils/network/m3u.rs (100%) rename {src => backend/src}/utils/network/mod.rs (100%) rename {src => backend/src}/utils/network/request.rs (99%) rename {src => backend/src}/utils/network/xtream.rs (99%) rename {src => backend/src}/utils/size_utils.rs (100%) rename {src => backend/src}/utils/step_measure.rs (100%) rename {src => backend/src}/utils/string_utils.rs (100%) rename {src => backend/src}/utils/sys_utils.rs (100%) rename {src => backend/src}/utils/time_utils.rs (100%) rename {src => backend/src}/utils/trakt/client.rs (100%) rename {src => backend/src}/utils/trakt/errors.rs (100%) rename {src => backend/src}/utils/trakt/mod.rs (100%) create mode 100644 shared/Cargo.toml create mode 100644 shared/src/lib.rs rename {src => shared/src}/model/cluster_flags.rs (100%) create mode 100644 shared/src/model/mod.rs create mode 100644 shared/src/model/playlist.rs diff --git a/.gitignore b/.gitignore index 01bc4b913..5d10d9040 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +dist /resources/*.ts /release /target diff --git a/Cargo.lock b/Cargo.lock index 3c93e698b..f633f2c58 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -143,9 +143,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.24" +version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d615619615a650c571269c00dca41db04b9210037fa76ed8239f70404ab56985" +checksum = "40f6024f3f856663b45fd0c9b6f2024034a702f453549449e0d84a305900dad4" dependencies = [ "brotli", "flate2", @@ -165,9 +165,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "axum" @@ -368,9 +368,9 @@ checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6" [[package]] name = "cc" -version = "1.2.26" +version = "1.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac" +checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" dependencies = [ "jobserver", "libc", @@ -995,7 +995,7 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", "wasm-bindgen", ] @@ -1457,9 +1457,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93" +checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" dependencies = [ "jiff-static", "log", @@ -1470,9 +1470,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442" +checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" dependencies = [ "proc-macro2", "quote", @@ -1542,9 +1542,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.172" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libnghttp2-sys" @@ -1627,9 +1627,9 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "mime" @@ -1664,7 +1664,7 @@ checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", "log", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", "windows-sys 0.59.0", ] @@ -1914,9 +1914,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" +checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" dependencies = [ "memchr", "thiserror 2.0.12", @@ -1925,9 +1925,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5" +checksum = "bb056d9e8ea77922845ec74a1c4e8fb17e7c218cc4fc11a15c5d25e189aa40bc" dependencies = [ "pest", "pest_generator", @@ -1935,9 +1935,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db7d01726be8ab66ab32f9df467ae8b1148906685bbe75c82d1e65d7f5b3f841" +checksum = "87e404e638f781eb3202dc82db6760c8ae8a1eeef7fb3fa8264b2ef280504966" dependencies = [ "pest", "pest_meta", @@ -1948,11 +1948,10 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0" +checksum = "edd1101f170f5903fde0914f899bb503d9ff5271d7ba76bbb70bea63690cc0d5" dependencies = [ - "once_cell", "pest", "sha2", ] @@ -2061,15 +2060,15 @@ dependencies = [ [[package]] name = "quanta" -version = "0.12.5" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bd1fe6824cea6538803de3ff1bc0cf3949024db3d43c9643024bfb33a807c0e" +checksum = "f3ab5a9d756f0d97bdc89019bd2e4ea098cf9cde50ee7564dde6b81ccc8f06c7" dependencies = [ "crossbeam-utils", "libc", "once_cell", "raw-cpuid", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", "web-sys", "winapi", ] @@ -2126,9 +2125,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee4e529991f949c5e25755532370b8af5d114acae52326361d68d47af64aa842" +checksum = "fcebb1209ee276352ef14ff8732e24cc2b02bbac986cd74a4c81bcb2f9881970" dependencies = [ "cfg_aliases", "libc", @@ -2149,9 +2148,9 @@ dependencies = [ [[package]] name = "r-efi" -version = "5.2.0" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rand" @@ -2213,9 +2212,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" dependencies = [ "bitflags 2.9.1", ] @@ -2251,9 +2250,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.19" +version = "0.12.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2f8e5513d63f2e5b386eb5106dc67eaf3f84e95258e210489136b8b92ad6119" +checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813" dependencies = [ "base64 0.22.1", "bytes", @@ -2269,12 +2268,10 @@ dependencies = [ "hyper-rustls", "hyper-tls", "hyper-util", - "ipnet", "js-sys", "log", "mime", "native-tls", - "once_cell", "percent-encoding", "pin-project-lite", "quinn", @@ -2400,9 +2397,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.27" +version = "0.23.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" +checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643" dependencies = [ "once_cell", "ring", @@ -2579,6 +2576,14 @@ dependencies = [ "digest", ] +[[package]] +name = "shared" +version = "0.1.0" +dependencies = [ + "bitflags 2.9.1", + "serde", +] + [[package]] name = "shlex" version = "1.3.0" @@ -2599,12 +2604,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" [[package]] name = "sluice" @@ -2662,9 +2664,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.102" +version = "2.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6397daf94fa90f058bd0fd88429dd9e5738999cca8d701813c80723add80462" +checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" dependencies = [ "proc-macro2", "quote", @@ -2984,9 +2986,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.29" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", @@ -3024,7 +3026,7 @@ version = "3.1.4" dependencies = [ "arc-swap", "axum", - "base64 0.21.7", + "base64 0.22.1", "bincode", "bitflags 2.9.1", "blake3", @@ -3065,6 +3067,7 @@ dependencies = [ "serde", "serde_json", "serde_yaml", + "shared", "socket2", "strsim", "tempfile", @@ -3220,9 +3223,9 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" @@ -3414,9 +3417,9 @@ dependencies = [ [[package]] name = "windows-link" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-registry" @@ -3645,18 +3648,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.25" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.25" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index ecae5ae76..16cce1c76 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,6 @@ -[package] -name = "tuliprox" -version = "3.1.4" -edition = "2021" +[workspace] +members = ["backend", "shared"] +resolver = "2" [profile.release] debug = false @@ -11,68 +10,3 @@ codegen-units = 1 # Reduce number of codegen units to increase optimizations. panic = 'abort' # Abort on panic strip = true -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -serde = { version = "1.0", features = ["derive", "rc"] } -serde_yaml = "0.9" -serde_json = { version = "1", features = ["arbitrary_precision"] } -quick-xml = "0.37" -regex = "1.11" -clap = { version = "4", features = ["derive"] } -url = "2.5" -reqwest = { version = "0", features = ["blocking", "json", "stream", "rustls-tls"] } -chrono = "0.4" -cron = "0.15" -axum = { version = "0" , features = ["macros", "default"]} -tower = "0" -tower-http = { version = "0", features = ["cors", "auth", "fs", "compression-full"]} -tower_governor = { version = "0.7", features = ["axum"] } -jsonwebtoken = "9.3" -rust-argon2 = "2.1" -futures = "0.3" -path-clean = "1" -pest = "2.8" -pest_derive = "2.8" -enum-iterator = "2" -openssl = { version = "*", features = ["vendored"] } #https://docs.rs/openssl/0.10.34/openssl/#vendored -deunicode = "1.6.2" -mime = "0.3" -log = "0.4" -env_logger = "0.11" -rustelebot = "0.3" -bincode = { version = "2.0.1", features = ["std", "serde"] } -rand = "0.9" -rpassword = "7.4" -flate2 = "1" -blake3 = "1.8" -bytes = "1.10" -tokio-stream = { version = "0.1", features = ["sync"] } -tokio = { version = "1.45", features = ["rt-multi-thread", "parking_lot", "fs"] } -tokio-util = "0.7" -tempfile = "3.20" -ruzstd = "0" -filetime = "0.2" -zeroize = "1.8" -strsim = "0.11" -rphonetic = "3" -rayon = "1.10" -base64 = "0" -paste = "1" -bitflags = "2" -indexmap = "2" -notify = "8" -arc-swap = "1" -dashmap = "6" -hyper = "1" -hyper-util = "0" -socket2 = "0" -#[cfg(target_os = "macos")] -libc = "0" -#[cfg(target_os = "windows")] -winapi = { version = "0", features = ["psapi", "minwindef", "processthreadsapi"] } -# [target.'cfg(not(target_env = "msvc"))'.dependencies] -# tikv-jemallocator = { version = "*", features = ["profiling", "unprefixed_malloc_on_supported_platforms"] } - -[build-dependencies] -vergen = { version = "9", features = ["build"] } diff --git a/backend/Cargo.lock b/backend/Cargo.lock new file mode 100644 index 000000000..3c93e698b --- /dev/null +++ b/backend/Cargo.lock @@ -0,0 +1,3752 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.59.0", +] + +[[package]] +name = "anyhow" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-compression" +version = "0.4.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d615619615a650c571269c00dca41db04b9210037fa76ed8239f70404ab56985" +dependencies = [ + "brotli", + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", + "zstd", + "zstd-safe", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "axum" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5" +dependencies = [ + "axum-core", + "axum-macros", + "bytes", + "form_urlencoded", + "futures-util", + "http 1.3.1", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6" +dependencies = [ + "bytes", + "futures-core", + "http 1.3.1", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "backtrace" +version = "0.3.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bincode" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" +dependencies = [ + "bincode_derive", + "serde", + "unty", +] + +[[package]] +name = "bincode_derive" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09" +dependencies = [ + "virtue", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + +[[package]] +name = "blake2b_simd" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06e903a20b159e944f91ec8499fe1e55651480c541ea0a584f5d967c49ad9d99" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + +[[package]] +name = "blake3" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "brotli" +version = "8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bumpalo" +version = "3.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "castaway" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6" + +[[package]] +name = "cc" +version = "1.2.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "clap" +version = "4.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[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]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "cron" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5877d3fbf742507b66bc2a1945106bd30dd8504019d596901ddd012a4dd01740" +dependencies = [ + "chrono", + "once_cell", + "winnow", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "curl" +version = "0.4.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e2d5c8f48d9c0c23250e52b55e82a6ab4fdba6650c931f5a0a57a43abda812b" +dependencies = [ + "curl-sys", + "libc", + "openssl-probe", + "openssl-sys", + "schannel", + "socket2", + "windows-sys 0.59.0", +] + +[[package]] +name = "curl-sys" +version = "0.4.82+curl-8.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4d63638b5ec65f1a4ae945287b3fd035be4554bbaf211901159c9a2a74fb5be" +dependencies = [ + "cc", + "libc", + "libnghttp2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", + "windows-sys 0.59.0", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "deranged" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derive_builder" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +dependencies = [ + "derive_builder_core", + "syn", +] + +[[package]] +name = "deunicode" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abd57806937c9cc163efc8ea3910e00a62e2aeb0b8119f1793a978088f8f6b04" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "document-features" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +dependencies = [ + "litrs", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enum-iterator" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c280b9e6b3ae19e152d8e31cf47f18389781e119d4013a2a2bb0180e5facc635" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "env_filter" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "filetime" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.59.0", +] + +[[package]] +name = "flate2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[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]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "forwarded-header-value" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835f84f38484cc86f110a805655697908257fb9a7af005234060891557198e9" +dependencies = [ + "nonempty", + "thiserror 1.0.69", +] + +[[package]] +name = "fsevent-sys" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "governor" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be93b4ec2e4710b04d9264c0c7350cdd62a8c20e5e4ac732552ebb8f0debe8eb" +dependencies = [ + "cfg-if", + "dashmap", + "futures-sink", + "futures-timer", + "futures-util", + "getrandom 0.3.3", + "no-std-compat", + "nonzero_ext", + "parking_lot", + "portable-atomic", + "quanta", + "rand", + "smallvec", + "spinning_top", + "web-time", +] + +[[package]] +name = "h2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.3.1", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.3.1", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http 1.3.1", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "http-range-header" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2", + "http 1.3.1", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http 1.3.1", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", +] + +[[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", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http 1.3.1", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "system-configuration", + "tokio", + "tower-service", + "tracing", + "windows-registry", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +dependencies = [ + "equivalent", + "hashbrown 0.15.4", +] + +[[package]] +name = "inotify" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" +dependencies = [ + "bitflags 2.9.1", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "isahc" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "334e04b4d781f436dc315cb1e7515bd96826426345d498149e4bde36b67f8ee9" +dependencies = [ + "async-channel", + "castaway", + "crossbeam-utils", + "curl", + "curl-sys", + "encoding_rs", + "event-listener", + "futures-lite", + "http 0.2.12", + "log", + "mime", + "once_cell", + "polling", + "serde", + "serde_json", + "slab", + "sluice", + "tracing", + "tracing-futures", + "url", + "waker-fn", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jiff" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", +] + +[[package]] +name = "jiff-static" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "jobserver" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "9.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" +dependencies = [ + "base64 0.22.1", + "js-sys", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "kqueue" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.172" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "libnghttp2-sys" +version = "0.1.11+1.64.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b6c24e48a7167cffa7119da39d577fa482e66c688a4aac016bee862e1a713c4" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.9.1", + "libc", + "redox_syscall", +] + +[[package]] +name = "libz-sys" +version = "1.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "litrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" + +[[package]] +name = "lock_api" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.59.0", +] + +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "no-std-compat" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" + +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + +[[package]] +name = "nonempty" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9e591e719385e6ebaeb5ce5d3887f7d5676fceca6411d1925ccc95745f3d6f7" + +[[package]] +name = "nonzero_ext" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" + +[[package]] +name = "notify" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fee8403b3d66ac7b26aee6e40a897d85dc5ce26f44da36b8b73e987cc52e943" +dependencies = [ + "bitflags 2.9.1", + "filetime", + "fsevent-sys", + "inotify", + "kqueue", + "libc", + "log", + "mio", + "notify-types", + "walkdir", + "windows-sys 0.59.0", +] + +[[package]] +name = "notify-types" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + +[[package]] +name = "openssl" +version = "0.10.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +dependencies = [ + "bitflags 2.9.1", + "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", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-src" +version = "300.5.0+3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8ce546f549326b0e6052b649198487d91320875da901e7bd11a06d1ee3f9c2f" +dependencies = [ + "cc", +] + +[[package]] +name = "openssl-sys" +version = "0.9.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +dependencies = [ + "cc", + "libc", + "openssl-src", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "path-clean" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef" + +[[package]] +name = "pem" +version = "3.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3" +dependencies = [ + "base64 0.22.1", + "serde", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" +dependencies = [ + "memchr", + "thiserror 2.0.12", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db7d01726be8ab66ab32f9df467ae8b1148906685bbe75c82d1e65d7f5b3f841" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.48.0", +] + +[[package]] +name = "portable-atomic" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quanta" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bd1fe6824cea6538803de3ff1bc0cf3949024db3d43c9643024bfb33a807c0e" +dependencies = [ + "crossbeam-utils", + "libc", + "once_cell", + "raw-cpuid", + "wasi 0.11.0+wasi-snapshot-preview1", + "web-sys", + "winapi", +] + +[[package]] +name = "quick-xml" +version = "0.37.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" +dependencies = [ + "memchr", +] + +[[package]] +name = "quinn" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.12", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" +dependencies = [ + "bytes", + "getrandom 0.3.3", + "lru-slab", + "rand", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.12", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee4e529991f949c5e25755532370b8af5d114acae52326361d68d47af64aa842" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "rand" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", +] + +[[package]] +name = "raw-cpuid" +version = "11.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146" +dependencies = [ + "bitflags 2.9.1", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +dependencies = [ + "bitflags 2.9.1", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "reqwest" +version = "0.12.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2f8e5513d63f2e5b386eb5106dc67eaf3f84e95258e210489136b8b92ad6119" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http 1.3.1", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tokio-rustls", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "webpki-roots", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rpassword" +version = "7.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d4c8b64f049c6721ec8ccec37ddfc3d641c4a7fca57e8f2a89de509c73df39" +dependencies = [ + "libc", + "rtoolbox", + "windows-sys 0.59.0", +] + +[[package]] +name = "rphonetic" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51016596e51b46757c38a94e15a56b293ad110fe37a6fadfea0083910c52b482" +dependencies = [ + "document-features", + "either", + "enum-iterator", + "lazy_static", + "nom", + "regex", + "serde", +] + +[[package]] +name = "rtoolbox" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7cc970b249fbe527d6e02e0a227762c9108b2f49d81094fe357ffc6d14d7f6f" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "rust-argon2" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d9848531d60c9cbbcf9d166c885316c24bc0e2a9d3eba0956bb6cbbd79bc6e8" +dependencies = [ + "base64 0.21.7", + "blake2b_simd", + "constant_time_eq", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustelebot" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8bbb00699ceced1255b72aad9b418ee29c3acf7da4597ea4d81bae0bd97b235" +dependencies = [ + "futures", + "isahc", + "serde", + "serde_json", + "url", +] + +[[package]] +name = "rustix" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +dependencies = [ + "bitflags 2.9.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustls" +version = "0.23.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" + +[[package]] +name = "ruzstd" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3640bec8aad418d7d03c72ea2de10d5c646a598f9883c7babc160d91e3c1b26c" +dependencies = [ + "twox-hash", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.9.1", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" +dependencies = [ + "itoa", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simple_asn1" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror 2.0.12", + "time", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "sluice" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7400c0eff44aa2fcb5e31a5f24ba9716ed90138769e4977a2ba6014ae63eb5" +dependencies = [ + "async-channel", + "futures-core", + "futures-io", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spinning_top" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300" +dependencies = [ + "lock_api", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6397daf94fa90f058bd0fd88429dd9e5738999cca8d701813c80723add80462" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.9.1", + "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]] +name = "tempfile" +version = "3.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +dependencies = [ + "fastrand 2.3.0", + "getrandom 0.3.3", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +dependencies = [ + "deranged", + "itoa", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" + +[[package]] +name = "time-macros" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[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]] +name = "tokio-rustls" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-util" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "async-compression", + "base64 0.22.1", + "bitflags 2.9.1", + "bytes", + "futures-core", + "futures-util", + "http 1.3.1", + "http-body", + "http-body-util", + "http-range-header", + "httpdate", + "iri-string", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "tokio", + "tokio-util", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tower_governor" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84e6672c7510df74859726427edea641674dad1aeeb30057b87335b1ba23b843" +dependencies = [ + "axum", + "forwarded-header-value", + "governor", + "http 1.3.1", + "pin-project", + "thiserror 2.0.12", + "tower", + "tracing", +] + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "tuliprox" +version = "3.1.4" +dependencies = [ + "arc-swap", + "axum", + "base64 0.21.7", + "bincode", + "bitflags 2.9.1", + "blake3", + "bytes", + "chrono", + "clap", + "cron", + "dashmap", + "deunicode", + "enum-iterator", + "env_logger", + "filetime", + "flate2", + "futures", + "hyper", + "hyper-util", + "indexmap", + "jsonwebtoken", + "libc", + "log", + "mime", + "notify", + "openssl", + "paste", + "path-clean", + "pest", + "pest_derive", + "quick-xml", + "rand", + "rayon", + "regex", + "reqwest", + "rpassword", + "rphonetic", + "rust-argon2", + "rustelebot", + "ruzstd", + "serde", + "serde_json", + "serde_yaml", + "socket2", + "strsim", + "tempfile", + "tokio", + "tokio-stream", + "tokio-util", + "tower", + "tower-http", + "tower_governor", + "url", + "vergen", + "winapi", + "zeroize", +] + +[[package]] +name = "twox-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b907da542cbced5261bd3256de1b3a1bf340a3d37f93425a07362a1d687de56" + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "unty" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "vergen" +version = "9.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b2bf58be11fc9414104c6d3a2e464163db5ef74b12296bda593cac37b6e4777" +dependencies = [ + "anyhow", + "derive_builder", + "rustversion", + "time", + "vergen-lib", +] + +[[package]] +name = "vergen-lib" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b07e6010c0f3e59fcb164e0163834597da68d1f864e2b8ca49f74de01e9c166" +dependencies = [ + "anyhow", + "derive_builder", + "rustversion", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "virtue" +version = "0.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" + +[[package]] +name = "waker-fn" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-registry" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3bab093bdd303a1240bb99b8aba8ea8a69ee19d34c9e2ef9594e708a4878820" +dependencies = [ + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "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]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "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_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[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_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.6.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e90edd2ac1aa278a5c4599b1d89cf03074b610800f866d4026dc199d7929a28" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags 2.9.1", +] + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.15+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/backend/Cargo.toml b/backend/Cargo.toml new file mode 100644 index 000000000..77e2f96f7 --- /dev/null +++ b/backend/Cargo.toml @@ -0,0 +1,71 @@ +[package] +name = "tuliprox" +version = "3.1.4" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +shared = {version = "0", path = "../shared" } +serde = { version = "1.0", features = ["derive", "rc"] } +serde_yaml = "0.9" +serde_json = { version = "1", features = ["arbitrary_precision"] } +quick-xml = "0.37" +regex = "1.11" +clap = { version = "4", features = ["derive"] } +url = "2.5" +reqwest = { version = "0", features = ["blocking", "json", "stream", "rustls-tls"] } +chrono = "0.4" +cron = "0.15" +axum = { version = "0" , features = ["macros", "default"]} +tower = "0" +tower-http = { version = "0", features = ["cors", "auth", "fs", "compression-full"]} +tower_governor = { version = "0.7", features = ["axum"] } +jsonwebtoken = "9.3" +rust-argon2 = "2.1" +futures = "0.3" +path-clean = "1" +pest = "2.8" +pest_derive = "2.8" +enum-iterator = "2" +openssl = { version = "*", features = ["vendored"] } #https://docs.rs/openssl/0.10.34/openssl/#vendored +deunicode = "1.6.2" +mime = "0.3" +log = "0.4" +env_logger = "0.11" +rustelebot = "0.3" +bincode = { version = "2.0.1", features = ["std", "serde"] } +rand = "0.9" +rpassword = "7.4" +flate2 = "1" +blake3 = "1.8" +bytes = "1.10" +tokio-stream = { version = "0.1", features = ["sync"] } +tokio = { version = "1.45", features = ["rt-multi-thread", "parking_lot", "fs"] } +tokio-util = "0.7" +tempfile = "3.20" +ruzstd = "0" +filetime = "0.2" +zeroize = "1.8" +strsim = "0.11" +rphonetic = "3" +rayon = "1.10" +base64 = "0" +paste = "1" +bitflags = "2" +indexmap = "2" +notify = "8" +arc-swap = "1" +dashmap = "6" +hyper = "1" +hyper-util = "0" +socket2 = "0" +#[cfg(target_os = "macos")] +libc = "0" +#[cfg(target_os = "windows")] +winapi = { version = "0", features = ["psapi", "minwindef", "processthreadsapi"] } +# [target.'cfg(not(target_env = "msvc"))'.dependencies] +# tikv-jemallocator = { version = "*", features = ["profiling", "unprefixed_malloc_on_supported_platforms"] } + +[build-dependencies] +vergen = { version = "9", features = ["build"] } diff --git a/build.rs b/backend/build.rs similarity index 100% rename from build.rs rename to backend/build.rs diff --git a/src/api/api_utils.rs b/backend/src/api/api_utils.rs similarity index 99% rename from src/api/api_utils.rs rename to backend/src/api/api_utils.rs index 56bbc2df1..e655ea58f 100644 --- a/src/api/api_utils.rs +++ b/backend/src/api/api_utils.rs @@ -14,7 +14,7 @@ use crate::api::model::streams::throttled_stream::ThrottledStream; use crate::auth::Claims; use crate::model::{ProxyUserCredentials, UserConnectionPermission}; use crate::model::{ConfigInput, ConfigTarget, InputFetchMethod, TargetType}; -use crate::model::{PlaylistEntry, PlaylistItemType, XtreamCluster}; +use shared::model::{PlaylistEntry, PlaylistItemType, XtreamCluster}; use crate::tools::atomic_once_flag::AtomicOnceFlag; use crate::tools::lru_cache::LRUResourceCache; use crate::utils::{DASH_EXT, HLS_EXT}; diff --git a/src/api/config_watch.rs b/backend/src/api/config_watch.rs similarity index 100% rename from src/api/config_watch.rs rename to backend/src/api/config_watch.rs diff --git a/src/api/endpoints/api_playlist_utils.rs b/backend/src/api/endpoints/api_playlist_utils.rs similarity index 98% rename from src/api/endpoints/api_playlist_utils.rs rename to backend/src/api/endpoints/api_playlist_utils.rs index 5dab9e45e..53f78e3c1 100644 --- a/src/api/endpoints/api_playlist_utils.rs +++ b/backend/src/api/endpoints/api_playlist_utils.rs @@ -1,5 +1,6 @@ use crate::model::{Config, ConfigInput, ConfigTarget, InputType, TargetType}; -use crate::model::{M3uPlaylistItem, PlaylistGroup, PlaylistItemType, XtreamCluster}; +use crate::model::{M3uPlaylistItem, PlaylistGroup}; +use shared::model::{PlaylistItemType, XtreamCluster}; use crate::repository::{m3u_repository, xtream_repository}; use crate::utils::{m3u, xtream}; use axum::response::IntoResponse; diff --git a/src/api/endpoints/download_api.rs b/backend/src/api/endpoints/download_api.rs similarity index 100% rename from src/api/endpoints/download_api.rs rename to backend/src/api/endpoints/download_api.rs diff --git a/src/api/endpoints/hdhomerun_api.rs b/backend/src/api/endpoints/hdhomerun_api.rs similarity index 99% rename from src/api/endpoints/hdhomerun_api.rs rename to backend/src/api/endpoints/hdhomerun_api.rs index 4951e9b0d..4db41ce9e 100644 --- a/src/api/endpoints/hdhomerun_api.rs +++ b/backend/src/api/endpoints/hdhomerun_api.rs @@ -2,7 +2,8 @@ use crate::api::model::app_state::HdHomerunAppState; use crate::auth::AuthBasic; use crate::model::ProxyUserCredentials; use crate::model::{Config, ConfigTarget, TargetType}; -use crate::model::{M3uPlaylistItem, PlaylistItemType, XtreamCluster, XtreamPlaylistItem}; +use crate::model::{M3uPlaylistItem, XtreamPlaylistItem}; +use shared::model::{PlaylistItemType, XtreamCluster}; use crate::processing::parser::xtream::get_xtream_url; use crate::repository::m3u_playlist_iterator::M3uPlaylistIterator; use crate::repository::xtream_playlist_iterator::XtreamPlaylistIterator; diff --git a/src/api/endpoints/hls_api.rs b/backend/src/api/endpoints/hls_api.rs similarity index 99% rename from src/api/endpoints/hls_api.rs rename to backend/src/api/endpoints/hls_api.rs index 79f818d96..a3e82c5f8 100644 --- a/src/api/endpoints/hls_api.rs +++ b/backend/src/api/endpoints/hls_api.rs @@ -4,7 +4,7 @@ use crate::api::model::app_state::AppState; use crate::api::model::streams::provider_stream::{create_custom_video_stream_response, CustomVideoStreamType}; use crate::model::{ProxyUserCredentials, UserConnectionPermission}; use crate::model::ConfigInput; -use crate::model::{PlaylistItemType, XtreamCluster}; +use shared::model::{PlaylistItemType, XtreamCluster}; use crate::processing::parser::hls::{get_hls_session_token_and_url_from_token, rewrite_hls, RewriteHlsProps}; use crate::utils::HLS_EXT; use crate::utils::request; diff --git a/src/api/endpoints/m3u_api.rs b/backend/src/api/endpoints/m3u_api.rs similarity index 99% rename from src/api/endpoints/m3u_api.rs rename to backend/src/api/endpoints/m3u_api.rs index da8b897d4..20561c444 100644 --- a/src/api/endpoints/m3u_api.rs +++ b/backend/src/api/endpoints/m3u_api.rs @@ -6,7 +6,7 @@ use crate::api::model::request::UserApiRequest; use crate::api::model::streams::provider_stream::{create_custom_video_stream_response, CustomVideoStreamType}; use crate::model::TargetType; use crate::model::UserConnectionPermission; -use crate::model::{FieldGetAccessor, PlaylistEntry, PlaylistItemType, XtreamCluster}; +use shared::model::{FieldGetAccessor, PlaylistEntry, PlaylistItemType, XtreamCluster}; use crate::repository::m3u_repository::{m3u_get_item_for_stream_id, m3u_load_rewrite_playlist}; use crate::repository::storage_const; use crate::utils::request::{extract_extension_from_url, sanitize_sensitive_info}; diff --git a/src/api/endpoints/mod.rs b/backend/src/api/endpoints/mod.rs similarity index 100% rename from src/api/endpoints/mod.rs rename to backend/src/api/endpoints/mod.rs diff --git a/src/api/endpoints/user_api.rs b/backend/src/api/endpoints/user_api.rs similarity index 99% rename from src/api/endpoints/user_api.rs rename to backend/src/api/endpoints/user_api.rs index 23e2804f9..b14147013 100644 --- a/src/api/endpoints/user_api.rs +++ b/backend/src/api/endpoints/user_api.rs @@ -2,7 +2,7 @@ use crate::api::api_utils::{get_user_target_by_username, get_username_from_auth_ use crate::api::model::app_state::AppState; use crate::auth::validator_user; use crate::model::{Config, ConfigTarget, TargetType}; -use crate::model::XtreamCluster; +use shared::model::XtreamCluster; use crate::model::PlaylistBouquetDto; use crate::model::PlaylistXtreamCategory; use crate::repository::user_repository::{load_user_bouquet_as_json, save_user_bouquet}; diff --git a/src/api/endpoints/v1_api.rs b/backend/src/api/endpoints/v1_api.rs similarity index 100% rename from src/api/endpoints/v1_api.rs rename to backend/src/api/endpoints/v1_api.rs diff --git a/src/api/endpoints/web_index.rs b/backend/src/api/endpoints/web_index.rs similarity index 100% rename from src/api/endpoints/web_index.rs rename to backend/src/api/endpoints/web_index.rs diff --git a/src/api/endpoints/xmltv_api.rs b/backend/src/api/endpoints/xmltv_api.rs similarity index 100% rename from src/api/endpoints/xmltv_api.rs rename to backend/src/api/endpoints/xmltv_api.rs diff --git a/src/api/endpoints/xtream_api.rs b/backend/src/api/endpoints/xtream_api.rs similarity index 99% rename from src/api/endpoints/xtream_api.rs rename to backend/src/api/endpoints/xtream_api.rs index 30efe3948..4e6d470ae 100644 --- a/src/api/endpoints/xtream_api.rs +++ b/backend/src/api/endpoints/xtream_api.rs @@ -10,16 +10,16 @@ use crate::api::model::request::UserApiRequest; use crate::api::model::streams::provider_stream::{create_custom_video_stream_response, CustomVideoStreamType}; use crate::api::model::xtream::XtreamAuthorizationResponse; use crate::model::TargetType; -use crate::model::{get_backdrop_path_value, FieldGetAccessor, PlaylistEntry, PlaylistItemType, XtreamCluster, XtreamPlaylistItem}; +use crate::model::{get_backdrop_path_value, XtreamPlaylistItem}; use crate::model::{Config, ConfigInput, ConfigTarget}; use crate::model::{ProxyType, ProxyUserCredentials, UserConnectionPermission}; use crate::repository::playlist_repository::get_target_id_mapping; -use crate::repository::storage::{get_target_storage_path, hex_encode}; +use crate::repository::storage::{get_target_storage_path}; use crate::repository::{storage_const, user_repository, xtream_repository}; use crate::tuliprox_error::create_tuliprox_error_result; use crate::tuliprox_error::info_err; use crate::tuliprox_error::{str_to_io_error, TuliproxError, TuliproxErrorKind}; -use crate::utils::generate_playlist_uuid; +use crate::utils::{generate_playlist_uuid, hex_encode}; use crate::utils::get_u32_from_serde_value; use crate::utils::request::{extract_extension_from_url, sanitize_sensitive_info}; use crate::utils::trace_if_enabled; @@ -41,6 +41,7 @@ use std::fmt::{Display, Formatter}; use std::path::Path; use std::str::FromStr; use std::sync::Arc; +use shared::model::{PlaylistItemType, XtreamCluster, FieldGetAccessor, PlaylistEntry}; #[derive(Serialize, Deserialize, Debug, Copy, Clone, Eq, PartialEq)] pub enum ApiStreamContext { diff --git a/src/api/main_api.rs b/backend/src/api/main_api.rs similarity index 100% rename from src/api/main_api.rs rename to backend/src/api/main_api.rs diff --git a/src/api/mod.rs b/backend/src/api/mod.rs similarity index 100% rename from src/api/mod.rs rename to backend/src/api/mod.rs diff --git a/src/api/model/active_provider_manager.rs b/backend/src/api/model/active_provider_manager.rs similarity index 100% rename from src/api/model/active_provider_manager.rs rename to backend/src/api/model/active_provider_manager.rs diff --git a/src/api/model/active_user_manager.rs b/backend/src/api/model/active_user_manager.rs similarity index 100% rename from src/api/model/active_user_manager.rs rename to backend/src/api/model/active_user_manager.rs diff --git a/src/api/model/app_state.rs b/backend/src/api/model/app_state.rs similarity index 100% rename from src/api/model/app_state.rs rename to backend/src/api/model/app_state.rs diff --git a/src/api/model/config.rs b/backend/src/api/model/config.rs similarity index 100% rename from src/api/model/config.rs rename to backend/src/api/model/config.rs diff --git a/src/api/model/download.rs b/backend/src/api/model/download.rs similarity index 98% rename from src/api/model/download.rs rename to backend/src/api/model/download.rs index 0ed865cfa..47beb38be 100644 --- a/src/api/model/download.rs +++ b/backend/src/api/model/download.rs @@ -7,7 +7,7 @@ use deunicode::deunicode; use serde::{Deserialize, Serialize}; use crate::model::{VideoDownloadConfig}; -use crate::repository::storage::hash_string_as_hex; +use crate::utils::hash_string_as_hex; use crate::utils::{CONSTANTS, FILENAME_TRIM_PATTERNS}; /// File-Download information. diff --git a/src/api/model/mod.rs b/backend/src/api/model/mod.rs similarity index 100% rename from src/api/model/mod.rs rename to backend/src/api/model/mod.rs diff --git a/src/api/model/model_utils.rs b/backend/src/api/model/model_utils.rs similarity index 100% rename from src/api/model/model_utils.rs rename to backend/src/api/model/model_utils.rs diff --git a/src/api/model/provider_config.rs b/backend/src/api/model/provider_config.rs similarity index 100% rename from src/api/model/provider_config.rs rename to backend/src/api/model/provider_config.rs diff --git a/src/api/model/request.rs b/backend/src/api/model/request.rs similarity index 100% rename from src/api/model/request.rs rename to backend/src/api/model/request.rs diff --git a/src/api/model/stream.rs b/backend/src/api/model/stream.rs similarity index 100% rename from src/api/model/stream.rs rename to backend/src/api/model/stream.rs diff --git a/src/api/model/stream_error.rs b/backend/src/api/model/stream_error.rs similarity index 100% rename from src/api/model/stream_error.rs rename to backend/src/api/model/stream_error.rs diff --git a/src/api/model/streams/active_client_stream.rs b/backend/src/api/model/streams/active_client_stream.rs similarity index 100% rename from src/api/model/streams/active_client_stream.rs rename to backend/src/api/model/streams/active_client_stream.rs diff --git a/src/api/model/streams/buffered_stream.rs b/backend/src/api/model/streams/buffered_stream.rs similarity index 100% rename from src/api/model/streams/buffered_stream.rs rename to backend/src/api/model/streams/buffered_stream.rs diff --git a/src/api/model/streams/client_stream.rs b/backend/src/api/model/streams/client_stream.rs similarity index 100% rename from src/api/model/streams/client_stream.rs rename to backend/src/api/model/streams/client_stream.rs diff --git a/src/api/model/streams/custom_video_stream.rs b/backend/src/api/model/streams/custom_video_stream.rs similarity index 100% rename from src/api/model/streams/custom_video_stream.rs rename to backend/src/api/model/streams/custom_video_stream.rs diff --git a/src/api/model/streams/mod.rs b/backend/src/api/model/streams/mod.rs similarity index 100% rename from src/api/model/streams/mod.rs rename to backend/src/api/model/streams/mod.rs diff --git a/src/api/model/streams/persist_pipe_stream.rs b/backend/src/api/model/streams/persist_pipe_stream.rs similarity index 100% rename from src/api/model/streams/persist_pipe_stream.rs rename to backend/src/api/model/streams/persist_pipe_stream.rs diff --git a/src/api/model/streams/provider_stream.rs b/backend/src/api/model/streams/provider_stream.rs similarity index 99% rename from src/api/model/streams/provider_stream.rs rename to backend/src/api/model/streams/provider_stream.rs index ed77c2855..01dbb27ba 100644 --- a/src/api/model/streams/provider_stream.rs +++ b/backend/src/api/model/streams/provider_stream.rs @@ -1,7 +1,7 @@ use crate::api::api_utils::{HeaderFilter}; use crate::api::model::streams::custom_video_stream::CustomVideoStream; use crate::model::{Config}; -use crate::model::PlaylistItemType; +use shared::model::PlaylistItemType; use log::{trace}; use reqwest::StatusCode; use axum::response::IntoResponse; diff --git a/src/api/model/streams/provider_stream_factory.rs b/backend/src/api/model/streams/provider_stream_factory.rs similarity index 99% rename from src/api/model/streams/provider_stream_factory.rs rename to backend/src/api/model/streams/provider_stream_factory.rs index 250d19f0c..606bcf7f3 100644 --- a/src/api/model/streams/provider_stream_factory.rs +++ b/backend/src/api/model/streams/provider_stream_factory.rs @@ -6,7 +6,7 @@ use crate::api::model::streams::buffered_stream::BufferedStream; use crate::api::model::streams::client_stream::ClientStream; use crate::api::model::streams::provider_stream::{create_channel_unavailable_stream, get_header_filter_for_item_type}; use crate::api::model::streams::timed_client_stream::TimedClientStream; -use crate::model::PlaylistItemType; +use shared::model::PlaylistItemType; use crate::model::{Config, DEFAULT_USER_AGENT}; use crate::tools::atomic_once_flag::AtomicOnceFlag; use crate::utils::request::{classify_content_type, get_request_headers, sanitize_sensitive_info, MimeCategory}; diff --git a/src/api/model/streams/shared_stream_manager.rs b/backend/src/api/model/streams/shared_stream_manager.rs similarity index 100% rename from src/api/model/streams/shared_stream_manager.rs rename to backend/src/api/model/streams/shared_stream_manager.rs diff --git a/src/api/model/streams/throttled_stream.rs b/backend/src/api/model/streams/throttled_stream.rs similarity index 100% rename from src/api/model/streams/throttled_stream.rs rename to backend/src/api/model/streams/throttled_stream.rs diff --git a/src/api/model/streams/timed_client_stream.rs b/backend/src/api/model/streams/timed_client_stream.rs similarity index 100% rename from src/api/model/streams/timed_client_stream.rs rename to backend/src/api/model/streams/timed_client_stream.rs diff --git a/src/api/model/streams/transport_stream_buffer.rs b/backend/src/api/model/streams/transport_stream_buffer.rs similarity index 100% rename from src/api/model/streams/transport_stream_buffer.rs rename to backend/src/api/model/streams/transport_stream_buffer.rs diff --git a/src/api/model/xtream.rs b/backend/src/api/model/xtream.rs similarity index 100% rename from src/api/model/xtream.rs rename to backend/src/api/model/xtream.rs diff --git a/src/api/scheduler.rs b/backend/src/api/scheduler.rs similarity index 100% rename from src/api/scheduler.rs rename to backend/src/api/scheduler.rs diff --git a/src/api/serve.rs b/backend/src/api/serve.rs similarity index 100% rename from src/api/serve.rs rename to backend/src/api/serve.rs diff --git a/src/auth/access_token.rs b/backend/src/auth/access_token.rs similarity index 97% rename from src/auth/access_token.rs rename to backend/src/auth/access_token.rs index 4735b1fc7..af2cf3fef 100644 --- a/src/auth/access_token.rs +++ b/backend/src/auth/access_token.rs @@ -1,4 +1,4 @@ -use crate::repository::storage::{hex_decode, hex_encode}; +use crate::utils::{hex_decode, hex_encode}; use chrono::Utc; use serde::{Deserialize, Serialize}; diff --git a/src/auth/auth_basic.rs b/backend/src/auth/auth_basic.rs similarity index 100% rename from src/auth/auth_basic.rs rename to backend/src/auth/auth_basic.rs diff --git a/src/auth/auth_bearer.rs b/backend/src/auth/auth_bearer.rs similarity index 100% rename from src/auth/auth_bearer.rs rename to backend/src/auth/auth_bearer.rs diff --git a/src/auth/authenticator.rs b/backend/src/auth/authenticator.rs similarity index 100% rename from src/auth/authenticator.rs rename to backend/src/auth/authenticator.rs diff --git a/src/auth/fingerprint.rs b/backend/src/auth/fingerprint.rs similarity index 100% rename from src/auth/fingerprint.rs rename to backend/src/auth/fingerprint.rs diff --git a/src/auth/mod.rs b/backend/src/auth/mod.rs similarity index 100% rename from src/auth/mod.rs rename to backend/src/auth/mod.rs diff --git a/src/auth/password.rs b/backend/src/auth/password.rs similarity index 100% rename from src/auth/password.rs rename to backend/src/auth/password.rs diff --git a/src/auth/user.rs b/backend/src/auth/user.rs similarity index 100% rename from src/auth/user.rs rename to backend/src/auth/user.rs diff --git a/src/foundation/filter.pest b/backend/src/foundation/filter.pest similarity index 100% rename from src/foundation/filter.pest rename to backend/src/foundation/filter.pest diff --git a/src/foundation/filter.rs b/backend/src/foundation/filter.rs similarity index 99% rename from src/foundation/filter.rs rename to backend/src/foundation/filter.rs index e0b4e410c..951900e2c 100644 --- a/src/foundation/filter.rs +++ b/backend/src/foundation/filter.rs @@ -8,8 +8,8 @@ use pest::iterators::Pair; use pest::Parser; use std::cmp::Ordering; use std::collections::HashMap; -use crate::model::{FieldGetAccessor, FieldSetAccessor, ItemField}; -use crate::model::{PlaylistItem, PlaylistItemType}; +use shared::model::{FieldGetAccessor, FieldSetAccessor, PlaylistItemType}; +use crate::model::{PlaylistItem, ItemField}; use crate::tools::directed_graph::DirectedGraph; use crate::tuliprox_error::{create_tuliprox_error_result, info_err}; use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind}; diff --git a/src/foundation/mapper.pest b/backend/src/foundation/mapper.pest similarity index 100% rename from src/foundation/mapper.pest rename to backend/src/foundation/mapper.pest diff --git a/src/foundation/mapper.rs b/backend/src/foundation/mapper.rs similarity index 100% rename from src/foundation/mapper.rs rename to backend/src/foundation/mapper.rs diff --git a/src/foundation/mod.rs b/backend/src/foundation/mod.rs similarity index 100% rename from src/foundation/mod.rs rename to backend/src/foundation/mod.rs diff --git a/src/main.rs b/backend/src/main.rs similarity index 100% rename from src/main.rs rename to backend/src/main.rs diff --git a/src/messaging.rs b/backend/src/messaging.rs similarity index 100% rename from src/messaging.rs rename to backend/src/messaging.rs diff --git a/src/model/config.rs b/backend/src/model/config.rs similarity index 100% rename from src/model/config.rs rename to backend/src/model/config.rs diff --git a/src/model/config_api_proxy.rs b/backend/src/model/config_api_proxy.rs similarity index 99% rename from src/model/config_api_proxy.rs rename to backend/src/model/config_api_proxy.rs index fc76f21d0..c3f5ebfcf 100644 --- a/src/model/config_api_proxy.rs +++ b/backend/src/model/config_api_proxy.rs @@ -1,6 +1,6 @@ use crate::api::model::app_state::AppState; use crate::tuliprox_error::{create_tuliprox_error_result, info_err, TuliproxError, TuliproxErrorKind}; -use crate::model::{Config, ClusterFlags}; +use crate::model::{Config}; use crate::repository::user_repository::{backup_api_user_db_file, get_api_user_db_path, load_api_user, merge_api_user}; use crate::utils::{default_as_true, save_api_proxy}; use chrono::Local; @@ -12,7 +12,7 @@ use std::fmt::Display; use std::fs; use std::str::FromStr; use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use crate::model::PlaylistItemType; +use shared::model::{PlaylistItemType, ClusterFlags}; use crate::utils; #[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)] diff --git a/src/model/config_cache.rs b/backend/src/model/config_cache.rs similarity index 100% rename from src/model/config_cache.rs rename to backend/src/model/config_cache.rs diff --git a/src/model/config_download.rs b/backend/src/model/config_download.rs similarity index 100% rename from src/model/config_download.rs rename to backend/src/model/config_download.rs diff --git a/src/model/config_epg.rs b/backend/src/model/config_epg.rs similarity index 100% rename from src/model/config_epg.rs rename to backend/src/model/config_epg.rs diff --git a/src/model/config_hdhomerun.rs b/backend/src/model/config_hdhomerun.rs similarity index 100% rename from src/model/config_hdhomerun.rs rename to backend/src/model/config_hdhomerun.rs diff --git a/src/model/config_healthcheck.rs b/backend/src/model/config_healthcheck.rs similarity index 100% rename from src/model/config_healthcheck.rs rename to backend/src/model/config_healthcheck.rs diff --git a/src/model/config_input.rs b/backend/src/model/config_input.rs similarity index 100% rename from src/model/config_input.rs rename to backend/src/model/config_input.rs diff --git a/src/model/config_ip_check.rs b/backend/src/model/config_ip_check.rs similarity index 100% rename from src/model/config_ip_check.rs rename to backend/src/model/config_ip_check.rs diff --git a/src/model/config_log.rs b/backend/src/model/config_log.rs similarity index 100% rename from src/model/config_log.rs rename to backend/src/model/config_log.rs diff --git a/src/model/config_messaging.rs b/backend/src/model/config_messaging.rs similarity index 100% rename from src/model/config_messaging.rs rename to backend/src/model/config_messaging.rs diff --git a/src/model/config_proxy.rs b/backend/src/model/config_proxy.rs similarity index 100% rename from src/model/config_proxy.rs rename to backend/src/model/config_proxy.rs diff --git a/src/model/config_rename.rs b/backend/src/model/config_rename.rs similarity index 100% rename from src/model/config_rename.rs rename to backend/src/model/config_rename.rs diff --git a/src/model/config_sort.rs b/backend/src/model/config_sort.rs similarity index 100% rename from src/model/config_sort.rs rename to backend/src/model/config_sort.rs diff --git a/src/model/config_source.rs b/backend/src/model/config_source.rs similarity index 100% rename from src/model/config_source.rs rename to backend/src/model/config_source.rs diff --git a/src/model/config_target.rs b/backend/src/model/config_target.rs similarity index 98% rename from src/model/config_target.rs rename to backend/src/model/config_target.rs index 90fb4d6fc..dd5c40eb8 100644 --- a/src/model/config_target.rs +++ b/backend/src/model/config_target.rs @@ -1,19 +1,30 @@ use crate::foundation::filter::{get_filter, Filter, PatternTemplate, ValueProvider}; -use crate::tuliprox_error::{create_tuliprox_error_result, handle_tuliprox_error_result_list, info_err, TuliproxError, TuliproxErrorKind}; -use crate::model::cluster_flags::ClusterFlags; use crate::model::config_rename::ConfigRename; use crate::model::config_sort::ConfigSort; use crate::model::mapping::Mapping; use crate::model::processing_order::ProcessingOrder; -use crate::model::PlaylistItemType; use crate::model::trakt::TraktConfig; +use crate::tuliprox_error::{create_tuliprox_error_result, handle_tuliprox_error_result_list, info_err, TuliproxError, TuliproxErrorKind}; use crate::utils::{default_as_default, default_as_true, default_resolve_delay_secs}; +use arc_swap::ArcSwapOption; use enum_iterator::Sequence; +use shared::model::ClusterFlags; +use shared::model::PlaylistItemType; use std::fmt::Display; use std::sync::Arc; -use arc_swap::{ArcSwapOption}; -#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, Sequence, PartialEq, Eq, Hash, Default)] +#[derive( + Debug, + Copy, + Clone, + serde::Serialize, + serde::Deserialize, + Sequence, + PartialEq, + Eq, + Hash, + Default +)] pub enum ExportStyle { #[serde(rename = "kodi")] #[default] @@ -184,7 +195,7 @@ pub enum TargetOutput { impl TargetOutput { pub fn prepare(&mut self) { - match self { + match self { TargetOutput::Xtream(output) => output.prepare(), TargetOutput::M3u(_) | TargetOutput::Strm(_) @@ -257,7 +268,7 @@ impl ConfigTarget { m3u_output.filename = m3u_output.filename.as_ref().map(|s| s.trim().to_string()); } TargetOutput::Strm(strm_output) => { - strm_cnt +=1; + strm_cnt += 1; strm_output.directory = strm_output.directory.trim().to_string(); if strm_output.directory.trim().is_empty() { return create_tuliprox_error_result!(TuliproxErrorKind::Info, "directory is required for strm type: {}", self.name); diff --git a/src/model/config_web_auth.rs b/backend/src/model/config_web_auth.rs similarity index 100% rename from src/model/config_web_auth.rs rename to backend/src/model/config_web_auth.rs diff --git a/src/model/config_webui.rs b/backend/src/model/config_webui.rs similarity index 100% rename from src/model/config_webui.rs rename to backend/src/model/config_webui.rs diff --git a/src/model/healthcheck.rs b/backend/src/model/healthcheck.rs similarity index 100% rename from src/model/healthcheck.rs rename to backend/src/model/healthcheck.rs diff --git a/src/model/mapping.rs b/backend/src/model/mapping.rs similarity index 100% rename from src/model/mapping.rs rename to backend/src/model/mapping.rs diff --git a/src/model/mod.rs b/backend/src/model/mod.rs similarity index 91% rename from src/model/mod.rs rename to backend/src/model/mod.rs index c3d9e33c8..1591fb34e 100644 --- a/src/model/mod.rs +++ b/backend/src/model/mod.rs @@ -14,7 +14,6 @@ mod config_ip_check; mod config_sort; mod config_rename; mod processing_order; -mod cluster_flags; mod config_target; mod config_source; mod config_proxy; @@ -29,8 +28,6 @@ mod config_healthcheck; mod config_cache; mod trakt; -// Re-export modules for easier access -pub use self::config_cache::*; pub use self::config::*; pub use self::playlist::*; pub use self::mapping::*; @@ -46,7 +43,6 @@ pub use self::config_ip_check::*; pub use self::config_sort::*; pub use self::config_rename::*; pub use self::processing_order::*; -pub use self::cluster_flags::*; pub use self::config_target::*; pub use self::config_source::*; pub use self::config_proxy::*; diff --git a/src/model/playlist.rs b/backend/src/model/playlist.rs similarity index 81% rename from src/model/playlist.rs rename to backend/src/model/playlist.rs index 20cb51ccc..e2d732fac 100644 --- a/src/model/playlist.rs +++ b/backend/src/model/playlist.rs @@ -1,28 +1,16 @@ use crate::model::xtream::{xtream_playlistitem_to_document, XtreamMappingOptions}; use crate::model::xtream_const; -use crate::model::ProxyUserCredentials; -use crate::model::TVGuide; -use crate::model::{ConfigInput, ConfigTargetOptions}; +use crate::model::{TVGuide, ProxyUserCredentials, ConfigInput, ConfigTargetOptions}; use crate::utils::request::extract_extension_from_url; use crate::utils::{generate_playlist_uuid, get_provider_id}; use crate::utils::{get_string_from_serde_value, get_u64_from_serde_value}; use serde::{Deserialize, Serialize}; use serde_json::{Map, Value}; use std::borrow::Cow; -use std::cmp::PartialEq; -use std::fmt::{Display, Formatter}; -use std::str::FromStr; +use shared::model::{PlaylistEntry, PlaylistItemType, UUIDType, XtreamCluster}; // https://de.wikipedia.org/wiki/M3U // https://siptv.eu/howto/playlist.html -pub trait PlaylistEntry: Send + Sync { - fn get_virtual_id(&self) -> u32; - fn get_provider_id(&self) -> Option; - fn get_category_id(&self) -> Option; - fn get_provider_url(&self) -> String; - fn get_uuid(&self) -> UUIDType; - fn get_item_type(&self) -> PlaylistItemType; -} #[derive(Debug, Clone)] pub struct FetchedPlaylist<'a> { // Contains playlist for one input @@ -42,120 +30,6 @@ impl FetchedPlaylist<'_> { } } -#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, Serialize, Deserialize, Default)] -#[repr(u8)] -pub enum XtreamCluster { - #[default] - Live = 1, - Video = 2, - Series = 3, -} - -impl XtreamCluster { - pub const fn as_str(&self) -> &str { - match self { - Self::Live => "Live", - Self::Video => "Video", - Self::Series => "Series", - } - } - pub const fn as_stream_type(&self) -> &str { - match self { - Self::Live => "live", - Self::Video => "movie", - Self::Series => "series", - } - } -} - -impl Display for XtreamCluster { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.as_str()) - } -} - -impl TryFrom for XtreamCluster { - type Error = String; - fn try_from(item_type: PlaylistItemType) -> Result { - match item_type { - PlaylistItemType::Live | PlaylistItemType::LiveHls | PlaylistItemType::LiveDash | PlaylistItemType::LiveUnknown => Ok(Self::Live), - PlaylistItemType::Catchup | PlaylistItemType::Video => Ok(Self::Video), - PlaylistItemType::Series | PlaylistItemType::SeriesInfo => Ok(Self::Series), - } - } -} - -#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, Serialize, Deserialize, Default)] -#[repr(u8)] -pub enum PlaylistItemType { - #[default] - Live = 1, - Video = 2, - Series = 3, // xtream series description - SeriesInfo = 4, // xtream series info fetched for series description - Catchup = 5, - LiveUnknown = 6, // No Provider id - LiveHls = 7, // m3u8 entry - LiveDash = 8, // mpd -} - -impl From for PlaylistItemType { - fn from(xtream_cluster: XtreamCluster) -> Self { - match xtream_cluster { - XtreamCluster::Live => Self::Live, - XtreamCluster::Video => Self::Video, - XtreamCluster::Series => Self::SeriesInfo, - } - } -} - - -impl FromStr for PlaylistItemType { - type Err = String; - - fn from_str(s: &str) -> Result { - match s { - "Live" => Ok(PlaylistItemType::Live), - "Video" => Ok(PlaylistItemType::Video), - "Series" => Ok(PlaylistItemType::Series), - "SeriesInfo" => Ok(PlaylistItemType::SeriesInfo), - "Catchup" => Ok(PlaylistItemType::Catchup), - "LiveUnknown" => Ok(PlaylistItemType::LiveUnknown), - "LiveHls" => Ok(PlaylistItemType::LiveHls), - "LiveDash" => Ok(PlaylistItemType::LiveDash), - _ => Err(format!("Invalid PlaylistItemType: {s}")), - } - } -} - -impl PlaylistItemType { - const LIVE: &'static str = "live"; - const VIDEO: &'static str = "video"; - const SERIES: &'static str = "series"; - const SERIES_INFO: &'static str = "series-info"; - const CATCHUP: &'static str = "catchup"; -} - -impl Display for PlaylistItemType { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", match self { - Self::Live | Self::LiveHls | Self::LiveDash | Self::LiveUnknown => Self::LIVE, - Self::Video => Self::VIDEO, - Self::Series => Self::SERIES, - Self::SeriesInfo => Self::SERIES_INFO, - Self::Catchup => Self::CATCHUP, - }) - } -} - -pub trait FieldGetAccessor { - fn get_field(&self, field: &str) -> Option>; -} -pub trait FieldSetAccessor { - fn set_field(&mut self, field: &str, value: &str) -> bool; -} - -pub type UUIDType = [u8; 32]; #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct PlaylistItemHeader { @@ -252,7 +126,7 @@ macro_rules! to_m3u_resource_non_empty_fields { macro_rules! generate_field_accessor_impl_for_playlist_item_header { ($($prop:ident),*;) => { - impl FieldGetAccessor for PlaylistItemHeader { + impl shared::model::FieldGetAccessor for PlaylistItemHeader { fn get_field(&self, field: &str) -> Option> { let field = field.to_lowercase(); match field.as_str() { @@ -267,7 +141,7 @@ macro_rules! generate_field_accessor_impl_for_playlist_item_header { } } } - impl FieldSetAccessor for PlaylistItemHeader { + impl shared::model::FieldSetAccessor for PlaylistItemHeader { fn set_field(&mut self, field: &str, value: &str) -> bool { let field = field.to_lowercase(); let val = String::from(value); @@ -379,7 +253,7 @@ impl PlaylistEntry for M3uPlaylistItem { macro_rules! generate_field_accessor_impl_for_m3u_playlist_item { ($($prop:ident),*;) => { - impl FieldGetAccessor for M3uPlaylistItem { + impl shared::model::FieldGetAccessor for M3uPlaylistItem { fn get_field(&self, field: &str) -> Option> { let field = field.to_lowercase(); match field.as_str() { @@ -490,7 +364,7 @@ pub fn get_backdrop_path_value<'a>(field: &'a str, value: Option<&'a Value>) -> macro_rules! generate_field_accessor_impl_for_xtream_playlist_item { ($($prop:ident),*;) => { - impl FieldGetAccessor for XtreamPlaylistItem { + impl shared::model::FieldGetAccessor for XtreamPlaylistItem { fn get_field(&self, field: &str) -> Option> { let field = field.to_lowercase(); match field.as_str() { diff --git a/src/model/playlist_categories.rs b/backend/src/model/playlist_categories.rs similarity index 100% rename from src/model/playlist_categories.rs rename to backend/src/model/playlist_categories.rs diff --git a/src/model/processing_order.rs b/backend/src/model/processing_order.rs similarity index 100% rename from src/model/processing_order.rs rename to backend/src/model/processing_order.rs diff --git a/src/model/serde_utils.rs b/backend/src/model/serde_utils.rs similarity index 100% rename from src/model/serde_utils.rs rename to backend/src/model/serde_utils.rs diff --git a/src/model/stats.rs b/backend/src/model/stats.rs similarity index 100% rename from src/model/stats.rs rename to backend/src/model/stats.rs diff --git a/src/model/trakt.rs b/backend/src/model/trakt.rs similarity index 100% rename from src/model/trakt.rs rename to backend/src/model/trakt.rs diff --git a/src/model/xmltv.rs b/backend/src/model/xmltv.rs similarity index 100% rename from src/model/xmltv.rs rename to backend/src/model/xmltv.rs diff --git a/src/model/xtream.rs b/backend/src/model/xtream.rs similarity index 99% rename from src/model/xtream.rs rename to backend/src/model/xtream.rs index daf9f775f..0a46a3372 100644 --- a/src/model/xtream.rs +++ b/backend/src/model/xtream.rs @@ -1,6 +1,6 @@ use crate::model::{ProxyUserCredentials}; -use crate::model::{Config, ConfigTarget, ClusterFlags, XtreamTargetOutput}; -use crate::model::{PlaylistEntry, PlaylistItem, XtreamCluster, XtreamPlaylistItem}; +use crate::model::{Config, ConfigTarget, XtreamTargetOutput}; +use crate::model::{PlaylistItem,XtreamPlaylistItem}; use crate::model::serde_utils::{deserialize_as_option_rc_string, deserialize_as_rc_string, deserialize_as_string_array, deserialize_number_from_string}; use crate::model::xtream_const; use crate::utils::{get_non_empty_str, opt_string_or_number_u32, string_default_on_null, string_or_number_f64, string_or_number_u32}; @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; use serde_json::{Map, Value}; use std::collections::HashMap; use std::iter::FromIterator; - +use shared::model::{ClusterFlags, PlaylistEntry, XtreamCluster}; #[derive(Deserialize, Default)] pub struct XtreamCategory { diff --git a/src/model/xtream_const.rs b/backend/src/model/xtream_const.rs similarity index 100% rename from src/model/xtream_const.rs rename to backend/src/model/xtream_const.rs diff --git a/src/modules.rs b/backend/src/modules.rs similarity index 100% rename from src/modules.rs rename to backend/src/modules.rs diff --git a/src/processing/mod.rs b/backend/src/processing/mod.rs similarity index 100% rename from src/processing/mod.rs rename to backend/src/processing/mod.rs diff --git a/src/processing/parser/hls.rs b/backend/src/processing/parser/hls.rs similarity index 100% rename from src/processing/parser/hls.rs rename to backend/src/processing/parser/hls.rs diff --git a/src/processing/parser/m3u.rs b/backend/src/processing/parser/m3u.rs similarity index 99% rename from src/processing/parser/m3u.rs rename to backend/src/processing/parser/m3u.rs index 992dbd69e..2b2d0b339 100644 --- a/src/processing/parser/m3u.rs +++ b/backend/src/processing/parser/m3u.rs @@ -1,6 +1,7 @@ use std::borrow::BorrowMut; +use shared::model::{PlaylistItemType, XtreamCluster}; use crate::model::{Config, ConfigInput}; -use crate::model::{PlaylistGroup, PlaylistItem, PlaylistItemHeader, PlaylistItemType, XtreamCluster}; +use crate::model::{PlaylistGroup, PlaylistItem, PlaylistItemHeader}; use crate::utils::{extract_id_from_url, get_title_group}; #[inline] diff --git a/src/processing/parser/mod.rs b/backend/src/processing/parser/mod.rs similarity index 100% rename from src/processing/parser/mod.rs rename to backend/src/processing/parser/mod.rs diff --git a/src/processing/parser/xmltv.rs b/backend/src/processing/parser/xmltv.rs similarity index 100% rename from src/processing/parser/xmltv.rs rename to backend/src/processing/parser/xmltv.rs diff --git a/src/processing/parser/xtream.rs b/backend/src/processing/parser/xtream.rs similarity index 99% rename from src/processing/parser/xtream.rs rename to backend/src/processing/parser/xtream.rs index 6df5ec879..e1c22e9a3 100644 --- a/src/processing/parser/xtream.rs +++ b/backend/src/processing/parser/xtream.rs @@ -1,12 +1,13 @@ use crate::tuliprox_error::{create_tuliprox_error_result, TuliproxError, TuliproxErrorKind}; use crate::model::ConfigInput; -use crate::model::{PlaylistGroup, PlaylistItem, PlaylistItemHeader, PlaylistItemType, XtreamCluster}; +use crate::model::{PlaylistGroup, PlaylistItem, PlaylistItemHeader}; use crate::model::{XtreamCategory, XtreamSeriesInfo, XtreamSeriesInfoEpisode, XtreamStream}; use crate::utils::generate_playlist_uuid; use crate::utils::xtream::{get_xtream_stream_url_base}; use serde_json::Value; use std::collections::HashMap; use std::sync::Arc; +use shared::model::{PlaylistItemType, XtreamCluster}; fn map_to_xtream_category(categories: &Value) -> Result, TuliproxError> { match serde_json::from_value::>(categories.to_owned()) { diff --git a/src/processing/playlist_watch.rs b/backend/src/processing/playlist_watch.rs similarity index 100% rename from src/processing/playlist_watch.rs rename to backend/src/processing/playlist_watch.rs diff --git a/src/processing/processor/affix.rs b/backend/src/processing/processor/affix.rs similarity index 100% rename from src/processing/processor/affix.rs rename to backend/src/processing/processor/affix.rs diff --git a/src/processing/processor/epg.rs b/backend/src/processing/processor/epg.rs similarity index 99% rename from src/processing/processor/epg.rs rename to backend/src/processing/processor/epg.rs index 30557c6cd..5509bd9fb 100644 --- a/src/processing/processor/epg.rs +++ b/backend/src/processing/processor/epg.rs @@ -1,11 +1,13 @@ use crate::model::{Epg, TVGuide, XmlTag, XmlTagIcon, EPG_ATTRIB_ID}; use crate::model::{EpgConfig, EpgSmartMatchConfig}; -use crate::model::{FetchedPlaylist, PlaylistItem, XtreamCluster}; +use crate::model::{FetchedPlaylist, PlaylistItem}; use crate::processing::parser::xmltv::normalize_channel_name; use log::{debug, trace}; use rphonetic::{DoubleMetaphone, Encoder}; use std::borrow::Cow; use std::collections::{HashMap, HashSet}; +use shared::model::XtreamCluster; + pub struct EpgIdCache<'a> { pub channel_epg_id: HashSet>, pub normalized: HashMap>, diff --git a/src/processing/processor/mod.rs b/backend/src/processing/processor/mod.rs similarity index 100% rename from src/processing/processor/mod.rs rename to backend/src/processing/processor/mod.rs diff --git a/src/processing/processor/playlist.rs b/backend/src/processing/processor/playlist.rs similarity index 99% rename from src/processing/processor/playlist.rs rename to backend/src/processing/processor/playlist.rs index 8f0e0a824..26bd1cd67 100644 --- a/src/processing/processor/playlist.rs +++ b/backend/src/processing/processor/playlist.rs @@ -13,7 +13,8 @@ use crate::foundation::filter::{get_field_value, set_field_value, ValueProvider, use crate::messaging::{send_message, MsgKind}; use crate::model::{ConfigTarget, InputType, ItemField, ProcessTargets, ProcessingOrder}; use crate::model::{CounterModifier, Mapping}; -use crate::model::{FetchedPlaylist, FieldGetAccessor, FieldSetAccessor, PlaylistEntry, PlaylistGroup, PlaylistItem, UUIDType, XtreamCluster}; +use crate::model::{FetchedPlaylist, PlaylistGroup, PlaylistItem}; +use shared::model::{FieldGetAccessor, FieldSetAccessor, PlaylistEntry, UUIDType, XtreamCluster}; use crate::model::{InputStats, PlaylistStats, SourceStats, TargetStats}; use crate::processing::playlist_watch::process_group_watch; use crate::processing::processor::xtream_series::playlist_resolve_series; diff --git a/src/processing/processor/sort.rs b/backend/src/processing/processor/sort.rs similarity index 100% rename from src/processing/processor/sort.rs rename to backend/src/processing/processor/sort.rs diff --git a/src/processing/processor/trakt.rs b/backend/src/processing/processor/trakt.rs similarity index 98% rename from src/processing/processor/trakt.rs rename to backend/src/processing/processor/trakt.rs index a041a32e1..97d37fa61 100644 --- a/src/processing/processor/trakt.rs +++ b/backend/src/processing/processor/trakt.rs @@ -1,5 +1,6 @@ use std::borrow::Cow; -use crate::model::{ConfigTarget, FieldGetAccessor, FieldSetAccessor, PlaylistGroup, PlaylistItem, XtreamCluster}; +use crate::model::{ConfigTarget, PlaylistGroup, PlaylistItem}; +use shared::model::{FieldGetAccessor, FieldSetAccessor, XtreamCluster}; use crate::model::{TraktConfig, TraktContentType, TraktListConfig, TraktListItem, TraktMatchItem, TraktMatchResult}; use crate::tuliprox_error::TuliproxError; use crate::utils::trakt::client::TraktClient; diff --git a/src/processing/processor/xtream.rs b/backend/src/processing/processor/xtream.rs similarity index 97% rename from src/processing/processor/xtream.rs rename to backend/src/processing/processor/xtream.rs index 010d42152..a700a399e 100644 --- a/src/processing/processor/xtream.rs +++ b/backend/src/processing/processor/xtream.rs @@ -1,7 +1,8 @@ use crate::tuliprox_error::{info_err, notify_err}; use crate::tuliprox_error::{str_to_io_error, TuliproxError, TuliproxErrorKind}; use crate::model::{Config, ConfigInput}; -use crate::model::{FetchedPlaylist, PlaylistEntry, PlaylistItem, PlaylistItemType, XtreamCluster}; +use crate::model::{FetchedPlaylist, PlaylistItem}; +use shared::model::{PlaylistEntry, PlaylistItemType, XtreamCluster}; use crate::model::normalize_release_date; use crate::repository::storage::get_input_storage_path; use serde::{Deserialize, Serialize}; diff --git a/src/processing/processor/xtream_series.rs b/backend/src/processing/processor/xtream_series.rs similarity index 98% rename from src/processing/processor/xtream_series.rs rename to backend/src/processing/processor/xtream_series.rs index f8f3b00a9..cc040229e 100644 --- a/src/processing/processor/xtream_series.rs +++ b/backend/src/processing/processor/xtream_series.rs @@ -1,6 +1,7 @@ use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind}; use crate::model::{Config, ConfigTarget, InputType}; -use crate::model::{FetchedPlaylist, PlaylistGroup, PlaylistItem, PlaylistItemType, XtreamCluster}; +use crate::model::{FetchedPlaylist, PlaylistGroup, PlaylistItem}; +use shared::model::{PlaylistItemType, XtreamCluster}; use crate::processing::processor::playlist::ProcessingPipe; use crate::processing::parser::xtream::parse_xtream_series_info; use crate::processing::processor::xtream::{create_resolve_episode_wal_files, create_resolve_info_wal_files, playlist_resolve_download_playlist_item, read_processed_info_ids, should_update_info}; diff --git a/src/processing/processor/xtream_vod.rs b/backend/src/processing/processor/xtream_vod.rs similarity index 98% rename from src/processing/processor/xtream_vod.rs rename to backend/src/processing/processor/xtream_vod.rs index eced6e37e..7aa0d7ffb 100644 --- a/src/processing/processor/xtream_vod.rs +++ b/backend/src/processing/processor/xtream_vod.rs @@ -1,6 +1,7 @@ use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind}; use crate::model::{Config, ConfigTarget, InputType}; -use crate::model::{FetchedPlaylist, PlaylistItem, PlaylistItemType, XtreamCluster}; +use crate::model::{FetchedPlaylist, PlaylistItem}; +use shared::model::{PlaylistItemType, XtreamCluster}; use crate::processing::processor::xtream::{create_resolve_info_wal_files, playlist_resolve_download_playlist_item, read_processed_info_ids, should_update_info}; use crate::repository::xtream_repository::{write_vod_info_to_wal_file, xtream_update_input_info_file, xtream_update_input_vod_record_from_wal_file, InputVodInfoRecord}; use crate::tuliprox_error::{notify_err}; diff --git a/src/repository/bplustree.rs b/backend/src/repository/bplustree.rs similarity index 100% rename from src/repository/bplustree.rs rename to backend/src/repository/bplustree.rs diff --git a/src/repository/epg_repository.rs b/backend/src/repository/epg_repository.rs similarity index 100% rename from src/repository/epg_repository.rs rename to backend/src/repository/epg_repository.rs diff --git a/src/repository/indexed_document.rs b/backend/src/repository/indexed_document.rs similarity index 100% rename from src/repository/indexed_document.rs rename to backend/src/repository/indexed_document.rs diff --git a/src/repository/m3u_playlist_iterator.rs b/backend/src/repository/m3u_playlist_iterator.rs similarity index 98% rename from src/repository/m3u_playlist_iterator.rs rename to backend/src/repository/m3u_playlist_iterator.rs index 0bb9ade32..ff043bbca 100644 --- a/src/repository/m3u_playlist_iterator.rs +++ b/backend/src/repository/m3u_playlist_iterator.rs @@ -2,7 +2,8 @@ use crate::tuliprox_error::info_err; use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind}; use crate::model::{ProxyType, ProxyUserCredentials}; use crate::model::{Config, ConfigTarget, ConfigTargetOptions, TargetType}; -use crate::model::{M3uPlaylistItem, PlaylistItemType, XtreamCluster}; +use crate::model::{M3uPlaylistItem}; +use shared::model::{PlaylistItemType, XtreamCluster}; use crate::repository::indexed_document::IndexedDocumentIterator; use crate::repository::m3u_repository::m3u_get_file_paths; use crate::repository::storage::ensure_target_storage_path; diff --git a/src/repository/m3u_repository.rs b/backend/src/repository/m3u_repository.rs similarity index 98% rename from src/repository/m3u_repository.rs rename to backend/src/repository/m3u_repository.rs index 2693aaacd..4fb1919ad 100644 --- a/src/repository/m3u_repository.rs +++ b/backend/src/repository/m3u_repository.rs @@ -2,7 +2,7 @@ use crate::tuliprox_error::{create_tuliprox_error,info_err}; use crate::tuliprox_error::{str_to_io_error, TuliproxError, TuliproxErrorKind}; use crate::model::ProxyUserCredentials; use crate::model::{Config, ConfigTarget, M3uTargetOutput}; -use crate::model::{M3uPlaylistItem, PlaylistGroup, PlaylistItem, PlaylistItemType}; +use crate::model::{M3uPlaylistItem, PlaylistGroup, PlaylistItem}; use crate::repository::indexed_document::{IndexedDocumentDirectAccess, IndexedDocumentIterator, IndexedDocumentWriter}; use crate::repository::m3u_playlist_iterator::{M3uPlaylistM3uTextIterator}; use crate::repository::storage::{get_target_storage_path}; @@ -11,6 +11,7 @@ use std::fs::File; use std::io::{Error, Write}; use std::path::{Path, PathBuf}; use std::sync::Arc; +use shared::model::PlaylistItemType; use crate::repository::storage_const; use crate::utils; diff --git a/src/repository/mod.rs b/backend/src/repository/mod.rs similarity index 100% rename from src/repository/mod.rs rename to backend/src/repository/mod.rs diff --git a/src/repository/playlist_repository.rs b/backend/src/repository/playlist_repository.rs similarity index 97% rename from src/repository/playlist_repository.rs rename to backend/src/repository/playlist_repository.rs index de1f2bd55..76d854fd7 100644 --- a/src/repository/playlist_repository.rs +++ b/backend/src/repository/playlist_repository.rs @@ -1,7 +1,8 @@ use crate::tuliprox_error::info_err; use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind}; use crate::model::{Config, ConfigTarget, TargetOutput}; -use crate::model::{PlaylistGroup, PlaylistItemType}; +use crate::model::{PlaylistGroup}; +use shared::model::{PlaylistItemType}; use crate::model::Epg; use crate::repository::epg_repository::epg_write; use crate::repository::strm_repository::write_strm_playlist; diff --git a/src/repository/storage.rs b/backend/src/repository/storage.rs similarity index 58% rename from src/repository/storage.rs rename to backend/src/repository/storage.rs index d35ef38ef..e0ba51733 100644 --- a/src/repository/storage.rs +++ b/backend/src/repository/storage.rs @@ -1,55 +1,10 @@ use std::path::{Path, PathBuf}; -use std::fmt::Write; use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind}; use crate::model::{Config}; -use crate::model::UUIDType; use crate::tuliprox_error::{notify_err}; use crate::repository::storage_const; use crate::utils; -#[inline] -pub fn hash_bytes(bytes: &[u8]) -> UUIDType { - blake3::hash(bytes).into() -} - -/// generates a hash from a string -#[inline] -pub fn hash_string(text: &str) -> UUIDType { - hash_bytes(text.as_bytes()) -} - -pub fn short_hash(text: &str) -> String { - let hash = blake3::hash(text.as_bytes()); - hex_encode(&hash.as_bytes()[..8]) -} - - -#[inline] -pub fn hex_encode(bytes: &[u8]) -> String { - bytes.iter().fold(String::new(), |mut output, b| { - let _ = write!(output, "{b:02X}"); - output - }) -} - -pub fn hex_decode(hex: &str) -> Result, String> { - if hex.len() % 2 != 0 { - return Err("hex string must have even length".to_string()); - } - - (0..hex.len()) - .step_by(2) - .map(|i| { - u8::from_str_radix(&hex[i..i+2], 16) - .map_err(|e| format!("invalid hex at position {i}: {e}")) - }) - .collect() -} - -pub fn hash_string_as_hex(url: &str) -> String { - hex_encode(&hash_string(url)) -} - pub(in crate::repository) fn get_target_id_mapping_file(target_path: &Path) -> PathBuf { target_path.join(PathBuf::from(storage_const::FILE_ID_MAPPING)) } diff --git a/src/repository/storage_const.rs b/backend/src/repository/storage_const.rs similarity index 100% rename from src/repository/storage_const.rs rename to backend/src/repository/storage_const.rs diff --git a/src/repository/strm_repository.rs b/backend/src/repository/strm_repository.rs similarity index 99% rename from src/repository/strm_repository.rs rename to backend/src/repository/strm_repository.rs index 9b922aaec..2db20989e 100644 --- a/src/repository/strm_repository.rs +++ b/backend/src/repository/strm_repository.rs @@ -1,16 +1,15 @@ use crate::tuliprox_error::{create_tuliprox_error_result, info_err}; use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind}; use crate::model::{ApiProxyServerInfo, ProxyUserCredentials}; -use crate::model::{ClusterFlags, Config, ConfigTarget, StrmTargetOutput}; -use crate::model::{ - FieldGetAccessor, PlaylistGroup, PlaylistItem, PlaylistItemType, UUIDType, ExportStyle, +use crate::model::{Config, ConfigTarget, StrmTargetOutput}; +use crate::model::{PlaylistGroup, PlaylistItem, ExportStyle, }; use crate::model::XtreamSeriesEpisode; use crate::repository::bplustree::BPlusTree; -use crate::repository::storage::{ensure_target_storage_path, get_input_storage_path, hash_bytes}; +use crate::repository::storage::{ensure_target_storage_path, get_input_storage_path}; use crate::repository::storage_const; use crate::repository::xtream_repository::{xtream_get_record_file_path, InputVodInfoRecord}; -use crate::utils::{ExportStyleConfig, CONSTANTS}; +use crate::utils::{hash_bytes, ExportStyleConfig, CONSTANTS}; use crate::utils::FileReadGuard; use crate::utils::request::extract_extension_from_url; use chrono::Datelike; @@ -23,6 +22,7 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use tokio::fs::{create_dir_all, remove_dir, remove_file, File}; use tokio::io::{AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader, BufWriter}; +use shared::model::{ClusterFlags, FieldGetAccessor, PlaylistItemType, UUIDType}; use crate::utils; /// Sanitizes a string to be safe for use as a file or directory name by diff --git a/src/repository/target_id_mapping.rs b/backend/src/repository/target_id_mapping.rs similarity index 99% rename from src/repository/target_id_mapping.rs rename to backend/src/repository/target_id_mapping.rs index 80971258a..ee6738c43 100644 --- a/src/repository/target_id_mapping.rs +++ b/backend/src/repository/target_id_mapping.rs @@ -7,7 +7,7 @@ use chrono::Local; use log::error; use serde::{Deserialize, Serialize}; -use crate::model::{PlaylistItemType, UUIDType}; +use shared::model::{PlaylistItemType, UUIDType}; use crate::repository::bplustree::BPlusTree; // TODO make configurable diff --git a/src/repository/user_repository.rs b/backend/src/repository/user_repository.rs similarity index 99% rename from src/repository/user_repository.rs rename to backend/src/repository/user_repository.rs index edddbb5cc..b3ab1fc9d 100644 --- a/src/repository/user_repository.rs +++ b/backend/src/repository/user_repository.rs @@ -1,6 +1,6 @@ use crate::model::{ProxyType, ProxyUserCredentials, ProxyUserStatus, TargetUser}; use crate::model::{Config, TargetType}; -use crate::model::XtreamCluster; +use shared::model::XtreamCluster; use crate::model::{PlaylistBouquetDto, TargetBouquetDto}; use crate::model::PlaylistXtreamCategory; use crate::repository::bplustree::BPlusTree; diff --git a/src/repository/xtream_playlist_iterator.rs b/backend/src/repository/xtream_playlist_iterator.rs similarity index 98% rename from src/repository/xtream_playlist_iterator.rs rename to backend/src/repository/xtream_playlist_iterator.rs index 513764e77..1be633ec8 100644 --- a/src/repository/xtream_playlist_iterator.rs +++ b/backend/src/repository/xtream_playlist_iterator.rs @@ -1,10 +1,11 @@ use std::collections::HashSet; use log::error; +use shared::model::XtreamCluster; use crate::tuliprox_error::info_err; use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind}; use crate::model::{ProxyUserCredentials}; use crate::model::{Config, ConfigTarget, TargetType}; -use crate::model::{XtreamCluster, XtreamPlaylistItem}; +use crate::model::{XtreamPlaylistItem}; use crate::model::XtreamMappingOptions; use crate::repository::indexed_document::{IndexedDocumentIterator}; use crate::repository::user_repository::user_get_bouquet_filter; diff --git a/src/repository/xtream_repository.rs b/backend/src/repository/xtream_repository.rs similarity index 99% rename from src/repository/xtream_repository.rs rename to backend/src/repository/xtream_repository.rs index 08897287b..0d73169f9 100644 --- a/src/repository/xtream_repository.rs +++ b/backend/src/repository/xtream_repository.rs @@ -1,13 +1,13 @@ use crate::tuliprox_error::{create_tuliprox_error, create_tuliprox_error_result, info_err, notify_err, str_to_io_error, to_io_error, TuliproxError, TuliproxErrorKind}; use crate::model::{ProxyUserCredentials}; use crate::model::{Config, ConfigInput, ConfigTarget, XtreamTargetOutput}; -use crate::model::{PlaylistEntry, PlaylistGroup, PlaylistItem, PlaylistItemType, XtreamCluster, XtreamPlaylistItem}; +use crate::model::{PlaylistGroup, PlaylistItem, XtreamPlaylistItem}; use crate::model::{rewrite_doc_urls, PlaylistXtreamCategory, XtreamMappingOptions, XtreamSeriesEpisode}; use crate::model::normalize_release_date; use crate::repository::bplustree::{BPlusTree, BPlusTreeQuery, BPlusTreeUpdate}; use crate::repository::indexed_document::{IndexedDocumentDirectAccess, IndexedDocumentGarbageCollector, IndexedDocumentIterator, IndexedDocumentWriter}; use crate::repository::playlist_repository::get_target_id_mapping; -use crate::repository::storage::hex_encode; +use crate::utils::hex_encode; use crate::repository::storage::{get_input_storage_path, get_target_id_mapping_file, get_target_storage_path}; use crate::repository::storage_const; use crate::repository::target_id_mapping::VirtualIdRecord; @@ -29,6 +29,7 @@ use std::fs::File; use std::io::{BufReader, BufWriter, Error, ErrorKind, Read, Write}; use std::path::{Path, PathBuf}; use std::sync::Arc; +use shared::model::{PlaylistEntry, PlaylistItemType, XtreamCluster}; macro_rules! cant_write_result { ($path:expr, $err:expr) => { diff --git a/src/tools/atomic_once_flag.rs b/backend/src/tools/atomic_once_flag.rs similarity index 100% rename from src/tools/atomic_once_flag.rs rename to backend/src/tools/atomic_once_flag.rs diff --git a/src/tools/directed_graph.rs b/backend/src/tools/directed_graph.rs similarity index 100% rename from src/tools/directed_graph.rs rename to backend/src/tools/directed_graph.rs diff --git a/src/tools/lru_cache.rs b/backend/src/tools/lru_cache.rs similarity index 98% rename from src/tools/lru_cache.rs rename to backend/src/tools/lru_cache.rs index f22f17fea..5d1002c69 100644 --- a/src/tools/lru_cache.rs +++ b/backend/src/tools/lru_cache.rs @@ -1,5 +1,4 @@ -use crate::repository::storage::hash_string_as_hex; -use crate::utils::traverse_dir; +use crate::utils::{hash_string_as_hex, traverse_dir}; use crate::utils::human_readable_byte_size; use log::{debug, error, info, trace}; use std::collections::{HashMap, VecDeque}; diff --git a/src/tools/mod.rs b/backend/src/tools/mod.rs similarity index 100% rename from src/tools/mod.rs rename to backend/src/tools/mod.rs diff --git a/src/tuliprox_error.rs b/backend/src/tuliprox_error.rs similarity index 100% rename from src/tuliprox_error.rs rename to backend/src/tuliprox_error.rs diff --git a/src/utils/bincode_utils.rs b/backend/src/utils/bincode_utils.rs similarity index 100% rename from src/utils/bincode_utils.rs rename to backend/src/utils/bincode_utils.rs diff --git a/src/utils/compression/compressed_file_reader.rs b/backend/src/utils/compression/compressed_file_reader.rs similarity index 100% rename from src/utils/compression/compressed_file_reader.rs rename to backend/src/utils/compression/compressed_file_reader.rs diff --git a/src/utils/compression/compression_utils.rs b/backend/src/utils/compression/compression_utils.rs similarity index 100% rename from src/utils/compression/compression_utils.rs rename to backend/src/utils/compression/compression_utils.rs diff --git a/src/utils/compression/mod.rs b/backend/src/utils/compression/mod.rs similarity index 100% rename from src/utils/compression/mod.rs rename to backend/src/utils/compression/mod.rs diff --git a/src/utils/constants.rs b/backend/src/utils/constants.rs similarity index 100% rename from src/utils/constants.rs rename to backend/src/utils/constants.rs diff --git a/src/utils/crypto_utils.rs b/backend/src/utils/crypto_utils.rs similarity index 100% rename from src/utils/crypto_utils.rs rename to backend/src/utils/crypto_utils.rs diff --git a/src/utils/default_utils.rs b/backend/src/utils/default_utils.rs similarity index 100% rename from src/utils/default_utils.rs rename to backend/src/utils/default_utils.rs diff --git a/src/utils/file/config_reader.rs b/backend/src/utils/file/config_reader.rs similarity index 100% rename from src/utils/file/config_reader.rs rename to backend/src/utils/file/config_reader.rs diff --git a/src/utils/file/csv_input_reader.rs b/backend/src/utils/file/csv_input_reader.rs similarity index 100% rename from src/utils/file/csv_input_reader.rs rename to backend/src/utils/file/csv_input_reader.rs diff --git a/src/utils/file/env_resolving_reader.rs b/backend/src/utils/file/env_resolving_reader.rs similarity index 100% rename from src/utils/file/env_resolving_reader.rs rename to backend/src/utils/file/env_resolving_reader.rs diff --git a/src/utils/file/file_lock_manager.rs b/backend/src/utils/file/file_lock_manager.rs similarity index 100% rename from src/utils/file/file_lock_manager.rs rename to backend/src/utils/file/file_lock_manager.rs diff --git a/src/utils/file/file_utils.rs b/backend/src/utils/file/file_utils.rs similarity index 100% rename from src/utils/file/file_utils.rs rename to backend/src/utils/file/file_utils.rs diff --git a/src/utils/file/mapping_reader.rs b/backend/src/utils/file/mapping_reader.rs similarity index 100% rename from src/utils/file/mapping_reader.rs rename to backend/src/utils/file/mapping_reader.rs diff --git a/src/utils/file/mod.rs b/backend/src/utils/file/mod.rs similarity index 100% rename from src/utils/file/mod.rs rename to backend/src/utils/file/mod.rs diff --git a/src/utils/file/multi_file_reader.rs b/backend/src/utils/file/multi_file_reader.rs similarity index 100% rename from src/utils/file/multi_file_reader.rs rename to backend/src/utils/file/multi_file_reader.rs diff --git a/src/utils/hash_utils.rs b/backend/src/utils/hash_utils.rs similarity index 56% rename from src/utils/hash_utils.rs rename to backend/src/utils/hash_utils.rs index 513c46510..f6ad81c21 100644 --- a/src/utils/hash_utils.rs +++ b/backend/src/utils/hash_utils.rs @@ -1,7 +1,50 @@ use base64::Engine; use base64::engine::general_purpose; -use crate::model::{PlaylistItemType, UUIDType}; -use crate::repository::storage::hash_string; +use shared::model::{PlaylistItemType, UUIDType}; +use std::fmt::Write; + +#[inline] +pub fn hash_bytes(bytes: &[u8]) -> UUIDType { + blake3::hash(bytes).into() +} + +/// generates a hash from a string +#[inline] +pub fn hash_string(text: &str) -> UUIDType { + hash_bytes(text.as_bytes()) +} + +pub fn short_hash(text: &str) -> String { + let hash = blake3::hash(text.as_bytes()); + hex_encode(&hash.as_bytes()[..8]) +} + + +#[inline] +pub fn hex_encode(bytes: &[u8]) -> String { + bytes.iter().fold(String::new(), |mut output, b| { + let _ = write!(output, "{b:02X}"); + output + }) +} + +pub fn hex_decode(hex: &str) -> Result, String> { + if hex.len() % 2 != 0 { + return Err("hex string must have even length".to_string()); + } + + (0..hex.len()) + .step_by(2) + .map(|i| { + u8::from_str_radix(&hex[i..i+2], 16) + .map_err(|e| format!("invalid hex at position {i}: {e}")) + }) + .collect() +} + +pub fn hash_string_as_hex(url: &str) -> String { + hex_encode(&hash_string(url)) +} pub fn extract_id_from_url(url: &str) -> Option { if let Some(possible_id_and_ext) = url.split('/').next_back() { diff --git a/src/utils/json_utils.rs b/backend/src/utils/json_utils.rs similarity index 100% rename from src/utils/json_utils.rs rename to backend/src/utils/json_utils.rs diff --git a/src/utils/logging.rs b/backend/src/utils/logging.rs similarity index 100% rename from src/utils/logging.rs rename to backend/src/utils/logging.rs diff --git a/src/utils/mod.rs b/backend/src/utils/mod.rs similarity index 100% rename from src/utils/mod.rs rename to backend/src/utils/mod.rs diff --git a/src/utils/network/epg.rs b/backend/src/utils/network/epg.rs similarity index 96% rename from src/utils/network/epg.rs rename to backend/src/utils/network/epg.rs index 89be19369..8f7bc85a4 100644 --- a/src/utils/network/epg.rs +++ b/backend/src/utils/network/epg.rs @@ -1,8 +1,7 @@ use crate::tuliprox_error::TuliproxError; use crate::model::{Config, ConfigInput, PersistedEpgSource}; use crate::model::TVGuide; -use crate::repository::storage::short_hash; -use crate::utils::{add_prefix_to_filename, cleanup_unlisted_files_with_suffix, prepare_file_path}; +use crate::utils::{add_prefix_to_filename, cleanup_unlisted_files_with_suffix, prepare_file_path, short_hash}; use crate::utils::request; use log::debug; use std::path::PathBuf; diff --git a/src/utils/network/ip_checker.rs b/backend/src/utils/network/ip_checker.rs similarity index 100% rename from src/utils/network/ip_checker.rs rename to backend/src/utils/network/ip_checker.rs diff --git a/src/utils/network/m3u.rs b/backend/src/utils/network/m3u.rs similarity index 100% rename from src/utils/network/m3u.rs rename to backend/src/utils/network/m3u.rs diff --git a/src/utils/network/mod.rs b/backend/src/utils/network/mod.rs similarity index 100% rename from src/utils/network/mod.rs rename to backend/src/utils/network/mod.rs diff --git a/src/utils/network/request.rs b/backend/src/utils/network/request.rs similarity index 99% rename from src/utils/network/request.rs rename to backend/src/utils/network/request.rs index 4a592c575..f99e4b7ae 100644 --- a/src/utils/network/request.rs +++ b/backend/src/utils/network/request.rs @@ -19,10 +19,10 @@ use crate::tuliprox_error::create_tuliprox_error_result; use crate::tuliprox_error::{str_to_io_error, TuliproxError, TuliproxErrorKind}; use crate::model::{format_elapsed_time, Config}; use crate::model::{ConfigInput, InputFetchMethod}; -use crate::repository::storage::{get_input_storage_path, short_hash}; +use crate::repository::storage::{get_input_storage_path}; use crate::repository::storage_const; use crate::utils::compression::compression_utils::{is_deflate, is_gzip}; -use crate::utils::{debug_if_enabled, filter_request_header}; +use crate::utils::{debug_if_enabled, filter_request_header, short_hash}; use crate::utils::{get_file_path, persist_file}; use crate::utils::{CONSTANTS, DASH_EXT, DASH_EXT_FRAGMENT, DASH_EXT_QUERY, ENCODING_DEFLATE, ENCODING_GZIP, HLS_EXT, HLS_EXT_FRAGMENT, HLS_EXT_QUERY}; diff --git a/src/utils/network/xtream.rs b/backend/src/utils/network/xtream.rs similarity index 99% rename from src/utils/network/xtream.rs rename to backend/src/utils/network/xtream.rs index 36bee9f63..4c7cacd59 100644 --- a/src/utils/network/xtream.rs +++ b/backend/src/utils/network/xtream.rs @@ -1,6 +1,6 @@ use crate::model::ProxyUserCredentials; use crate::model::{Config, ConfigInput, ConfigTarget, ProxyUserStatus}; -use crate::model::{PlaylistEntry, PlaylistGroup, XtreamCluster, XtreamPlaylistItem}; +use crate::model::{PlaylistGroup, XtreamPlaylistItem}; use crate::processing::parser::xtream; use crate::repository::xtream_repository; use crate::repository::xtream_repository::{rewrite_xtream_series_info_content, rewrite_xtream_vod_info_content, xtream_get_input_info}; @@ -15,6 +15,7 @@ use std::io::Error; use std::str::FromStr; use std::sync::Arc; use std::time::{SystemTime, UNIX_EPOCH}; +use shared::model::{PlaylistEntry, XtreamCluster}; use crate::messaging::{send_message, MsgKind}; #[inline] diff --git a/src/utils/size_utils.rs b/backend/src/utils/size_utils.rs similarity index 100% rename from src/utils/size_utils.rs rename to backend/src/utils/size_utils.rs diff --git a/src/utils/step_measure.rs b/backend/src/utils/step_measure.rs similarity index 100% rename from src/utils/step_measure.rs rename to backend/src/utils/step_measure.rs diff --git a/src/utils/string_utils.rs b/backend/src/utils/string_utils.rs similarity index 100% rename from src/utils/string_utils.rs rename to backend/src/utils/string_utils.rs diff --git a/src/utils/sys_utils.rs b/backend/src/utils/sys_utils.rs similarity index 100% rename from src/utils/sys_utils.rs rename to backend/src/utils/sys_utils.rs diff --git a/src/utils/time_utils.rs b/backend/src/utils/time_utils.rs similarity index 100% rename from src/utils/time_utils.rs rename to backend/src/utils/time_utils.rs diff --git a/src/utils/trakt/client.rs b/backend/src/utils/trakt/client.rs similarity index 100% rename from src/utils/trakt/client.rs rename to backend/src/utils/trakt/client.rs diff --git a/src/utils/trakt/errors.rs b/backend/src/utils/trakt/errors.rs similarity index 100% rename from src/utils/trakt/errors.rs rename to backend/src/utils/trakt/errors.rs diff --git a/src/utils/trakt/mod.rs b/backend/src/utils/trakt/mod.rs similarity index 100% rename from src/utils/trakt/mod.rs rename to backend/src/utils/trakt/mod.rs diff --git a/bin/build_aarch64.sh b/bin/build_aarch64.sh index e9149047b..305b8eb6c 100755 --- a/bin/build_aarch64.sh +++ b/bin/build_aarch64.sh @@ -1,3 +1,3 @@ #!/usr/bin/env bash echo "building binary for aarch64" -env RUSTFLAGS="--remap-path-prefix $HOME=~" cross build --release --target aarch64-unknown-linux-musl +env RUSTFLAGS="--remap-path-prefix $HOME=~" cross build -p tuliprox --release --target aarch64-unknown-linux-musl diff --git a/bin/build_armv7.sh b/bin/build_armv7.sh index 490f5cb33..e255d2c74 100755 --- a/bin/build_armv7.sh +++ b/bin/build_armv7.sh @@ -1,3 +1,3 @@ #!/usr/bin/env bash echo "building binary for armv7" -env RUSTFLAGS="--remap-path-prefix $HOME=~" cross build --release --target armv7-unknown-linux-musleabihf +env RUSTFLAGS="--remap-path-prefix $HOME=~" cross build -p tuliprox --release --target armv7-unknown-linux-musleabihf diff --git a/bin/build_darwin.sh b/bin/build_darwin.sh index f362300e6..7aa8e40ed 100755 --- a/bin/build_darwin.sh +++ b/bin/build_darwin.sh @@ -1,2 +1,2 @@ #!/usr/bin/env bash -env RUSTFLAGS="--remap-path-prefix $HOME=~" cross build --release --target x86_64-apple-darwin +env RUSTFLAGS="--remap-path-prefix $HOME=~" cross build -p tuliprox --release --target x86_64-apple-darwin diff --git a/bin/build_github_docker.sh b/bin/build_github_docker.sh index 080b10908..10b60e7e3 100755 --- a/bin/build_github_docker.sh +++ b/bin/build_github_docker.sh @@ -45,7 +45,7 @@ for PLATFORM in "${!ARCHITECTURES[@]}"; do echo "🛠️ Building binary for architecture: $ARCHITECTURE" cargo clean || true - env RUSTFLAGS="--remap-path-prefix $HOME=~" cross build --release --target "$ARCHITECTURE" + env RUSTFLAGS="--remap-path-prefix $HOME=~" cross build -p tuliprox --release --target "$ARCHITECTURE" BINARY_PATH="${WORKING_DIR}/target/${ARCHITECTURE}/release/tuliprox" if [ ! -f "$BINARY_PATH" ]; then diff --git a/bin/build_github_docker_aarch64.sh b/bin/build_github_docker_aarch64.sh index 7b69b1075..d9a16b4c0 100755 --- a/bin/build_github_docker_aarch64.sh +++ b/bin/build_github_docker_aarch64.sh @@ -58,7 +58,7 @@ if [ ! -d "$FRONTEND_DIR/build" ]; then fi cargo clean -env RUSTFLAGS="--remap-path-prefix $HOME=~" cross build --release --target "$TARGET" +env RUSTFLAGS="--remap-path-prefix $HOME=~" cross build -p tuliprox --release --target "$TARGET" # Check if the binary exists if [ ! -f "${WORKING_DIR}/target/${TARGET}/release/tuliprox" ]; then diff --git a/bin/build_github_docker_beta.sh b/bin/build_github_docker_beta.sh index bc27bcab5..c3f3cd65a 100755 --- a/bin/build_github_docker_beta.sh +++ b/bin/build_github_docker_beta.sh @@ -35,7 +35,7 @@ if [ ! -d "$FRONTEND_DIR/build" ]; then fi cargo clean -env RUSTFLAGS="--remap-path-prefix $HOME=~" cross build --release --target "$TARGET" +env RUSTFLAGS="--remap-path-prefix $HOME=~" cross build -p tuliprox --release --target "$TARGET" # Check if the binary exists if [ ! -f "${WORKING_DIR}/target/${TARGET}/release/tuliprox" ]; then diff --git a/bin/build_lin.sh b/bin/build_lin.sh index 6b5021029..af29c19bf 100755 --- a/bin/build_lin.sh +++ b/bin/build_lin.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash export RUSTFLAGS="--remap-path-prefix $HOME=~" if [ "$(uname)" != "Linux" ]; then - cross build --release --target --target x86_64-unknown-linux-gnu + cross build -p tuliprox --release --target --target x86_64-unknown-linux-gnu else cargo build --release fi \ No newline at end of file diff --git a/bin/build_lin_static.sh b/bin/build_lin_static.sh index a8989bfb0..799a2be29 100755 --- a/bin/build_lin_static.sh +++ b/bin/build_lin_static.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash DEFAULT_TARGET="x86_64-unknown-linux-musl" TARGET="${1:-$DEFAULT_TARGET}" -env RUSTFLAGS="--remap-path-prefix $HOME=~" cross build --release --target "$TARGET" +env RUSTFLAGS="--remap-path-prefix $HOME=~" cross build -p tuliprox --release --target "$TARGET" diff --git a/bin/build_win.sh b/bin/build_win.sh index a78582a4a..779969809 100755 --- a/bin/build_win.sh +++ b/bin/build_win.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash env RUSTFLAGS="--remap-path-prefix $HOME=~" cargo build --release --target x86_64-pc-windows-gnu # cross build, is only working with cargo clean -# env RUSTFLAGS="--remap-path-prefix $HOME=~" cross build --release --target x86_64-pc-windows-gnu +# env RUSTFLAGS="--remap-path-prefix $HOME=~" cross build -p tuliprox --release --target x86_64-pc-windows-gnu diff --git a/bin/release.sh b/bin/release.sh index 79197bd60..8bd043ee7 100755 --- a/bin/release.sh +++ b/bin/release.sh @@ -83,7 +83,7 @@ for PLATFORM in "${!ARCHITECTURES[@]}"; do # Build for each platform cd "$WORKING_DIR" cargo clean || true # Clean before each build to avoid conflicts - env RUSTFLAGS="--remap-path-prefix $HOME=~" cross build --release --target "$ARCHITECTURE" + env RUSTFLAGS="--remap-path-prefix $HOME=~" cross build -p tuliprox --release --target "$ARCHITECTURE" # Create directories and copy binaries and config files cd target diff --git a/docker/Dockerfile b/docker/Dockerfile index 2eb0b94e1..8694890b6 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -129,7 +129,7 @@ RUN rustup update && rustup target add $RUST_TARGET # Create the final application layout to mimic production WORKDIR /app COPY --from=node-build /app/build ./web -COPY --from=resource-build /src/resources ./resources +COPY --from=resource-build //resources ./resources # Create a separate directory for the source code WORKDIR /usr/src/tuliprox @@ -162,9 +162,9 @@ COPY --from=rust-build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ # App WORKDIR /app -COPY --from=rust-build /src/target/${RUST_TARGET}/release/tuliprox ./tuliprox +COPY --from=rust-build //target/${RUST_TARGET}/release/tuliprox ./tuliprox COPY --from=node-build /app/build ./web -COPY --from=resource-build /src/resources ./resources +COPY --from=resource-build //resources ./resources ENTRYPOINT ["/app/tuliprox"] CMD ["-s", "-p", "/app/config"] @@ -187,9 +187,9 @@ COPY --from=rust-build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ RUN ln -sf /usr/share/zoneinfo/${TZ} /etc/localtime WORKDIR /app -COPY --from=rust-build /src/target/${RUST_TARGET}/release/tuliprox ./tuliprox +COPY --from=rust-build //target/${RUST_TARGET}/release/tuliprox ./tuliprox COPY --from=node-build /app/build ./web -COPY --from=resource-build /src/resources ./resources +COPY --from=resource-build //resources ./resources ENTRYPOINT ["/sbin/tini", "--", "/app/tuliprox"] CMD ["-s", "-p", "/app/config"] \ No newline at end of file diff --git a/shared/Cargo.toml b/shared/Cargo.toml new file mode 100644 index 000000000..eb50051cd --- /dev/null +++ b/shared/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "shared" +version = "0.1.0" +edition = "2021" + +[dependencies] +bitflags = "2.9.1" +serde = { version = "1.0.219", features = ["derive"] } diff --git a/shared/src/lib.rs b/shared/src/lib.rs new file mode 100644 index 000000000..99bbd124c --- /dev/null +++ b/shared/src/lib.rs @@ -0,0 +1 @@ +pub mod model; \ No newline at end of file diff --git a/src/model/cluster_flags.rs b/shared/src/model/cluster_flags.rs similarity index 100% rename from src/model/cluster_flags.rs rename to shared/src/model/cluster_flags.rs diff --git a/shared/src/model/mod.rs b/shared/src/model/mod.rs new file mode 100644 index 000000000..b5b0b3e69 --- /dev/null +++ b/shared/src/model/mod.rs @@ -0,0 +1,5 @@ +mod cluster_flags; +mod playlist; + +pub use self::cluster_flags::*; +pub use self::playlist::*; \ No newline at end of file diff --git a/shared/src/model/playlist.rs b/shared/src/model/playlist.rs new file mode 100644 index 000000000..f35fd8199 --- /dev/null +++ b/shared/src/model/playlist.rs @@ -0,0 +1,128 @@ +use std::borrow::Cow; +use std::fmt::{Display, Formatter}; +use std::str::FromStr; +use serde::{Deserialize, Serialize}; + +pub type UUIDType = [u8; 32]; + +#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, Serialize, Deserialize, Default)] +#[repr(u8)] +pub enum XtreamCluster { + #[default] + Live = 1, + Video = 2, + Series = 3, +} + +impl XtreamCluster { + pub const fn as_str(&self) -> &str { + match self { + Self::Live => "Live", + Self::Video => "Video", + Self::Series => "Series", + } + } + pub const fn as_stream_type(&self) -> &str { + match self { + Self::Live => "live", + Self::Video => "movie", + Self::Series => "series", + } + } +} + +impl Display for XtreamCluster { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.as_str()) + } +} + +impl TryFrom for XtreamCluster { + type Error = String; + fn try_from(item_type: PlaylistItemType) -> Result { + match item_type { + PlaylistItemType::Live | PlaylistItemType::LiveHls | PlaylistItemType::LiveDash | PlaylistItemType::LiveUnknown => Ok(Self::Live), + PlaylistItemType::Catchup | PlaylistItemType::Video => Ok(Self::Video), + PlaylistItemType::Series | PlaylistItemType::SeriesInfo => Ok(Self::Series), + } + } +} + +#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, Serialize, Deserialize, Default)] +#[repr(u8)] +pub enum PlaylistItemType { + #[default] + Live = 1, + Video = 2, + Series = 3, // xtream series description + SeriesInfo = 4, // xtream series info fetched for series description + Catchup = 5, + LiveUnknown = 6, // No Provider id + LiveHls = 7, // m3u8 entry + LiveDash = 8, // mpd +} + +impl From for PlaylistItemType { + fn from(xtream_cluster: XtreamCluster) -> Self { + match xtream_cluster { + XtreamCluster::Live => Self::Live, + XtreamCluster::Video => Self::Video, + XtreamCluster::Series => Self::SeriesInfo, + } + } +} + + +impl FromStr for PlaylistItemType { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "Live" => Ok(PlaylistItemType::Live), + "Video" => Ok(PlaylistItemType::Video), + "Series" => Ok(PlaylistItemType::Series), + "SeriesInfo" => Ok(PlaylistItemType::SeriesInfo), + "Catchup" => Ok(PlaylistItemType::Catchup), + "LiveUnknown" => Ok(PlaylistItemType::LiveUnknown), + "LiveHls" => Ok(PlaylistItemType::LiveHls), + "LiveDash" => Ok(PlaylistItemType::LiveDash), + _ => Err(format!("Invalid PlaylistItemType: {s}")), + } + } +} + +impl PlaylistItemType { + const LIVE: &'static str = "live"; + const VIDEO: &'static str = "video"; + const SERIES: &'static str = "series"; + const SERIES_INFO: &'static str = "series-info"; + const CATCHUP: &'static str = "catchup"; +} + +impl Display for PlaylistItemType { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", match self { + Self::Live | Self::LiveHls | Self::LiveDash | Self::LiveUnknown => Self::LIVE, + Self::Video => Self::VIDEO, + Self::Series => Self::SERIES, + Self::SeriesInfo => Self::SERIES_INFO, + Self::Catchup => Self::CATCHUP, + }) + } +} + +pub trait FieldGetAccessor { + fn get_field(&self, field: &str) -> Option>; +} +pub trait FieldSetAccessor { + fn set_field(&mut self, field: &str, value: &str) -> bool; +} + +pub trait PlaylistEntry: Send + Sync { + fn get_virtual_id(&self) -> u32; + fn get_provider_id(&self) -> Option; + fn get_category_id(&self) -> Option; + fn get_provider_url(&self) -> String; + fn get_uuid(&self) -> UUIDType; + fn get_item_type(&self) -> PlaylistItemType; +} \ No newline at end of file From ae8fa052101e638d12082159bc1b769470777378 Mon Sep 17 00:00:00 2001 From: euzu Date: Thu, 19 Jun 2025 12:52:01 +0200 Subject: [PATCH 2/9] default_utils and time_utils moved to shared --- backend/src/utils/mod.rs | 4 ---- shared/src/lib.rs | 3 ++- {backend => shared}/src/utils/default_utils.rs | 0 shared/src/utils/mod.rs | 5 +++++ {backend => shared}/src/utils/time_utils.rs | 0 5 files changed, 7 insertions(+), 5 deletions(-) rename {backend => shared}/src/utils/default_utils.rs (100%) create mode 100644 shared/src/utils/mod.rs rename {backend => shared}/src/utils/time_utils.rs (100%) diff --git a/backend/src/utils/mod.rs b/backend/src/utils/mod.rs index 8ebaa34d7..c00abeaae 100644 --- a/backend/src/utils/mod.rs +++ b/backend/src/utils/mod.rs @@ -1,6 +1,5 @@ mod string_utils; mod json_utils; -mod default_utils; mod size_utils; mod sys_utils; mod hash_utils; @@ -8,7 +7,6 @@ mod compression; mod file; mod network; mod bincode_utils; -mod time_utils; mod crypto_utils; mod constants; mod step_measure; @@ -61,7 +59,6 @@ pub use debug_if_enabled; pub use trace_if_enabled; pub use with; -pub use self::default_utils::*; pub use self::string_utils::*; pub use self::json_utils::*; pub use self::size_utils::*; @@ -71,7 +68,6 @@ pub use self::compression::*; pub use self::file::*; pub use self::network::*; pub use self::bincode_utils::*; -pub use self::time_utils::*; pub use self::crypto_utils::*; pub use self::constants::*; pub use self::step_measure::*; diff --git a/shared/src/lib.rs b/shared/src/lib.rs index 99bbd124c..32c2eb054 100644 --- a/shared/src/lib.rs +++ b/shared/src/lib.rs @@ -1 +1,2 @@ -pub mod model; \ No newline at end of file +pub mod model; +pub mod utils; \ No newline at end of file diff --git a/backend/src/utils/default_utils.rs b/shared/src/utils/default_utils.rs similarity index 100% rename from backend/src/utils/default_utils.rs rename to shared/src/utils/default_utils.rs diff --git a/shared/src/utils/mod.rs b/shared/src/utils/mod.rs new file mode 100644 index 000000000..4dc975585 --- /dev/null +++ b/shared/src/utils/mod.rs @@ -0,0 +1,5 @@ +mod default_utils; +mod time_utils; + +pub use self::default_utils::*; +pub use self::time_utils::*; diff --git a/backend/src/utils/time_utils.rs b/shared/src/utils/time_utils.rs similarity index 100% rename from backend/src/utils/time_utils.rs rename to shared/src/utils/time_utils.rs From 068150561aed8e37d145c6fd0854f0981f28778c Mon Sep 17 00:00:00 2001 From: euzu Date: Thu, 19 Jun 2025 13:22:43 +0200 Subject: [PATCH 3/9] moved constants, size_utils, string_utils to shared --- Cargo.lock | 2 ++ backend/src/api/api_utils.rs | 5 ++--- backend/src/api/endpoints/download_api.rs | 3 ++- backend/src/api/endpoints/hls_api.rs | 2 +- backend/src/api/endpoints/m3u_api.rs | 2 +- backend/src/api/endpoints/web_index.rs | 2 +- backend/src/api/endpoints/xtream_api.rs | 2 +- .../src/api/model/active_provider_manager.rs | 2 +- backend/src/api/model/active_user_manager.rs | 2 +- backend/src/api/model/download.rs | 2 +- backend/src/api/model/model_utils.rs | 2 +- .../model/streams/provider_stream_factory.rs | 3 ++- backend/src/api/model/xtream.rs | 2 +- backend/src/foundation/filter.rs | 2 +- backend/src/foundation/mapper.rs | 2 +- backend/src/model/config.rs | 3 +-- backend/src/model/config_api_proxy.rs | 3 ++- backend/src/model/config_cache.rs | 2 +- backend/src/model/config_epg.rs | 2 +- backend/src/model/config_input.rs | 4 ++-- backend/src/model/config_log.rs | 2 +- backend/src/model/config_source.rs | 2 +- backend/src/model/config_target.rs | 2 +- backend/src/model/config_web_auth.rs | 2 +- backend/src/model/config_webui.rs | 2 +- backend/src/model/xtream.rs | 3 ++- backend/src/processing/parser/hls.rs | 2 +- backend/src/processing/parser/m3u.rs | 18 +++++++++++++++++- backend/src/processing/parser/xmltv.rs | 2 +- backend/src/processing/processor/playlist.rs | 2 +- backend/src/processing/processor/trakt.rs | 5 +++-- backend/src/repository/strm_repository.rs | 3 ++- backend/src/tools/lru_cache.rs | 2 +- backend/src/utils/file/config_reader.rs | 2 +- backend/src/utils/file/file_utils.rs | 2 +- backend/src/utils/mod.rs | 6 ------ backend/src/utils/network/request.rs | 9 +++------ backend/src/utils/sys_utils.rs | 2 +- backend/src/utils/trakt/mod.rs | 9 ++++++--- shared/Cargo.toml | 2 ++ {backend => shared}/src/utils/constants.rs | 0 shared/src/utils/mod.rs | 6 ++++++ {backend => shared}/src/utils/size_utils.rs | 5 +++++ {backend => shared}/src/utils/string_utils.rs | 17 +---------------- 44 files changed, 85 insertions(+), 71 deletions(-) rename {backend => shared}/src/utils/constants.rs (100%) rename {backend => shared}/src/utils/size_utils.rs (97%) rename {backend => shared}/src/utils/string_utils.rs (72%) diff --git a/Cargo.lock b/Cargo.lock index f633f2c58..901cdfc46 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2581,6 +2581,8 @@ name = "shared" version = "0.1.0" dependencies = [ "bitflags 2.9.1", + "rand", + "regex", "serde", ] diff --git a/backend/src/api/api_utils.rs b/backend/src/api/api_utils.rs index e655ea58f..ee759d3a8 100644 --- a/backend/src/api/api_utils.rs +++ b/backend/src/api/api_utils.rs @@ -17,12 +17,11 @@ use crate::model::{ConfigInput, ConfigTarget, InputFetchMethod, TargetType}; use shared::model::{PlaylistEntry, PlaylistItemType, XtreamCluster}; use crate::tools::atomic_once_flag::AtomicOnceFlag; use crate::tools::lru_cache::LRUResourceCache; -use crate::utils::{DASH_EXT, HLS_EXT}; -use crate::utils::default_grace_period_millis; +use shared::utils::{DASH_EXT, HLS_EXT}; +use shared::utils::{default_grace_period_millis, human_readable_byte_size}; use crate::utils::create_new_file_for_write; use crate::utils::request; use crate::utils::request::{extract_extension_from_url, replace_url_extension, sanitize_sensitive_info}; -use crate::utils::human_readable_byte_size; use crate::utils::{debug_if_enabled, trace_if_enabled}; use crate::{BUILD_TIMESTAMP}; use axum::body::Body; diff --git a/backend/src/api/endpoints/download_api.rs b/backend/src/api/endpoints/download_api.rs index f3c074d5f..8561581b3 100644 --- a/backend/src/api/endpoints/download_api.rs +++ b/backend/src/api/endpoints/download_api.rs @@ -12,6 +12,7 @@ use std::ops::Deref; use std::sync::Arc; use std::{fs}; use axum::response::IntoResponse; +use shared::utils::bytes_to_megabytes; use crate::tuliprox_error::to_io_error; use crate::utils::request::create_client; @@ -39,7 +40,7 @@ async fn download_file(active: Arc>>, client: &reqwe Err(err) => return Err(format!("Error while writing to file: {file_path_str} {err}")) } } else { - let megabytes = request::bytes_to_megabytes(downloaded); + let megabytes = bytes_to_megabytes(downloaded); info!("Downloaded {file_path_str}, filesize: {megabytes}MB"); active.write().await.as_mut().unwrap().size = downloaded; return Ok(()); diff --git a/backend/src/api/endpoints/hls_api.rs b/backend/src/api/endpoints/hls_api.rs index a3e82c5f8..f72fc470f 100644 --- a/backend/src/api/endpoints/hls_api.rs +++ b/backend/src/api/endpoints/hls_api.rs @@ -6,7 +6,7 @@ use crate::model::{ProxyUserCredentials, UserConnectionPermission}; use crate::model::ConfigInput; use shared::model::{PlaylistItemType, XtreamCluster}; use crate::processing::parser::hls::{get_hls_session_token_and_url_from_token, rewrite_hls, RewriteHlsProps}; -use crate::utils::HLS_EXT; +use shared::utils::HLS_EXT; use crate::utils::request; use crate::utils::request::{is_hls_url, replace_url_extension, sanitize_sensitive_info}; use axum::response::IntoResponse; diff --git a/backend/src/api/endpoints/m3u_api.rs b/backend/src/api/endpoints/m3u_api.rs index 20561c444..111ac420d 100644 --- a/backend/src/api/endpoints/m3u_api.rs +++ b/backend/src/api/endpoints/m3u_api.rs @@ -10,7 +10,7 @@ use shared::model::{FieldGetAccessor, PlaylistEntry, PlaylistItemType, XtreamClu use crate::repository::m3u_repository::{m3u_get_item_for_stream_id, m3u_load_rewrite_playlist}; use crate::repository::storage_const; use crate::utils::request::{extract_extension_from_url, sanitize_sensitive_info}; -use crate::utils::HLS_EXT; +use shared::utils::HLS_EXT; use axum::http::{HeaderMap, StatusCode}; use axum::response::IntoResponse; use bytes::Bytes; diff --git a/backend/src/api/endpoints/web_index.rs b/backend/src/api/endpoints/web_index.rs index fe25740af..74bc8a5b8 100644 --- a/backend/src/api/endpoints/web_index.rs +++ b/backend/src/api/endpoints/web_index.rs @@ -8,7 +8,7 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; use std::sync::{Arc}; use tower::Service; -use crate::utils::CONSTANTS; +use shared::utils::CONSTANTS; fn no_web_auth_token() -> impl axum::response::IntoResponse + Send { axum::Json(HashMap::from([("token", "authorized")])).into_response() diff --git a/backend/src/api/endpoints/xtream_api.rs b/backend/src/api/endpoints/xtream_api.rs index 4e6d470ae..4a5f710c1 100644 --- a/backend/src/api/endpoints/xtream_api.rs +++ b/backend/src/api/endpoints/xtream_api.rs @@ -24,7 +24,7 @@ use crate::utils::get_u32_from_serde_value; use crate::utils::request::{extract_extension_from_url, sanitize_sensitive_info}; use crate::utils::trace_if_enabled; use crate::utils::xtream::create_vod_info_from_item; -use crate::utils::HLS_EXT; +use shared::utils::HLS_EXT; use crate::utils::{request, xtream}; use crate::auth::Fingerprint; use axum::http::{HeaderMap, StatusCode}; diff --git a/backend/src/api/model/active_provider_manager.rs b/backend/src/api/model/active_provider_manager.rs index 63313c7cd..f87dcf9cf 100644 --- a/backend/src/api/model/active_provider_manager.rs +++ b/backend/src/api/model/active_provider_manager.rs @@ -6,7 +6,7 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; use tokio::sync::{Mutex, RwLock}; use crate::api::model::provider_config::{ProviderConfig, ProviderConfigWrapper}; -use crate::utils::{default_grace_period_millis, default_grace_period_timeout_secs}; +use shared::utils::{default_grace_period_millis, default_grace_period_timeout_secs}; pub struct ProviderConnectionGuard { // manager: Arc, diff --git a/backend/src/api/model/active_user_manager.rs b/backend/src/api/model/active_user_manager.rs index 08822138c..942ad277f 100644 --- a/backend/src/api/model/active_user_manager.rs +++ b/backend/src/api/model/active_user_manager.rs @@ -1,7 +1,7 @@ use crate::model::Config; use crate::model::{ProxyUserCredentials, UserConnectionPermission}; use crate::utils::request::sanitize_sensitive_info; -use crate::utils::{current_time_secs, default_grace_period_millis, default_grace_period_timeout_secs}; +use shared::utils::{current_time_secs, default_grace_period_millis, default_grace_period_timeout_secs}; use jsonwebtoken::get_current_timestamp; use log::{debug, info}; use std::collections::HashMap; diff --git a/backend/src/api/model/download.rs b/backend/src/api/model/download.rs index 47beb38be..36862f959 100644 --- a/backend/src/api/model/download.rs +++ b/backend/src/api/model/download.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; use crate::model::{VideoDownloadConfig}; use crate::utils::hash_string_as_hex; -use crate::utils::{CONSTANTS, FILENAME_TRIM_PATTERNS}; +use shared::utils::{CONSTANTS, FILENAME_TRIM_PATTERNS}; /// File-Download information. #[derive(Clone)] diff --git a/backend/src/api/model/model_utils.rs b/backend/src/api/model/model_utils.rs index cfe5e7be1..f865e496a 100644 --- a/backend/src/api/model/model_utils.rs +++ b/backend/src/api/model/model_utils.rs @@ -2,7 +2,7 @@ use reqwest::{StatusCode}; use std::collections::{HashSet}; use std::str::FromStr; use reqwest::header::HeaderMap; -use crate::utils::{filter_response_header}; +use shared::utils::{filter_response_header}; pub fn get_response_headers(headers: &HeaderMap) -> Vec<(String, String)> { let mut response_headers: Vec<(String, String)> = headers.iter() diff --git a/backend/src/api/model/streams/provider_stream_factory.rs b/backend/src/api/model/streams/provider_stream_factory.rs index 606bcf7f3..77498a45d 100644 --- a/backend/src/api/model/streams/provider_stream_factory.rs +++ b/backend/src/api/model/streams/provider_stream_factory.rs @@ -10,7 +10,8 @@ use shared::model::PlaylistItemType; use crate::model::{Config, DEFAULT_USER_AGENT}; use crate::tools::atomic_once_flag::AtomicOnceFlag; use crate::utils::request::{classify_content_type, get_request_headers, sanitize_sensitive_info, MimeCategory}; -use crate::utils::{debug_if_enabled, filter_request_header}; +use crate::utils::{debug_if_enabled}; +use shared::utils::{filter_request_header}; use futures::stream::{self}; use futures::{StreamExt, TryStreamExt}; use log::{debug, log_enabled, warn}; diff --git a/backend/src/api/model/xtream.rs b/backend/src/api/model/xtream.rs index 2bda9f843..fc5e0e508 100644 --- a/backend/src/api/model/xtream.rs +++ b/backend/src/api/model/xtream.rs @@ -1,7 +1,7 @@ use crate::model::{ApiProxyServerInfo, ProxyUserCredentials, ProxyUserStatus}; use chrono::{Duration, Local}; use serde::{Deserialize, Serialize}; -use crate::utils::CONSTANTS; +use shared::utils::CONSTANTS; #[derive(Serialize, Deserialize, Clone)] pub struct XtreamUserInfoResponse { diff --git a/backend/src/foundation/filter.rs b/backend/src/foundation/filter.rs index 951900e2c..37383fe9a 100644 --- a/backend/src/foundation/filter.rs +++ b/backend/src/foundation/filter.rs @@ -13,7 +13,7 @@ use crate::model::{PlaylistItem, ItemField}; use crate::tools::directed_graph::DirectedGraph; use crate::tuliprox_error::{create_tuliprox_error_result, info_err}; use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind}; -use crate::utils::CONSTANTS; +use shared::utils::CONSTANTS; pub fn get_field_value(pli: &PlaylistItem, field: ItemField) -> String { let header = &pli.header; diff --git a/backend/src/foundation/mapper.rs b/backend/src/foundation/mapper.rs index 4df41dd2c..ac536bb9f 100644 --- a/backend/src/foundation/mapper.rs +++ b/backend/src/foundation/mapper.rs @@ -3,7 +3,7 @@ use crate::foundation::filter::{PatternTemplate, TemplateValue, ValueAccessor}; use crate::foundation::mapper::EvalResult::{AnyValue, Failure, Named, Number, Undefined, Value}; use crate::tuliprox_error::{create_tuliprox_error_result, info_err, TuliproxError, TuliproxErrorKind}; -use crate::utils::Capitalize; +use shared::utils::Capitalize; use log::{debug, trace}; use pest::iterators::{Pair, Pairs}; use pest::Parser; diff --git a/backend/src/model/config.rs b/backend/src/model/config.rs index f8cbe6347..750c80e03 100644 --- a/backend/src/model/config.rs +++ b/backend/src/model/config.rs @@ -15,8 +15,7 @@ use rand::Rng; use crate::model::{ApiProxyConfig, ApiProxyServerInfo, Mappings, ProxyUserCredentials, SourcesConfig}; use crate::model::{ConfigInput, ConfigInputOptions, ConfigTarget, HdHomeRunConfig, IpCheckConfig, LogConfig, MessagingConfig, ProxyConfig, TargetOutput, VideoConfig, WebUiConfig}; use crate::tuliprox_error::{create_tuliprox_error_result, TuliproxError, TuliproxErrorKind}; -use crate::utils::{default_connect_timeout_secs, default_grace_period_millis, default_grace_period_timeout_secs}; -use crate::utils::{parse_to_kbps}; +use shared::utils::{parse_to_kbps, default_connect_timeout_secs, default_grace_period_millis, default_grace_period_timeout_secs}; const STREAM_QUEUE_SIZE: usize = 1024; // mpsc channel holding messages. with 8192byte chunks and 2Mbit/s approx 8MB diff --git a/backend/src/model/config_api_proxy.rs b/backend/src/model/config_api_proxy.rs index c3f5ebfcf..f25f31f73 100644 --- a/backend/src/model/config_api_proxy.rs +++ b/backend/src/model/config_api_proxy.rs @@ -2,7 +2,8 @@ use crate::api::model::app_state::AppState; use crate::tuliprox_error::{create_tuliprox_error_result, info_err, TuliproxError, TuliproxErrorKind}; use crate::model::{Config}; use crate::repository::user_repository::{backup_api_user_db_file, get_api_user_db_path, load_api_user, merge_api_user}; -use crate::utils::{default_as_true, save_api_proxy}; +use crate::utils::{save_api_proxy}; +use shared::utils::{default_as_true}; use chrono::Local; use enum_iterator::Sequence; use log::debug; diff --git a/backend/src/model/config_cache.rs b/backend/src/model/config_cache.rs index 6bc52b256..829e3f940 100644 --- a/backend/src/model/config_cache.rs +++ b/backend/src/model/config_cache.rs @@ -2,7 +2,7 @@ use std::path::PathBuf; use log::error; use path_clean::PathClean; use crate::tuliprox_error::{info_err, TuliproxError, TuliproxErrorKind}; -use crate::utils::parse_size_base_2; +use shared::utils::parse_size_base_2; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] #[serde(deny_unknown_fields)] diff --git a/backend/src/model/config_epg.rs b/backend/src/model/config_epg.rs index b6e2c3560..e4a0677c7 100644 --- a/backend/src/model/config_epg.rs +++ b/backend/src/model/config_epg.rs @@ -1,5 +1,5 @@ use crate::tuliprox_error::{create_tuliprox_error_result, info_err, TuliproxError, TuliproxErrorKind}; -use crate::utils::CONSTANTS; +use shared::utils::CONSTANTS; use log::warn; use regex::Regex; diff --git a/backend/src/model/config_input.rs b/backend/src/model/config_input.rs index 8fec6f5e2..5291c66d1 100644 --- a/backend/src/model/config_input.rs +++ b/backend/src/model/config_input.rs @@ -1,7 +1,7 @@ use crate::tuliprox_error::{create_tuliprox_error_result, handle_tuliprox_error_result_list, info_err, TuliproxError, TuliproxErrorKind}; use crate::model::{EpgConfig}; -use crate::utils::default_as_true; -use crate::utils::get_trimmed_string; +use shared::utils::default_as_true; +use shared::utils::get_trimmed_string; use crate::utils::request::{get_base_url_from_str, get_credentials_from_url, get_credentials_from_url_str, sanitize_sensitive_info}; use enum_iterator::Sequence; use log::{debug}; diff --git a/backend/src/model/config_log.rs b/backend/src/model/config_log.rs index 8860363e3..556fe6bc2 100644 --- a/backend/src/model/config_log.rs +++ b/backend/src/model/config_log.rs @@ -1,5 +1,5 @@ -use crate::utils::default_as_true; +use shared::utils::default_as_true; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] #[serde(deny_unknown_fields)] diff --git a/backend/src/model/config_source.rs b/backend/src/model/config_source.rs index 5a7ae12df..e7ab5639b 100644 --- a/backend/src/model/config_source.rs +++ b/backend/src/model/config_source.rs @@ -3,7 +3,7 @@ use crate::foundation::filter::{prepare_templates, PatternTemplate}; use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind, handle_tuliprox_error_result_list, create_tuliprox_error_result}; use crate::model::{ConfigInput, ProcessTargets}; use crate::model::config_target::ConfigTarget; -use crate::utils::default_as_default; +use shared::utils::default_as_default; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[serde(deny_unknown_fields)] diff --git a/backend/src/model/config_target.rs b/backend/src/model/config_target.rs index dd5c40eb8..6a999d85e 100644 --- a/backend/src/model/config_target.rs +++ b/backend/src/model/config_target.rs @@ -5,7 +5,7 @@ use crate::model::mapping::Mapping; use crate::model::processing_order::ProcessingOrder; use crate::model::trakt::TraktConfig; use crate::tuliprox_error::{create_tuliprox_error_result, handle_tuliprox_error_result_list, info_err, TuliproxError, TuliproxErrorKind}; -use crate::utils::{default_as_default, default_as_true, default_resolve_delay_secs}; +use shared::utils::{default_as_default, default_as_true, default_resolve_delay_secs}; use arc_swap::ArcSwapOption; use enum_iterator::Sequence; use shared::model::ClusterFlags; diff --git a/backend/src/model/config_web_auth.rs b/backend/src/model/config_web_auth.rs index 4ef61aec4..a1a424035 100644 --- a/backend/src/model/config_web_auth.rs +++ b/backend/src/model/config_web_auth.rs @@ -1,4 +1,4 @@ -use crate::utils::default_as_true; +use shared::utils::default_as_true; use std::fs::File; use std::io::BufRead; use std::path::PathBuf; diff --git a/backend/src/model/config_webui.rs b/backend/src/model/config_webui.rs index b3d4f1909..425e4a051 100644 --- a/backend/src/model/config_webui.rs +++ b/backend/src/model/config_webui.rs @@ -1,4 +1,4 @@ -use crate::utils::default_as_true; +use shared::utils::default_as_true; use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind}; use crate::model::WebAuthConfig; diff --git a/backend/src/model/xtream.rs b/backend/src/model/xtream.rs index 0a46a3372..bfcd5fd73 100644 --- a/backend/src/model/xtream.rs +++ b/backend/src/model/xtream.rs @@ -3,7 +3,8 @@ use crate::model::{Config, ConfigTarget, XtreamTargetOutput}; use crate::model::{PlaylistItem,XtreamPlaylistItem}; use crate::model::serde_utils::{deserialize_as_option_rc_string, deserialize_as_rc_string, deserialize_as_string_array, deserialize_number_from_string}; use crate::model::xtream_const; -use crate::utils::{get_non_empty_str, opt_string_or_number_u32, string_default_on_null, string_or_number_f64, string_or_number_u32}; +use crate::utils::{opt_string_or_number_u32, string_default_on_null, string_or_number_f64, string_or_number_u32}; +use shared::utils::{get_non_empty_str}; use serde::{Deserialize, Serialize}; use serde_json::{Map, Value}; use std::collections::HashMap; diff --git a/backend/src/processing/parser/hls.rs b/backend/src/processing/parser/hls.rs index b92618170..dc7111cb6 100644 --- a/backend/src/processing/parser/hls.rs +++ b/backend/src/processing/parser/hls.rs @@ -1,5 +1,5 @@ use crate::model::ProxyUserCredentials; -use crate::utils::{CONSTANTS, HLS_PREFIX}; +use shared::utils::{CONSTANTS, HLS_PREFIX}; use crate::utils::{deobfuscate_text, obfuscate_text}; use std::str; diff --git a/backend/src/processing/parser/m3u.rs b/backend/src/processing/parser/m3u.rs index 2b2d0b339..70b8d7981 100644 --- a/backend/src/processing/parser/m3u.rs +++ b/backend/src/processing/parser/m3u.rs @@ -2,7 +2,23 @@ use std::borrow::BorrowMut; use shared::model::{PlaylistItemType, XtreamCluster}; use crate::model::{Config, ConfigInput}; use crate::model::{PlaylistGroup, PlaylistItem, PlaylistItemHeader}; -use crate::utils::{extract_id_from_url, get_title_group}; +use crate::utils::{extract_id_from_url}; + + +// other implementations like calculating text_distance on all titles took too much time +// we keep it now as simple as possible and less memory intensive. +fn get_title_group(text: &str) -> String { + let alphabetic_only: String = text.chars().map(|c| if c.is_alphanumeric() { c } else { ' ' }).collect(); + let parts = alphabetic_only.split_whitespace(); + let mut combination = String::new(); + for p in parts { + combination = format!("{combination} {p}").trim().to_string(); + if combination.len() > 2 { + return combination; + } + } + text.to_string() +} #[inline] fn token_value(stack: &mut String, it: &mut std::str::Chars) -> String { diff --git a/backend/src/processing/parser/xmltv.rs b/backend/src/processing/parser/xmltv.rs index 47419f9b8..c3b6ef5f3 100644 --- a/backend/src/processing/parser/xmltv.rs +++ b/backend/src/processing/parser/xmltv.rs @@ -2,7 +2,7 @@ use crate::model::{Epg, TVGuide, XmlTag, XmlTagIcon, EPG_ATTRIB_CHANNEL, EPG_ATT use crate::model::{EpgNamePrefix, EpgSmartMatchConfig, PersistedEpgSource}; use crate::processing::processor::epg::EpgIdCache; use crate::utils::compressed_file_reader::CompressedFileReader; -use crate::utils::CONSTANTS; +use shared::utils::CONSTANTS; use deunicode::deunicode; use quick_xml::events::{BytesStart, BytesText, Event}; use quick_xml::Reader; diff --git a/backend/src/processing/processor/playlist.rs b/backend/src/processing/processor/playlist.rs index 26bd1cd67..802614342 100644 --- a/backend/src/processing/processor/playlist.rs +++ b/backend/src/processing/processor/playlist.rs @@ -22,7 +22,7 @@ use crate::processing::processor::trakt::process_trakt_categories_for_target; use crate::repository::playlist_repository::persist_playlist; use crate::tuliprox_error::{get_errors_notify_message, notify_err, TuliproxError, TuliproxErrorKind}; use crate::utils::debug_if_enabled; -use crate::utils::default_as_default; +use shared::utils::default_as_default; use deunicode::deunicode; use log::{debug, error, info, log_enabled, trace, warn, Level}; use std::time::Instant; diff --git a/backend/src/processing/processor/trakt.rs b/backend/src/processing/processor/trakt.rs index 97d37fa61..bfcf0170e 100644 --- a/backend/src/processing/processor/trakt.rs +++ b/backend/src/processing/processor/trakt.rs @@ -3,10 +3,11 @@ use crate::model::{ConfigTarget, PlaylistGroup, PlaylistItem}; use shared::model::{FieldGetAccessor, FieldSetAccessor, XtreamCluster}; use crate::model::{TraktConfig, TraktContentType, TraktListConfig, TraktListItem, TraktMatchItem, TraktMatchResult}; use crate::tuliprox_error::TuliproxError; -use crate::utils::trakt::client::TraktClient; +use crate::utils::trakt::TraktClient; use crate::utils::trakt::extract_year_from_title; use crate::utils::trakt::normalize_title_for_matching; -use crate::utils::{get_u32_from_serde_value, CONSTANTS}; +use crate::utils::{get_u32_from_serde_value}; +use shared::utils::{CONSTANTS}; use crate::utils::{trace_if_enabled, with}; use log::{debug, info, trace, warn}; use std::sync::Arc; diff --git a/backend/src/repository/strm_repository.rs b/backend/src/repository/strm_repository.rs index 2db20989e..f40fcd394 100644 --- a/backend/src/repository/strm_repository.rs +++ b/backend/src/repository/strm_repository.rs @@ -9,7 +9,8 @@ use crate::repository::bplustree::BPlusTree; use crate::repository::storage::{ensure_target_storage_path, get_input_storage_path}; use crate::repository::storage_const; use crate::repository::xtream_repository::{xtream_get_record_file_path, InputVodInfoRecord}; -use crate::utils::{hash_bytes, ExportStyleConfig, CONSTANTS}; +use crate::utils::{hash_bytes}; +use shared::utils::{ExportStyleConfig, CONSTANTS}; use crate::utils::FileReadGuard; use crate::utils::request::extract_extension_from_url; use chrono::Datelike; diff --git a/backend/src/tools/lru_cache.rs b/backend/src/tools/lru_cache.rs index 5d1002c69..449abece5 100644 --- a/backend/src/tools/lru_cache.rs +++ b/backend/src/tools/lru_cache.rs @@ -1,5 +1,5 @@ use crate::utils::{hash_string_as_hex, traverse_dir}; -use crate::utils::human_readable_byte_size; +use shared::utils::human_readable_byte_size; use log::{debug, error, info, trace}; use std::collections::{HashMap, VecDeque}; use std::fs; diff --git a/backend/src/utils/file/config_reader.rs b/backend/src/utils/file/config_reader.rs index b4cb5ee05..8e1cee9f8 100644 --- a/backend/src/utils/file/config_reader.rs +++ b/backend/src/utils/file/config_reader.rs @@ -4,7 +4,7 @@ use crate::tuliprox_error::{create_tuliprox_error, info_err, to_io_error, Tulip use crate::utils::{open_file, EnvResolvingReader}; use crate::utils::{file_reader}; use crate::utils::sys_utils::exit; -use crate::utils::CONSTANTS; +use shared::utils::CONSTANTS; use chrono::Local; use log::{error, info, warn}; use serde::Serialize; diff --git a/backend/src/utils/file/file_utils.rs b/backend/src/utils/file/file_utils.rs index b48de93d4..0e9ac14fc 100644 --- a/backend/src/utils/file/file_utils.rs +++ b/backend/src/utils/file/file_utils.rs @@ -7,7 +7,7 @@ use std::{env, fs}; use crate::tuliprox_error::str_to_io_error; use crate::utils::debug_if_enabled; -use crate::utils::{API_PROXY_FILE, CONFIG_FILE, CONFIG_PATH, MAPPING_FILE, SOURCE_FILE, USER_FILE}; +use shared::utils::{API_PROXY_FILE, CONFIG_FILE, CONFIG_PATH, MAPPING_FILE, SOURCE_FILE, USER_FILE}; use log::{debug, error}; use path_clean::PathClean; diff --git a/backend/src/utils/mod.rs b/backend/src/utils/mod.rs index c00abeaae..8d5c730bf 100644 --- a/backend/src/utils/mod.rs +++ b/backend/src/utils/mod.rs @@ -1,6 +1,4 @@ -mod string_utils; mod json_utils; -mod size_utils; mod sys_utils; mod hash_utils; mod compression; @@ -8,7 +6,6 @@ mod file; mod network; mod bincode_utils; mod crypto_utils; -mod constants; mod step_measure; pub mod logging; pub mod trakt; @@ -59,9 +56,7 @@ pub use debug_if_enabled; pub use trace_if_enabled; pub use with; -pub use self::string_utils::*; pub use self::json_utils::*; -pub use self::size_utils::*; pub use self::sys_utils::*; pub use self::hash_utils::*; pub use self::compression::*; @@ -69,5 +64,4 @@ pub use self::file::*; pub use self::network::*; pub use self::bincode_utils::*; pub use self::crypto_utils::*; -pub use self::constants::*; pub use self::step_measure::*; diff --git a/backend/src/utils/network/request.rs b/backend/src/utils/network/request.rs index f99e4b7ae..73bab66ed 100644 --- a/backend/src/utils/network/request.rs +++ b/backend/src/utils/network/request.rs @@ -22,13 +22,10 @@ use crate::model::{ConfigInput, InputFetchMethod}; use crate::repository::storage::{get_input_storage_path}; use crate::repository::storage_const; use crate::utils::compression::compression_utils::{is_deflate, is_gzip}; -use crate::utils::{debug_if_enabled, filter_request_header, short_hash}; +use crate::utils::{debug_if_enabled, short_hash}; +use shared::utils::{filter_request_header}; use crate::utils::{get_file_path, persist_file}; -use crate::utils::{CONSTANTS, DASH_EXT, DASH_EXT_FRAGMENT, DASH_EXT_QUERY, ENCODING_DEFLATE, ENCODING_GZIP, HLS_EXT, HLS_EXT_FRAGMENT, HLS_EXT_QUERY}; - -pub const fn bytes_to_megabytes(bytes: u64) -> u64 { - bytes / 1_048_576 -} +use shared::utils::{CONSTANTS, DASH_EXT, DASH_EXT_FRAGMENT, DASH_EXT_QUERY, ENCODING_DEFLATE, ENCODING_GZIP, HLS_EXT, HLS_EXT_FRAGMENT, HLS_EXT_QUERY}; pub async fn get_input_epg_content_as_file(client: Arc, input: &ConfigInput, working_dir: &str, url_str: &str, persist_filepath: Option) -> Result { debug_if_enabled!("getting input epg content working_dir: {}, url: {}", working_dir, sanitize_sensitive_info(url_str)); diff --git a/backend/src/utils/sys_utils.rs b/backend/src/utils/sys_utils.rs index e6b4a7fe4..a683a4f5c 100644 --- a/backend/src/utils/sys_utils.rs +++ b/backend/src/utils/sys_utils.rs @@ -7,7 +7,7 @@ macro_rules! exit { } pub use exit; #[cfg(target_os = "linux")] -use crate::utils::CONSTANTS; +use shared::utils::CONSTANTS; #[cfg(target_os = "linux")] fn get_memory_usage_linux() -> std::io::Result { diff --git a/backend/src/utils/trakt/mod.rs b/backend/src/utils/trakt/mod.rs index fb51ced11..41db3b443 100644 --- a/backend/src/utils/trakt/mod.rs +++ b/backend/src/utils/trakt/mod.rs @@ -1,9 +1,12 @@ // Common utilities for Trakt functionality -pub mod client; -pub mod errors; +mod client; +mod errors; + +pub use self::client::*; +pub use self::errors::*; use deunicode::deunicode; -use crate::utils::CONSTANTS; +use shared::utils::CONSTANTS; /// Normalize title for matching - optimized version with reduced allocations pub fn normalize_title_for_matching(title: &str) -> String { diff --git a/shared/Cargo.toml b/shared/Cargo.toml index eb50051cd..2433de59e 100644 --- a/shared/Cargo.toml +++ b/shared/Cargo.toml @@ -6,3 +6,5 @@ edition = "2021" [dependencies] bitflags = "2.9.1" serde = { version = "1.0.219", features = ["derive"] } +rand = "0.9.1" +regex = "1.11.1" diff --git a/backend/src/utils/constants.rs b/shared/src/utils/constants.rs similarity index 100% rename from backend/src/utils/constants.rs rename to shared/src/utils/constants.rs diff --git a/shared/src/utils/mod.rs b/shared/src/utils/mod.rs index 4dc975585..c02c842ed 100644 --- a/shared/src/utils/mod.rs +++ b/shared/src/utils/mod.rs @@ -1,5 +1,11 @@ mod default_utils; mod time_utils; +mod string_utils; +mod size_utils; +mod constants; pub use self::default_utils::*; pub use self::time_utils::*; +pub use self::string_utils::*; +pub use self::size_utils::*; +pub use self::constants::*; diff --git a/backend/src/utils/size_utils.rs b/shared/src/utils/size_utils.rs similarity index 97% rename from backend/src/utils/size_utils.rs rename to shared/src/utils/size_utils.rs index 3b4e3efb9..5e8d39d26 100644 --- a/backend/src/utils/size_utils.rs +++ b/shared/src/utils/size_utils.rs @@ -1,5 +1,10 @@ use std::str::FromStr; +# [inline] +pub const fn bytes_to_megabytes(bytes: u64) -> u64 { + bytes / 1_048_576 +} + // pub fn parse_size_base_10(size_str: &str) -> Result { // let units = [ // ("KB", 1_000u64), // Kilobytes (Base 10) diff --git a/backend/src/utils/string_utils.rs b/shared/src/utils/string_utils.rs similarity index 72% rename from backend/src/utils/string_utils.rs rename to shared/src/utils/string_utils.rs index 4d97af63c..c866c0e6b 100644 --- a/backend/src/utils/string_utils.rs +++ b/shared/src/utils/string_utils.rs @@ -1,20 +1,5 @@ use rand::Rng; -// other implementations like calculating text_distance on all titles took too much time -// we keep it now as simple as possible and less memory intensive. -pub fn get_title_group(text: &str) -> String { - let alphabetic_only: String = text.chars().map(|c| if c.is_alphanumeric() { c } else { ' ' }).collect(); - let parts = alphabetic_only.split_whitespace(); - let mut combination = String::new(); - for p in parts { - combination = format!("{combination} {p}").trim().to_string(); - if combination.len() > 2 { - return combination; - } - } - text.to_string() -} - pub trait Capitalize { fn capitalize(&self) -> String; } @@ -70,7 +55,7 @@ pub fn get_non_empty_str<'a>(first: &'a str, second: &'a str, third: &'a str) -> #[cfg(test)] mod test { use std::collections::HashSet; - use crate::utils::{generate_random_string, Capitalize}; + use super::generate_random_string; #[test] fn test_generate_random_string() { From 7f54327bfd8b6c8eccfa0899af30d458dc1df2c9 Mon Sep 17 00:00:00 2001 From: euzu Date: Thu, 19 Jun 2025 16:37:37 +0200 Subject: [PATCH 4/9] config added to shared model --- Cargo.lock | 1 + backend/src/api/config_watch.rs | 2 +- backend/src/api/endpoints/download_api.rs | 2 +- backend/src/api/endpoints/v1_api.rs | 2 +- backend/src/api/endpoints/xtream_api.rs | 6 +- backend/src/api/model/config.rs | 4 +- backend/src/auth/authenticator.rs | 2 +- backend/src/auth/password.rs | 2 +- backend/src/foundation/filter.rs | 8 +- backend/src/foundation/mapper.rs | 2 +- backend/src/messaging.rs | 13 +- backend/src/model/config.rs | 83 +------------ backend/src/model/config_api_proxy.rs | 2 +- backend/src/model/config_cache.rs | 2 +- backend/src/model/config_download.rs | 2 +- backend/src/model/config_epg.rs | 2 +- backend/src/model/config_hdhomerun.rs | 2 +- backend/src/model/config_input.rs | 2 +- backend/src/model/config_ip_check.rs | 2 +- backend/src/model/config_messaging.rs | 2 +- backend/src/model/config_proxy.rs | 2 +- backend/src/model/config_rename.rs | 4 +- backend/src/model/config_sort.rs | 4 +- backend/src/model/config_source.rs | 2 +- backend/src/model/config_target.rs | 30 +---- backend/src/model/config_web_auth.rs | 2 +- backend/src/model/config_webui.rs | 2 +- backend/src/model/mapping.rs | 4 +- backend/src/model/mod.rs | 2 - backend/src/modules.rs | 1 - backend/src/processing/parser/xmltv.rs | 2 +- backend/src/processing/parser/xtream.rs | 2 +- backend/src/processing/playlist_watch.rs | 3 +- backend/src/processing/processor/playlist.rs | 8 +- backend/src/processing/processor/trakt.rs | 2 +- backend/src/processing/processor/xtream.rs | 4 +- .../src/processing/processor/xtream_series.rs | 4 +- .../src/processing/processor/xtream_vod.rs | 4 +- backend/src/repository/bplustree.rs | 2 +- backend/src/repository/epg_repository.rs | 2 +- backend/src/repository/indexed_document.rs | 2 +- .../src/repository/m3u_playlist_iterator.rs | 4 +- backend/src/repository/m3u_repository.rs | 4 +- backend/src/repository/playlist_repository.rs | 4 +- backend/src/repository/storage.rs | 4 +- backend/src/repository/strm_repository.rs | 25 ++-- .../repository/xtream_playlist_iterator.rs | 4 +- backend/src/repository/xtream_repository.rs | 2 +- backend/src/utils/bincode_utils.rs | 2 +- backend/src/utils/crypto_utils.rs | 2 +- backend/src/utils/file/config_reader.rs | 4 +- backend/src/utils/file/csv_input_reader.rs | 2 +- backend/src/utils/file/file_lock_manager.rs | 2 +- backend/src/utils/file/file_utils.rs | 2 +- backend/src/utils/file/mapping_reader.rs | 2 +- backend/src/utils/network/epg.rs | 2 +- backend/src/utils/network/ip_checker.rs | 2 +- backend/src/utils/network/m3u.rs | 2 +- backend/src/utils/network/request.rs | 4 +- backend/src/utils/network/xtream.rs | 6 +- backend/src/utils/trakt/client.rs | 4 +- backend/src/utils/trakt/errors.rs | 2 +- shared/Cargo.toml | 1 + shared/src/error/mod.rs | 3 + .../src/error}/tuliprox_error.rs | 0 shared/src/lib.rs | 1 + shared/src/model/config/base.rs | 56 +++++++++ shared/src/model/config/cache.rs | 10 ++ shared/src/model/config/epg.rs | 49 ++++++++ shared/src/model/config/hdhomerun.rs | 45 +++++++ shared/src/model/config/input.rs | 91 ++++++++++++++ shared/src/model/config/ipcheck.rs | 24 ++++ shared/src/model/config/log.rs | 12 ++ shared/src/model/config/messaging.rs | 36 ++++++ shared/src/model/config/mod.rs | 38 ++++++ shared/src/model/config/proxy.rs | 8 ++ shared/src/model/config/rate_limit.rs | 7 ++ shared/src/model/config/reverse_proxy.rs | 16 +++ shared/src/model/config/schedule.rs | 9 ++ shared/src/model/config/sort.rs | 40 +++++++ shared/src/model/config/source.rs | 41 +++++++ shared/src/model/config/stream.rs | 29 +++++ shared/src/model/config/target.rs | 112 ++++++++++++++++++ shared/src/model/config/trakt.rs | 49 ++++++++ shared/src/model/config/video.rs | 25 ++++ shared/src/model/config/web.rs | 27 +++++ shared/src/model/item_field.rs | 83 +++++++++++++ shared/src/model/messaging.rs | 12 ++ shared/src/model/mod.rs | 14 ++- .../src/model/processing_order.rs | 0 shared/src/model/strm_export_style.rs | 15 +++ shared/src/model/target_type.rs | 32 +++++ 92 files changed, 982 insertions(+), 219 deletions(-) create mode 100644 shared/src/error/mod.rs rename {backend/src => shared/src/error}/tuliprox_error.rs (100%) create mode 100644 shared/src/model/config/base.rs create mode 100644 shared/src/model/config/cache.rs create mode 100644 shared/src/model/config/epg.rs create mode 100644 shared/src/model/config/hdhomerun.rs create mode 100644 shared/src/model/config/input.rs create mode 100644 shared/src/model/config/ipcheck.rs create mode 100644 shared/src/model/config/log.rs create mode 100644 shared/src/model/config/messaging.rs create mode 100644 shared/src/model/config/mod.rs create mode 100644 shared/src/model/config/proxy.rs create mode 100644 shared/src/model/config/rate_limit.rs create mode 100644 shared/src/model/config/reverse_proxy.rs create mode 100644 shared/src/model/config/schedule.rs create mode 100644 shared/src/model/config/sort.rs create mode 100644 shared/src/model/config/source.rs create mode 100644 shared/src/model/config/stream.rs create mode 100644 shared/src/model/config/target.rs create mode 100644 shared/src/model/config/trakt.rs create mode 100644 shared/src/model/config/video.rs create mode 100644 shared/src/model/config/web.rs create mode 100644 shared/src/model/item_field.rs create mode 100644 shared/src/model/messaging.rs rename {backend => shared}/src/model/processing_order.rs (100%) create mode 100644 shared/src/model/strm_export_style.rs create mode 100644 shared/src/model/target_type.rs diff --git a/Cargo.lock b/Cargo.lock index 901cdfc46..bea55808c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2581,6 +2581,7 @@ name = "shared" version = "0.1.0" dependencies = [ "bitflags 2.9.1", + "enum-iterator", "rand", "regex", "serde", diff --git a/backend/src/api/config_watch.rs b/backend/src/api/config_watch.rs index 403419910..fce37decd 100644 --- a/backend/src/api/config_watch.rs +++ b/backend/src/api/config_watch.rs @@ -1,5 +1,5 @@ use crate::api::model::app_state::AppState; -use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind}; +use shared::error::{TuliproxError, TuliproxErrorKind}; use crate::utils; use crate::utils::is_directory; use log::{debug, error, info}; diff --git a/backend/src/api/endpoints/download_api.rs b/backend/src/api/endpoints/download_api.rs index 8561581b3..d58146e8e 100644 --- a/backend/src/api/endpoints/download_api.rs +++ b/backend/src/api/endpoints/download_api.rs @@ -13,7 +13,7 @@ use std::sync::Arc; use std::{fs}; use axum::response::IntoResponse; use shared::utils::bytes_to_megabytes; -use crate::tuliprox_error::to_io_error; +use shared::error::to_io_error; use crate::utils::request::create_client; async fn download_file(active: Arc>>, client: &reqwest::Client) -> Result<(), String> { diff --git a/backend/src/api/endpoints/v1_api.rs b/backend/src/api/endpoints/v1_api.rs index 6857f9364..f9c7e417b 100644 --- a/backend/src/api/endpoints/v1_api.rs +++ b/backend/src/api/endpoints/v1_api.rs @@ -6,7 +6,7 @@ use crate::api::model::config::{ServerConfig, ServerInputConfig, ServerSourceCon use crate::api::model::request::{PlaylistRequest, PlaylistRequestType}; use crate::auth::create_access_token; use crate::auth::validator_admin; -use crate::tuliprox_error::TuliproxError; +use shared::error::TuliproxError; use crate::model::StatusCheck; use crate::model::XtreamPlaylistItem; use crate::model::{Config, ConfigDto, ConfigInput, ConfigInputOptions, ConfigSource, ConfigTarget, InputType}; diff --git a/backend/src/api/endpoints/xtream_api.rs b/backend/src/api/endpoints/xtream_api.rs index 4a5f710c1..b1107e8c1 100644 --- a/backend/src/api/endpoints/xtream_api.rs +++ b/backend/src/api/endpoints/xtream_api.rs @@ -16,9 +16,9 @@ use crate::model::{ProxyType, ProxyUserCredentials, UserConnectionPermission}; use crate::repository::playlist_repository::get_target_id_mapping; use crate::repository::storage::{get_target_storage_path}; use crate::repository::{storage_const, user_repository, xtream_repository}; -use crate::tuliprox_error::create_tuliprox_error_result; -use crate::tuliprox_error::info_err; -use crate::tuliprox_error::{str_to_io_error, TuliproxError, TuliproxErrorKind}; +use shared::error::create_tuliprox_error_result; +use shared::error::info_err; +use shared::error::{str_to_io_error, TuliproxError, TuliproxErrorKind}; use crate::utils::{generate_playlist_uuid, hex_encode}; use crate::utils::get_u32_from_serde_value; use crate::utils::request::{extract_extension_from_url, sanitize_sensitive_info}; diff --git a/backend/src/api/model/config.rs b/backend/src/api/model/config.rs index bbb243701..673f5e81f 100644 --- a/backend/src/api/model/config.rs +++ b/backend/src/api/model/config.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; - -use crate::model::{ApiProxyConfig, ConfigApi, InputType, LogConfig, MessagingConfig, ProcessingOrder, ReverseProxyConfig, ScheduleConfig, VideoConfig, ConfigRename, ConfigSort, ConfigTargetOptions, TargetOutput, WebUiConfig, ProxyConfig, IpCheckConfig}; +use shared::model::ProcessingOrder; +use crate::model::{ApiProxyConfig, ConfigApi, InputType, LogConfig, MessagingConfig, ReverseProxyConfig, ScheduleConfig, VideoConfig, ConfigRename, ConfigSort, ConfigTargetOptions, TargetOutput, WebUiConfig, ProxyConfig, IpCheckConfig}; #[derive(Deserialize, Serialize, Debug, Clone)] pub struct ServerInputConfig { diff --git a/backend/src/auth/authenticator.rs b/backend/src/auth/authenticator.rs index 64c9380c0..be3577c10 100644 --- a/backend/src/auth/authenticator.rs +++ b/backend/src/auth/authenticator.rs @@ -5,7 +5,7 @@ use crate::api::api_utils::get_username_from_auth_header; use crate::model::WebAuthConfig; use crate::api::model::app_state::AppState; use crate::auth::AuthBearer; -use crate::tuliprox_error::to_io_error; +use shared::error::to_io_error; const ROLE_ADMIN: &str = "ADMIN"; const ROLE_USER: &str = "USER"; diff --git a/backend/src/auth/password.rs b/backend/src/auth/password.rs index fea9a30be..6a80906ea 100644 --- a/backend/src/auth/password.rs +++ b/backend/src/auth/password.rs @@ -1,6 +1,6 @@ use rand::{Rng}; use rand::distr::Alphanumeric; -use crate::tuliprox_error::str_to_io_error; +use shared::error::str_to_io_error; fn generate_salt(length: usize) -> String { let salt: String = rand::rng() diff --git a/backend/src/foundation/filter.rs b/backend/src/foundation/filter.rs index 37383fe9a..e809faace 100644 --- a/backend/src/foundation/filter.rs +++ b/backend/src/foundation/filter.rs @@ -8,11 +8,11 @@ use pest::iterators::Pair; use pest::Parser; use std::cmp::Ordering; use std::collections::HashMap; -use shared::model::{FieldGetAccessor, FieldSetAccessor, PlaylistItemType}; -use crate::model::{PlaylistItem, ItemField}; +use shared::model::{FieldGetAccessor, FieldSetAccessor, ItemField, PlaylistItemType}; +use crate::model::{PlaylistItem}; use crate::tools::directed_graph::DirectedGraph; -use crate::tuliprox_error::{create_tuliprox_error_result, info_err}; -use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind}; +use shared::error::{create_tuliprox_error_result, info_err}; +use shared::error::{TuliproxError, TuliproxErrorKind}; use shared::utils::CONSTANTS; pub fn get_field_value(pli: &PlaylistItem, field: ItemField) -> String { diff --git a/backend/src/foundation/mapper.rs b/backend/src/foundation/mapper.rs index ac536bb9f..2e23478ed 100644 --- a/backend/src/foundation/mapper.rs +++ b/backend/src/foundation/mapper.rs @@ -2,7 +2,7 @@ use crate::foundation::filter::{PatternTemplate, TemplateValue, ValueAccessor}; use crate::foundation::mapper::EvalResult::{AnyValue, Failure, Named, Number, Undefined, Value}; -use crate::tuliprox_error::{create_tuliprox_error_result, info_err, TuliproxError, TuliproxErrorKind}; +use shared::error::{create_tuliprox_error_result, info_err, TuliproxError, TuliproxErrorKind}; use shared::utils::Capitalize; use log::{debug, trace}; use pest::iterators::{Pair, Pairs}; diff --git a/backend/src/messaging.rs b/backend/src/messaging.rs index 5b4fb8b5a..6a8e5ddb1 100644 --- a/backend/src/messaging.rs +++ b/backend/src/messaging.rs @@ -2,18 +2,7 @@ use std::sync::Arc; use crate::model::{MessagingConfig}; use log::{debug, error}; use reqwest::{header}; - -#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)] -pub enum MsgKind { - #[serde(rename = "info")] - Info, - #[serde(rename = "stats")] - Stats, - #[serde(rename = "error")] - Error, - #[serde(rename = "watch")] - Watch, -} +use shared::model::MsgKind; fn is_enabled(kind: MsgKind, cfg: &MessagingConfig) -> bool { cfg.notify_on.contains(&kind) diff --git a/backend/src/model/config.rs b/backend/src/model/config.rs index 750c80e03..2e48a793e 100644 --- a/backend/src/model/config.rs +++ b/backend/src/model/config.rs @@ -1,11 +1,8 @@ use arc_swap::{ArcSwapOption}; -use enum_iterator::Sequence; use std::collections::{HashSet}; -use std::fmt::Display; use std::fs::File; use std::io::Read; use std::path::{Path, PathBuf}; -use std::str::FromStr; use std::sync::Arc; use log::{debug, error, warn}; @@ -14,7 +11,7 @@ use rand::Rng; use crate::model::{ApiProxyConfig, ApiProxyServerInfo, Mappings, ProxyUserCredentials, SourcesConfig}; use crate::model::{ConfigInput, ConfigInputOptions, ConfigTarget, HdHomeRunConfig, IpCheckConfig, LogConfig, MessagingConfig, ProxyConfig, TargetOutput, VideoConfig, WebUiConfig}; -use crate::tuliprox_error::{create_tuliprox_error_result, TuliproxError, TuliproxErrorKind}; +use shared::error::{create_tuliprox_error_result, TuliproxError, TuliproxErrorKind}; use shared::utils::{parse_to_kbps, default_connect_timeout_secs, default_grace_period_millis, default_grace_period_timeout_secs}; const STREAM_QUEUE_SIZE: usize = 1024; // mpsc channel holding messages. with 8192byte chunks and 2Mbit/s approx 8MB @@ -43,84 +40,6 @@ use crate::api::model::streams::transport_stream_buffer::TransportStreamBuffer; use crate::model::config_cache::CacheConfig; use crate::utils; -#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, Sequence, Eq, PartialEq)] -pub enum ItemField { - #[serde(rename = "group")] - Group, - #[serde(rename = "name")] - Name, - #[serde(rename = "title")] - Title, - #[serde(rename = "url")] - Url, - #[serde(rename = "input")] - Input, - #[serde(rename = "type")] - Type, - #[serde(rename = "caption")] - Caption, -} - -impl ItemField { - const GROUP: &'static str = "Group"; - const NAME: &'static str = "Name"; - const TITLE: &'static str = "Title"; - const URL: &'static str = "Url"; - const INPUT: &'static str = "Input"; - const TYPE: &'static str = "Type"; - const CAPTION: &'static str = "Caption"; - - pub fn as_str(&self) -> &'static str { - match *self { - Self::Group => Self::GROUP, - Self::Name => Self::NAME, - Self::Title => Self::TITLE, - Self::Url => Self::URL, - Self::Input => Self::INPUT, - Self::Type => Self::TYPE, - Self::Caption => Self::CAPTION, - } - } -} - -impl Display for ItemField { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", match *self { - Self::Group => Self::GROUP, - Self::Name => Self::NAME, - Self::Title => Self::TITLE, - Self::Url => Self::URL, - Self::Input => Self::INPUT, - Self::Type => Self::TYPE, - Self::Caption => Self::CAPTION, - }) - } -} - -impl FromStr for ItemField { - type Err = TuliproxError; - - fn from_str(s: &str) -> Result { - if s.eq_ignore_ascii_case(Self::GROUP) { - Ok(Self::Group) - } else if s.eq_ignore_ascii_case(Self::NAME) { - Ok(Self::Name) - } else if s.eq_ignore_ascii_case(Self::TITLE) { - Ok(Self::Title) - } else if s.eq_ignore_ascii_case(Self::CAPTION) { - Ok(Self::Caption) - } else if s.eq_ignore_ascii_case(Self::URL) { - Ok(Self::Url) - } else if s.eq_ignore_ascii_case(Self::INPUT) { - Ok(Self::Input) - } else if s.eq_ignore_ascii_case(Self::TYPE) { - Ok(Self::Type) - } else { - create_tuliprox_error_result!(TuliproxErrorKind::Info, "Unknown InputType: {}", s) - } - } -} - #[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize)] pub enum FilterMode { diff --git a/backend/src/model/config_api_proxy.rs b/backend/src/model/config_api_proxy.rs index f25f31f73..29aeae7fc 100644 --- a/backend/src/model/config_api_proxy.rs +++ b/backend/src/model/config_api_proxy.rs @@ -1,5 +1,5 @@ use crate::api::model::app_state::AppState; -use crate::tuliprox_error::{create_tuliprox_error_result, info_err, TuliproxError, TuliproxErrorKind}; +use shared::error::{create_tuliprox_error_result, info_err, TuliproxError, TuliproxErrorKind}; use crate::model::{Config}; use crate::repository::user_repository::{backup_api_user_db_file, get_api_user_db_path, load_api_user, merge_api_user}; use crate::utils::{save_api_proxy}; diff --git a/backend/src/model/config_cache.rs b/backend/src/model/config_cache.rs index 829e3f940..3ddf1195c 100644 --- a/backend/src/model/config_cache.rs +++ b/backend/src/model/config_cache.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use log::error; use path_clean::PathClean; -use crate::tuliprox_error::{info_err, TuliproxError, TuliproxErrorKind}; +use shared::error::{info_err, TuliproxError, TuliproxErrorKind}; use shared::utils::parse_size_base_2; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] diff --git a/backend/src/model/config_download.rs b/backend/src/model/config_download.rs index 6c7e39a9b..eb072a509 100644 --- a/backend/src/model/config_download.rs +++ b/backend/src/model/config_download.rs @@ -1,4 +1,4 @@ -use crate::tuliprox_error::{create_tuliprox_error_result, TuliproxError, TuliproxErrorKind}; +use shared::error::{create_tuliprox_error_result, TuliproxError, TuliproxErrorKind}; use regex::Regex; use std::borrow::BorrowMut; use std::collections::HashMap; diff --git a/backend/src/model/config_epg.rs b/backend/src/model/config_epg.rs index e4a0677c7..74cbe3043 100644 --- a/backend/src/model/config_epg.rs +++ b/backend/src/model/config_epg.rs @@ -1,4 +1,4 @@ -use crate::tuliprox_error::{create_tuliprox_error_result, info_err, TuliproxError, TuliproxErrorKind}; +use shared::error::{create_tuliprox_error_result, info_err, TuliproxError, TuliproxErrorKind}; use shared::utils::CONSTANTS; use log::warn; use regex::Regex; diff --git a/backend/src/model/config_hdhomerun.rs b/backend/src/model/config_hdhomerun.rs index ad820ac49..f74e65cf5 100644 --- a/backend/src/model/config_hdhomerun.rs +++ b/backend/src/model/config_hdhomerun.rs @@ -1,6 +1,6 @@ use std::collections::HashSet; use log::warn; -use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind, create_tuliprox_error_result}; +use shared::error::{TuliproxError, TuliproxErrorKind, create_tuliprox_error_result}; fn default_friendly_name() -> String { String::from("TuliproxTV") } fn default_manufacturer() -> String { String::from("Silicondust") } fn default_model_name() -> String { String::from("HDTC-2US") } diff --git a/backend/src/model/config_input.rs b/backend/src/model/config_input.rs index 5291c66d1..0cc5db511 100644 --- a/backend/src/model/config_input.rs +++ b/backend/src/model/config_input.rs @@ -1,4 +1,4 @@ -use crate::tuliprox_error::{create_tuliprox_error_result, handle_tuliprox_error_result_list, info_err, TuliproxError, TuliproxErrorKind}; +use shared::error::{create_tuliprox_error_result, handle_tuliprox_error_result_list, info_err, TuliproxError, TuliproxErrorKind}; use crate::model::{EpgConfig}; use shared::utils::default_as_true; use shared::utils::get_trimmed_string; diff --git a/backend/src/model/config_ip_check.rs b/backend/src/model/config_ip_check.rs index aa60a6a60..8701a1611 100644 --- a/backend/src/model/config_ip_check.rs +++ b/backend/src/model/config_ip_check.rs @@ -1,5 +1,5 @@ use regex::Regex; -use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind}; +use shared::error::{TuliproxError, TuliproxErrorKind}; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] #[serde(deny_unknown_fields)] diff --git a/backend/src/model/config_messaging.rs b/backend/src/model/config_messaging.rs index 6f57c7c52..c9e76b99e 100644 --- a/backend/src/model/config_messaging.rs +++ b/backend/src/model/config_messaging.rs @@ -1,4 +1,4 @@ -use crate::messaging::MsgKind; +use shared::model::MsgKind; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[serde(deny_unknown_fields)] diff --git a/backend/src/model/config_proxy.rs b/backend/src/model/config_proxy.rs index 31dab8a01..3a9fc014e 100644 --- a/backend/src/model/config_proxy.rs +++ b/backend/src/model/config_proxy.rs @@ -1,4 +1,4 @@ -use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind}; +use shared::error::{TuliproxError, TuliproxErrorKind}; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] #[serde(deny_unknown_fields)] diff --git a/backend/src/model/config_rename.rs b/backend/src/model/config_rename.rs index b8f44621c..04df7e13e 100644 --- a/backend/src/model/config_rename.rs +++ b/backend/src/model/config_rename.rs @@ -1,6 +1,6 @@ +use shared::model::ItemField; use crate::foundation::filter::{apply_templates_to_pattern_single, PatternTemplate}; -use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind, create_tuliprox_error_result}; -use crate::model::ItemField; +use shared::error::{TuliproxError, TuliproxErrorKind, create_tuliprox_error_result}; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[serde(deny_unknown_fields)] diff --git a/backend/src/model/config_sort.rs b/backend/src/model/config_sort.rs index 65ff486a4..0826aa4cf 100644 --- a/backend/src/model/config_sort.rs +++ b/backend/src/model/config_sort.rs @@ -1,7 +1,7 @@ use regex::Regex; use crate::foundation::filter::{apply_templates_to_pattern, apply_templates_to_pattern_single, PatternTemplate, TemplateValue}; -use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind, create_tuliprox_error, handle_tuliprox_error_result_list}; -use crate::model::{ItemField}; +use shared::error::{TuliproxError, TuliproxErrorKind, create_tuliprox_error, handle_tuliprox_error_result_list}; +use shared::model::ItemField; #[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize)] pub enum SortOrder { diff --git a/backend/src/model/config_source.rs b/backend/src/model/config_source.rs index e7ab5639b..d861eaa8e 100644 --- a/backend/src/model/config_source.rs +++ b/backend/src/model/config_source.rs @@ -1,6 +1,6 @@ use std::collections::{HashMap, HashSet}; use crate::foundation::filter::{prepare_templates, PatternTemplate}; -use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind, handle_tuliprox_error_result_list, create_tuliprox_error_result}; +use shared::error::{TuliproxError, TuliproxErrorKind, handle_tuliprox_error_result_list, create_tuliprox_error_result}; use crate::model::{ConfigInput, ProcessTargets}; use crate::model::config_target::ConfigTarget; use shared::utils::default_as_default; diff --git a/backend/src/model/config_target.rs b/backend/src/model/config_target.rs index 6a999d85e..c914e5795 100644 --- a/backend/src/model/config_target.rs +++ b/backend/src/model/config_target.rs @@ -2,40 +2,16 @@ use crate::foundation::filter::{get_filter, Filter, PatternTemplate, ValueProvid use crate::model::config_rename::ConfigRename; use crate::model::config_sort::ConfigSort; use crate::model::mapping::Mapping; -use crate::model::processing_order::ProcessingOrder; use crate::model::trakt::TraktConfig; -use crate::tuliprox_error::{create_tuliprox_error_result, handle_tuliprox_error_result_list, info_err, TuliproxError, TuliproxErrorKind}; +use shared::error::{create_tuliprox_error_result, handle_tuliprox_error_result_list, info_err, TuliproxError, TuliproxErrorKind}; use shared::utils::{default_as_default, default_as_true, default_resolve_delay_secs}; use arc_swap::ArcSwapOption; use enum_iterator::Sequence; -use shared::model::ClusterFlags; +use shared::model::{ClusterFlags, ProcessingOrder, StrmExportStyle}; use shared::model::PlaylistItemType; use std::fmt::Display; use std::sync::Arc; -#[derive( - Debug, - Copy, - Clone, - serde::Serialize, - serde::Deserialize, - Sequence, - PartialEq, - Eq, - Hash, - Default -)] -pub enum ExportStyle { - #[serde(rename = "kodi")] - #[default] - Kodi, - #[serde(rename = "plex")] - Plex, - #[serde(rename = "emby")] - Emby, - #[serde(rename = "jellyfin")] - Jellyfin, -} #[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, Sequence, PartialEq, Eq, Hash)] pub enum TargetType { @@ -165,7 +141,7 @@ pub struct StrmTargetOutput { #[serde(default, skip_serializing_if = "Option::is_none")] pub username: Option, #[serde(default)] - pub style: ExportStyle, + pub style: StrmExportStyle, #[serde(default)] pub flat: bool, #[serde(default)] diff --git a/backend/src/model/config_web_auth.rs b/backend/src/model/config_web_auth.rs index a1a424035..7e4901d17 100644 --- a/backend/src/model/config_web_auth.rs +++ b/backend/src/model/config_web_auth.rs @@ -3,7 +3,7 @@ use std::fs::File; use std::io::BufRead; use std::path::PathBuf; use crate::auth::UserCredential; -use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind, create_tuliprox_error_result}; +use shared::error::{TuliproxError, TuliproxErrorKind, create_tuliprox_error_result}; use crate::utils; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] diff --git a/backend/src/model/config_webui.rs b/backend/src/model/config_webui.rs index 425e4a051..2f060168f 100644 --- a/backend/src/model/config_webui.rs +++ b/backend/src/model/config_webui.rs @@ -1,5 +1,5 @@ use shared::utils::default_as_true; -use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind}; +use shared::error::{TuliproxError, TuliproxErrorKind}; use crate::model::WebAuthConfig; const RESERVED_PATHS: &[&str] = &[ diff --git a/backend/src/model/mapping.rs b/backend/src/model/mapping.rs index 3ee28d58d..01f74f131 100644 --- a/backend/src/model/mapping.rs +++ b/backend/src/model/mapping.rs @@ -7,8 +7,8 @@ use log::{trace}; use crate::foundation::filter::{apply_templates_to_pattern_single, get_filter, prepare_templates, Filter, PatternTemplate}; use crate::foundation::mapper::MapperScript; use crate::model::valid_property; -use crate::tuliprox_error::{create_tuliprox_error_result, info_err}; -use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind}; +use shared::error::{create_tuliprox_error_result, info_err}; +use shared::error::{TuliproxError, TuliproxErrorKind}; pub const COUNTER_FIELDS: &[&str] = &["name", "title", "caption", "chno"]; diff --git a/backend/src/model/mod.rs b/backend/src/model/mod.rs index 1591fb34e..2c1f6d00c 100644 --- a/backend/src/model/mod.rs +++ b/backend/src/model/mod.rs @@ -13,7 +13,6 @@ mod config_hdhomerun; mod config_ip_check; mod config_sort; mod config_rename; -mod processing_order; mod config_target; mod config_source; mod config_proxy; @@ -42,7 +41,6 @@ pub use self::config_webui::*; pub use self::config_ip_check::*; pub use self::config_sort::*; pub use self::config_rename::*; -pub use self::processing_order::*; pub use self::config_target::*; pub use self::config_source::*; pub use self::config_proxy::*; diff --git a/backend/src/modules.rs b/backend/src/modules.rs index 279a067fd..250cec351 100644 --- a/backend/src/modules.rs +++ b/backend/src/modules.rs @@ -8,7 +8,6 @@ macro_rules! include_modules { extern crate pest_derive; pub mod api; pub mod auth; - pub mod tuliprox_error; pub mod messaging; pub mod model; pub mod processing; diff --git a/backend/src/processing/parser/xmltv.rs b/backend/src/processing/parser/xmltv.rs index c3b6ef5f3..88a34c0db 100644 --- a/backend/src/processing/parser/xmltv.rs +++ b/backend/src/processing/parser/xmltv.rs @@ -544,7 +544,7 @@ mod tests { assert_eq!("odisea.bg", normalize_channel_name("BG | ODISEA ᵁᴴᴰ ³⁸⁴⁰ᴾ", &epg_smart_cfg)); } - use crate::tuliprox_error::TuliproxError; + use shared::error::TuliproxError; use rphonetic::{Encoder, Metaphone}; #[test] diff --git a/backend/src/processing/parser/xtream.rs b/backend/src/processing/parser/xtream.rs index e1c22e9a3..983943c9d 100644 --- a/backend/src/processing/parser/xtream.rs +++ b/backend/src/processing/parser/xtream.rs @@ -1,4 +1,4 @@ -use crate::tuliprox_error::{create_tuliprox_error_result, TuliproxError, TuliproxErrorKind}; +use shared::error::{create_tuliprox_error_result, TuliproxError, TuliproxErrorKind}; use crate::model::ConfigInput; use crate::model::{PlaylistGroup, PlaylistItem, PlaylistItemHeader}; use crate::model::{XtreamCategory, XtreamSeriesInfo, XtreamSeriesInfoEpisode, XtreamStream}; diff --git a/backend/src/processing/playlist_watch.rs b/backend/src/processing/playlist_watch.rs index f0420fff5..11f23e021 100644 --- a/backend/src/processing/playlist_watch.rs +++ b/backend/src/processing/playlist_watch.rs @@ -2,7 +2,8 @@ use std::collections::BTreeSet; use std::path::{Path}; use std::sync::Arc; use log::{error, info}; -use crate::messaging::{MsgKind, send_message}; +use shared::model::MsgKind; +use crate::messaging::{send_message}; use crate::model::Config; use crate::model::PlaylistGroup; use crate::utils; diff --git a/backend/src/processing/processor/playlist.rs b/backend/src/processing/processor/playlist.rs index 802614342..1c2a53794 100644 --- a/backend/src/processing/processor/playlist.rs +++ b/backend/src/processing/processor/playlist.rs @@ -10,17 +10,17 @@ use std::thread; use tokio::sync::Mutex; use crate::foundation::filter::{get_field_value, set_field_value, ValueProvider, ValueAccessor}; -use crate::messaging::{send_message, MsgKind}; -use crate::model::{ConfigTarget, InputType, ItemField, ProcessTargets, ProcessingOrder}; +use crate::messaging::{send_message}; +use crate::model::{ConfigTarget, InputType, ProcessTargets}; use crate::model::{CounterModifier, Mapping}; use crate::model::{FetchedPlaylist, PlaylistGroup, PlaylistItem}; -use shared::model::{FieldGetAccessor, FieldSetAccessor, PlaylistEntry, UUIDType, XtreamCluster}; +use shared::model::{FieldGetAccessor, FieldSetAccessor, ItemField, MsgKind, PlaylistEntry, ProcessingOrder, UUIDType, XtreamCluster}; use crate::model::{InputStats, PlaylistStats, SourceStats, TargetStats}; use crate::processing::playlist_watch::process_group_watch; use crate::processing::processor::xtream_series::playlist_resolve_series; use crate::processing::processor::trakt::process_trakt_categories_for_target; use crate::repository::playlist_repository::persist_playlist; -use crate::tuliprox_error::{get_errors_notify_message, notify_err, TuliproxError, TuliproxErrorKind}; +use shared::error::{get_errors_notify_message, notify_err, TuliproxError, TuliproxErrorKind}; use crate::utils::debug_if_enabled; use shared::utils::default_as_default; use deunicode::deunicode; diff --git a/backend/src/processing/processor/trakt.rs b/backend/src/processing/processor/trakt.rs index bfcf0170e..7a8cf665e 100644 --- a/backend/src/processing/processor/trakt.rs +++ b/backend/src/processing/processor/trakt.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use crate::model::{ConfigTarget, PlaylistGroup, PlaylistItem}; use shared::model::{FieldGetAccessor, FieldSetAccessor, XtreamCluster}; use crate::model::{TraktConfig, TraktContentType, TraktListConfig, TraktListItem, TraktMatchItem, TraktMatchResult}; -use crate::tuliprox_error::TuliproxError; +use shared::error::TuliproxError; use crate::utils::trakt::TraktClient; use crate::utils::trakt::extract_year_from_title; use crate::utils::trakt::normalize_title_for_matching; diff --git a/backend/src/processing/processor/xtream.rs b/backend/src/processing/processor/xtream.rs index a700a399e..adcd8cb22 100644 --- a/backend/src/processing/processor/xtream.rs +++ b/backend/src/processing/processor/xtream.rs @@ -1,5 +1,5 @@ -use crate::tuliprox_error::{info_err, notify_err}; -use crate::tuliprox_error::{str_to_io_error, TuliproxError, TuliproxErrorKind}; +use shared::error::{info_err, notify_err}; +use shared::error::{str_to_io_error, TuliproxError, TuliproxErrorKind}; use crate::model::{Config, ConfigInput}; use crate::model::{FetchedPlaylist, PlaylistItem}; use shared::model::{PlaylistEntry, PlaylistItemType, XtreamCluster}; diff --git a/backend/src/processing/processor/xtream_series.rs b/backend/src/processing/processor/xtream_series.rs index cc040229e..399851ac1 100644 --- a/backend/src/processing/processor/xtream_series.rs +++ b/backend/src/processing/processor/xtream_series.rs @@ -1,4 +1,4 @@ -use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind}; +use shared::error::{TuliproxError, TuliproxErrorKind}; use crate::model::{Config, ConfigTarget, InputType}; use crate::model::{FetchedPlaylist, PlaylistGroup, PlaylistItem}; use shared::model::{PlaylistItemType, XtreamCluster}; @@ -8,7 +8,7 @@ use crate::processing::processor::xtream::{create_resolve_episode_wal_files, cre use crate::repository::storage::get_input_storage_path; use crate::repository::xtream_repository::{write_series_info_to_wal_file, xtream_get_info_file_paths, xtream_update_input_info_file, xtream_update_input_series_episodes_record_from_wal_file, xtream_update_input_series_record_from_wal_file}; use crate::repository::IndexedDocumentReader; -use crate::tuliprox_error::{notify_err, info_err}; +use shared::error::{notify_err, info_err}; use crate::processing::processor::{handle_error, handle_error_and_return, create_resolve_options_function_for_xtream_target}; use std::collections::HashMap; use std::fs::File; diff --git a/backend/src/processing/processor/xtream_vod.rs b/backend/src/processing/processor/xtream_vod.rs index 7aa0d7ffb..a4ab90241 100644 --- a/backend/src/processing/processor/xtream_vod.rs +++ b/backend/src/processing/processor/xtream_vod.rs @@ -1,10 +1,10 @@ -use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind}; +use shared::error::{TuliproxError, TuliproxErrorKind}; use crate::model::{Config, ConfigTarget, InputType}; use crate::model::{FetchedPlaylist, PlaylistItem}; use shared::model::{PlaylistItemType, XtreamCluster}; use crate::processing::processor::xtream::{create_resolve_info_wal_files, playlist_resolve_download_playlist_item, read_processed_info_ids, should_update_info}; use crate::repository::xtream_repository::{write_vod_info_to_wal_file, xtream_update_input_info_file, xtream_update_input_vod_record_from_wal_file, InputVodInfoRecord}; -use crate::tuliprox_error::{notify_err}; +use shared::error::{notify_err}; use crate::processing::processor::{handle_error, handle_error_and_return, create_resolve_options_function_for_xtream_target}; use crate::utils::{get_u32_from_serde_value, get_u64_from_serde_value, get_string_from_serde_value}; use crate::repository::xtream_repository::xtream_get_input_info; diff --git a/backend/src/repository/bplustree.rs b/backend/src/repository/bplustree.rs index e52fed0d7..c48e523d4 100644 --- a/backend/src/repository/bplustree.rs +++ b/backend/src/repository/bplustree.rs @@ -3,7 +3,7 @@ use std::io::{self, BufReader, Read, Seek, SeekFrom, Write}; use std::marker::PhantomData; use std::mem::size_of; use std::path::Path; -use crate::tuliprox_error::{str_to_io_error, to_io_error}; +use shared::error::{str_to_io_error, to_io_error}; use log::error; use ruzstd::decoding::StreamingDecoder; use ruzstd::encoding::{compress_to_vec, CompressionLevel}; diff --git a/backend/src/repository/epg_repository.rs b/backend/src/repository/epg_repository.rs index 104543ef5..c3f86d561 100644 --- a/backend/src/repository/epg_repository.rs +++ b/backend/src/repository/epg_repository.rs @@ -1,4 +1,4 @@ -use crate::tuliprox_error::{notify_err, TuliproxError, TuliproxErrorKind}; +use shared::error::{notify_err, TuliproxError, TuliproxErrorKind}; use crate::model::{Config, ConfigTarget, TargetOutput}; use crate::model::Epg; use crate::repository::m3u_repository::m3u_get_epg_file_path; diff --git a/backend/src/repository/indexed_document.rs b/backend/src/repository/indexed_document.rs index 034f3059b..7d735345d 100644 --- a/backend/src/repository/indexed_document.rs +++ b/backend/src/repository/indexed_document.rs @@ -8,7 +8,7 @@ use crate::repository::bplustree::{BPlusTree, BPlusTreeQuery}; use log::error; use serde::{Deserialize, Serialize}; use tempfile::NamedTempFile; -use crate::tuliprox_error::{str_to_io_error, to_io_error}; +use shared::error::{str_to_io_error, to_io_error}; use crate::utils; use crate::utils::{bincode_deserialize, bincode_serialize}; diff --git a/backend/src/repository/m3u_playlist_iterator.rs b/backend/src/repository/m3u_playlist_iterator.rs index ff043bbca..aafff56ea 100644 --- a/backend/src/repository/m3u_playlist_iterator.rs +++ b/backend/src/repository/m3u_playlist_iterator.rs @@ -1,5 +1,5 @@ -use crate::tuliprox_error::info_err; -use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind}; +use shared::error::info_err; +use shared::error::{TuliproxError, TuliproxErrorKind}; use crate::model::{ProxyType, ProxyUserCredentials}; use crate::model::{Config, ConfigTarget, ConfigTargetOptions, TargetType}; use crate::model::{M3uPlaylistItem}; diff --git a/backend/src/repository/m3u_repository.rs b/backend/src/repository/m3u_repository.rs index 4fb1919ad..12dbf2d9a 100644 --- a/backend/src/repository/m3u_repository.rs +++ b/backend/src/repository/m3u_repository.rs @@ -1,5 +1,5 @@ -use crate::tuliprox_error::{create_tuliprox_error,info_err}; -use crate::tuliprox_error::{str_to_io_error, TuliproxError, TuliproxErrorKind}; +use shared::error::{create_tuliprox_error,info_err}; +use shared::error::{str_to_io_error, TuliproxError, TuliproxErrorKind}; use crate::model::ProxyUserCredentials; use crate::model::{Config, ConfigTarget, M3uTargetOutput}; use crate::model::{M3uPlaylistItem, PlaylistGroup, PlaylistItem}; diff --git a/backend/src/repository/playlist_repository.rs b/backend/src/repository/playlist_repository.rs index 76d854fd7..4fd46cb77 100644 --- a/backend/src/repository/playlist_repository.rs +++ b/backend/src/repository/playlist_repository.rs @@ -1,5 +1,5 @@ -use crate::tuliprox_error::info_err; -use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind}; +use shared::error::info_err; +use shared::error::{TuliproxError, TuliproxErrorKind}; use crate::model::{Config, ConfigTarget, TargetOutput}; use crate::model::{PlaylistGroup}; use shared::model::{PlaylistItemType}; diff --git a/backend/src/repository/storage.rs b/backend/src/repository/storage.rs index e0ba51733..797615f28 100644 --- a/backend/src/repository/storage.rs +++ b/backend/src/repository/storage.rs @@ -1,7 +1,7 @@ use std::path::{Path, PathBuf}; -use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind}; +use shared::error::{TuliproxError, TuliproxErrorKind}; use crate::model::{Config}; -use crate::tuliprox_error::{notify_err}; +use shared::error::{notify_err}; use crate::repository::storage_const; use crate::utils; diff --git a/backend/src/repository/strm_repository.rs b/backend/src/repository/strm_repository.rs index f40fcd394..fb0a31f74 100644 --- a/backend/src/repository/strm_repository.rs +++ b/backend/src/repository/strm_repository.rs @@ -1,9 +1,8 @@ -use crate::tuliprox_error::{create_tuliprox_error_result, info_err}; -use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind}; +use shared::error::{create_tuliprox_error_result, info_err}; +use shared::error::{TuliproxError, TuliproxErrorKind}; use crate::model::{ApiProxyServerInfo, ProxyUserCredentials}; use crate::model::{Config, ConfigTarget, StrmTargetOutput}; -use crate::model::{PlaylistGroup, PlaylistItem, ExportStyle, -}; +use crate::model::{PlaylistGroup, PlaylistItem}; use crate::model::XtreamSeriesEpisode; use crate::repository::bplustree::BPlusTree; use crate::repository::storage::{ensure_target_storage_path, get_input_storage_path}; @@ -23,7 +22,7 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use tokio::fs::{create_dir_all, remove_dir, remove_file, File}; use tokio::io::{AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader, BufWriter}; -use shared::model::{ClusterFlags, FieldGetAccessor, PlaylistItemType, UUIDType}; +use shared::model::{ClusterFlags, FieldGetAccessor, PlaylistItemType, StrmExportStyle, UUIDType}; use crate::utils; /// Sanitizes a string to be safe for use as a file or directory name by @@ -673,7 +672,7 @@ async fn style_based_rename( cfg: &Config, strm_item_info: &StrmItemInfo, input_tmdb_indexes: &mut InputTmdbIndexMap, - style: &ExportStyle, + style: &StrmExportStyle, underscore_whitespace: bool, flat: bool, ) -> (PathBuf, String) { @@ -694,10 +693,10 @@ async fn style_based_rename( // Dispatch the call to the responsible function based on the style. match style { - ExportStyle::Kodi => format_for_kodi(strm_item_info, tmdb_id, separator, flat), - ExportStyle::Plex => format_for_plex(strm_item_info, tmdb_id, separator, flat), - ExportStyle::Emby => format_for_emby(strm_item_info, tmdb_id, separator, flat), - ExportStyle::Jellyfin => format_for_jellyfin(strm_item_info, tmdb_id, separator, flat), + StrmExportStyle::Kodi => format_for_kodi(strm_item_info, tmdb_id, separator, flat), + StrmExportStyle::Plex => format_for_plex(strm_item_info, tmdb_id, separator, flat), + StrmExportStyle::Emby => format_for_emby(strm_item_info, tmdb_id, separator, flat), + StrmExportStyle::Jellyfin => format_for_jellyfin(strm_item_info, tmdb_id, separator, flat), } } @@ -706,7 +705,7 @@ async fn prepare_strm_files( new_playlist: &mut [PlaylistGroup], _root_path: &Path, underscore_whitespace: bool, - style: &ExportStyle, + style: &StrmExportStyle, flat: bool, ) -> Vec { let channel_count = new_playlist @@ -769,13 +768,13 @@ async fn prepare_strm_files( // A style-specific match is not strictly necessary here but is good practice for future flexibility. let new_filename = match style { // Plex, Emby, and Kodi all follow the `Filename - Suffix` pattern. - ExportStyle::Plex | ExportStyle::Emby | ExportStyle::Kodi => { + StrmExportStyle::Plex | StrmExportStyle::Emby | StrmExportStyle::Kodi => { format!("{base_filename}{version_separator}{version_label}") } // Jellyfin also follows this pattern, but explicitly shows an option for " - [Label]". // Using brackets makes the version distinct and is a clean implementation. - ExportStyle::Jellyfin => { + StrmExportStyle::Jellyfin => { format!("{base_filename}{version_separator}[{version_label}]") } }; diff --git a/backend/src/repository/xtream_playlist_iterator.rs b/backend/src/repository/xtream_playlist_iterator.rs index 1be633ec8..d42a71428 100644 --- a/backend/src/repository/xtream_playlist_iterator.rs +++ b/backend/src/repository/xtream_playlist_iterator.rs @@ -1,8 +1,8 @@ use std::collections::HashSet; use log::error; use shared::model::XtreamCluster; -use crate::tuliprox_error::info_err; -use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind}; +use shared::error::info_err; +use shared::error::{TuliproxError, TuliproxErrorKind}; use crate::model::{ProxyUserCredentials}; use crate::model::{Config, ConfigTarget, TargetType}; use crate::model::{XtreamPlaylistItem}; diff --git a/backend/src/repository/xtream_repository.rs b/backend/src/repository/xtream_repository.rs index 0d73169f9..4cb992da7 100644 --- a/backend/src/repository/xtream_repository.rs +++ b/backend/src/repository/xtream_repository.rs @@ -1,4 +1,4 @@ -use crate::tuliprox_error::{create_tuliprox_error, create_tuliprox_error_result, info_err, notify_err, str_to_io_error, to_io_error, TuliproxError, TuliproxErrorKind}; +use shared::error::{create_tuliprox_error, create_tuliprox_error_result, info_err, notify_err, str_to_io_error, to_io_error, TuliproxError, TuliproxErrorKind}; use crate::model::{ProxyUserCredentials}; use crate::model::{Config, ConfigInput, ConfigTarget, XtreamTargetOutput}; use crate::model::{PlaylistGroup, PlaylistItem, XtreamPlaylistItem}; diff --git a/backend/src/utils/bincode_utils.rs b/backend/src/utils/bincode_utils.rs index f55d680f1..cb80df784 100644 --- a/backend/src/utils/bincode_utils.rs +++ b/backend/src/utils/bincode_utils.rs @@ -1,5 +1,5 @@ use std::io; -use crate::tuliprox_error::to_io_error; +use shared::error::to_io_error; #[inline] pub fn bincode_serialize(value: &T) -> io::Result> diff --git a/backend/src/utils/crypto_utils.rs b/backend/src/utils/crypto_utils.rs index 44f3c8807..8e3716aab 100644 --- a/backend/src/utils/crypto_utils.rs +++ b/backend/src/utils/crypto_utils.rs @@ -1,4 +1,4 @@ -use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind}; +use shared::error::{TuliproxError, TuliproxErrorKind}; use base64::{engine::general_purpose, Engine as _}; use openssl::symm::{Cipher, Crypter, Mode}; use rand::Rng; diff --git a/backend/src/utils/file/config_reader.rs b/backend/src/utils/file/config_reader.rs index 8e1cee9f8..d0091a96a 100644 --- a/backend/src/utils/file/config_reader.rs +++ b/backend/src/utils/file/config_reader.rs @@ -1,6 +1,6 @@ use crate::model::{ApiProxyConfig, SourcesConfig}; use crate::model::{Config, ConfigDto}; -use crate::tuliprox_error::{create_tuliprox_error, info_err, to_io_error, TuliproxError, TuliproxErrorKind}; +use shared::error::{create_tuliprox_error, info_err, to_io_error, TuliproxError, TuliproxErrorKind}; use crate::utils::{open_file, EnvResolvingReader}; use crate::utils::{file_reader}; use crate::utils::sys_utils::exit; @@ -73,8 +73,6 @@ pub fn read_sources(sources_file: &str, resolve_env: bool, include_computed: boo } } - - pub fn read_config(config_path: &str, config_file: &str, sources_file: &str, api_proxy_file: &str, mappings_file: Option, include_computed: bool) -> Result { let resolve_env = true; diff --git a/backend/src/utils/file/csv_input_reader.rs b/backend/src/utils/file/csv_input_reader.rs index a4ec54dbc..b93f6f1e6 100644 --- a/backend/src/utils/file/csv_input_reader.rs +++ b/backend/src/utils/file/csv_input_reader.rs @@ -1,5 +1,5 @@ use crate::model::{ConfigInput, ConfigInputAlias, InputType}; -use crate::tuliprox_error::{str_to_io_error, to_io_error}; +use shared::error::{str_to_io_error, to_io_error}; use crate::utils::request::{get_credentials_from_url, get_local_file_content}; use crate::utils::EnvResolvingReader; use crate::utils::{file_reader, resolve_relative_path}; diff --git a/backend/src/utils/file/file_lock_manager.rs b/backend/src/utils/file/file_lock_manager.rs index c460dc015..a692488fa 100644 --- a/backend/src/utils/file/file_lock_manager.rs +++ b/backend/src/utils/file/file_lock_manager.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use std::{fmt, io}; use std::path::{Path, PathBuf}; use tokio::sync::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard}; -use crate::tuliprox_error::str_to_io_error; +use shared::error::str_to_io_error; #[derive(Clone)] pub struct FileLockManager { diff --git a/backend/src/utils/file/file_utils.rs b/backend/src/utils/file/file_utils.rs index 0e9ac14fc..e32878831 100644 --- a/backend/src/utils/file/file_utils.rs +++ b/backend/src/utils/file/file_utils.rs @@ -5,7 +5,7 @@ use std::io::{BufReader, BufWriter, Read, Write}; use std::path::{Path, PathBuf}; use std::{env, fs}; -use crate::tuliprox_error::str_to_io_error; +use shared::error::str_to_io_error; use crate::utils::debug_if_enabled; use shared::utils::{API_PROXY_FILE, CONFIG_FILE, CONFIG_PATH, MAPPING_FILE, SOURCE_FILE, USER_FILE}; use log::{debug, error}; diff --git a/backend/src/utils/file/mapping_reader.rs b/backend/src/utils/file/mapping_reader.rs index 188140939..52d2feac2 100644 --- a/backend/src/utils/file/mapping_reader.rs +++ b/backend/src/utils/file/mapping_reader.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use crate::foundation::filter::PatternTemplate; use crate::model::{Mapping, MappingDefinition, Mappings}; -use crate::tuliprox_error::{create_tuliprox_error_result, info_err, TuliproxError, TuliproxErrorKind}; +use shared::error::{create_tuliprox_error_result, info_err, TuliproxError, TuliproxErrorKind}; use crate::utils::traverse_dir; use crate::utils::{config_file_reader, open_file}; use log::{warn}; diff --git a/backend/src/utils/network/epg.rs b/backend/src/utils/network/epg.rs index 8f7bc85a4..80f2705de 100644 --- a/backend/src/utils/network/epg.rs +++ b/backend/src/utils/network/epg.rs @@ -1,4 +1,4 @@ -use crate::tuliprox_error::TuliproxError; +use shared::error::TuliproxError; use crate::model::{Config, ConfigInput, PersistedEpgSource}; use crate::model::TVGuide; use crate::utils::{add_prefix_to_filename, cleanup_unlisted_files_with_suffix, prepare_file_path, short_hash}; diff --git a/backend/src/utils/network/ip_checker.rs b/backend/src/utils/network/ip_checker.rs index e688075c6..f0300afef 100644 --- a/backend/src/utils/network/ip_checker.rs +++ b/backend/src/utils/network/ip_checker.rs @@ -1,4 +1,4 @@ -use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind}; +use shared::error::{TuliproxError, TuliproxErrorKind}; use crate::model::IpCheckConfig; use regex::Regex; use reqwest::Client; diff --git a/backend/src/utils/network/m3u.rs b/backend/src/utils/network/m3u.rs index 0bd447c6f..3778226ad 100644 --- a/backend/src/utils/network/m3u.rs +++ b/backend/src/utils/network/m3u.rs @@ -1,5 +1,5 @@ use std::sync::Arc; -use crate::tuliprox_error::TuliproxError; +use shared::error::TuliproxError; use crate::model::{Config, ConfigInput}; use crate::model::PlaylistGroup; use crate::processing::parser::m3u; diff --git a/backend/src/utils/network/request.rs b/backend/src/utils/network/request.rs index 73bab66ed..4317d8786 100644 --- a/backend/src/utils/network/request.rs +++ b/backend/src/utils/network/request.rs @@ -15,8 +15,8 @@ use reqwest::header::CONTENT_ENCODING; use reqwest::header::{HeaderMap, HeaderName, HeaderValue}; use url::Url; -use crate::tuliprox_error::create_tuliprox_error_result; -use crate::tuliprox_error::{str_to_io_error, TuliproxError, TuliproxErrorKind}; +use shared::error::create_tuliprox_error_result; +use shared::error::{str_to_io_error, TuliproxError, TuliproxErrorKind}; use crate::model::{format_elapsed_time, Config}; use crate::model::{ConfigInput, InputFetchMethod}; use crate::repository::storage::{get_input_storage_path}; diff --git a/backend/src/utils/network/xtream.rs b/backend/src/utils/network/xtream.rs index 4c7cacd59..63231b965 100644 --- a/backend/src/utils/network/xtream.rs +++ b/backend/src/utils/network/xtream.rs @@ -4,7 +4,7 @@ use crate::model::{PlaylistGroup, XtreamPlaylistItem}; use crate::processing::parser::xtream; use crate::repository::xtream_repository; use crate::repository::xtream_repository::{rewrite_xtream_series_info_content, rewrite_xtream_vod_info_content, xtream_get_input_info}; -use crate::tuliprox_error::{str_to_io_error, TuliproxError}; +use shared::error::{str_to_io_error, TuliproxError}; use crate::utils; use crate::utils::{get_string_from_serde_value, request}; use crate::utils::request::extract_extension_from_url; @@ -15,8 +15,8 @@ use std::io::Error; use std::str::FromStr; use std::sync::Arc; use std::time::{SystemTime, UNIX_EPOCH}; -use shared::model::{PlaylistEntry, XtreamCluster}; -use crate::messaging::{send_message, MsgKind}; +use shared::model::{MsgKind, PlaylistEntry, XtreamCluster}; +use crate::messaging::{send_message}; #[inline] pub fn get_xtream_stream_url_base(url: &str, username: &str, password: &str) -> String { diff --git a/backend/src/utils/trakt/client.rs b/backend/src/utils/trakt/client.rs index a82eeddc2..234cb6df0 100644 --- a/backend/src/utils/trakt/client.rs +++ b/backend/src/utils/trakt/client.rs @@ -1,9 +1,9 @@ use crate::model::{TraktApiConfig, TraktListConfig, TraktListItem}; -use crate::tuliprox_error::TuliproxError; +use shared::error::TuliproxError; use reqwest::header::{HeaderMap, HeaderValue}; use std::sync::Arc; use log::{debug, info}; -use crate::tuliprox_error::{info_err, TuliproxErrorKind}; +use shared::error::{info_err, TuliproxErrorKind}; use super::errors::{handle_trakt_api_error}; pub struct TraktClient { diff --git a/backend/src/utils/trakt/errors.rs b/backend/src/utils/trakt/errors.rs index d4d320bb5..872e83759 100644 --- a/backend/src/utils/trakt/errors.rs +++ b/backend/src/utils/trakt/errors.rs @@ -1,4 +1,4 @@ -use crate::tuliprox_error::{create_tuliprox_error_result, TuliproxError, TuliproxErrorKind}; +use shared::error::{create_tuliprox_error_result, TuliproxError, TuliproxErrorKind}; use reqwest::StatusCode; /// Handle Trakt API response status and convert to appropriate error diff --git a/shared/Cargo.toml b/shared/Cargo.toml index 2433de59e..82a0d2b0c 100644 --- a/shared/Cargo.toml +++ b/shared/Cargo.toml @@ -8,3 +8,4 @@ bitflags = "2.9.1" serde = { version = "1.0.219", features = ["derive"] } rand = "0.9.1" regex = "1.11.1" +enum-iterator = "2" diff --git a/shared/src/error/mod.rs b/shared/src/error/mod.rs new file mode 100644 index 000000000..5f7963a06 --- /dev/null +++ b/shared/src/error/mod.rs @@ -0,0 +1,3 @@ +mod tuliprox_error; + +pub use tuliprox_error::*; \ No newline at end of file diff --git a/backend/src/tuliprox_error.rs b/shared/src/error/tuliprox_error.rs similarity index 100% rename from backend/src/tuliprox_error.rs rename to shared/src/error/tuliprox_error.rs diff --git a/shared/src/lib.rs b/shared/src/lib.rs index 32c2eb054..71087e205 100644 --- a/shared/src/lib.rs +++ b/shared/src/lib.rs @@ -1,2 +1,3 @@ +pub mod error; pub mod model; pub mod utils; \ No newline at end of file diff --git a/shared/src/model/config/base.rs b/shared/src/model/config/base.rs new file mode 100644 index 000000000..390b1de9c --- /dev/null +++ b/shared/src/model/config/base.rs @@ -0,0 +1,56 @@ +use crate::model::{WebUiConfigDto, MessagingConfigDto, IpCheckConfigDto, HdHomeRunConfigDto, VideoConfigDto, ScheduleConfigDto, LogConfigDto, ReverseProxyConfigDto, ProxyConfigDto}; +use crate::utils::{default_connect_timeout_secs}; + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct ConfigApiDto { + pub host: String, + pub port: u16, + #[serde(default)] + pub web_root: String, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct ConfigDto { + #[serde(default)] + pub threads: u8, + pub api: ConfigApiDto, + pub working_dir: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub backup_dir: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub user_config_dir: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub mapping_path: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub custom_stream_response_path: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub video: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub schedules: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub log: Option, + #[serde(default)] + pub user_access_control: bool, + #[serde(default = "default_connect_timeout_secs")] + pub connect_timeout_secs: u32, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub sleep_timer_mins: Option, + #[serde(default)] + pub update_on_boot: bool, + #[serde(default)] + pub config_hot_reload: bool, + #[serde(default)] + pub web_ui: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub messaging: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub reverse_proxy: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub hdhomerun: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub proxy: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub ipcheck: Option, +} diff --git a/shared/src/model/config/cache.rs b/shared/src/model/config/cache.rs new file mode 100644 index 000000000..29edb8aa5 --- /dev/null +++ b/shared/src/model/config/cache.rs @@ -0,0 +1,10 @@ +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct CacheConfigDto { + #[serde(default)] + pub enabled: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub dir: Option, +} \ No newline at end of file diff --git a/shared/src/model/config/epg.rs b/shared/src/model/config/epg.rs new file mode 100644 index 000000000..00d1a71d6 --- /dev/null +++ b/shared/src/model/config/epg.rs @@ -0,0 +1,49 @@ + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub struct EpgSourceDto { + pub url: String, + #[serde(default)] + pub priority: i16, + #[serde(default)] + pub logo_override: bool, +} + + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, Default)] +#[serde(rename_all = "lowercase")] +pub enum EpgNamePrefix { + #[default] + Ignore, + Suffix(String), + Prefix(String), +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub struct EpgSmartMatchConfigDto { + #[serde(default)] + pub enabled: bool, + pub normalize_regex: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub strip: Option>, + #[serde(default)] + pub name_prefix: EpgNamePrefix, + #[serde(default)] + pub name_prefix_separator: Option>, + #[serde(default)] + pub fuzzy_matching: bool, + #[serde(default)] + pub match_threshold: u16, + #[serde(default)] + pub best_match_threshold: u16, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub struct EpgConfigDto { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub sources: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub smart_match: Option, +} diff --git a/shared/src/model/config/hdhomerun.rs b/shared/src/model/config/hdhomerun.rs new file mode 100644 index 000000000..c60ea5c41 --- /dev/null +++ b/shared/src/model/config/hdhomerun.rs @@ -0,0 +1,45 @@ + +fn default_friendly_name() -> String { String::from("TuliproxTV") } +fn default_manufacturer() -> String { String::from("Silicondust") } +fn default_model_name() -> String { String::from("HDTC-2US") } +fn default_firmware_name() -> String { String::from("hdhomeruntc_atsc") } +fn default_firmware_version() -> String { String::from("20170930") } +fn default_device_type() -> String { String::from("urn:schemas-upnp-org:device:MediaServer:1") } +fn default_device_udn() -> String { String::from("uuid:12345678-90ab-cdef-1234-567890abcdef::urn:dial-multicast:com.silicondust.hdhomerun") } + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct HdHomeRunDeviceConfigDto { + #[serde(default = "default_friendly_name")] + pub friendly_name: String, + #[serde(default = "default_manufacturer")] + pub manufacturer: String, + #[serde(default = "default_model_name")] + pub model_name: String, + #[serde(default = "default_model_name")] + pub model_number: String, + #[serde(default = "default_firmware_name")] + pub firmware_name: String, + #[serde(default = "default_firmware_version")] + pub firmware_version: String, + // pub device_auth: String, + #[serde(default = "default_device_type")] + pub device_type: String, + #[serde(default = "default_device_udn")] + pub device_udn: String, + pub name: String, + #[serde(default)] + pub port: u16, + #[serde(default)] + pub tuner_count: u8, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct HdHomeRunConfigDto { + #[serde(default)] + pub enabled: bool, + #[serde(default)] + pub auth: bool, + pub devices: Vec, +} diff --git a/shared/src/model/config/input.rs b/shared/src/model/config/input.rs new file mode 100644 index 000000000..839544f19 --- /dev/null +++ b/shared/src/model/config/input.rs @@ -0,0 +1,91 @@ +use std::collections::HashMap; +use enum_iterator::Sequence; +use crate::model::{EpgConfigDto}; +use crate::utils::{default_as_true}; + +#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, Sequence, + PartialEq, Eq, Default)] +pub enum InputType { + #[serde(rename = "m3u")] + #[default] + M3u, + #[serde(rename = "xtream")] + Xtream, + #[serde(rename = "m3u_batch")] + M3uBatch, + #[serde(rename = "xtream_batch")] + XtreamBatch, +} + +#[allow(clippy::struct_excessive_bools)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct ConfigInputOptionsDto { + #[serde(default)] + pub xtream_skip_live: bool, + #[serde(default)] + pub xtream_skip_vod: bool, + #[serde(default)] + pub xtream_skip_series: bool, + #[serde(default = "default_as_true")] + pub xtream_live_stream_use_prefix: bool, + #[serde(default)] + pub xtream_live_stream_without_extension: bool, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct ConfigInputAliasDto { + #[serde(skip)] + pub id: u16, + pub name: String, + pub url: String, + pub username: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub password: Option, + #[serde(default)] + pub priority: i16, + #[serde(default)] + pub max_connections: u16, +} + +#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, Sequence, + PartialEq, Eq, Default)] +pub enum InputFetchMethod { + #[default] + GET, + POST, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct ConfigInputDto { + #[serde(skip)] + pub id: u16, + pub name: String, + #[serde(default, rename = "type")] + pub input_type: InputType, + #[serde(default)] + pub headers: HashMap, + pub url: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub epg: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub username: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub password: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub persist: Option, + #[serde(default = "default_as_true")] + pub enabled: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub options: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub aliases: Option>, + #[serde(default)] + pub priority: i16, + #[serde(default)] + pub max_connections: u16, + #[serde(default)] + pub method: InputFetchMethod, +} diff --git a/shared/src/model/config/ipcheck.rs b/shared/src/model/config/ipcheck.rs new file mode 100644 index 000000000..61456191c --- /dev/null +++ b/shared/src/model/config/ipcheck.rs @@ -0,0 +1,24 @@ +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct IpCheckConfigDto { + /// URL that may return both IPv4 and IPv6 in one response + #[serde(default, skip_serializing_if = "Option::is_none")] + pub url: Option, + + /// Dedicated URL to fetch only IPv4 + #[serde(default, skip_serializing_if = "Option::is_none")] + pub url_ipv4: Option, + + /// Dedicated URL to fetch only IPv6 + #[serde(default, skip_serializing_if = "Option::is_none")] + pub url_ipv6: Option, + + /// Optional regex pattern to extract IPv4 + #[serde(default, skip_serializing_if = "Option::is_none")] + pub pattern_ipv4: Option, + + /// Optional regex pattern to extract IPv6 + #[serde(default, skip_serializing_if = "Option::is_none")] + pub pattern_ipv6: Option, + +} \ No newline at end of file diff --git a/shared/src/model/config/log.rs b/shared/src/model/config/log.rs new file mode 100644 index 000000000..3a21d0777 --- /dev/null +++ b/shared/src/model/config/log.rs @@ -0,0 +1,12 @@ +use crate::utils::{default_as_true}; + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct LogConfigDto { + #[serde(default = "default_as_true")] + pub sanitize_sensitive_info: bool, + #[serde(default)] + pub log_active_user: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub log_level: Option, +} diff --git a/shared/src/model/config/messaging.rs b/shared/src/model/config/messaging.rs new file mode 100644 index 000000000..92e649614 --- /dev/null +++ b/shared/src/model/config/messaging.rs @@ -0,0 +1,36 @@ +use crate::model::MsgKind; + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub struct TelegramMessagingConfigDto { + pub bot_token: String, + pub chat_ids: Vec, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub struct RestMessagingConfigDto { + pub url: String, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub struct PushoverMessagingConfigDto { + pub url: Option, + pub token: String, + pub user: String, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct MessagingConfigDto { + #[serde(default)] + pub notify_on: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub telegram: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub rest: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub pushover: Option, + +} \ No newline at end of file diff --git a/shared/src/model/config/mod.rs b/shared/src/model/config/mod.rs new file mode 100644 index 000000000..c06f0ab70 --- /dev/null +++ b/shared/src/model/config/mod.rs @@ -0,0 +1,38 @@ +mod trakt; +mod base; +mod web; +mod messaging; +mod hdhomerun; +mod ipcheck; +mod source; +mod target; +mod sort; +mod video; +mod schedule; +mod log; +mod input; +mod stream; +mod epg; +mod reverse_proxy; +mod cache; +mod rate_limit; +mod proxy; + +pub use base::*; +pub use web::*; +pub use messaging::*; +pub use hdhomerun::*; +pub use ipcheck::*; +pub use source::*; +pub use sort::*; +pub use video::*; +pub use schedule::*; +pub use log::*; +pub use input::*; +pub use stream::*; +pub use epg::*; +pub use cache::*; +pub use rate_limit::*; +pub use reverse_proxy::*; +pub use proxy::*; +pub use trakt::*; diff --git a/shared/src/model/config/proxy.rs b/shared/src/model/config/proxy.rs new file mode 100644 index 000000000..8832eb777 --- /dev/null +++ b/shared/src/model/config/proxy.rs @@ -0,0 +1,8 @@ + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct ProxyConfigDto { + pub url: String, + pub username: Option, + pub password: Option, +} diff --git a/shared/src/model/config/rate_limit.rs b/shared/src/model/config/rate_limit.rs new file mode 100644 index 000000000..4df7ae8f5 --- /dev/null +++ b/shared/src/model/config/rate_limit.rs @@ -0,0 +1,7 @@ +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct RateLimitConfigDto { + pub enabled: bool, + pub period_millis: u64, + pub burst_size: u32, +} \ No newline at end of file diff --git a/shared/src/model/config/reverse_proxy.rs b/shared/src/model/config/reverse_proxy.rs new file mode 100644 index 000000000..03fe2a150 --- /dev/null +++ b/shared/src/model/config/reverse_proxy.rs @@ -0,0 +1,16 @@ +use crate::model::{CacheConfigDto, RateLimitConfigDto, StreamConfigDto}; + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct ReverseProxyConfigDto { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub stream: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub cache: Option, + #[serde(default)] + pub resource_rewrite_disabled: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub rate_limit: Option, + #[serde(default)] + pub disable_referer_header: bool, +} diff --git a/shared/src/model/config/schedule.rs b/shared/src/model/config/schedule.rs new file mode 100644 index 000000000..3c592586a --- /dev/null +++ b/shared/src/model/config/schedule.rs @@ -0,0 +1,9 @@ + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct ScheduleConfigDto { + #[serde(default)] + pub schedule: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub targets: Option>, +} \ No newline at end of file diff --git a/shared/src/model/config/sort.rs b/shared/src/model/config/sort.rs new file mode 100644 index 000000000..d34291185 --- /dev/null +++ b/shared/src/model/config/sort.rs @@ -0,0 +1,40 @@ +use crate::model::ItemField; + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub struct ConfigSortGroupDto { + pub order: SortOrder, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub sequence: Option>, +} + +#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize)] +pub enum SortOrder { + #[serde(rename = "asc")] + Asc, + #[serde(rename = "desc")] + Desc, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub struct ConfigSortChannelDto { + // channel field + pub field: ItemField, + // match against group title + pub group_pattern: String, + pub order: SortOrder, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub sequence: Option>, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct ConfigSortDto { + #[serde(default)] + pub match_as_ascii: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub groups: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub channels: Option>, +} diff --git a/shared/src/model/config/source.rs b/shared/src/model/config/source.rs new file mode 100644 index 000000000..2945ef1b4 --- /dev/null +++ b/shared/src/model/config/source.rs @@ -0,0 +1,41 @@ +use crate::model::{ConfigInputDto, ItemField}; +use crate::model::config::target::ConfigTargetDto; + + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +pub enum TemplateValue { + Single(String), + Multi(Vec), +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct PatternTemplateDto { + pub name: String, + pub value: TemplateValue, + #[serde(skip)] + pub placeholder: String, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub struct ConfigRenameDto { + pub field: ItemField, + pub pattern: String, + pub new_name: String, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub struct ConfigSourceDto { + pub inputs: Vec, + pub targets: Vec, +} + +#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub struct SourcesConfigDto { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub templates: Option>, + pub sources: Vec, +} \ No newline at end of file diff --git a/shared/src/model/config/stream.rs b/shared/src/model/config/stream.rs new file mode 100644 index 000000000..41fce620a --- /dev/null +++ b/shared/src/model/config/stream.rs @@ -0,0 +1,29 @@ +use crate::utils::{default_grace_period_millis, default_grace_period_timeout_secs}; + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct StreamBufferConfigDto { + #[serde(default)] + pub enabled: bool, + #[serde(default)] + pub size: usize, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct StreamConfigDto { + #[serde(default)] + pub retry: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub buffer: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub throttle: Option, + #[serde(default = "default_grace_period_millis")] + pub grace_period_millis: u64, + #[serde(default = "default_grace_period_timeout_secs")] + pub grace_period_timeout_secs: u64, + #[serde(default)] + pub forced_retry_interval_secs: u32, + #[serde(default, skip)] + pub throttle_kbps: u64, +} diff --git a/shared/src/model/config/target.rs b/shared/src/model/config/target.rs new file mode 100644 index 000000000..ae79cc9cb --- /dev/null +++ b/shared/src/model/config/target.rs @@ -0,0 +1,112 @@ +use crate::model::{ClusterFlags, ConfigSortDto, ProcessingOrder, StrmExportStyle, TargetType, TraktConfigDto}; +use crate::model::config::source::ConfigRenameDto; +use crate::utils::{default_as_true, default_resolve_delay_secs, default_as_default}; +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct ConfigTargetOptionsDto { + #[serde(default)] + pub ignore_logo: bool, + #[serde(default)] + pub share_live_streams: bool, + #[serde(default)] + pub remove_duplicates: bool, + #[serde(skip_serializing_if = "Option::is_none")] + pub force_redirect: Option, +} + +#[allow(clippy::struct_excessive_bools)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub struct XtreamTargetOutputDto { + #[serde(default = "default_as_true")] + pub skip_live_direct_source: bool, + #[serde(default = "default_as_true")] + pub skip_video_direct_source: bool, + #[serde(default = "default_as_true")] + pub skip_series_direct_source: bool, + #[serde(default)] + pub resolve_series: bool, + #[serde(default = "default_resolve_delay_secs")] + pub resolve_series_delay: u16, + #[serde(default)] + pub resolve_vod: bool, + #[serde(default = "default_resolve_delay_secs")] + pub resolve_vod_delay: u16, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub trakt: Option, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub struct M3uTargetOutputDto { + #[serde(skip_serializing_if = "Option::is_none")] + pub filename: Option, + #[serde(default)] + pub include_type_in_url: bool, + #[serde(default)] + pub mask_redirect_url: bool, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub struct StrmTargetOutputDto { + pub directory: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub username: Option, + #[serde(default)] + pub style: StrmExportStyle, + #[serde(default)] + pub flat: bool, + #[serde(default)] + pub underscore_whitespace: bool, + #[serde(default)] + pub cleanup: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub strm_props: Option>, +} +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub struct HdHomeRunTargetOutputDto { + pub device: String, + pub username: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub use_output: Option, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(deny_unknown_fields, tag = "type", rename_all = "lowercase")] +pub enum TargetOutput { + Xtream(XtreamTargetOutputDto), + M3u(M3uTargetOutputDto), + Strm(StrmTargetOutputDto), + HdHomeRun(HdHomeRunTargetOutputDto), +} + + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct ConfigTargetDto { + #[serde(skip)] + pub id: u16, + #[serde(default = "default_as_true")] + pub enabled: bool, + #[serde(default = "default_as_default")] + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub options: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub sort: Option, + pub filter: String, + #[serde(default)] + pub output: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub rename: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub mapping: Option>, + #[serde(default)] + pub processing_order: ProcessingOrder, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub watch: Option>, +} + + diff --git a/shared/src/model/config/trakt.rs b/shared/src/model/config/trakt.rs new file mode 100644 index 000000000..92ec4d161 --- /dev/null +++ b/shared/src/model/config/trakt.rs @@ -0,0 +1,49 @@ +use serde::{Deserialize, Serialize}; + +fn default_fuzzy_threshold() -> u8 { + 80 +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "lowercase")] +pub enum TraktContentType { + Vod, + Series, + Both, +} + +impl Default for TraktContentType { + fn default() -> Self { + Self::Both + } +} + +#[derive(Default, Debug, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct TraktApiConfigDto { + #[serde(default)] + pub(crate) key: String, + #[serde(default)] + pub(crate) version: String, + #[serde(default)] + pub(crate) url: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct TraktListConfigDto { + pub user: String, + pub list_slug: String, + pub category_name: String, + pub content_type: TraktContentType, + #[serde(default = "default_fuzzy_threshold")] + pub fuzzy_match_threshold: u8, // Percentage (0-100) +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct TraktConfigDto { + #[serde(default)] + pub api: TraktApiConfigDto, + pub lists: Vec, +} diff --git a/shared/src/model/config/video.rs b/shared/src/model/config/video.rs new file mode 100644 index 000000000..d40afc9d1 --- /dev/null +++ b/shared/src/model/config/video.rs @@ -0,0 +1,25 @@ +use std::collections::HashMap; + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct VideoDownloadConfigDto { + #[serde(default)] + pub headers: HashMap, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub directory: Option, + #[serde(default)] + pub organize_into_directories: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub episode_pattern: Option, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct VideoConfigDto { + #[serde(default)] + pub extensions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub download: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub web_search: Option, +} diff --git a/shared/src/model/config/web.rs b/shared/src/model/config/web.rs new file mode 100644 index 000000000..20f40fc15 --- /dev/null +++ b/shared/src/model/config/web.rs @@ -0,0 +1,27 @@ +use crate::utils::{default_as_true}; + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub struct WebAuthConfigDto { + #[serde(default = "default_as_true")] + pub enabled: bool, + pub issuer: String, + pub secret: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub userfile: Option, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct WebUiConfigDto { + #[serde(default = "default_as_true")] + pub enabled: bool, + #[serde(default = "default_as_true")] + pub user_ui_enabled: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub path: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub auth: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub player_server: Option, +} diff --git a/shared/src/model/item_field.rs b/shared/src/model/item_field.rs new file mode 100644 index 000000000..b03a44b0a --- /dev/null +++ b/shared/src/model/item_field.rs @@ -0,0 +1,83 @@ +use std::fmt::Display; +use std::str::FromStr; +use enum_iterator::Sequence; +use crate::create_tuliprox_error_result; +use crate::error::{TuliproxError, TuliproxErrorKind}; + +#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, Sequence, Eq, PartialEq)] +pub enum ItemField { + #[serde(rename = "group")] + Group, + #[serde(rename = "name")] + Name, + #[serde(rename = "title")] + Title, + #[serde(rename = "url")] + Url, + #[serde(rename = "input")] + Input, + #[serde(rename = "type")] + Type, + #[serde(rename = "caption")] + Caption, +} + +impl ItemField { + const GROUP: &'static str = "Group"; + const NAME: &'static str = "Name"; + const TITLE: &'static str = "Title"; + const URL: &'static str = "Url"; + const INPUT: &'static str = "Input"; + const TYPE: &'static str = "Type"; + const CAPTION: &'static str = "Caption"; + + pub fn as_str(&self) -> &'static str { + match *self { + Self::Group => Self::GROUP, + Self::Name => Self::NAME, + Self::Title => Self::TITLE, + Self::Url => Self::URL, + Self::Input => Self::INPUT, + Self::Type => Self::TYPE, + Self::Caption => Self::CAPTION, + } + } +} + +impl Display for ItemField { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", match *self { + Self::Group => Self::GROUP, + Self::Name => Self::NAME, + Self::Title => Self::TITLE, + Self::Url => Self::URL, + Self::Input => Self::INPUT, + Self::Type => Self::TYPE, + Self::Caption => Self::CAPTION, + }) + } +} + +impl FromStr for ItemField { + type Err = TuliproxError; + + fn from_str(s: &str) -> Result { + if s.eq_ignore_ascii_case(Self::GROUP) { + Ok(Self::Group) + } else if s.eq_ignore_ascii_case(Self::NAME) { + Ok(Self::Name) + } else if s.eq_ignore_ascii_case(Self::TITLE) { + Ok(Self::Title) + } else if s.eq_ignore_ascii_case(Self::CAPTION) { + Ok(Self::Caption) + } else if s.eq_ignore_ascii_case(Self::URL) { + Ok(Self::Url) + } else if s.eq_ignore_ascii_case(Self::INPUT) { + Ok(Self::Input) + } else if s.eq_ignore_ascii_case(Self::TYPE) { + Ok(Self::Type) + } else { + create_tuliprox_error_result!(TuliproxErrorKind::Info, "Unknown InputType: {}", s) + } + } +} diff --git a/shared/src/model/messaging.rs b/shared/src/model/messaging.rs new file mode 100644 index 000000000..d6affab47 --- /dev/null +++ b/shared/src/model/messaging.rs @@ -0,0 +1,12 @@ + +#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)] +pub enum MsgKind { + #[serde(rename = "info")] + Info, + #[serde(rename = "stats")] + Stats, + #[serde(rename = "error")] + Error, + #[serde(rename = "watch")] + Watch, +} \ No newline at end of file diff --git a/shared/src/model/mod.rs b/shared/src/model/mod.rs index b5b0b3e69..e1fba712c 100644 --- a/shared/src/model/mod.rs +++ b/shared/src/model/mod.rs @@ -1,5 +1,17 @@ mod cluster_flags; mod playlist; +mod messaging; +mod item_field; +mod target_type; +mod processing_order; +mod config; +mod strm_export_style; pub use self::cluster_flags::*; -pub use self::playlist::*; \ No newline at end of file +pub use self::playlist::*; +pub use self::messaging::*; +pub use self::item_field::*; +pub use self::target_type::*; +pub use self::processing_order::*; +pub use self::config::*; +pub use self::strm_export_style::*; \ No newline at end of file diff --git a/backend/src/model/processing_order.rs b/shared/src/model/processing_order.rs similarity index 100% rename from backend/src/model/processing_order.rs rename to shared/src/model/processing_order.rs diff --git a/shared/src/model/strm_export_style.rs b/shared/src/model/strm_export_style.rs new file mode 100644 index 000000000..30bcc530b --- /dev/null +++ b/shared/src/model/strm_export_style.rs @@ -0,0 +1,15 @@ +use enum_iterator::Sequence; + +#[derive( Debug, Copy, Clone, serde::Serialize, serde::Deserialize, Sequence, + PartialEq, Eq, Hash, Default)] +pub enum StrmExportStyle { + #[serde(rename = "kodi")] + #[default] + Kodi, + #[serde(rename = "plex")] + Plex, + #[serde(rename = "emby")] + Emby, + #[serde(rename = "jellyfin")] + Jellyfin, +} \ No newline at end of file diff --git a/shared/src/model/target_type.rs b/shared/src/model/target_type.rs new file mode 100644 index 000000000..405d47ba2 --- /dev/null +++ b/shared/src/model/target_type.rs @@ -0,0 +1,32 @@ +use std::fmt::Display; +use enum_iterator::Sequence; + +#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, Sequence, PartialEq, Eq, Hash)] +pub enum TargetType { + #[serde(rename = "m3u")] + M3u, + #[serde(rename = "xtream")] + Xtream, + #[serde(rename = "strm")] + Strm, + #[serde(rename = "hdhomerun")] + HdHomeRun, +} + +impl TargetType { + const M3U: &'static str = "M3u"; + const XTREAM: &'static str = "Xtream"; + const STRM: &'static str = "Strm"; + const HDHOMERUN: &'static str = "HdHomeRun"; +} + +impl Display for TargetType { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", match *self { + Self::M3u => Self::M3U, + Self::Xtream => Self::XTREAM, + Self::Strm => Self::STRM, + Self::HdHomeRun => Self::HDHOMERUN, + }) + } +} \ No newline at end of file From c0f293c99ab0edef9c9c9c634293ac0fa059bc6d Mon Sep 17 00:00:00 2001 From: euzu Date: Thu, 19 Jun 2025 17:09:00 +0200 Subject: [PATCH 5/9] backend config refactored --- backend/src/api/api_utils.rs | 6 +- backend/src/main.rs | 4 +- .../api_proxy.rs} | 0 .../src/model/{config.rs => config/base.rs} | 146 +----------------- .../{config_cache.rs => config/cache.rs} | 0 .../model/{config_epg.rs => config/epg.rs} | 0 .../hdhomerun.rs} | 0 .../healthcheck.rs} | 0 .../{config_input.rs => config/input.rs} | 0 .../ip_check.rs} | 0 .../model/{config_log.rs => config/log.rs} | 0 .../messaging.rs} | 0 backend/src/model/config/mod.rs | 47 ++++++ .../{config_proxy.rs => config/proxy.rs} | 0 backend/src/model/config/rate_limit.rs | 21 +++ .../{config_rename.rs => config/rename.rs} | 0 backend/src/model/config/reverse_proxy.rs | 42 +++++ backend/src/model/config/schedule.rs | 9 ++ .../model/{config_sort.rs => config/sort.rs} | 0 .../{config_source.rs => config/source.rs} | 3 +- backend/src/model/config/stream.rs | 80 ++++++++++ .../{config_target.rs => config/target.rs} | 59 +------ backend/src/model/{ => config}/trakt.rs | 2 +- .../video_download.rs} | 0 .../web_auth.rs} | 0 .../{config_webui.rs => config/webui.rs} | 0 backend/src/model/mod.rs | 41 +---- backend/src/model/xtream.rs | 2 +- backend/src/utils/mod.rs | 10 +- backend/src/{model => utils}/serde_utils.rs | 0 shared/src/model/config/hdhomerun.rs | 23 +++ shared/src/model/config/mod.rs | 5 +- shared/src/model/config/target.rs | 4 +- .../config/{video.rs => video_download.rs} | 0 shared/src/model/target_type.rs | 3 +- 35 files changed, 253 insertions(+), 254 deletions(-) rename backend/src/model/{config_api_proxy.rs => config/api_proxy.rs} (100%) rename backend/src/model/{config.rs => config/base.rs} (81%) rename backend/src/model/{config_cache.rs => config/cache.rs} (100%) rename backend/src/model/{config_epg.rs => config/epg.rs} (100%) rename backend/src/model/{config_hdhomerun.rs => config/hdhomerun.rs} (100%) rename backend/src/model/{config_healthcheck.rs => config/healthcheck.rs} (100%) rename backend/src/model/{config_input.rs => config/input.rs} (100%) rename backend/src/model/{config_ip_check.rs => config/ip_check.rs} (100%) rename backend/src/model/{config_log.rs => config/log.rs} (100%) rename backend/src/model/{config_messaging.rs => config/messaging.rs} (100%) create mode 100644 backend/src/model/config/mod.rs rename backend/src/model/{config_proxy.rs => config/proxy.rs} (100%) create mode 100644 backend/src/model/config/rate_limit.rs rename backend/src/model/{config_rename.rs => config/rename.rs} (100%) create mode 100644 backend/src/model/config/reverse_proxy.rs create mode 100644 backend/src/model/config/schedule.rs rename backend/src/model/{config_sort.rs => config/sort.rs} (100%) rename backend/src/model/{config_source.rs => config/source.rs} (98%) create mode 100644 backend/src/model/config/stream.rs rename backend/src/model/{config_target.rs => config/target.rs} (89%) rename backend/src/model/{ => config}/trakt.rs (98%) rename backend/src/model/{config_download.rs => config/video_download.rs} (100%) rename backend/src/model/{config_web_auth.rs => config/web_auth.rs} (100%) rename backend/src/model/{config_webui.rs => config/webui.rs} (100%) rename backend/src/{model => utils}/serde_utils.rs (100%) rename shared/src/model/config/{video.rs => video_download.rs} (100%) diff --git a/backend/src/api/api_utils.rs b/backend/src/api/api_utils.rs index ee759d3a8..41668eeb5 100644 --- a/backend/src/api/api_utils.rs +++ b/backend/src/api/api_utils.rs @@ -12,9 +12,9 @@ use crate::api::model::streams::provider_stream_factory::{create_provider_stream use crate::api::model::streams::shared_stream_manager::SharedStreamManager; use crate::api::model::streams::throttled_stream::ThrottledStream; use crate::auth::Claims; -use crate::model::{ProxyUserCredentials, UserConnectionPermission}; -use crate::model::{ConfigInput, ConfigTarget, InputFetchMethod, TargetType}; -use shared::model::{PlaylistEntry, PlaylistItemType, XtreamCluster}; +use crate::model::{ConfigTarget, ProxyUserCredentials, UserConnectionPermission}; +use crate::model::{ConfigInput, InputFetchMethod}; +use shared::model::{PlaylistEntry, PlaylistItemType, TargetType, XtreamCluster}; use crate::tools::atomic_once_flag::AtomicOnceFlag; use crate::tools::lru_cache::LRUResourceCache; use shared::utils::{DASH_EXT, HLS_EXT}; diff --git a/backend/src/main.rs b/backend/src/main.rs index f2d1de90e..e49f52327 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -10,7 +10,7 @@ mod modules; include_modules!(); use crate::auth::generate_password; -use crate::model::{Config, HealthcheckConfig, Healthcheck, ProcessTargets}; +use crate::model::{Config, Healthcheck, HealthcheckConfig, ProcessTargets}; use crate::processing::processor::playlist; use crate::utils::{config_file_reader, resolve_env_var}; use crate::utils::request::{create_client, set_sanitize_sensitive_info}; @@ -20,7 +20,7 @@ use log::{error, info}; use std::fs::File; use std::path::{Path, PathBuf}; use std::sync::Arc; -use crate::utils::logging::init_logger; +use crate::utils::init_logger; #[derive(Parser)] #[command(name = "tuliprox")] diff --git a/backend/src/model/config_api_proxy.rs b/backend/src/model/config/api_proxy.rs similarity index 100% rename from backend/src/model/config_api_proxy.rs rename to backend/src/model/config/api_proxy.rs diff --git a/backend/src/model/config.rs b/backend/src/model/config/base.rs similarity index 81% rename from backend/src/model/config.rs rename to backend/src/model/config/base.rs index 2e48a793e..750399ea6 100644 --- a/backend/src/model/config.rs +++ b/backend/src/model/config/base.rs @@ -5,17 +5,14 @@ use std::io::Read; use std::path::{Path, PathBuf}; use std::sync::Arc; -use log::{debug, error, warn}; +use log::{debug, error}; use path_clean::PathClean; use rand::Rng; -use crate::model::{ApiProxyConfig, ApiProxyServerInfo, Mappings, ProxyUserCredentials, SourcesConfig}; +use crate::model::{ApiProxyConfig, ApiProxyServerInfo, CustomStreamResponse, Mappings, ProxyUserCredentials, ReverseProxyConfig, ScheduleConfig, SourcesConfig}; use crate::model::{ConfigInput, ConfigInputOptions, ConfigTarget, HdHomeRunConfig, IpCheckConfig, LogConfig, MessagingConfig, ProxyConfig, TargetOutput, VideoConfig, WebUiConfig}; use shared::error::{create_tuliprox_error_result, TuliproxError, TuliproxErrorKind}; -use shared::utils::{parse_to_kbps, default_connect_timeout_secs, default_grace_period_millis, default_grace_period_timeout_secs}; - -const STREAM_QUEUE_SIZE: usize = 1024; // mpsc channel holding messages. with 8192byte chunks and 2Mbit/s approx 8MB - +use shared::utils::{default_connect_timeout_secs}; const CHANNEL_UNAVAILABLE: &str = "channel_unavailable.ts"; const USER_CONNECTIONS_EXHAUSTED: &str = "user_connections_exhausted.ts"; @@ -37,7 +34,6 @@ macro_rules! valid_property { } pub use valid_property; use crate::api::model::streams::transport_stream_buffer::TransportStreamBuffer; -use crate::model::config_cache::CacheConfig; use crate::utils; @@ -136,142 +132,6 @@ impl ConfigDto { } } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] -#[serde(deny_unknown_fields)] -pub struct ScheduleConfig { - #[serde(default)] - pub schedule: String, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub targets: Option>, -} - -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] -#[serde(deny_unknown_fields)] -pub struct StreamBufferConfig { - #[serde(default)] - pub enabled: bool, - #[serde(default)] - pub size: usize, -} - -impl StreamBufferConfig { - fn prepare(&mut self) { - if self.enabled && self.size == 0 { - self.size = STREAM_QUEUE_SIZE; - } - } -} - -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] -#[serde(deny_unknown_fields)] -pub struct StreamConfig { - #[serde(default)] - pub retry: bool, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub buffer: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub throttle: Option, - #[serde(default = "default_grace_period_millis")] - pub grace_period_millis: u64, - #[serde(default = "default_grace_period_timeout_secs")] - pub grace_period_timeout_secs: u64, - #[serde(default)] - pub forced_retry_interval_secs: u32, - #[serde(default, skip)] - pub throttle_kbps: u64, -} - -impl StreamConfig { - fn prepare(&mut self) -> Result<(), TuliproxError> { - if let Some(buffer) = self.buffer.as_mut() { - buffer.prepare(); - } - if let Some(throttle) = &self.throttle { - self.throttle_kbps = parse_to_kbps(throttle).map_err(|err| TuliproxError::new(TuliproxErrorKind::Info, err))?; - } - - if self.grace_period_millis > 0 { - if self.grace_period_timeout_secs == 0 { - let triple_ms = self.grace_period_millis * 3; - self.grace_period_timeout_secs = std::cmp::max(1, triple_ms.div_ceil(1000)); - } else if self.grace_period_millis / 1000 > self.grace_period_timeout_secs { - return Err(TuliproxError::new(TuliproxErrorKind::Info, format!("Grace time period timeout {} sec should be more than grace time period {} ms", self.grace_period_timeout_secs, self.grace_period_millis))); - } - } - - Ok(()) - } -} - -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] -#[serde(deny_unknown_fields)] -pub struct RateLimitConfig { - pub enabled: bool, - pub period_millis: u64, - pub burst_size: u32, -} - -impl RateLimitConfig { - fn prepare(&self) -> Result<(), TuliproxError> { - if self.period_millis == 0 { - return Err(TuliproxError::new(TuliproxErrorKind::Info, "Rate limiter period can't be 0".to_string())); - } - if self.burst_size == 0 { - return Err(TuliproxError::new(TuliproxErrorKind::Info, "Rate limiter bust can't be 0".to_string())); - } - Ok(()) - } -} - -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] -#[serde(deny_unknown_fields)] -pub struct ReverseProxyConfig { - #[serde(default, skip_serializing_if = "Option::is_none")] - pub stream: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub cache: Option, - #[serde(default)] - pub resource_rewrite_disabled: bool, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub rate_limit: Option, - #[serde(default)] - pub disable_referer_header: bool, -} - -impl ReverseProxyConfig { - fn prepare(&mut self, working_dir: &str) -> Result<(), TuliproxError> { - if let Some(stream) = self.stream.as_mut() { - stream.prepare()?; - } - if let Some(cache) = self.cache.as_mut() { - if cache.enabled && self.resource_rewrite_disabled { - warn!("The cache is disabled because resource rewrite is disabled"); - cache.enabled = false; - } - cache.prepare(working_dir)?; - } - - if let Some(rate_limit) = self.rate_limit.as_mut() { - if rate_limit.enabled { - rate_limit.prepare()?; - } - } - Ok(()) - } -} - -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] -#[serde(deny_unknown_fields)] -pub struct CustomStreamResponse { - #[serde(default, skip)] - pub channel_unavailable: Option, - #[serde(default, skip)] - pub user_connections_exhausted: Option, // user has no more connections - #[serde(default, skip)] - pub provider_connections_exhausted: Option, // provider limit reached, has no more connections - #[serde(default, skip)] - pub user_account_expired: Option, -} #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] #[serde(deny_unknown_fields)] diff --git a/backend/src/model/config_cache.rs b/backend/src/model/config/cache.rs similarity index 100% rename from backend/src/model/config_cache.rs rename to backend/src/model/config/cache.rs diff --git a/backend/src/model/config_epg.rs b/backend/src/model/config/epg.rs similarity index 100% rename from backend/src/model/config_epg.rs rename to backend/src/model/config/epg.rs diff --git a/backend/src/model/config_hdhomerun.rs b/backend/src/model/config/hdhomerun.rs similarity index 100% rename from backend/src/model/config_hdhomerun.rs rename to backend/src/model/config/hdhomerun.rs diff --git a/backend/src/model/config_healthcheck.rs b/backend/src/model/config/healthcheck.rs similarity index 100% rename from backend/src/model/config_healthcheck.rs rename to backend/src/model/config/healthcheck.rs diff --git a/backend/src/model/config_input.rs b/backend/src/model/config/input.rs similarity index 100% rename from backend/src/model/config_input.rs rename to backend/src/model/config/input.rs diff --git a/backend/src/model/config_ip_check.rs b/backend/src/model/config/ip_check.rs similarity index 100% rename from backend/src/model/config_ip_check.rs rename to backend/src/model/config/ip_check.rs diff --git a/backend/src/model/config_log.rs b/backend/src/model/config/log.rs similarity index 100% rename from backend/src/model/config_log.rs rename to backend/src/model/config/log.rs diff --git a/backend/src/model/config_messaging.rs b/backend/src/model/config/messaging.rs similarity index 100% rename from backend/src/model/config_messaging.rs rename to backend/src/model/config/messaging.rs diff --git a/backend/src/model/config/mod.rs b/backend/src/model/config/mod.rs new file mode 100644 index 000000000..27bda7f6d --- /dev/null +++ b/backend/src/model/config/mod.rs @@ -0,0 +1,47 @@ +mod trakt; +mod base; +mod webui; +mod web_auth; +mod messaging; +mod hdhomerun; +mod ip_check; +mod source; +mod target; +mod sort; +mod video_download; +mod log; +mod input; +mod stream; +mod epg; +mod reverse_proxy; +mod cache; +mod rate_limit; +mod proxy; +mod schedule; +mod api_proxy; +mod rename; + +mod healthcheck; + +pub use base::*; +pub use api_proxy::*; +pub use webui::*; +pub use web_auth::*; +pub use messaging::*; +pub use hdhomerun::*; +pub use ip_check::*; +pub use source::*; +pub use target::*; +pub use sort::*; +pub use video_download::*; +pub use schedule::*; +pub use log::*; +pub use input::*; +pub use stream::*; +pub use epg::*; +pub use rate_limit::*; +pub use reverse_proxy::*; +pub use proxy::*; +pub use rename::*; +pub use trakt::*; +pub use healthcheck::*; diff --git a/backend/src/model/config_proxy.rs b/backend/src/model/config/proxy.rs similarity index 100% rename from backend/src/model/config_proxy.rs rename to backend/src/model/config/proxy.rs diff --git a/backend/src/model/config/rate_limit.rs b/backend/src/model/config/rate_limit.rs new file mode 100644 index 000000000..d3ca7a9ba --- /dev/null +++ b/backend/src/model/config/rate_limit.rs @@ -0,0 +1,21 @@ +use shared::error::{TuliproxError, TuliproxErrorKind}; + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct RateLimitConfig { + pub enabled: bool, + pub period_millis: u64, + pub burst_size: u32, +} + +impl RateLimitConfig { + pub(crate) fn prepare(&self) -> Result<(), TuliproxError> { + if self.period_millis == 0 { + return Err(TuliproxError::new(TuliproxErrorKind::Info, "Rate limiter period can't be 0".to_string())); + } + if self.burst_size == 0 { + return Err(TuliproxError::new(TuliproxErrorKind::Info, "Rate limiter bust can't be 0".to_string())); + } + Ok(()) + } +} \ No newline at end of file diff --git a/backend/src/model/config_rename.rs b/backend/src/model/config/rename.rs similarity index 100% rename from backend/src/model/config_rename.rs rename to backend/src/model/config/rename.rs diff --git a/backend/src/model/config/reverse_proxy.rs b/backend/src/model/config/reverse_proxy.rs new file mode 100644 index 000000000..dc531856c --- /dev/null +++ b/backend/src/model/config/reverse_proxy.rs @@ -0,0 +1,42 @@ +use log::warn; +use shared::error::TuliproxError; +use crate::model::config::cache::CacheConfig; +use crate::model::{RateLimitConfig, StreamConfig}; + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct ReverseProxyConfig { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub stream: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub cache: Option, + #[serde(default)] + pub resource_rewrite_disabled: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub rate_limit: Option, + #[serde(default)] + pub disable_referer_header: bool, +} + + +impl ReverseProxyConfig { + pub(crate) fn prepare(&mut self, working_dir: &str) -> Result<(), TuliproxError> { + if let Some(stream) = self.stream.as_mut() { + stream.prepare()?; + } + if let Some(cache) = self.cache.as_mut() { + if cache.enabled && self.resource_rewrite_disabled { + warn!("The cache is disabled because resource rewrite is disabled"); + cache.enabled = false; + } + cache.prepare(working_dir)?; + } + + if let Some(rate_limit) = self.rate_limit.as_mut() { + if rate_limit.enabled { + rate_limit.prepare()?; + } + } + Ok(()) + } +} diff --git a/backend/src/model/config/schedule.rs b/backend/src/model/config/schedule.rs new file mode 100644 index 000000000..aea8d6841 --- /dev/null +++ b/backend/src/model/config/schedule.rs @@ -0,0 +1,9 @@ + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct ScheduleConfig { + #[serde(default)] + pub schedule: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub targets: Option>, +} diff --git a/backend/src/model/config_sort.rs b/backend/src/model/config/sort.rs similarity index 100% rename from backend/src/model/config_sort.rs rename to backend/src/model/config/sort.rs diff --git a/backend/src/model/config_source.rs b/backend/src/model/config/source.rs similarity index 98% rename from backend/src/model/config_source.rs rename to backend/src/model/config/source.rs index d861eaa8e..5559eddd2 100644 --- a/backend/src/model/config_source.rs +++ b/backend/src/model/config/source.rs @@ -1,8 +1,7 @@ use std::collections::{HashMap, HashSet}; use crate::foundation::filter::{prepare_templates, PatternTemplate}; use shared::error::{TuliproxError, TuliproxErrorKind, handle_tuliprox_error_result_list, create_tuliprox_error_result}; -use crate::model::{ConfigInput, ProcessTargets}; -use crate::model::config_target::ConfigTarget; +use crate::model::{ConfigInput, ConfigTarget, ProcessTargets}; use shared::utils::default_as_default; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] diff --git a/backend/src/model/config/stream.rs b/backend/src/model/config/stream.rs new file mode 100644 index 000000000..51fe357dc --- /dev/null +++ b/backend/src/model/config/stream.rs @@ -0,0 +1,80 @@ +use shared::utils::default_grace_period_millis; +use shared::utils::default_grace_period_timeout_secs; +use shared::error::{TuliproxError, TuliproxErrorKind}; +use shared::info_err; +use shared::utils::parse_to_kbps; +use crate::api::model::streams::transport_stream_buffer::TransportStreamBuffer; + +const STREAM_QUEUE_SIZE: usize = 1024; // mpsc channel holding messages. with 8192byte chunks and 2Mbit/s approx 8MB + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct StreamBufferConfig { + #[serde(default)] + pub enabled: bool, + #[serde(default)] + pub size: usize, +} + +impl StreamBufferConfig { + fn prepare(&mut self) { + if self.enabled && self.size == 0 { + self.size = STREAM_QUEUE_SIZE; + } + } +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct StreamConfig { + #[serde(default)] + pub retry: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub buffer: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub throttle: Option, + #[serde(default = "default_grace_period_millis")] + pub grace_period_millis: u64, + #[serde(default = "default_grace_period_timeout_secs")] + pub grace_period_timeout_secs: u64, + #[serde(default)] + pub forced_retry_interval_secs: u32, + #[serde(default, skip)] + pub throttle_kbps: u64, +} + +impl StreamConfig { + pub(crate) fn prepare(&mut self) -> Result<(), TuliproxError> { + if let Some(buffer) = self.buffer.as_mut() { + buffer.prepare(); + } + if let Some(throttle) = &self.throttle { + self.throttle_kbps = parse_to_kbps(throttle).map_err(|err| TuliproxError::new(TuliproxErrorKind::Info, err))?; + } + + if self.grace_period_millis > 0 { + if self.grace_period_timeout_secs == 0 { + let triple_ms = self.grace_period_millis * 3; + self.grace_period_timeout_secs = std::cmp::max(1, triple_ms.div_ceil(1000)); + } else if self.grace_period_millis / 1000 > self.grace_period_timeout_secs { + return Err(info_err!(format!("Grace time period timeout {} sec should be more than grace time period {} ms", self.grace_period_timeout_secs, self.grace_period_millis))); + } + } + + Ok(()) + } +} + + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct CustomStreamResponse { + #[serde(default, skip)] + pub channel_unavailable: Option, + #[serde(default, skip)] + pub user_connections_exhausted: Option, // user has no more connections + #[serde(default, skip)] + pub provider_connections_exhausted: Option, // provider limit reached, has no more connections + #[serde(default, skip)] + pub user_account_expired: Option, +} \ No newline at end of file diff --git a/backend/src/model/config_target.rs b/backend/src/model/config/target.rs similarity index 89% rename from backend/src/model/config_target.rs rename to backend/src/model/config/target.rs index c914e5795..2c54ab6e7 100644 --- a/backend/src/model/config_target.rs +++ b/backend/src/model/config/target.rs @@ -1,68 +1,15 @@ use crate::foundation::filter::{get_filter, Filter, PatternTemplate, ValueProvider}; -use crate::model::config_rename::ConfigRename; -use crate::model::config_sort::ConfigSort; use crate::model::mapping::Mapping; -use crate::model::trakt::TraktConfig; +use crate::model::config::trakt::TraktConfig; use shared::error::{create_tuliprox_error_result, handle_tuliprox_error_result_list, info_err, TuliproxError, TuliproxErrorKind}; use shared::utils::{default_as_default, default_as_true, default_resolve_delay_secs}; use arc_swap::ArcSwapOption; -use enum_iterator::Sequence; -use shared::model::{ClusterFlags, ProcessingOrder, StrmExportStyle}; +use shared::model::{ClusterFlags, ProcessingOrder, StrmExportStyle, TargetType}; use shared::model::PlaylistItemType; -use std::fmt::Display; use std::sync::Arc; +use crate::model::{ConfigRename, ConfigSort}; -#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, Sequence, PartialEq, Eq, Hash)] -pub enum TargetType { - #[serde(rename = "m3u")] - M3u, - #[serde(rename = "xtream")] - Xtream, - #[serde(rename = "strm")] - Strm, - #[serde(rename = "hdhomerun")] - HdHomeRun, -} - -impl TargetType { - const M3U: &'static str = "M3u"; - const XTREAM: &'static str = "Xtream"; - const STRM: &'static str = "Strm"; - const HDHOMERUN: &'static str = "HdHomeRun"; -} - -impl Display for TargetType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", match *self { - Self::M3u => Self::M3U, - Self::Xtream => Self::XTREAM, - Self::Strm => Self::STRM, - Self::HdHomeRun => Self::HDHOMERUN, - }) - } -} - -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Sequence, PartialEq, Eq, Hash)] -enum HdHomeRunUseTargetType { - #[serde(rename = "m3u")] - M3u, - #[serde(rename = "xtream")] - Xtream, -} - -impl TryFrom for HdHomeRunUseTargetType { - type Error = &'static str; - - fn try_from(value: TargetType) -> Result { - match value { - TargetType::Xtream => Ok(Self::Xtream), - TargetType::M3u => Ok(Self::M3u), - _ => Err("Not allowed!"), - } - } -} - #[derive(Clone, Debug)] pub struct ProcessTargets { pub enabled: bool, diff --git a/backend/src/model/trakt.rs b/backend/src/model/config/trakt.rs similarity index 98% rename from backend/src/model/trakt.rs rename to backend/src/model/config/trakt.rs index f923de0c3..183b8fb98 100644 --- a/backend/src/model/trakt.rs +++ b/backend/src/model/config/trakt.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; use crate::model::{PlaylistItem}; -use crate::utils::trakt::normalize_title_for_matching; +use crate::utils::normalize_title_for_matching; const TRAKT_API_KEY: &str = "0183a05ad97098d87287fe46da4ae286f434f32e8e951caad4cc147c947d79a3"; const TRAKT_API_VERSION: &str = "2"; diff --git a/backend/src/model/config_download.rs b/backend/src/model/config/video_download.rs similarity index 100% rename from backend/src/model/config_download.rs rename to backend/src/model/config/video_download.rs diff --git a/backend/src/model/config_web_auth.rs b/backend/src/model/config/web_auth.rs similarity index 100% rename from backend/src/model/config_web_auth.rs rename to backend/src/model/config/web_auth.rs diff --git a/backend/src/model/config_webui.rs b/backend/src/model/config/webui.rs similarity index 100% rename from backend/src/model/config_webui.rs rename to backend/src/model/config/webui.rs diff --git a/backend/src/model/mod.rs b/backend/src/model/mod.rs index 2c1f6d00c..bc343a3af 100644 --- a/backend/src/model/mod.rs +++ b/backend/src/model/mod.rs @@ -1,56 +1,19 @@ -mod config; mod playlist; mod mapping; -mod config_api_proxy; mod stats; mod xmltv; mod xtream; mod healthcheck; mod playlist_categories; mod xtream_const; -mod serde_utils; -mod config_hdhomerun; -mod config_ip_check; -mod config_sort; -mod config_rename; -mod config_target; -mod config_source; -mod config_proxy; -mod config_webui; -mod config_input; -mod config_epg; -mod config_messaging; -mod config_download; -mod config_web_auth; -mod config_log; -mod config_healthcheck; -mod config_cache; -mod trakt; +mod config; -pub use self::config::*; pub use self::playlist::*; pub use self::mapping::*; -pub use self::config_api_proxy::*; pub use self::stats::*; pub use self::xmltv::*; pub use self::xtream::*; pub use self::healthcheck::*; pub use self::playlist_categories::*; pub use self::xtream_const::*; -pub use self::config_webui::*; -pub use self::config_ip_check::*; -pub use self::config_sort::*; -pub use self::config_rename::*; -pub use self::config_target::*; -pub use self::config_source::*; -pub use self::config_proxy::*; -// pub use self::config_webui::*; -pub use self::config_input::*; -pub use self::config_epg::*; -pub use self::config_hdhomerun::*; -pub use self::config_messaging::*; -pub use self::config_download::*; -pub use self::config_web_auth::*; -pub use self::config_log::*; -pub use self::config_healthcheck::*; -pub use self::trakt::*; +pub use self::config::*; diff --git a/backend/src/model/xtream.rs b/backend/src/model/xtream.rs index bfcd5fd73..c5ac2977c 100644 --- a/backend/src/model/xtream.rs +++ b/backend/src/model/xtream.rs @@ -1,7 +1,7 @@ use crate::model::{ProxyUserCredentials}; use crate::model::{Config, ConfigTarget, XtreamTargetOutput}; use crate::model::{PlaylistItem,XtreamPlaylistItem}; -use crate::model::serde_utils::{deserialize_as_option_rc_string, deserialize_as_rc_string, deserialize_as_string_array, deserialize_number_from_string}; +use crate::utils::{deserialize_as_option_rc_string, deserialize_as_rc_string, deserialize_as_string_array, deserialize_number_from_string}; use crate::model::xtream_const; use crate::utils::{opt_string_or_number_u32, string_default_on_null, string_or_number_f64, string_or_number_u32}; use shared::utils::{get_non_empty_str}; diff --git a/backend/src/utils/mod.rs b/backend/src/utils/mod.rs index 8d5c730bf..335227cdb 100644 --- a/backend/src/utils/mod.rs +++ b/backend/src/utils/mod.rs @@ -7,8 +7,14 @@ mod network; mod bincode_utils; mod crypto_utils; mod step_measure; -pub mod logging; -pub mod trakt; +mod logging; +mod trakt; +mod serde_utils; + +pub use self::logging::*; +pub use self::trakt::*; +pub use self::serde_utils::*; + #[macro_export] macro_rules! debug_if_enabled { diff --git a/backend/src/model/serde_utils.rs b/backend/src/utils/serde_utils.rs similarity index 100% rename from backend/src/model/serde_utils.rs rename to backend/src/utils/serde_utils.rs diff --git a/shared/src/model/config/hdhomerun.rs b/shared/src/model/config/hdhomerun.rs index c60ea5c41..7807935dd 100644 --- a/shared/src/model/config/hdhomerun.rs +++ b/shared/src/model/config/hdhomerun.rs @@ -1,3 +1,5 @@ +use enum_iterator::Sequence; +use crate::model::TargetType; fn default_friendly_name() -> String { String::from("TuliproxTV") } fn default_manufacturer() -> String { String::from("Silicondust") } @@ -7,6 +9,27 @@ fn default_firmware_version() -> String { String::from("20170930") } fn default_device_type() -> String { String::from("urn:schemas-upnp-org:device:MediaServer:1") } fn default_device_udn() -> String { String::from("uuid:12345678-90ab-cdef-1234-567890abcdef::urn:dial-multicast:com.silicondust.hdhomerun") } + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Sequence, PartialEq, Eq, Hash)] +enum HdHomeRunUseTargetType { + #[serde(rename = "m3u")] + M3u, + #[serde(rename = "xtream")] + Xtream, +} + +impl TryFrom for HdHomeRunUseTargetType { + type Error = &'static str; + + fn try_from(value: TargetType) -> Result { + match value { + TargetType::Xtream => Ok(Self::Xtream), + TargetType::M3u => Ok(Self::M3u), + _ => Err("Not allowed!"), + } + } +} + #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] #[serde(deny_unknown_fields)] pub struct HdHomeRunDeviceConfigDto { diff --git a/shared/src/model/config/mod.rs b/shared/src/model/config/mod.rs index c06f0ab70..90d9771ed 100644 --- a/shared/src/model/config/mod.rs +++ b/shared/src/model/config/mod.rs @@ -7,7 +7,7 @@ mod ipcheck; mod source; mod target; mod sort; -mod video; +mod video_download; mod schedule; mod log; mod input; @@ -25,7 +25,8 @@ pub use hdhomerun::*; pub use ipcheck::*; pub use source::*; pub use sort::*; -pub use video::*; +pub use target::*; +pub use video_download::*; pub use schedule::*; pub use log::*; pub use input::*; diff --git a/shared/src/model/config/target.rs b/shared/src/model/config/target.rs index ae79cc9cb..2707956a8 100644 --- a/shared/src/model/config/target.rs +++ b/shared/src/model/config/target.rs @@ -75,7 +75,7 @@ pub struct HdHomeRunTargetOutputDto { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[serde(deny_unknown_fields, tag = "type", rename_all = "lowercase")] -pub enum TargetOutput { +pub enum TargetOutputDto { Xtream(XtreamTargetOutputDto), M3u(M3uTargetOutputDto), Strm(StrmTargetOutputDto), @@ -98,7 +98,7 @@ pub struct ConfigTargetDto { pub sort: Option, pub filter: String, #[serde(default)] - pub output: Vec, + pub output: Vec, #[serde(skip_serializing_if = "Option::is_none")] pub rename: Option>, #[serde(skip_serializing_if = "Option::is_none")] diff --git a/shared/src/model/config/video.rs b/shared/src/model/config/video_download.rs similarity index 100% rename from shared/src/model/config/video.rs rename to shared/src/model/config/video_download.rs diff --git a/shared/src/model/target_type.rs b/shared/src/model/target_type.rs index 405d47ba2..58998bc73 100644 --- a/shared/src/model/target_type.rs +++ b/shared/src/model/target_type.rs @@ -29,4 +29,5 @@ impl Display for TargetType { Self::HdHomeRun => Self::HDHOMERUN, }) } -} \ No newline at end of file +} + From 3cf00a809fee5d2eb78c98be6e2896bf9e4cc977 Mon Sep 17 00:00:00 2001 From: euzu Date: Thu, 19 Jun 2025 17:20:31 +0200 Subject: [PATCH 6/9] api_proxy refactored --- backend/src/api/api_utils.rs | 4 +- .../src/api/endpoints/api_playlist_utils.rs | 4 +- backend/src/api/endpoints/hdhomerun_api.rs | 6 +- backend/src/api/endpoints/hls_api.rs | 4 +- backend/src/api/endpoints/m3u_api.rs | 4 +- backend/src/api/endpoints/user_api.rs | 4 +- backend/src/api/endpoints/v1_api.rs | 4 +- backend/src/api/endpoints/xmltv_api.rs | 4 +- backend/src/api/endpoints/xtream_api.rs | 9 +- backend/src/api/model/active_user_manager.rs | 3 +- backend/src/api/model/app_state.rs | 3 +- backend/src/api/model/config.rs | 2 +- backend/src/api/model/xtream.rs | 3 +- backend/src/processing/processor/trakt.rs | 4 +- .../src/repository/m3u_playlist_iterator.rs | 6 +- backend/src/repository/user_repository.rs | 6 +- .../repository/xtream_playlist_iterator.rs | 4 +- shared/src/model/config/api_proxy.rs | 30 +++ shared/src/model/config/api_user.rs | 204 ++++++++++++++++++ shared/src/model/config/mod.rs | 6 + shared/src/model/config/rename.rs | 9 + shared/src/model/config/source.rs | 10 +- shared/src/model/config/target.rs | 3 +- 23 files changed, 287 insertions(+), 49 deletions(-) create mode 100644 shared/src/model/config/api_proxy.rs create mode 100644 shared/src/model/config/api_user.rs create mode 100644 shared/src/model/config/rename.rs diff --git a/backend/src/api/api_utils.rs b/backend/src/api/api_utils.rs index 41668eeb5..4df0cd9c2 100644 --- a/backend/src/api/api_utils.rs +++ b/backend/src/api/api_utils.rs @@ -12,9 +12,9 @@ use crate::api::model::streams::provider_stream_factory::{create_provider_stream use crate::api::model::streams::shared_stream_manager::SharedStreamManager; use crate::api::model::streams::throttled_stream::ThrottledStream; use crate::auth::Claims; -use crate::model::{ConfigTarget, ProxyUserCredentials, UserConnectionPermission}; +use crate::model::{ConfigTarget, ProxyUserCredentials}; use crate::model::{ConfigInput, InputFetchMethod}; -use shared::model::{PlaylistEntry, PlaylistItemType, TargetType, XtreamCluster}; +use shared::model::{PlaylistEntry, PlaylistItemType, TargetType, UserConnectionPermission, XtreamCluster}; use crate::tools::atomic_once_flag::AtomicOnceFlag; use crate::tools::lru_cache::LRUResourceCache; use shared::utils::{DASH_EXT, HLS_EXT}; diff --git a/backend/src/api/endpoints/api_playlist_utils.rs b/backend/src/api/endpoints/api_playlist_utils.rs index 53f78e3c1..26045c598 100644 --- a/backend/src/api/endpoints/api_playlist_utils.rs +++ b/backend/src/api/endpoints/api_playlist_utils.rs @@ -1,6 +1,6 @@ -use crate::model::{Config, ConfigInput, ConfigTarget, InputType, TargetType}; +use crate::model::{Config, ConfigInput, ConfigTarget, InputType}; use crate::model::{M3uPlaylistItem, PlaylistGroup}; -use shared::model::{PlaylistItemType, XtreamCluster}; +use shared::model::{PlaylistItemType, TargetType, XtreamCluster}; use crate::repository::{m3u_repository, xtream_repository}; use crate::utils::{m3u, xtream}; use axum::response::IntoResponse; diff --git a/backend/src/api/endpoints/hdhomerun_api.rs b/backend/src/api/endpoints/hdhomerun_api.rs index 4db41ce9e..784f27a9e 100644 --- a/backend/src/api/endpoints/hdhomerun_api.rs +++ b/backend/src/api/endpoints/hdhomerun_api.rs @@ -1,9 +1,9 @@ use crate::api::model::app_state::HdHomerunAppState; use crate::auth::AuthBasic; -use crate::model::ProxyUserCredentials; -use crate::model::{Config, ConfigTarget, TargetType}; +use crate::model::{ConfigTarget, ProxyUserCredentials}; +use crate::model::{Config}; use crate::model::{M3uPlaylistItem, XtreamPlaylistItem}; -use shared::model::{PlaylistItemType, XtreamCluster}; +use shared::model::{PlaylistItemType, TargetType, XtreamCluster}; use crate::processing::parser::xtream::get_xtream_url; use crate::repository::m3u_playlist_iterator::M3uPlaylistIterator; use crate::repository::xtream_playlist_iterator::XtreamPlaylistIterator; diff --git a/backend/src/api/endpoints/hls_api.rs b/backend/src/api/endpoints/hls_api.rs index f72fc470f..da5748d5f 100644 --- a/backend/src/api/endpoints/hls_api.rs +++ b/backend/src/api/endpoints/hls_api.rs @@ -2,9 +2,9 @@ use crate::api::api_utils::{force_provider_stream_response, get_stream_alternati use crate::api::api_utils::{try_option_bad_request}; use crate::api::model::app_state::AppState; use crate::api::model::streams::provider_stream::{create_custom_video_stream_response, CustomVideoStreamType}; -use crate::model::{ProxyUserCredentials, UserConnectionPermission}; +use crate::model::{ProxyUserCredentials}; use crate::model::ConfigInput; -use shared::model::{PlaylistItemType, XtreamCluster}; +use shared::model::{PlaylistItemType, UserConnectionPermission, XtreamCluster}; use crate::processing::parser::hls::{get_hls_session_token_and_url_from_token, rewrite_hls, RewriteHlsProps}; use shared::utils::HLS_EXT; use crate::utils::request; diff --git a/backend/src/api/endpoints/m3u_api.rs b/backend/src/api/endpoints/m3u_api.rs index 111ac420d..ddc166740 100644 --- a/backend/src/api/endpoints/m3u_api.rs +++ b/backend/src/api/endpoints/m3u_api.rs @@ -4,9 +4,7 @@ use crate::api::endpoints::xtream_api::{ApiStreamContext, ApiStreamRequest}; use crate::api::model::app_state::AppState; use crate::api::model::request::UserApiRequest; use crate::api::model::streams::provider_stream::{create_custom_video_stream_response, CustomVideoStreamType}; -use crate::model::TargetType; -use crate::model::UserConnectionPermission; -use shared::model::{FieldGetAccessor, PlaylistEntry, PlaylistItemType, XtreamCluster}; +use shared::model::{FieldGetAccessor, PlaylistEntry, PlaylistItemType, TargetType, UserConnectionPermission, XtreamCluster}; use crate::repository::m3u_repository::{m3u_get_item_for_stream_id, m3u_load_rewrite_playlist}; use crate::repository::storage_const; use crate::utils::request::{extract_extension_from_url, sanitize_sensitive_info}; diff --git a/backend/src/api/endpoints/user_api.rs b/backend/src/api/endpoints/user_api.rs index b14147013..7c355be47 100644 --- a/backend/src/api/endpoints/user_api.rs +++ b/backend/src/api/endpoints/user_api.rs @@ -1,8 +1,8 @@ use crate::api::api_utils::{get_user_target_by_username, get_username_from_auth_header}; use crate::api::model::app_state::AppState; use crate::auth::validator_user; -use crate::model::{Config, ConfigTarget, TargetType}; -use shared::model::XtreamCluster; +use crate::model::{Config, ConfigTarget}; +use shared::model::{TargetType, XtreamCluster}; use crate::model::PlaylistBouquetDto; use crate::model::PlaylistXtreamCategory; use crate::repository::user_repository::{load_user_bouquet_as_json, save_user_bouquet}; diff --git a/backend/src/api/endpoints/v1_api.rs b/backend/src/api/endpoints/v1_api.rs index f9c7e417b..25684b3d1 100644 --- a/backend/src/api/endpoints/v1_api.rs +++ b/backend/src/api/endpoints/v1_api.rs @@ -7,9 +7,9 @@ use crate::api::model::request::{PlaylistRequest, PlaylistRequestType}; use crate::auth::create_access_token; use crate::auth::validator_admin; use shared::error::TuliproxError; -use crate::model::StatusCheck; +use crate::model::{ConfigTarget, StatusCheck}; use crate::model::XtreamPlaylistItem; -use crate::model::{Config, ConfigDto, ConfigInput, ConfigInputOptions, ConfigSource, ConfigTarget, InputType}; +use crate::model::{Config, ConfigDto, ConfigInput, ConfigInputOptions, ConfigSource, InputType}; use crate::model::{ApiProxyConfig, ApiProxyServerInfo, ProxyUserCredentials, TargetUser}; use crate::processing::processor::playlist; use crate::repository::user_repository::store_api_user; diff --git a/backend/src/api/endpoints/xmltv_api.rs b/backend/src/api/endpoints/xmltv_api.rs index b661a4d34..937125274 100644 --- a/backend/src/api/endpoints/xmltv_api.rs +++ b/backend/src/api/endpoints/xmltv_api.rs @@ -12,8 +12,8 @@ use std::sync::Arc; use crate::api::api_utils::{get_user_target, serve_file}; use crate::api::model::app_state::AppState; use crate::api::model::request::UserApiRequest; -use crate::model::ProxyUserCredentials; -use crate::model::{Config, ConfigTarget, TargetOutput}; +use crate::model::{ConfigTarget, ProxyUserCredentials, TargetOutput}; +use crate::model::{Config}; use crate::repository::m3u_repository::m3u_get_epg_file_path; use crate::repository::storage::get_target_storage_path; use crate::repository::xtream_repository::{xtream_get_epg_file_path, xtream_get_storage_path}; diff --git a/backend/src/api/endpoints/xtream_api.rs b/backend/src/api/endpoints/xtream_api.rs index b1107e8c1..1b1f5202f 100644 --- a/backend/src/api/endpoints/xtream_api.rs +++ b/backend/src/api/endpoints/xtream_api.rs @@ -9,10 +9,9 @@ use crate::api::model::app_state::AppState; use crate::api::model::request::UserApiRequest; use crate::api::model::streams::provider_stream::{create_custom_video_stream_response, CustomVideoStreamType}; use crate::api::model::xtream::XtreamAuthorizationResponse; -use crate::model::TargetType; -use crate::model::{get_backdrop_path_value, XtreamPlaylistItem}; -use crate::model::{Config, ConfigInput, ConfigTarget}; -use crate::model::{ProxyType, ProxyUserCredentials, UserConnectionPermission}; +use crate::model::{get_backdrop_path_value, ConfigTarget, XtreamPlaylistItem}; +use crate::model::{Config, ConfigInput}; +use crate::model::{ProxyUserCredentials}; use crate::repository::playlist_repository::get_target_id_mapping; use crate::repository::storage::{get_target_storage_path}; use crate::repository::{storage_const, user_repository, xtream_repository}; @@ -41,7 +40,7 @@ use std::fmt::{Display, Formatter}; use std::path::Path; use std::str::FromStr; use std::sync::Arc; -use shared::model::{PlaylistItemType, XtreamCluster, FieldGetAccessor, PlaylistEntry}; +use shared::model::{PlaylistItemType, XtreamCluster, FieldGetAccessor, PlaylistEntry, TargetType, UserConnectionPermission, ProxyType}; #[derive(Serialize, Deserialize, Debug, Copy, Clone, Eq, PartialEq)] pub enum ApiStreamContext { diff --git a/backend/src/api/model/active_user_manager.rs b/backend/src/api/model/active_user_manager.rs index 942ad277f..35c1ebf60 100644 --- a/backend/src/api/model/active_user_manager.rs +++ b/backend/src/api/model/active_user_manager.rs @@ -1,5 +1,5 @@ use crate::model::Config; -use crate::model::{ProxyUserCredentials, UserConnectionPermission}; +use crate::model::{ProxyUserCredentials}; use crate::utils::request::sanitize_sensitive_info; use shared::utils::{current_time_secs, default_grace_period_millis, default_grace_period_timeout_secs}; use jsonwebtoken::get_current_timestamp; @@ -8,6 +8,7 @@ use std::collections::HashMap; use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; use tokio::sync::RwLock; +use shared::model::UserConnectionPermission; const USER_CON_TTL: u64 = 10_800; // 3 hours const USER_SESSION_LIMIT: usize = 50; diff --git a/backend/src/api/model/app_state.rs b/backend/src/api/model/app_state.rs index e9b5ec31f..190274b3f 100644 --- a/backend/src/api/model/app_state.rs +++ b/backend/src/api/model/app_state.rs @@ -1,10 +1,11 @@ use tokio::sync::{Mutex}; use std::sync::Arc; +use shared::model::UserConnectionPermission; use crate::api::model::active_provider_manager::ActiveProviderManager; use crate::api::model::active_user_manager::ActiveUserManager; use crate::api::model::download::DownloadQueue; use crate::api::model::streams::shared_stream_manager::SharedStreamManager; -use crate::model::{Config, UserConnectionPermission, HdHomeRunDeviceConfig}; +use crate::model::{Config, HdHomeRunDeviceConfig}; use crate::tools::lru_cache::LRUResourceCache; #[derive(Clone)] diff --git a/backend/src/api/model/config.rs b/backend/src/api/model/config.rs index 673f5e81f..5fe0597cb 100644 --- a/backend/src/api/model/config.rs +++ b/backend/src/api/model/config.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; use shared::model::ProcessingOrder; -use crate::model::{ApiProxyConfig, ConfigApi, InputType, LogConfig, MessagingConfig, ReverseProxyConfig, ScheduleConfig, VideoConfig, ConfigRename, ConfigSort, ConfigTargetOptions, TargetOutput, WebUiConfig, ProxyConfig, IpCheckConfig}; +use crate::model::{ApiProxyConfig, ConfigApi, InputType, LogConfig, MessagingConfig, ReverseProxyConfig, ScheduleConfig, VideoConfig, ConfigSort, WebUiConfig, ProxyConfig, IpCheckConfig, ConfigTargetOptions, TargetOutput, ConfigRename}; #[derive(Deserialize, Serialize, Debug, Clone)] pub struct ServerInputConfig { diff --git a/backend/src/api/model/xtream.rs b/backend/src/api/model/xtream.rs index fc5e0e508..e9f18ef92 100644 --- a/backend/src/api/model/xtream.rs +++ b/backend/src/api/model/xtream.rs @@ -1,6 +1,7 @@ -use crate::model::{ApiProxyServerInfo, ProxyUserCredentials, ProxyUserStatus}; +use crate::model::{ApiProxyServerInfo, ProxyUserCredentials}; use chrono::{Duration, Local}; use serde::{Deserialize, Serialize}; +use shared::model::ProxyUserStatus; use shared::utils::CONSTANTS; #[derive(Serialize, Deserialize, Clone)] diff --git a/backend/src/processing/processor/trakt.rs b/backend/src/processing/processor/trakt.rs index 7a8cf665e..4f180726a 100644 --- a/backend/src/processing/processor/trakt.rs +++ b/backend/src/processing/processor/trakt.rs @@ -3,9 +3,7 @@ use crate::model::{ConfigTarget, PlaylistGroup, PlaylistItem}; use shared::model::{FieldGetAccessor, FieldSetAccessor, XtreamCluster}; use crate::model::{TraktConfig, TraktContentType, TraktListConfig, TraktListItem, TraktMatchItem, TraktMatchResult}; use shared::error::TuliproxError; -use crate::utils::trakt::TraktClient; -use crate::utils::trakt::extract_year_from_title; -use crate::utils::trakt::normalize_title_for_matching; +use crate::utils::{TraktClient, extract_year_from_title, normalize_title_for_matching}; use crate::utils::{get_u32_from_serde_value}; use shared::utils::{CONSTANTS}; use crate::utils::{trace_if_enabled, with}; diff --git a/backend/src/repository/m3u_playlist_iterator.rs b/backend/src/repository/m3u_playlist_iterator.rs index aafff56ea..6fc40951e 100644 --- a/backend/src/repository/m3u_playlist_iterator.rs +++ b/backend/src/repository/m3u_playlist_iterator.rs @@ -1,9 +1,9 @@ use shared::error::info_err; use shared::error::{TuliproxError, TuliproxErrorKind}; -use crate::model::{ProxyType, ProxyUserCredentials}; -use crate::model::{Config, ConfigTarget, ConfigTargetOptions, TargetType}; +use crate::model::{ProxyUserCredentials}; +use crate::model::{Config, ConfigTarget, ConfigTargetOptions}; use crate::model::{M3uPlaylistItem}; -use shared::model::{PlaylistItemType, XtreamCluster}; +use shared::model::{PlaylistItemType, ProxyType, TargetType, XtreamCluster}; use crate::repository::indexed_document::IndexedDocumentIterator; use crate::repository::m3u_repository::m3u_get_file_paths; use crate::repository::storage::ensure_target_storage_path; diff --git a/backend/src/repository/user_repository.rs b/backend/src/repository/user_repository.rs index b3ab1fc9d..10bc3f095 100644 --- a/backend/src/repository/user_repository.rs +++ b/backend/src/repository/user_repository.rs @@ -1,6 +1,6 @@ -use crate::model::{ProxyType, ProxyUserCredentials, ProxyUserStatus, TargetUser}; -use crate::model::{Config, TargetType}; -use shared::model::XtreamCluster; +use crate::model::{ProxyUserCredentials, TargetUser}; +use crate::model::{Config}; +use shared::model::{ProxyType, ProxyUserStatus, TargetType, XtreamCluster}; use crate::model::{PlaylistBouquetDto, TargetBouquetDto}; use crate::model::PlaylistXtreamCategory; use crate::repository::bplustree::BPlusTree; diff --git a/backend/src/repository/xtream_playlist_iterator.rs b/backend/src/repository/xtream_playlist_iterator.rs index d42a71428..7fbda0bfc 100644 --- a/backend/src/repository/xtream_playlist_iterator.rs +++ b/backend/src/repository/xtream_playlist_iterator.rs @@ -1,10 +1,10 @@ use std::collections::HashSet; use log::error; -use shared::model::XtreamCluster; +use shared::model::{TargetType, XtreamCluster}; use shared::error::info_err; use shared::error::{TuliproxError, TuliproxErrorKind}; use crate::model::{ProxyUserCredentials}; -use crate::model::{Config, ConfigTarget, TargetType}; +use crate::model::{Config, ConfigTarget}; use crate::model::{XtreamPlaylistItem}; use crate::model::XtreamMappingOptions; use crate::repository::indexed_document::{IndexedDocumentIterator}; diff --git a/shared/src/model/config/api_proxy.rs b/shared/src/model/config/api_proxy.rs new file mode 100644 index 000000000..ac69e8244 --- /dev/null +++ b/shared/src/model/config/api_proxy.rs @@ -0,0 +1,30 @@ +use crate::model::{ProxyUserCredentialsDto}; + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct TargetUserDto { + pub target: String, + pub credentials: Vec, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub struct ApiProxyServerInfoDto { + pub name: String, + pub protocol: String, + pub host: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub port: Option, + pub timezone: String, + pub message: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub path: Option, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub struct ApiProxyConfigDto { + pub server: Vec, + pub user: Vec, + #[serde(default)] + pub use_user_db: bool, +} diff --git a/shared/src/model/config/api_user.rs b/shared/src/model/config/api_user.rs new file mode 100644 index 000000000..ae9375a7a --- /dev/null +++ b/shared/src/model/config/api_user.rs @@ -0,0 +1,204 @@ +use crate::utils::default_as_true; +use std::fmt::Display; +use std::str::FromStr; +use enum_iterator::Sequence; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use crate::create_tuliprox_error_result; +use crate::error::{TuliproxError, TuliproxErrorKind}; +use crate::model::{ClusterFlags, PlaylistItemType}; + +#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)] +pub enum UserConnectionPermission { + Exhausted, + Allowed, + GracePeriod, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ProxyType { + Reverse(Option), + Redirect, +} + +impl Default for ProxyType { + fn default() -> Self { + Self::Redirect + } +} + +impl ProxyType { + const REVERSE: &'static str = "reverse"; + const REDIRECT: &'static str = "redirect"; + + pub fn is_redirect(&self, item_type: PlaylistItemType) -> bool { + match self { + ProxyType::Reverse(Some(flags)) => { + if flags.is_empty() { + return false; + } + if flags.has_cluster(item_type) { + return false; + } + true + }, + ProxyType::Reverse(None) => false, + ProxyType::Redirect => true + } + } + + pub fn is_reverse(&self, item_type: PlaylistItemType) -> bool { + !self.is_redirect(item_type) + } +} + +impl Display for ProxyType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Reverse(force_redirect) => { + if let Some(force) = force_redirect { + write!(f, "{}{force:?}", Self::REVERSE) + } else { + write!(f, "{}", Self::REVERSE) + } + } + Self::Redirect => write!(f, "{}", Self::REDIRECT), + } + } +} + +impl FromStr for ProxyType { + type Err = TuliproxError; + + fn from_str(s: &str) -> Result { + if s == Self::REDIRECT { + return Ok(Self::Redirect); + } + if s == Self::REVERSE { + return Ok(Self::Reverse(None)); + } + + if s.starts_with(Self::REVERSE) { + let suffix = s.strip_prefix(Self::REVERSE).unwrap(); + if let Ok(force_redirect) = ClusterFlags::try_from(suffix) { + if force_redirect.has_full_flags() { + return Ok(ProxyType::Reverse(None)); + } + return Ok(Self::Reverse(Some(force_redirect))); + } + } + + create_tuliprox_error_result!(TuliproxErrorKind::Info, "Unknown ProxyType: {}", s) + } +} + +impl<'de> Deserialize<'de> for ProxyType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let raw: String = Deserialize::deserialize(deserializer)?; + if raw == ProxyType::REDIRECT { + return Ok(ProxyType::Redirect); + } else if raw.starts_with(ProxyType::REVERSE) { + return ProxyType::from_str(raw.as_str()).map_err(serde::de::Error::custom); + } + Err(serde::de::Error::custom("Unknown proxy type")) + } +} + +impl Serialize for ProxyType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match *self { + ProxyType::Redirect => serializer.serialize_str(ProxyType::REDIRECT), + ProxyType::Reverse(None) => serializer.serialize_str(ProxyType::REVERSE), + ProxyType::Reverse(Some(ref force_redirect)) => { + serializer.serialize_str(&format!("{}{}", ProxyType::REVERSE, force_redirect)) + }, + } + } +} + +#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, Sequence, PartialEq, Eq)] +pub enum ProxyUserStatus { + Active, // The account is in good standing and can stream content + Expired, // The account can no longer access content unless it is renewed. + Banned, // The account is temporarily or permanently disabled. Typically used for users who violate terms of service or abuse the system. + Trial, // The account is marked as a trial account. + Disabled, // The account is inactive or deliberately disabled by the administrator. + Pending, +} + + +impl Default for ProxyUserStatus { + fn default() -> Self { + Self::Active + } +} + +impl ProxyUserStatus { + const ACTIVE: &'static str = "Active"; + const EXPIRED: &'static str = "Expired"; + const BANNED: &'static str = "Banned"; + const TRIAL: &'static str = "Trial"; + const DISABLED: &'static str = "Disabled"; + const PENDING: &'static str = "Pending"; +} + +impl Display for ProxyUserStatus { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", match self { + Self::Active => Self::ACTIVE, + Self::Expired => Self::EXPIRED, + Self::Banned => Self::BANNED, + Self::Trial => Self::TRIAL, + Self::Disabled => Self::DISABLED, + Self::Pending => Self::PENDING, + }) + } +} + +impl FromStr for ProxyUserStatus { + type Err = TuliproxError; + + fn from_str(s: &str) -> Result { + match s { + Self::ACTIVE => Ok(Self::Active), + Self::EXPIRED => Ok(Self::Expired), + Self::BANNED => Ok(Self::Banned), + Self::TRIAL => Ok(Self::Trial), + Self::DISABLED => Ok(Self::Disabled), + Self::PENDING => Ok(Self::Pending), + _ => create_tuliprox_error_result!(TuliproxErrorKind::Info, "Unknown ProxyUserStatus: {}", s) + } + } +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub struct ProxyUserCredentialsDto { + pub username: String, + pub password: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub token: Option, + #[serde(default = "ProxyType::default")] + pub proxy: ProxyType, + #[serde(skip_serializing_if = "Option::is_none")] + pub server: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub epg_timeshift: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub created_at: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub exp_date: Option, + #[serde(default)] + pub max_connections: u32, + #[serde(skip_serializing_if = "Option::is_none")] + pub status: Option, + #[serde(default = "default_as_true")] + pub ui_enabled: bool, + #[serde(skip_serializing_if = "Option::is_none")] + pub comment: Option, +} diff --git a/shared/src/model/config/mod.rs b/shared/src/model/config/mod.rs index 90d9771ed..952db41ad 100644 --- a/shared/src/model/config/mod.rs +++ b/shared/src/model/config/mod.rs @@ -17,8 +17,13 @@ mod reverse_proxy; mod cache; mod rate_limit; mod proxy; +mod rename; +mod api_proxy; +mod api_user; pub use base::*; +pub use api_proxy::*; +pub use api_user::*; pub use web::*; pub use messaging::*; pub use hdhomerun::*; @@ -37,3 +42,4 @@ pub use rate_limit::*; pub use reverse_proxy::*; pub use proxy::*; pub use trakt::*; +pub use rename::*; diff --git a/shared/src/model/config/rename.rs b/shared/src/model/config/rename.rs new file mode 100644 index 000000000..a22f53f09 --- /dev/null +++ b/shared/src/model/config/rename.rs @@ -0,0 +1,9 @@ +use crate::model::ItemField; + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub struct ConfigRenameDto { + pub field: ItemField, + pub pattern: String, + pub new_name: String, +} \ No newline at end of file diff --git a/shared/src/model/config/source.rs b/shared/src/model/config/source.rs index 2945ef1b4..5ea4f181b 100644 --- a/shared/src/model/config/source.rs +++ b/shared/src/model/config/source.rs @@ -1,4 +1,4 @@ -use crate::model::{ConfigInputDto, ItemField}; +use crate::model::{ConfigInputDto}; use crate::model::config::target::ConfigTargetDto; @@ -17,14 +17,6 @@ pub struct PatternTemplateDto { pub placeholder: String, } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -#[serde(deny_unknown_fields)] -pub struct ConfigRenameDto { - pub field: ItemField, - pub pattern: String, - pub new_name: String, -} - #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[serde(deny_unknown_fields)] pub struct ConfigSourceDto { diff --git a/shared/src/model/config/target.rs b/shared/src/model/config/target.rs index 2707956a8..1d89c7e5b 100644 --- a/shared/src/model/config/target.rs +++ b/shared/src/model/config/target.rs @@ -1,5 +1,4 @@ -use crate::model::{ClusterFlags, ConfigSortDto, ProcessingOrder, StrmExportStyle, TargetType, TraktConfigDto}; -use crate::model::config::source::ConfigRenameDto; +use crate::model::{ClusterFlags, ConfigRenameDto, ConfigSortDto, 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)] #[serde(deny_unknown_fields)] From 3a0185b4f0363387939beaa72e175c58407afbfe Mon Sep 17 00:00:00 2001 From: euzu Date: Thu, 19 Jun 2025 17:32:29 +0200 Subject: [PATCH 7/9] build scripts adapted for modules build --- README.md | 8 ++++---- bin/build_lin.sh | 2 +- bin/build_win.sh | 2 +- docker/Dockerfile | 4 ++-- docker/debug/debug-entrypoint.sh | 2 +- shared/src/model/config/base.rs | 23 +++++++++++++++++++++++ 6 files changed, 32 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 8e9c9f96c..4b5ab75b3 100644 --- a/README.md +++ b/README.md @@ -1516,7 +1516,7 @@ Ease way to compile is a docker toolchain `cross` ```shell rust install cross -env RUSTFLAGS="--remap-path-prefix $HOME=~" cross build --release --target x86_64-unknown-linux-musl +env RUSTFLAGS="--remap-path-prefix $HOME=~" cross build -p tuliprox --release --target x86_64-unknown-linux-musl ``` #### Manual compile - install prerequisites @@ -1527,7 +1527,7 @@ rustup target add x86_64-unknown-linux-musl ``` #### Build statically linked binary ```shell -cargo build --target x86_64-unknown-linux-musl --release +cargo build -p tuliprox --target x86_64-unknown-linux-musl --release ``` #### Dockerize There is a Dockerfile in `docker` directory. @@ -1645,7 +1645,7 @@ rustup toolchain install stable-x86_64-pc-windows-gnu Compile it with: ```shell -cargo build --release --target x86_64-pc-windows-gnu +cargo build -p tuliprox --release --target x86_64-pc-windows-gnu ``` ### Cross compile for raspberry pi 2/3/4 @@ -1654,7 +1654,7 @@ Ease way to compile is a docker toolchain `cross` ```shell rust install cross -env RUSTFLAGS="--remap-path-prefix $HOME=~" cross build --release --target armv7-unknown-linux-musleabihf +env RUSTFLAGS="--remap-path-prefix $HOME=~" cross build -p tuliprox --release --target armv7-unknown-linux-musleabihf ``` # Different Scenarios diff --git a/bin/build_lin.sh b/bin/build_lin.sh index af29c19bf..a28d250d1 100755 --- a/bin/build_lin.sh +++ b/bin/build_lin.sh @@ -3,5 +3,5 @@ export RUSTFLAGS="--remap-path-prefix $HOME=~" if [ "$(uname)" != "Linux" ]; then cross build -p tuliprox --release --target --target x86_64-unknown-linux-gnu else - cargo build --release + cargo build -p tuliprox --release fi \ No newline at end of file diff --git a/bin/build_win.sh b/bin/build_win.sh index 779969809..84348b025 100755 --- a/bin/build_win.sh +++ b/bin/build_win.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash -env RUSTFLAGS="--remap-path-prefix $HOME=~" cargo build --release --target x86_64-pc-windows-gnu +env RUSTFLAGS="--remap-path-prefix $HOME=~" cargo build -p tuliprox --release --target x86_64-pc-windows-gnu # cross build, is only working with cargo clean # env RUSTFLAGS="--remap-path-prefix $HOME=~" cross build -p tuliprox --release --target x86_64-pc-windows-gnu diff --git a/docker/Dockerfile b/docker/Dockerfile index 8694890b6..06e00b346 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -29,11 +29,11 @@ COPY Cargo.toml Cargo.lock ./ # Create a dummy src/main.rs to build dependencies only RUN mkdir src && echo "fn main() {}" > src/main.rs -RUN cargo build --target $RUST_TARGET --release || true +RUN cargo build -p tuliprox --target $RUST_TARGET --release || true # Now copy the actual source code and build the project COPY . . -RUN cargo build --target $RUST_TARGET --release +RUN cargo build -p tuliprox --target $RUST_TARGET --release # ----------------------------------------------------------------- # Stage 2: Build the Node.js frontend diff --git a/docker/debug/debug-entrypoint.sh b/docker/debug/debug-entrypoint.sh index 15e6c6dbb..1254ea4be 100755 --- a/docker/debug/debug-entrypoint.sh +++ b/docker/debug/debug-entrypoint.sh @@ -11,7 +11,7 @@ LLDB_MAX_PORT=${LLDB_MAX_PORT:-10700} # --- Build Step --- # 1. Ensure the Rust binary is up-to-date. echo ">>> [debug-entrypoint] Ensuring the binary is up-to-date for target: ${RUST_TARGET}..." -cargo build --target "${RUST_TARGET}" +cargo build -p tuliprox --target "${RUST_TARGET}" # --- LLDB Server Start --- diff --git a/shared/src/model/config/base.rs b/shared/src/model/config/base.rs index 390b1de9c..b5d481b99 100644 --- a/shared/src/model/config/base.rs +++ b/shared/src/model/config/base.rs @@ -10,6 +10,7 @@ pub struct ConfigApiDto { pub web_root: String, } +#[allow(clippy::struct_excessive_bools)] #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] #[serde(deny_unknown_fields)] pub struct ConfigDto { @@ -54,3 +55,25 @@ pub struct ConfigDto { #[serde(default, skip_serializing_if = "Option::is_none")] pub ipcheck: Option, } + +impl ConfigDto { + pub fn is_valid(&self) -> bool { + if self.api.host.is_empty() { + return false; + } + + if let Some(video) = &self.video { + if let Some(download) = &video.download { + if let Some(episode_pattern) = &download.episode_pattern { + if !episode_pattern.is_empty() { + let re = regex::Regex::new(episode_pattern); + if re.is_err() { + return false; + } + } + } + } + } + true + } +} \ No newline at end of file From 5957dd01d6e6a65937f2676dd772d55ceba6cca7 Mon Sep 17 00:00:00 2001 From: euzu Date: Thu, 19 Jun 2025 17:48:42 +0200 Subject: [PATCH 8/9] config refactored for hot reload --- backend/src/api/endpoints/v1_api.rs | 3 +- .../api/model/streams/active_client_stream.rs | 3 +- backend/src/model/config/api_proxy.rs | 178 +----------------- backend/src/model/config/base.rs | 71 ------- backend/src/model/config/rate_limit.rs | 2 +- backend/src/utils/file/config_reader.rs | 3 +- backend/src/utils/network/xtream.rs | 4 +- 7 files changed, 11 insertions(+), 253 deletions(-) diff --git a/backend/src/api/endpoints/v1_api.rs b/backend/src/api/endpoints/v1_api.rs index 25684b3d1..a42119eea 100644 --- a/backend/src/api/endpoints/v1_api.rs +++ b/backend/src/api/endpoints/v1_api.rs @@ -9,7 +9,7 @@ use crate::auth::validator_admin; use shared::error::TuliproxError; use crate::model::{ConfigTarget, StatusCheck}; use crate::model::XtreamPlaylistItem; -use crate::model::{Config, ConfigDto, ConfigInput, ConfigInputOptions, ConfigSource, InputType}; +use crate::model::{Config, ConfigInput, ConfigInputOptions, ConfigSource, InputType}; use crate::model::{ApiProxyConfig, ApiProxyServerInfo, ProxyUserCredentials, TargetUser}; use crate::processing::processor::playlist; use crate::repository::user_repository::store_api_user; @@ -21,6 +21,7 @@ use log::error; use serde_json::json; use std::collections::{BTreeMap, HashSet}; use std::sync::Arc; +use shared::model::ConfigDto; fn intern_save_config_api_proxy(backup_dir: &str, api_proxy: &ApiProxyConfig, file_path: &str) -> Option { match utils::save_api_proxy(file_path, backup_dir, api_proxy) { diff --git a/backend/src/api/model/streams/active_client_stream.rs b/backend/src/api/model/streams/active_client_stream.rs index 5b62d36fc..87842e0cd 100644 --- a/backend/src/api/model/streams/active_client_stream.rs +++ b/backend/src/api/model/streams/active_client_stream.rs @@ -6,7 +6,7 @@ use crate::api::model::app_state::AppState; use crate::api::model::stream::BoxedProviderStream; use crate::api::model::stream_error::StreamError; use crate::api::model::streams::transport_stream_buffer::TransportStreamBuffer; -use crate::model::{ProxyUserCredentials, UserConnectionPermission}; +use crate::model::{ProxyUserCredentials}; use bytes::Bytes; use futures::Stream; use log::{error, info}; @@ -16,6 +16,7 @@ use std::sync::{Arc, Mutex}; use std::task::{Poll, Waker}; use crate::api::model::streams::timed_client_stream::TimedClientStream; use futures::{StreamExt}; +use shared::model::UserConnectionPermission; const INNER_STREAM: u8 = 0_u8; const GRACE_BLOCK_STREAM: u8 = 1_u8; diff --git a/backend/src/model/config/api_proxy.rs b/backend/src/model/config/api_proxy.rs index 29aeae7fc..e76b305a6 100644 --- a/backend/src/model/config/api_proxy.rs +++ b/backend/src/model/config/api_proxy.rs @@ -1,191 +1,17 @@ use crate::api::model::app_state::AppState; -use shared::error::{create_tuliprox_error_result, info_err, TuliproxError, TuliproxErrorKind}; +use shared::error::{info_err, TuliproxError, TuliproxErrorKind}; use crate::model::{Config}; use crate::repository::user_repository::{backup_api_user_db_file, get_api_user_db_path, load_api_user, merge_api_user}; use crate::utils::{save_api_proxy}; use shared::utils::{default_as_true}; use chrono::Local; -use enum_iterator::Sequence; use log::debug; use std::cmp::PartialEq; use std::collections::HashSet; -use std::fmt::Display; use std::fs; -use std::str::FromStr; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use shared::model::{PlaylistItemType, ClusterFlags}; +use shared::model::{ProxyType, ProxyUserStatus, UserConnectionPermission}; use crate::utils; -#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)] -pub enum UserConnectionPermission { - Exhausted, - Allowed, - GracePeriod, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ProxyType { - Reverse(Option), - Redirect, -} - -impl Default for ProxyType { - fn default() -> Self { - Self::Redirect - } -} - -impl ProxyType { - const REVERSE: &'static str = "reverse"; - const REDIRECT: &'static str = "redirect"; - - pub fn is_redirect(&self, item_type: PlaylistItemType) -> bool { - match self { - ProxyType::Reverse(Some(flags)) => { - if flags.is_empty() { - return false; - } - if flags.has_cluster(item_type) { - return false; - } - true - }, - ProxyType::Reverse(None) => false, - ProxyType::Redirect => true - } - } - - pub fn is_reverse(&self, item_type: PlaylistItemType) -> bool { - !self.is_redirect(item_type) - } -} - -impl Display for ProxyType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Reverse(force_redirect) => { - if let Some(force) = force_redirect { - write!(f, "{}{force:?}", Self::REVERSE) - } else { - write!(f, "{}", Self::REVERSE) - } - } - Self::Redirect => write!(f, "{}", Self::REDIRECT), - } - } -} - -impl FromStr for ProxyType { - type Err = TuliproxError; - - fn from_str(s: &str) -> Result { - if s == Self::REDIRECT { - return Ok(Self::Redirect); - } - if s == Self::REVERSE { - return Ok(Self::Reverse(None)); - } - - if s.starts_with(Self::REVERSE) { - let suffix = s.strip_prefix(Self::REVERSE).unwrap(); - if let Ok(force_redirect) = ClusterFlags::try_from(suffix) { - if force_redirect.has_full_flags() { - return Ok(ProxyType::Reverse(None)); - } - return Ok(Self::Reverse(Some(force_redirect))); - } - } - - create_tuliprox_error_result!(TuliproxErrorKind::Info, "Unknown ProxyType: {}", s) - } -} - -impl<'de> Deserialize<'de> for ProxyType { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let raw: String = Deserialize::deserialize(deserializer)?; - if raw == ProxyType::REDIRECT { - return Ok(ProxyType::Redirect); - } else if raw.starts_with(ProxyType::REVERSE) { - return ProxyType::from_str(raw.as_str()).map_err(serde::de::Error::custom); - } - Err(serde::de::Error::custom("Unknown proxy type")) - } -} - -impl Serialize for ProxyType { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match *self { - ProxyType::Redirect => serializer.serialize_str(ProxyType::REDIRECT), - ProxyType::Reverse(None) => serializer.serialize_str(ProxyType::REVERSE), - ProxyType::Reverse(Some(ref force_redirect)) => { - serializer.serialize_str(&format!("{}{}", ProxyType::REVERSE, force_redirect)) - }, - } - } -} - - -#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, Sequence, PartialEq, Eq)] -pub enum ProxyUserStatus { - Active, // The account is in good standing and can stream content - Expired, // The account can no longer access content unless it is renewed. - Banned, // The account is temporarily or permanently disabled. Typically used for users who violate terms of service or abuse the system. - Trial, // The account is marked as a trial account. - Disabled, // The account is inactive or deliberately disabled by the administrator. - Pending, -} - - -impl Default for ProxyUserStatus { - fn default() -> Self { - Self::Active - } -} - -impl ProxyUserStatus { - const ACTIVE: &'static str = "Active"; - const EXPIRED: &'static str = "Expired"; - const BANNED: &'static str = "Banned"; - const TRIAL: &'static str = "Trial"; - const DISABLED: &'static str = "Disabled"; - const PENDING: &'static str = "Pending"; -} - -impl Display for ProxyUserStatus { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", match self { - Self::Active => Self::ACTIVE, - Self::Expired => Self::EXPIRED, - Self::Banned => Self::BANNED, - Self::Trial => Self::TRIAL, - Self::Disabled => Self::DISABLED, - Self::Pending => Self::PENDING, - }) - } -} - -impl FromStr for ProxyUserStatus { - type Err = TuliproxError; - - fn from_str(s: &str) -> Result { - match s { - Self::ACTIVE => Ok(Self::Active), - Self::EXPIRED => Ok(Self::Expired), - Self::BANNED => Ok(Self::Banned), - Self::TRIAL => Ok(Self::Trial), - Self::DISABLED => Ok(Self::Disabled), - Self::PENDING => Ok(Self::Pending), - _ => create_tuliprox_error_result!(TuliproxErrorKind::Info, "Unknown ProxyUserStatus: {}", s) - } - } -} - #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[serde(deny_unknown_fields)] pub struct ProxyUserCredentials { diff --git a/backend/src/model/config/base.rs b/backend/src/model/config/base.rs index 750399ea6..e89ee66be 100644 --- a/backend/src/model/config/base.rs +++ b/backend/src/model/config/base.rs @@ -62,77 +62,6 @@ impl ConfigApi { } } -#[allow(clippy::struct_excessive_bools)] -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] -#[serde(deny_unknown_fields)] -pub struct ConfigDto { - #[serde(default)] - pub threads: u8, - pub api: ConfigApi, - #[serde(default)] - pub working_dir: String, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub backup_dir: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub user_config_dir: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub mapping_path: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub custom_stream_response_path: Option, - #[serde(default)] - pub user_access_control: bool, - #[serde(default = "default_connect_timeout_secs")] - pub connect_timeout_secs: u32, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub sleep_timer_mins: Option, - #[serde(default)] - pub config_hot_reload: bool, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub video: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub schedules: Option>, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub messaging: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub log: Option, - #[serde(default)] - pub update_on_boot: bool, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub web_ui: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub reverse_proxy: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub proxy: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub ipcheck: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub hdhomerun: Option, - -} - -impl ConfigDto { - pub fn is_valid(&self) -> bool { - if self.api.host.is_empty() { - return false; - } - - if let Some(video) = &self.video { - if let Some(download) = &video.download { - if let Some(episode_pattern) = &download.episode_pattern { - if !episode_pattern.is_empty() { - let re = regex::Regex::new(episode_pattern); - if re.is_err() { - return false; - } - } - } - } - } - true - } -} - - #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] #[serde(deny_unknown_fields)] pub struct Config { diff --git a/backend/src/model/config/rate_limit.rs b/backend/src/model/config/rate_limit.rs index d3ca7a9ba..c123239b5 100644 --- a/backend/src/model/config/rate_limit.rs +++ b/backend/src/model/config/rate_limit.rs @@ -14,7 +14,7 @@ impl RateLimitConfig { return Err(TuliproxError::new(TuliproxErrorKind::Info, "Rate limiter period can't be 0".to_string())); } if self.burst_size == 0 { - return Err(TuliproxError::new(TuliproxErrorKind::Info, "Rate limiter bust can't be 0".to_string())); + return Err(TuliproxError::new(TuliproxErrorKind::Info, "Rate limiter burst can't be 0".to_string())); } Ok(()) } diff --git a/backend/src/utils/file/config_reader.rs b/backend/src/utils/file/config_reader.rs index d0091a96a..650a07a8c 100644 --- a/backend/src/utils/file/config_reader.rs +++ b/backend/src/utils/file/config_reader.rs @@ -1,5 +1,5 @@ use crate::model::{ApiProxyConfig, SourcesConfig}; -use crate::model::{Config, ConfigDto}; +use crate::model::{Config}; use shared::error::{create_tuliprox_error, info_err, to_io_error, TuliproxError, TuliproxErrorKind}; use crate::utils::{open_file, EnvResolvingReader}; use crate::utils::{file_reader}; @@ -13,6 +13,7 @@ use std::fs::File; use std::io::{self, BufReader, Read}; use std::path::{PathBuf}; use std::sync::Arc; +use shared::model::ConfigDto; use crate::utils; enum EitherReader { diff --git a/backend/src/utils/network/xtream.rs b/backend/src/utils/network/xtream.rs index 63231b965..c07c623d0 100644 --- a/backend/src/utils/network/xtream.rs +++ b/backend/src/utils/network/xtream.rs @@ -1,5 +1,5 @@ use crate::model::ProxyUserCredentials; -use crate::model::{Config, ConfigInput, ConfigTarget, ProxyUserStatus}; +use crate::model::{Config, ConfigInput, ConfigTarget}; use crate::model::{PlaylistGroup, XtreamPlaylistItem}; use crate::processing::parser::xtream; use crate::repository::xtream_repository; @@ -15,7 +15,7 @@ use std::io::Error; use std::str::FromStr; use std::sync::Arc; use std::time::{SystemTime, UNIX_EPOCH}; -use shared::model::{MsgKind, PlaylistEntry, XtreamCluster}; +use shared::model::{MsgKind, PlaylistEntry, ProxyUserStatus, XtreamCluster}; use crate::messaging::{send_message}; #[inline] From 46e430cdd4b7889e4bef249ce50552b15771a4de Mon Sep 17 00:00:00 2001 From: euzu Date: Thu, 19 Jun 2025 17:49:02 +0200 Subject: [PATCH 9/9] config refactored for hot reload --- backend/src/model/config/stream.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/model/config/stream.rs b/backend/src/model/config/stream.rs index 51fe357dc..11bb86054 100644 --- a/backend/src/model/config/stream.rs +++ b/backend/src/model/config/stream.rs @@ -54,7 +54,7 @@ impl StreamConfig { if self.grace_period_millis > 0 { if self.grace_period_timeout_secs == 0 { - let triple_ms = self.grace_period_millis * 3; + let triple_ms = self.grace_period_millis.saturating_mul(3); self.grace_period_timeout_secs = std::cmp::max(1, triple_ms.div_ceil(1000)); } else if self.grace_period_millis / 1000 > self.grace_period_timeout_secs { return Err(info_err!(format!("Grace time period timeout {} sec should be more than grace time period {} ms", self.grace_period_timeout_secs, self.grace_period_millis)));