OneLauncher-Cracked/packages/core/src/api/cluster/sync.rs
2025-04-18 16:28:38 +02:00

122 lines
No EOL
3.3 KiB
Rust

use std::{collections::HashSet, path::PathBuf};
use onelauncher_entity::clusters;
use serde::Serialize;
use crate::{error::{DaoError, LauncherResult}, send_error, store::Dirs, utils::io};
use super::dao::{self, ClusterId};
#[onelauncher_macro::specta]
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub enum SyncAction {
Created,
Updated,
MissingDb,
MissingFs,
NoAction,
}
impl SyncAction {
#[must_use]
pub const fn is_missing(self) -> bool {
matches!(self, Self::MissingDb | Self::MissingFs)
}
}
/// Syncs all clusters in the database. Returns a list of cluster IDs that are missing.
#[tracing::instrument]
pub async fn sync_clusters() -> LauncherResult<Vec<ClusterId>> {
let clusters = dao::get_all_clusters().await?;
let mut missing_ids = Vec::new();
let mut checked_paths = HashSet::new();
for cluster in clusters {
if sync_cluster(&cluster)
.await
.map(SyncAction::is_missing)
.unwrap_or(false)
{
missing_ids.push(cluster.id);
let path = cluster.path.clone();
send_error!(
"cluster {} is missing from the filesystem",
path.clone()
);
}
checked_paths.insert(PathBuf::from(cluster.path));
}
// Check for clusters in the filesystem that are not in the database
// It iterates over the directories in the cluster directory
// and checks if they are in the database
let cluster_dir = Dirs::get_clusters_dir().await?;
if cluster_dir.exists() {
let mut stream = io::read_dir(cluster_dir).await?;
while let Ok(Some(entry)) = stream.next_entry().await {
let path = entry.path();
if !path.is_dir() || checked_paths.contains(&path) {
// Skip if it's not a directory or if we've already checked it
continue;
}
// We have a directory that is not in the database
if let Err(err) = sync_from_fs_to_db(&path).await {
tracing::error!("failed to sync cluster from fs to db: {}", err);
}
}
} else {
io::create_dir_all(cluster_dir).await?;
}
Ok(missing_ids)
}
/// Syncs the cluster with the database.
/// Checks if the cluster in the database exists and if the directory exists.
#[tracing::instrument]
pub async fn sync_cluster(cluster: &clusters::Model) -> LauncherResult<SyncAction> {
let path = PathBuf::from(cluster.path.clone());
if !path.exists() {
return Ok(SyncAction::MissingFs);
}
// TODO: sync packages
Ok(SyncAction::NoAction)
}
/// Syncs the cluster with the database.
/// Checks if the cluster in the database exists and if the directory exists.
#[tracing::instrument]
pub async fn sync_cluster_by_id(id: ClusterId) -> LauncherResult<SyncAction> {
let cluster = dao::get_cluster_by_id(id)
.await?
.ok_or(DaoError::NotFound)?;
sync_cluster(&cluster).await
}
/// Syncs the cluster with the database.
/// Checks if the cluster in the database exists and if the directory exists.
#[tracing::instrument]
pub async fn sync_cluster_by_path(path: &PathBuf) -> LauncherResult<SyncAction> {
let Some(cluster) = dao::get_cluster_by_path(path).await? else {
tracing::warn!("cluster with path {path:?} not found in database");
return Ok(SyncAction::MissingDb);
};
sync_cluster(&cluster).await
}
#[tracing::instrument]
async fn sync_from_fs_to_db(path: &PathBuf) -> LauncherResult<clusters::Model> {
// TODO: Create database entry from what can be inferred from the directory
Err(anyhow::anyhow!(
"TODO: failed to sync cluster from fs to db: {}",
path.display()
).into())
}