some refactor, addedd google loggin', corrected plugin handling
11 files modified
13 files added
4 files deleted
| | |
| | | build |
| | | # Compiled Object files |
| | | *.slo |
| | | *.lo |
| | |
| | | *.exe |
| | | *.out |
| | | *.app |
| | | build |
| | | .vscode |
| | |
| | | [submodule "external/serio"] |
| | | path = external/serio |
| | | url = https://github.com/ShahriarRezghi/serio.git |
| | | [submodule "external/cista"] |
| | | path = external/cista |
| | | url = https://github.com/felixguendling/cista.git |
| | | [submodule "src/plugins/TcpServerPlugin/external/sockets-cpp"] |
| | | path = src/plugins/TcpServerPlugin/external/sockets-cpp |
| | | url = https://github.com/CJLove/sockets-cpp.git |
| | | [submodule "external/tser"] |
| | | path = external/tser |
| | | url = https://github.com/KonanM/tser.git |
| | | [submodule "external/rocksdbwrapper"] |
| | | path = external/rocksdbwrapper |
| | | url = https://git.spamming.hu/r/fcloud/RocksDBWrapper.git |
| | |
| | | { |
| | | "files.associations": { |
| | | "string": "cpp" |
| | | "string": "cpp", |
| | | "ostream": "cpp", |
| | | "optional": "cpp", |
| | | "memory": "cpp", |
| | | "unordered_map": "cpp", |
| | | "condition_variable": "cpp", |
| | | "any": "cpp", |
| | | "array": "cpp", |
| | | "atomic": "cpp", |
| | | "bit": "cpp", |
| | | "*.tcc": "cpp", |
| | | "bitset": "cpp", |
| | | "cctype": "cpp", |
| | | "cfenv": "cpp", |
| | | "charconv": "cpp", |
| | | "chrono": "cpp", |
| | | "cinttypes": "cpp", |
| | | "clocale": "cpp", |
| | | "cmath": "cpp", |
| | | "codecvt": "cpp", |
| | | "compare": "cpp", |
| | | "complex": "cpp", |
| | | "concepts": "cpp", |
| | | "csignal": "cpp", |
| | | "cstdarg": "cpp", |
| | | "cstddef": "cpp", |
| | | "cstdint": "cpp", |
| | | "cstdio": "cpp", |
| | | "cstdlib": "cpp", |
| | | "cstring": "cpp", |
| | | "ctime": "cpp", |
| | | "cwchar": "cpp", |
| | | "cwctype": "cpp", |
| | | "deque": "cpp", |
| | | "forward_list": "cpp", |
| | | "list": "cpp", |
| | | "map": "cpp", |
| | | "set": "cpp", |
| | | "unordered_set": "cpp", |
| | | "vector": "cpp", |
| | | "exception": "cpp", |
| | | "expected": "cpp", |
| | | "algorithm": "cpp", |
| | | "functional": "cpp", |
| | | "iterator": "cpp", |
| | | "memory_resource": "cpp", |
| | | "numeric": "cpp", |
| | | "random": "cpp", |
| | | "ratio": "cpp", |
| | | "source_location": "cpp", |
| | | "string_view": "cpp", |
| | | "system_error": "cpp", |
| | | "tuple": "cpp", |
| | | "type_traits": "cpp", |
| | | "utility": "cpp", |
| | | "format": "cpp", |
| | | "fstream": "cpp", |
| | | "initializer_list": "cpp", |
| | | "iomanip": "cpp", |
| | | "iosfwd": "cpp", |
| | | "iostream": "cpp", |
| | | "istream": "cpp", |
| | | "limits": "cpp", |
| | | "mutex": "cpp", |
| | | "new": "cpp", |
| | | "numbers": "cpp", |
| | | "ranges": "cpp", |
| | | "semaphore": "cpp", |
| | | "span": "cpp", |
| | | "sstream": "cpp", |
| | | "stdexcept": "cpp", |
| | | "stop_token": "cpp", |
| | | "streambuf": "cpp", |
| | | "thread": "cpp", |
| | | "typeindex": "cpp", |
| | | "typeinfo": "cpp", |
| | | "valarray": "cpp", |
| | | "variant": "cpp", |
| | | "regex": "cpp" |
| | | } |
| | | } |
| | |
| | | cmake_minimum_required(VERSION 3.10) |
| | | project(MyServerProject) |
| | | set(PROJECT_NAME "FServer") |
| | | project(${PROJECT_NAME}) |
| | | |
| | | set(CMAKE_CXX_STANDARD 17) |
| | | set(CMAKE_CXX_STANDARD_REQUIRED True) |
| | | |
| | | |
| | | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") |
| | | set(CMAKE_LINKER_FLAGS "${CMAKE_LINKER_FLAGS} -fsanitize=address") |
| | | |
| | | # Add Address Sanitizer flags if available |
| | | find_library(ASAN_LIBRARY asan) |
| | | if (ASAN_LIBRARY) |
| | | message(STATUS "Address Sanitizer found: ${ASAN_LIBRARY}") |
| | | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") |
| | | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address") |
| | | else() |
| | | message(WARNING "Address Sanitizer not found. Proceeding without ASAN.") |
| | | endif() |
| | | |
| | | find_package (glog REQUIRED) |
| | | |
| | | # Include the nlohmann/json library |
| | | find_package(nlohmann_json REQUIRED) |
| | | find_package(msgpack REQUIRED) |
| | | |
| | | include_directories(${CMAKE_SOURCE_DIR}/src) |
| | | include_directories(${CMAKE_SOURCE_DIR}/plugins) |
| | | |
| | | add_subdirectory(external/serio) |
| | | # Add external libraries |
| | | add_subdirectory(external/tser) |
| | | |
| | | include_directories(${CMAKE_SOURCE_DIR}/external/tser/include) |
| | | |
| | | |
| | | # Set the output directories for executables and libraries |
| | | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) |
| | | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins) |
| | | |
| | | # Main server executable |
| | | add_executable(server |
| | | add_executable(${PROJECT_NAME} |
| | | src/main.cpp |
| | | src/Server.cpp |
| | | src/IPC.cpp |
| | |
| | | ) |
| | | |
| | | # Link libraries |
| | | target_link_libraries(server ${SERIO_LIBRARIES} nlohmann_json::nlohmann_json) |
| | | target_include_directories(server PUBLIC ${SERIO_INCLUDE_DIRS}) |
| | | message(STATUS "Serio: \n\t${SERIO_LIBRARIES} \n\t${SERIO_INCLUDE_DIRS}") |
| | | # Add the plugins subdirectory |
| | | add_subdirectory(src/plugins) |
| | | target_link_libraries(${PROJECT_NAME} nlohmann_json::nlohmann_json glog::glog) |
| | | |
| | | # Add the plugins subdirectories |
| | | add_subdirectory(${CMAKE_SOURCE_DIR}/src/plugins/SamplePlugin) |
| | | add_subdirectory(${CMAKE_SOURCE_DIR}/src/plugins/TcpServerPlugin) |
| | | add_subdirectory(${CMAKE_SOURCE_DIR}/src/plugins/DatabasePlugin) |
| New file |
| | |
| | | Subproject commit 3ac954922108b07fb3f7a7ce1c727bfcfad8b263 |
| New file |
| | |
| | | Subproject commit 9f44236de8fc9e1af5bbea443c8fe8b5a4952ec5 |
| | |
| | | #ifndef COMMAND_H |
| | | #define COMMAND_H |
| | | |
| | | #include <serio/serio.h> |
| | | #include <tser/tser.hpp> |
| | | #include <string> |
| | | #include <unordered_map> |
| | | #include <cstdint> |
| | | |
| | | // Define the command types as an enum |
| | | enum class CommandType { |
| | | enum class CommandType |
| | | { |
| | | PluginRegistered = 1000, |
| | | PluginList = 1001 |
| | | }; |
| | | SERIO_REGISTER(CommandType::PluginRegistered, CommandType::PluginList) |
| | | |
| | | // Map the CommandType enum to its string representation |
| | | static const std::unordered_map<CommandType, std::string> CommandTypeToString = { |
| | | {CommandType::PluginRegistered, "PluginRegistered"}, |
| | | {CommandType::PluginList, "PluginList"} |
| | | }; |
| | | {CommandType::PluginList, "PluginList"}}; |
| | | |
| | | |
| | | |
| | | struct Command { |
| | | struct Command |
| | | { |
| | | DEFINE_SERIALIZABLE(Command, commandType, payload) |
| | | CommandType commandType; |
| | | std::string payload; |
| | | |
| | | SERIO_REGISTER(commandType, payload); |
| | | }; |
| | | |
| | | #endif // COMMAND_H |
| | |
| | | #include "IPC.h" |
| | | #include <iostream> |
| | | |
| | | IPC::IPC() {} |
| | | IPC::IPC() |
| | | { |
| | | DLOG(INFO) << "IPC ready.. queue size at init: " << messageQueue.size(); |
| | | } |
| | | |
| | | void IPC::registerHandler(std::shared_ptr<IPlugin> handler) { |
| | | IPC::~IPC() |
| | | { |
| | | while (!messageQueue.empty()) |
| | | { |
| | | messageQueue.pop(); |
| | | } |
| | | } |
| | | |
| | | void IPC::registerHandler(std::shared_ptr<IPlugin> handler) |
| | | { |
| | | handlers.push_back(handler); |
| | | } |
| | | |
| | | void IPC::sendMessage(const Command& cmd) { |
| | | void IPC::sendMessage(const Command &cmd) |
| | | { |
| | | std::lock_guard<std::mutex> lock(queueMutex); |
| | | messageQueue.push(cmd); |
| | | } |
| | | std::lock_guard lock(queueMutex); |
| | | std::string val; |
| | | tser::Serialize(cmd, val); |
| | | messageQueue.push(std::move(val)); |
| | | queueCondVar.notify_one(); |
| | | } |
| | | |
| | | std::optional<Command> IPC::receiveMessage() { |
| | | std::optional<Command> IPC::receiveMessage() |
| | | { |
| | | std::unique_lock<std::mutex> lock(queueMutex); |
| | | queueCondVar.wait(lock, [this] { return !messageQueue.empty(); }); |
| | | queueCondVar.wait(lock, [this] |
| | | { return !messageQueue.empty(); }); |
| | | |
| | | if (!messageQueue.empty()) { |
| | | Command cmd = messageQueue.front(); |
| | | if (!messageQueue.empty()) |
| | | { |
| | | std::string a = std::move(messageQueue.front()); |
| | | messageQueue.pop(); |
| | | return cmd; |
| | | |
| | | Command c; |
| | | tser::DeSerialize(a, c); |
| | | return c; |
| | | } |
| | | return std::nullopt; |
| | | } |
| | |
| | | #ifndef IPC_H |
| | | #define IPC_H |
| | | |
| | | #include <msgpack.h> |
| | | #include <optional> |
| | | #include <queue> |
| | | #include <mutex> |
| | | #include <condition_variable> |
| | | #include "Command.h" |
| | | #include "PluginInterface.h" |
| | | #include <memory> |
| | | #include <optional> |
| | | #include "tser/tser.hpp" |
| | | #include "Serialize.h" |
| | | #include "PluginInterface.h" // Include your IPlugin interface header |
| | | #include "Command.h" // Include your Command structure header |
| | | #include <glog/logging.h> |
| | | |
| | | class IPC { |
| | | class IPC |
| | | { |
| | | public: |
| | | IPC(); |
| | | ~IPC(); |
| | | |
| | | void registerHandler(std::shared_ptr<IPlugin> handler); |
| | | void sendMessage(const Command& cmd); |
| | | std::optional<Command> receiveMessage(); |
| | | |
| | | private: |
| | | std::queue<Command> messageQueue; |
| | | std::queue<std::string> messageQueue; |
| | | std::vector<std::shared_ptr<IPlugin>> handlers; |
| | | std::mutex queueMutex; |
| | | std::condition_variable queueCondVar; |
| | | std::vector<std::shared_ptr<IPlugin>> handlers; |
| | | }; |
| | | |
| | | #endif // IPC_H |
| | |
| | | virtual ~IPlugin() = default; |
| | | virtual void handleMessage(const Command& cmd) = 0; |
| | | virtual void updateConfig(const nlohmann::json& config) = 0; |
| | | virtual const std::string getPluginName() = 0; |
| | | }; |
| | | |
| | | extern "C" IPlugin* create(); |
| | | |
| | | #endif // PLUGIN_INTERFACE_H |
| New file |
| | |
| | | #ifndef __SERIALIZE_H |
| | | #define __SERIALIZE_H |
| | | |
| | | #include <tser/tser.hpp> |
| | | |
| | | namespace tser |
| | | { |
| | | template <typename T> |
| | | inline void DeSerialize(const std::string &data, T &value) |
| | | { |
| | | tser::BinaryArchive archive(0); |
| | | archive.initialize(data); |
| | | value = archive.load<T>(); |
| | | }; |
| | | |
| | | template <typename T> |
| | | inline void Serialize(const T &value, std::string &data) |
| | | { |
| | | tser::BinaryArchive archive(0); |
| | | archive.save(value); |
| | | data = archive.get_buffer().data(); |
| | | }; |
| | | } |
| | | #endif |
| | |
| | | #include "Server.h" |
| | | #include <iostream> |
| | | #include <csignal> |
| | | #include <chrono> |
| | | |
| | | // Initialize the static instance pointer |
| | | Server* Server::instance = nullptr; |
| | | |
| | | Server::Server() : reloadConfigFlag(false) { |
| | | Server::Server() : reloadConfigFlag(false) |
| | | { |
| | | instance = this; // Set the instance pointer |
| | | ipc = std::make_unique<IPC>(); |
| | | signal(SIGUSR1, Server::handleSignal); |
| | | if (!config.loadFromFile("config.json")) { |
| | | if (!config.loadFromFile("/etc/fserver/config.json")) |
| | | { |
| | | std::cerr << "Failed to load config.json" << std::endl; |
| | | } |
| | | loadPlugins(); |
| | | for (int i = 0; i < 4; ++i) { |
| | | threadPool.emplace_back(std::make_unique<std::thread>(&Server::handleIPC, this)); |
| | | for (int i = 0; i < 4; ++i) |
| | | { |
| | | threadPool.emplace_back(&Server::handleIPC, this); |
| | | } |
| | | } |
| | | |
| | | Server::~Server() { |
| | | for (auto& handle : pluginHandles) { |
| | | Server::~Server() |
| | | { |
| | | // Join all threads |
| | | for (auto &thread : threadPool) |
| | | { |
| | | if (thread.joinable()) |
| | | { |
| | | thread.join(); |
| | | } |
| | | } |
| | | |
| | | // Close all plugin handles |
| | | for (auto &handle : pluginHandles) |
| | | { |
| | | dlclose(handle); |
| | | } |
| | | } |
| | | |
| | | Server& Server::getInstance() { |
| | | Server &Server::getInstance() |
| | | { |
| | | return *instance; |
| | | } |
| | | |
| | | void Server::run() { |
| | | void Server::run() |
| | | { |
| | | mainLoop(); |
| | | } |
| | | |
| | | void Server::reloadConfig() { |
| | | if (config.loadFromFile("config.json")) { |
| | | std::cout << "Configuration reloaded." << std::endl; |
| | | for (auto& plugin : plugins) { |
| | | plugin->updateConfig(config.getConfig()); |
| | | void Server::reloadConfig() |
| | | { |
| | | if (config.loadFromFile("/etc/fserver/config.json")) |
| | | { |
| | | // std::cout << "Configuration reloaded." << std::endl; |
| | | LOG(INFO) << "Configuration reloaded /etc/fserver/config.json"; |
| | | |
| | | // Stop and clear existing plugins |
| | | for (auto &plugin : plugins) |
| | | { |
| | | plugin->updateConfig({}); // Optionally reset plugin config |
| | | } |
| | | } else { |
| | | std::cerr << "Failed to reload configuration." << std::endl; |
| | | plugins.clear(); |
| | | |
| | | // Close and clear plugin handles |
| | | for (auto &handle : pluginHandles) |
| | | { |
| | | dlclose(handle); |
| | | } |
| | | pluginHandles.clear(); |
| | | |
| | | loadPlugins(); |
| | | } |
| | | else |
| | | { |
| | | LOG(ERROR) << "Failed to reload configuration"; |
| | | } |
| | | } |
| | | |
| | | void Server::loadPlugins() { |
| | | const char* pluginPath = "./plugins/libSamplePlugin.so"; |
| | | void* handle = dlopen(pluginPath, RTLD_LAZY); |
| | | if (!handle) { |
| | | std::cerr << "Cannot open library: " << dlerror() << '\n'; |
| | | return; |
| | | void Server::loadPlugins() |
| | | { |
| | | auto configData = config.getConfig(); |
| | | auto pluginsArray = configData["plugins"]; |
| | | for (const auto &pluginName : pluginsArray) |
| | | { |
| | | std::string pluginPath = "./plugins/" + pluginName.get<std::string>(); |
| | | void *handle = dlopen(pluginPath.c_str(), RTLD_LAZY); |
| | | if (!handle) |
| | | { |
| | | LOG(WARNING) << "Can not open lib: " << dlerror(); |
| | | continue; |
| | | } |
| | | pluginHandles.push_back(handle); |
| | | |
| | | typedef IPlugin* (*create_t)(); |
| | | typedef IPlugin *(*create_t)(IPC *); |
| | | create_t create_plugin = (create_t)dlsym(handle, "create"); |
| | | const char* dlsym_error = dlerror(); |
| | | if (dlsym_error) { |
| | | std::cerr << "Cannot load symbol create: " << dlsym_error << '\n'; |
| | | return; |
| | | if (dlsym_error) |
| | | { |
| | | LOG(ERROR) << "Cannot load symbol create: " << dlsym_error; |
| | | dlclose(handle); |
| | | continue; |
| | | } |
| | | |
| | | std::shared_ptr<IPlugin> plugin(create_plugin()); |
| | | std::shared_ptr<IPlugin> plugin(create_plugin(ipc.get())); |
| | | plugins.push_back(plugin); |
| | | ipc.registerHandler(plugin); |
| | | ipc->registerHandler(plugin); |
| | | plugin->updateConfig(config.getConfig()); // Forward the config to the plugin |
| | | LOG(INFO) << "Plugin loaded: " << plugin->getPluginName(); |
| | | } |
| | | } |
| | | |
| | | void Server::mainLoop() { |
| | | while (true) { |
| | | if (reloadConfigFlag.load()) { |
| | | void Server::mainLoop() |
| | | { |
| | | while (true) |
| | | { |
| | | if (reloadConfigFlag.load()) |
| | | { |
| | | reloadConfig(); |
| | | reloadConfigFlag.store(false); |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | void Server::handleIPC() { |
| | | while (true) { |
| | | auto message = ipc.receiveMessage(); |
| | | if (message.has_value()) { |
| | | for (auto& plugin : plugins) { |
| | | void Server::handleIPC() |
| | | { |
| | | while (true) |
| | | { |
| | | auto message = ipc->receiveMessage(); |
| | | if (message.has_value()) |
| | | { |
| | | for (auto &plugin : plugins) |
| | | { |
| | | plugin->handleMessage(message.value()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | void Server::handleSignal(int signal) { |
| | | if (signal == SIGUSR1) { |
| | | void Server::handleSignal(int signal) |
| | | { |
| | | if (signal == SIGUSR1) |
| | | { |
| | | std::cout << "Received signal to reload configuration." << std::endl; |
| | | Server::getInstance().reloadConfigFlag.store(true); |
| | | } |
| | |
| | | #include <memory> |
| | | #include <dlfcn.h> |
| | | #include <atomic> |
| | | #include <glog/logging.h> |
| | | #include "IPC.h" |
| | | #include "PluginInterface.h" |
| | | #include "Config.h" |
| | | |
| | | |
| | | class Server { |
| | | public: |
| | |
| | | void handleIPC(); |
| | | static void handleSignal(int signal); |
| | | |
| | | std::vector<std::unique_ptr<std::thread>> threadPool; |
| | | std::vector<std::thread> threadPool; // Use std::thread directly |
| | | std::vector<void*> pluginHandles; |
| | | std::vector<std::shared_ptr<IPlugin>> plugins; |
| | | IPC ipc; |
| | | std::unique_ptr<IPC> ipc; |
| | | Config config; |
| | | std::atomic<bool> reloadConfigFlag; |
| | | |
| | |
| | | #include "Server.h" |
| | | #include <iostream> |
| | | #include <glog/logging.h> |
| | | |
| | | int main() { |
| | | try { |
| | | LOG(INFO) << "Starting up server..."; |
| | | Server server; |
| | | server.run(); |
| | | } catch (const std::exception& e) { |
| | | LOG(FATAL) << "Exception: " << e.what(); |
| | | } |
| | | return 0; |
| | | } |
| New file |
| | |
| | | # Sample Plugin compilation |
| | | add_library(DataBasePlugin SHARED |
| | | DataBasePlugin.cpp |
| | | ) |
| | | |
| | | target_link_libraries(DataBasePlugin nlohmann_json::nlohmann_json) |
| | | target_include_directories(DataBasePlugin PUBLIC ${CMAKE_SOURCE_DIR}/external/rocksdbwrapper) |
| | | |
| | | # Set the output directory for the plugins |
| | | set_target_properties(DataBasePlugin PROPERTIES |
| | | LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins |
| | | ) |
| New file |
| | |
| | | #include "DataBasePlugin.h" |
| | | |
| | | extern "C" IPlugin *create(IPC *ipc) |
| | | { |
| | | return new DataBasePlugin(ipc); |
| | | } |
| | | |
| | | DataBasePlugin::DataBasePlugin(IPC* ipc) : ipc(ipc) |
| | | { |
| | | } |
| | | |
| | | void DataBasePlugin::handleMessage(const Command &cmd) |
| | | { |
| | | auto it = CommandTypeToString.find(cmd.commandType); |
| | | } |
| | | |
| | | void DataBasePlugin::updateConfig(const nlohmann::json &config) |
| | | { |
| | | DLOG(INFO) << "Updated plugin config: " << config.dump() << std::endl; |
| | | } |
| | | const std::string DataBasePlugin::getPluginName() { return this->plugin_name; } |
| New file |
| | |
| | | #ifndef DB_PLUGIN_H |
| | | #define DB_PLUGIN_H |
| | | |
| | | #include "PluginInterface.h" |
| | | #include "IPC.h" |
| | | #include <iostream> |
| | | #include <glog/logging.h> |
| | | #include "RocksDBWrapper.h" |
| | | |
| | | |
| | | class DataBasePlugin : public IPlugin |
| | | { |
| | | private: |
| | | IPC *ipc; |
| | | |
| | | public: |
| | | DataBasePlugin(IPC *ipc); |
| | | void handleMessage(const Command &cmd) override; |
| | | void updateConfig(const nlohmann::json &config) override; |
| | | const std::string getPluginName() override; |
| | | const std::string plugin_name = "RocksDB"; |
| | | }; |
| | | |
| | | #endif // DB_PLUGIN_H |
| New file |
| | |
| | | # Sample Plugin compilation |
| | | add_library(SamplePlugin SHARED |
| | | SamplePlugin.cpp |
| | | ) |
| | | |
| | | target_link_libraries(SamplePlugin nlohmann_json::nlohmann_json) |
| | | target_include_directories(SamplePlugin PUBLIC ${CMAKE_SOURCE_DIR}/external/cista/include) |
| | | |
| | | # Set the output directory for the plugins |
| | | set_target_properties(SamplePlugin PROPERTIES |
| | | LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins |
| | | ) |
| New file |
| | |
| | | #include "SamplePlugin.h" |
| | | |
| | | extern "C" IPlugin *create(IPC *ipc) |
| | | { |
| | | return new SamplePlugin(ipc); |
| | | } |
| | | |
| | | SamplePlugin::SamplePlugin(IPC* ipc) : ipc(ipc) |
| | | { |
| | | } |
| | | |
| | | void SamplePlugin::handleMessage(const Command &cmd) |
| | | { |
| | | auto it = CommandTypeToString.find(cmd.commandType); |
| | | if (it != CommandTypeToString.end()) |
| | | { |
| | | DLOG(INFO) << "Handled command: " << it->second << " with payload: " << cmd.payload; |
| | | } |
| | | } |
| | | |
| | | void SamplePlugin::updateConfig(const nlohmann::json &config) |
| | | { |
| | | DLOG(INFO) << "Updated plugin config: " << config.dump() << std::endl; |
| | | |
| | | } |
| | | |
| | | const std::string SamplePlugin::getPluginName() { return this->plugin_name; } |
| New file |
| | |
| | | #ifndef SAMPLE_PLUGIN_H |
| | | #define SAMPLE_PLUGIN_H |
| | | |
| | | #include "PluginInterface.h" |
| | | #include "IPC.h" |
| | | #include <iostream> |
| | | #include <glog/logging.h> |
| | | |
| | | class SamplePlugin : public IPlugin |
| | | { |
| | | private: |
| | | IPC *ipc; |
| | | |
| | | public: |
| | | SamplePlugin(IPC *ipc); |
| | | void handleMessage(const Command &cmd) override; |
| | | void updateConfig(const nlohmann::json &config) override; |
| | | const std::string getPluginName() override; |
| | | const std::string plugin_name = "SamplePlugin"; |
| | | }; |
| | | |
| | | #endif // SAMPLE_PLUGIN_H |
| New file |
| | |
| | | # Tcp Server Plugin compilation |
| | | add_library(TcpServerPlugin SHARED |
| | | TcpServerPlugin.cpp ${CMAKE_SOURCE_DIR}/src/IPC.cpp |
| | | ) |
| | | |
| | | include(ExternalProject) |
| | | ExternalProject_Add(socketscpp |
| | | GIT_REPOSITORY https://github.com/CJLove/sockets-cpp.git |
| | | GIT_TAG master |
| | | UPDATE_COMMAND "" |
| | | PATCH_COMMAND "" |
| | | CONFIGURE_COMMAND "" |
| | | BUILD_COMMAND "" |
| | | INSTALL_COMMAND "" |
| | | LOG_DOWNLOAD ON |
| | | ) |
| | | |
| | | # Set include directories for socketscpp |
| | | ExternalProject_Get_Property(socketscpp source_dir) |
| | | set(SOCKETSCPP_INCLUDE_DIR ${source_dir}/include/sockets-cpp) |
| | | |
| | | target_link_libraries(TcpServerPlugin nlohmann_json::nlohmann_json) |
| | | target_include_directories(TcpServerPlugin PUBLIC ${SOCKETSCPP_INCLUDE_DIR}) |
| | | |
| | | # Set the output directory for the plugins |
| | | set_target_properties(TcpServerPlugin PROPERTIES |
| | | LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins |
| | | ) |
| | | |
| | | |
| | | add_dependencies(TcpServerPlugin socketscpp) |
| New file |
| | |
| | | #include "TcpServerPlugin.h" |
| | | #include <iostream> |
| | | |
| | | TcpServerPlugin::TcpServerPlugin(IPC *ipc) : ipc(ipc), running(false) |
| | | { |
| | | DLOG(INFO) << "TcpServerPlugin constructor called"; |
| | | } |
| | | |
| | | TcpServerPlugin::~TcpServerPlugin() |
| | | { |
| | | DLOG(INFO) << "TcpServerPlugin destructor called"; |
| | | stopServer(); |
| | | } |
| | | |
| | | void TcpServerPlugin::handleMessage(const Command &cmd) |
| | | { |
| | | DLOG(INFO) << "TcpServerPlugin::handleMessage called with command: " << CommandTypeToString.at(cmd.commandType); |
| | | } |
| | | |
| | | void TcpServerPlugin::updateConfig(const nlohmann::json &config) |
| | | { |
| | | DLOG(INFO) << "TcpServerPlugin::updateConfig called"; |
| | | this->config = config; |
| | | if (running) |
| | | { |
| | | stopServer(); |
| | | } |
| | | startServer(); |
| | | } |
| | | |
| | | const std::string TcpServerPlugin::getPluginName() |
| | | { |
| | | return this->plugin_name; |
| | | } |
| | | |
| | | void TcpServerPlugin::startServer() |
| | | { |
| | | DLOG(INFO) << "TcpServerPlugin::startServer called"; |
| | | |
| | | sockets::SocketOpt options; |
| | | options.m_listenAddr = config["listen_addr"].get<std::string>(); |
| | | |
| | | options.m_rxBufSize = 65536; |
| | | options.m_txBufSize = 65536; |
| | | if (config.contains("rxBufSize")) |
| | | { |
| | | options.m_rxBufSize = config["rxBufSize"].get<int>(); |
| | | } |
| | | if (config.contains("txBufSize")) |
| | | { |
| | | options.m_txBufSize = config["txBufSize"].get<int>(); |
| | | } |
| | | |
| | | server = std::make_unique<sockets::TcpServer<TcpServerPlugin>>(*this, &options); |
| | | auto result = server->start(config["port"].get<uint16_t>()); |
| | | if (!result.m_success) |
| | | { |
| | | LOG(FATAL) << "Failed to start TCP server: " << result.m_msg; |
| | | return; |
| | | } |
| | | |
| | | running = true; |
| | | |
| | | Command cmd; |
| | | cmd.commandType = CommandType::PluginRegistered; |
| | | cmd.payload = "TCP Server started"; |
| | | ipc->sendMessage(cmd); |
| | | } |
| | | |
| | | void TcpServerPlugin::stopServer() |
| | | { |
| | | DLOG(INFO) << "TcpServerPlugin::stopServer called"; |
| | | |
| | | if (server) |
| | | { |
| | | server->finish(); |
| | | server.reset(); |
| | | } |
| | | |
| | | running = false; |
| | | |
| | | Command cmd; |
| | | cmd.commandType = CommandType::PluginList; |
| | | cmd.payload = "TCP Server stopped"; |
| | | ipc->sendMessage(cmd); |
| | | } |
| | | |
| | | void TcpServerPlugin::onClientConnect(sockets::ClientHandle client) |
| | | { |
| | | Command cmd; |
| | | cmd.commandType = CommandType::PluginRegistered; |
| | | cmd.payload = "New client connected: " + std::to_string(client); |
| | | ipc->sendMessage(cmd); |
| | | DLOG(INFO) << "New client connected: " + std::to_string(client); |
| | | } |
| | | |
| | | void TcpServerPlugin::onClientDisconnect(sockets::ClientHandle client, const sockets::SocketRet &ret) |
| | | { |
| | | Command cmd; |
| | | cmd.commandType = CommandType::PluginRegistered; |
| | | cmd.payload = "Client disconnected: " + std::to_string(client); |
| | | ipc->sendMessage(cmd); |
| | | DLOG(INFO) << "Client disconnected: " + std::to_string(client); |
| | | } |
| | | |
| | | void TcpServerPlugin::onReceiveClientData(sockets::ClientHandle client, const char *data, size_t size) |
| | | { |
| | | std::string message(data, size); |
| | | |
| | | Command cmd; |
| | | cmd.commandType = CommandType::PluginRegistered; |
| | | cmd.payload = "Message from client: " + message; |
| | | ipc->sendMessage(cmd); |
| | | |
| | | // Echo back the message to the client |
| | | server->sendClientMessage(client, data, size); |
| | | } |
| | | |
| | | extern "C" IPlugin *create(IPC *ipc) |
| | | { |
| | | return new TcpServerPlugin(ipc); |
| | | } |
| New file |
| | |
| | | #ifndef TCPSERVERPLUGIN_H |
| | | #define TCPSERVERPLUGIN_H |
| | | |
| | | #include "PluginInterface.h" |
| | | #include "IPC.h" |
| | | #include <nlohmann/json.hpp> |
| | | #include <memory> |
| | | #include <TcpServer.h> |
| | | #include <glog/logging.h> |
| | | |
| | | class TcpServerPlugin : public IPlugin { |
| | | public: |
| | | TcpServerPlugin(IPC *ipc); |
| | | ~TcpServerPlugin(); |
| | | |
| | | void handleMessage(const Command& cmd) override; |
| | | void updateConfig(const nlohmann::json& config) override; |
| | | const std::string getPluginName() override; |
| | | |
| | | void onClientConnect(sockets::ClientHandle client); |
| | | void onClientDisconnect(sockets::ClientHandle client, const sockets::SocketRet& ret); |
| | | void onReceiveClientData(sockets::ClientHandle client, const char* data, size_t size); |
| | | |
| | | const std::string plugin_name = "TcpServer"; |
| | | |
| | | private: |
| | | void startServer(); |
| | | void stopServer(); |
| | | |
| | | IPC *ipc; |
| | | nlohmann::json config; |
| | | bool running; |
| | | std::unique_ptr<sockets::TcpServer<TcpServerPlugin>> server; |
| | | }; |
| | | |
| | | extern "C" IPlugin* create(IPC * ipc); |
| | | |
| | | #endif // TCPSERVERPLUGIN_H |
| New file |
| | |
| | | Subproject commit 4b46f598c7e64011a5f244eee80d57963d5decd1 |