diff --git a/CMakeLists.txt b/CMakeLists.txt index aa5fe3e..f18b1b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,8 +39,7 @@ CPMAddPackage("gh:nlohmann/json@${JSON_VERSION}") CPMAddPackage("gh:evan1026/blink1-lib@${BLINK1_LIB_VERSION}") CPMAddPackage("gh:jarro2783/cxxopts@${CXXOPTS_VERSION}") CPMAddPackage("gh:google/googletest@${GOOGLE_TEST_VERSION}#release-${GOOGLE_TEST_VERSION}") - -install_boost_library_recursively("asio" ${BOOST_VERSION}) +CPMAddPackage("gh:boostorg/boost@${BOOST_VERSION}#boost-${BOOST_VERSION}") set(GTEST_LIBRARIES gtest gtest_main gmock gmock_main) @@ -52,6 +51,7 @@ set(EXECUTABLE_NAME "blink1-control") set(SOURCES ${SOURCE_DIR}/config/ConfigParser.cpp ${SOURCE_DIR}/config/PatternCommand.cpp + ${SOURCE_DIR}/network/NetworkManager.cpp ) set(EXECUTABLE_SOURCES @@ -60,7 +60,7 @@ set(EXECUTABLE_SOURCES ) add_executable(${EXECUTABLE_NAME} ${EXECUTABLE_SOURCES}) -target_link_libraries(${EXECUTABLE_NAME} nlohmann_json Boost::asio cxxopts) +target_link_libraries(${EXECUTABLE_NAME} nlohmann_json Boost::asio Boost::thread cxxopts) set(WARNINGS "-Wall -Wextra -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wunused -Woverloaded-virtual -Wpedantic -Wconversion -Wsign-conversion") if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") @@ -113,7 +113,7 @@ set(TEST_SOURCES enable_testing() add_executable(${TEST_EXECUTABLE_NAME} ${TEST_SOURCES} ${SOURCES}) -target_link_libraries(${TEST_EXECUTABLE_NAME} ${GTEST_LIBRARIES} blink1-testing nlohmann_json) +target_link_libraries(${TEST_EXECUTABLE_NAME} ${GTEST_LIBRARIES} blink1-testing nlohmann_json Boost::asio Boost::thread) set_property(TARGET ${TEST_EXECUTABLE_NAME} PROPERTY CXX_STANDARD 20) include(GoogleTest) diff --git a/cmake/cpm_utilities.cmake b/cmake/cpm_utilities.cmake index 2efc144..e800fe2 100644 --- a/cmake/cpm_utilities.cmake +++ b/cmake/cpm_utilities.cmake @@ -1,32 +1,3 @@ -function(install_boost_library_recursively library_name boost_version) - CPMAddPackage( - NAME boost-${library_name} - VERSION ${boost_version} - GIT_TAG boost-${boost_version} - GITHUB_REPOSITORY "boostorg/${library_name}" - EXCLUDE_FROM_ALL yes - ) - - set(PROCESSED_BOOST_LIBRARIES "${PROCESSED_BOOST_LIBRARIES};${library_name}" CACHE INTERNAL "") - - set_target_properties(boost_${library_name} PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $) - get_target_property(libs Boost::${library_name} INTERFACE_LINK_LIBRARIES) - - while (libs) - - list(GET libs 0 first_library) - string(REPLACE "::" ";" library_name_parts ${first_library}) - list(GET library_name_parts 1 child_library_name) - - install_boost_library_recursively(${child_library_name} ${boost_version}) - - list(REMOVE_AT libs 0) - - endwhile() -endfunction() - - - function(install_cpm CPM_DOWNLOAD_VERSION) if(CPM_SOURCE_CACHE) set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") diff --git a/include/network.hpp b/include/network.hpp new file mode 100644 index 0000000..2d15867 --- /dev/null +++ b/include/network.hpp @@ -0,0 +1,19 @@ +/** + * @file network.hpp + * @brief Header file for blink1_control::network + * + * Including this file will give access to all classes within blink1_control::network + */ +#pragma once + +#include "network/NetworkManager.hpp" + +namespace blink1_control { + + /** + * Classes related to network connections + */ + namespace network { + + } +} diff --git a/include/network/NetworkManager.hpp b/include/network/NetworkManager.hpp new file mode 100644 index 0000000..5854e6f --- /dev/null +++ b/include/network/NetworkManager.hpp @@ -0,0 +1,64 @@ +/** + * @file NetworkManager.hpp + * @brief Header file for blink1_control::network::NetworkManager. + */ + +#pragma once + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-conversion" +#pragma GCC diagnostic ignored "-Wold-style-cast" +#pragma GCC diagnostic ignored "-Wshorten-64-to-32" +#pragma GCC diagnostic ignored "-Wshadow" +#include +#include +#pragma GCC diagnostic pop + +namespace blink1_control::network { + + /** + * This class creates and maintains network connections. + */ + class NetworkManager { + + std::shared_ptr ioc; + boost::asio::local::stream_protocol::endpoint endpoint; + boost::asio::local::stream_protocol::acceptor acceptor; + std::unique_ptr ioThread; + + void acceptHandler(const boost::system::error_code& error, boost::asio::local::stream_protocol::socket peer); + + void startAccept(); + + public: + + /** + * Constructor. + * + * @param socketPath The path to bind the socket to. + */ + NetworkManager(std::string_view socketPath); + + /** + * Destructor. + */ + ~NetworkManager(); + + NetworkManager(const NetworkManager& other) = delete; + NetworkManager(NetworkManager&& other) = delete; + NetworkManager& operator=(const NetworkManager& other) = delete; + NetworkManager& operator=(NetworkManager&& other) = delete; + + /** + * Starts the network I/O service. + */ + void start(); + + /** + * Stops the network I/O service. + */ + void stop(); + + }; + +} diff --git a/src/main.cpp b/src/main.cpp index 99ca5a2..bbd5e67 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,10 +5,10 @@ #include #include #include -#include #include "blink-lib.hpp" #include "config.hpp" +#include "network.hpp" #ifdef USE_BLINK1_TESTING_LIBRARY #include "Blink1TestingLibrary.hpp" @@ -69,25 +69,25 @@ void runPatterns(std::optional config) { while (LOOPING) { for (auto it = config->patternConfigs.begin(); it != config->patternConfigs.end() && LOOPING; ++it) { PatternConfig& pattern = *it->second; - std::cout << "Playing " << pattern.name << "\n"; +// std::cout << "Playing " << pattern.name << "\n"; - std::cout << " Playing before pattern\n"; +// std::cout << " Playing before pattern\n"; for (auto& patternLine : pattern.before) { - std::cout << " Playing " << *patternLine << "\n"; +// std::cout << " Playing " << *patternLine << "\n"; patternLine->execute(blinkDevice); } for (int i = 0; i < pattern.repeat && LOOPING; ++i) { - std::cout << " Playing iteration " << i << "/" << pattern.repeat << "\n"; +// std::cout << " Playing iteration " << i << "/" << pattern.repeat << "\n"; for (auto& patternLine : pattern.pattern) { - std::cout << " Playing " << *patternLine << "\n"; +// std::cout << " Playing " << *patternLine << "\n"; patternLine->execute(blinkDevice); } } - std::cout << " Playing after pattern\n"; +// std::cout << " Playing after pattern\n"; for (auto& patternLine : pattern.after) { - std::cout << " Playing " << *patternLine << "\n"; +// std::cout << " Playing " << *patternLine << "\n"; patternLine->execute(blinkDevice); } } @@ -98,9 +98,6 @@ void cleanSocketFile() { std::filesystem::remove("./blink1-control.sock"); } -namespace ba = boost::asio; -namespace bal = boost::asio::local; - int main(int argc, const char* argv[]) { signal(SIGINT, signalCallbackHandler); @@ -113,20 +110,16 @@ int main(int argc, const char* argv[]) { std::atexit(cleanSocketFile); - ba::io_context ioc; - bal::stream_protocol::endpoint ep("./blink1-control.sock"); - bal::stream_protocol::acceptor acceptor(ioc, ep); - bal::stream_protocol::socket socket(ioc); - - while (LOOPING) { - bal::stream_protocol::iostream clientIos; - acceptor.accept(clientIos.socket()); + blink1_control::network::NetworkManager networkManager(config->socketPath); - std::string data; - clientIos << "Hello, World!\n"; - std::getline(clientIos, data); - std::cout << data << "\n"; - } + std::cout << "Starting\n"; + networkManager.start(); + std::this_thread::sleep_for(std::chrono::seconds(1)); + std::cout << "Stopping\n"; + networkManager.stop(); + std::this_thread::sleep_for(std::chrono::seconds(1)); + std::cout << "Starting\n"; + networkManager.start(); runPatterns(config); } diff --git a/src/network/NetworkManager.cpp b/src/network/NetworkManager.cpp new file mode 100644 index 0000000..912056a --- /dev/null +++ b/src/network/NetworkManager.cpp @@ -0,0 +1,67 @@ +#include "network/NetworkManager.hpp" + +#include + +namespace b = boost; +namespace ba = boost::asio; +namespace bal = boost::asio::local; + +static void runIo(std::shared_ptr ioContext) { + ba::io_service::work work(*ioContext); + std::cout << "Starting I/O service\n"; + ioContext->run(); + std::cout << "I/O service finished\n"; +} + +namespace blink1_control::network { + + NetworkManager::NetworkManager(std::string_view socketPath) : + ioc(std::make_shared()), + endpoint(socketPath), + acceptor(*ioc, endpoint), + ioThread(nullptr) + {} + + NetworkManager::~NetworkManager() { + stop(); + } + + void NetworkManager::start() { + ioc->restart(); + acceptor.listen(); + startAccept(); + ioThread = std::make_unique(std::bind_front(&runIo, this->ioc)); + } + + void NetworkManager::stop() { + acceptor.cancel(); + ioc->stop(); + } + + void NetworkManager::startAccept() { + acceptor.async_accept(std::bind_front(&NetworkManager::acceptHandler, this)); + } + + void NetworkManager::acceptHandler(const b::system::error_code& error, bal::stream_protocol::socket peer) { + if (error) { + + if (error.value() != b::system::errc::operation_canceled) { + std::cout << "Error accepting connection: " << error.what() << "\n"; + } + + return; + } + + std::cout << "Got connection\n"; + bal::stream_protocol::iostream clientIos(std::move(peer)); + std::string data; + std::cout << "Outbound: \"Hello, World!\"\n"; + clientIos << "Hello, World!\n"; + std::getline(clientIos, data); + std::cout << "Inbound: " << data << "\n"; + std::cout << "Closing connection\n"; + + startAccept(); + } + +}