From 4241adb4d381e7ab7399b099554eaa0dd4aa4d33 Mon Sep 17 00:00:00 2001 From: "Scott E. Graves" Date: Thu, 23 Jan 2025 09:37:45 -0600 Subject: [PATCH] refactor event system --- CHANGELOG.md | 1 + .../include/comm/curl/curl_comm.hpp | 9 +- .../include/events/event_system2.hpp | 123 +++++++++++++ .../librepertory/include/events/events.hpp | 38 ---- .../librepertory/include/events/i_event.hpp | 40 +++++ .../include/events/types/curl_error.hpp | 73 ++++++++ .../include/events/types/debug_log.hpp | 67 +++++++ .../events/types/directory_remove_failed.hpp | 77 ++++++++ .../events/types/directory_removed.hpp | 68 +++++++ .../types/directory_removed_externally.hpp | 77 ++++++++ .../events/types/drive_mount_failed.hpp | 77 ++++++++ .../events/types/drive_mount_result.hpp | 75 ++++++++ .../include/events/types/drive_mounted.hpp | 69 ++++++++ .../src/drives/fuse/fuse_drive.cpp | 11 +- .../fuse/remotefuse/remote_fuse_drive.cpp | 88 ++++++---- .../winfsp/remotewinfsp/remote_client.cpp | 5 +- .../remotewinfsp/remote_winfsp_drive.cpp | 16 +- .../src/drives/winfsp/winfsp_drive.cpp | 18 +- .../src/events/event_system_2.cpp | 166 ++++++++++++++++++ .../src/providers/base_provider.cpp | 20 ++- .../providers/encrypt/encrypt_provider.cpp | 6 +- repertory/librepertory/src/utils/utils.cpp | 6 +- .../include/fixtures/file_db_fixture.hpp | 3 + .../include/fixtures/file_mgr_db_fixture.hpp | 3 + .../include/fixtures/meta_db_fixture.hpp | 3 + .../repertory_test/include/test_common.hpp | 1 + repertory/repertory_test/src/config_test.cpp | 6 +- .../src/direct_open_file_test.cpp | 10 +- .../repertory_test/src/file_manager_test.cpp | 6 +- .../repertory_test/src/open_file_test.cpp | 13 +- .../repertory_test/src/providers_test.cpp | 12 ++ .../src/ring_buffer_open_file_test.cpp | 10 +- repertory/repertory_test/src/upload_test.cpp | 10 +- 33 files changed, 1101 insertions(+), 106 deletions(-) create mode 100644 repertory/librepertory/include/events/event_system2.hpp create mode 100644 repertory/librepertory/include/events/i_event.hpp create mode 100644 repertory/librepertory/include/events/types/curl_error.hpp create mode 100644 repertory/librepertory/include/events/types/debug_log.hpp create mode 100644 repertory/librepertory/include/events/types/directory_remove_failed.hpp create mode 100644 repertory/librepertory/include/events/types/directory_removed.hpp create mode 100644 repertory/librepertory/include/events/types/directory_removed_externally.hpp create mode 100644 repertory/librepertory/include/events/types/drive_mount_failed.hpp create mode 100644 repertory/librepertory/include/events/types/drive_mount_result.hpp create mode 100644 repertory/librepertory/include/events/types/drive_mounted.hpp create mode 100644 repertory/librepertory/src/events/event_system_2.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 10d7d520..c0e1eef3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ * Fixed invalid directory nullptr error on remote mounts * Fixed memory leak in event system * Refactored application shutdown +* Refactored event system * Updated build system to Alpine 3.21.0 * Updated build system to MinGW-w64 12.0.0 * Updated copyright to 2018-2025 diff --git a/repertory/librepertory/include/comm/curl/curl_comm.hpp b/repertory/librepertory/include/comm/curl/curl_comm.hpp index ebb9b099..abbe8a85 100644 --- a/repertory/librepertory/include/comm/curl/curl_comm.hpp +++ b/repertory/librepertory/include/comm/curl/curl_comm.hpp @@ -25,8 +25,8 @@ #include "app_config.hpp" #include "comm/curl/multi_request.hpp" #include "comm/i_http_comm.hpp" -#include "events/event_system.hpp" -#include "events/events.hpp" +#include "events/event_system2.hpp" +#include "events/types/curl_error.hpp" #include "utils/encryption.hpp" namespace repertory { @@ -137,6 +137,8 @@ public: [[nodiscard]] static auto make_request(const host_config &cfg, const request_type &request, long &response_code, stop_type &stop_requested) -> bool { + REPERTORY_USES_FUNCTION_NAME(); + if (request.decryption_token.has_value() && not request.decryption_token.value().empty()) { return make_encrypted_request(cfg, request, response_code, @@ -223,7 +225,8 @@ public: } if (curl_code != CURLE_OK) { - event_system::instance().raise(url, curl_code); + event_system2::instance().raise(curl_code, function_name, + url); return false; } diff --git a/repertory/librepertory/include/events/event_system2.hpp b/repertory/librepertory/include/events/event_system2.hpp new file mode 100644 index 00000000..a62c5e13 --- /dev/null +++ b/repertory/librepertory/include/events/event_system2.hpp @@ -0,0 +1,123 @@ +/* + Copyright <2018-2025> + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +#ifndef REPERTORY_INCLUDE_EVENTS_EVENT_SYSTEM2_HPP_ +#define REPERTORY_INCLUDE_EVENTS_EVENT_SYSTEM2_HPP_ + +namespace repertory { +class i_event; + +class event_system2 final { +private: + static constexpr const std::uint8_t max_queue_retry{ + 30U, + }; + + const std::uint32_t max_queue_size{ + std::thread::hardware_concurrency() * 4U, + }; + + static constexpr const std::chrono::seconds queue_wait_secs{ + 5s, + }; + +public: + event_system2(const event_system2 &) = delete; + event_system2(event_system2 &&) = delete; + auto operator=(const event_system2 &) -> event_system2 & = delete; + auto operator=(event_system2 &&) -> event_system2 & = delete; + +protected: + event_system2() = default; + + ~event_system2() { stop(); } + +public: + class event_consumer final { + public: + explicit event_consumer(std::function callback) + : callback_(std::move(callback)) { + event_system2::instance().attach(this); + } + + event_consumer(std::string_view event_name, + std::function callback) + : callback_(std::move(callback)) { + event_system2::instance().attach(event_name, this); + } + + ~event_consumer() { event_system2::instance().release(this); } + + public: + event_consumer(const event_consumer &) = delete; + event_consumer(event_consumer &&) = delete; + auto operator=(const event_consumer &) -> event_consumer & = delete; + auto operator=(event_consumer &&) -> event_consumer & = delete; + + private: + std::function callback_; + + public: + void notify_event(const i_event &event) { callback_(event); } + }; + +private: + static event_system2 event_system_; + +public: + static auto instance() -> event_system2 &; + +private: + std::unordered_map> + event_consumers_; + std::recursive_mutex consumer_mutex_; + std::vector> event_list_; + std::condition_variable event_notify_; + std::mutex event_mutex_; + std::unique_ptr event_thread_; + std::mutex run_mutex_; + stop_type stop_requested_{false}; + +private: + [[nodiscard]] auto get_stop_requested() const -> bool; + + void process_events(); + + void queue_event(std::shared_ptr evt); + +public: + void attach(event_consumer *consumer); + + void attach(std::string_view event_name, event_consumer *consumer); + + template void raise(arg_t &&...args) { + queue_event(std::make_shared(std::forward(args)...)); + } + + void release(event_consumer *consumer); + + void start(); + + void stop(); +}; +} // namespace repertory + +#endif // REPERTORY_INCLUDE_EVENTS_EVENT_SYSTEM2_HPP_ diff --git a/repertory/librepertory/include/events/events.hpp b/repertory/librepertory/include/events/events.hpp index fcb7e5fc..c0e11bb8 100644 --- a/repertory/librepertory/include/events/events.hpp +++ b/repertory/librepertory/include/events/events.hpp @@ -28,44 +28,6 @@ namespace repertory { // clang-format off -E_SIMPLE2(curl_error, error, - std::string, url, url, E_FROM_STRING, - CURLcode, res, res, E_FROM_CURL_CODE -); - -E_SIMPLE3(debug_log, debug, - std::string, function, func, E_FROM_STRING, - std::string, api_path, ap, E_FROM_STRING, - std::string, data, data, E_FROM_STRING -); - -E_SIMPLE1(directory_removed, debug, - std::string, api_path, ap, E_FROM_STRING -); - -E_SIMPLE2(directory_removed_externally, warn, - std::string, api_path, ap, E_FROM_STRING, - std::string, source, src, E_FROM_STRING -); - -E_SIMPLE2(directory_remove_failed, error, - std::string, api_path, ap, E_FROM_STRING, - std::string, error, err, E_FROM_STRING -); - -E_SIMPLE2(drive_mount_failed, error, - std::string, location, loc, E_FROM_STRING, - std::string, result, res, E_FROM_STRING -); - -E_SIMPLE1(drive_mounted, info, - std::string, location, loc, E_FROM_STRING -); - -E_SIMPLE1(drive_mount_result, info, - std::string, result, res, E_FROM_STRING -); - E_SIMPLE1(drive_unmount_pending, info, std::string, location, loc, E_FROM_STRING ); diff --git a/repertory/librepertory/include/events/i_event.hpp b/repertory/librepertory/include/events/i_event.hpp new file mode 100644 index 00000000..ae70fe5e --- /dev/null +++ b/repertory/librepertory/include/events/i_event.hpp @@ -0,0 +1,40 @@ +/* + Copyright <2018-2025> + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +#ifndef REPERTORY_INCLUDE_EVENTS_I_EVENT_HPP_ +#define REPERTORY_INCLUDE_EVENTS_I_EVENT_HPP_ + +#include "types/repertory.hpp" + +namespace repertory { +class i_event { + INTERFACE_SETUP(i_event); + +public: + [[nodiscard]] virtual auto get_event_level() const -> event_level = 0; + + [[nodiscard]] virtual auto get_name() const -> std::string_view = 0; + + [[nodiscard]] virtual auto get_single_line() const -> std::string = 0; +}; +} // namespace repertory + +#endif // REPERTORY_INCLUDE_EVENTS_EVENT_HPP_ diff --git a/repertory/librepertory/include/events/types/curl_error.hpp b/repertory/librepertory/include/events/types/curl_error.hpp new file mode 100644 index 00000000..e7316113 --- /dev/null +++ b/repertory/librepertory/include/events/types/curl_error.hpp @@ -0,0 +1,73 @@ +/* + Copyright <2018-2025> + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +#ifndef REPERTORY_INCLUDE_EVENTS_TYPES_CURL_ERROR_HPP_ +#define REPERTORY_INCLUDE_EVENTS_TYPES_CURL_ERROR_HPP_ + +#include "events/i_event.hpp" +#include "types/repertory.hpp" + +namespace repertory { +struct curl_error final : public i_event { + curl_error() = default; + curl_error(CURLcode code_, std::string_view function_name_, std::string url_) + : code(code_), + function_name(std::string{function_name_}), + url(std::move(url_)) {} + + static constexpr const std::string_view name{"curl_error"}; + + CURLcode code{}; + std::string function_name; + std::string url; + + [[nodiscard]] auto get_event_level() const -> event_level override { + return event_level::error; + } + + [[nodiscard]] auto get_name() const -> std::string_view override { + return name; + } + + [[nodiscard]] auto get_single_line() const -> std::string override { + return fmt::format("{}|func|{}|url|{}|code|{}", name, function_name, url, + static_cast(code)); + } +}; +} // namespace repertory + +NLOHMANN_JSON_NAMESPACE_BEGIN +template <> struct adl_serializer { + static void to_json(json &data, const repertory::curl_error &value) { + data["code"] = value.code; + data["function_name"] = value.function_name; + data["url"] = value.url; + } + + static void from_json(const json &data, repertory::curl_error &value) { + data.at("code").get_to(value.code); + data.at("function_name").get_to(value.function_name); + data.at("url").get_to(value.url); + } +}; +NLOHMANN_JSON_NAMESPACE_END + +#endif // REPERTORY_INCLUDE_EVENTS_TYPES_CURL_ERROR_HPP_ diff --git a/repertory/librepertory/include/events/types/debug_log.hpp b/repertory/librepertory/include/events/types/debug_log.hpp new file mode 100644 index 00000000..3f385e90 --- /dev/null +++ b/repertory/librepertory/include/events/types/debug_log.hpp @@ -0,0 +1,67 @@ +/* + Copyright <2018-2025> + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +#ifndef REPERTORY_INCLUDE_EVENTS_TYPES_DEBUG_LOG_HPP_ +#define REPERTORY_INCLUDE_EVENTS_TYPES_DEBUG_LOG_HPP_ + +#include "events/i_event.hpp" +#include "types/repertory.hpp" + +namespace repertory { +struct debug_log final : public i_event { + debug_log() = default; + debug_log(std::string_view function_name_, std::string msg_) + : function_name(std::string(function_name_)), msg(std::move(msg_)) {} + + static constexpr const std::string_view name{"debug_log"}; + + std::string function_name; + std::string msg; + + [[nodiscard]] auto get_event_level() const -> event_level override { + return event_level::debug; + } + + [[nodiscard]] auto get_name() const -> std::string_view override { + return name; + } + + [[nodiscard]] auto get_single_line() const -> std::string override { + return fmt::format("{}|func|{}|msg|{}", name, function_name, msg); + } +}; +} // namespace repertory + +NLOHMANN_JSON_NAMESPACE_BEGIN +template <> struct adl_serializer { + static void to_json(json &data, const repertory::debug_log &value) { + data["function_name"] = value.function_name; + data["msg"] = value.msg; + } + + static void from_json(const json &data, repertory::debug_log &value) { + data.at("function_name").get_to(value.function_name); + data.at("msg").get_to(value.msg); + } +}; +NLOHMANN_JSON_NAMESPACE_END + +#endif // REPERTORY_INCLUDE_EVENTS_TYPES_DEBUG_LOG_HPP_ diff --git a/repertory/librepertory/include/events/types/directory_remove_failed.hpp b/repertory/librepertory/include/events/types/directory_remove_failed.hpp new file mode 100644 index 00000000..113cd01f --- /dev/null +++ b/repertory/librepertory/include/events/types/directory_remove_failed.hpp @@ -0,0 +1,77 @@ +/* + Copyright <2018-2025> + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +#ifndef REPERTORY_INCLUDE_EVENTS_TYPES_DIRECTORY_REMOVE_FAILED_HPP_ +#define REPERTORY_INCLUDE_EVENTS_TYPES_DIRECTORY_REMOVE_FAILED_HPP_ + +#include "events/i_event.hpp" +#include "types/repertory.hpp" + +namespace repertory { +struct directory_remove_failed final : public i_event { + directory_remove_failed() = default; + directory_remove_failed(std::string api_path_, api_error error_, + std::string_view function_name_) + : api_path(std::move(api_path_)), + error(error_), + function_name(std::string(function_name_)) {} + + static constexpr const std::string_view name{"directory_remove_failed"}; + + std::string api_path; + api_error error{}; + std::string function_name; + + [[nodiscard]] auto get_event_level() const -> event_level override { + return event_level::error; + } + + [[nodiscard]] auto get_name() const -> std::string_view override { + return name; + } + + [[nodiscard]] auto get_single_line() const -> std::string override { + return fmt::format("{}|func|{}|ap|{}|error|{}", name, function_name, + api_path, api_error_to_string(error)); + } +}; +} // namespace repertory + +NLOHMANN_JSON_NAMESPACE_BEGIN +template <> struct adl_serializer { + static void to_json(json &data, + const repertory::directory_remove_failed &value) { + data["api_path"] = value.api_path; + data["error"] = repertory::api_error_to_string(value.error); + data["function_name"] = value.function_name; + } + + static void from_json(const json &data, + repertory::directory_remove_failed &value) { + data.at("api_path").get_to(value.api_path); + value.error = + repertory::api_error_from_string(data.at("error").get()); + data.at("function_name").get_to(value.function_name); + } +}; +NLOHMANN_JSON_NAMESPACE_END + +#endif // REPERTORY_INCLUDE_EVENTS_TYPES_DIRECTORY_REMOVE_FAILED_HPP_ diff --git a/repertory/librepertory/include/events/types/directory_removed.hpp b/repertory/librepertory/include/events/types/directory_removed.hpp new file mode 100644 index 00000000..607738ce --- /dev/null +++ b/repertory/librepertory/include/events/types/directory_removed.hpp @@ -0,0 +1,68 @@ +/* + Copyright <2018-2025> + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +#ifndef REPERTORY_INCLUDE_EVENTS_TYPES_DIRECTORY_REMOVED_HPP_ +#define REPERTORY_INCLUDE_EVENTS_TYPES_DIRECTORY_REMOVED_HPP_ + +#include "events/i_event.hpp" +#include "types/repertory.hpp" + +namespace repertory { +struct directory_removed final : public i_event { + directory_removed() = default; + directory_removed(std::string api_path_, std::string_view function_name_) + : api_path(std::move(api_path_)), + function_name(std::string(function_name_)) {} + + static constexpr const std::string_view name{"directory_removed"}; + + std::string api_path; + std::string function_name; + + [[nodiscard]] auto get_event_level() const -> event_level override { + return event_level::debug; + } + + [[nodiscard]] auto get_name() const -> std::string_view override { + return name; + } + + [[nodiscard]] auto get_single_line() const -> std::string override { + return fmt::format("{}|func|{}|ap|{}", name, function_name, api_path); + } +}; +} // namespace repertory + +NLOHMANN_JSON_NAMESPACE_BEGIN +template <> struct adl_serializer { + static void to_json(json &data, const repertory::directory_removed &value) { + data["api_path"] = value.api_path; + data["function_name"] = value.function_name; + } + + static void from_json(const json &data, repertory::directory_removed &value) { + data.at("api_path").get_to(value.api_path); + data.at("function_name").get_to(value.function_name); + } +}; +NLOHMANN_JSON_NAMESPACE_END + +#endif // REPERTORY_INCLUDE_EVENTS_TYPES_DIRECTORY_REMOVED_HPP_ diff --git a/repertory/librepertory/include/events/types/directory_removed_externally.hpp b/repertory/librepertory/include/events/types/directory_removed_externally.hpp new file mode 100644 index 00000000..b3ccb4b2 --- /dev/null +++ b/repertory/librepertory/include/events/types/directory_removed_externally.hpp @@ -0,0 +1,77 @@ +/* + Copyright <2018-2025> + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +#ifndef REPERTORY_INCLUDE_EVENTS_TYPES_DIRECTORY_REMOVED_EXTERNALLY_HPP_ +#define REPERTORY_INCLUDE_EVENTS_TYPES_DIRECTORY_REMOVED_EXTERNALLY_HPP_ + +#include "events/i_event.hpp" +#include "types/repertory.hpp" + +namespace repertory { +struct directory_removed_externally final : public i_event { + directory_removed_externally() = default; + directory_removed_externally(std::string api_path_, + std::string_view function_name_, + std::string source_path_) + : api_path(std::move(api_path_)), + function_name(std::string(function_name_)), + source_path(std::move(source_path_)) {} + + static constexpr const std::string_view name{"directory_removed_externally"}; + + std::string api_path; + std::string function_name; + std::string source_path; + + [[nodiscard]] auto get_event_level() const -> event_level override { + return event_level::warn; + } + + [[nodiscard]] auto get_name() const -> std::string_view override { + return name; + } + + [[nodiscard]] auto get_single_line() const -> std::string override { + return fmt::format("{}|func|{}|ap|{}|src|{}", name, function_name, api_path, + source_path); + } +}; +} // namespace repertory + +NLOHMANN_JSON_NAMESPACE_BEGIN +template <> struct adl_serializer { + static void to_json(json &data, + const repertory::directory_removed_externally &value) { + data["api_path"] = value.api_path; + data["function_name"] = value.function_name; + data["source_path"] = value.source_path; + } + + static void from_json(const json &data, + repertory::directory_removed_externally &value) { + data.at("api_path").get_to(value.api_path); + data.at("function_name").get_to(value.function_name); + data.at("source_path").get_to(value.source_path); + } +}; +NLOHMANN_JSON_NAMESPACE_END + +#endif // REPERTORY_INCLUDE_EVENTS_TYPES_DIRECTORY_REMOVED_EXTERNALLY_HPP_ diff --git a/repertory/librepertory/include/events/types/drive_mount_failed.hpp b/repertory/librepertory/include/events/types/drive_mount_failed.hpp new file mode 100644 index 00000000..558c503d --- /dev/null +++ b/repertory/librepertory/include/events/types/drive_mount_failed.hpp @@ -0,0 +1,77 @@ +/* + Copyright <2018-2025> + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +#ifndef REPERTORY_INCLUDE_EVENTS_TYPES_DRIVE_MOUNT_FAILED_HPP_ +#define REPERTORY_INCLUDE_EVENTS_TYPES_DRIVE_MOUNT_FAILED_HPP_ +#if defined(_WIN32) + +#include "events/i_event.hpp" +#include "types/repertory.hpp" + +namespace repertory { +struct drive_mount_failed final : public i_event { + drive_mount_failed() = default; + drive_mount_failed(std::string_view function_name_, + std::string mount_location_, NTSTATUS status_) + : function_name(std::string(function_name_)), + mount_location(std::move(mount_location_)), + status(status_) {} + + static constexpr const std::string_view name{"drive_mount_failed"}; + + std::string function_name; + std::string mount_location; + NTSTATUS status{}; + + [[nodiscard]] auto get_event_level() const -> event_level override { + return event_level::error; + } + + [[nodiscard]] auto get_name() const -> std::string_view override { + return name; + } + + [[nodiscard]] auto get_single_line() const -> std::string override { + return fmt::format("{}|func|{}|location|{}|status|{}", name, function_name, + mount_location, status); + } +}; +} // namespace repertory + +NLOHMANN_JSON_NAMESPACE_BEGIN +template <> struct adl_serializer { + static void to_json(json &data, const repertory::drive_mount_failed &value) { + data["function_name"] = value.function_name; + data["mount_location"] = value.mount_location; + data["status"] = value.status; + } + + static void from_json(const json &data, + repertory::drive_mount_failed &value) { + data.at("function_name").get_to(value.function_name); + data.at("mount_location").get_to(value.mount_location); + data.at("status").get_to(value.status); + } +}; +NLOHMANN_JSON_NAMESPACE_END + +#endif // defined(_WIN32) +#endif // REPERTORY_INCLUDE_EVENTS_TYPES_DRIVE_MOUNT_FAILED_HPP_ diff --git a/repertory/librepertory/include/events/types/drive_mount_result.hpp b/repertory/librepertory/include/events/types/drive_mount_result.hpp new file mode 100644 index 00000000..5077e68e --- /dev/null +++ b/repertory/librepertory/include/events/types/drive_mount_result.hpp @@ -0,0 +1,75 @@ +/* + Copyright <2018-2025> + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +#ifndef REPERTORY_INCLUDE_EVENTS_TYPES_DRIVE_MOUNT_RESULT_HPP_ +#define REPERTORY_INCLUDE_EVENTS_TYPES_DRIVE_MOUNT_RESULT_HPP_ + +#include "events/i_event.hpp" +#include "types/repertory.hpp" + +namespace repertory { +struct drive_mount_result final : public i_event { + drive_mount_result() = default; + drive_mount_result(std::string_view function_name_, + std::string mount_location_, std::string result_) + : function_name(std::string(function_name_)), + mount_location(std::move(mount_location_)), + result(std::move(result_)) {} + + static constexpr const std::string_view name{"drive_mount_result"}; + + std::string function_name; + std::string mount_location; + std::string result; + + [[nodiscard]] auto get_event_level() const -> event_level override { + return event_level::info; + } + + [[nodiscard]] auto get_name() const -> std::string_view override { + return name; + } + + [[nodiscard]] auto get_single_line() const -> std::string override { + return fmt::format("{}|func|{}|location|{}|result|{}", name, function_name, + mount_location, result); + } +}; +} // namespace repertory + +NLOHMANN_JSON_NAMESPACE_BEGIN +template <> struct adl_serializer { + static void to_json(json &data, const repertory::drive_mount_result &value) { + data["function_name"] = value.function_name; + data["mount_location"] = value.mount_location; + data["result"] = value.result; + } + + static void from_json(const json &data, + repertory::drive_mount_result &value) { + data.at("function_name").get_to(value.function_name); + data.at("mount_location").get_to(value.mount_location); + data.at("result").get_to(value.result); + } +}; +NLOHMANN_JSON_NAMESPACE_END + +#endif // REPERTORY_INCLUDE_EVENTS_TYPES_DRIVE_MOUNT_RESULT_HPP_ diff --git a/repertory/librepertory/include/events/types/drive_mounted.hpp b/repertory/librepertory/include/events/types/drive_mounted.hpp new file mode 100644 index 00000000..874f58f4 --- /dev/null +++ b/repertory/librepertory/include/events/types/drive_mounted.hpp @@ -0,0 +1,69 @@ +/* + Copyright <2018-2025> + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +#ifndef REPERTORY_INCLUDE_EVENTS_TYPES_DRIVE_MOUNTED_HPP_ +#define REPERTORY_INCLUDE_EVENTS_TYPES_DRIVE_MOUNTED_HPP_ + +#include "events/i_event.hpp" +#include "types/repertory.hpp" + +namespace repertory { +struct drive_mounted final : public i_event { + drive_mounted() = default; + drive_mounted(std::string_view function_name_, std::string mount_location_) + : function_name(std::string(function_name_)), + mount_location(std::move(mount_location_)) {} + + static constexpr const std::string_view name{"drive_mounted"}; + + std::string function_name; + std::string mount_location; + + [[nodiscard]] auto get_event_level() const -> event_level override { + return event_level::info; + } + + [[nodiscard]] auto get_name() const -> std::string_view override { + return name; + } + + [[nodiscard]] auto get_single_line() const -> std::string override { + return fmt::format("{}|func|{}|location|{}", name, function_name, + mount_location); + } +}; +} // namespace repertory + +NLOHMANN_JSON_NAMESPACE_BEGIN +template <> struct adl_serializer { + static void to_json(json &data, const repertory::drive_mounted &value) { + data["function_name"] = value.function_name; + data["mount_location"] = value.mount_location; + } + + static void from_json(const json &data, repertory::drive_mounted &value) { + data.at("function_name").get_to(value.function_name); + data.at("mount_location").get_to(value.mount_location); + } +}; +NLOHMANN_JSON_NAMESPACE_END + +#endif // REPERTORY_INCLUDE_EVENTS_TYPES_DRIVE_MOUNTED_HPP_ diff --git a/repertory/librepertory/src/drives/fuse/fuse_drive.cpp b/repertory/librepertory/src/drives/fuse/fuse_drive.cpp index 1fca30ee..04a579e0 100644 --- a/repertory/librepertory/src/drives/fuse/fuse_drive.cpp +++ b/repertory/librepertory/src/drives/fuse/fuse_drive.cpp @@ -31,7 +31,10 @@ #include "events/consumers/console_consumer.hpp" #include "events/consumers/logging_consumer.hpp" #include "events/event_system.hpp" +#include "events/event_system2.hpp" #include "events/events.hpp" +#include "events/types/drive_mount_result.hpp" +#include "events/types/drive_mounted.hpp" #include "platform/platform.hpp" #include "providers/i_provider.hpp" #include "rpc/server/full_server.hpp" @@ -576,6 +579,7 @@ void *fuse_drive::init_impl(struct fuse_conn_info *conn) { logging_consumer_ = std::make_unique( config_.get_event_level(), config_.get_log_directory()); event_system::instance().start(); + event_system2::instance().start(); was_mounted_ = true; fm_ = std::make_unique(config_, provider_); @@ -611,7 +615,8 @@ void *fuse_drive::init_impl(struct fuse_conn_info *conn) { utils::error::raise_error(function_name, "failed to set mount state"); } - event_system::instance().raise(get_mount_location()); + event_system2::instance().raise(function_name, + get_mount_location()); } catch (const std::exception &e) { utils::error::raise_error(function_name, e, "exception during fuse init"); @@ -659,8 +664,10 @@ auto fuse_drive::mkdir_impl(std::string api_path, mode_t mode) -> api_error { void fuse_drive::notify_fuse_main_exit(int &ret) { if (was_mounted_) { - event_system::instance().raise(std::to_string(ret)); + event_system2::instance().raise( + function_name, get_mount_location(), std::to_string(ret)); event_system::instance().stop(); + event_system2::instance().stop(); logging_consumer_.reset(); console_consumer_.reset(); } diff --git a/repertory/librepertory/src/drives/fuse/remotefuse/remote_fuse_drive.cpp b/repertory/librepertory/src/drives/fuse/remotefuse/remote_fuse_drive.cpp index a1699a08..16c740bc 100644 --- a/repertory/librepertory/src/drives/fuse/remotefuse/remote_fuse_drive.cpp +++ b/repertory/librepertory/src/drives/fuse/remotefuse/remote_fuse_drive.cpp @@ -28,7 +28,10 @@ #include "events/consumers/console_consumer.hpp" #include "events/consumers/logging_consumer.hpp" #include "events/event_system.hpp" +#include "events/event_system2.hpp" #include "events/events.hpp" +#include "events/types/drive_mount_result.hpp" +#include "events/types/drive_mounted.hpp" #include "platform/platform.hpp" #include "rpc/server/server.hpp" #include "types/remote.hpp" @@ -40,8 +43,8 @@ #include "utils/utils.hpp" namespace repertory::remote_fuse { -auto remote_fuse_drive::access_impl(std::string api_path, - int mask) -> api_error { +auto remote_fuse_drive::access_impl(std::string api_path, int mask) + -> api_error { return utils::to_api_error( remote_instance_->fuse_access(api_path.c_str(), mask)); } @@ -59,8 +62,8 @@ auto remote_fuse_drive::chmod_impl(std::string api_path, mode_t mode, struct fuse_file_info * /*f_info*/) -> api_error { #else -auto remote_fuse_drive::chmod_impl(std::string api_path, - mode_t mode) -> api_error { +auto remote_fuse_drive::chmod_impl(std::string api_path, mode_t mode) + -> api_error { #endif return utils::to_api_error(remote_instance_->fuse_chmod( api_path.c_str(), static_cast(mode))); @@ -71,8 +74,8 @@ auto remote_fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid, struct fuse_file_info * /*f_info*/) -> api_error { #else -auto remote_fuse_drive::chown_impl(std::string api_path, uid_t uid, - gid_t gid) -> api_error { +auto remote_fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid) + -> api_error { #endif return utils::to_api_error( remote_instance_->fuse_chown(api_path.c_str(), uid, gid)); @@ -116,9 +119,10 @@ void remote_fuse_drive::destroy_impl(void *ptr) { fuse_base::destroy_impl(ptr); } -auto remote_fuse_drive::fgetattr_impl( - std::string api_path, struct stat *unix_st, - struct fuse_file_info *f_info) -> api_error { +auto remote_fuse_drive::fgetattr_impl(std::string api_path, + struct stat *unix_st, + struct fuse_file_info *f_info) + -> api_error { remote::stat r_stat{}; auto directory = false; @@ -179,8 +183,8 @@ auto remote_fuse_drive::getattr_impl(std::string api_path, struct stat *unix_st, struct fuse_file_info * /*f_info*/) -> api_error { #else -auto remote_fuse_drive::getattr_impl(std::string api_path, - struct stat *unix_st) -> api_error { +auto remote_fuse_drive::getattr_impl(std::string api_path, struct stat *unix_st) + -> api_error { #endif bool directory = false; remote::stat r_stat{}; @@ -242,6 +246,7 @@ auto remote_fuse_drive::init_impl(struct fuse_conn_info *conn) -> void * { logging_consumer_ = std::make_shared( config_.get_event_level(), config_.get_log_directory()); event_system::instance().start(); + event_system2::instance().start(); if (not lock_data_.set_mount_state(true, get_mount_location(), getpid())) { utils::error::raise_error(function_name, "failed to set mount state"); @@ -257,22 +262,27 @@ auto remote_fuse_drive::init_impl(struct fuse_conn_info *conn) -> void * { } else { server_ = std::make_shared(config_); server_->start(); - event_system::instance().raise(get_mount_location()); + event_system2::instance().raise(function_name, + get_mount_location()); } return ret; } -auto remote_fuse_drive::mkdir_impl(std::string api_path, - mode_t mode) -> api_error { +auto remote_fuse_drive::mkdir_impl(std::string api_path, mode_t mode) + -> api_error { return utils::to_api_error(remote_instance_->fuse_mkdir( api_path.c_str(), static_cast(mode))); } void remote_fuse_drive::notify_fuse_main_exit(int &ret) { + REPERTORY_USES_FUNCTION_NAME(); + if (was_mounted_) { - event_system::instance().raise(std::to_string(ret)); + event_system2::instance().raise( + function_name, get_mount_location(), std::to_string(ret)); event_system::instance().stop(); + event_system2::instance().stop(); logging_consumer_.reset(); console_consumer_.reset(); } @@ -286,8 +296,9 @@ auto remote_fuse_drive::open_impl(std::string api_path, f_info->fh)); } -auto remote_fuse_drive::opendir_impl( - std::string api_path, struct fuse_file_info *f_info) -> api_error { +auto remote_fuse_drive::opendir_impl(std::string api_path, + struct fuse_file_info *f_info) + -> api_error { if ((f_info->flags & O_APPEND) == O_APPEND || (f_info->flags & O_EXCL) == O_EXCL) { return api_error::directory_exists; @@ -364,14 +375,18 @@ auto remote_fuse_drive::read_impl(std::string api_path, char *buffer, } #if FUSE_USE_VERSION >= 30 -auto remote_fuse_drive::readdir_impl( - std::string api_path, void *buf, fuse_fill_dir_t fuse_fill_dir, - off_t offset, struct fuse_file_info *f_info, - fuse_readdir_flags /*flags*/) -> api_error { +auto remote_fuse_drive::readdir_impl(std::string api_path, void *buf, + fuse_fill_dir_t fuse_fill_dir, + off_t offset, + struct fuse_file_info *f_info, + fuse_readdir_flags /*flags*/) + -> api_error { #else -auto remote_fuse_drive::readdir_impl( - std::string api_path, void *buf, fuse_fill_dir_t fuse_fill_dir, - off_t offset, struct fuse_file_info *f_info) -> api_error { +auto remote_fuse_drive::readdir_impl(std::string api_path, void *buf, + fuse_fill_dir_t fuse_fill_dir, + off_t offset, + struct fuse_file_info *f_info) + -> api_error { #endif std::string item_path; int res = 0; @@ -399,14 +414,16 @@ auto remote_fuse_drive::readdir_impl( return utils::to_api_error(res); } -auto remote_fuse_drive::release_impl( - std::string api_path, struct fuse_file_info *f_info) -> api_error { +auto remote_fuse_drive::release_impl(std::string api_path, + struct fuse_file_info *f_info) + -> api_error { return utils::to_api_error( remote_instance_->fuse_release(api_path.c_str(), f_info->fh)); } -auto remote_fuse_drive::releasedir_impl( - std::string api_path, struct fuse_file_info *f_info) -> api_error { +auto remote_fuse_drive::releasedir_impl(std::string api_path, + struct fuse_file_info *f_info) + -> api_error { return utils::to_api_error( remote_instance_->fuse_releasedir(api_path.c_str(), f_info->fh)); } @@ -503,8 +520,8 @@ api_error remote_fuse_drive::statfs_x_impl(std::string api_path, return utils::to_api_error(res); } #else // __APPLE__ -auto remote_fuse_drive::statfs_impl(std::string api_path, - struct statvfs *stbuf) -> api_error { +auto remote_fuse_drive::statfs_impl(std::string api_path, struct statvfs *stbuf) + -> api_error { auto res = statvfs(config_.get_data_directory().c_str(), stbuf); if (res == 0) { remote::statfs r_stat{}; @@ -531,8 +548,8 @@ auto remote_fuse_drive::truncate_impl(std::string api_path, off_t size, struct fuse_file_info * /*f_info*/) -> api_error { #else -auto remote_fuse_drive::truncate_impl(std::string api_path, - off_t size) -> api_error { +auto remote_fuse_drive::truncate_impl(std::string api_path, off_t size) + -> api_error { #endif return utils::to_api_error(remote_instance_->fuse_truncate( api_path.c_str(), static_cast(size))); @@ -543,9 +560,10 @@ auto remote_fuse_drive::unlink_impl(std::string api_path) -> api_error { } #if FUSE_USE_VERSION >= 30 -auto remote_fuse_drive::utimens_impl( - std::string api_path, const struct timespec tv[2], - struct fuse_file_info * /*f_info*/) -> api_error { +auto remote_fuse_drive::utimens_impl(std::string api_path, + const struct timespec tv[2], + struct fuse_file_info * /*f_info*/) + -> api_error { #else auto remote_fuse_drive::utimens_impl(std::string api_path, const struct timespec tv[2]) -> api_error { diff --git a/repertory/librepertory/src/drives/winfsp/remotewinfsp/remote_client.cpp b/repertory/librepertory/src/drives/winfsp/remotewinfsp/remote_client.cpp index d3cf35be..2d6a58fa 100644 --- a/repertory/librepertory/src/drives/winfsp/remotewinfsp/remote_client.cpp +++ b/repertory/librepertory/src/drives/winfsp/remotewinfsp/remote_client.cpp @@ -23,8 +23,9 @@ #include "app_config.hpp" #include "drives/winfsp/remotewinfsp/i_remote_instance.hpp" -#include "events/event_system.hpp" +#include "events/event_system2.hpp" #include "events/events.hpp" +#include "events/types/drive_mounted.hpp" #include "types/repertory.hpp" #include "utils/path.hpp" #include "version.hpp" @@ -361,7 +362,7 @@ auto remote_client::winfsp_mounted(const std::wstring &location) auto mount_location{ utils::string::to_utf8(location), }; - event_system::instance().raise(mount_location); + event_system2::instance().raise(function_name, mount_location); RAISE_REMOTE_WINFSP_CLIENT_EVENT(function_name, mount_location, ret); return ret; diff --git a/repertory/librepertory/src/drives/winfsp/remotewinfsp/remote_winfsp_drive.cpp b/repertory/librepertory/src/drives/winfsp/remotewinfsp/remote_winfsp_drive.cpp index b62c0af9..0e7d0447 100644 --- a/repertory/librepertory/src/drives/winfsp/remotewinfsp/remote_winfsp_drive.cpp +++ b/repertory/librepertory/src/drives/winfsp/remotewinfsp/remote_winfsp_drive.cpp @@ -26,7 +26,10 @@ #include "app_config.hpp" #include "events/consumers/console_consumer.hpp" #include "events/consumers/logging_consumer.hpp" +#include "events/event_system2.hpp" #include "events/events.hpp" +#include "events/types/drive_mount_failed.hpp" +#include "events/types/drive_mount_result.hpp" #include "platform/platform.hpp" #include "rpc/server/server.hpp" #include "utils/collection.hpp" @@ -74,8 +77,8 @@ auto remote_winfsp_drive::winfsp_service::OnStart(ULONG, PWSTR *) -> NTSTATUS { } if (ret != STATUS_SUCCESS) { - event_system::instance().raise(mount_location, - std::to_string(ret)); + event_system2::instance().raise( + function_name, mount_location, std::to_string(ret)); if (not lock_.set_mount_state(false, "", -1)) { utils::error::raise_error(function_name, "failed to set mount state"); } @@ -233,6 +236,8 @@ auto remote_winfsp_drive::Init(PVOID host) -> NTSTATUS { auto remote_winfsp_drive::mount(const std::vector &drive_args) -> int { + REPERTORY_USES_FUNCTION_NAME(); + std::vector parsed_drive_args; auto force_no_console = utils::collection::includes(drive_args, "-nc"); @@ -254,9 +259,14 @@ auto remote_winfsp_drive::mount(const std::vector &drive_args) c = std::make_unique(config_.get_event_level()); } event_system::instance().start(); + event_system2::instance().start(); + auto ret = winfsp_service(lock_, *this, parsed_drive_args, config_).Run(); - event_system::instance().raise(std::to_string(ret)); + + event_system2::instance().raise(function_name, "", + std::to_string(ret)); event_system::instance().stop(); + event_system2::instance().stop(); c.reset(); return static_cast(ret); } diff --git a/repertory/librepertory/src/drives/winfsp/winfsp_drive.cpp b/repertory/librepertory/src/drives/winfsp/winfsp_drive.cpp index e9bc705b..e952912c 100644 --- a/repertory/librepertory/src/drives/winfsp/winfsp_drive.cpp +++ b/repertory/librepertory/src/drives/winfsp/winfsp_drive.cpp @@ -27,7 +27,11 @@ #include "drives/directory_iterator.hpp" #include "events/consumers/console_consumer.hpp" #include "events/consumers/logging_consumer.hpp" +#include "events/event_system2.hpp" #include "events/events.hpp" +#include "events/types/drive_mount_failed.hpp" +#include "events/types/drive_mount_result.hpp" +#include "events/types/drive_mounted.hpp" #include "platform/platform.hpp" #include "providers/i_provider.hpp" #include "types/repertory.hpp" @@ -131,8 +135,8 @@ auto winfsp_drive::winfsp_service::OnStart(ULONG /*Argc*/, PWSTR * /*Argv*/) utils::error::raise_error(function_name, ret, "failed to set mount state"); } - event_system::instance().raise(mount_location, - std::to_string(ret)); + event_system2::instance().raise(function_name, + mount_location, ret); return ret; } @@ -619,12 +623,17 @@ auto winfsp_drive::mount(const std::vector &drive_args) -> int { if (enable_console) { cons = std::make_unique(config_.get_event_level()); } + event_system::instance().start(); + event_system2::instance().start(); + auto svc = winfsp_service(lock_, *this, parsed_drive_args, config_); auto ret = svc.Run(); - event_system::instance().raise(std::to_string(ret)); + event_system2::instance().raise(function_name, "", + std::to_string(ret)); event_system::instance().stop(); + event_system2::instance().stop(); cons.reset(); return static_cast(ret); @@ -676,7 +685,8 @@ auto winfsp_drive::Mounted(PVOID host) -> NTSTATUS { utils::error::raise_error(function_name, "failed to set mount state"); } - event_system::instance().raise(mount_location); + event_system2::instance().raise(function_name, + mount_location); return STATUS_SUCCESS; } catch (const std::exception &e) { utils::error::raise_error(function_name, e, "exception occurred"); diff --git a/repertory/librepertory/src/events/event_system_2.cpp b/repertory/librepertory/src/events/event_system_2.cpp new file mode 100644 index 00000000..0eb37ed9 --- /dev/null +++ b/repertory/librepertory/src/events/event_system_2.cpp @@ -0,0 +1,166 @@ +/* + Copyright <2018-2025> + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +#include "events/event_system2.hpp" + +#include "app_config.hpp" +#include "events/i_event.hpp" +#include "utils/collection.hpp" + +namespace repertory { +void event_system2::attach(event_consumer *consumer) { + recur_mutex_lock lock(consumer_mutex_); + event_consumers_[""].push_back(consumer); +} + +void event_system2::attach(std::string_view event_name, + event_consumer *consumer) { + recur_mutex_lock lock(consumer_mutex_); + event_consumers_[std::string{event_name}].push_back(consumer); +} + +[[nodiscard]] auto event_system2::get_stop_requested() const -> bool { + return stop_requested_ || app_config::get_stop_requested(); +} + +void event_system2::process_events() { + std::vector> events; + + unique_mutex_lock lock(event_mutex_); + const auto lock_and_notify = [this, &lock]() { + lock.lock(); + event_notify_.notify_all(); + lock.unlock(); + }; + + if (not get_stop_requested() && event_list_.empty()) { + event_notify_.wait_for(lock, queue_wait_secs); + } + + if (not event_list_.empty()) { + events.insert(events.end(), event_list_.begin(), event_list_.end()); + event_list_.clear(); + } + + lock.unlock(); + + if (events.empty()) { + lock_and_notify(); + return; + } + + const auto notify_events = [this](std::string_view name, + const i_event &event) { + std::deque> futures; + recur_mutex_lock consumer_lock(consumer_mutex_); + for (auto *consumer : event_consumers_[std::string{name}]) { + futures.emplace_back(std::async(std::launch::async, [consumer, &event]() { + consumer->notify_event(event); + })); + } + + while (not futures.empty()) { + futures.front().get(); + futures.pop_front(); + } + }; + + for (const auto &evt : events) { + notify_events("", *evt.get()); + notify_events(evt->get_name(), *evt.get()); + } + + lock_and_notify(); +} + +void event_system2::queue_event(std::shared_ptr evt) { + unique_mutex_lock lock(event_mutex_); + event_list_.push_back(std::move(evt)); + auto size = event_list_.size(); + event_notify_.notify_all(); + lock.unlock(); + + for (std::uint8_t retry{0U}; + size > max_queue_size && retry < max_queue_retry && + not get_stop_requested(); + ++retry) { + lock.lock(); + size = event_list_.size(); + if (size > max_queue_size) { + event_notify_.wait_for(lock, queue_wait_secs); + size = event_list_.size(); + } + + event_notify_.notify_all(); + lock.unlock(); + } +} + +void event_system2::release(event_consumer *consumer) { + recur_mutex_lock lock(consumer_mutex_); + auto iter = + std::ranges::find_if(event_consumers_, [&](const auto &item) -> bool { + return utils::collection::includes(item.second, consumer); + }); + + if (iter != event_consumers_.end()) { + utils::collection::remove_element((*iter).second, consumer); + } +} + +void event_system2::start() { + mutex_lock lock(run_mutex_); + if (event_thread_) { + event_notify_.notify_all(); + return; + } + + stop_requested_ = false; + + event_thread_ = std::make_unique([this]() { + while (not get_stop_requested()) { + process_events(); + } + }); + event_notify_.notify_all(); +} + +void event_system2::stop() { + unique_mutex_lock lock(run_mutex_); + if (not event_thread_) { + event_notify_.notify_all(); + return; + } + + stop_requested_ = true; + + std::unique_ptr thread{nullptr}; + std::swap(thread, event_thread_); + + event_notify_.notify_all(); + lock.unlock(); + + thread->join(); + thread.reset(); + + process_events(); +} +} // namespace repertory diff --git a/repertory/librepertory/src/providers/base_provider.cpp b/repertory/librepertory/src/providers/base_provider.cpp index bbbfdbd2..9179d1b2 100644 --- a/repertory/librepertory/src/providers/base_provider.cpp +++ b/repertory/librepertory/src/providers/base_provider.cpp @@ -24,7 +24,11 @@ #include "app_config.hpp" #include "db/meta_db.hpp" #include "events/event_system.hpp" +#include "events/event_system2.hpp" #include "events/events.hpp" +#include "events/types/directory_remove_failed.hpp" +#include "events/types/directory_removed.hpp" +#include "events/types/directory_removed_externally.hpp" #include "file_manager/cache_size_mgr.hpp" #include "file_manager/i_file_manager.hpp" #include "platform/platform.hpp" @@ -34,6 +38,7 @@ #include "utils/polling.hpp" #include "utils/tasks.hpp" #include "utils/time.hpp" +#include namespace repertory { void base_provider::add_all_items(stop_type &stop_requested) { @@ -442,6 +447,8 @@ auto base_provider::is_file_writeable(const std::string &api_path) const void base_provider::process_removed_directories( std::deque removed_list, stop_type &stop_requested) { + REPERTORY_USES_FUNCTION_NAME(); + const auto get_stop_requested = [&stop_requested]() -> bool { return stop_requested || app_config::get_stop_requested(); }; @@ -456,8 +463,8 @@ void base_provider::process_removed_directories( } db3_->remove_api_path(item.api_path); - event_system::instance().raise( - item.api_path, item.source_path); + event_system2::instance().raise( + item.api_path, function_name, item.source_path); } } @@ -655,12 +662,15 @@ auto base_provider::remove_file(const std::string &api_path) -> api_error { } auto base_provider::remove_directory(const std::string &api_path) -> api_error { + REPERTORY_USES_FUNCTION_NAME(); + const auto notify_end = [&api_path](api_error error) -> api_error { if (error == api_error::success) { - event_system::instance().raise(api_path); + event_system2::instance().raise(api_path, + function_name); } else { - event_system::instance().raise( - api_path, api_error_to_string(error)); + event_system2::instance().raise(api_path, error, + function_name); } return error; }; diff --git a/repertory/librepertory/src/providers/encrypt/encrypt_provider.cpp b/repertory/librepertory/src/providers/encrypt/encrypt_provider.cpp index cfca5392..35aa4892 100644 --- a/repertory/librepertory/src/providers/encrypt/encrypt_provider.cpp +++ b/repertory/librepertory/src/providers/encrypt/encrypt_provider.cpp @@ -23,7 +23,9 @@ #include "db/file_db.hpp" #include "events/event_system.hpp" +#include "events/event_system2.hpp" #include "events/events.hpp" +#include "events/types/directory_removed_externally.hpp" #include "types/repertory.hpp" #include "types/startup_exception.hpp" #include "utils/collection.hpp" @@ -849,8 +851,8 @@ void encrypt_provider::remove_deleted_files(stop_type &stop_requested) { } if (item.directory) { - event_system::instance().raise( - item.api_path, item.source_path); + event_system2::instance().raise( + item.api_path, function_name, item.source_path); continue; } diff --git a/repertory/librepertory/src/utils/utils.cpp b/repertory/librepertory/src/utils/utils.cpp index cc5d1b67..9949ef0b 100644 --- a/repertory/librepertory/src/utils/utils.cpp +++ b/repertory/librepertory/src/utils/utils.cpp @@ -57,7 +57,7 @@ auto create_rocksdb( auto db_dir = utils::path::combine(cfg.get_data_directory(), {"db"}); if (not utils::file::directory{db_dir}.create_directory()) { throw startup_exception( - fmt::format("failed to create db directory|", db_dir)); + fmt::format("failed to create db directory|{}", db_dir)); } auto path = utils::path::combine(db_dir, {name}); @@ -76,8 +76,8 @@ auto create_rocksdb( auto status = rocksdb::TransactionDB::Open( options, rocksdb::TransactionDBOptions{}, path, families, &handles, &ptr); if (not status.ok()) { - throw startup_exception(fmt::format("failed to open rocksdb|path{}|error{}", - path, status.ToString())); + throw startup_exception(fmt::format( + "failed to open rocksdb|path|{}|error{}", path, status.ToString())); } return std::unique_ptr(ptr); diff --git a/repertory/repertory_test/include/fixtures/file_db_fixture.hpp b/repertory/repertory_test/include/fixtures/file_db_fixture.hpp index a5964160..3987b2d4 100644 --- a/repertory/repertory_test/include/fixtures/file_db_fixture.hpp +++ b/repertory/repertory_test/include/fixtures/file_db_fixture.hpp @@ -42,6 +42,8 @@ protected: static std::uint64_t idx{}; event_system::instance().start(); + event_system2::instance().start(); + auto cfg_directory = utils::path::combine(test::get_test_output_dir(), { "file_db_test", @@ -55,6 +57,7 @@ protected: file_db.reset(); config.reset(); event_system::instance().stop(); + event_system2::instance().stop(); } }; diff --git a/repertory/repertory_test/include/fixtures/file_mgr_db_fixture.hpp b/repertory/repertory_test/include/fixtures/file_mgr_db_fixture.hpp index 4b272f61..1733de01 100644 --- a/repertory/repertory_test/include/fixtures/file_mgr_db_fixture.hpp +++ b/repertory/repertory_test/include/fixtures/file_mgr_db_fixture.hpp @@ -42,6 +42,8 @@ protected: static std::uint64_t idx{}; event_system::instance().start(); + event_system2::instance().start(); + auto cfg_directory = utils::path::combine(test::get_test_output_dir(), { "file_mgr_db_test", @@ -55,6 +57,7 @@ protected: file_mgr_db.reset(); config.reset(); event_system::instance().stop(); + event_system2::instance().stop(); } }; diff --git a/repertory/repertory_test/include/fixtures/meta_db_fixture.hpp b/repertory/repertory_test/include/fixtures/meta_db_fixture.hpp index 37b552c2..1f68c08a 100644 --- a/repertory/repertory_test/include/fixtures/meta_db_fixture.hpp +++ b/repertory/repertory_test/include/fixtures/meta_db_fixture.hpp @@ -42,6 +42,8 @@ protected: static std::uint64_t idx{}; event_system::instance().start(); + event_system2::instance().start(); + auto cfg_directory = utils::path::combine(test::get_test_output_dir(), { "meta_db_test", @@ -55,6 +57,7 @@ protected: meta_db.reset(); config.reset(); event_system::instance().stop(); + event_system2::instance().stop(); } }; diff --git a/repertory/repertory_test/include/test_common.hpp b/repertory/repertory_test/include/test_common.hpp index 030a06ea..0b943812 100644 --- a/repertory/repertory_test/include/test_common.hpp +++ b/repertory/repertory_test/include/test_common.hpp @@ -28,6 +28,7 @@ REPERTORY_IGNORE_WARNINGS_DISABLE() #include "events/consumers/console_consumer.hpp" #include "events/event_system.hpp" +#include "events/event_system2.hpp" #include "events/events.hpp" #endif // REPERTORY_TEST_INCLUDE_TEST_COMMON_HPP_ diff --git a/repertory/repertory_test/src/config_test.cpp b/repertory/repertory_test/src/config_test.cpp index 176dea5f..2eda652c 100644 --- a/repertory/repertory_test/src/config_test.cpp +++ b/repertory/repertory_test/src/config_test.cpp @@ -52,9 +52,13 @@ public: std::to_string(++idx), }); event_system::instance().start(); + event_system2::instance().start(); } - void TearDown() override { event_system::instance().stop(); } + void TearDown() override { + event_system::instance().stop(); + event_system2::instance().stop(); + } }; std::atomic config_test::idx{0U}; diff --git a/repertory/repertory_test/src/direct_open_file_test.cpp b/repertory/repertory_test/src/direct_open_file_test.cpp index 4e87491d..5de02038 100644 --- a/repertory/repertory_test/src/direct_open_file_test.cpp +++ b/repertory/repertory_test/src/direct_open_file_test.cpp @@ -35,9 +35,15 @@ public: mock_provider provider; protected: - void SetUp() override { event_system::instance().start(); } + void SetUp() override { + event_system::instance().start(); + event_system2::instance().start(); + } - void TearDown() override { event_system::instance().stop(); } + void TearDown() override { + event_system::instance().stop(); + event_system2::instance().stop(); + } }; TEST_F(direct_open_file_test, read_full_file) { diff --git a/repertory/repertory_test/src/file_manager_test.cpp b/repertory/repertory_test/src/file_manager_test.cpp index 47c02cd6..1d406bd8 100644 --- a/repertory/repertory_test/src/file_manager_test.cpp +++ b/repertory/repertory_test/src/file_manager_test.cpp @@ -61,6 +61,7 @@ public: protected: void SetUp() override { event_system::instance().start(); + event_system2::instance().start(); file_manager_dir = repertory::utils::path::combine( repertory::test::get_test_output_dir(), @@ -72,7 +73,10 @@ protected: cache_size_mgr::instance().initialize(cfg.get()); } - void TearDown() override { event_system::instance().stop(); } + void TearDown() override { + event_system::instance().stop(); + event_system2::instance().stop(); + } }; std::atomic file_manager_test::inst{0U}; diff --git a/repertory/repertory_test/src/open_file_test.cpp b/repertory/repertory_test/src/open_file_test.cpp index 1bb957a9..86bfc179 100644 --- a/repertory/repertory_test/src/open_file_test.cpp +++ b/repertory/repertory_test/src/open_file_test.cpp @@ -46,6 +46,7 @@ public: protected: void SetUp() override { event_system::instance().start(); + event_system2::instance().start(); auto open_file_dir = repertory::utils::path::combine( repertory::test::get_test_output_dir(), @@ -56,7 +57,10 @@ protected: cache_size_mgr::instance().initialize(cfg.get()); } - void TearDown() override { event_system::instance().stop(); } + void TearDown() override { + event_system::instance().stop(); + event_system2::instance().stop(); + } }; std::atomic open_file_test::inst{0U}; @@ -590,6 +594,7 @@ TEST_F(open_file_test, resize_file_by_full_chunk) { TEST_F(open_file_test, can_add_handle) { event_system::instance().start(); + event_system2::instance().start(); console_consumer c; const auto source_path = test::generate_test_file_name("file_manager_open_file_test"); @@ -644,12 +649,15 @@ TEST_F(open_file_test, can_add_handle) { capture.wait_for_empty(); event_system::instance().stop(); + event_system2::instance().stop(); } TEST_F(open_file_test, can_remove_handle) { - event_system::instance().start(); console_consumer c; + event_system::instance().start(); + event_system2::instance().start(); + const auto source_path = test::generate_test_file_name("file_manager_open_file_test"); @@ -706,6 +714,7 @@ TEST_F(open_file_test, can_remove_handle) { capture.wait_for_empty(); event_system::instance().stop(); + event_system2::instance().stop(); } TEST_F(open_file_test, diff --git a/repertory/repertory_test/src/providers_test.cpp b/repertory/repertory_test/src/providers_test.cpp index 7d028942..dd6b9e2c 100644 --- a/repertory/repertory_test/src/providers_test.cpp +++ b/repertory/repertory_test/src/providers_test.cpp @@ -635,6 +635,8 @@ TEST(providers, encrypt_provider) { console_consumer consumer{}; event_system::instance().start(); + event_system2::instance().start(); + { app_config cfg(provider_type::encrypt, config_path); @@ -668,7 +670,9 @@ TEST(providers, encrypt_provider) { provider.stop(); mgr.stop(); } + event_system::instance().stop(); + event_system2::instance().stop(); } TEST(providers, s3_provider) { @@ -677,6 +681,8 @@ TEST(providers, s3_provider) { console_consumer consumer{}; event_system::instance().start(); + event_system2::instance().start(); + { app_config cfg(provider_type::s3, config_path); { @@ -706,7 +712,9 @@ TEST(providers, s3_provider) { provider.stop(); mgr.stop(); } + event_system::instance().stop(); + event_system2::instance().stop(); } TEST(providers, sia_provider) { @@ -715,6 +723,8 @@ TEST(providers, sia_provider) { console_consumer consumer{}; event_system::instance().start(); + event_system2::instance().start(); + { app_config cfg(provider_type::sia, config_path); { @@ -744,7 +754,9 @@ TEST(providers, sia_provider) { provider.stop(); mgr.stop(); } + event_system::instance().stop(); + event_system2::instance().stop(); } } // namespace repertory diff --git a/repertory/repertory_test/src/ring_buffer_open_file_test.cpp b/repertory/repertory_test/src/ring_buffer_open_file_test.cpp index 6a660693..02e75ea7 100644 --- a/repertory/repertory_test/src/ring_buffer_open_file_test.cpp +++ b/repertory/repertory_test/src/ring_buffer_open_file_test.cpp @@ -45,9 +45,15 @@ public: mock_provider provider; protected: - void SetUp() override { event_system::instance().start(); } + void SetUp() override { + event_system::instance().start(); + event_system2::instance().start(); + } - void TearDown() override { event_system::instance().stop(); } + void TearDown() override { + event_system::instance().stop(); + event_system2::instance().stop(); + } }; TEST_F(ring_buffer_open_file_test, can_forward_to_last_chunk) { diff --git a/repertory/repertory_test/src/upload_test.cpp b/repertory/repertory_test/src/upload_test.cpp index 5b4f9af8..50140f4f 100644 --- a/repertory/repertory_test/src/upload_test.cpp +++ b/repertory/repertory_test/src/upload_test.cpp @@ -32,6 +32,7 @@ TEST(upload, can_upload_a_valid_file) { console_consumer con; event_system::instance().start(); + event_system2::instance().start(); const auto source_path = test::generate_test_file_name("upload_test"); @@ -69,12 +70,14 @@ TEST(upload, can_upload_a_valid_file) { EXPECT_FALSE(upload.is_cancelled()); event_system::instance().stop(); + event_system2::instance().stop(); } TEST(upload, can_cancel_upload) { console_consumer con; event_system::instance().start(); + event_system2::instance().start(); const auto source_path = test::generate_test_file_name("upload_test"); @@ -135,12 +138,14 @@ TEST(upload, can_cancel_upload) { EXPECT_TRUE(upload.is_cancelled()); event_system::instance().stop(); + event_system2::instance().stop(); } TEST(upload, can_stop_upload) { console_consumer con; event_system::instance().start(); + event_system2::instance().start(); const auto source_path = test::generate_test_file_name("upload_test"); @@ -173,10 +178,13 @@ TEST(upload, can_stop_upload) { event_capture evt_cap({"file_upload_completed"}); - { upload upload(fsi, mock_provider); } + { + upload upload(fsi, mock_provider); + } evt_cap.wait_for_empty(); event_system::instance().stop(); + event_system2::instance().stop(); } } // namespace repertory