replace progress box result from bool to Result. Display error box if progress box fails.

This commit is contained in:
ITotalJustice
2025-05-21 16:50:18 +01:00
parent 71415e5044
commit 654f3a1446
14 changed files with 308 additions and 432 deletions

View File

@@ -61,6 +61,9 @@ public:
static void NotifyClear(ui::NotifEntry::Side side = ui::NotifEntry::Side::RIGHT); static void NotifyClear(ui::NotifEntry::Side side = ui::NotifEntry::Side::RIGHT);
static void NotifyFlashLed(); static void NotifyFlashLed();
// if R_FAILED(rc), pushes error box. returns rc passed in.
static Result PushErrorBox(Result rc, const std::string& message);
static auto GetThemeMetaList() -> std::span<ThemeMeta>; static auto GetThemeMetaList() -> std::span<ThemeMeta>;
static void SetTheme(s64 theme_index); static void SetTheme(s64 theme_index);
static auto GetThemeIndex() -> s64; static auto GetThemeIndex() -> s64;

View File

@@ -8,15 +8,15 @@
namespace sphaira::ui { namespace sphaira::ui {
struct ProgressBox; struct ProgressBox;
using ProgressBoxCallback = std::function<bool(ProgressBox*)>; using ProgressBoxCallback = std::function<Result(ProgressBox*)>;
using ProgressBoxDoneCallback = std::function<void(bool success)>; using ProgressBoxDoneCallback = std::function<void(Result rc)>;
struct ProgressBox final : Widget { struct ProgressBox final : Widget {
ProgressBox( ProgressBox(
int image, int image,
const std::string& action, const std::string& action,
const std::string& title, const std::string& title,
ProgressBoxCallback callback, ProgressBoxDoneCallback done = [](bool success){}, ProgressBoxCallback callback, ProgressBoxDoneCallback done = [](Result rc){},
int cpuid = 1, int prio = 0x2C, int stack_size = 1024*128 int cpuid = 1, int prio = 0x2C, int stack_size = 1024*128
); );
~ProgressBox(); ~ProgressBox();
@@ -30,8 +30,10 @@ struct ProgressBox final : Widget {
// not const in order to avoid copy by using std::swap // not const in order to avoid copy by using std::swap
auto SetImageData(std::vector<u8>& data) -> ProgressBox&; auto SetImageData(std::vector<u8>& data) -> ProgressBox&;
auto SetImageDataConst(std::span<const u8> data) -> ProgressBox&; auto SetImageDataConst(std::span<const u8> data) -> ProgressBox&;
void RequestExit(); void RequestExit();
auto ShouldExit() -> bool; auto ShouldExit() -> bool;
auto ShouldExitResult() -> Result;
// helper functions // helper functions
auto CopyFile(const fs::FsPath& src, const fs::FsPath& dst) -> Result; auto CopyFile(const fs::FsPath& src, const fs::FsPath& dst) -> Result;
@@ -64,7 +66,7 @@ public:
struct ThreadData { struct ThreadData {
ProgressBox* pbox{}; ProgressBox* pbox{};
ProgressBoxCallback callback{}; ProgressBoxCallback callback{};
bool result{}; Result result{};
}; };
private: private:

View File

@@ -50,15 +50,17 @@ void download_default_music() {
curl::OnProgress{pbox->OnDownloadProgressCallback()} curl::OnProgress{pbox->OnDownloadProgressCallback()}
); );
return result.success; if (!result.success) {
}, [](bool success){ R_THROW(0x1);
if (success) { }
R_SUCCEED();
}, [](Result rc){
App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
if (R_SUCCEEDED(rc)) {
App::Notify("Downloaded "_i18n + "default_music.bfstm"); App::Notify("Downloaded "_i18n + "default_music.bfstm");
App::SetTheme(App::GetThemeIndex()); App::SetTheme(App::GetThemeIndex());
} else {
App::Push(std::make_shared<ui::ErrorBox>(
"Failed to download default_music.bfstm, please try again"_i18n
));
} }
})); }));
} }
@@ -568,6 +570,13 @@ void App::NotifyFlashLed() {
} }
} }
Result App::PushErrorBox(Result rc, const std::string& message) {
if (R_FAILED(rc)) {
App::Push(std::make_shared<ui::ErrorBox>(rc, message));
}
return rc;
}
auto App::GetThemeMetaList() -> std::span<ThemeMeta> { auto App::GetThemeMetaList() -> std::span<ThemeMeta> {
return g_app->m_theme_meta_entries; return g_app->m_theme_meta_entries;
} }
@@ -742,9 +751,10 @@ void App::SetReplaceHbmenuEnable(bool enable) {
if (R_FAILED(rc = fs.copy_entire_file("/hbmenu.nro", "/switch/hbmenu.nro"))) { if (R_FAILED(rc = fs.copy_entire_file("/hbmenu.nro", "/switch/hbmenu.nro"))) {
// try and restore sphaira in a last ditch effort. // try and restore sphaira in a last ditch effort.
if (R_FAILED(rc = fs.copy_entire_file("/hbmenu.nro", sphaira_path))) { if (R_FAILED(rc = fs.copy_entire_file("/hbmenu.nro", sphaira_path))) {
App::Push(std::make_shared<ui::ErrorBox>(rc, App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
App::PushErrorBox(rc,
"Failed to restore hbmenu, please re-download hbmenu"_i18n "Failed to restore hbmenu, please re-download hbmenu"_i18n
)); );
} else { } else {
App::Push(std::make_shared<ui::OptionBox>( App::Push(std::make_shared<ui::OptionBox>(
"Failed to restore hbmenu, using sphaira instead"_i18n, "Failed to restore hbmenu, using sphaira instead"_i18n,

View File

@@ -1012,8 +1012,8 @@ auto install_forwarder(ui::ProgressBox* pbox, OwoConfig& config, NcmStorageId st
} }
auto install_forwarder(OwoConfig& config, NcmStorageId storage_id) -> Result { auto install_forwarder(OwoConfig& config, NcmStorageId storage_id) -> Result {
App::Push(std::make_shared<ui::ProgressBox>(0, "Installing Forwarder"_i18n, config.name, [config, storage_id](auto pbox) mutable -> bool { App::Push(std::make_shared<ui::ProgressBox>(0, "Installing Forwarder"_i18n, config.name, [config, storage_id](auto pbox) mutable -> Result {
return R_SUCCEEDED(install_forwarder(pbox, config, storage_id)); return install_forwarder(pbox, config, storage_id);
})); }));
R_SUCCEED(); R_SUCCEED();
} }

View File

@@ -286,14 +286,12 @@ void ReadFromInfoJson(Entry& e) {
// this ignores ShouldExit() as leaving somthing in a half // this ignores ShouldExit() as leaving somthing in a half
// deleted state is a bad idea :) // deleted state is a bad idea :)
auto UninstallApp(ProgressBox* pbox, const Entry& entry) -> bool { auto UninstallApp(ProgressBox* pbox, const Entry& entry) -> Result {
const auto manifest = LoadAndParseManifest(entry); const auto manifest = LoadAndParseManifest(entry);
fs::FsNativeSd fs; fs::FsNativeSd fs;
if (manifest.empty()) { if (manifest.empty()) {
if (entry.binary.empty()) { R_UNLESS(!entry.binary.empty(), 0x1);
return false;
}
fs.DeleteFile(entry.binary); fs.DeleteFile(entry.binary);
} else { } else {
for (auto& e : manifest) { for (auto& e : manifest) {
@@ -319,7 +317,8 @@ auto UninstallApp(ProgressBox* pbox, const Entry& entry) -> bool {
} else { } else {
log_write("deleted: %s\n", dir.s); log_write("deleted: %s\n", dir.s);
} }
return true;
R_SUCCEED();
} }
// this is called by ProgressBox on a seperate thread // this is called by ProgressBox on a seperate thread
@@ -328,12 +327,12 @@ auto UninstallApp(ProgressBox* pbox, const Entry& entry) -> bool {
// 2. md5 check the zip // 2. md5 check the zip
// 3. parse manifest and unzip everything to placeholder // 3. parse manifest and unzip everything to placeholder
// 4. move everything from placeholder to normal location // 4. move everything from placeholder to normal location
auto InstallApp(ProgressBox* pbox, const Entry& entry) -> bool { auto InstallApp(ProgressBox* pbox, const Entry& entry) -> Result {
static const fs::FsPath zip_out{"/switch/sphaira/cache/appstore/temp.zip"}; static const fs::FsPath zip_out{"/switch/sphaira/cache/appstore/temp.zip"};
constexpr auto chunk_size = 1024 * 512; // 512KiB constexpr auto chunk_size = 1024 * 512; // 512KiB
fs::FsNativeSd fs; fs::FsNativeSd fs;
R_TRY_RESULT(fs.GetFsOpenResult(), false); R_TRY(fs.GetFsOpenResult());
// 1. download the zip // 1. download the zip
if (!pbox->ShouldExit()) { if (!pbox->ShouldExit()) {
@@ -341,14 +340,13 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> bool {
log_write("starting download\n"); log_write("starting download\n");
const auto url = BuildZipUrl(entry); const auto url = BuildZipUrl(entry);
if (!curl::Api().ToFile( const auto result = curl::Api().ToFile(
curl::Url{url}, curl::Url{url},
curl::Path{zip_out}, curl::Path{zip_out},
curl::OnProgress{pbox->OnDownloadProgressCallback()} curl::OnProgress{pbox->OnDownloadProgressCallback()}
).success) { );
log_write("error with download\n");
return false; R_UNLESS(result.success, 0x1);
}
} }
ON_SCOPE_EXIT(fs.DeleteFile(zip_out)); ON_SCOPE_EXIT(fs.DeleteFile(zip_out));
@@ -359,15 +357,11 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> bool {
log_write("starting md5 check\n"); log_write("starting md5 check\n");
FsFile f; FsFile f;
if (R_FAILED(fs.OpenFile(zip_out, FsOpenMode_Read, &f))) { R_TRY(fs.OpenFile(zip_out, FsOpenMode_Read, &f));
return false;
}
ON_SCOPE_EXIT(fsFileClose(&f)); ON_SCOPE_EXIT(fsFileClose(&f));
s64 size; s64 size;
if (R_FAILED(fsFileGetSize(&f, &size))) { R_TRY(fsFileGetSize(&f, &size));
return false;
}
mbedtls_md5_context ctx; mbedtls_md5_context ctx;
mbedtls_md5_init(&ctx); mbedtls_md5_init(&ctx);
@@ -380,19 +374,14 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> bool {
std::vector<u8> chunk(chunk_size); std::vector<u8> chunk(chunk_size);
s64 offset{}; s64 offset{};
while (offset < size) { while (offset < size) {
if (pbox->ShouldExit()) { R_TRY(pbox->ShouldExitResult());
return false;
}
u64 bytes_read; u64 bytes_read;
if (R_FAILED(fsFileRead(&f, offset, chunk.data(), chunk.size(), 0, &bytes_read))) { R_TRY(fsFileRead(&f, offset, chunk.data(), chunk.size(), 0, &bytes_read));
log_write("failed to read file offset: %zd size: %zd\n", offset, size);
return false;
}
if (mbedtls_md5_update_ret(&ctx, chunk.data(), bytes_read)) { if (mbedtls_md5_update_ret(&ctx, chunk.data(), bytes_read)) {
log_write("failed to update ret\n"); log_write("failed to update ret\n");
return false; R_THROW(0x1);
} }
offset += bytes_read; offset += bytes_read;
@@ -401,7 +390,7 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> bool {
u8 md5_out[16]; u8 md5_out[16];
if (mbedtls_md5_finish_ret(&ctx, (u8*)md5_out)) { if (mbedtls_md5_finish_ret(&ctx, (u8*)md5_out)) {
return false; R_THROW(0x1);
} }
// convert md5 to hex string // convert md5 to hex string
@@ -412,23 +401,20 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> bool {
if (strncasecmp(md5_str, entry.md5.data(), entry.md5.length())) { if (strncasecmp(md5_str, entry.md5.data(), entry.md5.length())) {
log_write("bad md5: %.*s vs %.*s\n", 32, md5_str, 32, entry.md5.c_str()); log_write("bad md5: %.*s vs %.*s\n", 32, md5_str, 32, entry.md5.c_str());
return false; R_THROW(0x1);
} }
} }
// 3. extract the zip // 3. extract the zip
if (!pbox->ShouldExit()) { if (!pbox->ShouldExit()) {
auto zfile = unzOpen64(zip_out); auto zfile = unzOpen64(zip_out);
if (!zfile) { R_UNLESS(zfile, 0x1);
log_write("failed to open zip: %s\n", zip_out.s);
return false;
}
ON_SCOPE_EXIT(unzClose(zfile)); ON_SCOPE_EXIT(unzClose(zfile));
// get manifest // get manifest
if (UNZ_END_OF_LIST_OF_FILE == unzLocateFile(zfile, "manifest.install", 0)) { if (UNZ_END_OF_LIST_OF_FILE == unzLocateFile(zfile, "manifest.install", 0)) {
log_write("failed to find manifest.install\n"); log_write("failed to find manifest.install\n");
return false; R_THROW(0x1);
} }
ManifestEntries new_manifest; ManifestEntries new_manifest;
@@ -436,47 +422,47 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> bool {
{ {
if (UNZ_OK != unzOpenCurrentFile(zfile)) { if (UNZ_OK != unzOpenCurrentFile(zfile)) {
log_write("failed to open current file\n"); log_write("failed to open current file\n");
return false; R_THROW(0x1);
} }
ON_SCOPE_EXIT(unzCloseCurrentFile(zfile)); ON_SCOPE_EXIT(unzCloseCurrentFile(zfile));
unz_file_info64 info; unz_file_info64 info;
if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &info, 0, 0, 0, 0, 0, 0)) { if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &info, 0, 0, 0, 0, 0, 0)) {
log_write("failed to get current info\n"); log_write("failed to get current info\n");
return false; R_THROW(0x1);
} }
std::vector<char> manifest_data(info.uncompressed_size); std::vector<char> manifest_data(info.uncompressed_size);
if ((int)info.uncompressed_size != unzReadCurrentFile(zfile, manifest_data.data(), manifest_data.size())) { if ((int)info.uncompressed_size != unzReadCurrentFile(zfile, manifest_data.data(), manifest_data.size())) {
log_write("failed to read manifest file\n"); log_write("failed to read manifest file\n");
return false; R_THROW(0x1);
} }
new_manifest = ParseManifest(manifest_data); new_manifest = ParseManifest(manifest_data);
if (new_manifest.empty()) { if (new_manifest.empty()) {
log_write("manifest is empty!\n"); log_write("manifest is empty!\n");
return false; R_THROW(0x1);
} }
} }
const auto unzip_to = [pbox, &fs, zfile](const fs::FsPath& inzip, fs::FsPath output) -> bool { const auto unzip_to = [pbox, &fs, zfile](const fs::FsPath& inzip, fs::FsPath output) -> Result {
pbox->NewTransfer(inzip); pbox->NewTransfer(inzip);
if (UNZ_END_OF_LIST_OF_FILE == unzLocateFile(zfile, inzip, 0)) { if (UNZ_END_OF_LIST_OF_FILE == unzLocateFile(zfile, inzip, 0)) {
log_write("failed to find %s\n", inzip.s); log_write("failed to find %s\n", inzip.s);
return false; R_THROW(0x1);
} }
if (UNZ_OK != unzOpenCurrentFile(zfile)) { if (UNZ_OK != unzOpenCurrentFile(zfile)) {
log_write("failed to open current file\n"); log_write("failed to open current file\n");
return false; R_THROW(0x1);
} }
ON_SCOPE_EXIT(unzCloseCurrentFile(zfile)); ON_SCOPE_EXIT(unzCloseCurrentFile(zfile));
unz_file_info64 info; unz_file_info64 info;
if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &info, 0, 0, 0, 0, 0, 0)) { if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &info, 0, 0, 0, 0, 0, 0)) {
log_write("failed to get current info\n"); log_write("failed to get current info\n");
return false; R_THROW(0x1);
} }
if (output[0] != '/') { if (output[0] != '/') {
@@ -489,58 +475,41 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> bool {
Result rc; Result rc;
if (R_FAILED(rc = fs.CreateFile(output, info.uncompressed_size, 0)) && rc != FsError_PathAlreadyExists) { if (R_FAILED(rc = fs.CreateFile(output, info.uncompressed_size, 0)) && rc != FsError_PathAlreadyExists) {
log_write("failed to create file: %s 0x%04X\n", output.s, rc); log_write("failed to create file: %s 0x%04X\n", output.s, rc);
return false; R_THROW(rc);
} }
FsFile f; FsFile f;
if (R_FAILED(rc = fs.OpenFile(output, FsOpenMode_Write, &f))) { R_TRY(fs.OpenFile(output, FsOpenMode_Write, &f));
log_write("failed to open file: %s 0x%04X\n", output.s, rc);
return false;
}
ON_SCOPE_EXIT(fsFileClose(&f)); ON_SCOPE_EXIT(fsFileClose(&f));
if (R_FAILED(rc = fsFileSetSize(&f, info.uncompressed_size))) { R_TRY(fsFileSetSize(&f, info.uncompressed_size));
log_write("failed to set file size: %s 0x%04X\n", output.s, rc);
return false;
}
std::vector<char> buf(chunk_size); std::vector<char> buf(chunk_size);
u64 offset{}; u64 offset{};
while (offset < info.uncompressed_size) { while (offset < info.uncompressed_size) {
if (pbox->ShouldExit()) { R_TRY(pbox->ShouldExitResult());
return false;
}
const auto bytes_read = unzReadCurrentFile(zfile, buf.data(), buf.size()); const auto bytes_read = unzReadCurrentFile(zfile, buf.data(), buf.size());
if (bytes_read <= 0) { if (bytes_read <= 0) {
log_write("failed to read zip file: %s\n", inzip.s); log_write("failed to read zip file: %s\n", inzip.s);
return false; R_THROW(0x1);
} }
if (R_FAILED(rc = fsFileWrite(&f, offset, buf.data(), bytes_read, FsWriteOption_None))) { R_TRY(fsFileWrite(&f, offset, buf.data(), bytes_read, FsWriteOption_None));
log_write("failed to write file: %s 0x%04X\n", output.s, rc);
return false;
}
pbox->UpdateTransfer(offset, info.uncompressed_size); pbox->UpdateTransfer(offset, info.uncompressed_size);
offset += bytes_read; offset += bytes_read;
} }
return true; R_SUCCEED();
}; };
// unzip manifest and info // unzip manifest and info
if (!unzip_to("info.json", BuildInfoCachePath(entry))) { R_TRY(unzip_to("info.json", BuildInfoCachePath(entry)));
return false; R_TRY(unzip_to("manifest.install", BuildManifestCachePath(entry)));
}
if (!unzip_to("manifest.install", BuildManifestCachePath(entry))) {
return false;
}
for (auto& new_entry : new_manifest) { for (auto& new_entry : new_manifest) {
if (pbox->ShouldExit()) { R_TRY(pbox->ShouldExitResult());
return false;
}
switch (new_entry.command) { switch (new_entry.command) {
case 'E': // both are the same? case 'E': // both are the same?
@@ -586,7 +555,7 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> bool {
} }
log_write("finished install :)\n"); log_write("finished install :)\n");
return true; R_SUCCEED();
} }
// case-insensitive version of str.find() // case-insensitive version of str.find()
@@ -775,27 +744,31 @@ void EntryMenu::UpdateOptions() {
const auto install = [this](){ const auto install = [this](){
App::Push(std::make_shared<ProgressBox>(m_entry.image.image, "Downloading "_i18n, m_entry.title, [this](auto pbox){ App::Push(std::make_shared<ProgressBox>(m_entry.image.image, "Downloading "_i18n, m_entry.title, [this](auto pbox){
return InstallApp(pbox, m_entry); return InstallApp(pbox, m_entry);
}, [this](bool success){ }, [this](Result rc){
if (success) { App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
if (R_SUCCEEDED(rc)) {
App::Notify("Downloaded "_i18n + m_entry.title); App::Notify("Downloaded "_i18n + m_entry.title);
m_entry.status = EntryStatus::Installed; m_entry.status = EntryStatus::Installed;
m_menu.SetDirty(); m_menu.SetDirty();
UpdateOptions(); UpdateOptions();
} }
}, 2)); }));
}; };
const auto uninstall = [this](){ const auto uninstall = [this](){
App::Push(std::make_shared<ProgressBox>(m_entry.image.image, "Uninstalling "_i18n, m_entry.title, [this](auto pbox){ App::Push(std::make_shared<ProgressBox>(m_entry.image.image, "Uninstalling "_i18n, m_entry.title, [this](auto pbox){
return UninstallApp(pbox, m_entry); return UninstallApp(pbox, m_entry);
}, [this](bool success){ }, [this](Result rc){
if (success) { App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
if (R_SUCCEEDED(rc)) {
App::Notify("Removed "_i18n + m_entry.title); App::Notify("Removed "_i18n + m_entry.title);
m_entry.status = EntryStatus::Get; m_entry.status = EntryStatus::Get;
m_menu.SetDirty(); m_menu.SetDirty();
UpdateOptions(); UpdateOptions();
} }
}, 2)); }));
}; };
const Option install_option{"Install"_i18n, install}; const Option install_option{"Install"_i18n, install};

View File

@@ -489,7 +489,7 @@ Menu::Menu(const std::vector<NroEntry>& nro_entries) : MenuBase{"FileBrowser"_i1
Scan(m_path); Scan(m_path);
} else { } else {
const auto msg = std::string("Failed to rename file: ") + entry.name; const auto msg = std::string("Failed to rename file: ") + entry.name;
App::Push(std::make_shared<ErrorBox>(rc, msg.c_str())); App::PushErrorBox(rc, msg);
} }
} }
})); }));
@@ -854,15 +854,13 @@ void Menu::InstallForwarder() {
if (op_index) { if (op_index) {
const auto assoc = assoc_list[*op_index]; const auto assoc = assoc_list[*op_index];
log_write("pushing it\n"); log_write("pushing it\n");
App::Push(std::make_shared<ProgressBox>(0, "Installing Forwarder"_i18n, GetEntry().name, [assoc, this](auto pbox) -> bool { App::Push(std::make_shared<ProgressBox>(0, "Installing Forwarder"_i18n, GetEntry().name, [assoc, this](auto pbox) -> Result {
log_write("inside callback\n"); log_write("inside callback\n");
NroEntry nro{}; NroEntry nro{};
log_write("parsing nro\n"); log_write("parsing nro\n");
if (R_FAILED(nro_parse(assoc.path, nro))) { R_TRY(nro_parse(assoc.path, nro));
log_write("failed nro parse\n");
return false;
}
log_write("got nro data\n"); log_write("got nro data\n");
auto file_name = assoc.use_base_name ? GetEntry().GetName() : GetEntry().GetInternalName(); auto file_name = assoc.use_base_name ? GetEntry().GetName() : GetEntry().GetInternalName();
@@ -883,7 +881,7 @@ void Menu::InstallForwarder() {
config.icon = GetRomIcon(m_fs.get(), pbox, file_name, db_indexs, nro); config.icon = GetRomIcon(m_fs.get(), pbox, file_name, db_indexs, nro);
pbox->SetImageDataConst(config.icon); pbox->SetImageDataConst(config.icon);
return R_SUCCEEDED(App::Install(pbox, config)); return App::Install(pbox, config);
})); }));
} else { } else {
log_write("pressed B to skip launch...\n"); log_write("pressed B to skip launch...\n");
@@ -899,19 +897,13 @@ void Menu::InstallFiles() {
if (op_index && *op_index) { if (op_index && *op_index) {
App::PopToMenu(); App::PopToMenu();
App::Push(std::make_shared<ui::ProgressBox>(0, "Installing "_i18n, "", [this, targets](auto pbox) mutable -> bool { App::Push(std::make_shared<ui::ProgressBox>(0, "Installing "_i18n, "", [this, targets](auto pbox) -> Result {
for (auto& e : targets) { for (auto& e : targets) {
const auto rc = yati::InstallFromFile(pbox, &m_fs->m_fs, GetNewPath(e)); R_TRY(yati::InstallFromFile(pbox, &m_fs->m_fs, GetNewPath(e)));
if (rc == yati::Result_Cancelled) { App::Notify("Installed " + e.GetName());
break;
} else if (R_FAILED(rc)) {
return false;
} else {
App::Notify("Installed " + e.GetName());
}
} }
return true; R_SUCCEED();
})); }));
} }
})); }));
@@ -925,7 +917,7 @@ void Menu::UnzipFiles(fs::FsPath dir_path) {
dir_path = m_path; dir_path = m_path;
} }
App::Push(std::make_shared<ui::ProgressBox>(0, "Extracting "_i18n, "", [this, dir_path, targets](auto pbox) mutable -> bool { App::Push(std::make_shared<ui::ProgressBox>(0, "Extracting "_i18n, "", [this, dir_path, targets](auto pbox) -> Result {
constexpr auto chunk_size = 1024 * 512; // 512KiB constexpr auto chunk_size = 1024 * 512; // 512KiB
auto& fs = *m_fs.get(); auto& fs = *m_fs.get();
@@ -934,28 +926,25 @@ void Menu::UnzipFiles(fs::FsPath dir_path) {
const auto zip_out = GetNewPath(e); const auto zip_out = GetNewPath(e);
auto zfile = unzOpen64(zip_out); auto zfile = unzOpen64(zip_out);
if (!zfile) { R_UNLESS(zfile, 0x1);
log_write("failed to open zip: %s\n", zip_out.s);
return false;
}
ON_SCOPE_EXIT(unzClose(zfile)); ON_SCOPE_EXIT(unzClose(zfile));
unz_global_info64 pglobal_info; unz_global_info64 pglobal_info;
if (UNZ_OK != unzGetGlobalInfo64(zfile, &pglobal_info)) { if (UNZ_OK != unzGetGlobalInfo64(zfile, &pglobal_info)) {
return false; R_THROW(0x1);
} }
for (int i = 0; i < pglobal_info.number_entry; i++) { for (int i = 0; i < pglobal_info.number_entry; i++) {
if (i > 0) { if (i > 0) {
if (UNZ_OK != unzGoToNextFile(zfile)) { if (UNZ_OK != unzGoToNextFile(zfile)) {
log_write("failed to unzGoToNextFile\n"); log_write("failed to unzGoToNextFile\n");
return false; R_THROW(0x1);
} }
} }
if (UNZ_OK != unzOpenCurrentFile(zfile)) { if (UNZ_OK != unzOpenCurrentFile(zfile)) {
log_write("failed to open current file\n"); log_write("failed to open current file\n");
return false; R_THROW(0x1);
} }
ON_SCOPE_EXIT(unzCloseCurrentFile(zfile)); ON_SCOPE_EXIT(unzCloseCurrentFile(zfile));
@@ -963,7 +952,7 @@ void Menu::UnzipFiles(fs::FsPath dir_path) {
char name[512]; char name[512];
if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &info, name, sizeof(name), 0, 0, 0, 0)) { if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &info, name, sizeof(name), 0, 0, 0, 0)) {
log_write("failed to get current info\n"); log_write("failed to get current info\n");
return false; R_THROW(0x1);
} }
const auto file_path = fs::AppendPath(dir_path, name); const auto file_path = fs::AppendPath(dir_path, name);
@@ -975,38 +964,27 @@ void Menu::UnzipFiles(fs::FsPath dir_path) {
Result rc; Result rc;
if (R_FAILED(rc = fs.CreateFile(file_path, info.uncompressed_size, 0)) && rc != FsError_PathAlreadyExists) { if (R_FAILED(rc = fs.CreateFile(file_path, info.uncompressed_size, 0)) && rc != FsError_PathAlreadyExists) {
log_write("failed to create file: %s 0x%04X\n", file_path.s, rc); log_write("failed to create file: %s 0x%04X\n", file_path.s, rc);
return false; R_THROW(rc);
} }
FsFile f; FsFile f;
if (R_FAILED(rc = fs.OpenFile(file_path, FsOpenMode_Write, &f))) { R_TRY(fs.OpenFile(file_path, FsOpenMode_Write, &f));
log_write("failed to open file: %s 0x%04X\n", file_path.s, rc);
return false;
}
ON_SCOPE_EXIT(fsFileClose(&f)); ON_SCOPE_EXIT(fsFileClose(&f));
if (R_FAILED(rc = fsFileSetSize(&f, info.uncompressed_size))) { R_TRY(fsFileSetSize(&f, info.uncompressed_size));
log_write("failed to set file size: %s 0x%04X\n", file_path.s, rc);
return false;
}
std::vector<char> buf(chunk_size); std::vector<char> buf(chunk_size);
s64 offset{}; s64 offset{};
while (offset < info.uncompressed_size) { while (offset < info.uncompressed_size) {
if (pbox->ShouldExit()) { R_TRY(pbox->ShouldExitResult());
return false;
}
const auto bytes_read = unzReadCurrentFile(zfile, buf.data(), buf.size()); const auto bytes_read = unzReadCurrentFile(zfile, buf.data(), buf.size());
if (bytes_read <= 0) { if (bytes_read <= 0) {
log_write("failed to read zip file: %s\n", name); log_write("failed to read zip file: %s\n", name);
return false; R_THROW(0x1);
} }
if (R_FAILED(rc = fsFileWrite(&f, offset, buf.data(), bytes_read, FsWriteOption_None))) { R_TRY(fsFileWrite(&f, offset, buf.data(), bytes_read, FsWriteOption_None));
log_write("failed to write file: %s 0x%04X\n", file_path.s, rc);
return false;
}
pbox->UpdateTransfer(offset, info.uncompressed_size); pbox->UpdateTransfer(offset, info.uncompressed_size);
offset += bytes_read; offset += bytes_read;
@@ -1014,13 +992,14 @@ void Menu::UnzipFiles(fs::FsPath dir_path) {
} }
} }
return true; R_SUCCEED();
}, [this](bool success){ }, [this](Result rc){
if (success) { App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
if (R_SUCCEEDED(rc)) {
App::Notify("Extract success!"); App::Notify("Extract success!");
} else {
App::Notify("Extract failed!");
} }
Scan(m_path); Scan(m_path);
log_write("did extract\n"); log_write("did extract\n");
})); }));
@@ -1062,7 +1041,7 @@ void Menu::ZipFiles(fs::FsPath zip_out) {
} }
} }
App::Push(std::make_shared<ui::ProgressBox>(0, "Compressing "_i18n, "", [this, zip_out, targets](auto pbox) mutable -> bool { App::Push(std::make_shared<ui::ProgressBox>(0, "Compressing "_i18n, "", [this, zip_out, targets](auto pbox) -> Result {
constexpr auto chunk_size = 1024 * 512; // 512KiB constexpr auto chunk_size = 1024 * 512; // 512KiB
auto& fs = *m_fs.get(); auto& fs = *m_fs.get();
@@ -1079,13 +1058,10 @@ void Menu::ZipFiles(fs::FsPath zip_out) {
zip_info.tmz_date.tm_year = tm->tm_year; zip_info.tmz_date.tm_year = tm->tm_year;
auto zfile = zipOpen(zip_out, APPEND_STATUS_CREATE); auto zfile = zipOpen(zip_out, APPEND_STATUS_CREATE);
if (!zfile) { R_UNLESS(zfile, 0x1);
log_write("failed to open zip: %s\n", zip_out.s);
return false;
}
ON_SCOPE_EXIT(zipClose(zfile, "sphaira v" APP_VERSION_HASH)); ON_SCOPE_EXIT(zipClose(zfile, "sphaira v" APP_VERSION_HASH));
const auto zip_add = [&](const fs::FsPath& file_path){ const auto zip_add = [&](const fs::FsPath& file_path) -> Result {
// the file name needs to be relative to the current directory. // the file name needs to be relative to the current directory.
const char* file_name_in_zip = file_path.s + std::strlen(m_path); const char* file_name_in_zip = file_path.s + std::strlen(m_path);
@@ -1100,56 +1076,42 @@ void Menu::ZipFiles(fs::FsPath zip_out) {
const auto raw = ext && IsExtension(ext + 1, COMPRESSED_EXTENSIONS); const auto raw = ext && IsExtension(ext + 1, COMPRESSED_EXTENSIONS);
if (ZIP_OK != zipOpenNewFileInZip2(zfile, file_name_in_zip, &zip_info, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION, raw)) { if (ZIP_OK != zipOpenNewFileInZip2(zfile, file_name_in_zip, &zip_info, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION, raw)) {
return false; R_THROW(0x1);
} }
ON_SCOPE_EXIT(zipCloseFileInZip(zfile)); ON_SCOPE_EXIT(zipCloseFileInZip(zfile));
FsFile f; FsFile f;
Result rc; R_TRY(fs.OpenFile(file_path, FsOpenMode_Read, &f));
if (R_FAILED(rc = fs.OpenFile(file_path, FsOpenMode_Read, &f))) {
log_write("failed to open file: %s 0x%04X\n", file_path.s, rc);
return false;
}
ON_SCOPE_EXIT(fsFileClose(&f)); ON_SCOPE_EXIT(fsFileClose(&f));
s64 file_size; s64 file_size;
if (R_FAILED(rc = fsFileGetSize(&f, &file_size))) { R_TRY(fsFileGetSize(&f, &file_size));
log_write("failed to get file size: %s 0x%04X\n", file_path.s, rc);
return false;
}
std::vector<char> buf(chunk_size); std::vector<char> buf(chunk_size);
s64 offset{}; s64 offset{};
while (offset < file_size) { while (offset < file_size) {
if (pbox->ShouldExit()) { R_TRY(pbox->ShouldExitResult());
return false;
}
u64 bytes_read; u64 bytes_read;
if (R_FAILED(rc = fsFileRead(&f, offset, buf.data(), buf.size(), FsReadOption_None, &bytes_read))) { R_TRY(fsFileRead(&f, offset, buf.data(), buf.size(), FsReadOption_None, &bytes_read));
log_write("failed to write file: %s 0x%04X\n", file_path.s, rc);
return false;
}
if (ZIP_OK != zipWriteInFileInZip(zfile, buf.data(), bytes_read)) { if (ZIP_OK != zipWriteInFileInZip(zfile, buf.data(), bytes_read)) {
log_write("failed to write zip file: %s\n", file_path.s); log_write("failed to write zip file: %s\n", file_path.s);
return false; R_THROW(0x1);
} }
pbox->UpdateTransfer(offset, file_size); pbox->UpdateTransfer(offset, file_size);
offset += bytes_read; offset += bytes_read;
} }
return true; R_SUCCEED();
}; };
for (auto& e : targets) { for (auto& e : targets) {
pbox->SetTitle(e.GetName()); pbox->SetTitle(e.GetName());
if (e.IsFile()) { if (e.IsFile()) {
const auto file_path = GetNewPath(e); const auto file_path = GetNewPath(e);
if (!zip_add(file_path)) { R_TRY(zip_add(file_path));
return false;
}
} else { } else {
FsDirCollections collections; FsDirCollections collections;
get_collections(GetNewPath(e), e.name, collections); get_collections(GetNewPath(e), e.name, collections);
@@ -1157,21 +1119,20 @@ void Menu::ZipFiles(fs::FsPath zip_out) {
for (const auto& collection : collections) { for (const auto& collection : collections) {
for (const auto& file : collection.files) { for (const auto& file : collection.files) {
const auto file_path = fs::AppendPath(collection.path, file.name); const auto file_path = fs::AppendPath(collection.path, file.name);
if (!zip_add(file_path)) { R_TRY(zip_add(file_path));
return false;
}
} }
} }
} }
} }
return true; R_SUCCEED();
}, [this](bool success){ }, [this](Result rc){
if (success) { App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
if (R_SUCCEEDED(rc)) {
App::Notify("Compress success!"); App::Notify("Compress success!");
} else {
App::Notify("Compress failed!");
} }
Scan(m_path); Scan(m_path);
log_write("did compress\n"); log_write("did compress\n");
})); }));
@@ -1198,7 +1159,7 @@ void Menu::UploadFiles() {
} }
const auto loc = network_locations[*op_index]; const auto loc = network_locations[*op_index];
App::Push(std::make_shared<ProgressBox>(0, "Uploading"_i18n, "", [this, loc](auto pbox) -> bool { App::Push(std::make_shared<ProgressBox>(0, "Uploading"_i18n, "", [this, loc](auto pbox) -> Result {
auto targets = GetSelectedEntries(); auto targets = GetSelectedEntries();
const auto file_add = [&](s64 file_size, const fs::FsPath& file_path, const char* name) -> Result { const auto file_add = [&](s64 file_size, const fs::FsPath& file_path, const char* name) -> Result {
@@ -1250,9 +1211,7 @@ void Menu::UploadFiles() {
for (auto& e : targets) { for (auto& e : targets) {
if (e.IsFile()) { if (e.IsFile()) {
const auto file_path = GetNewPath(e); const auto file_path = GetNewPath(e);
if (R_FAILED(file_add(e.file_size, file_path, e.GetName().c_str()))) { R_TRY(file_add(e.file_size, file_path, e.GetName().c_str()));
return false;
}
} else { } else {
FsDirCollections collections; FsDirCollections collections;
get_collections(GetNewPath(e), e.name, collections, true); get_collections(GetNewPath(e), e.name, collections, true);
@@ -1260,24 +1219,20 @@ void Menu::UploadFiles() {
for (const auto& collection : collections) { for (const auto& collection : collections) {
for (const auto& file : collection.files) { for (const auto& file : collection.files) {
const auto file_path = fs::AppendPath(collection.path, file.name); const auto file_path = fs::AppendPath(collection.path, file.name);
if (R_FAILED(file_add(file.file_size, file_path, file.name))) { R_TRY(file_add(file.file_size, file_path, file.name));
return false;
}
} }
} }
} }
} }
return true; R_SUCCEED();
}, [this](bool success){ }, [this](Result rc){
App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
ResetSelection(); ResetSelection();
if (success) { if (R_SUCCEEDED(rc)) {
App::Notify("Upload successfull!"); App::Notify("Upload successfull!");
log_write("Upload successfull!!!\n"); log_write("Upload successfull!!!\n");
} else {
App::Notify("Upload failed!");
log_write("Upload failed!!!\n");
} }
})); }));
} }
@@ -1643,80 +1598,70 @@ void Menu::OnDeleteCallback() {
Scan(m_path); Scan(m_path);
log_write("did delete\n"); log_write("did delete\n");
} else { } else {
App::Push(std::make_shared<ProgressBox>(0, "Deleting"_i18n, "", [this](auto pbox){ App::Push(std::make_shared<ProgressBox>(0, "Deleting"_i18n, "", [this](auto pbox) -> Result {
FsDirCollections collections; FsDirCollections collections;
// build list of dirs / files // build list of dirs / files
for (const auto&p : m_selected_files) { for (const auto&p : m_selected_files) {
pbox->Yield(); pbox->Yield();
if (pbox->ShouldExit()) { R_TRY(pbox->ShouldExitResult());
return false;
}
const auto full_path = GetNewPath(m_selected_path, p.name); const auto full_path = GetNewPath(m_selected_path, p.name);
if (p.IsDir()) { if (p.IsDir()) {
pbox->NewTransfer("Scanning "_i18n + full_path); pbox->NewTransfer("Scanning "_i18n + full_path);
if (R_FAILED(get_collections(full_path, p.name, collections))) { R_TRY(get_collections(full_path, p.name, collections));
log_write("failed to get dir collection: %s\n", full_path.s);
return false;
}
} }
} }
// delete everything in collections, reversed // delete everything in collections, reversed
for (const auto& c : std::views::reverse(collections)) { for (const auto& c : std::views::reverse(collections)) {
const auto delete_func = [&](auto& array) { const auto delete_func = [&](auto& array) -> Result {
for (const auto& p : array) { for (const auto& p : array) {
pbox->Yield(); pbox->Yield();
if (pbox->ShouldExit()) { R_TRY(pbox->ShouldExitResult());
return false;
}
const auto full_path = GetNewPath(c.path, p.name); const auto full_path = GetNewPath(c.path, p.name);
pbox->NewTransfer("Deleting "_i18n + full_path); pbox->NewTransfer("Deleting "_i18n + full_path);
if (p.type == FsDirEntryType_Dir) { if (p.type == FsDirEntryType_Dir) {
log_write("deleting dir: %s\n", full_path.s); log_write("deleting dir: %s\n", full_path.s);
m_fs->DeleteDirectory(full_path); R_TRY(m_fs->DeleteDirectory(full_path));
} else { } else {
log_write("deleting file: %s\n", full_path.s); log_write("deleting file: %s\n", full_path.s);
m_fs->DeleteFile(full_path); R_TRY(m_fs->DeleteFile(full_path));
} }
} }
return true;
R_SUCCEED();
}; };
if (!delete_func(c.files)) { R_TRY(delete_func(c.files));
return false; R_TRY(delete_func(c.dirs));
}
if (!delete_func(c.dirs)) {
return false;
}
} }
for (const auto& p : m_selected_files) { for (const auto& p : m_selected_files) {
pbox->Yield(); pbox->Yield();
if (pbox->ShouldExit()) { R_TRY(pbox->ShouldExitResult());
return false;
}
const auto full_path = GetNewPath(m_selected_path, p.name); const auto full_path = GetNewPath(m_selected_path, p.name);
pbox->NewTransfer("Deleting "_i18n + full_path); pbox->NewTransfer("Deleting "_i18n + full_path);
if (p.IsDir()) { if (p.IsDir()) {
log_write("deleting dir: %s\n", full_path.s); log_write("deleting dir: %s\n", full_path.s);
m_fs->DeleteDirectory(full_path); R_TRY(m_fs->DeleteDirectory(full_path));
} else { } else {
log_write("deleting file: %s\n", full_path.s); log_write("deleting file: %s\n", full_path.s);
m_fs->DeleteFile(full_path); R_TRY(m_fs->DeleteFile(full_path));
} }
} }
return true; R_SUCCEED();
}, [this](bool success){ }, [this](Result rc){
App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
ResetSelection(); ResetSelection();
Scan(m_path); Scan(m_path);
log_write("did delete\n"); log_write("did delete\n");
}, 2)); }));
} }
} }
@@ -1736,14 +1681,12 @@ void Menu::OnPasteCallback() {
Scan(m_path); Scan(m_path);
log_write("did paste\n"); log_write("did paste\n");
} else { } else {
App::Push(std::make_shared<ProgressBox>(0, "Pasting"_i18n, "", [this](auto pbox){ App::Push(std::make_shared<ProgressBox>(0, "Pasting"_i18n, "", [this](auto pbox) -> Result {
if (m_selected_type == SelectedType::Cut) { if (m_selected_type == SelectedType::Cut) {
for (const auto& p : m_selected_files) { for (const auto& p : m_selected_files) {
pbox->Yield(); pbox->Yield();
if (pbox->ShouldExit()) { R_TRY(pbox->ShouldExitResult());
return false;
}
const auto src_path = GetNewPath(m_selected_path, p.name); const auto src_path = GetNewPath(m_selected_path, p.name);
const auto dst_path = GetNewPath(m_path, p.name); const auto dst_path = GetNewPath(m_path, p.name);
@@ -1762,25 +1705,18 @@ void Menu::OnPasteCallback() {
// build list of dirs / files // build list of dirs / files
for (const auto&p : m_selected_files) { for (const auto&p : m_selected_files) {
pbox->Yield(); pbox->Yield();
if (pbox->ShouldExit()) { R_TRY(pbox->ShouldExitResult());
return false;
}
const auto full_path = GetNewPath(m_selected_path, p.name); const auto full_path = GetNewPath(m_selected_path, p.name);
if (p.IsDir()) { if (p.IsDir()) {
pbox->NewTransfer("Scanning "_i18n + full_path); pbox->NewTransfer("Scanning "_i18n + full_path);
if (R_FAILED(get_collections(full_path, p.name, collections))) { R_TRY(get_collections(full_path, p.name, collections));
log_write("failed to get dir collection: %s\n", full_path.s);
return false;
}
} }
} }
for (const auto& p : m_selected_files) { for (const auto& p : m_selected_files) {
pbox->Yield(); pbox->Yield();
if (pbox->ShouldExit()) { R_TRY(pbox->ShouldExitResult());
return false;
}
const auto src_path = GetNewPath(m_selected_path, p.name); const auto src_path = GetNewPath(m_selected_path, p.name);
const auto dst_path = GetNewPath(p); const auto dst_path = GetNewPath(p);
@@ -1790,7 +1726,7 @@ void Menu::OnPasteCallback() {
m_fs->CreateDirectory(dst_path); m_fs->CreateDirectory(dst_path);
} else { } else {
pbox->NewTransfer("Copying "_i18n + src_path); pbox->NewTransfer("Copying "_i18n + src_path);
R_TRY_RESULT(pbox->CopyFile(src_path, dst_path), false); R_TRY(pbox->CopyFile(src_path, dst_path));
} }
} }
@@ -1800,9 +1736,7 @@ void Menu::OnPasteCallback() {
for (const auto& p : c.dirs) { for (const auto& p : c.dirs) {
pbox->Yield(); pbox->Yield();
if (pbox->ShouldExit()) { R_TRY(pbox->ShouldExitResult());
return false;
}
const auto src_path = GetNewPath(c.path, p.name); const auto src_path = GetNewPath(c.path, p.name);
const auto dst_path = GetNewPath(base_dst_path, p.name); const auto dst_path = GetNewPath(base_dst_path, p.name);
@@ -1814,26 +1748,26 @@ void Menu::OnPasteCallback() {
for (const auto& p : c.files) { for (const auto& p : c.files) {
pbox->Yield(); pbox->Yield();
if (pbox->ShouldExit()) { R_TRY(pbox->ShouldExitResult());
return false;
}
const auto src_path = GetNewPath(c.path, p.name); const auto src_path = GetNewPath(c.path, p.name);
const auto dst_path = GetNewPath(base_dst_path, p.name); const auto dst_path = GetNewPath(base_dst_path, p.name);
pbox->NewTransfer("Copying "_i18n + src_path); pbox->NewTransfer("Copying "_i18n + src_path);
log_write("copying: %s to %s\n", src_path.s, dst_path.s); log_write("copying: %s to %s\n", src_path.s, dst_path.s);
R_TRY_RESULT(pbox->CopyFile(src_path, dst_path), false); R_TRY(pbox->CopyFile(src_path, dst_path));
} }
} }
} }
return true; R_SUCCEED();
}, [this](bool success){ }, [this](Result rc){
App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
ResetSelection(); ResetSelection();
Scan(m_path); Scan(m_path);
log_write("did paste\n"); log_write("did paste\n");
}, 2)); }));
} }
} }

View File

@@ -202,25 +202,25 @@ void Menu::Update(Controller* controller, TouchInfo* touch) {
log_write("set to progress\n"); log_write("set to progress\n");
m_state = State::Progress; m_state = State::Progress;
log_write("got connection\n"); log_write("got connection\n");
App::Push(std::make_shared<ui::ProgressBox>(0, "Installing "_i18n, "", [this](auto pbox) mutable -> bool { App::Push(std::make_shared<ui::ProgressBox>(0, "Installing "_i18n, "", [this](auto pbox) -> Result {
log_write("inside progress box\n"); log_write("inside progress box\n");
const auto rc = yati::InstallFromSource(pbox, m_source, m_source->m_path); const auto rc = yati::InstallFromSource(pbox, m_source, m_source->m_path);
if (R_FAILED(rc)) { if (R_FAILED(rc)) {
m_source->Disable(); m_source->Disable();
return false; R_THROW(rc);
} }
log_write("progress box is done\n"); R_SUCCEED();
return true; }, [this](Result rc){
}, [this](bool result){ App::PushErrorBox(rc, "Ftp install failed!"_i18n);
mutexLock(&m_mutex); mutexLock(&m_mutex);
ON_SCOPE_EXIT(mutexUnlock(&m_mutex)); ON_SCOPE_EXIT(mutexUnlock(&m_mutex));
if (result) { if (R_SUCCEEDED(rc)) {
App::Notify("Ftp install success!"_i18n); App::Notify("Ftp install success!"_i18n);
m_state = State::Done; m_state = State::Done;
} else { } else {
App::Notify("Ftp install failed!"_i18n);
m_state = State::Failed; m_state = State::Failed;
} }
})); }));

View File

@@ -1361,7 +1361,7 @@ void Menu::OnLayoutChange() {
} }
void Menu::DeleteGames() { void Menu::DeleteGames() {
App::Push(std::make_shared<ProgressBox>(0, "Deleting"_i18n, "", [this](auto pbox) -> bool { App::Push(std::make_shared<ProgressBox>(0, "Deleting"_i18n, "", [this](auto pbox) -> Result {
auto targets = GetSelectedEntries(); auto targets = GetSelectedEntries();
for (s64 i = 0; i < std::size(targets); i++) { for (s64 i = 0; i < std::size(targets); i++) {
@@ -1370,18 +1370,18 @@ void Menu::DeleteGames() {
LoadControlEntry(e); LoadControlEntry(e);
pbox->SetTitle(e.GetName()); pbox->SetTitle(e.GetName());
pbox->UpdateTransfer(i + 1, std::size(targets)); pbox->UpdateTransfer(i + 1, std::size(targets));
nsDeleteApplicationCompletely(e.app_id); R_TRY(nsDeleteApplicationCompletely(e.app_id));
} }
return true; R_SUCCEED();
}, [this](bool success){ }, [this](Result rc){
App::PushErrorBox(rc, "Delete failed"_i18n);
ClearSelection(); ClearSelection();
m_dirty = true; m_dirty = true;
if (success) { if (R_SUCCEEDED(rc)) {
App::Notify("Delete successfull!"); App::Notify("Delete successfull!");
} else {
App::Notify("Delete failed!");
} }
})); }));
} }
@@ -1405,7 +1405,7 @@ void Menu::DumpGames(u32 flags) {
} }
const auto index = *op_index; const auto index = *op_index;
App::Push(std::make_shared<ProgressBox>(0, "Dumping"_i18n, "", [this, network_locations, index, flags](auto pbox) -> bool { App::Push(std::make_shared<ProgressBox>(0, "Dumping"_i18n, "", [this, network_locations, index, flags](auto pbox) -> Result {
auto targets = GetSelectedEntries(); auto targets = GetSelectedEntries();
std::vector<NspEntry> nsp_entries; std::vector<NspEntry> nsp_entries;
@@ -1416,25 +1416,23 @@ void Menu::DumpGames(u32 flags) {
const auto index2 = index - network_locations.size(); const auto index2 = index - network_locations.size();
if (!network_locations.empty() && index < network_locations.size()) { if (!network_locations.empty() && index < network_locations.size()) {
return R_SUCCEEDED(DumpNspToNetwork(pbox, network_locations[index], nsp_entries)); R_TRY(DumpNspToNetwork(pbox, network_locations[index], nsp_entries));
} else if (index2 == DumpLocationType_SdCard) { } else if (index2 == DumpLocationType_SdCard) {
return R_SUCCEEDED(DumpNspToFile(pbox, nsp_entries)); R_TRY(DumpNspToFile(pbox, nsp_entries));
} else if (index2 == DumpLocationType_UsbS2S) { } else if (index2 == DumpLocationType_UsbS2S) {
return R_SUCCEEDED(DumpNspToUsbS2S(pbox, nsp_entries)); R_TRY(DumpNspToUsbS2S(pbox, nsp_entries));
} else if (index2 == DumpLocationType_DevNull) { } else if (index2 == DumpLocationType_DevNull) {
return R_SUCCEEDED(DumpNspToDevNull(pbox, nsp_entries)); R_TRY(DumpNspToDevNull(pbox, nsp_entries));
} }
return false; R_SUCCEED();
}, [this](bool success){ }, [this](Result rc){
App::PushErrorBox(rc, "Dump failed!"_i18n);
ClearSelection(); ClearSelection();
if (success) { if (R_SUCCEEDED(rc)) {
App::Notify("Dump successfull!"); App::Notify("Dump successfull!");
log_write("dump successfull!!!\n"); log_write("dump successfull!!!\n");
} else {
App::Notify("Dump failed!");
log_write("dump failed!!!\n");
} }
})); }));
} }

View File

@@ -875,14 +875,14 @@ Result Menu::GcMount() {
} }
if (m_option_index == 0) { if (m_option_index == 0) {
App::Push(std::make_shared<ui::ProgressBox>(m_icon, "Installing "_i18n, m_entries[m_entry_index].lang_entry.name, [this](auto pbox) mutable -> bool { App::Push(std::make_shared<ui::ProgressBox>(m_icon, "Installing "_i18n, m_entries[m_entry_index].lang_entry.name, [this](auto pbox) -> Result {
auto source = std::make_shared<GcSource>(m_entries[m_entry_index], m_fs.get()); auto source = std::make_shared<GcSource>(m_entries[m_entry_index], m_fs.get());
return R_SUCCEEDED(yati::InstallFromCollections(pbox, source, source->m_collections, source->m_config)); return yati::InstallFromCollections(pbox, source, source->m_collections, source->m_config);
}, [this](bool result){ }, [this](Result rc){
if (result) { App::PushErrorBox(rc, "Gc install failed"_i18n);
if (R_SUCCEEDED(rc)) {
App::Notify("Gc install success!"_i18n); App::Notify("Gc install success!"_i18n);
} else {
App::Notify("Gc install failed!"_i18n);
} }
})); }));
} else { } else {
@@ -1197,15 +1197,12 @@ void Menu::DumpGames(u32 flags) {
} }
const auto index = *op_index; const auto index = *op_index;
App::Push(std::make_shared<ProgressBox>(0, "Dumping"_i18n, "", [this, network_locations, index, flags](auto pbox) -> bool { App::Push(std::make_shared<ProgressBox>(0, "Dumping"_i18n, "", [this, network_locations, index, flags](auto pbox) -> Result {
XciEntry entry{}; XciEntry entry{};
entry.menu = this; entry.menu = this;
entry.application_name = m_entries[m_entry_index].lang_entry.name; entry.application_name = m_entries[m_entry_index].lang_entry.name;
if (R_FAILED(GcMountStorage())) { R_TRY(GcMountStorage());
log_write("failed to mount storage\n");
return false;
}
std::vector<fs::FsPath> paths; std::vector<fs::FsPath> paths;
if (flags & DumpFileFlag_XCI) { if (flags & DumpFileFlag_XCI) {
@@ -1221,9 +1218,7 @@ void Menu::DumpGames(u32 flags) {
if (flags & DumpFileFlag_Set) { if (flags & DumpFileFlag_Set) {
entry.id_set.resize(0xC); entry.id_set.resize(0xC);
if (R_FAILED(fsDeviceOperatorGetGameCardIdSet(&m_dev_op, entry.id_set.data(), entry.id_set.size(), entry.id_set.size()))) { R_TRY(fsDeviceOperatorGetGameCardIdSet(&m_dev_op, entry.id_set.data(), entry.id_set.size(), entry.id_set.size()));
return false;
}
paths.emplace_back(BuildFullDumpPath(DumpFileType_Set, m_entries)); paths.emplace_back(BuildFullDumpPath(DumpFileType_Set, m_entries));
} }
@@ -1235,12 +1230,7 @@ void Menu::DumpGames(u32 flags) {
if (flags & DumpFileFlag_Cert) { if (flags & DumpFileFlag_Cert) {
s64 size; s64 size;
entry.cert.resize(0x200); entry.cert.resize(0x200);
if (R_FAILED(fsDeviceOperatorGetGameCardDeviceCertificate(&m_dev_op, &m_handle, entry.cert.data(), entry.cert.size(), &size, entry.cert.size()))) { R_TRY(fsDeviceOperatorGetGameCardDeviceCertificate(&m_dev_op, &m_handle, entry.cert.data(), entry.cert.size(), &size, entry.cert.size()));
return false;
}
if (size != entry.cert.size()) {
return false;
}
paths.emplace_back(BuildFullDumpPath(DumpFileType_Cert, m_entries)); paths.emplace_back(BuildFullDumpPath(DumpFileType_Cert, m_entries));
} }
@@ -1252,23 +1242,22 @@ void Menu::DumpGames(u32 flags) {
const auto index2 = index - network_locations.size(); const auto index2 = index - network_locations.size();
if (!network_locations.empty() && index < network_locations.size()) { if (!network_locations.empty() && index < network_locations.size()) {
return R_SUCCEEDED(DumpNspToNetwork(pbox, network_locations[index], paths, entry)); R_TRY(DumpNspToNetwork(pbox, network_locations[index], paths, entry));
} else if (index2 == DumpLocationType_SdCard) { } else if (index2 == DumpLocationType_SdCard) {
return R_SUCCEEDED(DumpNspToFile(pbox, paths, entry)); R_TRY(DumpNspToFile(pbox, paths, entry));
} else if (index2 == DumpLocationType_UsbS2S) { } else if (index2 == DumpLocationType_UsbS2S) {
return R_SUCCEEDED(DumpNspToUsbS2S(pbox, paths, entry)); R_TRY(DumpNspToUsbS2S(pbox, paths, entry));
} else if (index2 == DumpLocationType_DevNull) { } else if (index2 == DumpLocationType_DevNull) {
return R_SUCCEEDED(DumpNspToDevNull(pbox, paths, entry)); R_TRY(DumpNspToDevNull(pbox, paths, entry));
} }
return false; R_SUCCEED();
}, [this](bool success){ }, [this](Result rc){
if (success) { App::PushErrorBox(rc, "Dump failed!"_i18n);
if (R_SUCCEEDED(rc)) {
App::Notify("Dump successfull!"); App::Notify("Dump successfull!");
log_write("dump successfull!!!\n"); log_write("dump successfull!!!\n");
} else {
App::Notify("Dump failed!");
log_write("dump failed!!!\n");
} }
GcUmountStorage(); GcUmountStorage();

View File

@@ -81,32 +81,28 @@ void from_json(const fs::FsPath& path, GhApiEntry& e) {
); );
} }
auto DownloadApp(ProgressBox* pbox, const GhApiAsset& gh_asset, const AssetEntry* entry) -> bool { auto DownloadApp(ProgressBox* pbox, const GhApiAsset& gh_asset, const AssetEntry* entry) -> Result {
static const fs::FsPath temp_file{"/switch/sphaira/cache/github/ghdl.temp"}; static const fs::FsPath temp_file{"/switch/sphaira/cache/github/ghdl.temp"};
constexpr auto chunk_size = 1024 * 512; // 512KiB constexpr auto chunk_size = 1024 * 512; // 512KiB
fs::FsNativeSd fs; fs::FsNativeSd fs;
R_TRY_RESULT(fs.GetFsOpenResult(), false); R_TRY(fs.GetFsOpenResult());
ON_SCOPE_EXIT(fs.DeleteFile(temp_file)); ON_SCOPE_EXIT(fs.DeleteFile(temp_file));
if (gh_asset.browser_download_url.empty()) { R_UNLESS(!gh_asset.browser_download_url.empty(), 0x1);
log_write("failed to find asset\n");
return false;
}
// 2. download the asset // 2. download the asset
if (!pbox->ShouldExit()) { if (!pbox->ShouldExit()) {
pbox->NewTransfer("Downloading "_i18n + gh_asset.name); pbox->NewTransfer("Downloading "_i18n + gh_asset.name);
log_write("starting download: %s\n", gh_asset.browser_download_url.c_str()); log_write("starting download: %s\n", gh_asset.browser_download_url.c_str());
if (!curl::Api().ToFile( const auto result = curl::Api().ToFile(
curl::Url{gh_asset.browser_download_url}, curl::Url{gh_asset.browser_download_url},
curl::Path{temp_file}, curl::Path{temp_file},
curl::OnProgress{pbox->OnDownloadProgressCallback()} curl::OnProgress{pbox->OnDownloadProgressCallback()}
).success){ );
log_write("error with download\n");
return false; R_UNLESS(result.success, 0x1);
}
} }
fs::FsPath root_path{"/"}; fs::FsPath root_path{"/"};
@@ -118,28 +114,25 @@ auto DownloadApp(ProgressBox* pbox, const GhApiAsset& gh_asset, const AssetEntry
if (gh_asset.content_type.find("zip") != gh_asset.content_type.npos) { if (gh_asset.content_type.find("zip") != gh_asset.content_type.npos) {
log_write("found zip\n"); log_write("found zip\n");
auto zfile = unzOpen64(temp_file); auto zfile = unzOpen64(temp_file);
if (!zfile) { R_UNLESS(zfile, 0x1);
log_write("failed to open zip: %s\n", temp_file.s);
return false;
}
ON_SCOPE_EXIT(unzClose(zfile)); ON_SCOPE_EXIT(unzClose(zfile));
unz_global_info64 pglobal_info; unz_global_info64 pglobal_info;
if (UNZ_OK != unzGetGlobalInfo64(zfile, &pglobal_info)) { if (UNZ_OK != unzGetGlobalInfo64(zfile, &pglobal_info)) {
return false; R_THROW(0x1);
} }
for (int i = 0; i < pglobal_info.number_entry; i++) { for (int i = 0; i < pglobal_info.number_entry; i++) {
if (i > 0) { if (i > 0) {
if (UNZ_OK != unzGoToNextFile(zfile)) { if (UNZ_OK != unzGoToNextFile(zfile)) {
log_write("failed to unzGoToNextFile\n"); log_write("failed to unzGoToNextFile\n");
return false; R_THROW(0x1);
} }
} }
if (UNZ_OK != unzOpenCurrentFile(zfile)) { if (UNZ_OK != unzOpenCurrentFile(zfile)) {
log_write("failed to open current file\n"); log_write("failed to open current file\n");
return false; R_THROW(0x1);
} }
ON_SCOPE_EXIT(unzCloseCurrentFile(zfile)); ON_SCOPE_EXIT(unzCloseCurrentFile(zfile));
@@ -147,7 +140,7 @@ auto DownloadApp(ProgressBox* pbox, const GhApiAsset& gh_asset, const AssetEntry
fs::FsPath file_path; fs::FsPath file_path;
if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &info, file_path, sizeof(file_path), 0, 0, 0, 0)) { if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &info, file_path, sizeof(file_path), 0, 0, 0, 0)) {
log_write("failed to get current info\n"); log_write("failed to get current info\n");
return false; R_THROW(0x1);
} }
file_path = fs::AppendPath(root_path, file_path); file_path = fs::AppendPath(root_path, file_path);
@@ -156,44 +149,37 @@ auto DownloadApp(ProgressBox* pbox, const GhApiAsset& gh_asset, const AssetEntry
if (file_path[strlen(file_path) -1] == '/') { if (file_path[strlen(file_path) -1] == '/') {
if (R_FAILED(rc = fs.CreateDirectoryRecursively(file_path)) && rc != FsError_PathAlreadyExists) { if (R_FAILED(rc = fs.CreateDirectoryRecursively(file_path)) && rc != FsError_PathAlreadyExists) {
log_write("failed to create folder: %s 0x%04X\n", file_path.s, rc); log_write("failed to create folder: %s 0x%04X\n", file_path.s, rc);
return false; R_THROW(rc);
} }
} else { } else {
if (R_FAILED(rc = fs.CreateDirectoryRecursivelyWithPath(file_path)) && rc != FsError_PathAlreadyExists) { if (R_FAILED(rc = fs.CreateDirectoryRecursivelyWithPath(file_path)) && rc != FsError_PathAlreadyExists) {
log_write("failed to create folder: %s 0x%04X\n", file_path.s, rc); log_write("failed to create folder: %s 0x%04X\n", file_path.s, rc);
return false; R_THROW(rc);
} }
if (R_FAILED(rc = fs.CreateFile(file_path, info.uncompressed_size, 0)) && rc != FsError_PathAlreadyExists) { if (R_FAILED(rc = fs.CreateFile(file_path, info.uncompressed_size, 0)) && rc != FsError_PathAlreadyExists) {
log_write("failed to create file: %s 0x%04X\n", file_path.s, rc); log_write("failed to create file: %s 0x%04X\n", file_path.s, rc);
return false; R_THROW(rc);
} }
FsFile f; FsFile f;
if (R_FAILED(rc = fs.OpenFile(file_path, FsOpenMode_Write, &f))) { R_TRY(fs.OpenFile(file_path, FsOpenMode_Write, &f));
log_write("failed to open file: %s 0x%04X\n", file_path.s, rc);
return false;
}
ON_SCOPE_EXIT(fsFileClose(&f)); ON_SCOPE_EXIT(fsFileClose(&f));
if (R_FAILED(rc = fsFileSetSize(&f, info.uncompressed_size))) { R_TRY(fsFileSetSize(&f, info.uncompressed_size));
log_write("failed to set file size: %s 0x%04X\n", file_path.s, rc);
return false;
}
std::vector<char> buf(chunk_size); std::vector<char> buf(chunk_size);
s64 offset{}; s64 offset{};
while (offset < info.uncompressed_size) { while (offset < info.uncompressed_size) {
R_TRY(pbox->ShouldExitResult());
const auto bytes_read = unzReadCurrentFile(zfile, buf.data(), buf.size()); const auto bytes_read = unzReadCurrentFile(zfile, buf.data(), buf.size());
if (bytes_read <= 0) { if (bytes_read <= 0) {
log_write("failed to read zip file: %s\n", file_path.s); log_write("failed to read zip file: %s\n", file_path.s);
return false; R_THROW(0x1);
} }
if (R_FAILED(rc = fsFileWrite(&f, offset, buf.data(), bytes_read, FsWriteOption_None))) { R_TRY(fsFileWrite(&f, offset, buf.data(), bytes_read, FsWriteOption_None));
log_write("failed to write file: %s 0x%04X\n", file_path.s, rc);
return false;
}
pbox->UpdateTransfer(offset, info.uncompressed_size); pbox->UpdateTransfer(offset, info.uncompressed_size);
offset += bytes_read; offset += bytes_read;
@@ -203,16 +189,14 @@ auto DownloadApp(ProgressBox* pbox, const GhApiAsset& gh_asset, const AssetEntry
} else { } else {
fs.CreateDirectoryRecursivelyWithPath(root_path); fs.CreateDirectoryRecursivelyWithPath(root_path);
fs.DeleteFile(root_path); fs.DeleteFile(root_path);
if (R_FAILED(fs.RenameFile(temp_file, root_path))) { R_TRY(fs.RenameFile(temp_file, root_path));
log_write("failed to rename file: %s -> %s\n", temp_file.s, root_path.s);
}
} }
log_write("success\n"); log_write("success\n");
return true; R_SUCCEED();
} }
auto DownloadAssetJson(ProgressBox* pbox, const std::string& url, GhApiEntry& out) -> bool { auto DownloadAssetJson(ProgressBox* pbox, const std::string& url, GhApiEntry& out) -> Result {
// 1. download the json // 1. download the json
if (!pbox->ShouldExit()) { if (!pbox->ShouldExit()) {
pbox->NewTransfer("Downloading json"_i18n); pbox->NewTransfer("Downloading json"_i18n);
@@ -230,15 +214,12 @@ auto DownloadAssetJson(ProgressBox* pbox, const std::string& url, GhApiEntry& ou
} }
); );
if (!result.success) { R_UNLESS(result.success, 0x1);
log_write("json empty\n");
return false;
}
from_json(result.path, out); from_json(result.path, out);
} }
return !out.assets.empty(); R_UNLESS(!out.assets.empty(), 0x1);
R_SUCCEED();
} }
} // namespace } // namespace
@@ -256,10 +237,12 @@ Menu::Menu() : MenuBase{"GitHub"_i18n} {
static GhApiEntry gh_entry; static GhApiEntry gh_entry;
gh_entry = {}; gh_entry = {};
App::Push(std::make_shared<ProgressBox>(0, "Downloading "_i18n, GetEntry().repo, [this](auto pbox){ App::Push(std::make_shared<ProgressBox>(0, "Downloading "_i18n, GetEntry().repo, [this](auto pbox) -> Result {
return DownloadAssetJson(pbox, GenerateApiUrl(GetEntry()), gh_entry); return DownloadAssetJson(pbox, GenerateApiUrl(GetEntry()), gh_entry);
}, [this](bool success){ }, [this](Result rc){
if (success) { App::PushErrorBox(rc, "Failed to download json"_i18n);
if (R_SUCCEEDED(rc)) {
const auto& assets = GetEntry().assets; const auto& assets = GetEntry().assets;
PopupList::Items asset_items; PopupList::Items asset_items;
std::vector<const AssetEntry*> asset_ptr; std::vector<const AssetEntry*> asset_ptr;
@@ -304,10 +287,12 @@ Menu::Menu() : MenuBase{"GitHub"_i18n} {
} }
const auto func = [this, &asset_entry, ptr](){ const auto func = [this, &asset_entry, ptr](){
App::Push(std::make_shared<ProgressBox>(0, "Downloading "_i18n, GetEntry().repo, [this, &asset_entry, ptr](auto pbox){ App::Push(std::make_shared<ProgressBox>(0, "Downloading "_i18n, GetEntry().repo, [this, &asset_entry, ptr](auto pbox) -> Result {
return DownloadApp(pbox, asset_entry, ptr); return DownloadApp(pbox, asset_entry, ptr);
}, [this, ptr](bool success){ }, [this, ptr](Result rc){
if (success) { App::PushErrorBox(rc, "Failed to download app!"_i18n);
if (R_SUCCEEDED(rc)) {
App::Notify("Downloaded "_i18n + GetEntry().repo); App::Notify("Downloaded "_i18n + GetEntry().repo);
auto post_install_message = GetEntry().post_install_message; auto post_install_message = GetEntry().post_install_message;
if (ptr && !ptr->post_install_message.empty()) { if (ptr && !ptr->post_install_message.empty()) {
@@ -318,7 +303,7 @@ Menu::Menu() : MenuBase{"GitHub"_i18n} {
App::Push(std::make_shared<OptionBox>(post_install_message, "OK"_i18n)); App::Push(std::make_shared<OptionBox>(post_install_message, "OK"_i18n));
} }
} }
}, 2)); }));
}; };
if (!pre_install_message.empty()) { if (!pre_install_message.empty()) {
@@ -335,7 +320,7 @@ Menu::Menu() : MenuBase{"GitHub"_i18n} {
} }
})); }));
} }
}, 2)); }));
}}), }}),
std::make_pair(Button::B, Action{"Back"_i18n, [this](){ std::make_pair(Button::B, Action{"Back"_i18n, [this](){

View File

@@ -47,26 +47,25 @@ const MiscMenuEntry MISC_MENU_ENTRIES[] = {
{ .name = "IRS", .title = "IRS (Infrared Joycon Camera)", .func = MiscMenuFuncGenerator<ui::menu::irs::Menu>, .flag = MiscMenuFlag_Shortcut }, { .name = "IRS", .title = "IRS (Infrared Joycon Camera)", .func = MiscMenuFuncGenerator<ui::menu::irs::Menu>, .flag = MiscMenuFlag_Shortcut },
}; };
auto InstallUpdate(ProgressBox* pbox, const std::string url, const std::string version) -> bool { auto InstallUpdate(ProgressBox* pbox, const std::string url, const std::string version) -> Result {
static fs::FsPath zip_out{"/switch/sphaira/cache/update.zip"}; static fs::FsPath zip_out{"/switch/sphaira/cache/update.zip"};
constexpr auto chunk_size = 1024 * 512; // 512KiB constexpr auto chunk_size = 1024 * 512; // 512KiB
fs::FsNativeSd fs; fs::FsNativeSd fs;
R_TRY_RESULT(fs.GetFsOpenResult(), false); R_TRY(fs.GetFsOpenResult());
// 1. download the zip // 1. download the zip
if (!pbox->ShouldExit()) { if (!pbox->ShouldExit()) {
pbox->NewTransfer("Downloading "_i18n + version); pbox->NewTransfer("Downloading "_i18n + version);
log_write("starting download: %s\n", url.c_str()); log_write("starting download: %s\n", url.c_str());
if (!curl::Api().ToFile( const auto result = curl::Api().ToFile(
curl::Url{url}, curl::Url{url},
curl::Path{zip_out}, curl::Path{zip_out},
curl::OnProgress{pbox->OnDownloadProgressCallback()} curl::OnProgress{pbox->OnDownloadProgressCallback()}
).success) { );
log_write("error with download\n");
return false; R_UNLESS(result.success, 0x1);
}
} }
ON_SCOPE_EXIT(fs.DeleteFile(zip_out)); ON_SCOPE_EXIT(fs.DeleteFile(zip_out));
@@ -74,28 +73,25 @@ auto InstallUpdate(ProgressBox* pbox, const std::string url, const std::string v
// 2. extract the zip // 2. extract the zip
if (!pbox->ShouldExit()) { if (!pbox->ShouldExit()) {
auto zfile = unzOpen64(zip_out); auto zfile = unzOpen64(zip_out);
if (!zfile) { R_UNLESS(zfile, 0x1);
log_write("failed to open zip: %s\n", zip_out.s);
return false;
}
ON_SCOPE_EXIT(unzClose(zfile)); ON_SCOPE_EXIT(unzClose(zfile));
unz_global_info64 pglobal_info; unz_global_info64 pglobal_info;
if (UNZ_OK != unzGetGlobalInfo64(zfile, &pglobal_info)) { if (UNZ_OK != unzGetGlobalInfo64(zfile, &pglobal_info)) {
return false; R_THROW(0x1);
} }
for (int i = 0; i < pglobal_info.number_entry; i++) { for (int i = 0; i < pglobal_info.number_entry; i++) {
if (i > 0) { if (i > 0) {
if (UNZ_OK != unzGoToNextFile(zfile)) { if (UNZ_OK != unzGoToNextFile(zfile)) {
log_write("failed to unzGoToNextFile\n"); log_write("failed to unzGoToNextFile\n");
return false; R_THROW(0x1);
} }
} }
if (UNZ_OK != unzOpenCurrentFile(zfile)) { if (UNZ_OK != unzOpenCurrentFile(zfile)) {
log_write("failed to open current file\n"); log_write("failed to open current file\n");
return false; R_THROW(0x1);
} }
ON_SCOPE_EXIT(unzCloseCurrentFile(zfile)); ON_SCOPE_EXIT(unzCloseCurrentFile(zfile));
@@ -103,7 +99,7 @@ auto InstallUpdate(ProgressBox* pbox, const std::string url, const std::string v
fs::FsPath file_path; fs::FsPath file_path;
if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &info, file_path, sizeof(file_path), 0, 0, 0, 0)) { if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &info, file_path, sizeof(file_path), 0, 0, 0, 0)) {
log_write("failed to get current info\n"); log_write("failed to get current info\n");
return false; R_THROW(0x1);
} }
if (file_path[0] != '/') { if (file_path[0] != '/') {
@@ -118,26 +114,20 @@ auto InstallUpdate(ProgressBox* pbox, const std::string url, const std::string v
if (file_path[strlen(file_path) -1] == '/') { if (file_path[strlen(file_path) -1] == '/') {
if (R_FAILED(rc = fs.CreateDirectoryRecursively(file_path)) && rc != FsError_PathAlreadyExists) { if (R_FAILED(rc = fs.CreateDirectoryRecursively(file_path)) && rc != FsError_PathAlreadyExists) {
log_write("failed to create folder: %s 0x%04X\n", file_path.s, rc); log_write("failed to create folder: %s 0x%04X\n", file_path.s, rc);
return false; R_THROW(0x1);
} }
} else { } else {
Result rc; Result rc;
if (R_FAILED(rc = fs.CreateFile(file_path, info.uncompressed_size, 0)) && rc != FsError_PathAlreadyExists) { if (R_FAILED(rc = fs.CreateFile(file_path, info.uncompressed_size, 0)) && rc != FsError_PathAlreadyExists) {
log_write("failed to create file: %s 0x%04X\n", file_path.s, rc); log_write("failed to create file: %s 0x%04X\n", file_path.s, rc);
return false; R_THROW(rc);
} }
FsFile f; FsFile f;
if (R_FAILED(rc = fs.OpenFile(file_path, FsOpenMode_Write, &f))) { R_TRY(fs.OpenFile(file_path, FsOpenMode_Write, &f));
log_write("failed to open file: %s 0x%04X\n", file_path.s, rc);
return false;
}
ON_SCOPE_EXIT(fsFileClose(&f)); ON_SCOPE_EXIT(fsFileClose(&f));
if (R_FAILED(rc = fsFileSetSize(&f, info.uncompressed_size))) { R_TRY(fsFileSetSize(&f, info.uncompressed_size));
log_write("failed to set file size: %s 0x%04X\n", file_path.s, rc);
return false;
}
std::vector<char> buf(chunk_size); std::vector<char> buf(chunk_size);
s64 offset{}; s64 offset{};
@@ -145,13 +135,10 @@ auto InstallUpdate(ProgressBox* pbox, const std::string url, const std::string v
const auto bytes_read = unzReadCurrentFile(zfile, buf.data(), buf.size()); const auto bytes_read = unzReadCurrentFile(zfile, buf.data(), buf.size());
if (bytes_read <= 0) { if (bytes_read <= 0) {
// log_write("failed to read zip file: %s\n", inzip.c_str()); // log_write("failed to read zip file: %s\n", inzip.c_str());
return false; R_THROW(0x1);
} }
if (R_FAILED(rc = fsFileWrite(&f, offset, buf.data(), bytes_read, FsWriteOption_None))) { R_TRY(fsFileWrite(&f, offset, buf.data(), bytes_read, FsWriteOption_None));
log_write("failed to write file: %s 0x%04X\n", file_path.s, rc);
return false;
}
pbox->UpdateTransfer(offset, info.uncompressed_size); pbox->UpdateTransfer(offset, info.uncompressed_size);
offset += bytes_read; offset += bytes_read;
@@ -161,7 +148,7 @@ auto InstallUpdate(ProgressBox* pbox, const std::string url, const std::string v
} }
log_write("finished update :)\n"); log_write("finished update :)\n");
return true; R_SUCCEED();
} }
auto CreateRightSideMenu() -> std::shared_ptr<MenuBase> { auto CreateRightSideMenu() -> std::shared_ptr<MenuBase> {
@@ -293,10 +280,12 @@ MainMenu::MainMenu() {
if (m_update_state == UpdateState::Update) { if (m_update_state == UpdateState::Update) {
options->Add(std::make_shared<SidebarEntryCallback>("Download update: "_i18n + m_update_version, [this](){ options->Add(std::make_shared<SidebarEntryCallback>("Download update: "_i18n + m_update_version, [this](){
App::Push(std::make_shared<ProgressBox>(0, "Downloading "_i18n, "Sphaira v" + m_update_version, [this](auto pbox){ App::Push(std::make_shared<ProgressBox>(0, "Downloading "_i18n, "Sphaira v" + m_update_version, [this](auto pbox) -> Result {
return InstallUpdate(pbox, m_update_url, m_update_version); return InstallUpdate(pbox, m_update_url, m_update_version);
}, [this](bool success){ }, [this](Result rc){
if (success) { App::PushErrorBox(rc, "Failed to download update"_i18n);
if (R_SUCCEEDED(rc)) {
m_update_state = UpdateState::None; m_update_state = UpdateState::None;
App::Notify("Updated to "_i18n + m_update_version); App::Notify("Updated to "_i18n + m_update_version);
App::Push(std::make_shared<OptionBox>( App::Push(std::make_shared<OptionBox>(
@@ -304,10 +293,8 @@ MainMenu::MainMenu() {
App::ExitRestart(); App::ExitRestart();
} }
)); ));
} else {
App::Push(std::make_shared<ui::ErrorBox>(MAKERESULT(351, 1), "Failed to download update"_i18n));
} }
}, 2)); }));
})); }));
} }
})); }));

View File

@@ -220,12 +220,12 @@ void from_json(const fs::FsPath& path, PackList& e) {
); );
} }
auto InstallTheme(ProgressBox* pbox, const PackListEntry& entry) -> bool { auto InstallTheme(ProgressBox* pbox, const PackListEntry& entry) -> Result {
static const fs::FsPath zip_out{"/switch/sphaira/cache/themezer/temp.zip"}; static const fs::FsPath zip_out{"/switch/sphaira/cache/themezer/temp.zip"};
constexpr auto chunk_size = 1024 * 512; // 512KiB constexpr auto chunk_size = 1024 * 512; // 512KiB
fs::FsNativeSd fs; fs::FsNativeSd fs;
R_TRY_RESULT(fs.GetFsOpenResult(), false); R_TRY(fs.GetFsOpenResult());
DownloadPack download_pack; DownloadPack download_pack;
@@ -243,7 +243,7 @@ auto InstallTheme(ProgressBox* pbox, const PackListEntry& entry) -> bool {
if (!result.success || result.data.empty()) { if (!result.success || result.data.empty()) {
log_write("error with download: %s\n", url.c_str()); log_write("error with download: %s\n", url.c_str());
return false; R_THROW(0x1);
} }
from_json(result.data, download_pack); from_json(result.data, download_pack);
@@ -254,13 +254,13 @@ auto InstallTheme(ProgressBox* pbox, const PackListEntry& entry) -> bool {
pbox->NewTransfer("Downloading "_i18n + entry.details.name); pbox->NewTransfer("Downloading "_i18n + entry.details.name);
log_write("starting download: %s\n", download_pack.url.c_str()); log_write("starting download: %s\n", download_pack.url.c_str());
if (!curl::Api().ToFile( const auto result = curl::Api().ToFile(
curl::Url{download_pack.url}, curl::Url{download_pack.url},
curl::Path{zip_out}, curl::Path{zip_out},
curl::OnProgress{pbox->OnDownloadProgressCallback()}).success) { curl::OnProgress{pbox->OnDownloadProgressCallback()}
log_write("error with download\n"); );
return false;
} R_UNLESS(result.success, 0x1);
} }
ON_SCOPE_EXIT(fs.DeleteFile(zip_out)); ON_SCOPE_EXIT(fs.DeleteFile(zip_out));
@@ -273,28 +273,25 @@ auto InstallTheme(ProgressBox* pbox, const PackListEntry& entry) -> bool {
// 3. extract the zip // 3. extract the zip
if (!pbox->ShouldExit()) { if (!pbox->ShouldExit()) {
auto zfile = unzOpen64(zip_out); auto zfile = unzOpen64(zip_out);
if (!zfile) { R_UNLESS(zfile, 0x1);
log_write("failed to open zip: %s\n", zip_out.s);
return false;
}
ON_SCOPE_EXIT(unzClose(zfile)); ON_SCOPE_EXIT(unzClose(zfile));
unz_global_info64 pglobal_info; unz_global_info64 pglobal_info;
if (UNZ_OK != unzGetGlobalInfo64(zfile, &pglobal_info)) { if (UNZ_OK != unzGetGlobalInfo64(zfile, &pglobal_info)) {
return false; R_THROW(0x1);
} }
for (int i = 0; i < pglobal_info.number_entry; i++) { for (int i = 0; i < pglobal_info.number_entry; i++) {
if (i > 0) { if (i > 0) {
if (UNZ_OK != unzGoToNextFile(zfile)) { if (UNZ_OK != unzGoToNextFile(zfile)) {
log_write("failed to unzGoToNextFile\n"); log_write("failed to unzGoToNextFile\n");
return false; R_THROW(0x1);
} }
} }
if (UNZ_OK != unzOpenCurrentFile(zfile)) { if (UNZ_OK != unzOpenCurrentFile(zfile)) {
log_write("failed to open current file\n"); log_write("failed to open current file\n");
return false; R_THROW(0x1);
} }
ON_SCOPE_EXIT(unzCloseCurrentFile(zfile)); ON_SCOPE_EXIT(unzCloseCurrentFile(zfile));
@@ -302,7 +299,7 @@ auto InstallTheme(ProgressBox* pbox, const PackListEntry& entry) -> bool {
char name[512]; char name[512];
if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &info, name, sizeof(name), 0, 0, 0, 0)) { if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &info, name, sizeof(name), 0, 0, 0, 0)) {
log_write("failed to get current info\n"); log_write("failed to get current info\n");
return false; R_THROW(0x1);
} }
const auto file_path = fs::AppendPath(dir_path, name); const auto file_path = fs::AppendPath(dir_path, name);
@@ -311,38 +308,27 @@ auto InstallTheme(ProgressBox* pbox, const PackListEntry& entry) -> bool {
Result rc; Result rc;
if (R_FAILED(rc = fs.CreateFile(file_path, info.uncompressed_size, 0)) && rc != FsError_PathAlreadyExists) { if (R_FAILED(rc = fs.CreateFile(file_path, info.uncompressed_size, 0)) && rc != FsError_PathAlreadyExists) {
log_write("failed to create file: %s 0x%04X\n", file_path.s, rc); log_write("failed to create file: %s 0x%04X\n", file_path.s, rc);
return false; R_THROW(rc);
} }
FsFile f; FsFile f;
if (R_FAILED(rc = fs.OpenFile(file_path, FsOpenMode_Write, &f))) { R_TRY(fs.OpenFile(file_path, FsOpenMode_Write, &f));
log_write("failed to open file: %s 0x%04X\n", file_path.s, rc);
return false;
}
ON_SCOPE_EXIT(fsFileClose(&f)); ON_SCOPE_EXIT(fsFileClose(&f));
if (R_FAILED(rc = fsFileSetSize(&f, info.uncompressed_size))) { R_TRY(fsFileSetSize(&f, info.uncompressed_size));
log_write("failed to set file size: %s 0x%04X\n", file_path.s, rc);
return false;
}
std::vector<char> buf(chunk_size); std::vector<char> buf(chunk_size);
s64 offset{}; s64 offset{};
while (offset < info.uncompressed_size) { while (offset < info.uncompressed_size) {
if (pbox->ShouldExit()) { R_TRY(pbox->ShouldExitResult());
return false;
}
const auto bytes_read = unzReadCurrentFile(zfile, buf.data(), buf.size()); const auto bytes_read = unzReadCurrentFile(zfile, buf.data(), buf.size());
if (bytes_read <= 0) { if (bytes_read <= 0) {
// log_write("failed to read zip file: %s\n", inzip.c_str()); // log_write("failed to read zip file: %s\n", inzip.c_str());
return false; R_THROW(0x1);
} }
if (R_FAILED(rc = fsFileWrite(&f, offset, buf.data(), bytes_read, FsWriteOption_None))) { R_TRY(fsFileWrite(&f, offset, buf.data(), bytes_read, FsWriteOption_None));
log_write("failed to write file: %s 0x%04X\n", file_path.s, rc);
return false;
}
pbox->UpdateTransfer(offset, info.uncompressed_size); pbox->UpdateTransfer(offset, info.uncompressed_size);
offset += bytes_read; offset += bytes_read;
@@ -351,7 +337,7 @@ auto InstallTheme(ProgressBox* pbox, const PackListEntry& entry) -> bool {
} }
log_write("finished install :)\n"); log_write("finished install :)\n");
return true; R_SUCCEED();
} }
} // namespace } // namespace
@@ -386,13 +372,15 @@ Menu::Menu() : MenuBase{"Themezer"_i18n} {
const auto& entry = page.m_packList[m_index]; const auto& entry = page.m_packList[m_index];
const auto url = apiBuildUrlDownloadPack(entry); const auto url = apiBuildUrlDownloadPack(entry);
App::Push(std::make_shared<ProgressBox>(entry.themes[0].preview.lazy_image.image, "Downloading "_i18n, entry.details.name, [this, &entry](auto pbox){ App::Push(std::make_shared<ProgressBox>(entry.themes[0].preview.lazy_image.image, "Downloading "_i18n, entry.details.name, [this, &entry](auto pbox) -> Result {
return InstallTheme(pbox, entry); return InstallTheme(pbox, entry);
}, [this, &entry](bool success){ }, [this, &entry](Result rc){
if (success) { App::PushErrorBox(rc, "Failed to download theme"_i18n);
if (R_SUCCEEDED(rc)) {
App::Notify("Downloaded "_i18n + entry.details.name); App::Notify("Downloaded "_i18n + entry.details.name);
} }
}, 2)); }));
} }
} }
} }

View File

@@ -109,31 +109,31 @@ void Menu::Update(Controller* controller, TouchInfo* touch) {
log_write("set to progress\n"); log_write("set to progress\n");
m_state = State::Progress; m_state = State::Progress;
log_write("got connection\n"); log_write("got connection\n");
App::Push(std::make_shared<ui::ProgressBox>(0, "Installing "_i18n, "", [this](auto pbox) mutable -> bool { App::Push(std::make_shared<ui::ProgressBox>(0, "Installing "_i18n, "", [this](auto pbox) -> Result {
ON_SCOPE_EXIT(m_usb_source->Finished(FINISHED_TIMEOUT)); ON_SCOPE_EXIT(m_usb_source->Finished(FINISHED_TIMEOUT));
log_write("inside progress box\n"); log_write("inside progress box\n");
for (const auto& file_name : m_names) { for (const auto& file_name : m_names) {
m_usb_source->SetFileNameForTranfser(file_name); m_usb_source->SetFileNameForTranfser(file_name);
const auto rc = yati::InstallFromSource(pbox, m_usb_source, file_name); const auto rc = yati::InstallFromSource(pbox, m_usb_source, file_name);
if (R_FAILED(rc)) { if (R_FAILED(rc)) {
m_usb_source->SignalCancel(); m_usb_source->SignalCancel();
log_write("exiting usb install\n"); log_write("exiting usb install\n");
return false; R_THROW(rc);
} }
App::Notify("Installed via usb"_i18n); App::Notify("Installed via usb"_i18n);
} }
return true; R_SUCCEED();
}, [this](bool result){ }, [this](Result rc){
if (result) { App::PushErrorBox(rc, "USB install failed"_i18n);
if (R_SUCCEEDED(rc)) {
App::Notify("Usb install success!"_i18n); App::Notify("Usb install success!"_i18n);
m_state = State::Done; m_state = State::Done;
SetPop(); SetPop();
} else { } else {
App::Notify("Usb install failed!"_i18n);
m_state = State::Failed; m_state = State::Failed;
} }
})); }));

View File

@@ -212,6 +212,13 @@ auto ProgressBox::ShouldExit() -> bool {
return m_stop_source.stop_requested(); return m_stop_source.stop_requested();
} }
auto ProgressBox::ShouldExitResult() -> Result {
if (ShouldExit()) {
R_THROW(0xFFFF);
}
R_SUCCEED();
}
auto ProgressBox::CopyFile(const fs::FsPath& src_path, const fs::FsPath& dst_path) -> Result { auto ProgressBox::CopyFile(const fs::FsPath& src_path, const fs::FsPath& dst_path) -> Result {
fs::FsNativeSd fs; fs::FsNativeSd fs;
R_TRY(fs.GetFsOpenResult()); R_TRY(fs.GetFsOpenResult());