From 7ca95a09740297ae9c041c5f8ae4caa0a57a149a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 13 Jun 2017 10:30:51 +0200 Subject: Find sqlite3 instead of litesql Simplifies the CMakeLists.txt a little bit --- CMakeLists.txt | 31 ++++++----------- cmake/Modules/FindLITESQL.cmake | 76 ----------------------------------------- cmake/Modules/FindSQLITE3.cmake | 43 +++++++++++++++++++++++ 3 files changed, 54 insertions(+), 96 deletions(-) delete mode 100644 cmake/Modules/FindLITESQL.cmake create mode 100644 cmake/Modules/FindSQLITE3.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b081bc..ed20870 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,10 +124,10 @@ elseif(NOT WITHOUT_UDNS) find_package(UDNS) endif() -if(WITH_LITESQL) - find_package(LITESQL REQUIRED) -elseif(NOT WITHOUT_LITESQL) - find_package(LITESQL) +if(WITH_SQLITE3) + find_package(SQLITE3 REQUIRED) +elseif(NOT WITHOUT_SQLITE3) + find_package(SQLITE3) endif() # @@ -158,17 +158,14 @@ include_directories("${CMAKE_CURRENT_BINARY_DIR}/") file(GLOB source_utils src/utils/*.[hc]pp) add_library(utils OBJECT ${source_utils}) -add_dependencies(utils litesql_generated_sources) file(GLOB source_irc src/irc/*.[hc]pp) add_library(irc OBJECT ${source_irc}) -add_dependencies(irc litesql_generated_sources) file(GLOB source_xmpp src/xmpp/*.[hc]pp) add_library(xmpp OBJECT ${source_xmpp}) -add_dependencies(xmpp litesql_generated_sources) file(GLOB source_identd src/identd/*.[hc]pp) @@ -177,7 +174,6 @@ add_library(identd OBJECT ${source_identd}) file(GLOB source_bridge src/bridge/*.[hc]pp) add_library(bridge OBJECT ${source_bridge}) -add_dependencies(bridge litesql_generated_sources) file(GLOB source_config src/config/*.[hc]pp) @@ -191,20 +187,15 @@ file(GLOB source_network src/network/*.[hc]pp) add_library(network OBJECT ${source_network}) -if(LITESQL_FOUND) - LITESQL_GENERATE_CPP("database/database.xml" - "biboudb" - LITESQL_GENERATED_SOURCES) - add_custom_target(litesql_generated_sources SOURCES ${LITESQL_GENERATED_SOURCES}) +if(SQLITE3_FOUND) + file(GLOB source_database + src/database/*.[hc]pp) + add_library(database OBJECT ${source_database}) - add_library(database OBJECT src/database/database.cpp ${LITESQL_GENERATED_SOURCES}) - add_dependencies(database litesql_generated_sources) - - include_directories(database ${LITESQL_INCLUDE_DIRS}) + include_directories(database ${SQLITE3_INCLUDE_DIRS}) set(USE_DATABASE TRUE) else() add_library(database OBJECT "") - add_custom_target(litesql_generated_sources) endif() # @@ -269,8 +260,8 @@ if(LIBIDN_FOUND) target_link_libraries(test_suite ${LIBIDN_LIBRARIES}) endif() if(USE_DATABASE) - target_link_libraries(${PROJECT_NAME} ${LITESQL_LIBRARIES}) - target_link_libraries(test_suite ${LITESQL_LIBRARIES}) + target_link_libraries(${PROJECT_NAME} ${SQLITE3_LIBRARIES}) + target_link_libraries(test_suite ${SQLITE3_LIBRARIES}) endif() # Define a __FILENAME__ macro with the relative path (from the base project directory) diff --git a/cmake/Modules/FindLITESQL.cmake b/cmake/Modules/FindLITESQL.cmake deleted file mode 100644 index 2d3b073..0000000 --- a/cmake/Modules/FindLITESQL.cmake +++ /dev/null @@ -1,76 +0,0 @@ -# - Find LiteSQL -# -# Find the LiteSQL library, and defines a function to generate C++ files -# from the database xml file using litesql-gen fro -# -# This module defines the following variables: -# LITESQL_FOUND - True if library and include directory are found -# If set to TRUE, the following are also defined: -# LITESQL_INCLUDE_DIRS - The directory where to find the header file -# LITESQL_LIBRARIES - Where to find the library file -# LITESQL_GENERATE_CPP - A function, to be used like this: -# LITESQL_GENERATE_CPP("db/database.xml" # The file defining the db schemas -# "database" # The name of the C++ “module” -# # that will be generated -# LITESQL_GENERATED_SOURCES # Variable containing the -# resulting C++ files to compile -# -# For conveniance, these variables are also set. They have the same values -# than the variables above. The user can thus choose his/her prefered way -# to write them. -# LITESQL_INCLUDE_DIR -# LITESQL_LIBRARY -# -# This file is in the public domain - -find_path(LITESQL_INCLUDE_DIRS NAMES litesql.hpp - DOC "The LiteSQL include directory") - -find_library(LITESQL_LIBRARIES NAMES litesql - DOC "The LiteSQL library") - -foreach(DB_TYPE sqlite postgresql mysql ocilib) - string(TOUPPER ${DB_TYPE} DB_TYPE_UPPER) - find_library(LITESQL_${DB_TYPE_UPPER}_LIB_PATH NAMES litesql_${DB_TYPE} - DOC "The ${DB_TYPE} backend for LiteSQL") - if(LITESQL_${DB_TYPE_UPPER}_LIB_PATH) - list(APPEND LITESQL_LIBRARIES ${LITESQL_${DB_TYPE_UPPER}_LIB_PATH}) - endif() - mark_as_advanced(LITESQL_${DB_TYPE_UPPER}_LIB_PATH) -endforeach() - -find_program(LITESQLGEN_EXECUTABLE NAMES litesql-gen - DOC "The utility that creates .h and .cpp files from a xml database description") - -# Use some standard module to handle the QUIETLY and REQUIRED arguments, and -# set LITESQL_FOUND to TRUE if these two variables are set. -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(LITESQL REQUIRED_VARS LITESQL_LIBRARIES LITESQL_INCLUDE_DIRS - LITESQLGEN_EXECUTABLE) - -# Compatibility for all the ways of writing these variables -if(LITESQL_FOUND) - set(LITESQL_INCLUDE_DIR ${LITESQL_INCLUDE_DIRS}) - set(LITESQL_LIBRARY ${LITESQL_LIBRARIES}) -endif() - -mark_as_advanced(LITESQL_INCLUDE_DIRS LITESQL_LIBRARIES LITESQLGEN_EXECUTABLE) - - -# LITESQL_GENERATE_CPP function - -function(LITESQL_GENERATE_CPP - SOURCE_FILE OUTPUT_NAME OUTPUT_SOURCES) - set(${OUTPUT_SOURCES}) - add_custom_command( - OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_NAME}.cpp" - "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_NAME}.hpp" - COMMAND ${LITESQLGEN_EXECUTABLE} - ARGS -t c++ --output-dir=${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE_FILE} - DEPENDS ${SOURCE_FILE} - COMMENT "Running litesql-gen on ${SOURCE_FILE}" - VERBATIM) - list(APPEND ${OUTPUT_SOURCES} "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_NAME}.cpp") - set_source_files_properties(${${OUTPUT_SOURCES}} PROPERTIES GENERATED TRUE) - set(${OUTPUT_SOURCES} ${${OUTPUT_SOURCES}} PARENT_SCOPE) -endfunction() diff --git a/cmake/Modules/FindSQLITE3.cmake b/cmake/Modules/FindSQLITE3.cmake new file mode 100644 index 0000000..2861b37 --- /dev/null +++ b/cmake/Modules/FindSQLITE3.cmake @@ -0,0 +1,43 @@ +# - Find sqlite3 +# Find the sqlite3 cryptographic library +# +# This module defines the following variables: +# SQLITE3_FOUND - True if library and include directory are found +# If set to TRUE, the following are also defined: +# SQLITE3_INCLUDE_DIRS - The directory where to find the header file +# SQLITE3_LIBRARIES - Where to find the library file +# +# For conveniance, these variables are also set. They have the same values +# than the variables above. The user can thus choose his/her prefered way +# to write them. +# SQLITE3_LIBRARY +# SQLITE3_INCLUDE_DIR +# +# This file is in the public domain + +include(FindPkgConfig) + +if(NOT SQLITE3_FOUND) + pkg_check_modules(SQLITE3 sqlite3) +endif() + +if(NOT SQLITE3_FOUND) + find_path(SQLITE3_INCLUDE_DIRS NAMES sqlite3.h + DOC "The sqlite3 include directory") + + find_library(SQLITE3_LIBRARIES NAMES sqlite3 + DOC "The sqlite3 library") + + # Use some standard module to handle the QUIETLY and REQUIRED arguments, and + # set SQLITE3_FOUND to TRUE if these two variables are set. + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(SQLITE3 REQUIRED_VARS SQLITE3_LIBRARIES SQLITE3_INCLUDE_DIRS) + + if(SQLITE3_FOUND) + set(SQLITE3_LIBRARY ${SQLITE3_LIBRARIES} CACHE INTERNAL "") + set(SQLITE3_INCLUDE_DIR ${SQLITE3_INCLUDE_DIRS} CACHE INTERNAL "") + set(SQLITE3_FOUND ${SQLITE3_FOUND} CACHE INTERNAL "") + endif() +endif() + +mark_as_advanced(SQLITE3_INCLUDE_DIRS SQLITE3_LIBRARIES) \ No newline at end of file -- cgit v1.2.3 From 50cadf3dac0d56ef8181d1800cc30f8dcb749141 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 13 Jun 2017 10:38:39 +0200 Subject: Implement our own database ORM, and update the whole code to use it Entirely replace LiteSQL fix #3271 --- database/database.xml | 70 ------------- src/bridge/bridge.cpp | 18 ++-- src/database/column.hpp | 13 +++ src/database/count_query.hpp | 35 +++++++ src/database/database.cpp | 204 +++++++++++++++++------------------- src/database/database.hpp | 153 ++++++++++++++++++++------- src/database/insert_query.hpp | 128 ++++++++++++++++++++++ src/database/query.cpp | 11 ++ src/database/query.hpp | 46 ++++++++ src/database/row.hpp | 75 +++++++++++++ src/database/select_query.hpp | 153 +++++++++++++++++++++++++++ src/database/table.hpp | 84 +++++++++++++++ src/database/type_to_sql.cpp | 7 ++ src/database/type_to_sql.hpp | 6 ++ src/irc/irc_client.cpp | 24 ++--- src/main.cpp | 5 +- src/utils/reload.cpp | 2 +- src/xmpp/biboumi_adhoc_commands.cpp | 88 ++++++++-------- src/xmpp/biboumi_component.cpp | 16 ++- src/xmpp/biboumi_component.hpp | 4 +- tests/database.cpp | 46 ++++---- 21 files changed, 867 insertions(+), 321 deletions(-) delete mode 100644 database/database.xml create mode 100644 src/database/column.hpp create mode 100644 src/database/count_query.hpp create mode 100644 src/database/insert_query.hpp create mode 100644 src/database/query.cpp create mode 100644 src/database/query.hpp create mode 100644 src/database/row.hpp create mode 100644 src/database/select_query.hpp create mode 100644 src/database/table.hpp create mode 100644 src/database/type_to_sql.cpp create mode 100644 src/database/type_to_sql.hpp diff --git a/database/database.xml b/database/database.xml deleted file mode 100644 index e641fdf..0000000 --- a/database/database.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 4a41b50..fcfcc24 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -23,7 +23,7 @@ static std::string in_encoding_for(const Bridge& bridge, const Iid& iid) #ifdef USE_DATABASE const auto jid = bridge.get_bare_jid(); auto options = Database::get_irc_channel_options_with_server_default(jid, iid.get_server(), iid.get_local()); - return options.encodingIn.value(); + return options.col(); #else (void)bridge; (void)iid; @@ -32,13 +32,13 @@ static std::string in_encoding_for(const Bridge& bridge, const Iid& iid) } Bridge::Bridge(std::string user_jid, BiboumiComponent& xmpp, std::shared_ptr& poller): - user_jid(std::move(user_jid)), + user_jid(std::move(user_jid)), xmpp(xmpp), poller(poller) { #ifdef USE_DATABASE const auto options = Database::get_global_options(this->user_jid); - this->set_record_history(options.recordHistory.value()); + this->set_record_history(options.col()); #endif } @@ -258,7 +258,7 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body) #ifdef USE_DATABASE const auto xmpp_body = this->make_xmpp_body(line); if (this->record_history) - uuid = Database::store_muc_message(this->get_bare_jid(), iid, std::chrono::system_clock::now(), + uuid = Database::store_muc_message(this->get_bare_jid(), iid.get_local(), iid.get_server(), std::chrono::system_clock::now(), std::get<0>(xmpp_body), irc->get_own_nick()); #endif for (const auto& resource: this->resources_in_chan[iid.to_tuple()]) @@ -436,7 +436,7 @@ void Bridge::leave_irc_channel(Iid&& iid, const std::string& status_message, con #ifdef USE_DATABASE const auto coptions = Database::get_irc_channel_options_with_server_default(this->user_jid, iid.get_server(), iid.get_local()); - persistent = coptions.persistent.value(); + persistent = coptions.col(); #endif if (channel->joined && !channel->parting && !persistent) { @@ -837,7 +837,7 @@ void Bridge::send_message(const Iid& iid, const std::string& nick, const std::st #ifdef USE_DATABASE const auto xmpp_body = this->make_xmpp_body(body, encoding); if (!nick.empty() && this->record_history) - Database::store_muc_message(this->get_bare_jid(), iid, std::chrono::system_clock::now(), + Database::store_muc_message(this->get_bare_jid(), iid.get_local(), iid.get_server(), std::chrono::system_clock::now(), std::get<0>(xmpp_body), nick); #endif for (const auto& resource: this->resources_in_chan[iid.to_tuple()]) @@ -994,12 +994,12 @@ void Bridge::send_room_history(const std::string& hostname, std::string chan_nam { #ifdef USE_DATABASE const auto coptions = Database::get_irc_channel_options_with_server_and_global_default(this->user_jid, hostname, chan_name); - const auto lines = Database::get_muc_logs(this->user_jid, chan_name, hostname, coptions.maxHistoryLength.value()); + const auto lines = Database::get_muc_logs(this->user_jid, chan_name, hostname, coptions.col()); chan_name.append(utils::empty_if_fixed_server("%" + hostname)); for (const auto& line: lines) { - const auto seconds = line.date.value().timeStamp(); - this->xmpp.send_history_message(chan_name, line.nick.value(), line.body.value(), + const auto seconds = line.col(); + this->xmpp.send_history_message(chan_name, line.col(), line.col(), this->user_jid + "/" + resource, seconds); } #else diff --git a/src/database/column.hpp b/src/database/column.hpp new file mode 100644 index 0000000..e74d426 --- /dev/null +++ b/src/database/column.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include + +template +struct Column +{ + using real_type = T; + T value; +}; + +struct Id: Column { static constexpr auto name = "id_"; + static constexpr auto options = "PRIMARY KEY AUTOINCREMENT"; }; diff --git a/src/database/count_query.hpp b/src/database/count_query.hpp new file mode 100644 index 0000000..863fad1 --- /dev/null +++ b/src/database/count_query.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +#include + +#include + +struct CountQuery: public Query +{ + CountQuery(std::string name): + Query("SELECT count(*) FROM ") + { + this->body += std::move(name); + } + + std::size_t execute(sqlite3* db) + { + auto statement = this->prepare(db); + std::size_t res = 0; + if (sqlite3_step(statement) == SQLITE_ROW) + res = sqlite3_column_int64(statement, 0); + else + { + log_error("Count request didn’t return a result"); + return 0; + } + if (sqlite3_step(statement) != SQLITE_DONE) + log_warning("Count request returned more than one result."); + + log_debug("Returning count: ", res); + return res; + } +}; diff --git a/src/database/database.cpp b/src/database/database.cpp index 9f310da..1738a69 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -2,175 +2,166 @@ #ifdef USE_DATABASE #include -#include -#include #include #include #include -using namespace std::string_literals; +#include -std::unique_ptr Database::db; +sqlite3* Database::db; +Database::MucLogLineTable Database::muc_log_lines("MucLogLine_"); +Database::GlobalOptionsTable Database::global_options("GlobalOptions_"); +Database::IrcServerOptionsTable Database::irc_server_options("IrcServerOptions_"); +Database::IrcChannelOptionsTable Database::irc_channel_options("IrcChannelOptions_"); -void Database::open(const std::string& filename, const std::string& db_type) +void Database::open(const std::string& filename) { - try - { - auto new_db = std::make_unique(db_type, - "database="s + filename); - if (new_db->needsUpgrade()) - new_db->upgrade(); - Database::db = std::move(new_db); - } catch (const litesql::DatabaseError& e) { - log_error("Failed to open database ", filename, ". ", e.what()); - throw; - } + auto res = sqlite3_open_v2(filename.data(), &Database::db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr); + log_debug("open: ", res); + Database::muc_log_lines.create(Database::db); + Database::global_options.create(Database::db); + Database::irc_server_options.create(Database::db); + Database::irc_channel_options.create(Database::db); } -void Database::set_verbose(const bool val) -{ - Database::db->verbose = val; -} -db::GlobalOptions Database::get_global_options(const std::string& owner) +Database::GlobalOptions Database::get_global_options(const std::string& owner) { - try { - auto options = litesql::select(*Database::db, - db::GlobalOptions::Owner == owner).one(); - return options; - } catch (const litesql::NotFound& e) { - db::GlobalOptions options(*Database::db); - options.owner = owner; - return options; - } + auto request = Database::global_options.select().where() << Owner{} << "=" << owner; + + Database::GlobalOptions options{Database::global_options.get_name()}; + auto result = request.execute(Database::db); + if (result.size() == 1) + options = result.front(); + else + options.col() = owner; + return options; } -db::IrcServerOptions Database::get_irc_server_options(const std::string& owner, - const std::string& server) +Database::IrcServerOptions Database::get_irc_server_options(const std::string& owner, const std::string& server) { - try { - auto options = litesql::select(*Database::db, - db::IrcServerOptions::Owner == owner && - db::IrcServerOptions::Server == server).one(); - return options; - } catch (const litesql::NotFound& e) { - db::IrcServerOptions options(*Database::db); - options.owner = owner; - options.server = server; - // options.update(); - return options; - } + auto request = Database::irc_server_options.select().where() << Owner{} << "=" << owner << " and " << Server{} << "=" << server; + + Database::IrcServerOptions options{Database::irc_server_options.get_name()}; + auto result = request.execute(Database::db); + if (result.size() == 1) + options = result.front(); + else + { + options.col() = owner; + options.col() = server; + } + return options; } -db::IrcChannelOptions Database::get_irc_channel_options(const std::string& owner, - const std::string& server, - const std::string& channel) +Database::IrcChannelOptions Database::get_irc_channel_options(const std::string& owner, const std::string& server, const std::string& channel) { - try { - auto options = litesql::select(*Database::db, - db::IrcChannelOptions::Owner == owner && - db::IrcChannelOptions::Server == server && - db::IrcChannelOptions::Channel == channel).one(); - return options; - } catch (const litesql::NotFound& e) { - db::IrcChannelOptions options(*Database::db); - options.owner = owner; - options.server = server; - options.channel = channel; - return options; - } + auto request = Database::irc_channel_options.select().where() << Owner{} << "=" << owner <<\ + " and " << Server{} << "=" << server <<\ + " and " << Channel{} << "=" << channel; + Database::IrcChannelOptions options{Database::irc_channel_options.get_name()}; + auto result = request.execute(Database::db); + if (result.size() == 1) + options = result.front(); + else + { + options.col() = owner; + options.col() = server; + options.col() = channel; + } + return options; } -db::IrcChannelOptions Database::get_irc_channel_options_with_server_default(const std::string& owner, - const std::string& server, - const std::string& channel) +Database::IrcChannelOptions Database::get_irc_channel_options_with_server_default(const std::string& owner, const std::string& server, + const std::string& channel) { auto coptions = Database::get_irc_channel_options(owner, server, channel); auto soptions = Database::get_irc_server_options(owner, server); - coptions.encodingIn = get_first_non_empty(coptions.encodingIn.value(), - soptions.encodingIn.value()); - coptions.encodingOut = get_first_non_empty(coptions.encodingOut.value(), - soptions.encodingOut.value()); + coptions.col() = get_first_non_empty(coptions.col(), + soptions.col()); + coptions.col() = get_first_non_empty(coptions.col(), + soptions.col()); - coptions.maxHistoryLength = get_first_non_empty(coptions.maxHistoryLength.value(), - soptions.maxHistoryLength.value()); + coptions.col() = get_first_non_empty(coptions.col(), + soptions.col()); return coptions; } -db::IrcChannelOptions Database::get_irc_channel_options_with_server_and_global_default(const std::string& owner, - const std::string& server, - const std::string& channel) +Database::IrcChannelOptions Database::get_irc_channel_options_with_server_and_global_default(const std::string& owner, const std::string& server, const std::string& channel) { auto coptions = Database::get_irc_channel_options(owner, server, channel); auto soptions = Database::get_irc_server_options(owner, server); auto goptions = Database::get_global_options(owner); - coptions.encodingIn = get_first_non_empty(coptions.encodingIn.value(), - soptions.encodingIn.value()); - coptions.encodingOut = get_first_non_empty(coptions.encodingOut.value(), - soptions.encodingOut.value()); + coptions.col() = get_first_non_empty(coptions.col(), + soptions.col()); - coptions.maxHistoryLength = get_first_non_empty(coptions.maxHistoryLength.value(), - soptions.maxHistoryLength.value(), - goptions.maxHistoryLength.value()); + coptions.col() = get_first_non_empty(coptions.col(), + soptions.col()); + + coptions.col() = get_first_non_empty(coptions.col(), + soptions.col(), + goptions.col()); return coptions; } -std::string Database::store_muc_message(const std::string& owner, const Iid& iid, - Database::time_point date, - const std::string& body, - const std::string& nick) +std::string Database::store_muc_message(const std::string& owner, const std::string& chan_name, + const std::string& server_name, Database::time_point date, + const std::string& body, const std::string& nick) { - db::MucLogLine line(*Database::db); + auto line = Database::muc_log_lines.row(); auto uuid = Database::gen_uuid(); - line.uuid = uuid; - line.owner = owner; - line.ircChanName = iid.get_local(); - line.ircServerName = iid.get_server(); - line.date = std::chrono::duration_cast(date.time_since_epoch()).count(); - line.body = body; - line.nick = nick; + line.col() = uuid; + line.col() = owner; + line.col() = chan_name; + line.col() = server_name; + line.col() = std::chrono::duration_cast(date.time_since_epoch()).count(); + line.col() = body; + line.col() = nick; - line.update(); + line.save(Database::db); return uuid; } -std::vector Database::get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, +std::vector Database::get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, int limit, const std::string& start, const std::string& end) { - auto request = litesql::select(*Database::db, - db::MucLogLine::Owner == owner && - db::MucLogLine::IrcChanName == chan_name && - db::MucLogLine::IrcServerName == server); - request.orderBy(db::MucLogLine::Id, false); + auto request = Database::muc_log_lines.select().where() << Database::Owner{} << "=" << owner << \ + " and " << Database::IrcChanName{} << "=" << chan_name << \ + " and " << Database::IrcServerName{} << "=" << server; - if (limit >= 0) - request.limit(limit); if (!start.empty()) { const auto start_time = utils::parse_datetime(start); if (start_time != -1) - request.where(db::MucLogLine::Date >= start_time); + request << " and " << Database::Date{} << ">=" << start_time; } if (!end.empty()) { const auto end_time = utils::parse_datetime(end); if (end_time != -1) - request.where(db::MucLogLine::Date <= end_time); + request << " and " << Database::Date{} << "<=" << end_time; } - const auto& res = request.all(); - return {res.crbegin(), res.crend()}; + + request.order_by() << Id{} << " DESC "; + + if (limit >= 0) + request.limit() << limit; + + auto result = request.execute(Database::db); + + return {result.crbegin(), result.crend()}; } void Database::close() { - Database::db.reset(nullptr); + sqlite3_close_v2(Database::db); } std::string Database::gen_uuid() @@ -182,5 +173,4 @@ std::string Database::gen_uuid() return uuid_str; } - -#endif +#endif \ No newline at end of file diff --git a/src/database/database.hpp b/src/database/database.hpp index b08a175..ebc4878 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -1,22 +1,101 @@ #pragma once - #include #ifdef USE_DATABASE -#include "biboudb.hpp" - -#include +#include +#include +#include -#include #include +#include + +#include -class Iid; class Database { -public: + public: using time_point = std::chrono::system_clock::time_point; + + struct Uuid: Column { static constexpr auto name = "uuid_"; + static constexpr auto options = ""; }; + + struct Owner: Column { static constexpr auto name = "owner_"; + static constexpr auto options = ""; }; + + struct IrcChanName: Column { static constexpr auto name = "ircChanName_"; + static constexpr auto options = ""; }; + + struct Channel: Column { static constexpr auto name = "channel_"; + static constexpr auto options = ""; }; + + struct IrcServerName: Column { static constexpr auto name = "ircServerName_"; + static constexpr auto options = ""; }; + + struct Server: Column { static constexpr auto name = "server_"; + static constexpr auto options = ""; }; + + struct Date: Column { static constexpr auto name = "date_"; + static constexpr auto options = ""; }; + + struct Body: Column { static constexpr auto name = "body_"; + static constexpr auto options = ""; }; + + struct Nick: Column { static constexpr auto name = "nick_"; + static constexpr auto options = ""; }; + + struct Pass: Column { static constexpr auto name = "pass_"; + static constexpr auto options = ""; }; + + struct Ports: Column { static constexpr auto name = "tlsPorts_"; + static constexpr auto options = ""; }; + + struct TlsPorts: Column { static constexpr auto name = "ports_"; + static constexpr auto options = ""; }; + + struct Username: Column { static constexpr auto name = "username_"; + static constexpr auto options = ""; }; + + struct Realname: Column { static constexpr auto name = "realname_"; + static constexpr auto options = ""; }; + + struct AfterConnectionCommand: Column { static constexpr auto name = "afterConnectionCommand_"; + static constexpr auto options = ""; }; + + struct TrustedFingerprint: Column { static constexpr auto name = "trustedFingerprint_"; + static constexpr auto options = ""; }; + + struct EncodingOut: Column { static constexpr auto name = "encodingOut_"; + static constexpr auto options = ""; }; + + struct EncodingIn: Column { static constexpr auto name = "encodingIn_"; + static constexpr auto options = ""; }; + + struct MaxHistoryLength: Column { static constexpr auto name = "maxHistoryLength_"; + static constexpr auto options = ""; }; + + struct RecordHistory: Column { static constexpr auto name = "recordHistory_"; + static constexpr auto options = ""; }; + + struct VerifyCert: Column { static constexpr auto name = "verifyCert_"; + static constexpr auto options = ""; }; + + struct Persistent: Column { static constexpr auto name = "persistent_"; + static constexpr auto options = ""; }; + + using MucLogLineTable = Table; + using MucLogLine = MucLogLineTable::RowType; + + using GlobalOptionsTable = Table; + using GlobalOptions = GlobalOptionsTable::RowType; + + using IrcServerOptionsTable = Table; + using IrcServerOptions = IrcServerOptionsTable::RowType; + + using IrcChannelOptionsTable = Table; + using IrcChannelOptions = IrcChannelOptionsTable::RowType; + Database() = default; ~Database() = default; @@ -25,42 +104,40 @@ public: Database& operator=(const Database&) = delete; Database& operator=(Database&&) = delete; - static void set_verbose(const bool val); - - template - static size_t count() - { - return litesql::select(*Database::db).count(); - } - /** - * Return the object from the db. Create it beforehand (with all default - * values) if it is not already present. - */ - static db::GlobalOptions get_global_options(const std::string& owner); - static db::IrcServerOptions get_irc_server_options(const std::string& owner, + static GlobalOptions get_global_options(const std::string& owner); + static IrcServerOptions get_irc_server_options(const std::string& owner, const std::string& server); - static db::IrcChannelOptions get_irc_channel_options(const std::string& owner, - const std::string& server, - const std::string& channel); - static db::IrcChannelOptions get_irc_channel_options_with_server_default(const std::string& owner, - const std::string& server, - const std::string& channel); - static db::IrcChannelOptions get_irc_channel_options_with_server_and_global_default(const std::string& owner, - const std::string& server, - const std::string& channel); - static std::vector get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, - int limit=-1, const std::string& start="", const std::string& end=""); - static std::string store_muc_message(const std::string& owner, const Iid& iid, - time_point date, const std::string& body, const std::string& nick); + static IrcChannelOptions get_irc_channel_options(const std::string& owner, + const std::string& server, + const std::string& channel); + static IrcChannelOptions get_irc_channel_options_with_server_default(const std::string& owner, + const std::string& server, + const std::string& channel); + static IrcChannelOptions get_irc_channel_options_with_server_and_global_default(const std::string& owner, + const std::string& server, + const std::string& channel); + static std::vector get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, + int limit=-1, const std::string& start="", const std::string& end=""); + static std::string store_muc_message(const std::string& owner, const std::string& chan_name, const std::string& server_name, + time_point date, const std::string& body, const std::string& nick); static void close(); - static void open(const std::string& filename, const std::string& db_type="sqlite3"); + static void open(const std::string& filename); + template + static std::size_t count(const TableType& table) + { + CountQuery query{table.get_name()}; + return query.execute(Database::db); + } + + static MucLogLineTable muc_log_lines; + static GlobalOptionsTable global_options; + static IrcServerOptionsTable irc_server_options; + static IrcChannelOptionsTable irc_channel_options; + static sqlite3* db; -private: + private: static std::string gen_uuid(); - static std::unique_ptr db; }; #endif /* USE_DATABASE */ - - diff --git a/src/database/insert_query.hpp b/src/database/insert_query.hpp new file mode 100644 index 0000000..00b77c5 --- /dev/null +++ b/src/database/insert_query.hpp @@ -0,0 +1,128 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include +#include + +#include + +template +typename std::enable_if, Id>::value, void>::type +actual_bind(sqlite3_stmt* statement, std::vector& params, const std::tuple&) +{ + const auto value = params.front(); + params.erase(params.begin()); + if (sqlite3_bind_text(statement, N + 1, value.data(), static_cast(value.size()), SQLITE_TRANSIENT) != SQLITE_OK) + log_error("Failed to bind ", value, " to param ", N); + else + log_debug("Bound (not id) [", value, "] to ", N); +} + +template +typename std::enable_if, Id>::value, void>::type +actual_bind(sqlite3_stmt* statement, std::vector&, const std::tuple& columns) +{ + auto&& column = std::get(columns); + if (column.value != 0) + { + if (sqlite3_bind_int64(statement, N + 1, column.value) != SQLITE_OK) + log_error("Failed to bind ", column.value, " to id."); + } + else if (sqlite3_bind_null(statement, N + 1) != SQLITE_OK) + log_error("Failed to bind NULL to param ", N); + else + log_debug("Bound NULL to ", N); +} + +struct InsertQuery: public Query +{ + InsertQuery(const std::string& name): + Query("INSERT OR REPLACE INTO ") + { + this->body += name; + } + + template + void execute(const std::tuple& columns, sqlite3* db) + { + auto statement = this->prepare(db); + { + this->bind_param<0>(columns, statement); + if (sqlite3_step(statement) != SQLITE_DONE) + log_error("Failed to execute query: ", sqlite3_errmsg(db)); + } + } + + template + typename std::enable_if::type + bind_param(const std::tuple& columns, sqlite3_stmt* statement) + { + using ColumnType = typename std::remove_reference(columns))>::type; + + actual_bind(statement, this->params, columns); + this->bind_param(columns, statement); + } + + template + typename std::enable_if::type + bind_param(const std::tuple&, sqlite3_stmt*) + {} + + template + void insert_values(const std::tuple& columns) + { + this->body += "VALUES ("; + this->insert_value<0>(columns); + this->body += ")"; + } + + template + typename std::enable_if::type + insert_value(const std::tuple& columns) + { + this->body += "?"; + if (N != sizeof...(T) - 1) + this->body += ","; + this->body += " "; + add_param(*this, std::get(columns)); + this->insert_value(columns); + } + template + typename std::enable_if::type + insert_value(const std::tuple&) + { } + + template + void insert_col_names(const std::tuple& columns) + { + this->body += " ("; + this->insert_col_name<0>(columns); + this->body += ")\n"; + } + + template + typename std::enable_if::type + insert_col_name(const std::tuple& columns) + { + auto value = std::get(columns); + + this->body += value.name; + + if (N < (sizeof...(T) - 1)) + this->body += ", "; + + this->insert_col_name(columns); + } + template + typename std::enable_if::type + insert_col_name(const std::tuple&) + {} + + + private: +}; diff --git a/src/database/query.cpp b/src/database/query.cpp new file mode 100644 index 0000000..fb8c055 --- /dev/null +++ b/src/database/query.cpp @@ -0,0 +1,11 @@ +#include +#include + +template <> +void add_param(Query&, const Id&) +{} + +void actual_add_param(Query& query, const std::string& val) +{ + query.params.push_back(val); +} diff --git a/src/database/query.hpp b/src/database/query.hpp new file mode 100644 index 0000000..92845d0 --- /dev/null +++ b/src/database/query.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include + +#include +#include + +#include + +struct Query +{ + std::string body; + std::vector params; + + Query(std::string str): + body(std::move(str)) + {} + + sqlite3_stmt* prepare(sqlite3* db) + { + sqlite3_stmt* statement; + log_debug(this->body); + auto res = sqlite3_prepare(db, this->body.data(), static_cast(this->body.size()) + 1, + &statement, nullptr); + if (res != SQLITE_OK) + { + log_error("Error preparing statement: ", sqlite3_errmsg(db)); + return nullptr; + } + return statement; + } +}; + +template +void add_param(Query& query, const ColumnType& column) +{ + actual_add_param(query, column.value); +} + +template +void actual_add_param(Query& query, const T& val) +{ + query.params.push_back(std::to_string(val)); +} + +void actual_add_param(Query& query, const std::string& val); diff --git a/src/database/row.hpp b/src/database/row.hpp new file mode 100644 index 0000000..ca686c1 --- /dev/null +++ b/src/database/row.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include +#include + +#include + +#include + +template +typename std::enable_if, Id>::value, void>::type +update_id(std::tuple&, sqlite3*) +{} + +template +typename std::enable_if, Id>::value, void>::type +update_id(std::tuple& columns, sqlite3* db) +{ + auto&& column = std::get(columns); + log_debug("Found an autoincrement col."); + auto res = sqlite3_last_insert_rowid(db); + log_debug("Value is now: ", res); + column.value = res; +} + +template +typename std::enable_if::type +update_autoincrement_id(std::tuple& columns, sqlite3* db) +{ + using ColumnType = typename std::remove_reference(columns))>::type; + update_id(columns, db); + update_autoincrement_id(columns, db); +} + +template +typename std::enable_if::type +update_autoincrement_id(std::tuple&, sqlite3*) +{} + +template +struct Row +{ + Row(std::string name): + table_name(std::move(name)) + {} + + template + auto& col() + { + auto&& col = std::get(this->columns); + return col.value; + } + + template + const auto& col() const + { + auto&& col = std::get(this->columns); + return col.value; + } + + void save(sqlite3* db) + { + InsertQuery query(this->table_name); + query.insert_col_names(this->columns); + query.insert_values(this->columns); + log_debug(query.body); + + query.execute(this->columns, db); + + update_autoincrement_id<0>(this->columns, db); + } + + std::tuple columns; + std::string table_name; +}; diff --git a/src/database/select_query.hpp b/src/database/select_query.hpp new file mode 100644 index 0000000..b41632e --- /dev/null +++ b/src/database/select_query.hpp @@ -0,0 +1,153 @@ +#pragma once + +#include +#include +#include + +#include +#include + +#include + +using namespace std::string_literals; + +template +typename std::enable_if::value, sqlite3_int64>::type +extract_row_value(sqlite3_stmt* statement, const int i) +{ + return sqlite3_column_int64(statement, i); +} + +template +typename std::enable_if::value, std::string>::type +extract_row_value(sqlite3_stmt* statement, const int i) +{ + const auto size = sqlite3_column_bytes(statement, i); + const unsigned char* str = sqlite3_column_text(statement, i); + std::string result(reinterpret_cast(str), size); + return result; +} + +template +typename std::enable_if::type +extract_row_values(Row& row, sqlite3_stmt* statement) +{ + using ColumnType = typename std::remove_reference(row.columns))>::type; + + auto&& column = std::get(row.columns); + column.value = static_cast(extract_row_value(statement, N)); + + extract_row_values(row, statement); +} + +template +typename std::enable_if::type +extract_row_values(Row&, sqlite3_stmt*) +{} + +template +struct SelectQuery: public Query +{ + SelectQuery(std::string table_name): + Query("SELECT"), + table_name(table_name) + { + this->insert_col_name<0>(); + this->body += " from " + this->table_name; + } + + template + typename std::enable_if::type + insert_col_name() + { + using ColumnsType = std::tuple; + ColumnsType tuple{}; + auto value = std::get(tuple); + + this->body += " "s + value.name; + + if (N < (sizeof...(T) - 1)) + this->body += ", "; + + this->insert_col_name(); + } + template + typename std::enable_if::type + insert_col_name() + {} + + SelectQuery& where() + { + this->body += " WHERE "; + return *this; + }; + + SelectQuery& order_by() + { + this->body += " ORDER BY "; + return *this; + } + + SelectQuery& limit() + { + this->body += " LIMIT "; + return *this; + } + + auto execute(sqlite3* db) + { + auto statement = this->prepare(db); + int i = 1; + for (const std::string& param: this->params) + { + if (sqlite3_bind_text(statement, i, param.data(), static_cast(param.size()), SQLITE_TRANSIENT) != SQLITE_OK) + log_debug("Failed to bind ", param, " to param ", i); + else + log_debug("Bound ", param, " to ", i); + + i++; + } + std::vector> rows; + while (sqlite3_step(statement) == SQLITE_ROW) + { + Row row(this->table_name); + extract_row_values(row, statement); + rows.push_back(row); + } + return rows; + } + + const std::string table_name; +}; + +template +typename std::enable_if::value, SelectQuery&>::type +operator<<(SelectQuery& query, const T&) +{ + query.body += T::name; + return query; +} + +template +SelectQuery& operator<<(SelectQuery& query, const char* str) +{ + query.body += str; + return query; +} + +template +SelectQuery& operator<<(SelectQuery& query, const std::string& str) +{ + query.body += "?"; + actual_add_param(query, str); + return query; +} + +template +typename std::enable_if::value, SelectQuery&>::type +operator<<(SelectQuery& query, const Integer& i) +{ + query.body += "?"; + actual_add_param(query, i); + return query; +} diff --git a/src/database/table.hpp b/src/database/table.hpp new file mode 100644 index 0000000..163b97f --- /dev/null +++ b/src/database/table.hpp @@ -0,0 +1,84 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include + +template +class Table +{ + static_assert(sizeof...(T) > 0, "Table cannot be empty"); + using ColumnTypes = std::tuple; + + public: + using RowType = Row; + + Table(std::string name): + name(std::move(name)) + {} + + void create(sqlite3* db) + { + std::string res{"CREATE TABLE IF NOT EXISTS "}; + res += this->name; + res += " (\n"; + this->add_column_create<0>(res); + res += ")"; + + log_debug(res); + + char* error; + const auto result = sqlite3_exec(db, res.data(), nullptr, nullptr, &error); + log_debug("result: ", +result); + if (result != SQLITE_OK) + { + log_error("Error executing query: ", error); + sqlite3_free(error); + } + } + + RowType row() + { + return {this->name}; + } + + SelectQuery select() + { + SelectQuery select(this->name); + return select; + } + + const std::string& get_name() const + { + return this->name; + } + + private: + template + typename std::enable_if::type + add_column_create(std::string& str) + { + using ColumnType = typename std::remove_reference(std::declval()))>::type; + using RealType = typename ColumnType::real_type; + str += ColumnType::name; + str += " "; + str += TypeToSQLType::type; + str += " "s + ColumnType::options; + if (N != sizeof...(T) - 1) + str += ","; + str += "\n"; + + add_column_create(str); + } + + template + typename std::enable_if::type + add_column_create(std::string&) + { } + + const std::string name; +}; diff --git a/src/database/type_to_sql.cpp b/src/database/type_to_sql.cpp new file mode 100644 index 0000000..5de012e --- /dev/null +++ b/src/database/type_to_sql.cpp @@ -0,0 +1,7 @@ +#include + +template <> const std::string TypeToSQLType::type = "INTEGER"; +template <> const std::string TypeToSQLType::type = "INTEGER"; +template <> const std::string TypeToSQLType::type = "INTEGER"; +template <> const std::string TypeToSQLType::type = "INTEGER"; +template <> const std::string TypeToSQLType::type = "TEXT"; diff --git a/src/database/type_to_sql.hpp b/src/database/type_to_sql.hpp new file mode 100644 index 0000000..5ae03ad --- /dev/null +++ b/src/database/type_to_sql.hpp @@ -0,0 +1,6 @@ +#pragma once + +#include + +template +struct TypeToSQLType { static const std::string type; }; diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 1d74098..bacb89e 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -156,11 +156,11 @@ IrcClient::IrcClient(std::shared_ptr& poller, std::string hostname, #ifdef USE_DATABASE auto options = Database::get_irc_server_options(this->bridge.get_bare_jid(), this->get_hostname()); - std::vector ports = utils::split(options.ports, ';', false); + std::vector ports = utils::split(options.col(), ';', false); for (auto it = ports.rbegin(); it != ports.rend(); ++it) this->ports_to_try.emplace(*it, false); # ifdef BOTAN_FOUND - ports = utils::split(options.tlsPorts, ';', false); + ports = utils::split(options.col(), ';', false); for (auto it = ports.rbegin(); it != ports.rend(); ++it) this->ports_to_try.emplace(*it, true); # endif // BOTAN_FOUND @@ -204,7 +204,7 @@ void IrcClient::start() # ifdef USE_DATABASE auto options = Database::get_irc_server_options(this->bridge.get_bare_jid(), this->get_hostname()); - this->credential_manager.set_trusted_fingerprint(options.trustedFingerprint); + this->credential_manager.set_trusted_fingerprint(options.col()); # endif #endif this->connect(this->hostname, port, tls); @@ -275,8 +275,8 @@ void IrcClient::on_connected() #ifdef USE_DATABASE auto options = Database::get_irc_server_options(this->bridge.get_bare_jid(), this->get_hostname()); - if (!options.pass.value().empty()) - this->send_pass_command(options.pass.value()); + if (!options.col().empty()) + this->send_pass_command(options.col()); #endif this->send_nick_command(this->current_nick); @@ -284,10 +284,10 @@ void IrcClient::on_connected() #ifdef USE_DATABASE if (Config::get("realname_customization", "true") == "true") { - if (!options.username.value().empty()) - this->username = options.username.value(); - if (!options.realname.value().empty()) - this->realname = options.realname.value(); + if (!options.col().empty()) + this->username = options.col(); + if (!options.col().empty()) + this->realname = options.col(); this->send_user_command(username, realname); } else @@ -894,8 +894,8 @@ void IrcClient::on_welcome_message(const IrcMessage& message) #ifdef USE_DATABASE auto options = Database::get_irc_server_options(this->bridge.get_bare_jid(), this->get_hostname()); - if (!options.afterConnectionCommand.value().empty()) - this->send_raw(options.afterConnectionCommand.value()); + if (!options.col().empty()) + this->send_raw(options.col()); #endif // Install a repeated events to regularly send a PING TimedEventsManager::instance().add_event(TimedEvent(240s, std::bind(&IrcClient::send_ping_command, this), @@ -1260,7 +1260,7 @@ bool IrcClient::abort_on_invalid_cert() const { #ifdef USE_DATABASE auto options = Database::get_irc_server_options(this->bridge.get_bare_jid(), this->hostname); - return options.verifyCert.value(); + return options.col(); #endif return true; } diff --git a/src/main.cpp b/src/main.cpp index 1a9b065..5725584 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,9 +12,6 @@ #include #include -#ifdef USE_DATABASE -# include -#endif #include @@ -91,7 +88,7 @@ int main(int ac, char** av) #ifdef USE_DATABASE try { open_database(); - } catch (const litesql::DatabaseError&) { + } catch (...) { return 1; } #endif diff --git a/src/utils/reload.cpp b/src/utils/reload.cpp index 348c5b5..fdca9bc 100644 --- a/src/utils/reload.cpp +++ b/src/utils/reload.cpp @@ -26,7 +26,7 @@ void reload_process() #ifdef USE_DATABASE try { open_database(); - } catch (const litesql::DatabaseError&) { + } catch (...) { log_warning("Re-using the previous database."); } #endif diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp index ab28cfd..a13dbb8 100644 --- a/src/xmpp/biboumi_adhoc_commands.cpp +++ b/src/xmpp/biboumi_adhoc_commands.cpp @@ -130,7 +130,7 @@ void ConfigureGlobalStep1(XmppComponent&, AdhocSession& session, XmlNode& comman { XmlSubNode value(max_histo_length, "value"); - value.set_inner(std::to_string(options.maxHistoryLength.value())); + value.set_inner(std::to_string(options.col())); } XmlSubNode record_history(x, "field"); @@ -142,7 +142,7 @@ void ConfigureGlobalStep1(XmppComponent&, AdhocSession& session, XmlNode& comman { XmlSubNode value(record_history, "value"); value.set_name("value"); - if (options.recordHistory.value()) + if (options.col()) value.set_inner("true"); else value.set_inner("false"); @@ -164,18 +164,18 @@ void ConfigureGlobalStep2(XmppComponent& xmpp_component, AdhocSession& session, if (field->get_tag("var") == "max_history_length" && value && !value->get_inner().empty()) - options.maxHistoryLength = value->get_inner(); + options.col() = atoi(value->get_inner().data()); else if (field->get_tag("var") == "record_history" && value && !value->get_inner().empty()) { - options.recordHistory = to_bool(value->get_inner()); + options.col() = to_bool(value->get_inner()); Bridge* bridge = biboumi_component.find_user_bridge(owner.bare()); if (bridge) - bridge->set_record_history(options.recordHistory.value()); + bridge->set_record_history(options.col()); } } - options.update(); + options.save(Database::db); command_node.delete_all_children(); XmlSubNode note(command_node, "note"); @@ -211,8 +211,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com ports["type"] = "text-multi"; ports["label"] = "Ports"; ports["desc"] = "List of ports to try, without TLS. Defaults: 6667."; - auto vals = utils::split(options.ports.value(), ';', false); - for (const auto& val: vals) + for (const auto& val: utils::split(options.col(), ';', false)) { XmlSubNode ports_value(ports, "value"); ports_value.set_inner(val); @@ -224,8 +223,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com tls_ports["type"] = "text-multi"; tls_ports["label"] = "TLS ports"; tls_ports["desc"] = "List of ports to try, with TLS. Defaults: 6697, 6670."; - vals = utils::split(options.tlsPorts.value(), ';', false); - for (const auto& val: vals) + for (const auto& val: utils::split(options.col(), ';', false)) { XmlSubNode tls_ports_value(tls_ports, "value"); tls_ports_value.set_inner(val); @@ -237,7 +235,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com verify_cert["label"] = "Verify certificate"; verify_cert["desc"] = "Whether or not to abort the connection if the server’s TLS certificate is invalid"; XmlSubNode verify_cert_value(verify_cert, "value"); - if (options.verifyCert.value()) + if (options.col()) verify_cert_value.set_inner("true"); else verify_cert_value.set_inner("false"); @@ -246,10 +244,10 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com fingerprint["var"] = "fingerprint"; fingerprint["type"] = "text-single"; fingerprint["label"] = "SHA-1 fingerprint of the TLS certificate to trust."; - if (!options.trustedFingerprint.value().empty()) + if (!options.col().empty()) { XmlSubNode fingerprint_value(fingerprint, "value"); - fingerprint_value.set_inner(options.trustedFingerprint.value()); + fingerprint_value.set_inner(options.col()); } #endif @@ -258,10 +256,10 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com pass["type"] = "text-private"; pass["label"] = "Server password"; pass["desc"] = "Will be used in a PASS command when connecting"; - if (!options.pass.value().empty()) + if (!options.col().empty()) { XmlSubNode pass_value(pass, "value"); - pass_value.set_inner(options.pass.value()); + pass_value.set_inner(options.col()); } XmlSubNode after_cnt_cmd(x, "field"); @@ -269,10 +267,10 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com after_cnt_cmd["type"] = "text-single"; after_cnt_cmd["desc"] = "Custom IRC command sent after the connection is established with the server."; after_cnt_cmd["label"] = "After-connection IRC command"; - if (!options.afterConnectionCommand.value().empty()) + if (!options.col().empty()) { XmlSubNode after_cnt_cmd_value(after_cnt_cmd, "value"); - after_cnt_cmd_value.set_inner(options.afterConnectionCommand.value()); + after_cnt_cmd_value.set_inner(options.col()); } if (Config::get("realname_customization", "true") == "true") @@ -281,20 +279,20 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com username["var"] = "username"; username["type"] = "text-single"; username["label"] = "Username"; - if (!options.username.value().empty()) + if (!options.col().empty()) { XmlSubNode username_value(username, "value"); - username_value.set_inner(options.username.value()); + username_value.set_inner(options.col()); } XmlSubNode realname(x, "field"); realname["var"] = "realname"; realname["type"] = "text-single"; realname["label"] = "Realname"; - if (!options.realname.value().empty()) + if (!options.col().empty()) { XmlSubNode realname_value(realname, "value"); - realname_value.set_inner(options.realname.value()); + realname_value.set_inner(options.col()); } } @@ -303,10 +301,10 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com encoding_out["type"] = "text-single"; encoding_out["desc"] = "The encoding used when sending messages to the IRC server."; encoding_out["label"] = "Out encoding"; - if (!options.encodingOut.value().empty()) + if (!options.col().empty()) { XmlSubNode encoding_out_value(encoding_out, "value"); - encoding_out_value.set_inner(options.encodingOut.value()); + encoding_out_value.set_inner(options.col()); } XmlSubNode encoding_in(x, "field"); @@ -314,10 +312,10 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com encoding_in["type"] = "text-single"; encoding_in["desc"] = "The encoding used to decode message received from the IRC server."; encoding_in["label"] = "In encoding"; - if (!options.encodingIn.value().empty()) + if (!options.col().empty()) { XmlSubNode encoding_in_value(encoding_in, "value"); - encoding_in_value.set_inner(options.encodingIn.value()); + encoding_in_value.set_inner(options.col()); } } @@ -342,7 +340,7 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com std::string ports; for (const auto& val: values) ports += val->get_inner() + ";"; - options.ports = ports; + options.col() = ports; } #ifdef BOTAN_FOUND @@ -351,31 +349,31 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com std::string ports; for (const auto& val: values) ports += val->get_inner() + ";"; - options.tlsPorts = ports; + options.col() = ports; } else if (field->get_tag("var") == "verify_cert" && value && !value->get_inner().empty()) { auto val = to_bool(value->get_inner()); - options.verifyCert = val; + options.col() = val; } else if (field->get_tag("var") == "fingerprint" && value && !value->get_inner().empty()) { - options.trustedFingerprint = value->get_inner(); + options.col() = value->get_inner(); } #endif // BOTAN_FOUND else if (field->get_tag("var") == "pass" && value && !value->get_inner().empty()) - options.pass = value->get_inner(); + options.col() = value->get_inner(); else if (field->get_tag("var") == "after_connect_command" && value && !value->get_inner().empty()) - options.afterConnectionCommand = value->get_inner(); + options.col() = value->get_inner(); else if (field->get_tag("var") == "username" && value && !value->get_inner().empty()) @@ -383,24 +381,24 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com auto username = value->get_inner(); // The username must not contain spaces std::replace(username.begin(), username.end(), ' ', '_'); - options.username = username; + options.col() = username; } else if (field->get_tag("var") == "realname" && value && !value->get_inner().empty()) - options.realname = value->get_inner(); + options.col() = value->get_inner(); else if (field->get_tag("var") == "encoding_out" && value && !value->get_inner().empty()) - options.encodingOut = value->get_inner(); + options.col() = value->get_inner(); else if (field->get_tag("var") == "encoding_in" && value && !value->get_inner().empty()) - options.encodingIn = value->get_inner(); + options.col() = value->get_inner(); } - options.update(); + options.save(Database::db); command_node.delete_all_children(); XmlSubNode note(command_node, "note"); @@ -441,10 +439,10 @@ void insert_irc_channel_configuration_form(XmlNode& node, const Jid& requester, encoding_out["type"] = "text-single"; encoding_out["desc"] = "The encoding used when sending messages to the IRC server. Defaults to the server's “out encoding” if unset for the channel"; encoding_out["label"] = "Out encoding"; - if (!options.encodingOut.value().empty()) + if (!options.col().empty()) { XmlSubNode encoding_out_value(encoding_out, "value"); - encoding_out_value.set_inner(options.encodingOut.value()); + encoding_out_value.set_inner(options.col()); } XmlSubNode encoding_in(x, "field"); @@ -452,10 +450,10 @@ void insert_irc_channel_configuration_form(XmlNode& node, const Jid& requester, encoding_in["type"] = "text-single"; encoding_in["desc"] = "The encoding used to decode message received from the IRC server. Defaults to the server's “in encoding” if unset for the channel"; encoding_in["label"] = "In encoding"; - if (!options.encodingIn.value().empty()) + if (!options.col().empty()) { XmlSubNode encoding_in_value(encoding_in, "value"); - encoding_in_value.set_inner(options.encodingIn.value()); + encoding_in_value.set_inner(options.col()); } XmlSubNode persistent(x, "field"); @@ -466,7 +464,7 @@ void insert_irc_channel_configuration_form(XmlNode& node, const Jid& requester, { XmlSubNode value(persistent, "value"); value.set_name("value"); - if (options.persistent.value()) + if (options.col()) value.set_inner("true"); else value.set_inner("false"); @@ -510,18 +508,18 @@ bool handle_irc_channel_configuration_form(const XmlNode& node, const Jid& reque if (field->get_tag("var") == "encoding_out" && value && !value->get_inner().empty()) - options.encodingOut = value->get_inner(); + options.col() = value->get_inner(); else if (field->get_tag("var") == "encoding_in" && value && !value->get_inner().empty()) - options.encodingIn = value->get_inner(); + options.col() = value->get_inner(); else if (field->get_tag("var") == "persistent" && value) - options.persistent = to_bool(value->get_inner()); + options.col() = to_bool(value->get_inner()); } - options.update(); + options.save(Database::db); } return true; } diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index ca3a887..881e757 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -18,8 +18,6 @@ #include -#include - #ifdef SYSTEMD_FOUND # include #endif @@ -648,9 +646,9 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza) limit = 100; } const auto lines = Database::get_muc_logs(from.bare(), iid.get_local(), iid.get_server(), limit, start, end); - for (const db::MucLogLine& line: lines) + for (const Database::MucLogLine& line: lines) { - if (!line.nick.value().empty()) + if (!line.col().empty()) this->send_archived_message(line, to.full(), from.full(), query_id); } this->send_iq_result_full_jid(id, from.full(), to.full()); @@ -659,7 +657,7 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza) return false; } -void BiboumiComponent::send_archived_message(const db::MucLogLine& log_line, const std::string& from, const std::string& to, +void BiboumiComponent::send_archived_message(const Database::MucLogLine& log_line, const std::string& from, const std::string& to, const std::string& queryid) { Stanza message("message"); @@ -671,22 +669,22 @@ void BiboumiComponent::send_archived_message(const db::MucLogLine& log_line, con result["xmlns"] = MAM_NS; if (!queryid.empty()) result["queryid"] = queryid; - result["id"] = log_line.uuid.value(); + result["id"] = log_line.col(); XmlSubNode forwarded(result, "forwarded"); forwarded["xmlns"] = FORWARD_NS; XmlSubNode delay(forwarded, "delay"); delay["xmlns"] = DELAY_NS; - delay["stamp"] = utils::to_string(log_line.date.value().timeStamp()); + delay["stamp"] = utils::to_string(log_line.col()); XmlSubNode submessage(forwarded, "message"); submessage["xmlns"] = CLIENT_NS; - submessage["from"] = from + "/" + log_line.nick.value(); + submessage["from"] = from + "/" + log_line.col(); submessage["type"] = "groupchat"; XmlSubNode body(submessage, "body"); - body.set_inner(log_line.body.value()); + body.set_inner(log_line.col()); } this->send_stanza(message); } diff --git a/src/xmpp/biboumi_component.hpp b/src/xmpp/biboumi_component.hpp index ac9bde4..87311f9 100644 --- a/src/xmpp/biboumi_component.hpp +++ b/src/xmpp/biboumi_component.hpp @@ -1,6 +1,6 @@ #pragma once - +#include #include #include @@ -96,7 +96,7 @@ public: #ifdef USE_DATABASE bool handle_mam_request(const Stanza& stanza); - void send_archived_message(const db::MucLogLine& log_line, const std::string& from, const std::string& to, + void send_archived_message(const Database::MucLogLine& log_line, const std::string& from, const std::string& to, const std::string& queryid); bool handle_room_configuration_form_request(const std::string& from, const Jid& to, const std::string& id); bool handle_room_configuration_form(const XmlNode& query, const std::string& from, const Jid& to, const std::string& id); diff --git a/tests/database.cpp b/tests/database.cpp index 4e2be14..47dfd7c 100644 --- a/tests/database.cpp +++ b/tests/database.cpp @@ -8,24 +8,22 @@ TEST_CASE("Database") { #ifdef USE_DATABASE Database::open(":memory:"); - Database::set_verbose(false); SECTION("Basic retrieve and update") { auto o = Database::get_irc_server_options("zouzou@example.com", "irc.example.com"); - o.update(); + o.save(Database::db); auto a = Database::get_irc_server_options("zouzou@example.com", "irc.example.com"); auto b = Database::get_irc_server_options("moumou@example.com", "irc.example.com"); // b does not yet exist in the db, the object is created but not yet // inserted - CHECK(1 == Database::count()); + CHECK(1 == Database::count(Database::irc_server_options)); - b.update(); - CHECK(2 == Database::count()); + b.save(Database::db); + CHECK(2 == Database::count(Database::irc_server_options)); - CHECK(b.pass == ""); - CHECK(b.pass.value() == ""); + CHECK(b.col() == ""); } SECTION("channel options") @@ -33,16 +31,16 @@ TEST_CASE("Database") Config::set("db_name", ":memory:"); auto o = Database::get_irc_channel_options("zouzou@example.com", "irc.example.com", "#foo"); - CHECK(o.encodingIn == ""); - o.encodingIn = "ISO-8859-1"; - o.update(); + CHECK(o.col() == ""); + o.col() = "ISO-8859-1"; + o.save(Database::db); auto b = Database::get_irc_channel_options("zouzou@example.com", "irc.example.com", "#foo"); - CHECK(o.encodingIn == "ISO-8859-1"); + CHECK(o.col() == "ISO-8859-1"); } SECTION("Channel options with server default") { - const std::string owner{"zouzou@example.com"}; + const std::string owner{"CACA@example.com"}; const std::string server{"irc.example.com"}; const std::string chan1{"#foo"}; @@ -51,43 +49,43 @@ TEST_CASE("Database") GIVEN("An option defined for the channel but not the server") { - c.encodingIn = "channelEncoding"; - c.update(); + c.col() = "channelEncoding"; + c.save(Database::db); WHEN("we fetch that option") { auto r = Database::get_irc_channel_options_with_server_default(owner, server, chan1); THEN("we get the channel option") - CHECK(r.encodingIn == "channelEncoding"); + CHECK(r.col() == "channelEncoding"); } } GIVEN("An option defined for the server but not the channel") { - s.encodingIn = "serverEncoding"; - s.update(); + s.col() = "serverEncoding"; + s.save(Database::db); WHEN("we fetch that option") { auto r = Database::get_irc_channel_options_with_server_default(owner, server, chan1); THEN("we get the server option") - CHECK(r.encodingIn == "serverEncoding"); + CHECK(r.col() == "serverEncoding"); } } GIVEN("An option defined for both the server and the channel") { - s.encodingIn = "serverEncoding"; - s.update(); - c.encodingIn = "channelEncoding"; - c.update(); + s.col() = "serverEncoding"; + s.save(Database::db); + c.col() = "channelEncoding"; + c.save(Database::db); WHEN("we fetch that option") { auto r = Database::get_irc_channel_options_with_server_default(owner, server, chan1); THEN("we get the channel option") - CHECK(r.encodingIn == "channelEncoding"); + CHECK(r.col() == "channelEncoding"); } WHEN("we fetch that option, with no channel specified") { auto r = Database::get_irc_channel_options_with_server_default(owner, server, ""); THEN("we get the server option") - CHECK(r.encodingIn == "serverEncoding"); + CHECK(r.col() == "serverEncoding"); } } } -- cgit v1.2.3 From 369ccb037619871403b14c959bbb359332133810 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 13 Jun 2017 11:18:05 +0200 Subject: Add default values for the database columns --- src/bridge/bridge.cpp | 6 ++++-- src/database/column.hpp | 6 +++++- src/database/database.hpp | 18 ++++++++++++------ tests/end_to_end/__main__.py | 2 +- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index fcfcc24..23ecfe9 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -23,12 +23,14 @@ static std::string in_encoding_for(const Bridge& bridge, const Iid& iid) #ifdef USE_DATABASE const auto jid = bridge.get_bare_jid(); auto options = Database::get_irc_channel_options_with_server_default(jid, iid.get_server(), iid.get_local()); - return options.col(); + auto result = options.col(); + if (!result.empty()) + return result; #else (void)bridge; (void)iid; - return {"ISO-8859-1"}; #endif + return {"ISO-8859-1"}; } Bridge::Bridge(std::string user_jid, BiboumiComponent& xmpp, std::shared_ptr& poller): diff --git a/src/database/column.hpp b/src/database/column.hpp index e74d426..22f4254 100644 --- a/src/database/column.hpp +++ b/src/database/column.hpp @@ -5,8 +5,12 @@ template struct Column { + Column(T default_value): + value{default_value} {} + Column(): + value{} {} using real_type = T; - T value; + T value{}; }; struct Id: Column { static constexpr auto name = "id_"; diff --git a/src/database/database.hpp b/src/database/database.hpp index ebc4878..a0611c1 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -49,10 +49,12 @@ class Database static constexpr auto options = ""; }; struct Ports: Column { static constexpr auto name = "tlsPorts_"; - static constexpr auto options = ""; }; + static constexpr auto options = ""; + Ports(): Column("6667") {}}; struct TlsPorts: Column { static constexpr auto name = "ports_"; - static constexpr auto options = ""; }; + static constexpr auto options = ""; + TlsPorts(): Column("6697;6670") {} }; struct Username: Column { static constexpr auto name = "username_"; static constexpr auto options = ""; }; @@ -73,16 +75,20 @@ class Database static constexpr auto options = ""; }; struct MaxHistoryLength: Column { static constexpr auto name = "maxHistoryLength_"; - static constexpr auto options = ""; }; + static constexpr auto options = ""; + MaxHistoryLength(): Column(20) {} }; struct RecordHistory: Column { static constexpr auto name = "recordHistory_"; - static constexpr auto options = ""; }; + static constexpr auto options = ""; + RecordHistory(): Column(true) {}}; struct VerifyCert: Column { static constexpr auto name = "verifyCert_"; - static constexpr auto options = ""; }; + static constexpr auto options = ""; + VerifyCert(): Column(true) {} }; struct Persistent: Column { static constexpr auto name = "persistent_"; - static constexpr auto options = ""; }; + static constexpr auto options = ""; + Persistent(): Column(false) {} }; using MucLogLineTable = Table; using MucLogLine = MucLogLineTable::RowType; diff --git a/tests/end_to_end/__main__.py b/tests/end_to_end/__main__.py index f9e04a8..8f108ee 100644 --- a/tests/end_to_end/__main__.py +++ b/tests/end_to_end/__main__.py @@ -2417,7 +2417,7 @@ if __name__ == '__main__': "/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='username']", "/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='realname']", "/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='encoding_in']", - "/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='encoding_out']/dataform:value[text()='ISO-8859-1']", + "/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='encoding_out']", "/iq/commands:command/commands:actions/commands:next", ), after = partial(save_value, "sessionid", partial(extract_attribute, "/iq[@type='result']/commands:command[@node='configure']", "sessionid")) -- cgit v1.2.3 From 41c23aab37905a97007d095c3997a0d0a9dfddda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 13 Jun 2017 11:51:10 +0200 Subject: Update the docker images and the gitlab-ci script to use sqlite3 --- .gitlab-ci.yml | 19 ++++------ docker/biboumi-test/alpine/Dockerfile | 50 +++++++++++++++++++++++-- docker/biboumi-test/alpine/Dockerfile.base | 51 -------------------------- docker/biboumi-test/debian/Dockerfile | 56 ++++++++++++++++++++++++++-- docker/biboumi-test/debian/Dockerfile.base | 57 ----------------------------- docker/biboumi-test/fedora/Dockerfile | 58 +++++++++++++++++++++++++++-- docker/biboumi-test/fedora/Dockerfile.base | 59 ------------------------------ docker/biboumi/Dockerfile | 5 +-- 8 files changed, 163 insertions(+), 192 deletions(-) delete mode 100644 docker/biboumi-test/alpine/Dockerfile.base delete mode 100644 docker/biboumi-test/debian/Dockerfile.base delete mode 100644 docker/biboumi-test/fedora/Dockerfile.base diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6604adb..0286ef8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -22,7 +22,7 @@ variables: UDNS: "-DWITH_UDNS=1" SYSTEMD: "-DWITH_SYSTEMD=1" LIBIDN: "-DWITH_LIBIDN=1" - LITESQL: "-DWITH_LITESQL=1" + SQLITE3: "-DWITH_SQLITE3=1" # ## Build jobs @@ -33,8 +33,8 @@ variables: tags: - docker script: - - "echo Running cmake with the following parameters: -DCMAKE_CXX_COMPILER=${COMPILER} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ${BOTAN} ${UDNS} ${SYSTEMD} ${LIBIDN} ${LITESQL}" - - cmake .. -DCMAKE_CXX_COMPILER=${COMPILER} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ${BOTAN} ${UDNS} ${SYSTEMD} ${LIBIDN} ${LITESQL} + - "echo Running cmake with the following parameters: -DCMAKE_CXX_COMPILER=${COMPILER} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ${BOTAN} ${UDNS} ${SYSTEMD} ${LIBIDN} ${SQLITE3}" + - cmake .. -DCMAKE_CXX_COMPILER=${COMPILER} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ${BOTAN} ${UDNS} ${SYSTEMD} ${LIBIDN} ${SQLITE3} - make everything -j$(nproc || echo 1) - make coverage_check -j$(nproc || echo 1) artifacts: @@ -77,19 +77,19 @@ build:2: build:3: variables: - LITESQL: "-DWITHOUT_LITESQL=1" + SQLITE3: "-DWITHOUT_SQLITE3=1" <<: *fedora_build build:4: variables: - LITESQL: "-DWITHOUT_LITESQL=1" + SQLITE3: "-DWITHOUT_SQLITE3=1" BOTAN: "-DWITHOUT_BOTAN=1" LIBIDN: "-DWITHOUT_LIBIDN=1" <<: *fedora_build build:5: variables: - LITESQL: "-DWITHOUT_LITESQL=1" + SQLITE3: "-DWITHOUT_SQLITE3=1" UDNS: "-DWITHOUT_UDNS=1" <<: *fedora_build @@ -163,7 +163,7 @@ test:freebsd: SYSTEMD: "-DWITHOUT_SYSTEMD=1" stage: test script: - - cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ${BOTAN} ${UDNS} ${SYSTEMD} ${LIBIDN} ${LITESQL} + - cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ${BOTAN} ${UDNS} ${SYSTEMD} ${LIBIDN} ${SQLITE3} - make check - make e2e @@ -303,11 +303,6 @@ packaging:archlinux: image: docker.louiz.org/biboumi-test-archlinux:latest before_script: [] script: - - sudo pacman -Syuu --noconfirm - - git clone https://aur.archlinux.org/litesql-git.git - - cd litesql-git - - makepkg -si --noconfirm - - cd .. - git clone https://aur.archlinux.org/biboumi-git.git - cd biboumi-git - makepkg -si --noconfirm diff --git a/docker/biboumi-test/alpine/Dockerfile b/docker/biboumi-test/alpine/Dockerfile index ab288b6..1938a8b 100644 --- a/docker/biboumi-test/alpine/Dockerfile +++ b/docker/biboumi-test/alpine/Dockerfile @@ -1,10 +1,54 @@ # This Dockerfile creates a docker image suitable to run biboumi’s build and # tests. For example, it can be used on with gitlab-ci. -FROM docker.louiz.org/biboumi-test-alpine-base +FROM docker.io/alpine:latest -# Install litesql -RUN git clone git://git.louiz.org/litesql && mkdir /litesql/build && cd /litesql/build && cmake .. -DCMAKE_INSTALL_PREFIX=/usr && make -j8 && cd /litesql/build && make install && rm -rf /litesql && ldconfig || true +ENV LC_ALL C.UTF-8 + +# Needed to build biboumi +RUN apk add --no-cache g++\ + clang\ + valgrind\ + udns-dev\ + c-ares-dev\ + sqlite-dev\ + libuuid\ + util-linux-dev\ + libgcrypt-dev\ + cmake\ + make\ + expat-dev\ + libidn-dev\ + git\ + py3-lxml\ + libtool\ + py3-pip\ + python2\ + python3-dev\ + automake\ + autoconf\ + flex\ + bison\ + libltdl\ + openssl\ + libressl-dev\ + zlib-dev\ + curl + +# Install botan +RUN git clone https://github.com/randombit/botan.git && cd botan && ./configure.py --prefix=/usr && make -j8 && make install && rm -rf /botan + +# Install slixmpp, for e2e tests +RUN git clone https://github.com/saghul/aiodns.git && cd aiodns && git checkout 7ee13f9bea25784322~ && python3 setup.py build && python3 setup.py install && git clone git://git.louiz.org/slixmpp && pip3 install pyasn1 && cd slixmpp && python3 setup.py build && python3 setup.py install + +RUN adduser tester -D -h /home/tester + +# Install charybdis, for e2e tests +RUN git clone https://github.com/charybdis-ircd/charybdis.git && cd charybdis && cd /charybdis && git checkout 4f2b9a4 && sed s/113/1113/ -i /charybdis/authd/providers/ident.c && ./autogen.sh && ./configure --prefix=/home/tester/ircd --bindir=/usr/bin && make -j8 && make install && rm -rf /charybdis + +RUN chown -R tester:tester /home/tester/ircd + +RUN yes "" | openssl req -nodes -x509 -newkey rsa:4096 -keyout /home/tester/ircd/etc/ssl.key -out /home/tester/ircd/etc/ssl.pem WORKDIR /home/tester USER tester diff --git a/docker/biboumi-test/alpine/Dockerfile.base b/docker/biboumi-test/alpine/Dockerfile.base deleted file mode 100644 index dffa1d1..0000000 --- a/docker/biboumi-test/alpine/Dockerfile.base +++ /dev/null @@ -1,51 +0,0 @@ -# This Dockerfile creates a docker image suitable to run biboumi’s build and -# tests. For example, it can be used on with gitlab-ci. - -FROM docker.io/alpine:latest - -ENV LC_ALL C.UTF-8 - -# Needed to build biboumi -RUN apk add --no-cache g++\ - clang\ - valgrind\ - udns-dev\ - c-ares-dev\ - sqlite-dev\ - libuuid\ - util-linux-dev\ - libgcrypt-dev\ - cmake\ - make\ - expat-dev\ - libidn-dev\ - git\ - py3-lxml\ - libtool\ - py3-pip\ - python2\ - python3-dev\ - automake\ - autoconf\ - flex\ - bison\ - libltdl\ - openssl\ - libressl-dev\ - zlib-dev\ - curl - -# Install botan -RUN git clone https://github.com/randombit/botan.git && cd botan && ./configure.py --prefix=/usr && make -j8 && make install && rm -rf /botan - -# Install slixmpp, for e2e tests -RUN git clone https://github.com/saghul/aiodns.git && cd aiodns && git checkout 7ee13f9bea25784322~ && python3 setup.py build && python3 setup.py install && git clone git://git.louiz.org/slixmpp && pip3 install pyasn1 && cd slixmpp && python3 setup.py build && python3 setup.py install - -RUN adduser tester -D -h /home/tester - -# Install charybdis, for e2e tests -RUN git clone https://github.com/charybdis-ircd/charybdis.git && cd charybdis && cd /charybdis && git checkout 4f2b9a4 && sed s/113/1113/ -i /charybdis/authd/providers/ident.c && ./autogen.sh && ./configure --prefix=/home/tester/ircd --bindir=/usr/bin && make -j8 && make install && rm -rf /charybdis - -RUN chown -R tester:tester /home/tester/ircd - -RUN yes "" | openssl req -nodes -x509 -newkey rsa:4096 -keyout /home/tester/ircd/etc/ssl.key -out /home/tester/ircd/etc/ssl.pem diff --git a/docker/biboumi-test/debian/Dockerfile b/docker/biboumi-test/debian/Dockerfile index b811ea4..232a585 100644 --- a/docker/biboumi-test/debian/Dockerfile +++ b/docker/biboumi-test/debian/Dockerfile @@ -1,10 +1,60 @@ # This Dockerfile creates a docker image suitable to run biboumi’s build and # tests. For example, it can be used on with gitlab-ci. -FROM docker.louiz.org/biboumi-test-debian-base +FROM docker.io/debian:latest -# Install litesql -RUN git clone git://git.louiz.org/litesql && mkdir /litesql/build && cd /litesql/build && cmake .. -DCMAKE_INSTALL_PREFIX=/usr && make -j8 && cd /litesql/build && make install && rm -rf /litesql && ldconfig +ENV LC_ALL C.UTF-8 + +RUN apt update + +# Needed to build biboumi +RUN apt install -y g++\ + clang\ + valgrind\ + libudns-dev\ + libc-ares-dev\ + libsqlite3-dev\ + libuuid1\ + libgcrypt20-dev\ + cmake\ + make\ + libexpat1-dev\ + libidn11-dev\ + uuid-dev\ + libsystemd-dev\ + pandoc\ + libasan1\ + libubsan0\ + git\ + python3-lxml\ + lcov\ + libtool\ + python3-pip\ + python3-dev\ + automake\ + autoconf\ + flex\ + bison\ + libltdl-dev\ + openssl\ + zlib1g-dev\ + libssl-dev\ + curl + +# Install botan +RUN git clone https://github.com/randombit/botan.git && cd botan && ./configure.py --prefix=/usr && make -j8 && make install && rm -rf /botan + +# Install slixmpp, for e2e tests +RUN git clone https://github.com/saghul/aiodns.git && cd aiodns && git checkout 7ee13f9bea25784322~ && python3 setup.py build && python3 setup.py install && git clone git://git.louiz.org/slixmpp && pip3 install pyasn1 && cd slixmpp && python3 setup.py build && python3 setup.py install + +RUN useradd tester -m + +# Install charybdis, for e2e tests +RUN git clone https://github.com/charybdis-ircd/charybdis.git && cd charybdis && cd /charybdis && git checkout 4f2b9a4 && sed s/113/1113/ -i /charybdis/authd/providers/ident.c && ./autogen.sh && ./configure --prefix=/home/tester/ircd --bindir=/usr/bin && make -j8 && make install && rm -rf /charybdis + +RUN chown -R tester:tester /home/tester/ircd + +RUN yes "" | openssl req -nodes -x509 -newkey rsa:4096 -keyout /home/tester/ircd/etc/ssl.key -out /home/tester/ircd/etc/ssl.pem WORKDIR /home/tester USER tester diff --git a/docker/biboumi-test/debian/Dockerfile.base b/docker/biboumi-test/debian/Dockerfile.base deleted file mode 100644 index f5d061b..0000000 --- a/docker/biboumi-test/debian/Dockerfile.base +++ /dev/null @@ -1,57 +0,0 @@ -# This Dockerfile creates a docker image suitable to run biboumi’s build and -# tests. For example, it can be used on with gitlab-ci. - -FROM docker.io/debian:latest - -ENV LC_ALL C.UTF-8 - -RUN apt update - -# Needed to build biboumi -RUN apt install -y g++\ - clang\ - valgrind\ - libudns-dev\ - libc-ares-dev\ - libsqlite3-dev\ - libuuid1\ - libgcrypt20-dev\ - cmake\ - make\ - libexpat1-dev\ - libidn11-dev\ - uuid-dev\ - libsystemd-dev\ - pandoc\ - libasan1\ - libubsan0\ - git\ - python3-lxml\ - lcov\ - libtool\ - python3-pip\ - python3-dev\ - automake\ - autoconf\ - flex\ - bison\ - libltdl-dev\ - openssl\ - zlib1g-dev\ - libssl-dev\ - curl - -# Install botan -RUN git clone https://github.com/randombit/botan.git && cd botan && ./configure.py --prefix=/usr && make -j8 && make install && rm -rf /botan - -# Install slixmpp, for e2e tests -RUN git clone https://github.com/saghul/aiodns.git && cd aiodns && git checkout 7ee13f9bea25784322~ && python3 setup.py build && python3 setup.py install && git clone git://git.louiz.org/slixmpp && pip3 install pyasn1 && cd slixmpp && python3 setup.py build && python3 setup.py install - -RUN useradd tester -m - -# Install charybdis, for e2e tests -RUN git clone https://github.com/charybdis-ircd/charybdis.git && cd charybdis && cd /charybdis && git checkout 4f2b9a4 && sed s/113/1113/ -i /charybdis/authd/providers/ident.c && ./autogen.sh && ./configure --prefix=/home/tester/ircd --bindir=/usr/bin && make -j8 && make install && rm -rf /charybdis - -RUN chown -R tester:tester /home/tester/ircd - -RUN yes "" | openssl req -nodes -x509 -newkey rsa:4096 -keyout /home/tester/ircd/etc/ssl.key -out /home/tester/ircd/etc/ssl.pem diff --git a/docker/biboumi-test/fedora/Dockerfile b/docker/biboumi-test/fedora/Dockerfile index 45dbe76..384fd51 100644 --- a/docker/biboumi-test/fedora/Dockerfile +++ b/docker/biboumi-test/fedora/Dockerfile @@ -1,10 +1,62 @@ # This Dockerfile creates a docker image suitable to run biboumi’s build and # tests. For example, it can be used on with gitlab-ci. -FROM docker.louiz.org/biboumi-test-fedora-base +FROM docker.io/fedora:latest -# Install litesql -RUN git clone git://git.louiz.org/litesql && mkdir /litesql/build && cd /litesql/build && cmake .. -DCMAKE_INSTALL_PREFIX=/usr && make -j8 && cd /litesql/build && make install && ldconfig && rm -rf /litesql +ENV LC_ALL C.UTF-8 + +RUN dnf --refresh install -y\ + gcc-c++\ + clang\ + valgrind\ + udns-devel\ + c-ares-devel\ + sqlite-devel\ + libuuid-devel\ + libgcrypt-devel\ + cmake\ + make\ + expat-devel\ + libidn-devel\ + uuid-devel\ + systemd-devel\ + pandoc\ + libasan\ + libubsan\ + git\ + fedora-packager\ + python3-lxml\ + lcov\ + rpmdevtools\ + python3-devel\ + automake\ + autoconf\ + flex\ + flex-devel\ + bison\ + libtool-ltdl-devel\ + libtool\ + openssl-devel\ + which\ + java-1.8.0-openjdk\ + && dnf clean all + +# Install botan +RUN git clone https://github.com/randombit/botan.git && cd botan && ./configure.py --prefix=/usr && make -j8 && make install && ldconfig && rm -rf /botan + +# Install slixmpp, for e2e tests +RUN git clone git://git.louiz.org/slixmpp && pip3 install pyasn1 && cd slixmpp && python3 setup.py build && python3 setup.py install + +RUN useradd tester + +# Install charybdis, for e2e tests +RUN git clone https://github.com/charybdis-ircd/charybdis.git && cd charybdis && cd /charybdis && git checkout 4f2b9a4 && sed s/113/1113/ -i /charybdis/authd/providers/ident.c && ./autogen.sh && ./configure --prefix=/home/tester/ircd --bindir=/usr/bin --with-included-boost && make -j8 && make install && rm -rf /charybdis + +RUN chown -R tester:tester /home/tester/ircd + +RUN yes "" | openssl req -nodes -x509 -newkey rsa:4096 -keyout /home/tester/ircd/etc/ssl.key -out /home/tester/ircd/etc/ssl.pem + +COPY coverity /home/tester/coverity WORKDIR /home/tester USER tester diff --git a/docker/biboumi-test/fedora/Dockerfile.base b/docker/biboumi-test/fedora/Dockerfile.base deleted file mode 100644 index 20984a2..0000000 --- a/docker/biboumi-test/fedora/Dockerfile.base +++ /dev/null @@ -1,59 +0,0 @@ -# This Dockerfile creates a docker image suitable to run biboumi’s build and -# tests. For example, it can be used on with gitlab-ci. - -FROM docker.io/fedora:latest - -ENV LC_ALL C.UTF-8 - -RUN dnf --refresh install -y\ - gcc-c++\ - clang\ - valgrind\ - udns-devel\ - c-ares-devel\ - sqlite-devel\ - libuuid-devel\ - libgcrypt-devel\ - cmake\ - make\ - expat-devel\ - libidn-devel\ - uuid-devel\ - systemd-devel\ - pandoc\ - libasan\ - libubsan\ - git\ - fedora-packager\ - python3-lxml\ - lcov\ - rpmdevtools\ - python3-devel\ - automake\ - autoconf\ - flex\ - flex-devel\ - bison\ - libtool-ltdl-devel\ - libtool\ - openssl-devel\ - which\ - java-1.8.0-openjdk\ - && dnf clean all - -# Install botan -RUN git clone https://github.com/randombit/botan.git && cd botan && ./configure.py --prefix=/usr && make -j8 && make install && ldconfig && rm -rf /botan - -# Install slixmpp, for e2e tests -RUN git clone git://git.louiz.org/slixmpp && pip3 install pyasn1 && cd slixmpp && python3 setup.py build && python3 setup.py install - -RUN useradd tester - -# Install charybdis, for e2e tests -RUN git clone https://github.com/charybdis-ircd/charybdis.git && cd charybdis && cd /charybdis && git checkout 4f2b9a4 && sed s/113/1113/ -i /charybdis/authd/providers/ident.c && ./autogen.sh && ./configure --prefix=/home/tester/ircd --bindir=/usr/bin --with-included-boost && make -j8 && make install && rm -rf /charybdis - -RUN chown -R tester:tester /home/tester/ircd - -RUN yes "" | openssl req -nodes -x509 -newkey rsa:4096 -keyout /home/tester/ircd/etc/ssl.key -out /home/tester/ircd/etc/ssl.pem - -COPY coverity /home/tester/coverity diff --git a/docker/biboumi/Dockerfile b/docker/biboumi/Dockerfile index d27421b..67f0f41 100644 --- a/docker/biboumi/Dockerfile +++ b/docker/biboumi/Dockerfile @@ -18,15 +18,12 @@ RUN apk add --no-cache\ # Install botan RUN git clone https://github.com/randombit/botan.git && cd botan && ./configure.py --prefix=/usr && make -j8 && make install && rm -rf /botan -# Install litesql -RUN git clone git://git.louiz.org/litesql && mkdir /litesql/build && cd /litesql/build && cmake .. -DCMAKE_INSTALL_PREFIX=/usr && make -j8 && cd /litesql/build && make install && rm -rf /litesql - # Install biboumi RUN git clone git://git.louiz.org/biboumi && mkdir ./biboumi/build && cd ./biboumi/build &&\ cmake .. -DCMAKE_INSTALL_PREFIX=/usr\ -DCMAKE_BUILD_TYPE=Release\ -DWITH_BOTAN=1\ - -DWITH_LITESQL=1\ + -DWITH_SQLITE3=1\ -DWITH_LIBIDN=1\ && make -j8 && make install && rm -rf /biboumi -- cgit v1.2.3 From 9defd0ccb75b1905c308ed0437e5ccd479e3a7b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 14 Jun 2017 00:04:00 +0200 Subject: Add a Statement class to manage the sqlite3_stmt objects and avoid leaks --- src/database/count_query.hpp | 6 +++--- src/database/insert_query.hpp | 17 +++++++++-------- src/database/query.hpp | 6 ++++-- src/database/select_query.hpp | 19 ++++++++++--------- src/database/statement.hpp | 35 +++++++++++++++++++++++++++++++++++ 5 files changed, 61 insertions(+), 22 deletions(-) create mode 100644 src/database/statement.hpp diff --git a/src/database/count_query.hpp b/src/database/count_query.hpp index 863fad1..322ad1b 100644 --- a/src/database/count_query.hpp +++ b/src/database/count_query.hpp @@ -19,14 +19,14 @@ struct CountQuery: public Query { auto statement = this->prepare(db); std::size_t res = 0; - if (sqlite3_step(statement) == SQLITE_ROW) - res = sqlite3_column_int64(statement, 0); + if (sqlite3_step(statement.get()) == SQLITE_ROW) + res = sqlite3_column_int64(statement.get(), 0); else { log_error("Count request didn’t return a result"); return 0; } - if (sqlite3_step(statement) != SQLITE_DONE) + if (sqlite3_step(statement.get()) != SQLITE_DONE) log_warning("Count request returned more than one result."); log_debug("Returning count: ", res); diff --git a/src/database/insert_query.hpp b/src/database/insert_query.hpp index 00b77c5..1712916 100644 --- a/src/database/insert_query.hpp +++ b/src/database/insert_query.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -13,11 +14,11 @@ template typename std::enable_if, Id>::value, void>::type -actual_bind(sqlite3_stmt* statement, std::vector& params, const std::tuple&) +actual_bind(Statement& statement, std::vector& params, const std::tuple&) { const auto value = params.front(); params.erase(params.begin()); - if (sqlite3_bind_text(statement, N + 1, value.data(), static_cast(value.size()), SQLITE_TRANSIENT) != SQLITE_OK) + if (sqlite3_bind_text(statement.get(), N + 1, value.data(), static_cast(value.size()), SQLITE_TRANSIENT) != SQLITE_OK) log_error("Failed to bind ", value, " to param ", N); else log_debug("Bound (not id) [", value, "] to ", N); @@ -25,15 +26,15 @@ actual_bind(sqlite3_stmt* statement, std::vector& params, const std template typename std::enable_if, Id>::value, void>::type -actual_bind(sqlite3_stmt* statement, std::vector&, const std::tuple& columns) +actual_bind(Statement& statement, std::vector&, const std::tuple& columns) { auto&& column = std::get(columns); if (column.value != 0) { - if (sqlite3_bind_int64(statement, N + 1, column.value) != SQLITE_OK) + if (sqlite3_bind_int64(statement.get(), N + 1, column.value) != SQLITE_OK) log_error("Failed to bind ", column.value, " to id."); } - else if (sqlite3_bind_null(statement, N + 1) != SQLITE_OK) + else if (sqlite3_bind_null(statement.get(), N + 1) != SQLITE_OK) log_error("Failed to bind NULL to param ", N); else log_debug("Bound NULL to ", N); @@ -53,14 +54,14 @@ struct InsertQuery: public Query auto statement = this->prepare(db); { this->bind_param<0>(columns, statement); - if (sqlite3_step(statement) != SQLITE_DONE) + if (sqlite3_step(statement.get()) != SQLITE_DONE) log_error("Failed to execute query: ", sqlite3_errmsg(db)); } } template typename std::enable_if::type - bind_param(const std::tuple& columns, sqlite3_stmt* statement) + bind_param(const std::tuple& columns, Statement& statement) { using ColumnType = typename std::remove_reference(columns))>::type; @@ -70,7 +71,7 @@ struct InsertQuery: public Query template typename std::enable_if::type - bind_param(const std::tuple&, sqlite3_stmt*) + bind_param(const std::tuple&, Statement&) {} template diff --git a/src/database/query.hpp b/src/database/query.hpp index 92845d0..b77a421 100644 --- a/src/database/query.hpp +++ b/src/database/query.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include #include @@ -16,7 +18,7 @@ struct Query body(std::move(str)) {} - sqlite3_stmt* prepare(sqlite3* db) + Statement prepare(sqlite3* db) { sqlite3_stmt* statement; log_debug(this->body); @@ -27,7 +29,7 @@ struct Query log_error("Error preparing statement: ", sqlite3_errmsg(db)); return nullptr; } - return statement; + return {statement}; } }; diff --git a/src/database/select_query.hpp b/src/database/select_query.hpp index b41632e..80d1424 100644 --- a/src/database/select_query.hpp +++ b/src/database/select_query.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -13,24 +14,24 @@ using namespace std::string_literals; template typename std::enable_if::value, sqlite3_int64>::type -extract_row_value(sqlite3_stmt* statement, const int i) +extract_row_value(Statement& statement, const int i) { - return sqlite3_column_int64(statement, i); + return sqlite3_column_int64(statement.get(), i); } template typename std::enable_if::value, std::string>::type -extract_row_value(sqlite3_stmt* statement, const int i) +extract_row_value(Statement& statement, const int i) { - const auto size = sqlite3_column_bytes(statement, i); - const unsigned char* str = sqlite3_column_text(statement, i); + const auto size = sqlite3_column_bytes(statement.get(), i); + const unsigned char* str = sqlite3_column_text(statement.get(), i); std::string result(reinterpret_cast(str), size); return result; } template typename std::enable_if::type -extract_row_values(Row& row, sqlite3_stmt* statement) +extract_row_values(Row& row, Statement& statement) { using ColumnType = typename std::remove_reference(row.columns))>::type; @@ -42,7 +43,7 @@ extract_row_values(Row& row, sqlite3_stmt* statement) template typename std::enable_if::type -extract_row_values(Row&, sqlite3_stmt*) +extract_row_values(Row&, Statement&) {} template @@ -100,7 +101,7 @@ struct SelectQuery: public Query int i = 1; for (const std::string& param: this->params) { - if (sqlite3_bind_text(statement, i, param.data(), static_cast(param.size()), SQLITE_TRANSIENT) != SQLITE_OK) + if (sqlite3_bind_text(statement.get(), i, param.data(), static_cast(param.size()), SQLITE_TRANSIENT) != SQLITE_OK) log_debug("Failed to bind ", param, " to param ", i); else log_debug("Bound ", param, " to ", i); @@ -108,7 +109,7 @@ struct SelectQuery: public Query i++; } std::vector> rows; - while (sqlite3_step(statement) == SQLITE_ROW) + while (sqlite3_step(statement.get()) == SQLITE_ROW) { Row row(this->table_name); extract_row_values(row, statement); diff --git a/src/database/statement.hpp b/src/database/statement.hpp new file mode 100644 index 0000000..87cd70f --- /dev/null +++ b/src/database/statement.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include + +class Statement +{ + public: + Statement(sqlite3_stmt* stmt): + stmt(stmt) {} + ~Statement() + { + sqlite3_finalize(this->stmt); + } + + Statement(const Statement&) = delete; + Statement& operator=(const Statement&) = delete; + Statement(Statement&& other): + stmt(other.stmt) + { + other.stmt = nullptr; + } + Statement& operator=(Statement&& other) + { + this->stmt = other.stmt; + other.stmt = nullptr; + return *this; + } + sqlite3_stmt* get() + { + return this->stmt; + } + + private: + sqlite3_stmt* stmt; +}; -- cgit v1.2.3 From 8d1d822edf72e2bf426a1512fb2e19ef65e97b8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 14 Jun 2017 00:04:19 +0200 Subject: Explicitely close the Database before re-opening it --- src/utils/reload.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/reload.cpp b/src/utils/reload.cpp index fdca9bc..807a9ab 100644 --- a/src/utils/reload.cpp +++ b/src/utils/reload.cpp @@ -11,6 +11,7 @@ void open_database() #ifdef USE_DATABASE const auto db_filename = Config::get("db_name", xdg_data_path("biboumi.sqlite")); log_info("Opening database: ", db_filename); + Database::close(); Database::open(db_filename); log_info("database successfully opened."); #endif -- cgit v1.2.3 From 94dd16cbe6af11bfcaf2f62b6dc91998567fdf95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 14 Jun 2017 00:15:22 +0200 Subject: The packaging:archlinux build only makes sense on the master branch --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0286ef8..83e5e86 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -298,6 +298,8 @@ packaging:deb: packaging:archlinux: stage: packaging + only: + - master@louiz/biboumi tags: - docker image: docker.louiz.org/biboumi-test-archlinux:latest -- cgit v1.2.3 From 3d1e85fd488c265cbeaf07b8fc3a2175ccff10ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 14 Jun 2017 00:18:44 +0200 Subject: Update INSTALL.rst and CHANGELOG.rst for the sqlite dependency --- CHANGELOG.rst | 6 ++++++ CONTRIBUTING.rst | 6 +++--- INSTALL.rst | 13 +++++++------ 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5709483..9bfecd6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,9 @@ +Version 6.0 +=========== + + - The LiteSQL dependency was removed. Only libsqlite3 is now necessary + to work with the database. + Version 5.0 - 2017-05-24 ======================== diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 74459d1..8df4899 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -52,8 +52,8 @@ There are two test suites for biboumi: uses a specific IRC server (`charybdis`_), and only tests the most complete biboumi configuration (when all dependencies are used). To run it, you need to install various dependencies: refer to fedora’s `Dockerfile.base`_ and - `Dockerfile`_ to see how to install charybdis, slixmpp, botan, litesql, an - ssl certificate, etc. + `Dockerfile`_ to see how to install charybdis, slixmpp, botan, a ssl + certificate, etc. Once all the dependencies are correctly installed, the tests are run with @@ -94,4 +94,4 @@ Please try to follow the existing style: .. _Dockerfile.base: docker/biboumi-test/fedora/Dockerfile.base .. _Dockerfile: docker/biboumi-test/fedora/Dockerfile .. _charybdis: https://github.com/charybdis-ircd/charybdis -.. _the __main__.py file: tests/end_to_end/__main__.py \ No newline at end of file +.. _the __main__.py file: tests/end_to_end/__main__.py diff --git a/INSTALL.rst b/INSTALL.rst index 6cd85d2..5bb0ca8 100644 --- a/INSTALL.rst +++ b/INSTALL.rst @@ -32,6 +32,12 @@ libiconv_ libuuid_ Generate unique IDs +sqlite3_ (option, but highly recommended) + Provides a way to store various options in a (sqlite3) database. Each user + of the gateway can store their own values (for example their prefered port, + or their IRC password). Without this dependency, many interesting features + are missing. + libidn_ (optional, but recommended) Provides the stringprep functionality. Without it, JIDs for IRC users are not provided. @@ -48,11 +54,6 @@ libbotan_ 1.11 or 2.0 (optional) gcrypt_ (mandatory only if botan is absent) Provides the SHA-1 hash function, for the case where Botan is absent. -litesql_ (optional) - Provides a way to store various options in a (sqlite3) database. Each user - of the gateway can store their own values (for example their prefered port, - or their IRC password). - systemd_ (optional) Provides the support for a systemd service of Type=notify. This is useful only if you are packaging biboumi in a distribution with Systemd. @@ -160,7 +161,7 @@ to use biboumi. .. _libidn: http://www.gnu.org/software/libidn/ .. _libbotan: http://botan.randombit.net/ .. _udns: http://www.corpit.ru/mjt/udns.html -.. _litesql: http://git.louiz.org/litesql +.. _sqlite3: https://sqlite.org .. _systemd: https://www.freedesktop.org/wiki/Software/systemd/ .. _biboumi.1.rst: doc/biboumi.1.rst .. _gcrypt: https://www.gnu.org/software/libgcrypt/ -- cgit v1.2.3 From 922610cdbf0469e01fd99655c46cceff57a825d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 14 Jun 2017 00:24:35 +0200 Subject: Run the coverity and freebsd tests in all louiz/biboumi branches --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 83e5e86..2c39731 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -156,7 +156,7 @@ test:alpine: test:freebsd: only: - - master@louiz/biboumi + - branches@louiz/biboumi tags: - freebsd variables: @@ -240,7 +240,7 @@ codecov:build:7: coverity: stage: external only: - - master@louiz/biboumi + - branches@louiz/biboumi tags: - docker image: docker.louiz.org/biboumi-test-fedora:latest -- cgit v1.2.3 From dac19da4c791a6c16cde09e61841fd7f6b6268d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 14 Jun 2017 10:09:03 +0200 Subject: Fix an inversion of tlsPorts_ and ports_ --- src/database/database.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/database/database.hpp b/src/database/database.hpp index a0611c1..3a99867 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -48,11 +48,11 @@ class Database struct Pass: Column { static constexpr auto name = "pass_"; static constexpr auto options = ""; }; - struct Ports: Column { static constexpr auto name = "tlsPorts_"; + struct Ports: Column { static constexpr auto name = "ports_"; static constexpr auto options = ""; - Ports(): Column("6667") {}}; + Ports(): Column("6667") {} }; - struct TlsPorts: Column { static constexpr auto name = "ports_"; + struct TlsPorts: Column { static constexpr auto name = "tlsPorts_"; static constexpr auto options = ""; TlsPorts(): Column("6697;6670") {} }; -- cgit v1.2.3 From 2677ac42e8d2e1cf162fec773a9acb453bef8b9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 14 Jun 2017 10:31:45 +0200 Subject: Fix compilation (many warnings, and a linkage error) with clang++ --- src/database/count_query.hpp | 4 ++-- src/database/database.hpp | 2 +- src/database/insert_query.hpp | 6 +++--- src/database/row.hpp | 2 +- src/database/select_query.hpp | 7 +++---- src/database/type_to_sql.cpp | 1 + src/database/type_to_sql.hpp | 7 +++++++ 7 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/database/count_query.hpp b/src/database/count_query.hpp index 322ad1b..b7bbf51 100644 --- a/src/database/count_query.hpp +++ b/src/database/count_query.hpp @@ -15,10 +15,10 @@ struct CountQuery: public Query this->body += std::move(name); } - std::size_t execute(sqlite3* db) + int64_t execute(sqlite3* db) { auto statement = this->prepare(db); - std::size_t res = 0; + int64_t res = 0; if (sqlite3_step(statement.get()) == SQLITE_ROW) res = sqlite3_column_int64(statement.get(), 0); else diff --git a/src/database/database.hpp b/src/database/database.hpp index 3a99867..1ad62fc 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -131,7 +131,7 @@ class Database static void open(const std::string& filename); template - static std::size_t count(const TableType& table) + static int64_t count(const TableType& table) { CountQuery query{table.get_name()}; return query.execute(Database::db); diff --git a/src/database/insert_query.hpp b/src/database/insert_query.hpp index 1712916..4965fc0 100644 --- a/src/database/insert_query.hpp +++ b/src/database/insert_query.hpp @@ -31,7 +31,7 @@ actual_bind(Statement& statement, std::vector&, const std::tuple(columns); if (column.value != 0) { - if (sqlite3_bind_int64(statement.get(), N + 1, column.value) != SQLITE_OK) + if (sqlite3_bind_int64(statement.get(), N + 1, static_cast(column.value)) != SQLITE_OK) log_error("Failed to bind ", column.value, " to id."); } else if (sqlite3_bind_null(statement.get(), N + 1) != SQLITE_OK) @@ -110,9 +110,9 @@ struct InsertQuery: public Query typename std::enable_if::type insert_col_name(const std::tuple& columns) { - auto value = std::get(columns); + using ColumnType = typename std::remove_reference(columns))>::type; - this->body += value.name; + this->body += ColumnType::name; if (N < (sizeof...(T) - 1)) this->body += ", "; diff --git a/src/database/row.hpp b/src/database/row.hpp index ca686c1..b6887cb 100644 --- a/src/database/row.hpp +++ b/src/database/row.hpp @@ -20,7 +20,7 @@ update_id(std::tuple& columns, sqlite3* db) log_debug("Found an autoincrement col."); auto res = sqlite3_last_insert_rowid(db); log_debug("Value is now: ", res); - column.value = res; + column.value = static_cast(res); } template diff --git a/src/database/select_query.hpp b/src/database/select_query.hpp index 80d1424..d0c1d59 100644 --- a/src/database/select_query.hpp +++ b/src/database/select_query.hpp @@ -25,7 +25,7 @@ extract_row_value(Statement& statement, const int i) { const auto size = sqlite3_column_bytes(statement.get(), i); const unsigned char* str = sqlite3_column_text(statement.get(), i); - std::string result(reinterpret_cast(str), size); + std::string result(reinterpret_cast(str), static_cast(size)); return result; } @@ -62,10 +62,9 @@ struct SelectQuery: public Query insert_col_name() { using ColumnsType = std::tuple; - ColumnsType tuple{}; - auto value = std::get(tuple); + using ColumnType = typename std::remove_reference(std::declval()))>::type; - this->body += " "s + value.name; + this->body += " "s + ColumnType::name; if (N < (sizeof...(T) - 1)) this->body += ", "; diff --git a/src/database/type_to_sql.cpp b/src/database/type_to_sql.cpp index 5de012e..0b26185 100644 --- a/src/database/type_to_sql.cpp +++ b/src/database/type_to_sql.cpp @@ -3,5 +3,6 @@ template <> const std::string TypeToSQLType::type = "INTEGER"; template <> const std::string TypeToSQLType::type = "INTEGER"; template <> const std::string TypeToSQLType::type = "INTEGER"; +template <> const std::string TypeToSQLType::type = "INTEGER"; template <> const std::string TypeToSQLType::type = "INTEGER"; template <> const std::string TypeToSQLType::type = "TEXT"; diff --git a/src/database/type_to_sql.hpp b/src/database/type_to_sql.hpp index 5ae03ad..1942268 100644 --- a/src/database/type_to_sql.hpp +++ b/src/database/type_to_sql.hpp @@ -4,3 +4,10 @@ template struct TypeToSQLType { static const std::string type; }; + +template <> const std::string TypeToSQLType::type; +template <> const std::string TypeToSQLType::type; +template <> const std::string TypeToSQLType::type; +template <> const std::string TypeToSQLType::type; +template <> const std::string TypeToSQLType::type; +template <> const std::string TypeToSQLType::type; \ No newline at end of file -- cgit v1.2.3