diff --git a/backend/src/api/api_utils.rs b/backend/src/api/api_utils.rs index daa48d35d..94f0f283b 100644 --- a/backend/src/api/api_utils.rs +++ b/backend/src/api/api_utils.rs @@ -1181,4 +1181,4 @@ pub async fn is_seek_request(cluster: XtreamCluster, req_headers: &HeaderMap) -> } } false -} +} \ No newline at end of file diff --git a/backend/src/api/endpoints/hdhomerun_api.rs b/backend/src/api/endpoints/hdhomerun_api.rs index cd972574b..95d5694dd 100644 --- a/backend/src/api/endpoints/hdhomerun_api.rs +++ b/backend/src/api/endpoints/hdhomerun_api.rs @@ -12,7 +12,7 @@ use log::{error, warn}; use serde::{Deserialize, Serialize}; use serde_json::json; use std::sync::Arc; -use shared::utils::get_string_from_serde_value; +use shared::utils::{concat_path, get_string_from_serde_value}; use crate::api::api_utils::try_unwrap_body; // https://info.hdhomerun.com/info/http_api @@ -173,8 +173,8 @@ fn create_device(app_state: &Arc) -> Option { firmware_version: device.firmware_version.to_string(), auth: String::new(), id: device.device_udn.to_string(), - lineup_url: format!("{device_url}/lineup.json"), - discover_url: format!("{device_url}/discover.json"), + lineup_url: concat_path(&device_url, "lineup.json"), + discover_url: concat_path(&device_url, "discover.json"), base_url: device_url, }) } else { diff --git a/backend/src/api/endpoints/m3u_api.rs b/backend/src/api/endpoints/m3u_api.rs index 433130cb6..b03005b09 100644 --- a/backend/src/api/endpoints/m3u_api.rs +++ b/backend/src/api/endpoints/m3u_api.rs @@ -20,7 +20,7 @@ use shared::model::{ FieldGetAccessor, PlaylistEntry, PlaylistItemType, TargetType, UserConnectionPermission, XtreamCluster, }; -use shared::utils::{extract_extension_from_url, sanitize_sensitive_info, HLS_EXT}; +use shared::utils::{concat_path, extract_extension_from_url, sanitize_sensitive_info, HLS_EXT}; use std::sync::Arc; async fn m3u_api(api_req: &UserApiRequest, app_state: &AppState) -> impl IntoResponse + Send { @@ -363,15 +363,15 @@ pub fn m3u_api_register() -> axum::Router> { [ (storage_const::M3U_STREAM_PATH, m3u_api_live_stream_alt), ( - format!("{}/live", storage_const::M3U_STREAM_PATH), + concat_path(storage_const::M3U_STREAM_PATH, "live"), m3u_api_live_stream ), ( - format!("{}/movie", storage_const::M3U_STREAM_PATH), + concat_path(storage_const::M3U_STREAM_PATH, "movie"), m3u_api_movie_stream ), ( - format!("{}/series", storage_const::M3U_STREAM_PATH), + concat_path(storage_const::M3U_STREAM_PATH, "series"), m3u_api_series_stream ) ] diff --git a/backend/src/api/endpoints/v1_api.rs b/backend/src/api/endpoints/v1_api.rs index 2bbf7207b..83946ed74 100644 --- a/backend/src/api/endpoints/v1_api.rs +++ b/backend/src/api/endpoints/v1_api.rs @@ -16,7 +16,7 @@ use log::error; use serde_json::json; use shared::error::TuliproxError; use shared::model::{ApiProxyConfigDto, ApiProxyServerInfoDto, ConfigDto, InputType, IpCheckDto, PlaylistRequest, PlaylistRequestType, StatusCheck, TargetUserDto, XtreamPlaylistItem}; -use shared::utils::sanitize_sensitive_info; +use shared::utils::{concat_path, sanitize_sensitive_info}; use std::collections::{BTreeMap, HashSet}; use std::sync::Arc; use crate::utils::prepare_sources_batch; @@ -349,5 +349,5 @@ pub fn v1_api_register(web_auth_enabled: bool, app_state: Arc, web_ui_ if config.web_ui.as_ref().is_none_or(|c| c.user_ui_enabled) { base_router = base_router.merge(user_api_register(app_state)); } - base_router.nest(&format!("{web_ui_path}/api/v1"), router) + base_router.nest(&concat_path(web_ui_path, "api/v1"), router) } diff --git a/backend/src/api/endpoints/web_index.rs b/backend/src/api/endpoints/web_index.rs index ce2b5b735..60c083135 100644 --- a/backend/src/api/endpoints/web_index.rs +++ b/backend/src/api/endpoints/web_index.rs @@ -6,7 +6,7 @@ use axum::response::IntoResponse; use log::error; use serde_json::json; use shared::model::{TokenResponse, UserCredential}; -use shared::utils::CONSTANTS; +use shared::utils::{concat_path, CONSTANTS}; use std::path::{Path, PathBuf}; use std::sync::Arc; use tower::Service; @@ -107,10 +107,10 @@ async fn index( match tokio::fs::read_to_string(&path).await { Ok(content) => { let mut new_content = CONSTANTS.re_base_href.replace_all(&content, |caps: ®ex::Captures| { - format!(r#"{}="/{web_ui_path}/{}""#, &caps[1], &caps[2]) + format!(r#"{}="/{}""#, &caps[1], concat_path(&web_ui_path, &caps[2]).trim_start_matches('/')) }).to_string(); - let base_href = format!(r#""#); + let base_href = format!(r#""#, web_ui_path.trim_matches('/')); if let Some(pos) = new_content.find("") { new_content.replace_range(pos..pos + 6, &base_href); } @@ -139,13 +139,13 @@ async fn index_config( if let Some(api) = json_data.get_mut("api") { if let Some(api_url) = api.get_mut("apiUrl") { if let Some(url) = api_url.as_str() { - let new_url = format!("/{web_ui_path}{url}"); + let new_url = concat_path(web_ui_path, url); *api_url = json!(new_url); } } if let Some(auth_url) = api.get_mut("authUrl") { if let Some(url) = auth_url.as_str() { - let new_url = format!("/{web_ui_path}{url}"); + let new_url = concat_path(web_ui_path, url); *auth_url = json!(new_url); } } @@ -177,12 +177,12 @@ pub fn index_register_without_path(web_dir_path: &Path) -> axum::Router axum::Router> { axum::Router::new() - .nest(&format!("{web_ui_path}/auth"), axum::Router::new() + .nest(&concat_path(web_ui_path, "auth"), axum::Router::new() .route("/token", axum::routing::post(token)) .route("/refresh", axum::routing::post(token_refresh))) .merge(axum::Router::new() - .route(&format!("{web_ui_path}/"), axum::routing::get(index)) - .route(&format!("{web_ui_path}/config.json"), axum::routing::get(index_config)) + .route(&format!("/{}/", web_ui_path.trim_matches('/')), axum::routing::get(index)) + .route(&concat_path(web_ui_path, "config.json"), axum::routing::get(index_config)) .fallback({ let mut serve_dir = tower_http::services::ServeDir::new(web_dir_path); let path_prefix = web_ui_path.to_string(); diff --git a/backend/src/api/endpoints/websocket_api.rs b/backend/src/api/endpoints/websocket_api.rs index dc15a1d3c..2eafa8edf 100644 --- a/backend/src/api/endpoints/websocket_api.rs +++ b/backend/src/api/endpoints/websocket_api.rs @@ -10,6 +10,7 @@ use axum::{ use log::{error, info}; use shared::model::{ProtocolHandler, ProtocolHandlerMemory, ProtocolMessage, UserRole, WsCloseCode, PROTOCOL_VERSION}; use std::sync::Arc; +use shared::utils::concat_path; // WebSocket upgrade handler async fn websocket_handler( @@ -32,12 +33,12 @@ async fn websocket_handler_auth( pub fn ws_api_register(web_auth_enabled: bool, web_ui_path: &str) -> axum::Router> { if web_auth_enabled { axum::Router::new().route( - &format!("{web_ui_path}/ws"), + &format!("/{}", concat_path(web_ui_path.trim_start_matches('/'), "ws")), axum::routing::get(websocket_handler_auth), ) } else { axum::Router::new().route( - &format!("{web_ui_path}/ws"), + &format!("/{}", concat_path(web_ui_path.trim_start_matches('/'), "ws")), axum::routing::get(websocket_handler), ) } diff --git a/backend/src/api/main_api.rs b/backend/src/api/main_api.rs index 2a1a5b809..dd38051f3 100644 --- a/backend/src/api/main_api.rs +++ b/backend/src/api/main_api.rs @@ -30,6 +30,7 @@ use std::path::PathBuf; use std::sync::Arc; use tokio_util::sync::CancellationToken; use tower_governor::key_extractor::SmartIpKeyExtractor; +use shared::utils::concat_path; fn get_web_dir_path(web_ui_enabled: bool, web_root: &str) -> Result { let web_dir = web_root.to_string(); @@ -275,11 +276,11 @@ pub async fn start_server( if web_ui_enabled { router = router .nest_service( - &format!("{web_ui_path}/static"), + &concat_path(&web_ui_path, "static"), tower_http::services::ServeDir::new(web_dir_path.join("static")), ) .nest_service( - &format!("{web_ui_path}/assets"), + &concat_path(&web_ui_path, "assets"), tower_http::services::ServeDir::new(web_dir_path.join("assets")), ) .merge(v1_api_register( diff --git a/shared/src/utils/request.rs b/shared/src/utils/request.rs index a75ffe8a1..b5173fa17 100644 --- a/shared/src/utils/request.rs +++ b/shared/src/utils/request.rs @@ -120,3 +120,10 @@ pub fn get_base_url_from_str(url: &str) -> Option { None } } + +pub fn concat_path(first: &str, second: &str) -> String { + let first = first.trim_end_matches('/'); + let second = second.trim_start_matches('/'); + + format!("{first}/{second}") +} \ No newline at end of file diff --git a/webui/index.html b/webui/index.html index 698f8da22..007ce8499 100644 --- a/webui/index.html +++ b/webui/index.html @@ -1,6 +1,7 @@ + @@ -8,9 +9,7 @@ - - Tuliprox diff --git a/webui/src/app/components/mod.rs b/webui/src/app/components/mod.rs index c900be5b0..b8e21133b 100644 --- a/webui/src/app/components/mod.rs +++ b/webui/src/app/components/mod.rs @@ -3,7 +3,6 @@ mod svg_icon; mod authentication; mod home; mod login; -mod preferences; mod input; mod menu_item; mod icon_button; @@ -46,7 +45,6 @@ pub use self::authentication::*; pub use self::login::*; pub use self::home::*; pub use self::sidebar::*; -pub use self::preferences::*; pub use self::dashboard::*; pub use self::breadcrumbs::*; pub use self::playlist::*; diff --git a/webui/src/app/components/preferences.rs b/webui/src/app/components/preferences.rs deleted file mode 100644 index f9788364e..000000000 --- a/webui/src/app/components/preferences.rs +++ /dev/null @@ -1,122 +0,0 @@ -use crate::app::components::AppIcon; -use crate::app::components::Panel; -use std::fmt; -use std::str::FromStr; -use wasm_bindgen::JsCast; -use yew::prelude::*; -use yew_i18n::use_translation; - -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -enum PrefPage { - Update, - User, - ApiServer, - MainConfig, - Status, -} - -impl fmt::Display for PrefPage { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let s = match self { - PrefPage::Update => "update", - PrefPage::User => "user", - PrefPage::ApiServer => "apiserver", - PrefPage::MainConfig => "mainconfig", - PrefPage::Status => "status", - }; - write!(f, "{s}") - } -} - -impl FromStr for PrefPage { - type Err = (); - - fn from_str(s: &str) -> Result { - match s { - "update" => Ok(PrefPage::Update), - "user" => Ok(PrefPage::User), - "apiserver" => Ok(PrefPage::ApiServer), - "mainconfig" => Ok(PrefPage::MainConfig), - "status" => Ok(PrefPage::Status), - _ => Err(()) - } - } -} - -struct SidebarAction { - page: PrefPage, - icon: &'static str, - label: &'static str, -} - -const SIDEBAR_ACTIONS: &[SidebarAction] = &[ - SidebarAction { page: PrefPage::Update, icon: "Refresh", label: "LABEL.REFRESH" }, - SidebarAction { page: PrefPage::User, icon: "User", label: "LABEL.USERS" }, - SidebarAction { page: PrefPage::ApiServer, icon: "ApiServer", label: "LABEL.PROXY" }, - SidebarAction { page: PrefPage::MainConfig, icon: "Config", label: "LABEL.CONFIG" }, - SidebarAction { page: PrefPage::Status, icon: "Status", label: "LABEL.STATUS" }, -]; - -#[function_component] -pub fn Preferences() -> Html { - let active_page = use_state(|| PrefPage::Update); - - let translation = use_translation(); - - let handle_sidebar_action = { - let active_page = active_page.clone(); - Callback::from(move |e: MouseEvent| { - if let Some(target) = e.target() { - if let Ok(element) = target.dyn_into::() { - if let Some(data_page) = element.get_attribute("data-page") { - if let Ok(page) = PrefPage::from_str(&data_page) { - active_page.set(page); - } - } - } - } - }) - }; - - html! { -
-
-
- { - SIDEBAR_ACTIONS.iter().map(|action| { - html! { -
- - -
- } - }).collect::>() - } -
-
- -
{"Update"}
-
- -
{"User"}
-
- -
{"Api"}
-
- -
{"MainConfig"}
-
- -
{"Status"}
-
-
-
-
- } -} \ No newline at end of file diff --git a/webui/src/app/mod.rs b/webui/src/app/mod.rs index 2207a9153..b17301866 100644 --- a/webui/src/app/mod.rs +++ b/webui/src/app/mod.rs @@ -12,7 +12,7 @@ use yew_i18n::I18nProvider; use yew::prelude::*; use yew_hooks::{use_async_with_options, UseAsyncOptions}; use yew_router::prelude::*; -use crate::app::components::{Authentication, Home, Login, Preferences}; +use crate::app::components::{Authentication, Home, Login}; use crate::error::Error; use crate::hooks::IconDefinition; use crate::model::WebConfig; @@ -50,8 +50,6 @@ fn flatten_json(value: &Value, prefix: String, map: &mut HashMap Html { match route { AppRoute::Login => html! {}, AppRoute::Home => html! {}, - AppRoute::Preferences => html! {}, AppRoute::NotFound => html! { "Page not found" }, } } diff --git a/webui/src/services/auth_service.rs b/webui/src/services/auth_service.rs index 3546edd69..9ff61a1bd 100644 --- a/webui/src/services/auth_service.rs +++ b/webui/src/services/auth_service.rs @@ -1,23 +1,25 @@ use std::cell::RefCell; -use super::request_post; +use super::{get_base_href, request_post}; use crate::error::Error; use crate::services::requests::set_token; use futures_signals::signal::Mutable; use futures_signals::signal::SignalExt; use shared::model::{TokenResponse, UserCredential}; use std::future::Future; +use shared::utils::concat_path; #[derive(Debug)] pub struct AuthService { + auth_path: String, username: RefCell, auth_channel: Mutable, } -const AUTH_PATH: &str = "/auth"; - impl AuthService { pub fn new() -> Self { + let base_href = get_base_href(); Self { + auth_path: format!("{base_href}auth"), username: RefCell::new(String::new()), auth_channel: Mutable::new(false), } @@ -47,7 +49,7 @@ impl AuthService { username, password, }; - match request_post::(&format!("{AUTH_PATH}/token"), credentials).await { + match request_post::(&concat_path(&self.auth_path, "token"), credentials).await { Ok(token) => { self.username.replace(token.username.to_string()); self.auth_channel.set(true); @@ -64,7 +66,7 @@ impl AuthService { } pub async fn refresh(&self) -> Result { - match request_post::<(), TokenResponse>(&format!("{AUTH_PATH}/refresh"), ()).await { + match request_post::<(), TokenResponse>(&concat_path(&self.auth_path, "refresh"), ()).await { Ok(token) => { self.username.replace(token.username.to_string()); self.auth_channel.set(true); diff --git a/webui/src/services/config_service.rs b/webui/src/services/config_service.rs index 47944759a..deeb58f27 100644 --- a/webui/src/services/config_service.rs +++ b/webui/src/services/config_service.rs @@ -1,5 +1,5 @@ use crate::model::WebConfig; -use crate::services::request_get; +use crate::services::{get_base_href, request_get}; use shared::model::{AppConfigDto, IpCheckDto}; use std::cell::RefCell; use std::future::Future; @@ -10,23 +10,25 @@ use futures_signals::signal::Mutable; use futures_signals::signal::SignalExt; use shared::foundation::filter::{get_filter, prepare_templates}; -const CONFIG_PATH: &str = "/api/v1/config"; -const IP_CHECK_PATH: &str = "/api/v1/ipinfo"; - pub struct ConfigService { pub ui_config: Rc, pub server_config: RefCell>>, config_channel: Mutable>>, is_fetching: AtomicBool, + config_path: String, + ip_check_path: String, } impl ConfigService { pub fn new(config: &WebConfig) -> Self { + let base_href = get_base_href(); Self { ui_config: Rc::new(config.clone()), server_config: RefCell::new(None), config_channel: Mutable::new(None), is_fetching: AtomicBool::new(false), + config_path: format!("{base_href}api/v1/config"), + ip_check_path: format!("{base_href}api/v1/ipinfo"), } } @@ -48,7 +50,7 @@ impl ConfigService { if self.is_fetching.swap(true, Ordering::SeqCst) { return; } - let result = match request_get::(CONFIG_PATH).await { + let result = match request_get::(&self.config_path).await { Ok(mut app_config) => { let templates = { if let Some(templ) = app_config.sources.templates.as_mut() { @@ -76,7 +78,7 @@ impl ConfigService { } pub async fn get_ip_info(&self) -> Option { - match request_get::(IP_CHECK_PATH).await { + match request_get::(&self.ip_check_path).await { Ok(cfg) => Some(cfg), Err(err) => { error!("{err}"); diff --git a/webui/src/services/playlist_service.rs b/webui/src/services/playlist_service.rs index 57c4d7d7c..313add5a9 100644 --- a/webui/src/services/playlist_service.rs +++ b/webui/src/services/playlist_service.rs @@ -1,12 +1,12 @@ -use crate::services::request_post; +use crate::services::{get_base_href, request_post}; use log::error; use shared::model::{PlaylistCategoriesResponse, PlaylistRequest, UiPlaylistCategories}; use std::rc::Rc; -const TARGET_UPDATE_API_PATH: &str = "/api/v1/playlist/update"; -const PLAYLIST_API_PATH: &str = "/api/v1/playlist"; - -pub struct PlaylistService {} +pub struct PlaylistService { + target_update_api_path: String, + playlist_api_path: String, +} impl Default for PlaylistService { fn default() -> Self { Self::new() @@ -15,18 +15,21 @@ impl Default for PlaylistService { impl PlaylistService { pub fn new() -> Self { - Self {} + let base_href = get_base_href(); + Self { + target_update_api_path: format!("{base_href}api/v1/playlist/update"), + playlist_api_path: format!("{base_href}api/v1/playlist"), + } } - pub async fn update_targets(&self, targets: &[&str]) -> bool { - request_post::<&[&str], ()>(TARGET_UPDATE_API_PATH, targets).await.map_or_else(|err| { + request_post::<&[&str], ()>(&self.target_update_api_path, targets).await.map_or_else(|err| { error!("{err}"); false }, |_| true) } pub async fn get_playlist_categories(&self, playlist_request: &PlaylistRequest) -> Option> { - request_post::<&PlaylistRequest, PlaylistCategoriesResponse>(PLAYLIST_API_PATH, playlist_request).await.map_or_else(|err| { + request_post::<&PlaylistRequest, PlaylistCategoriesResponse>(&self.playlist_api_path, playlist_request).await.map_or_else(|err| { error!("{err}"); None }, |response| Some(Rc::new(response.into()))) diff --git a/webui/src/services/requests.rs b/webui/src/services/requests.rs index 751229026..832384ace 100644 --- a/webui/src/services/requests.rs +++ b/webui/src/services/requests.rs @@ -1,18 +1,19 @@ -use gloo_storage::{LocalStorage, Storage}; use crate::error::{Error, ErrorInfo}; -use log::{error}; -use serde::{de::DeserializeOwned, Serialize}; +use gloo_storage::{LocalStorage, Storage}; +use log::error; use reqwasm::http::Request; +use serde::{de::DeserializeOwned, Serialize}; +use web_sys::window; enum RequestMethod { Get, Post, Put, // PATCH, - Delete + Delete, } -const API_ROOT: &str = "/api/v1"; +//const API_ROOT: &str = "/api/v1"; const TOKEN_KEY: &str = "tuliprox.token"; pub fn get_token() -> Option { @@ -36,9 +37,9 @@ where let mut request = match method { RequestMethod::Get => Request::get(url), RequestMethod::Post => Request::post(url).body(serde_json::to_string(&body).unwrap()), - RequestMethod::Put => Request::put(url).body(serde_json::to_string(&body).unwrap()), + RequestMethod::Put => Request::put(url).body(serde_json::to_string(&body).unwrap()), // RequestMethod::PATCH => Request::patch(&url).body(serde_json::to_string(&body).unwrap()), - RequestMethod::Delete => Request::delete(url), + RequestMethod::Delete => Request::delete(url), }.header("Content-Type", "application/json"); if let Some(token) = get_token() { request = request.header("Authorization", format!("Bearer {token}").as_str()); @@ -48,7 +49,7 @@ where match response.status() { 200 => { if std::any::TypeId::of::() == std::any::TypeId::of::<()>() { - // `T = ()` valid + // `T = ()` valid serde_json::from_str("null").map_err(|_| Error::DeserializeError) } else { let data: Result = response.json::().await; @@ -58,7 +59,7 @@ where Err(Error::DeserializeError) } } - }, + } 401 => Err(Error::Unauthorized), 403 => Err(Error::Forbidden), 404 => Err(Error::NotFound), @@ -97,12 +98,12 @@ where request(RequestMethod::Get, url, ()).await } -pub async fn request_get_api(url: &str) -> Result -where - T: DeserializeOwned + 'static + std::fmt::Debug, -{ - request(RequestMethod::Get, format!("{API_ROOT}{url}").as_str(), ()).await -} +// pub async fn request_get_api(url: &str) -> Result +// where +// T: DeserializeOwned + 'static + std::fmt::Debug, +// { +// request(RequestMethod::Get, format!("{API_ROOT}{url}").as_str(), ()).await +// } /// Post request with a body pub async fn request_post(url: &str, body: B) -> Result @@ -127,3 +128,17 @@ pub fn limit(count: u32, p: u32) -> String { let offset = if p > 0 { p * count } else { 0 }; format!("limit={count}&offset={offset}") } + +pub fn get_base_href() -> String { + let mut href = window() + .and_then(|w| w.document()) + .and_then(|doc| doc.query_selector("base").ok().flatten()) + .and_then(|base| base.get_attribute("href")) + .map_or_else(|| "/".to_owned(), |s| s.trim().to_owned()); + + if !href.ends_with('/') { + href.push('/'); + } + + href +} \ No newline at end of file diff --git a/webui/src/services/status_service.rs b/webui/src/services/status_service.rs index eaf6b342a..c5cc12a06 100644 --- a/webui/src/services/status_service.rs +++ b/webui/src/services/status_service.rs @@ -1,11 +1,10 @@ use std::rc::Rc; -use crate::services::request_get; +use crate::services::{get_base_href, request_get}; use shared::model::StatusCheck; -const STATUS_PATH: &str = "/api/v1/status"; - - -pub struct StatusService {} +pub struct StatusService { + status_path: String, +} impl Default for StatusService { fn default() -> Self { @@ -14,9 +13,14 @@ impl Default for StatusService { } impl StatusService { - pub fn new() -> Self { Self {} } + pub fn new() -> Self { + let base_href = get_base_href(); + Self { + status_path: format!("{base_href}api/v1/status"), + } + } pub async fn get_server_status(&self) -> Result, crate::error::Error> { - request_get::>(STATUS_PATH).await + request_get::>(&self.status_path).await } } \ No newline at end of file diff --git a/webui/src/services/websocket_service.rs b/webui/src/services/websocket_service.rs index 29c5c6a0a..af10d5760 100644 --- a/webui/src/services/websocket_service.rs +++ b/webui/src/services/websocket_service.rs @@ -7,26 +7,27 @@ use std::sync::atomic::{AtomicBool, Ordering}; use web_sys::js_sys::{Uint8Array, ArrayBuffer}; use log::{debug, error, trace}; use shared::model::{ProtocolMessage, PROTOCOL_VERSION}; +use shared::utils::concat_path; use crate::model::EventMessage; -use crate::services::{get_token, EventService, StatusService}; - -const WS_PATH: &str = "/ws"; - +use crate::services::{get_base_href, get_token, EventService, StatusService}; pub struct WebSocketService { connected: Rc, ws: Rc>>, status_service: Rc, - event_service: Rc + event_service: Rc, + ws_path: String, } impl WebSocketService { pub fn new(status_service: Rc, event_service: Rc) -> Self { + let base_href = get_base_href(); Self { connected: Rc::new(AtomicBool::new(false)), ws: Rc::new(RefCell::new(None)), status_service, event_service, + ws_path: concat_path(&base_href, "ws"), } } @@ -34,7 +35,7 @@ impl WebSocketService { if self.connected.load(Ordering::SeqCst) { return; } - match WebSocket::new(WS_PATH) { + match WebSocket::new(&self.ws_path) { Err(err) => error!("Failed to open websocket connection: {err:?}"), Ok(socket) => { socket.set_binary_type(web_sys::BinaryType::Arraybuffer);