122 lines
No EOL
3.3 KiB
Rust
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())
|
|
} |