M module-services/service-desktop/CMakeLists.txt => module-services/service-desktop/CMakeLists.txt +1 -0
@@ 17,6 17,7 @@ set(SOURCES
endpoints/contacts/ContactsEndpoint.cpp
endpoints/developerMode/DeveloperModeEndpoint.cpp
endpoints/developerMode/DeveloperModeHelper.cpp
+ endpoints/developerMode/fs/FS_Helper.cpp
endpoints/developerMode/Mode/UI_Helper.cpp
endpoints/developerMode/event/DomRequest.cpp
endpoints/developerMode/event/ATRequest.cpp
M module-services/service-desktop/endpoints/developerMode/DeveloperModeEndpoint.cpp => module-services/service-desktop/endpoints/developerMode/DeveloperModeEndpoint.cpp +3 -0
@@ 37,5 37,8 @@ auto DeveloperModeEndpoint::helperSwitcher(parserFSM::Context &ctx) -> parserFSM
if (ctx.getBody()["ui"] == true) {
return *uiHelper;
}
+ if (ctx.getBody()["fs"] == true) {
+ return *fsHelper;
+ }
return *helper;
}
M module-services/service-desktop/endpoints/developerMode/DeveloperModeEndpoint.hpp => module-services/service-desktop/endpoints/developerMode/DeveloperModeEndpoint.hpp +4 -1
@@ 5,6 5,7 @@
#include "DeveloperModeHelper.hpp"
#include "Mode/UI_Helper.hpp"
+#include "fs/FS_Helper.hpp"
#include <endpoints/Endpoint.hpp>
#include <parser/ParserUtils.hpp>
@@ 27,11 28,13 @@ class DeveloperModeEndpoint : public parserFSM::Endpoint
private:
const std::unique_ptr<parserFSM::DeveloperModeHelper> helper;
const std::unique_ptr<parserFSM::UI_Helper> uiHelper;
+ const std::unique_ptr<parserFSM::FS_Helper> fsHelper;
public:
explicit DeveloperModeEndpoint(sys::Service *_ownerServicePtr)
: Endpoint(_ownerServicePtr), helper(std::make_unique<parserFSM::DeveloperModeHelper>(ownerServicePtr)),
- uiHelper(std::make_unique<parserFSM::UI_Helper>(ownerServicePtr))
+ uiHelper(std::make_unique<parserFSM::UI_Helper>(ownerServicePtr)),
+ fsHelper(std::make_unique<parserFSM::FS_Helper>(ownerServicePtr))
{
debugName = "DeveloperModeEndpoint";
}
A module-services/service-desktop/endpoints/developerMode/fs/FS_Helper.cpp => module-services/service-desktop/endpoints/developerMode/fs/FS_Helper.cpp +93 -0
@@ 0,0 1,93 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "FS_Helper.hpp"
+
+#include <log.hpp>
+#include <service-desktop/Constants.hpp>
+#include <service-desktop/DeveloperModeMessage.hpp>
+#include <service-desktop/parser/MessageHandler.hpp>
+
+#include <filesystem>
+#include <system_error>
+
+namespace parserFSM
+{
+ void FS_Helper::preProcess(http::Method method, Context &context)
+ {
+ LOG_INFO("In FS helper - requesting %d", static_cast<int>(method));
+ }
+
+ auto FS_Helper::processGet(Context &context) -> ProcessResult
+ {
+ const auto &body = context.getBody();
+ if (body[json::fs::listDir].is_string()) {
+ const auto &dir = body[json::fs::listDir].string_value();
+ auto response = requestListDir(dir);
+ return {sent::no, std::move(response)};
+ }
+ else {
+ return {sent::no, endpoint::ResponseContext{.status = http::Code::BadRequest}};
+ }
+ }
+
+ auto FS_Helper::processPut(Context &context) -> ProcessResult
+ {
+ auto body = context.getBody();
+ auto code = http::Code::BadRequest;
+ if (body[json::fs::removeFile].is_string()) {
+ const auto &fileName = body[json::fs::removeFile].string_value();
+ try {
+ code = requestFileRemoval(fileName) ? http::Code::NoContent : http::Code::NotFound;
+ }
+ catch (const std::filesystem::filesystem_error &) {
+ LOG_WARN("Can't remove requested file");
+ code = http::Code::InternalServerError;
+ }
+ }
+ else if (body[json::fs::renameFile].is_string()) {
+ const auto &fileName = body[json::fs::renameFile].string_value();
+ if (body[json::fs::destFileName].is_string()) {
+ const auto &destFileName = body[json::fs::destFileName].string_value();
+ code = requestFileRename(fileName, destFileName) ? http::Code::NoContent : http::Code::NotFound;
+ }
+ else {
+ code = http::Code::NotFound;
+ }
+ }
+ else {
+ context.setResponseStatus(http::Code::BadRequest);
+ MessageHandler::putToSendQueue(context.createSimpleResponse());
+ }
+
+ return {sent::no, endpoint::ResponseContext{.status = code}};
+ }
+
+ bool FS_Helper::requestFileRemoval(const std::string &fileName)
+ {
+ return std::filesystem::remove(fileName);
+ }
+
+ bool FS_Helper::requestFileRename(const std::string &fileName, const std::string &destFileName) noexcept
+ {
+ std::error_code ec;
+ std::filesystem::rename(fileName, destFileName, ec);
+ return (!ec) ? true : false;
+ }
+
+ endpoint::ResponseContext FS_Helper::requestListDir(const std::string &directory)
+ {
+ std::vector<std::string> filesInDir;
+ for (const auto &entry : std::filesystem::directory_iterator{directory}) {
+ filesInDir.push_back(entry.path());
+ }
+ json11::Json::array jsonArr;
+ jsonArr.reserve(filesInDir.size());
+ for (const auto &path : filesInDir) {
+ jsonArr.push_back(json11::Json::object{{json::fs::path, path}});
+ }
+ json11::Json::object response({{directory, jsonArr}});
+ return endpoint::ResponseContext{.status = http::Code::OK, .body = response};
+ }
+
+} // namespace parserFSM
A module-services/service-desktop/endpoints/developerMode/fs/FS_Helper.hpp => module-services/service-desktop/endpoints/developerMode/fs/FS_Helper.hpp +37 -0
@@ 0,0 1,37 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <endpoints/Context.hpp>
+#include <Service/Common.hpp>
+#include <endpoints/BaseHelper.hpp>
+
+namespace parserFSM
+{
+
+ class FS_Helper : public BaseHelper
+ {
+ public:
+ explicit FS_Helper(sys::Service *p) : BaseHelper(p)
+ {}
+
+ private:
+ auto processGet(Context &context) -> ProcessResult final;
+ auto processPut(Context &context) -> ProcessResult final;
+ void preProcess(http::Method method, Context &context) final;
+
+ bool requestFileRemoval(const std::string &fileName);
+ bool requestFileRename(const std::string &fileName, const std::string &destFileName) noexcept;
+ endpoint::ResponseContext requestListDir(const std::string &directory);
+ };
+
+ namespace json::fs
+ {
+ inline constexpr auto removeFile = "removeFile";
+ inline constexpr auto renameFile = "renameFile";
+ inline constexpr auto destFileName = "destfilename";
+ inline constexpr auto listDir = "listDir";
+ inline constexpr auto path = "path";
+ } // namespace json::fs
+} // namespace parserFSM
A test/pytest/test_file_indexer.py => test/pytest/test_file_indexer.py +25 -0
@@ 0,0 1,25 @@
+# Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+# For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+from harness.harness import Harness
+import pytest
+import eyed3
+from harness.api.filesystem import put_file
+
+def remove_file(harness, filename):
+ body = {"fs": True, "removeFile": filename}
+ return harness.endpoint_request("developerMode", "put", body)
+
+def rename_file(harness, filename, destfilename):
+ body = {"fs": True, "renameFile": filename, "destfilename": destfilename}
+ return harness.endpoint_request("developerMode", "put", body)
+
+def list_files(harness, directory):
+ body = {"fs": True, "listDir": directory}
+ return harness.endpoint_request("developerMode", "get", body)["body"][directory]
+
+def add_tags(filename, title, artist, album):
+ audioFile = eyed3.load(filename)
+ audioFile.tag.title = title
+ audioFile.tag.artist = artist
+ audioFile.tag.album = album
+ audioFile.tag.save()
M test/requirements.txt => test/requirements.txt +3 -0
@@ 9,4 9,7 @@ pytest==6.1.2
six==1.15.0
toml==0.10.2
inotify==0.2.10
+dataclasses==0.6
dataclasses_json==0.5.4
+tqdm=4.62.2
+eyed3=0.9.6