OneLauncher-Cracked/packages/oneclient_cluster/src/profiles.rs

165 lines
5.4 KiB
Rust

//! A profile is a sparse override on the global baseline a `None` field
//! inherits so `Patch::Clear` means "inherit again" not "set to nothing"
//! The baseline is passed in so this crate needn't depend on launcher config
use oneclient_common::patch::Patch;
use oneclient_db::DbPool;
use crate::error::{ClusterError, ClusterResult};
use crate::profile::{GameSettingsProfile, SettingsOsExtra};
use oneclient_common::Resolution;
use oneclient_common::domain::PackageUpdateMode;
#[tracing::instrument(level = "debug", skip(pool, global))]
pub async fn get_profile_or_default(
pool: &DbPool,
global: &GameSettingsProfile,
name: Option<&str>,
) -> ClusterResult<GameSettingsProfile> {
if let Some(name) = name
&& let Some(row) = oneclient_db::dao::setting_profile::get_by_name(pool, name).await?
{
return GameSettingsProfile::from_row(row);
}
Ok(global.clone())
}
#[tracing::instrument(level = "debug", skip(pool, global))]
/// Falls back to the whole baseline when the name is missing or unknown so a
/// deleted profile cannot brick a cluster
pub async fn resolve_cluster_profile(
pool: &DbPool,
global: &GameSettingsProfile,
profile_name: Option<&str>,
) -> ClusterResult<GameSettingsProfile> {
let Some(name) = profile_name else {
return Ok(global.clone());
};
let Some(row) = oneclient_db::dao::setting_profile::get_by_name(pool, name).await? else {
return Ok(global.clone());
};
let mut profile = GameSettingsProfile::from_row(row)?;
if !profile.is_global() {
profile.merge_global(global);
}
Ok(profile)
}
#[tracing::instrument(level = "debug", skip_all)]
pub async fn upsert_named_profile(
pool: &DbPool,
profile: &GameSettingsProfile,
) -> ClusterResult<GameSettingsProfile> {
if profile.is_global() {
return Err(ClusterError::InvalidProfile {
reason: "the Global profile is stored in settings.json".into(),
});
}
let row = profile.into_row()?;
let saved = oneclient_db::dao::setting_profile::upsert(pool, &row).await?;
GameSettingsProfile::from_row(saved)
}
#[tracing::instrument(level = "debug", skip(pool, global))]
pub async fn create_profile_from_global(
pool: &DbPool,
global: &GameSettingsProfile,
name: &str,
mem_max: Option<u32>,
force_fullscreen: Option<bool>,
) -> ClusterResult<GameSettingsProfile> {
let mut profile = global.clone();
profile.name = name.to_string();
profile.mem_max = mem_max;
if let Some(fullscreen) = force_fullscreen {
profile.force_fullscreen = Some(fullscreen);
}
upsert_named_profile(pool, &profile).await
}
#[tracing::instrument(level = "debug", skip(pool, global))]
pub async fn create_settings_profile(
pool: &DbPool,
global: &GameSettingsProfile,
name: &str,
) -> ClusterResult<GameSettingsProfile> {
create_profile_from_global(pool, global, name, None, None).await
}
#[tracing::instrument(level = "debug", skip(pool))]
pub async fn list_named_profiles(pool: &DbPool) -> ClusterResult<Vec<GameSettingsProfile>> {
let rows = oneclient_db::dao::setting_profile::list_all(pool).await?;
rows.into_iter()
.map(GameSettingsProfile::from_row)
.collect()
}
#[tracing::instrument(level = "debug", skip(pool))]
pub async fn delete_named_profile(pool: &DbPool, name: &str) -> ClusterResult<()> {
oneclient_db::dao::setting_profile::delete_by_name(pool, name).await?;
Ok(())
}
#[derive(Debug, Clone, Default)]
pub struct ProfileUpdate {
pub java_path: Patch<String>,
pub resolution: Patch<Resolution>,
pub force_fullscreen: Patch<bool>,
pub mem_max: Patch<u32>,
pub launch_args: Patch<String>,
pub launch_env: Patch<String>,
pub hook_pre: Patch<String>,
pub hook_wrapper: Patch<String>,
pub hook_post: Patch<String>,
pub os_extra: Patch<SettingsOsExtra>,
pub browser_update_mode: Patch<PackageUpdateMode>,
}
impl ProfileUpdate {
pub fn apply(&self, profile: &mut GameSettingsProfile) {
self.java_path.apply_to_option(&mut profile.java_path);
self.resolution.apply_to_option(&mut profile.resolution);
self.force_fullscreen
.apply_to_option(&mut profile.force_fullscreen);
self.mem_max.apply_to_option(&mut profile.mem_max);
self.launch_args
.apply_to_command_option(&mut profile.launch_args);
self.launch_env
.apply_to_command_option(&mut profile.launch_env);
self.hook_pre.apply_to_command_option(&mut profile.hook_pre);
self.hook_wrapper
.apply_to_command_option(&mut profile.hook_wrapper);
self.hook_post
.apply_to_command_option(&mut profile.hook_post);
self.os_extra.apply_to_option(&mut profile.os_extra);
self.browser_update_mode
.apply_to_option(&mut profile.browser_update_mode);
}
}
#[tracing::instrument(level = "debug", skip(pool, update))]
pub async fn update_named_profile(
pool: &DbPool,
name: &str,
update: ProfileUpdate,
) -> ClusterResult<GameSettingsProfile> {
let Some(row) = oneclient_db::dao::setting_profile::get_by_name(pool, name).await? else {
return Err(ClusterError::InvalidProfile {
reason: format!("profile '{name}' not found"),
});
};
let mut profile = GameSettingsProfile::from_row(row)?;
update.apply(&mut profile);
upsert_named_profile(pool, &profile).await
}