@@ -41,6 +41,7 @@ const std::string StatsManager::METADATA_FILE_NAME = "metadata";
4141const std::string StatsManager::FROM0_FILE_NAME = " general.dt" ;
4242const std::string StatsManager::SESSIONS_DIR_NAME = " sessions" ;
4343const std::string StatsManager::BACKUPS_DIR_NAME = " backups" ;
44+ arc::TaskHandle<void > StatsManager::backupHandler{};
4445
4546std::filesystem::path StatsManager::getSavesFolderPath (){
4647 return Settings::getSavePath ();
@@ -331,100 +332,140 @@ Result<> StatsManager::setGeneral(const GeneralData& stats, const std::string& l
331332 return Ok ();
332333}
333334
334- Result<> StatsManager::addBackup (const std::string& levelKey, bool saveLevelStats, std::optional<int > sessionsToSave){
335+ void StatsManager::addBackup (const std::string& levelKey, bool saveLevelStats, std::optional<int > sessionsToSave, bool showNotifications ){
335336 // log::info("adding backup for level {} | {} | {}", levelKey, saveLevelStats, sessionsToSave);
336- std::error_code ec;
337- auto metaRes = getMetadata (levelKey);
338- if (metaRes.isErr ()) return Err (" No level to back up! {}" , metaRes.unwrapErr ().error );
339- auto metadata = metaRes.unwrap ();
340-
341- createFilesIfNeeded (levelKey);
342337
343- auto levelBackupsFilePath = getSavesFolderPath () / levelKey / StatsManager::BACKUPS_DIR_NAME;
344-
345- auto lvlBackupsDirRes = geode::utils::file::createDirectory (levelBackupsFilePath);
346- if (lvlBackupsDirRes.isErr ()) return Err (" failed to create backups folder! {}" , lvlBackupsDirRes.unwrapErr ());
347-
348- auto currBackupName = StatsManager::getNowSeconds ();
338+ if (backupHandler.isValid ()){
339+ backupHandler.abort ();
340+ }
349341
350- levelBackupsFilePath /= std::to_string (currBackupName);
342+ auto progressFunc = [](float progress01){
343+ // maybe ill use this later for somethn idk bruh
344+ };
351345
352- auto lvlBackupDirRes = geode::utils::file::createDirectory (levelBackupsFilePath);
353- if (lvlBackupDirRes.isErr ()) return Err (" failed to create backup folder! {}" , lvlBackupDirRes.unwrapErr ());
346+ backupHandler = async::spawn (
347+ [levelKey, saveLevelStats, sessionsToSave, progressFunc]() -> arc::Future<Result<>> {
348+ std::error_code ec;
349+ progressFunc (0 .0f );
350+ auto metaRes = getMetadata (levelKey);
351+ if (metaRes.isErr ()) co_return Err (" No level to back up! {}" , metaRes.unwrapErr ().error );
352+ auto metadata = metaRes.unwrap ();
353+
354+ createFilesIfNeeded (levelKey);
355+ progressFunc (0 .1f );
354356
355- if (saveLevelStats){
357+ auto levelBackupsFilePath = getSavesFolderPath () / levelKey / StatsManager::BACKUPS_DIR_NAME;
356358
357- if ( getGeneral (levelKey). isErr ()){
358- ( void ) deleteBackup (levelKey, currBackupName );
359+ auto lvlBackupsDirRes = geode::utils::file::createDirectory (levelBackupsFilePath);
360+ if (lvlBackupsDirRes. isErr ()) co_return Err ( " failed to create backups folder! {} " , lvlBackupsDirRes. unwrapErr () );
359361
360- return Err (" backup failed! failed to read general stats" );
361- }
362+ auto currBackupName = StatsManager::getNowSeconds ();
362363
363- std::filesystem::copy_file (getSavesFolderPath () / levelKey / StatsManager::FROM0_FILE_NAME, levelBackupsFilePath / StatsManager::FROM0_FILE_NAME, std::filesystem::copy_options::overwrite_existing, ec);
364- if (ec) return Err (" Failed to backup level stats: {}" , ec.message ());
365- }
364+ levelBackupsFilePath /= std::to_string (currBackupName);
366365
367- auto backupsAmount = Settings::getMaxBackupAmount ();
366+ auto lvlBackupDirRes = geode::utils::file::createDirectory (levelBackupsFilePath);
367+ if (lvlBackupDirRes.isErr ()) co_return Err (" failed to create backup folder! {}" , lvlBackupDirRes.unwrapErr ());
368+ progressFunc (0 .2f );
368369
369- if (backupsAmount != std::nullopt ){
370- auto count = getBackupsCount (levelKey);
370+ if (saveLevelStats){
371371
372- if (count.size () > backupsAmount.value ()){
373- int index = 0 ;
374- for (const auto & backupName : count)
375- {
376- if (index == count.size () - backupsAmount.value ()) break ;
372+ if (getGeneral (levelKey).isErr ()){
373+ (void )deleteBackup (levelKey, currBackupName);
377374
378- (void )deleteBackup (levelKey, backupName);
375+ co_return Err (" backup failed! failed to read general stats" );
376+ }
379377
380- index++;
378+ std::filesystem::copy_file (getSavesFolderPath () / levelKey / StatsManager::FROM0_FILE_NAME, levelBackupsFilePath / StatsManager::FROM0_FILE_NAME, std::filesystem::copy_options::overwrite_existing, ec);
379+ if (ec) co_return Err (" Failed to backup level stats: {}" , ec.message ());
381380 }
382- }
383- }
384-
385- std::filesystem::copy_file (getSavesFolderPath () / levelKey / StatsManager::METADATA_FILE_NAME, levelBackupsFilePath / StatsManager::METADATA_FILE_NAME, std::filesystem::copy_options::overwrite_existing, ec);
386- if (ec) return Err (" Failed to backup level metadata: {}" , ec.message ());
381+ progressFunc (0 .35f );
387382
388- if (sessionsToSave == std:: nullopt ) return Ok ();
383+ auto backupsAmount = Settings::getMaxBackupAmount ();
389384
390- if (sessionsToSave. value () >= - 1 ){
391- levelBackupsFilePath /= StatsManager::SESSIONS_DIR_NAME ;
385+ if (backupsAmount != std:: nullopt ){
386+ auto count = getBackupsCount (levelKey) ;
392387
393- auto lvlBackupsDirRes = geode::utils::file::createDirectory (levelBackupsFilePath);
394- if (lvlBackupsDirRes.isErr ()) return Err (" failed to create backup sessions folder! {}" , lvlBackupsDirRes.unwrapErr ());
388+ if (count.size () > backupsAmount.value ()){
389+ int index = 0 ;
390+ for (const auto & backupName : count)
391+ {
392+ if (index == count.size () - backupsAmount.value ()) break ;
395393
396- std::set<long long , std::greater<long long >> sessionTimes{};
397- auto nonSorted = getAllSessionTimesForLevel (levelKey);
398- sessionTimes.insert (nonSorted.begin (), nonSorted.end ());
394+ (void )deleteBackup (levelKey, backupName);
399395
400- int numToSave = sessionsToSave.value ();
401- if (numToSave == -1 )
402- numToSave = sessionTimes.size ();
403-
404- int index = 0 ;
405- for (const auto & sessionTime : sessionTimes)
406- {
407- if (index == numToSave) break ;
396+ index++;
397+ }
398+ }
399+ }
400+ progressFunc (0 .5f );
408401
409- if (getSession (levelKey, sessionTime).isErr ()){
410- log::error (" Failed to backup session {}" , sessionTime);
402+ std::filesystem::copy_file (getSavesFolderPath () / levelKey / StatsManager::METADATA_FILE_NAME, levelBackupsFilePath / StatsManager::METADATA_FILE_NAME, std::filesystem::copy_options::overwrite_existing, ec);
403+ if (ec) co_return Err (" Failed to backup level metadata: {}" , ec.message ());
404+ progressFunc (0 .7f );
411405
412- continue ;
406+ if (sessionsToSave == std::nullopt ) {
407+ progressFunc (1 .0f );
408+ co_return Ok ();
413409 }
414410
415- std::filesystem::copy_file (
416- getSavesFolderPath () / levelKey / StatsManager::SESSIONS_DIR_NAME / (std::to_string (sessionTime) + " .dt" ),
417- levelBackupsFilePath / (std::to_string (sessionTime) + " .dt" ),
418- std::filesystem::copy_options::overwrite_existing,
419- ec
420- );
421- if (ec) return Err (" Failed to backup session {}: {}" , sessionTime, ec.message ());
422-
423- index++;
411+ if (sessionsToSave.value () >= -1 ){
412+ levelBackupsFilePath /= StatsManager::SESSIONS_DIR_NAME;
413+
414+ auto lvlBackupsDirRes = geode::utils::file::createDirectory (levelBackupsFilePath);
415+ if (lvlBackupsDirRes.isErr ()) co_return Err (" failed to create backup sessions folder! {}" , lvlBackupsDirRes.unwrapErr ());
416+
417+ std::set<long long , std::greater<long long >> sessionTimes{};
418+ auto nonSorted = getAllSessionTimesForLevel (levelKey);
419+ sessionTimes.insert (nonSorted.begin (), nonSorted.end ());
420+
421+ int numToSave = sessionsToSave.value ();
422+ if (numToSave == -1 )
423+ numToSave = sessionTimes.size ();
424+
425+ int index = 0 ;
426+ for (const auto & sessionTime : sessionTimes)
427+ {
428+ if (index == numToSave) break ;
429+
430+ if (getSession (levelKey, sessionTime).isErr ()){
431+ log::error (" Failed to backup session {}" , sessionTime);
432+ index++;
433+ continue ;
434+ }
435+
436+ std::filesystem::copy_file (
437+ getSavesFolderPath () / levelKey / StatsManager::SESSIONS_DIR_NAME / (std::to_string (sessionTime) + " .dt" ),
438+ levelBackupsFilePath / (std::to_string (sessionTime) + " .dt" ),
439+ std::filesystem::copy_options::overwrite_existing,
440+ ec
441+ );
442+ if (ec) co_return Err (" Failed to backup session {}: {}" , sessionTime, ec.message ());
443+
444+ index++;
445+ if (numToSave > 0 ) {
446+ float sessionProgress = 0 .7f + 0 .3f * (static_cast <float >(index) / static_cast <float >(numToSave));
447+ if (sessionProgress > 1 .0f ) sessionProgress = 1 .0f ;
448+ progressFunc (sessionProgress);
449+ }
450+ }
451+
452+ if (!sessionTimes.size ())
453+ progressFunc (1 .0f );
454+ }
455+ else progressFunc (1 .0f );
456+
457+ co_return Ok ();
458+ },
459+ [showNotifications](Result<> res){
460+ if (!showNotifications) return ;
461+
462+ if (res.isErr ()) {
463+ log::error (" {}" , res.unwrapErr ());
464+ Notification::create (" Failed to create backup!" , NotificationIcon::Error)->show ();
465+ }
466+ else Notification::create (" Created backup successfully!" , NotificationIcon::Success)->show ();
424467 }
425- }
426-
427- return Ok ();
468+ );
428469}
429470
430471void StatsManager::createFilesIfNeeded (const std::string& levelKey){
0 commit comments