use super::{ThemeName, ThemeOverride};
use config::{Config, ConfigError, File, FileFormat};
use serde::Deserialize;
#[derive(Debug, Deserialize, Default, Clone)]
pub struct ThemeSettings {
#[serde(default)]
pub(super) name: ThemeName,
#[serde(default)]
pub(super) overrides: ThemeOverride,
}
#[derive(Debug, Deserialize)]
pub struct SchedulerSettings {
pub url: String,
}
#[cfg(not(target_arch = "wasm32"))]
#[derive(Debug, Deserialize)]
pub struct HttpSettings {
pub timeout: u64,
}
#[derive(Debug, Deserialize)]
pub struct Settings {
pub scheduler: SchedulerSettings,
#[cfg(not(target_arch = "wasm32"))]
pub http: HttpSettings,
pub data_reload_interval_ms: u64,
pub repaint_interval_ms: u64,
#[serde(default)]
pub theme: ThemeSettings,
}
const DEFAULT_CONFIG: &str = r#"
data_reload_interval_ms: 2000
repaint_interval_ms: 50
scheduler:
url: "http://localhost:50050"
http:
timeout: 2000
theme:
name: "dark"
"#;
impl Settings {
pub(crate) fn new() -> Result<Self, ConfigError> {
let builder = Config::builder()
.add_source(File::from_str(DEFAULT_CONFIG, FileFormat::Yaml));
#[cfg(all(feature = "web", not(feature = "tui")))]
let builder = builder.add_source(web::QueryString::parse());
#[cfg(all(feature = "tui", not(feature = "web")))]
let builder = {
use config::Environment;
let config_dir = dirs::config_local_dir()
.or_else(|| dirs::home_dir().map(|h| h.join(".config")))
.unwrap_or_else(|| std::path::PathBuf::from(".config"))
.join("ballista");
builder .add_source(
File::with_name(&format!("{}/tui", config_dir.display()))
.format(FileFormat::Yaml)
.required(false),
)
.add_source(Environment::with_prefix("BALLISTA").separator("__"))
};
let config = builder.build()?;
config.try_deserialize()
}
}
#[cfg(feature = "web")]
mod web {
use config::{File, FileFormat, FileSourceString};
#[derive(Debug, Clone)]
pub(super) struct QueryString;
impl QueryString {
pub(super) fn parse() -> File<FileSourceString, FileFormat> {
let mut data_reload_interval_ms = 2000;
let mut repaint_interval_ms = 50;
let mut scheduler_url = String::from("http://localhost:50050");
let mut http_timeout_ms = 2000;
let mut theme_name = String::from("dark");
let mut theme_app_background_bg = String::from("black");
let query_string = Self::decode_request();
query_string.split('&').for_each(|setting| {
let mut pair = setting.split('=');
if let (Some(key), Some(value)) = (pair.next(), pair.next()) {
match key {
"ballista_data_reload_interval_ms" => {
data_reload_interval_ms = value.parse::<u64>().unwrap_or(2000)
}
"ballista_repaint_interval_ms" => {
repaint_interval_ms = value.parse::<u64>().unwrap_or(50)
}
"ballista_scheduler_url" => {
scheduler_url = url_escape::decode(value).to_string()
}
"ballista_http_timeout" => {
http_timeout_ms = value.parse::<u64>().unwrap_or(2000)
}
"ballista_theme_name" => {
theme_name = url_escape::decode(value).to_string()
}
"ballista_theme_overrides_app_background_bg" => {
theme_app_background_bg =
url_escape::decode(value).to_string();
}
_ => {}
}
}
});
let config = format!(
r#"
data_reload_interval_ms: {data_reload_interval_ms}
repaint_interval_ms: {repaint_interval_ms}
scheduler:
url: {scheduler_url}
http:
timeout: {http_timeout_ms}
theme:
name: {theme_name}
overrides:
app_background:
bg: {theme_app_background_bg}
"#
);
tracing::info!("Using query string: {}", config);
File::from_str(&config, FileFormat::Yaml)
}
fn decode_request() -> std::string::String {
let window = web_sys::window().expect("no global `window` exists");
let document = window.document().expect("no global document exist");
let location = document.location().expect("no location exists");
let raw_search = location.search().expect("no search exists");
raw_search.trim_start_matches("?").to_string()
}
}
}