diff --git a/Tactility/Include/Tactility/app/App.h b/Tactility/Include/Tactility/app/App.h index a6ad89a5..bcb11e7b 100644 --- a/Tactility/Include/Tactility/app/App.h +++ b/Tactility/Include/Tactility/app/App.h @@ -94,6 +94,10 @@ std::shared_ptr _Nullable getCurrentAppContext(); /** @return the currently running app (it is only ever null before the splash screen is shown) */ std::shared_ptr _Nullable getCurrentApp(); +std::string getTempPath(); + +std::string getInstallPath(); + bool install(const std::string& path); } diff --git a/Tactility/Source/app/AppInstall.cpp b/Tactility/Source/app/AppInstall.cpp index 5fdf4904..076a844d 100644 --- a/Tactility/Source/app/AppInstall.cpp +++ b/Tactility/Source/app/AppInstall.cpp @@ -9,11 +9,14 @@ #include #include #include -#include #include #include +#include #include +#include #include +#include +#include constexpr auto* TAG = "App"; @@ -99,35 +102,86 @@ bool untar(const std::string& tarPath, const std::string& destinationPath) { return success; } -bool install(const std::string& path) { - auto filename = file::getLastPathSegment(path); - const std::string target_path = std::format("/data/apps/{}", filename); - if (file::isDirectory(target_path) && !file::deleteRecursively(target_path)) { - TT_LOG_W(TAG, "Failed to delete %s", target_path.c_str()); - } +bool findFirstMountedSdCardPath(std::string& path) { + // const auto sdcards = hal::findDevices(hal::Device::Type::SdCard); + bool is_set = false; + hal::findDevices(hal::Device::Type::SdCard, [&is_set, &path](const auto& device) { + if (device->isMounted()) { + path = device->getMountPath(); + is_set = true; + return false; // stop iterating + } else { + return true; + } + }); + return is_set; +} - if (!file::findOrCreateDirectory(target_path, 0777)) { - TT_LOG_I(TAG, "Failed to create directory %s", target_path.c_str()); +std::string getTempPath() { + std::string root_path; + if (!findFirstMountedSdCardPath(root_path)) { + root_path = file::MOUNT_POINT_DATA; + } + return root_path + "/tmp"; +} + +std::string getInstallPath() { + std::string root_path; + if (!findFirstMountedSdCardPath(root_path)) { + root_path = file::MOUNT_POINT_DATA; + } + return root_path + "/apps"; +} + +bool install(const std::string& path) { + // TODO: Make better: lock for each path type properly (source vs target) + + // We lock and unlock frequently because SPI SD card devices share + // the lock with the display. We don't want to lock the display for very long. + + auto app_parent_path = getInstallPath(); + TT_LOG_I(TAG, "Installing app %s to %s", path.c_str(), app_parent_path.c_str()); + + auto lock = file::getLock(app_parent_path)->asScopedLock(); + + lock.lock(); + auto filename = file::getLastPathSegment(path); + const std::string app_target_path = std::format("{}/{}", app_parent_path, filename); + if (file::isDirectory(app_target_path) && !file::deleteRecursively(app_target_path)) { + TT_LOG_W(TAG, "Failed to delete %s", app_target_path.c_str()); + } + lock.unlock(); + + lock.lock(); + if (!file::findOrCreateDirectory(app_target_path, 0777)) { + TT_LOG_I(TAG, "Failed to create directory %s", app_target_path.c_str()); return false; } + lock.unlock(); - TT_LOG_I(TAG, "Extracting app from %s to %s", path.c_str(), target_path.c_str()); - if (!untar(path, target_path)) { + lock.lock(); + TT_LOG_I(TAG, "Extracting app from %s to %s", path.c_str(), app_target_path.c_str()); + if (!untar(path, app_target_path)) { TT_LOG_E(TAG, "Failed to extract"); return false; } + lock.unlock(); - auto manifest_path = target_path + "/manifest.properties"; + lock.lock(); + auto manifest_path = app_target_path + "/manifest.properties"; if (!file::isFile(manifest_path)) { TT_LOG_E(TAG, "Manifest not found at %s", manifest_path.c_str()); return false; } + lock.unlock(); + lock.lock(); std::map properties; if (!file::loadPropertiesFile(manifest_path, properties)) { TT_LOG_E(TAG, "Failed to load manifest at %s", manifest_path.c_str()); return false; } + lock.unlock(); auto app_id_iterator = properties.find("[app]id"); if (app_id_iterator == properties.end()) { @@ -135,11 +189,22 @@ bool install(const std::string& path) { return false; } - const std::string renamed_target_path = std::format("/data/apps/{}", app_id_iterator->second); - if (rename(target_path.c_str(), renamed_target_path.c_str()) != 0) { - TT_LOG_E(TAG, "Failed to rename %s to %s", target_path.c_str(), app_id_iterator->second.c_str()); + lock.lock(); + const std::string renamed_target_path = std::format("{}/{}", app_parent_path, app_id_iterator->second); + if (file::isDirectory(renamed_target_path)) { + if (!file::deleteRecursively(renamed_target_path)) { + TT_LOG_W(TAG, "Failed to delete existing installation at %s", renamed_target_path.c_str()); + return false; + } + } + lock.unlock(); + + lock.lock(); + if (rename(app_target_path.c_str(), renamed_target_path.c_str()) != 0) { + TT_LOG_E(TAG, "Failed to rename %s to %s", app_target_path.c_str(), app_id_iterator->second.c_str()); return false; } + lock.unlock(); return true; } diff --git a/Tactility/Source/service/development/DevelopmentService.cpp b/Tactility/Source/service/development/DevelopmentService.cpp index 303d6a80..fe628435 100644 --- a/Tactility/Source/service/development/DevelopmentService.cpp +++ b/Tactility/Source/service/development/DevelopmentService.cpp @@ -19,6 +19,7 @@ #include #include #include +#include namespace tt::service::development { @@ -98,6 +99,7 @@ void DevelopmentService::startServer() { deviceResponse = stream.str(); httpd_config_t config = HTTPD_DEFAULT_CONFIG(); + config.stack_size = 5120; config.server_port = 6666; config.uri_match_fn = httpd_uri_match_wildcard; @@ -257,13 +259,19 @@ esp_err_t DevelopmentService::handleAppInstall(httpd_req_t* request) { } content_left -= content_read; - if (!file::findOrCreateDirectory("/data/tmp", 0777)) { + const std::string tmp_path = app::getTempPath(); + auto lock = file::getLock(tmp_path)->asScopedLock(); + + lock.lock(); + if (!file::findOrCreateDirectory(tmp_path, 0777)) { httpd_resp_send_err(request, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to save file"); return ESP_FAIL; } + lock.unlock(); // Write file - auto file_path = std::format("/data/tmp/{}", filename_entry->second); + lock.lock(); + auto file_path = std::format("{}/{}", tmp_path, filename_entry->second); auto* file = fopen(file_path.c_str(), "wb"); auto file_bytes_written = fwrite(buffer.get(), 1, file_size, file); fclose(file); @@ -271,6 +279,8 @@ esp_err_t DevelopmentService::handleAppInstall(httpd_req_t* request) { httpd_resp_send_err(request, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to save file"); return ESP_FAIL; } + lock.unlock(); + // Read and verify part if (!network::readAndDiscardOrSendError(request, part_after_file)) { @@ -287,6 +297,12 @@ esp_err_t DevelopmentService::handleAppInstall(httpd_req_t* request) { return ESP_FAIL; } + lock.lock(); + if (remove(file_path.c_str()) != 0) { + TT_LOG_W(TAG, "Failed to delete %s", file_path.c_str()); + } + lock.unlock(); + TT_LOG_I(TAG, "[200] /app/install -> %s", file_path.c_str()); httpd_resp_send(request, nullptr, 0);