diff --git a/src/models/streaming_server.rs b/src/models/streaming_server.rs index da5500564..15fed876e 100644 --- a/src/models/streaming_server.rs +++ b/src/models/streaming_server.rs @@ -7,8 +7,8 @@ use crate::runtime::msg::{ use crate::runtime::{Effect, EffectFuture, Effects, Env, EnvError, EnvFutureExt, UpdateWithCtx}; use crate::types::addon::ResourcePath; use crate::types::api::SuccessResponse; -use crate::types::profile::Profile; -use crate::types::streaming_server::Statistics; +use crate::types::profile::{AuthKey, Profile}; +use crate::types::streaming_server::{Settings, Statistics}; use enclose::enclose; use futures::{FutureExt, TryFutureExt}; use http::request::Request; @@ -18,21 +18,6 @@ use sha1::{Digest, Sha1}; use std::iter; use url::Url; -#[derive(Clone, PartialEq, Serialize, Deserialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct Settings { - pub app_path: String, - pub cache_root: String, - pub server_version: String, - pub cache_size: Option, - pub bt_max_connections: u64, - pub bt_handshake_timeout: u64, - pub bt_request_timeout: u64, - pub bt_download_speed_soft_limit: f64, - pub bt_download_speed_hard_limit: f64, - pub bt_min_peers_for_stable: u64, -} - #[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct PlaybackDevice { @@ -48,6 +33,14 @@ pub struct StatisticsRequest { pub file_idx: u16, } +#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct GetHTTPSResponse { + pub ip_address: String, + pub domain: String, + pub port: u16, +} + #[derive(Clone, Serialize, Debug)] #[serde(rename_all = "camelCase")] pub struct Selected { @@ -60,7 +53,8 @@ pub struct Selected { pub struct StreamingServer { pub selected: Selected, pub settings: Loadable, - pub base_url: Loadable, + pub base_url: Option, + pub remote_url: Option, pub playback_devices: Loadable, EnvError>, pub torrent: Option<(String, Loadable)>, pub statistics: Option>, @@ -70,7 +64,6 @@ impl StreamingServer { pub fn new(profile: &Profile) -> (Self, Effects) { let effects = Effects::many(vec![ get_settings::(&profile.settings.streaming_server_url), - get_base_url::(&profile.settings.streaming_server_url), get_playback_devices::(&profile.settings.streaming_server_url), ]); ( @@ -80,7 +73,8 @@ impl StreamingServer { statistics: None, }, settings: Loadable::Loading, - base_url: Loadable::Loading, + base_url: None, + remote_url: None, playback_devices: Loadable::Loading, torrent: None, statistics: None, @@ -95,24 +89,28 @@ impl UpdateWithCtx for StreamingServer { match msg { Msg::Action(Action::StreamingServer(ActionStreamingServer::Reload)) => { let settings_effects = eq_update(&mut self.settings, Loadable::Loading); - let base_url_effects = eq_update(&mut self.base_url, Loadable::Loading); + let base_url_effects = eq_update(&mut self.base_url, None); + let remote_url_effects = eq_update(&mut self.remote_url, None); Effects::many(vec![ get_settings::(&self.selected.transport_url), - get_base_url::(&self.selected.transport_url), get_playback_devices::(&self.selected.transport_url), ]) .unchanged() .join(settings_effects) .join(base_url_effects) + .join(remote_url_effects) } Msg::Action(Action::StreamingServer(ActionStreamingServer::UpdateSettings( settings, ))) if self.settings.is_ready() => { let settings_effects = eq_update(&mut self.settings, Loadable::Ready(settings.to_owned())); + let remote_url_effects = + update_remote_url::(&mut self.remote_url, &self.selected, settings, ctx); Effects::one(set_settings::(&self.selected.transport_url, settings)) .unchanged() .join(settings_effects) + .join(remote_url_effects) } Msg::Action(Action::StreamingServer(ActionStreamingServer::CreateTorrent( CreateTorrentArgs::Magnet(magnet), @@ -217,12 +215,12 @@ impl UpdateWithCtx for StreamingServer { statistics: None, }; self.settings = Loadable::Loading; - self.base_url = Loadable::Loading; + self.base_url = None; + self.remote_url = None; self.torrent = None; self.statistics = None; Effects::many(vec![ get_settings::(&self.selected.transport_url), - get_base_url::(&self.selected.transport_url), get_playback_devices::(&self.selected.transport_url), ]) } @@ -231,39 +229,30 @@ impl UpdateWithCtx for StreamingServer { { match result { Ok(settings) => { - eq_update(&mut self.settings, Loadable::Ready(settings.to_owned())) - } - Err(error) => { - let base_url_effects = - eq_update(&mut self.base_url, Loadable::Err(error.to_owned())); - let playback_devices_effects = - eq_update(&mut self.playback_devices, Loadable::Err(error.to_owned())); let settings_effects = - eq_update(&mut self.settings, Loadable::Err(error.to_owned())); - let torrent_effects = eq_update(&mut self.torrent, None); - base_url_effects - .join(playback_devices_effects) - .join(settings_effects) - .join(torrent_effects) - } - } - } - Msg::Internal(Internal::StreamingServerBaseURLResult(url, result)) - if self.selected.transport_url == *url && self.base_url.is_loading() => - { - match result { - Ok(base_url) => { - eq_update(&mut self.base_url, Loadable::Ready(base_url.to_owned())) + eq_update(&mut self.settings, Loadable::Ready(settings.to_owned())); + let base_url_effects = + eq_update(&mut self.base_url, Some(settings.base_url.to_owned())); + let remote_url_effects = update_remote_url::( + &mut self.remote_url, + &self.selected, + settings, + ctx, + ); + settings_effects + .join(base_url_effects) + .join(remote_url_effects) } Err(error) => { - let base_url_effects = - eq_update(&mut self.base_url, Loadable::Err(error.to_owned())); + let base_url_effects = eq_update(&mut self.base_url, None); + let remote_url_effects = eq_update(&mut self.remote_url, None); let playback_devices_effects = eq_update(&mut self.playback_devices, Loadable::Err(error.to_owned())); let settings_effects = eq_update(&mut self.settings, Loadable::Err(error.to_owned())); let torrent_effects = eq_update(&mut self.torrent, None); base_url_effects + .join(remote_url_effects) .join(playback_devices_effects) .join(settings_effects) .join(torrent_effects) @@ -279,14 +268,15 @@ impl UpdateWithCtx for StreamingServer { Loadable::Ready(playback_devices.to_owned()), ), Err(error) => { - let base_url_effects = - eq_update(&mut self.base_url, Loadable::Err(error.to_owned())); + let base_url_effects = eq_update(&mut self.base_url, None); + let remote_url_effects = eq_update(&mut self.remote_url, None); let playback_devices_effects = eq_update(&mut self.playback_devices, Loadable::Err(error.to_owned())); let settings_effects = eq_update(&mut self.settings, Loadable::Err(error.to_owned())); let torrent_effects = eq_update(&mut self.torrent, None); base_url_effects + .join(remote_url_effects) .join(playback_devices_effects) .join(settings_effects) .join(torrent_effects) @@ -299,12 +289,13 @@ impl UpdateWithCtx for StreamingServer { match result { Ok(_) => Effects::none().unchanged(), Err(error) => { - let base_url_effects = - eq_update(&mut self.base_url, Loadable::Err(error.to_owned())); + let base_url_effects = eq_update(&mut self.base_url, None); + let remote_url_effects = eq_update(&mut self.remote_url, None); let settings_effects = eq_update(&mut self.settings, Loadable::Err(error.to_owned())); let torrent_effects = eq_update(&mut self.torrent, None); base_url_effects + .join(remote_url_effects) .join(settings_effects) .join(torrent_effects) } @@ -331,6 +322,17 @@ impl UpdateWithCtx for StreamingServer { Err(_) => Effects::none().unchanged(), } } + Msg::Internal(Internal::StreamingServerGetHTTPSResult(url, result)) + if self.selected.transport_url == *url => + { + match result { + Ok(GetHTTPSResponse { domain, .. }) => { + let remote_url = Url::parse(&format!("https://{domain}")).ok(); + eq_update(&mut self.remote_url, remote_url) + } + Err(_) => Effects::none().unchanged(), + } + } Msg::Internal(Internal::StreamingServerCreateTorrentResult( loading_info_hash, result, @@ -357,17 +359,12 @@ impl UpdateWithCtx for StreamingServer { } fn get_settings(url: &Url) -> Effect { - #[derive(Deserialize)] - struct Resp { - values: Settings, - } let endpoint = url.join("settings").expect("url builder failed"); let request = Request::get(endpoint.as_str()) .body(()) .expect("request builder failed"); EffectFuture::Concurrent( - E::fetch::<_, Resp>(request) - .map_ok(|resp| resp.values) + E::fetch::<_, Settings>(request) .map(enclose!((url) move |result| { Msg::Internal(Internal::StreamingServerSettingsResult( url, result, @@ -378,27 +375,6 @@ fn get_settings(url: &Url) -> Effect { .into() } -fn get_base_url(url: &Url) -> Effect { - #[derive(Deserialize)] - struct Resp { - #[serde(rename = "baseUrl")] - base_url: Url, - } - let endpoint = url.join("settings").expect("url builder failed"); - let request = Request::get(endpoint.as_str()) - .body(()) - .expect("request builder failed"); - EffectFuture::Concurrent( - E::fetch::<_, Resp>(request) - .map_ok(|resp| resp.base_url) - .map(enclose!((url) move |result| - Msg::Internal(Internal::StreamingServerBaseURLResult(url, result)) - )) - .boxed_env(), - ) - .into() -} - fn get_playback_devices(url: &Url) -> Effect { let endpoint = url.join("casting").expect("url builder failed"); let request = Request::get(endpoint.as_str()) @@ -419,6 +395,7 @@ fn set_settings(url: &Url, settings: &Settings) -> Effect { #[derive(Serialize)] #[serde(rename_all = "camelCase")] struct Body { + remote_https: Option, cache_size: Option, bt_max_connections: u64, bt_handshake_timeout: u64, @@ -428,13 +405,14 @@ fn set_settings(url: &Url, settings: &Settings) -> Effect { bt_min_peers_for_stable: u64, } let body = Body { - cache_size: settings.cache_size.to_owned(), - bt_max_connections: settings.bt_max_connections.to_owned(), - bt_handshake_timeout: settings.bt_handshake_timeout.to_owned(), - bt_request_timeout: settings.bt_request_timeout.to_owned(), - bt_download_speed_soft_limit: settings.bt_download_speed_soft_limit.to_owned(), - bt_download_speed_hard_limit: settings.bt_download_speed_hard_limit.to_owned(), - bt_min_peers_for_stable: settings.bt_min_peers_for_stable.to_owned(), + remote_https: settings.values.remote_https.to_owned(), + cache_size: settings.values.cache_size.to_owned(), + bt_max_connections: settings.values.bt_max_connections.to_owned(), + bt_handshake_timeout: settings.values.bt_handshake_timeout.to_owned(), + bt_request_timeout: settings.values.bt_request_timeout.to_owned(), + bt_download_speed_soft_limit: settings.values.bt_download_speed_soft_limit.to_owned(), + bt_download_speed_hard_limit: settings.values.bt_download_speed_hard_limit.to_owned(), + bt_min_peers_for_stable: settings.values.bt_min_peers_for_stable.to_owned(), }; let endpoint = url.join("settings").expect("url builder failed"); let request = Request::post(endpoint.as_str()) @@ -626,3 +604,46 @@ fn play_on_device(url: &Url, args: &PlayOnDeviceArgs) -> Effec ) .into() } + +fn get_https_endpoint( + url: &Url, + auth_key: &AuthKey, + ip_address: &String, +) -> Effect { + let endpoint = url + .join(&format!( + "/get-https?authKey={:?}&ipAddress={}", + auth_key, ip_address, + )) + .expect("url builder failed"); + let request = Request::get(endpoint.as_str()) + .header(http::header::CONTENT_TYPE, "application/json") + .body(()) + .expect("request builder failed"); + EffectFuture::Concurrent( + E::fetch::<_, GetHTTPSResponse>(request) + .map(enclose!((url) move |result| + Msg::Internal(Internal::StreamingServerGetHTTPSResult(url, result)) + )) + .boxed_env(), + ) + .into() +} + +fn update_remote_url( + remote_url: &mut Option, + selected: &Selected, + settings: &Settings, + ctx: &Ctx, +) -> Effects { + match ( + settings.values.remote_https.as_ref(), + ctx.profile.auth_key(), + ) { + (Some(ip_address), Some(auth_key)) if ip_address.is_empty() => Effects::one( + get_https_endpoint::(&selected.transport_url, auth_key, ip_address), + ) + .unchanged(), + _ => eq_update(remote_url, None), + } +} diff --git a/src/runtime/msg/action.rs b/src/runtime/msg/action.rs index d9e413a86..5a0237312 100644 --- a/src/runtime/msg/action.rs +++ b/src/runtime/msg/action.rs @@ -13,10 +13,7 @@ use crate::{ library_with_filters::Selected as LibraryWithFiltersSelected, meta_details::Selected as MetaDetailsSelected, player::{Selected as PlayerSelected, VideoParams}, - streaming_server::{ - Settings as StreamingServerSettings, - StatisticsRequest as StreamingServerStatisticsRequest, - }, + streaming_server::StatisticsRequest as StreamingServerStatisticsRequest, }, types::{ addon::Descriptor, @@ -24,6 +21,7 @@ use crate::{ library::LibraryItemId, profile::Settings as ProfileSettings, resource::{MetaItemId, MetaItemPreview, Video}, + streaming_server::Settings as StreamingServerSettings, }, }; diff --git a/src/runtime/msg/internal.rs b/src/runtime/msg/internal.rs index 6849a1187..3aee08251 100644 --- a/src/runtime/msg/internal.rs +++ b/src/runtime/msg/internal.rs @@ -3,9 +3,7 @@ use url::Url; use crate::models::ctx::CtxError; use crate::models::link::LinkError; use crate::models::local_search::Searchable; -use crate::models::streaming_server::{ - PlaybackDevice, Settings as StreamingServerSettings, StatisticsRequest, -}; +use crate::models::streaming_server::{GetHTTPSResponse, PlaybackDevice, StatisticsRequest}; use crate::runtime::EnvError; use crate::types::addon::{Descriptor, Manifest, ResourceRequest, ResourceResponse}; use crate::types::api::{ @@ -15,7 +13,7 @@ use crate::types::api::{ use crate::types::library::{LibraryBucket, LibraryItem, LibraryItemId}; use crate::types::profile::{Auth, AuthKey, Profile, User}; use crate::types::resource::Stream; -use crate::types::streaming_server::Statistics; +use crate::types::streaming_server::{Settings as StreamingServerSettings, Statistics}; pub type CtxStorageResponse = ( Option, @@ -94,6 +92,8 @@ pub enum Internal { StreamingServerPlayOnDeviceResult(String, Result<(), EnvError>), // Result for streaming server statistics. StreamingServerStatisticsResult((Url, StatisticsRequest), Result), + // Result for get https endpoint request + StreamingServerGetHTTPSResult(Url, Result), /// Result for fetching resource from addons. ResourceRequestResult(ResourceRequest, Box>), /// Result for fetching manifest from addon. diff --git a/src/types/streaming_server/mod.rs b/src/types/streaming_server/mod.rs index dbf10aa51..55af229eb 100644 --- a/src/types/streaming_server/mod.rs +++ b/src/types/streaming_server/mod.rs @@ -1,2 +1,5 @@ +mod settings; +pub use settings::*; + mod statistics; pub use statistics::*; diff --git a/src/types/streaming_server/settings.rs b/src/types/streaming_server/settings.rs new file mode 100644 index 000000000..6e370062c --- /dev/null +++ b/src/types/streaming_server/settings.rs @@ -0,0 +1,48 @@ +use serde::{Deserialize, Serialize}; +use url::Url; + +#[derive(Clone, PartialEq, Serialize, Deserialize, Debug)] +#[serde(untagged)] +pub enum SettingsOptionSelectionValue { + String(String), + Number(u64), + Float(f64), +} + +#[derive(Clone, PartialEq, Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct SettingsOptionSelection { + pub name: String, + pub val: Option, +} + +#[derive(Clone, PartialEq, Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct SettingsOption { + pub id: String, + pub selections: Option>, +} + +#[derive(Clone, PartialEq, Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct SettingsValues { + pub app_path: String, + pub cache_root: String, + pub server_version: String, + pub remote_https: Option, + pub cache_size: Option, + pub bt_max_connections: u64, + pub bt_handshake_timeout: u64, + pub bt_request_timeout: u64, + pub bt_download_speed_soft_limit: f64, + pub bt_download_speed_hard_limit: f64, + pub bt_min_peers_for_stable: u64, +} + +#[derive(Clone, PartialEq, Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Settings { + pub base_url: Url, + pub values: SettingsValues, + pub options: Vec, +}