From 562c65840ccc9a16091f5504aa65a23f31bbf8a9 Mon Sep 17 00:00:00 2001 From: kj16609 Date: Tue, 30 Jul 2024 23:12:36 -0400 Subject: [PATCH] Restart yet again, This time with passion --- .gitmodules | 21 +++ CMakeLists.txt | 37 ++-- {src/IDHAN => IDHAN}/CMakeLists.txt | 6 +- IDHANClient/CMakeLists.txt | 6 + IDHANClient/include/idhan/ClientContext.hpp | 15 ++ IDHANClient/src/ClientContext.cpp | 10 ++ IDHANServer/CMakeLists.txt | 10 ++ .../include/idhan/ConnectionArguments.hpp | 27 +++ IDHANServer/include/idhan/ServerContext.hpp | 27 +++ IDHANServer/include/idhan/logging/log.hpp | 47 ++++++ IDHANServer/include/idhan/versions.hpp | 10 ++ IDHANServer/main.cpp | 23 +++ IDHANServer/src/ServerContext.cpp | 80 +++++++++ IDHANServer/src/core/Database.cpp | 158 ++++++++++++++++++ IDHANServer/src/core/Database.hpp | 27 +++ IDHANServer/src/core/records.cpp | 23 +++ IDHANServer/src/core/records.hpp | 27 +++ IDHANServer/src/crypto/sha256.hpp | 16 ++ IDHANServer/src/fixme.hpp | 18 ++ IDHANServer/src/hyapi/access.cpp | 87 ++++++++++ IDHANServer/src/hyapi/files.cpp | 21 +++ IDHANServer/src/hyapi/services.cpp | 41 +++++ IDHANServer/src/hyapi/setups.hpp | 12 ++ dependencies/Catch.cmake | 1 + dependencies/drogon | 1 + dependencies/drogon.cmake | 1 + dependencies/libpqxx | 1 + dependencies/postgres.cmake | 1 + dependencies/spdlog.cmake | 3 + dependencies/sqlite3.cmake | 1 + docs/server/main.tex | 81 +++++++++ fgl_cmake_modules | 1 + src/CMakeLists.txt | 4 - src/IDHAN/include/idhan/MessageHeader.hpp | 30 ---- src/IDHAN/include/idhan/net_constants.hpp | 12 -- .../include/idhan/requests/NetRequestInfo.hpp | 24 --- .../idhan/requests/NetResponseInfo.hpp | 14 -- .../include/idhan/requests/VersionInfo.hpp | 33 ---- src/IDHAN/include/idhan/requests/concepts.hpp | 33 ---- src/IDHAN/include/idhan/version.hpp | 39 ----- src/IDHAN/src/version.cpp | 5 - src/IDHANClient/CMakeLists.txt | 16 -- .../include/idhan/client/ClientContext.hpp | 82 --------- .../include/idhan/client/DatabaseContext.hpp | 5 - .../include/idhan/client/TagContext.hpp | 5 - src/IDHANClient/src/ClientContext.cpp | 78 --------- src/IDHANClient/src/DatabaseContext.cpp | 3 - src/IDHANClient/src/TagContext.cpp | 3 - src/IDHANServer/CMakeLists.txt | 15 -- .../include/idhan/server/ServerContext.hpp | 64 ------- src/IDHANServer/src/ServerContext.cpp | 135 --------------- tests/CMakeLists.txt | 6 +- tests/src/server.cpp | 34 +--- 53 files changed, 817 insertions(+), 663 deletions(-) rename {src/IDHAN => IDHAN}/CMakeLists.txt (54%) create mode 100644 IDHANClient/CMakeLists.txt create mode 100644 IDHANClient/include/idhan/ClientContext.hpp create mode 100644 IDHANClient/src/ClientContext.cpp create mode 100644 IDHANServer/CMakeLists.txt create mode 100644 IDHANServer/include/idhan/ConnectionArguments.hpp create mode 100644 IDHANServer/include/idhan/ServerContext.hpp create mode 100644 IDHANServer/include/idhan/logging/log.hpp create mode 100644 IDHANServer/include/idhan/versions.hpp create mode 100644 IDHANServer/main.cpp create mode 100644 IDHANServer/src/ServerContext.cpp create mode 100644 IDHANServer/src/core/Database.cpp create mode 100644 IDHANServer/src/core/Database.hpp create mode 100644 IDHANServer/src/core/records.cpp create mode 100644 IDHANServer/src/core/records.hpp create mode 100644 IDHANServer/src/crypto/sha256.hpp create mode 100644 IDHANServer/src/fixme.hpp create mode 100644 IDHANServer/src/hyapi/access.cpp create mode 100644 IDHANServer/src/hyapi/files.cpp create mode 100644 IDHANServer/src/hyapi/services.cpp create mode 100644 IDHANServer/src/hyapi/setups.hpp create mode 100644 dependencies/Catch.cmake create mode 160000 dependencies/drogon create mode 100644 dependencies/drogon.cmake create mode 160000 dependencies/libpqxx create mode 100644 dependencies/postgres.cmake create mode 100644 dependencies/spdlog.cmake create mode 100644 dependencies/sqlite3.cmake create mode 100644 docs/server/main.tex create mode 160000 fgl_cmake_modules delete mode 100644 src/CMakeLists.txt delete mode 100644 src/IDHAN/include/idhan/MessageHeader.hpp delete mode 100644 src/IDHAN/include/idhan/net_constants.hpp delete mode 100644 src/IDHAN/include/idhan/requests/NetRequestInfo.hpp delete mode 100644 src/IDHAN/include/idhan/requests/NetResponseInfo.hpp delete mode 100644 src/IDHAN/include/idhan/requests/VersionInfo.hpp delete mode 100644 src/IDHAN/include/idhan/requests/concepts.hpp delete mode 100644 src/IDHAN/include/idhan/version.hpp delete mode 100644 src/IDHAN/src/version.cpp delete mode 100644 src/IDHANClient/CMakeLists.txt delete mode 100644 src/IDHANClient/include/idhan/client/ClientContext.hpp delete mode 100644 src/IDHANClient/include/idhan/client/DatabaseContext.hpp delete mode 100644 src/IDHANClient/include/idhan/client/TagContext.hpp delete mode 100644 src/IDHANClient/src/ClientContext.cpp delete mode 100644 src/IDHANClient/src/DatabaseContext.cpp delete mode 100644 src/IDHANClient/src/TagContext.cpp delete mode 100644 src/IDHANServer/CMakeLists.txt delete mode 100644 src/IDHANServer/include/idhan/server/ServerContext.hpp delete mode 100644 src/IDHANServer/src/ServerContext.cpp diff --git a/.gitmodules b/.gitmodules index 77e13bf..552eaa1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,24 @@ [submodule "dependencies/spdlog"] path = dependencies/spdlog url = https://github.com/gabime/spdlog.git +[submodule "submodules/websocket"] + path = submodules/websocket + url = https://gitlab.com/eidheim/Simple-WebSocket-Server.git +[submodule "submodules/webserver"] + path = submodules/webserver + url = https://github.com/dendisuhubdy/asio-webserver.git +[submodule "dependencies/drogon"] + path = dependencies/drogon + url = https://github.com/drogonframework/drogon.git +[submodule "fgl_cmake_modules"] + path = fgl_cmake_modules + url = git@github.com:KJNeko/fgl_cmake_modules.git +[submodule "dependencies/libpqxx"] + path = dependencies/libpqxx + url = https://github.com/jtv/libpqxx.git +[submodule "dependencies/postgres"] + path = dependencies/postgres + url = https://github.com/postgres/postgres.git +[submodule "dependencies/sqlite3"] + path = dependencies/sqlite3 + url = https://github.com/sqlite/sqlite.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 154909f..f70495a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,37 +1,26 @@ # /CMakeLists.txt cmake_minimum_required(VERSION 3.25.0) -project(Game LANGUAGES CXX) +project(IDHAN LANGUAGES CXX) enable_testing() -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/fgl_cmake_modules) -set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_MESSAGE_LOG_LEVEL DEBUG CACHE STRING "CMake messaging level") +PreSetup() -file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/bin/data) +include(Catch) +include(spdlog) +include(postgres) +include(sqlite3) +include(drogon) -#Enable cmake_modules -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules") -include(common) - -message("-- CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}") -string(TOUPPER ${CMAKE_BUILD_TYPE} UPPER_BUILD_TYPE) - -PlatformPreSetup() -CompilerPreSetup() -message("-- FGL_FLAGS: ${FGL_FLAGS}") - -include(dependencies/catch2) -include(dependencies/openssl) -include(dependencies/asio) -include(dependencies/spdlog) - -add_subdirectory(src) +#add_subdirectory(IDHAN) +add_subdirectory(IDHANServer) +add_subdirectory(IDHANClient) add_subdirectory(tests) -SetVersionInfo() -CompilerPostSetup() \ No newline at end of file +PostSetup() \ No newline at end of file diff --git a/src/IDHAN/CMakeLists.txt b/IDHAN/CMakeLists.txt similarity index 54% rename from src/IDHAN/CMakeLists.txt rename to IDHAN/CMakeLists.txt index a534caf..7947ea4 100644 --- a/src/IDHAN/CMakeLists.txt +++ b/IDHAN/CMakeLists.txt @@ -5,8 +5,10 @@ file(GLOB_RECURSE LIB_IDHAN_HEADERS "include/*.hpp") add_library(IDHAN SHARED ${LIB_IDHAN_SOURCES} ${LIB_IDHAN_HEADERS}) -target_include_directories(IDHAN PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) -target_include_directories(IDHAN PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) +target_include_directories(IDHAN PRIVATE src) +target_include_directories(IDHAN PUBLIC include) + + diff --git a/IDHANClient/CMakeLists.txt b/IDHANClient/CMakeLists.txt new file mode 100644 index 0000000..3385b9d --- /dev/null +++ b/IDHANClient/CMakeLists.txt @@ -0,0 +1,6 @@ + + +file(GLOB_RECURSE LIB_IDHAN_CLIENT_SOURCES "src/**.cpp") +file(GLOB_RECURSE LIB_IDHAN_CLIENT_HEADERS "include/**.hpp") + +AddFGLLibrary(LibIDHANClient SHARED ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/IDHANClient/include/idhan/ClientContext.hpp b/IDHANClient/include/idhan/ClientContext.hpp new file mode 100644 index 0000000..aba089d --- /dev/null +++ b/IDHANClient/include/idhan/ClientContext.hpp @@ -0,0 +1,15 @@ +// +// Created by kj16609 on 7/23/24. +// + +#pragma once + + +namespace idhan +{ + + class Client + {}; + + +} diff --git a/IDHANClient/src/ClientContext.cpp b/IDHANClient/src/ClientContext.cpp new file mode 100644 index 0000000..f435375 --- /dev/null +++ b/IDHANClient/src/ClientContext.cpp @@ -0,0 +1,10 @@ +// +// Created by kj16609 on 7/23/24. +// + +#include "ClientContext.hpp" + +namespace idhan +{ + +} diff --git a/IDHANServer/CMakeLists.txt b/IDHANServer/CMakeLists.txt new file mode 100644 index 0000000..809c43c --- /dev/null +++ b/IDHANServer/CMakeLists.txt @@ -0,0 +1,10 @@ + + +AddFGLLibrary(LibIDHANServer OBJECT ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/include) +target_link_libraries(LibIDHANServer PUBLIC spdlog fmt drogon) +target_link_libraries(LibIDHANServer PRIVATE pqxx sqlite3) +target_include_directories(LibIDHANServer PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) + +add_executable(IDHANServer main.cpp) +SetFGLFlags(IDHANServer) +target_link_libraries(IDHANServer LibIDHANServer) diff --git a/IDHANServer/include/idhan/ConnectionArguments.hpp b/IDHANServer/include/idhan/ConnectionArguments.hpp new file mode 100644 index 0000000..0faa3a6 --- /dev/null +++ b/IDHANServer/include/idhan/ConnectionArguments.hpp @@ -0,0 +1,27 @@ +// +// Created by kj16609 on 7/24/24. +// + +#pragma once + +#include +#include + +#ifndef IDHAN_DEFAULT_POSTRES_PORT +constexpr std::uint16_t IDHAN_DEFAULT_POSTGRES_PORT { 5432 }; +#endif + +namespace idhan +{ + + struct ConnectionArguments + { + std::string hostname { "" }; + std::uint16_t port { IDHAN_DEFAULT_POSTGRES_PORT }; + std::string dbname { "idhan-db" }; + std::string user { "idhan" }; + + std::string format() const; + }; + +} // namespace idhan \ No newline at end of file diff --git a/IDHANServer/include/idhan/ServerContext.hpp b/IDHANServer/include/idhan/ServerContext.hpp new file mode 100644 index 0000000..3e33d3b --- /dev/null +++ b/IDHANServer/include/idhan/ServerContext.hpp @@ -0,0 +1,27 @@ +// +// Created by kj16609 on 7/23/24. +// + +#pragma once +#include + +namespace idhan +{ + struct ConnectionArguments; + class Database; + + class ServerContext + { + std::unique_ptr< Database > m_db; + + public: + + ServerContext() = delete; + + ServerContext( const ConnectionArguments& arguments ); + void run(); + + ~ServerContext(); + }; + +} // namespace idhan diff --git a/IDHANServer/include/idhan/logging/log.hpp b/IDHANServer/include/idhan/logging/log.hpp new file mode 100644 index 0000000..ee061d5 --- /dev/null +++ b/IDHANServer/include/idhan/logging/log.hpp @@ -0,0 +1,47 @@ +// +// Created by kj16609 on 7/23/24. +// + +#pragma once + +#include + +#include + +namespace idhan::log +{ + + template < typename... Ts > + void debug( const std::string str, Ts&&... ts ) + { + ::spdlog::debug( str, std::forward< Ts >( ts )... ); + } + + template < typename... Ts > + void info( const std::string str, Ts&&... ts ) + { + ::spdlog::info( str, std::forward< Ts >( ts )... ); + } + + template < typename... Ts > + void error( const std::string str, Ts&&... ts ) + { + ::spdlog::error( str, std::forward< Ts >( ts )... ); + } + + template < typename... Ts > + void critical( const std::string str, Ts&&... ts ) + { + ::spdlog::critical( str, std::forward< Ts >( ts )... ); + } + + namespace server + { + template < typename... Ts > + void info( const std::string str, Ts&&... ts ) + { + ::spdlog::info( std::format( "[SERVER]: {}", str ), std::forward< Ts >( ts )... ); + } + } // namespace server + +} // namespace idhan::log \ No newline at end of file diff --git a/IDHANServer/include/idhan/versions.hpp b/IDHANServer/include/idhan/versions.hpp new file mode 100644 index 0000000..04614a4 --- /dev/null +++ b/IDHANServer/include/idhan/versions.hpp @@ -0,0 +1,10 @@ +// +// Created by kj16609 on 7/30/24. +// + +#pragma once + +#define MAKE_IDHAN_VERSION( major, minor, patch ) ( major << 16 ) | ( minor < 8 ) || patch + +#define IDHAN_SERVER_VERSION MAKE_IDHAN_VERSION( 1, 0, 0 ) +#define IDHAN_API_VERSION MAKE_IDHAN_VERSION( 1, 0, 0 ) diff --git a/IDHANServer/main.cpp b/IDHANServer/main.cpp new file mode 100644 index 0000000..c470efd --- /dev/null +++ b/IDHANServer/main.cpp @@ -0,0 +1,23 @@ +// +// Created by kj16609 on 7/23/24. +// + +#include + +#include "idhan/ConnectionArguments.hpp" +#include "idhan/ServerContext.hpp" + +int main( int argc, char** argv ) +{ + idhan::ConnectionArguments arguments {}; + //arguments.hydrus_info.hydrus_db_path = "/home/kj16609/.local/share/hydrus/db/"; + arguments.hydrus_info.hydrus_db_path = "/run/media/kj16609/SDD1/CuddleDBHydrus/"; + arguments.user = "idhan"; + arguments.hostname = "localhost"; + + idhan::ServerContext context { arguments }; + + context.run(); + + return EXIT_SUCCESS; +} diff --git a/IDHANServer/src/ServerContext.cpp b/IDHANServer/src/ServerContext.cpp new file mode 100644 index 0000000..50da14b --- /dev/null +++ b/IDHANServer/src/ServerContext.cpp @@ -0,0 +1,80 @@ +// +// Created by kj16609 on 7/23/24. +// + +#include "idhan/ServerContext.hpp" + +#include + +#include "core/Database.hpp" +#include "drogon/HttpAppFramework.h" +#include "hyapi/setups.hpp" +#include "idhan/logging/log.hpp" + +constexpr std::uint16_t DEFAULT_PORT { 16609 }; + +namespace idhan +{ + + ServerContext::ServerContext( const ConnectionArguments& arguments ) : + m_db( std::make_unique< Database >( arguments ) ) + { + log::server::info( "IDHAN initalization starting" ); + + auto& app { drogon::app() }; + + drogon::app() + .setLogPath( "./" ) + .setLogLevel( trantor::Logger::kInfo ) + .addListener( "127.0.0.1", DEFAULT_PORT ) + .setThreadNum( 16 ); + + drogon::app().registerPreRoutingAdvice( + []( const drogon::HttpRequestPtr& request, + drogon::FilterCallback&& stop, + drogon::FilterChainCallback&& pass ) + { + if ( !request->path().starts_with( "/hyapi" ) || request->method() != drogon::Options ) + { + pass(); + return; + } + + auto response { drogon::HttpResponse::newHttpResponse() }; + + response->addHeader( "Access-Control-Allow-Headers", "*" ); + response->addHeader( "Access-Control-Allow-Origin", "*" ); + response->addHeader( "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD" ); + + stop( response ); + } ); + + drogon::app().registerPostHandlingAdvice( + []( [[maybe_unused]] const drogon::HttpRequestPtr& request, const drogon::HttpResponsePtr& response ) + { + response->addHeader( "Access-Control-Allow-Headers", "*" ); + response->addHeader( "Access-Control-Allow-Origin", "*" ); + response->addHeader( "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD" ); + } ); + + hyapi::setupAccessHandlers(); + hyapi::setupServiceHandlers(); + + log::server::info( "IDHAN initalization finished" ); + } + + void ServerContext::run() + { + log::server::info( "Starting runtime" ); + + drogon::app().run(); + + log::server::info( "Shutting down" ); + } + + ServerContext::~ServerContext() + { + + } + +} // namespace idhan diff --git a/IDHANServer/src/core/Database.cpp b/IDHANServer/src/core/Database.cpp new file mode 100644 index 0000000..4c5164a --- /dev/null +++ b/IDHANServer/src/core/Database.cpp @@ -0,0 +1,158 @@ +// +// Created by kj16609 on 7/24/24. +// + +#include "Database.hpp" + +#include "hyapi/HydrusDB.hpp" +#include "idhan/logging/log.hpp" +#include "sqlite/Transaction.hpp" + +namespace idhan +{ + + bool tableExists( pqxx::nontransaction& tx, const std::string_view name ) + { + const pqxx::result table_result { + tx.exec_params( "SELECT table_name FROM information_schema.tables WHERE table_name = $1", name ) + }; + + return table_result.size() > 0; + } + + //! Returns the table version. + std::uint16_t getTableVersion( pqxx::nontransaction& tx, const std::string_view name ) + { + auto result { tx.exec_params( "SELECT table_version FROM idhan_info WHERE table_name = $1", name ) }; + + if ( result.size() == 0 ) return 0; + + return std::get< 0 >( result.at( 0 ).as< std::uint16_t >() ); + } + + void addTableToInfo( pqxx::nontransaction& tx, const std::string_view name, const std::string_view creation_query ) + { + tx.exec_params( + "INSERT INTO idhan_info ( table_version, table_name, creation_query ) VALUES ($1, $2, $3)", + 1, + name, + creation_query ); + } + + void updateTableVersion( pqxx::nontransaction& tx, const std::string_view name, const std::uint16_t version ) + { + tx.exec_params( "UPDATE idhan_info SET table_version = $1 WHERE table_name = $2", version, name ); + } + + // clang-format off + constexpr std::array< std::tuple< std::string_view, std::string_view >, 14 > table_creation_sql { + { + { + "idhan_info", + "CREATE TABLE idhan_info (table_version INTEGER NOT NULL, table_name TEXT UNIQUE NOT NULL, creation_query TEXT NOT NULL)" + }, + { + "file_records", + "CREATE TABLE file_records (file_record_id BIGSERIAL PRIMARY KEY, sha256 BYTEA UNIQUE NOT NULL, creation_time TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP)" }, + { + "tag_namespaces", + "CREATE TABLE tag_namespaces (namespace_id SERIAL PRIMARY KEY, namespace_text TEXT UNIQUE NOT NULL)" }, + { + "tag_subtags", + "CREATE TABLE tag_subtags (subtag_id SERIAL PRIMARY KEY, subtag_text TEXT UNIQUE NOT NULL)" + }, + { + "tag_domains", + "CREATE TABLE tag_domains (tag_domain_id SMALLSERIAL PRIMARY KEY, domain_name TEXT UNIQUE NOT NULL)" + }, + { + "tags", + "CREATE TABLE tags (tag_domain_id SMALLINT NOT NULL REFERENCES tag_domains (tag_domain_id), tag_id BIGSERIAL PRIMARY KEY, namespace_id INTEGER REFERENCES tag_namespaces(namespace_id), subtag_id INTEGER REFERENCES tag_subtags(subtag_id), UNIQUE(namespace_id, subtag_id))" + }, + { + "url_domains", + "CREATE TABLE url_domains (url_domain_id SERIAL PRIMARY KEY, url_domain TEXT UNIQUE NOT NULL)" + }, + { + "urls", + "CREATE TABLE urls (url_id SERIAL PRIMARY KEY, url_domain_id INTEGER NOT NULL REFERENCES url_domains(url_domain_id), url TEXT UNIQUE NOT NULL)" + }, + { + "url_map", + "CREATE TABLE url_map (file_record_id BIGINT REFERENCES file_records(file_record_id), url_id INTEGER REFERENCES urls(url_id))" + }, + { + "deleted_files", + "CREATE TABLE deleted_files (file_record_id BIGINT REFERENCES file_records(file_record_id), deleted_time TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP)" + }, + { + "file_notes", + "CREATE TABLE file_notes (file_record_id BIGINT REFERENCES file_records(file_record_id), note TEXT NOT NULL)" + }, + { + "tag_aliases", + "CREATE TABLE tag_aliases (alias_id BIGINT REFERENCES tags(tag_id), aliased_id BIGINT REFERENCES tags(tag_id) UNIQUE)" + }, + { + "tag_parents", + "CREATE TABLE tag_parents (parent_id BIGINT REFERENCES tags(tag_id), child_id BIGINT REFERENCES tags(tag_id), UNIQUE(parent_id, child_id))" + }, + { + "tag_siblings", + "CREATE TABLE tag_siblings (older_id BIGINT REFERENCES tags(tag_id), younger_id BIGINT REFERENCES tags(tag_id), UNIQUE(older_id, younger_id))" } + } + }; + // clang-format on + + void Database::initalSetup( pqxx::nontransaction& tx ) + { + log::info( "Starting inital table setup" ); + + for ( const auto& [ table_name, query ] : table_creation_sql ) + { + log::info( "Running {}", query ); + tx.exec( query ); + addTableToInfo( tx, table_name, query ); + } + + tx.commit(); + } + + void Database::importHydrus( const ConnectionArguments& connection_arguments ) + {} + + Database::Database( const ConnectionArguments& arguments ) : connection( arguments.format() ) + { + log::info( "Postgres connection made: {}", connection.dbname() ); + + // Determine if we should do our inital setup (if the idhan_info table is missing then we should do our setup) + { + pqxx::nontransaction tx { connection }; + + tx.exec( + "DROP TABLE IF EXISTS idhan_info, url_map, urls, url_domains, deleted_files, file_notes, file_records, tag_aliases, tag_parents, tag_siblings, tags, tag_namespaces, tag_subtags, tag_domains cascade;" ); + + if ( !tableExists( tx, "idhan_info" ) ) + { + initalSetup( tx ); + } + } + + log::info( "Database loading finished" ); + } + + std::string ConnectionArguments::format() const + { + std::string str; + if ( hostname.empty() ) throw std::runtime_error( "Hostname empty" ); + + if ( port == std::numeric_limits< std::uint16_t >::quiet_NaN() ) throw std::runtime_error( "Port not set" ); + + str += std::format( "host={} ", hostname ); + str += std::format( "port={} ", port ); + str += std::format( "dbname={} ", dbname ); + str += std::format( "user={} ", user ); + + return str; + } +} // namespace idhan diff --git a/IDHANServer/src/core/Database.hpp b/IDHANServer/src/core/Database.hpp new file mode 100644 index 0000000..ab7f278 --- /dev/null +++ b/IDHANServer/src/core/Database.hpp @@ -0,0 +1,27 @@ +// +// Created by kj16609 on 7/24/24. +// + +#pragma once + +#include + +#include "idhan/ConnectionArguments.hpp" + +namespace idhan +{ + + class Database + { + pqxx::connection connection; + + void initalSetup( pqxx::nontransaction& nontransaction ); + + void importHydrus( const ConnectionArguments& connection_arguments ); + + public: + + Database( const ConnectionArguments& arguments ); + }; + +} // namespace idhan diff --git a/IDHANServer/src/core/records.cpp b/IDHANServer/src/core/records.cpp new file mode 100644 index 0000000..cf1aa30 --- /dev/null +++ b/IDHANServer/src/core/records.cpp @@ -0,0 +1,23 @@ +// +// Created by kj16609 on 7/24/24. +// + +#include "records.hpp" + +#include "crypto/sha256.hpp" + +namespace idhan +{ + + //! Returns the recordID associated with a given sha256. + RecordID getRecordID( const SHA256& sha256 ) + { + + } + + bool recordExists( const SHA256& sha256 ) + { + return getRecordID( sha256 ) != INVALID_RECORD_ID; + } + +} // namespace idhan diff --git a/IDHANServer/src/core/records.hpp b/IDHANServer/src/core/records.hpp new file mode 100644 index 0000000..bddfa46 --- /dev/null +++ b/IDHANServer/src/core/records.hpp @@ -0,0 +1,27 @@ +// +// Created by kj16609 on 7/24/24. +// + +#pragma once + +#include +#include + +namespace idhan +{ + class SHA256; + + using RecordID = std::uint64_t; + + inline constexpr static RecordID INVALID_RECORD_ID { std::numeric_limits< RecordID >::max() }; + + //! Creates a record with the given SHA256. If the record exists it will be returned + RecordID createRecord( const SHA256& sha256 ); + + //! Returns the record ID for a given sha256. If the record does not exist then INVALID_RECORD_ID is returned + RecordID getRecordID( const SHA256& sha256 ); + + //! Returns true if a given record exists + bool recordExists( const SHA256& sha256 ); + +} // namespace idhan diff --git a/IDHANServer/src/crypto/sha256.hpp b/IDHANServer/src/crypto/sha256.hpp new file mode 100644 index 0000000..e0f154b --- /dev/null +++ b/IDHANServer/src/crypto/sha256.hpp @@ -0,0 +1,16 @@ +// +// Created by kj16609 on 7/24/24. +// + +#pragma once + +namespace idhan +{ + + class SHA256 + { + + }; + + +} diff --git a/IDHANServer/src/fixme.hpp b/IDHANServer/src/fixme.hpp new file mode 100644 index 0000000..5c459f6 --- /dev/null +++ b/IDHANServer/src/fixme.hpp @@ -0,0 +1,18 @@ +// +// Created by kj16609 on 7/23/24. +// + +#pragma once + +#include +#include + +namespace idhan +{ + inline void fixme( const std::source_location location = std::source_location::current() ) + { + std::cout << std::format( "{}:{} {}", location.file_name(), location.line(), location.function_name() ) + << std::endl; + } + +} // namespace idhan \ No newline at end of file diff --git a/IDHANServer/src/hyapi/access.cpp b/IDHANServer/src/hyapi/access.cpp new file mode 100644 index 0000000..182531d --- /dev/null +++ b/IDHANServer/src/hyapi/access.cpp @@ -0,0 +1,87 @@ +// +// Created by kj16609 on 7/23/24. +// + +#include "drogon/HttpAppFramework.h" +#include "fixme.hpp" +#include "idhan/versions.hpp" + +namespace idhan::hyapi +{ + + constexpr auto PRETEND_API_VERSION { 65 }; + constexpr auto PRETEND_HYDRUS_VERISON { 583 }; + + using ResponseFunction = std::function< void( const drogon::HttpResponsePtr& ) >; + + // /hyapi/api_version + void getApiVersion( [[maybe_unused]] const drogon::HttpRequestPtr& request, ResponseFunction&& callback ) + { + Json::Value json; + json[ "version" ] = PRETEND_API_VERSION; + json[ "hydrus_version" ] = PRETEND_HYDRUS_VERISON; + + // I'm unsure if anything would actually ever need this. + // But i figured i'd supply it anyways + json[ "idhan_server_version" ] = IDHAN_SERVER_VERSION; + json[ "idhan_api_version" ] = IDHAN_API_VERSION; + + const auto response { drogon::HttpResponse::newHttpJsonResponse( json ) }; + + callback( response ); + } + + // /hyapi/access/request_new_permissions + void getRequestNewPermissions( + const drogon::HttpRequestPtr& request, + ResponseFunction&& callback, + const std::string& name, + const std::vector< int >& permissions ) + { + fixme(); + } + + // /hyapi/access/session_key + void getSessionKey( + const drogon::HttpRequestPtr& request, ResponseFunction&& callback, const std::string& access_key ) + { + fixme(); + } + + // In order to get the access key we also need to check if it's in the header given to us. + std::string getAccessKey( const drogon::HttpRequestPtr& request, const std::string& string ) + { + if ( string.empty() ) + return request->getHeader( "Hydrus-Client-API-Access-Key" ); + else + return string; + } + + // /hyapi/access/verify_access_key + void getVerifyAccessKey( + const drogon::HttpRequestPtr& request, ResponseFunction&& callback, const std::string& access_key ) + { + std::string auth_key { getAccessKey( request, access_key ) }; + + Json::Value json; + json[ "basic_permissions" ] = 0; + json[ "human_description" ] = ""; + + const auto response { drogon::HttpResponse::newHttpJsonResponse( json ) }; + + callback( response ); + } + + void setupAccessHandlers() + { + auto& app = drogon::app(); + app.registerHandler( "/hyapi/api_version", &getApiVersion ); + app.registerHandler( + "/hyapi/access/request_new_permissions?name={name}&basic_permissions={permissions}", + &getRequestNewPermissions ); + app.registerHandler( "/hyapi/session_key?Hydrus-Client-API-Access-Key={access_key}", &getSessionKey ); + app.registerHandler( + "/hyapi/verify_access_key?Hydrus-Client-API-Access-Key={access_key}", &getVerifyAccessKey ); + } + +} // namespace idhan::hyapi diff --git a/IDHANServer/src/hyapi/files.cpp b/IDHANServer/src/hyapi/files.cpp new file mode 100644 index 0000000..8138bd6 --- /dev/null +++ b/IDHANServer/src/hyapi/files.cpp @@ -0,0 +1,21 @@ +// +// Created by kj16609 on 7/24/24. +// + + + + + +namespace idhan::hyapi +{ + + + + + void setupFileHandlers(); + + + + +} + diff --git a/IDHANServer/src/hyapi/services.cpp b/IDHANServer/src/hyapi/services.cpp new file mode 100644 index 0000000..4691702 --- /dev/null +++ b/IDHANServer/src/hyapi/services.cpp @@ -0,0 +1,41 @@ +// +// Created by kj16609 on 7/23/24. +// + +#include "drogon/HttpAppFramework.h" +#include "fixme.hpp" + +namespace idhan::hyapi +{ + + using ResponseFunction = std::function< void( const drogon::HttpResponsePtr& ) >; + + // /hyapi/services/get_service + void getServiceFromName( + const drogon::HttpRequestPtr& request, + ResponseFunction&& callback, + const std::string& service_name, + const std::string& service_key ) + { + std::cout << std::format( "Name: {}\nKey: {}", service_name, service_key ) << std::endl; + fixme(); + } + + // /hyapi/services/get_services + void getServices( const drogon::HttpRequestPtr& request, ResponseFunction&& callback ) + { + fixme(); + } + + void setupServiceHandlers() + { + auto& app = drogon::app(); + app.registerHandler( + "/hyapi/get_service?service_name={service_name}&service_key={service_key}", &getServiceFromName ); + //app.registerHandler( "/hyapi/get_service?service_key={service_key}", &getServiceFromKey ); + app.registerHandler( "/hyapi/get_services", &getServices ); + //app.registerHandler( "/hyapi/access/session_key", &getSessionKey ); + //app.registerHandler( "/hyapi/access/verify_access_key", &getVerifyAccessKey ); + } + +} // namespace idhan::hyapi diff --git a/IDHANServer/src/hyapi/setups.hpp b/IDHANServer/src/hyapi/setups.hpp new file mode 100644 index 0000000..c8f3a09 --- /dev/null +++ b/IDHANServer/src/hyapi/setups.hpp @@ -0,0 +1,12 @@ +// +// Created by kj16609 on 7/23/24. +// + +#pragma once + +namespace idhan::hyapi +{ + void setupAccessHandlers(); + void setupServiceHandlers(); + void setupFileHandlers(); +} // namespace idhan::hyapi diff --git a/dependencies/Catch.cmake b/dependencies/Catch.cmake new file mode 100644 index 0000000..8a8a8cf --- /dev/null +++ b/dependencies/Catch.cmake @@ -0,0 +1 @@ +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/dependencies/Catch2) \ No newline at end of file diff --git a/dependencies/drogon b/dependencies/drogon new file mode 160000 index 0000000..500d44f --- /dev/null +++ b/dependencies/drogon @@ -0,0 +1 @@ +Subproject commit 500d44faac87daa3877a7911215a06deca53c7a1 diff --git a/dependencies/drogon.cmake b/dependencies/drogon.cmake new file mode 100644 index 0000000..5e7c52e --- /dev/null +++ b/dependencies/drogon.cmake @@ -0,0 +1 @@ +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/dependencies/drogon) \ No newline at end of file diff --git a/dependencies/libpqxx b/dependencies/libpqxx new file mode 160000 index 0000000..86f7d62 --- /dev/null +++ b/dependencies/libpqxx @@ -0,0 +1 @@ +Subproject commit 86f7d62cb101d59df2d788888c90b3a463418860 diff --git a/dependencies/postgres.cmake b/dependencies/postgres.cmake new file mode 100644 index 0000000..5f278fd --- /dev/null +++ b/dependencies/postgres.cmake @@ -0,0 +1 @@ +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libpqxx) \ No newline at end of file diff --git a/dependencies/spdlog.cmake b/dependencies/spdlog.cmake new file mode 100644 index 0000000..d638a78 --- /dev/null +++ b/dependencies/spdlog.cmake @@ -0,0 +1,3 @@ + +set(SPDLOG_USE_STD_FORMAT ON) +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/dependencies/spdlog) \ No newline at end of file diff --git a/dependencies/sqlite3.cmake b/dependencies/sqlite3.cmake new file mode 100644 index 0000000..612757d --- /dev/null +++ b/dependencies/sqlite3.cmake @@ -0,0 +1 @@ +find_package(SQLite3 REQUIRED) \ No newline at end of file diff --git a/docs/server/main.tex b/docs/server/main.tex new file mode 100644 index 0000000..23d5f25 --- /dev/null +++ b/docs/server/main.tex @@ -0,0 +1,81 @@ +%! Author = kj16609 +%! Date = 4/4/24 + +% Preamble +\documentclass[11pt]{article} + +% Packages +\usepackage{amsmath} +\usepackage{amssymb} + +% Document +\begin{document} + + \section{IDHAN Basics} + \subsection[whatisidhan]{What is IDHAN} + IDHAN is a file management database designed for modularity and performance. It's design attempts to use system resources given by the user as effectively as possible + + \subsection[terms]{Basic Terminology} + \begin{description} + \item[Server]: The primary IDHAN instance that handles API access and management of the database. + \item[Client]: Any API accessor (Typically will have some sort of GUI interface). + \item[API]: Both the RESTful and Socket based APIs. + \item[Record]: A sha256 matching a set of data + \item[File]: A single file/data and it's associated hash + \item[Archive]: A file containing multiple other files + \item[Tag]: A piece of information attached to a given Record. + \end{description} + + + + \section{Tagging} + \subsection[tags-terms]{Tag terminology} + \begin{description} + \item[Tag]: (See Basic Terminology) + \item[Alias]: A tag connection that turns A into B, Along with B inheriting all parents/children/siblings from A + \item[Siblings]: A tag connection that acts as an XOR (Exclusive or). Tag A as a older sibling to tag B. If both are present the older sibling 'wins' and is presented while the younger sibling is hidden + \item[Parents]: A tag connection that assuming A is a parent of B will cause A to be present whenever B is present. (A child can't be without it's parents) + \end{description} + + \subsection[tags-visual]{Tag visulizations} + The following are various ways to write tag connections without explicitly refering to them as parents/siblings/children + \begin{description} + \item[Alias] A $\rightarrow$ B ( B is the idealized or prefered tag over A ) (Writen as $->$) + \item[Parents] A $\Rightarrow$ B (B is the child of A) (Written as $=>$) + \item[Siblings] A $\rightrightarrows$ B (B is the older sibling of A) (Written as $=>>$) + \end{description} + + + + \section{Core functionality} + + + \subsection[client-connection]{Client Connections} + \subsubsection[socket-connection]{Socket connections} + The following only applies to clients that are using a messageing type API (Such as the socket API).\newline + The client's challenge must be performed as follows:\newline + The client will recieve information about the Server after inital connection and before authentication. This information consists of the version. This allows the client to check it's version and disconnect upon being unable to communicate with the server.\newline + The client will then issue an authorization request. The client must provide the key it wishes to authenticate with in the request. \newline + Upon the client being rejected the server will issue a rejection response and close the connection.\newline + Upon the client being accepted the server with issue a acceptance response that contains any extra information about the server that can't be sent to unauthenticated clients + + + \subsection[work-queue]{Work Queue} + Each client connection will be given it's own work queue. The server can be configured to assign more or less threads to each queue as well as a priority. + Each client's config will be of the following: + \begin{description} + \item[Priority] The priority of the queue. Higher work gets done first. + \item[Reserved Threads] The number of dedicated threads for processing a given thread pool. Reserved threads will NOT steal work from another queue. Must be lower then max threads + \item[Max threads] The max number of threads that will process on a given thread pool. This value is overriden by the minimum of either this value or the global thread max value. 0 means unlimited/global max + \end{description} + + + + + \subsection[file-importing]{File Importing} + + + + + +\end{document} diff --git a/fgl_cmake_modules b/fgl_cmake_modules new file mode 160000 index 0000000..00bb654 --- /dev/null +++ b/fgl_cmake_modules @@ -0,0 +1 @@ +Subproject commit 00bb654939e18dff9fd9c1b5d7ff16c34a82eb48 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt deleted file mode 100644 index 44474e7..0000000 --- a/src/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ - -add_subdirectory(IDHANClient) -add_subdirectory(IDHAN) -add_subdirectory(IDHANServer) diff --git a/src/IDHAN/include/idhan/MessageHeader.hpp b/src/IDHAN/include/idhan/MessageHeader.hpp deleted file mode 100644 index 9271815..0000000 --- a/src/IDHAN/include/idhan/MessageHeader.hpp +++ /dev/null @@ -1,30 +0,0 @@ -// -// Created by kj16609 on 3/27/24. -// - -#pragma once -#include -#include - -#include "requests/concepts.hpp" - -namespace idhan -{ - - constexpr std::uint64_t IDHAN_SIG_FULL { 0x49'44'48'41'4e'00'00'00 }; - - struct MessageHeader - { - std::size_t routing_id; - std::uint64_t flags { 0 }; - - enum Flags - { - EXPECTING_RESPONSE - }; - - static std::vector< std::byte > serialize( const MessageHeader& msg ); - static MessageHeader desieralize( const std::vector< std::byte >& data ); - }; - -} // namespace idhan diff --git a/src/IDHAN/include/idhan/net_constants.hpp b/src/IDHAN/include/idhan/net_constants.hpp deleted file mode 100644 index d9bc3f6..0000000 --- a/src/IDHAN/include/idhan/net_constants.hpp +++ /dev/null @@ -1,12 +0,0 @@ -// -// Created by kj16609 on 3/27/24. -// - -#pragma once - -namespace idhan::constants -{ - constexpr std::uint16_t MAX_PACKET_SIZE { 1024 }; -} - - diff --git a/src/IDHAN/include/idhan/requests/NetRequestInfo.hpp b/src/IDHAN/include/idhan/requests/NetRequestInfo.hpp deleted file mode 100644 index 6b4d900..0000000 --- a/src/IDHAN/include/idhan/requests/NetRequestInfo.hpp +++ /dev/null @@ -1,24 +0,0 @@ -// -// Created by kj16609 on 3/28/24. -// - -#pragma once -#include "concepts.hpp" - -namespace idhan -{ - - template < typename T, std::size_t TypeID > - struct NetRequestInfo - { - static constexpr std::size_t type_id { TypeID }; - - static std::vector< std::byte > response( const std::vector< std::byte >& data ) - { - const T t { T::deserialize( data ) }; - const typename T::ResponseT response { T::response( t ) }; - return T::ResponseT::serialize( response ); - } - }; - -} // namespace idhan diff --git a/src/IDHAN/include/idhan/requests/NetResponseInfo.hpp b/src/IDHAN/include/idhan/requests/NetResponseInfo.hpp deleted file mode 100644 index e8e1f12..0000000 --- a/src/IDHAN/include/idhan/requests/NetResponseInfo.hpp +++ /dev/null @@ -1,14 +0,0 @@ -// -// Created by kj16609 on 3/28/24. -// - -#pragma once - -namespace idhan -{ - template < typename T, std::size_t TypeID > - struct NetResponseInfo - { - static constexpr std::size_t type_id { TypeID }; - }; -} // namespace idhan \ No newline at end of file diff --git a/src/IDHAN/include/idhan/requests/VersionInfo.hpp b/src/IDHAN/include/idhan/requests/VersionInfo.hpp deleted file mode 100644 index 4631378..0000000 --- a/src/IDHAN/include/idhan/requests/VersionInfo.hpp +++ /dev/null @@ -1,33 +0,0 @@ -// -// Created by kj16609 on 3/27/24. -// - -#pragma once -#include - -#include "NetRequestInfo.hpp" -#include "NetResponseInfo.hpp" -#include "concepts.hpp" - -namespace idhan -{ - constexpr std::size_t VersionInfoNetID { 1 }; - - struct ServerVersionInfoResponse : public NetResponseInfo< ServerVersionInfoResponse, VersionInfoNetID > - { - static std::vector< std::byte > serialize( const ServerVersionInfoResponse& ); - static ServerVersionInfoResponse deserialize( const std::vector< std::byte >& ); - }; - - struct ServerVersionInfoRequest : public NetRequestInfo< ServerVersionInfoRequest, VersionInfoNetID > - { - using ResponseT = ServerVersionInfoResponse; - - //! Executed on the server - static ResponseT response( ServerVersionInfoRequest& req ); - - static std::vector< std::byte > serialize( const ServerVersionInfoRequest& ); - static ServerVersionInfoRequest deserialize( const std::vector< std::byte >& ); - }; - -} // namespace idhan diff --git a/src/IDHAN/include/idhan/requests/concepts.hpp b/src/IDHAN/include/idhan/requests/concepts.hpp deleted file mode 100644 index a9ad7fe..0000000 --- a/src/IDHAN/include/idhan/requests/concepts.hpp +++ /dev/null @@ -1,33 +0,0 @@ -// -// Created by kj16609 on 3/27/24. -// - -#pragma once -#include -#include - -namespace idhan -{ - template < typename T > - concept is_serializable = requires( T t ) { - { - T::serialize( t ) - } -> std::same_as< std::vector< std::byte > >; - }; - - template < typename T > - concept is_deserializable = requires( T t ) { - { - T::deserialize( std::declval< std::vector< std::byte > >() ) - } -> std::same_as< T >; - }; - - template < typename T > - concept is_respondable = requires( T t ) { - typename T::ResponseT; - { - T::response( t ) - } -> std::same_as< typename T::ResponseT >; - }; - -} // namespace idhan diff --git a/src/IDHAN/include/idhan/version.hpp b/src/IDHAN/include/idhan/version.hpp deleted file mode 100644 index db0ccb0..0000000 --- a/src/IDHAN/include/idhan/version.hpp +++ /dev/null @@ -1,39 +0,0 @@ -// -// Created by kj16609 on 2/21/24. -// - -#pragma once - -#include - -#define IDHAN_MAJOR_VERSION 0 -#define IDHAN_MINOR_VERSION 1 -#define IDHAN_PATCH_VERSION 0 - -// Define version number as a string -#define STRINGIFY( x ) #x -#define TO_STRING( x ) STRINGIFY( x ) - -#define D_IDHAN_VERSION_STRING \ - TO_STRING( IDHAN_MAJOR_VERSION ) "." TO_STRING( IDHAN_MINOR_VERSION ) "." TO_STRING( IDHAN_PATCH_VERSION ) - -// 0.0.0 - -// 0000 0000 0000 -// major minor patch - -#define D_IDHAN_VERSION_NUMBER( MAJOR, MINOR, PATCH ) ( MAJOR * 10000 + MINOR * 100 + PATCH ) - -namespace idhan::version -{ - constexpr int IDHAN_VERSION { - D_IDHAN_VERSION_NUMBER( IDHAN_MAJOR_VERSION, IDHAN_MINOR_VERSION, IDHAN_PATCH_VERSION ) - }; - - constexpr static char IDHAN_VERSION_STRING[] { D_IDHAN_VERSION_STRING }; - - constexpr std::string_view IDHAN_STRING_VIEW { - std::string_view( IDHAN_VERSION_STRING, sizeof( IDHAN_VERSION_STRING ) - 1 ) - }; - -} // namespace idhan::version diff --git a/src/IDHAN/src/version.cpp b/src/IDHAN/src/version.cpp deleted file mode 100644 index d310888..0000000 --- a/src/IDHAN/src/version.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// -// Created by kj16609 on 2/21/24. -// - -#include "idhan/version.hpp" diff --git a/src/IDHANClient/CMakeLists.txt b/src/IDHANClient/CMakeLists.txt deleted file mode 100644 index 54334bd..0000000 --- a/src/IDHANClient/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ - - -file(GLOB_RECURSE LIB_IDHAN_CLIENT_SOURCES "src/**.cpp") -file(GLOB_RECURSE LIB_IDHAN_CLIENT_HEADERS "include/**.hpp") - -add_library(IDHANClient SHARED ${LIB_IDHAN_CLIENT_SOURCES} ${LIB_IDHAN_CLIENT_HEADERS}) - -target_link_libraries(IDHANClient PUBLIC IDHAN) -target_link_libraries(IDHANClient PUBLIC OpenSSL::SSL OpenSSL::Crypto asio spdlog) - -target_include_directories(IDHANClient PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src) -target_include_directories(IDHANClient PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) - - - - diff --git a/src/IDHANClient/include/idhan/client/ClientContext.hpp b/src/IDHANClient/include/idhan/client/ClientContext.hpp deleted file mode 100644 index 774bf11..0000000 --- a/src/IDHANClient/include/idhan/client/ClientContext.hpp +++ /dev/null @@ -1,82 +0,0 @@ -// -// Created by kj16609 on 3/25/24. -// - -#pragma once -#include -#include -#include - -#include -#include - -#include "idhan/MessageHeader.hpp" -#include "idhan/requests/VersionInfo.hpp" - -namespace idhan -{ - - struct MessageFutureBase - {}; - - class ClientContext - { - asio::io_context asio_context {}; - asio::ip::tcp::resolver resolver; - asio::ssl::context ssl_context { asio::ssl::context::sslv23 }; - asio::ssl::stream< asio::ip::tcp::socket > secure_socket; - std::jthread runner; - - //! Futures for messages that are to be fullfilled by the server - std::vector< std::unique_ptr< MessageFutureBase > > futures {}; - - public: - - constexpr static std::uint16_t DEFAULT_LISTEN_PORT { 16609 }; - - ClientContext() = delete; - - ClientContext( const std::string& host, const std::uint16_t port = DEFAULT_LISTEN_PORT ); - - ClientContext( const ClientContext& other ) = delete; - ClientContext& operator=( const ClientContext& other ) = delete; - - //! Sends a message request to the server and creates a future for a response - template < typename T > - requires is_respondable< T > - std::future< typename T::ResponseT > getResponse( const T&& req ) - { - using ResponseType = typename T::ResponseT; - std::promise< ResponseType > promise {}; - - MessageHeader header {}; - - // If the message future return type is void then we should NOT be expecting a response - if constexpr ( !std::same_as< typename T::ResponseT, void > ) - header.flags |= MessageHeader::EXPECTING_RESPONSE; // Add response expected - - // Set the routing ID for the server to call the right function - header.routing_id = T::type_id; - - std::future< ResponseType > future { promise.get_future() }; - - sendMessage( header, T::serialize( std::forward< const T&& >( req ) ), std::move( promise ) ); - - return future; - } - - std::future< ServerVersionInfoResponse > requestServerVersionInfo(); - - ClientContext( ClientContext&& other ) noexcept = delete; - ClientContext& operator=( ClientContext&& other ) = delete; - - void shutdown(); - void waitForShutdown(); - - ~ClientContext() - { - shutdown(); - waitForShutdown(); - } - }; -} // namespace idhan \ No newline at end of file diff --git a/src/IDHANClient/include/idhan/client/DatabaseContext.hpp b/src/IDHANClient/include/idhan/client/DatabaseContext.hpp deleted file mode 100644 index c3d6411..0000000 --- a/src/IDHANClient/include/idhan/client/DatabaseContext.hpp +++ /dev/null @@ -1,5 +0,0 @@ -// -// Created by kj16609 on 3/27/24. -// - -#pragma once \ No newline at end of file diff --git a/src/IDHANClient/include/idhan/client/TagContext.hpp b/src/IDHANClient/include/idhan/client/TagContext.hpp deleted file mode 100644 index c3d6411..0000000 --- a/src/IDHANClient/include/idhan/client/TagContext.hpp +++ /dev/null @@ -1,5 +0,0 @@ -// -// Created by kj16609 on 3/27/24. -// - -#pragma once \ No newline at end of file diff --git a/src/IDHANClient/src/ClientContext.cpp b/src/IDHANClient/src/ClientContext.cpp deleted file mode 100644 index 14d2025..0000000 --- a/src/IDHANClient/src/ClientContext.cpp +++ /dev/null @@ -1,78 +0,0 @@ -// -// Created by kj16609 on 3/25/24. -// - -#include "idhan/client/ClientContext.hpp" - -#include -#include - -#include - -#include "spdlog/spdlog.h" - -namespace idhan -{ - ClientContext::ClientContext( const std::string& host, const std::uint16_t port ) : - secure_socket( asio_context, ssl_context ), - resolver( asio_context ) - { - runner = std::jthread( - [ this ]( std::stop_token token ) -> void - { - spdlog::info( "[IDHANClient] Starting asio IO thread" ); - while ( !token.stop_requested() ) - { - asio_context.run(); - } - spdlog::info( "[IDHANClient] Shutting down asio IO thread" ); - } ); - - //Resolve host - auto endpoints { resolver.resolve( host, std::to_string( port ) ) }; - - try - { - //Begin inital connection - spdlog::info( "[IDHANClient] Starting connection to {}:{}", host, port ); - asio::connect( secure_socket.lowest_layer(), endpoints ); - - spdlog::info( "[IDHANClient] Connection established. Attempting handshake" ); - - secure_socket.set_verify_mode( asio::ssl::verify_none ); - secure_socket.async_handshake( - decltype( secure_socket )::client, - [ this ]( const std::error_code error_code ) - { - if ( error_code ) - spdlog::error( "[IDHANClient] SSL Handshake failed: {}", error_code.message() ); - else - spdlog::info( "[IDHANClient] Handshake complete" ); - } ); - } - catch ( std::exception& e ) - { - spdlog::error( "Failed to connect to remote host {}:{} due to errror: {}", host, port, e.what() ); - } - } - - std::future< ServerVersionInfoResponse > ClientContext::requestServerVersionInfo() - { - ServerVersionInfoRequest req {}; - - return getResponse( std::move( req ) ); - } - - void ClientContext::shutdown() - { - //TODO: Submit client disconnect message. - (void)runner.request_stop(); - asio_context.stop(); - } - - void ClientContext::waitForShutdown() - { - runner.join(); - } - -} // namespace idhan diff --git a/src/IDHANClient/src/DatabaseContext.cpp b/src/IDHANClient/src/DatabaseContext.cpp deleted file mode 100644 index 9af1cca..0000000 --- a/src/IDHANClient/src/DatabaseContext.cpp +++ /dev/null @@ -1,3 +0,0 @@ -// -// Created by kj16609 on 3/27/24. -// diff --git a/src/IDHANClient/src/TagContext.cpp b/src/IDHANClient/src/TagContext.cpp deleted file mode 100644 index 9af1cca..0000000 --- a/src/IDHANClient/src/TagContext.cpp +++ /dev/null @@ -1,3 +0,0 @@ -// -// Created by kj16609 on 3/27/24. -// diff --git a/src/IDHANServer/CMakeLists.txt b/src/IDHANServer/CMakeLists.txt deleted file mode 100644 index f61bef5..0000000 --- a/src/IDHANServer/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ - - -file(GLOB_RECURSE LIB_IDHAN_SERVER_SOURCES "src/**.cpp") -file(GLOB_RECURSE LIB_IDHAN_SERVER_HEADERS "include/**.hpp") - -add_library(IDHANServer SHARED ${LIB_IDHAN_SERVER_SOURCES} ${LIB_IDHAN_SERVER_HEADERS}) - -target_link_libraries(IDHANServer PRIVATE IDHAN OpenSSL::SSL OpenSSL::Crypto asio spdlog) - -target_include_directories(IDHANServer PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) -target_include_directories(IDHANServer PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) - - - - diff --git a/src/IDHANServer/include/idhan/server/ServerContext.hpp b/src/IDHANServer/include/idhan/server/ServerContext.hpp deleted file mode 100644 index 24f0eb8..0000000 --- a/src/IDHANServer/include/idhan/server/ServerContext.hpp +++ /dev/null @@ -1,64 +0,0 @@ -// -// Created by kj16609 on 3/26/24. -// - -#pragma once -#include -#include -#include - -#include -#include -#include - -namespace idhan -{ - - struct ClientConnection : std::enable_shared_from_this< ClientConnection > - { - asio::ssl::stream< asio::ip::tcp::socket > secure_socket; - std::array< std::byte, 1024 > in_data_buffer {}; - std::vector< std::byte > in_working_buffer {}; - - void prepareRead(); - - public: - - ClientConnection( asio::ip::tcp::socket&& socket, asio::ssl::context& ssl_context ) : - secure_socket( std::forward< decltype( socket ) >( socket ), ssl_context ) - {} - - void startHandshake(); - - void routeMessage( const std::vector< std::byte >& move ); - }; - - class ServerContext - { - std::jthread runner; - asio::io_context io_context {}; - asio::ssl::context ssl_context { asio::ssl::context::sslv23 }; - asio::ip::tcp::endpoint endpoint; - asio::ip::tcp::acceptor acceptor; - - bool accept_new_connections { true }; - - std::vector< std::shared_ptr< ClientConnection > > clients {}; - - public: - - constexpr static std::string DEFAULT_LISTEN_HOST { "127.0.0.1" }; - constexpr static std::uint16_t DEFAULT_LISTEN_PORT { 16609 }; - - void handleNewConnection( const std::error_code& ec, asio::ip::tcp::socket socket ); - void prepareIncomingAcceptor(); - ServerContext( - const std::string& listen_address = DEFAULT_LISTEN_HOST, const std::uint16_t port = DEFAULT_LISTEN_PORT ); - ~ServerContext(); - - asio::ip::address listenAddress() const { return endpoint.address(); } - - asio::ip::port_type listenPort() const { return endpoint.port(); } - }; - -} // namespace idhan diff --git a/src/IDHANServer/src/ServerContext.cpp b/src/IDHANServer/src/ServerContext.cpp deleted file mode 100644 index 92900fb..0000000 --- a/src/IDHANServer/src/ServerContext.cpp +++ /dev/null @@ -1,135 +0,0 @@ -// -// Created by kj16609 on 3/26/24. -// - -#include "idhan/server/ServerContext.hpp" - -#include - -#include - -#include "../../IDHAN/include/idhan/requests/concepts.hpp" -#include "idhan/MessageHeader.hpp" -#include "spdlog/spdlog.h" - -namespace idhan -{ - - void ServerContext::handleNewConnection( const std::error_code& ec, asio::ip::tcp::socket socket ) - { - if ( !accept_new_connections ) return socket.close(); - - prepareIncomingAcceptor(); - const auto address { socket.remote_endpoint().address() }; - spdlog::info( "[IDHANServer]: Handling new connection from host: {}", address.to_string() ); - if ( ec ) - { - spdlog:: - error( "[IDHANServer] Aborted connection from {} due to error: {}", address.to_string(), ec.message() ); - return; - } - - this->clients.emplace_back( std::make_shared< ClientConnection >( std::move( socket ), ssl_context ) ) - ->startHandshake(); - } - - void ClientConnection::startHandshake() - { - auto self { shared_from_this() }; - secure_socket.async_handshake( - asio::ssl::stream_base::server, - [ this, self ]( const std::error_code& error_code ) - { - if ( error_code ) - spdlog::error( "[IDHANServer] Failed to do handshake: {}", error_code.message() ); - else - { - spdlog::info( "[IDHANServer] Handshake completed." ); - - prepareRead(); - } - } ); - spdlog::info( "[IDHANServer] Handshake for new connection queued" ); - } - - void ClientConnection::prepareRead() - { - auto self { shared_from_this() }; - secure_socket.async_read_some( - asio::buffer( in_data_buffer ), - [ this, self ]( const std::error_code& ec, std::size_t length ) -> void - { - spdlog::info( "Received message with length: {}", length ); - if ( ec ) - { - spdlog::error( "Error while reading data from remote: {}", ec.message() ); - } - else - { - if ( in_working_buffer.size() > sizeof( std::size_t ) ) - { - if ( const auto message_header = MessageHeader::decodeFromBuffer( in_working_buffer ); - message_header.length <= in_working_buffer.size() ) - { - //We have the entire message. Extract it then send it to the message router. - - std::vector< std::byte > new_buffer {}; - new_buffer.resize( message_header.length ); - - std::memcpy( new_buffer.data(), in_working_buffer.data(), message_header.length ); - - routeMessage( std::move( new_buffer ) ); - - //Erase the message from the buffer - in_working_buffer - .erase( in_working_buffer.begin(), in_working_buffer.begin() + message_header.length ); - } - //Insufficent data. Need to wait for more. - } - - prepareRead(); - } - } ); - } - - void ServerContext::prepareIncomingAcceptor() - { - spdlog::info( "[IDHANServer] Prepared acceptor for next incoming connection" ); - acceptor.async_accept( - std::bind( &ServerContext::handleNewConnection, this, std::placeholders::_1, std::placeholders::_2 ) ); - } - - ServerContext::ServerContext( const std::string& listen_address, const std::uint16_t port ) : - io_context( 2 ), - endpoint( asio::ip::address::from_string( listen_address ), port ), - acceptor( io_context, endpoint ) - { - if ( !std::filesystem::exists( "server.pem" ) ) - throw std::runtime_error( - std::string( "No server.pem file exists at " ) + std::filesystem::current_path().string() ); - ssl_context.use_certificate_chain_file( "server.pem" ); - ssl_context.use_private_key_file( "server.pem", asio::ssl::context::pem ); - - prepareIncomingAcceptor(); - - spdlog::info( "[IDHANServer] Listening on port {}:{}", listen_address, port ); - - runner = std::jthread( - [ this ]( std::stop_token token ) -> void - { - spdlog::info( "[IDHANServer] Starting asio IO thread" ); - while ( !token.stop_requested() ) - { - io_context.run(); - } - spdlog::info( "[IDHANServer] Shutting down asio IO thread" ); - } ); - } - - ServerContext::~ServerContext() - { - runner.request_stop(); - io_context.stop(); - } - -} // namespace idhan diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ab7d52a..50f85e3 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,8 +5,6 @@ enable_testing() file(GLOB_RECURSE FGL_TEST_SOURCES "*.cpp") add_executable(IDHANTests ${FGL_TEST_SOURCES}) -target_link_libraries(IDHANTests PUBLIC IDHAN Catch2::Catch2WithMain IDHANServer IDHANClient) +target_link_libraries(IDHANTests PUBLIC IDHAN Catch2::Catch2WithMain LibIDHANServer LibIDHANClient) -include(CTest) -include(Catch) -catch_discover_tests(IDHANTests) \ No newline at end of file +#catch_discover_tests(IDHANTests) \ No newline at end of file diff --git a/tests/src/server.cpp b/tests/src/server.cpp index e0a61f3..0409499 100644 --- a/tests/src/server.cpp +++ b/tests/src/server.cpp @@ -11,37 +11,5 @@ using namespace idhan; TEST_CASE( "Server setup", "[server][network]" ) { - WHEN( "Default constructed" ) - { - ServerContext server_ctx {}; - THEN( "The host should be \"localhost\"" ) - { - REQUIRE( - server_ctx.listenAddress() == asio::ip::address::from_string( ServerContext::DEFAULT_LISTEN_HOST ) ); - } - - THEN( "The port should be 16609" ) - { - REQUIRE( server_ctx.listenPort() == ServerContext::DEFAULT_LISTEN_PORT ); - } - - THEN( "A client should be able to connect" ) - { - ClientContext client { ServerContext::DEFAULT_LISTEN_HOST, ClientContext::DEFAULT_LISTEN_PORT }; - using namespace std::chrono_literals; - std::this_thread::sleep_for( 100ms ); - AND_THEN( "A second client should be able to connect" ) - { - ClientContext second_client { ServerContext::DEFAULT_LISTEN_HOST, ClientContext::DEFAULT_LISTEN_PORT }; - } - - AND_THEN( "A client should be able to request the version information" ) - { - auto server_info { client.requestServerVersionInfo() }; - - server_info.wait_for( std::chrono::seconds( 1 ) ); - } - } - } -} +} \ No newline at end of file