use crate::db::connection::Database;
use crate::remote::client::SubsonicClient;
use super::*;
#[derive(Debug, Default)]
pub struct Synced {
pub library: crate::remote::sync::SyncResult,
pub favourites: FavouriteSync,
pub playlists: crate::playlists::PlaylistSync,
pub history: crate::remote::history::HistorySync,
pub dsp: crate::remote::dsp_sync::DspSync,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Walk {
Always,
IfChanged,
}
static SYNCING: parking_lot::Mutex<()> = parking_lot::Mutex::new(());
pub(crate) fn hold_syncs() -> parking_lot::MutexGuard<'static, ()> {
SYNCING.lock()
}
pub fn sync_remote(
db: &Database,
client: &SubsonicClient,
walk: Walk,
url: &str,
username: &str,
progress: &(dyn Fn(crate::remote::sync::SyncProgress) + Sync),
) -> Result<Synced, crate::remote::sync::SyncError> {
use crate::remote::sync;
let running = sync::Running::enter(url);
let cancelled = || {
if running.cancel.load(std::sync::atomic::Ordering::Relaxed) {
Err(sync::SyncError::Cancelled)
} else {
Ok(())
}
};
let _one_at_a_time = SYNCING.lock();
cancelled()?;
let walked = sync::library_version(db, url);
let modified = client.library_modified(walked);
crate::remote::refusal::observe(client.auth(), &modified);
let version = modified
.inspect_err(|e| log::debug!("library version unavailable: {e}"))
.ok()
.flatten();
let library = if walk == Walk::IfChanged && version.is_some() && version == walked {
log::info!("library unchanged on the server; not walked");
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs() as i64;
sync::update_last_sync(db, url, username, now)?;
sync::SyncResult::default()
} else {
let library = sync::sync_library(db, client, url, username, progress, &running.cancel)
.inspect_err(|e| {
if let sync::SyncError::Subsonic(e) = e {
crate::remote::refusal::observe_error(client.auth(), e);
}
})?;
if library.is_complete()
&& let Some(version) = version
{
sync::set_library_version(db, url, username, version)?;
}
library
};
cancelled()?;
let favourites = reconcile_favourites(db, client);
cancelled()?;
let playlists = crate::playlists::reconcile_playlists(db, client, url, username);
cancelled()?;
let history = crate::remote::history::reconcile(db, client, url, username);
cancelled()?;
Ok(Synced {
library,
favourites,
playlists,
history,
dsp: crate::remote::dsp_sync::reconcile(db, client, url),
})
}