1
0
forked from blue/pica

just some thoughts

This commit is contained in:
Blue 2023-12-11 20:29:55 -03:00
parent 03d7614673
commit f0d205dee7
Signed by untrusted user: blue
GPG Key ID: 9B203B252A63EE38
15 changed files with 172 additions and 34 deletions

View File

@ -13,14 +13,37 @@ include(GNUInstallDirs)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
set(PICA_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR})
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug)
endif()
message("Build type: ${CMAKE_BUILD_TYPE}")
set(COMPILE_OPTIONS -fno-sized-deallocation)
if (CMAKE_BUILD_TYPE STREQUAL Release)
list(APPEND COMPILE_OPTIONS -O3)
elseif (CMAKE_BUILD_TYPE STREQUAL Debug)
list(APPEND COMPILE_OPTIONS -g)
list(APPEND COMPILE_OPTIONS -Wall)
list(APPEND COMPILE_OPTIONS -Wextra)
endif()
set(COMPILE_OPTIONS_STRING "")
foreach(element IN LISTS COMPILE_OPTIONS)
if(NOT COMPILE_OPTIONS_STRING STREQUAL "")
set(COMPILE_OPTIONS_STRING "${COMPILE_OPTIONS_STRING} ")
endif()
set(COMPILE_OPTIONS_STRING "${COMPILE_OPTIONS_STRING}${element}")
endforeach()
message("Compile options: " ${COMPILE_OPTIONS_STRING})
find_package(nlohmann_json REQUIRED)
find_package(FCGI REQUIRED)
add_executable(pica main.cpp)
target_include_directories(pica PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_include_directories(pica PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
add_executable(${PROJECT_NAME} main.cpp)
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_compile_options(${PROJECT_NAME} PRIVATE ${COMPILE_OPTIONS})
add_subdirectory(server)
add_subdirectory(request)
@ -31,10 +54,10 @@ add_subdirectory(utils)
configure_file(config.h.in config.h @ONLY)
target_link_libraries(pica PRIVATE
target_link_libraries(${PROJECT_NAME} PRIVATE
FCGI::FCGI
FCGI::FCGI++
nlohmann_json::nlohmann_json
)
install(TARGETS pica RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})

View File

@ -7,3 +7,4 @@
#define BIN_DIR "@CMAKE_INSTALL_BINDIR@"
#define PROJECT_NAME "@PROJECT_NAME@"
#define PROJECT_VERSION "@PROJECT_VERSION@"

View File

@ -6,7 +6,7 @@ set(SOURCES
dbinterface.cpp
)
target_sources(pica PRIVATE ${SOURCES})
target_sources(${PROJECT_NAME} PRIVATE ${SOURCES})
add_subdirectory(mysql)
add_subdirectory(migrations)

View File

@ -1,5 +1,5 @@
set(MIGRATIONS migrations)
configure_file(m0.sql ${PICA_BIN_DIR}/${CMAKE_INSTALL_DATADIR}/${MIGRATIONS}/m0.sql COPYONLY)
configure_file(m0.sql ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/${MIGRATIONS}/m0.sql COPYONLY)
install(
FILES

View File

@ -1,6 +1,36 @@
--creating system table
CREATE TABLE IF NOT EXISTS system (
`key` VARCHAR(32) PRIMARY KEY,
`value` TEXT
);
--creating roles table
CREATE TABLE IF NOT EXISTS roles (
`id` INTEGER UNSIGNED AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(256) UNIQUE NOT NULL,
`color` INTEGER UNSIGNED DEFAULT 0
);
--creating accounts table
CREATE TABLE IF NOT EXISTS accounts (
`id` INTEGER UNSIGNED AUTO_INCREMENT PRIMARY KEY,
`login` VARCHAR(256) UNIQUE NOT NULL,
`nick` VARCHAR(256),
`type` INTEGER UNSIGNED NOT NULL,
`password` VARCHAR(64),
`salt` VARCHAR(32),
`role` INTEGER UNSIGNED NOT NULL,
`created` TIMESTAMP DEFAULT UTC_TIMESTAMP(),
FOREIGN KEY (role) REFERENCES roles(id)
);
--creating defailt roles
INSERT IGNORE INTO roles (`name`)
VALUES ('root');
--inserting initial version
INSERT INTO system (`key`, `value`) VALUES ('version', '0');
--recording initial time
INSERT INTO system (`key`, `value`) VALUES ('created', UTC_TIMESTAMP());

View File

@ -10,6 +10,6 @@ set(SOURCES
find_package(MariaDB REQUIRED)
target_sources(pica PRIVATE ${SOURCES})
target_sources(${PROJECT_NAME} PRIVATE ${SOURCES})
target_link_libraries(pica PRIVATE MariaDB::client)
target_link_libraries(${PROJECT_NAME} PRIVATE MariaDB::client)

View File

@ -116,6 +116,14 @@ void MySQL::executeFile(const std::filesystem::path& relativePath) {
std::ifstream inputFile(path);
std::string query;
while (std::getline(inputFile, query, ';')) {
std::optional<std::string> comment = getComment(query);
while (comment) {
std::cout << '\t' << comment.value() << std::endl;
comment = getComment(query);
}
if (query.empty())
continue;
int result = mysql_query(con, query.c_str());
if (result != 0) {
int errcode = mysql_errno(con);
@ -162,15 +170,49 @@ void MySQL::migrate(uint8_t targetVersion) {
uint8_t currentVersion = getVersion();
while (currentVersion < targetVersion) {
if (currentVersion == 255)
throw std::runtime_error("Maximum possible database version reached");
uint8_t nextVersion = currentVersion + 1;
std::string fileName = "migrations/m" + std::to_string(currentVersion) + ".sql";
std::cout << "Performing migration "
<< std::to_string(currentVersion)
<< " -> "
<< std::to_string(++currentVersion)
<< std::to_string(nextVersion)
<< std::endl;
executeFile(fileName);
setVersion(currentVersion);
setVersion(nextVersion);
currentVersion = nextVersion;
}
std::cout << "Database is now on actual version " << std::to_string(targetVersion) << std::endl;
}
std::optional<std::string> MySQL::getComment(std::string& string) {
ltrim(string);
if (string.length() < 2)
return std::nullopt;
if (string[0] == '-') {
if (string[1] == '-') {
string.erase(0, 2);
std::string::size_type eol = string.find('\n');
return extract(string, 0, eol);
}
} else if (string[0] == '/') {
if (string[1] == '*') {
string.erase(0, 2);
std::string::size_type end = 0;
do {
end = string.find(end, '*');
} while (end != std::string::npos && end < string.size() - 1 && string[end + 1] == '/');
if (end < string.size() - 1)
end = std::string::npos;
return extract(string, 0, end);
}
}
return std::nullopt;
}

View File

@ -5,6 +5,7 @@
#include <stdexcept>
#include <filesystem>
#include <optional>
#include <mysql.h>
@ -28,6 +29,7 @@ public:
private:
void executeFile(const std::filesystem::path& relativePath);
static std::optional<std::string> getComment(std::string& string);
protected:
MYSQL connection;

View File

@ -6,4 +6,4 @@ set(SOURCES
response.cpp
)
target_sources(pica PRIVATE ${SOURCES})
target_sources(${PROJECT_NAME} PRIVATE ${SOURCES})

View File

@ -8,4 +8,4 @@ set(SOURCES
router.cpp
)
target_sources(pica PRIVATE ${SOURCES})
target_sources(${PROJECT_NAME} PRIVATE ${SOURCES})

View File

@ -20,17 +20,7 @@ Server::Server():
db->setCredentials("pica", "pica");
db->setDatabase("pica");
bool connected = false;
try {
db->connect("/run/mysqld/mysqld.sock");
connected = true;
std::cout << "Successfully connected to the database" << std::endl;
} catch (const std::runtime_error& e) {
std::cerr << "Couldn't connect to the database: " << e.what() << std::endl;
}
if (connected)
db->migrate(currentDbVesion);
router.addRoute("info", Server::info);
@ -74,7 +64,7 @@ void Server::handleRequest(std::unique_ptr<Request> request) {
try {
std::string path = request->getPath(serverName.value());
router.route(path.data(), std::move(request), this);
} catch (const std::exception e) {
} catch (const std::exception& e) {
Response error(Response::Status::internalError);
error.setBody(std::string(e.what()));
error.replyTo(*request.get());
@ -82,7 +72,7 @@ void Server::handleRequest(std::unique_ptr<Request> request) {
}
bool Server::printEnvironment(Request* request, Server* server) {
(void)server;
UNUSED(server);
nlohmann::json body = nlohmann::json::object();
request->printEnvironment(body);
@ -94,11 +84,11 @@ bool Server::printEnvironment(Request* request, Server* server) {
}
bool Server::info(Request* request, Server* server) {
(void)server;
UNUSED(server);
Response res;
nlohmann::json body = nlohmann::json::object();
body["type"] = "Pica";
body["version"] = "0.0.1";
body["type"] = PROJECT_NAME;
body["version"] = PROJECT_VERSION;
res.setBody(body);
res.replyTo(*request);

View File

@ -21,6 +21,8 @@
#include "response/response.h"
#include "router.h"
#include "database/dbinterface.h"
#include "utils/helpers.h"
#include "config.h"
class Server {
public:

View File

@ -8,4 +8,4 @@ set(SOURCES
ostream.cpp
)
target_sources(pica PRIVATE ${SOURCES})
target_sources(${PROJECT_NAME} PRIVATE ${SOURCES})

View File

@ -4,12 +4,18 @@
#include "helpers.h"
#include "iostream"
#include <algorithm>
#include <functional>
#include "config.h"
static bool installed = false;
static std::filesystem::path sPath;
bool isSpace(char ch){
return std::isspace(static_cast<unsigned char>(ch));
}
void setAbsoluteSharedPath () {
installed = true;
sPath = FULL_DATA_DIR "/" PROJECT_NAME; // should be something like /usr/share/pica or /local/usr/share/pica
@ -36,7 +42,7 @@ void initPaths(const char* programPath) {
if (endsWith(parent.string(), BIN_DIR)) { //this is the case when the program is installed somewhere but not system root
std::filesystem::path bin(BIN_DIR); //so it will read from something like ../share/pica/ relative to the binary
for (const auto& hop : bin) {
(void)hop; //I do this just to make as many ups as many members are in bin
UNUSED(hop); //I do this just to make as many ups as many members are in bin
parent = parent.parent_path();
}
sPath = parent / DATA_DIR / PROJECT_NAME;
@ -59,3 +65,40 @@ bool endsWith(const std::string& string, const std::string& query) {
return false;
}
}
void ltrim(std::string& string) {
string.erase(
string.begin(),
std::find_if(
string.begin(),
string.end(),
std::not_fn(isSpace)
)
);
}
void rtrim(std::string& string) {
string.erase(
std::find_if(
string.rbegin(),
string.rend(),
std::not_fn(isSpace)
).base(),
string.end()
);
}
void trim(std::string& string) {
ltrim(string);
rtrim(string);
}
std::string extract(std::string& string, std::string::size_type begin, std::string::size_type end) {
std::string result = string.substr(begin, end);
if (end == std::string::npos)
string.erase(begin, end);
else
string.erase(begin, result.length() + 1);
return result;
}

View File

@ -6,7 +6,12 @@
#include <filesystem>
#include <string>
#define UNUSED(variable) (void)variable
void initPaths(const char* programPath);
const std::filesystem::path& sharedPath();
bool endsWith(const std::string& string, const std::string& query);
void ltrim(std::string& string);
void rtrim(std::string& string);
void trim(std::string& string);
std::string extract(std::string& string, std::string::size_type begin, std::string::size_type end);