Skip to content

Commit f26f0d3

Browse files
committed
async backups
1 parent d841efc commit f26f0d3

5 files changed

Lines changed: 117 additions & 79 deletions

File tree

src/hooks/DTPlayLayer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ void DTPlayLayer::onExit(){
364364
if (lvlKey.isOk() && Settings::getAutoBackupEnabled() && Settings::getAutoBackupAtLvlExit()){
365365
auto metaRes = StatsManager::getMetadata(lvlKey.unwrap());
366366
if (metaRes.isOk() && metaRes.unwrap().autoBackup){
367-
(void)StatsManager::addBackup(
367+
StatsManager::addBackup(
368368
lvlKey.unwrap(),
369369
Settings::getAutoBackupGeneral(),
370370
Settings::getAutoBackupSessionAmount()

src/managers/StatsManager.cpp

Lines changed: 111 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ const std::string StatsManager::METADATA_FILE_NAME = "metadata";
4141
const std::string StatsManager::FROM0_FILE_NAME = "general.dt";
4242
const std::string StatsManager::SESSIONS_DIR_NAME = "sessions";
4343
const std::string StatsManager::BACKUPS_DIR_NAME = "backups";
44+
arc::TaskHandle<void> StatsManager::backupHandler{};
4445

4546
std::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

430471
void StatsManager::createFilesIfNeeded(const std::string& levelKey){

src/managers/StatsManager.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ class StatsManager {
2525
static const std::string SESSIONS_DIR_NAME;
2626
static const std::string BACKUPS_DIR_NAME;
2727

28+
static arc::TaskHandle<void> backupHandler;
29+
2830
public:
2931
StatsManager() = delete;
3032

@@ -61,7 +63,7 @@ class StatsManager {
6163
static Result<> setGeneral(const GeneralData& stats, const std::string& levelKey);
6264
// add a backup into the levels backups folder
6365
// sessionsToSave: how many sessions to save into the backup, -1 for all, nullopt for none
64-
static Result<> addBackup(const std::string& levelKey, bool saveLevelStats, std::optional<int> sessionsToSave);
66+
static void addBackup(const std::string& levelKey, bool saveLevelStats, std::optional<int> sessionsToSave, bool showNotifications = false);
6567

6668
static Result<std::set<long long>> getAllSessionTimesForLevel(GJGameLevel* const level);
6769
static std::set<long long> getAllSessionTimesForLevel(const std::string& levelKey);

src/nodes/layers/DTLayer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1062,7 +1062,7 @@ void DTLayer::keyBackClicked(){
10621062
void DTLayer::onClose(CCObject* sender){
10631063
if (m_MyLevelStats.isOk() && Settings::getAutoBackupEnabled() && Settings::getAutoBackupAtDTExit()){
10641064
if (m_MyLevelStats.unwrap().metadata.autoBackup){
1065-
(void)StatsManager::addBackup(
1065+
StatsManager::addBackup(
10661066
m_MyLevelStats.unwrap().levelKey,
10671067
Settings::getAutoBackupGeneral(),
10681068
Settings::getAutoBackupSessionAmount()

src/nodes/optionNodes/SaveOptions.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -262,12 +262,7 @@ void SaveOptions::onBackup(CCObject*){
262262

263263
auto popup = CreateBackupPopup::create();
264264
popup->setCallback([this](bool general, std::optional<int> sessions) {
265-
auto addBackupRes = StatsManager::addBackup(DTLayer::get()->m_MyLevelStats.unwrap().levelKey, general, sessions);
266-
if (addBackupRes.isErr()) {
267-
log::error("{}", addBackupRes.unwrapErr());
268-
Notification::create("Failed to create backup!", NotificationIcon::Error)->show();
269-
}
270-
else Notification::create("Created backup successfully!", NotificationIcon::Success)->show();
265+
StatsManager::addBackup(DTLayer::get()->m_MyLevelStats.unwrap().levelKey, general, sessions, true);
271266

272267
updateBackupsList();
273268
});

0 commit comments

Comments
 (0)