From 69f7f625f8ce12b609e45771e354236f786b6616 Mon Sep 17 00:00:00 2001 From: Lukas Forsberg Date: Sun, 1 Jun 2025 21:19:54 +0200 Subject: [PATCH] added shadowrun database --- .vscode/settings.json | 88 +-------------- CMakeLists.txt | 33 +++++- README.md | 2 +- src/database/database.cpp | 35 ++++++ src/database/database.hpp | 21 ++++ src/htmx_helper.cpp | 1 + src/main.cpp | 31 ++++-- src/shadowrun/HtmxShAttributeList.cpp | 26 +++++ src/shadowrun/HtmxShAttributeList.hpp | 18 +++ src/shadowrun/HtmxShCondition.cpp | 28 +++++ src/shadowrun/HtmxShCondition.hpp | 13 +++ src/shadowrun/HtmxShItemList.cpp | 43 ++++++++ src/shadowrun/HtmxShItemList.hpp | 18 +++ src/shadowrun/ShadowrunApi.cpp | 106 ++++++++++++++++++ src/shadowrun/ShadowrunApi.hpp | 11 ++ src/shadowrun/ShadowrunCharacterForm.cpp | 122 +++++++++++++++++++++ src/shadowrun/ShadowrunCharacterForm.hpp | 14 +++ src/utils.cpp | 79 ++++++++++++++ src/utils.hpp | 19 ++++ templates/shadowrun.html | 133 +++++++++++++++++++++++ 20 files changed, 738 insertions(+), 103 deletions(-) create mode 100644 src/database/database.cpp create mode 100644 src/database/database.hpp create mode 100644 src/shadowrun/HtmxShAttributeList.cpp create mode 100644 src/shadowrun/HtmxShAttributeList.hpp create mode 100644 src/shadowrun/HtmxShCondition.cpp create mode 100644 src/shadowrun/HtmxShCondition.hpp create mode 100644 src/shadowrun/HtmxShItemList.cpp create mode 100644 src/shadowrun/HtmxShItemList.hpp create mode 100644 src/shadowrun/ShadowrunApi.cpp create mode 100644 src/shadowrun/ShadowrunApi.hpp create mode 100644 src/shadowrun/ShadowrunCharacterForm.cpp create mode 100644 src/shadowrun/ShadowrunCharacterForm.hpp create mode 100644 src/utils.cpp create mode 100644 src/utils.hpp create mode 100644 templates/shadowrun.html diff --git a/.vscode/settings.json b/.vscode/settings.json index a6f1e00..23a0c9f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,92 +1,6 @@ { "files.associations": { - "any": "cpp", - "array": "cpp", - "atomic": "cpp", - "hash_map": "cpp", - "bit": "cpp", - "*.tcc": "cpp", - "bitset": "cpp", - "cctype": "cpp", - "charconv": "cpp", - "chrono": "cpp", - "clocale": "cpp", - "cmath": "cpp", - "codecvt": "cpp", - "compare": "cpp", - "concepts": "cpp", - "condition_variable": "cpp", - "coroutine": "cpp", - "csignal": "cpp", - "cstdarg": "cpp", - "cstddef": "cpp", - "cstdint": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "ctime": "cpp", - "cwchar": "cpp", - "cwctype": "cpp", - "deque": "cpp", - "forward_list": "cpp", - "list": "cpp", - "map": "cpp", - "set": "cpp", - "string": "cpp", - "unordered_map": "cpp", - "unordered_set": "cpp", - "vector": "cpp", - "exception": "cpp", - "algorithm": "cpp", - "functional": "cpp", - "iterator": "cpp", - "memory": "cpp", - "memory_resource": "cpp", - "numeric": "cpp", - "optional": "cpp", - "random": "cpp", - "ratio": "cpp", - "source_location": "cpp", - "string_view": "cpp", - "system_error": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "utility": "cpp", - "format": "cpp", - "fstream": "cpp", - "future": "cpp", - "initializer_list": "cpp", - "iomanip": "cpp", - "iosfwd": "cpp", - "iostream": "cpp", - "istream": "cpp", - "limits": "cpp", - "mutex": "cpp", - "new": "cpp", - "numbers": "cpp", - "ostream": "cpp", - "ranges": "cpp", - "semaphore": "cpp", - "shared_mutex": "cpp", - "span": "cpp", - "sstream": "cpp", - "stdexcept": "cpp", - "stdfloat": "cpp", - "stop_token": "cpp", - "streambuf": "cpp", "text_encoding": "cpp", - "thread": "cpp", - "cfenv": "cpp", - "cinttypes": "cpp", - "typeinfo": "cpp", - "valarray": "cpp", - "variant": "cpp", - "*.ipp": "cpp", - "expected": "cpp", - "queue": "cpp", - "stack": "cpp", - "strstream": "cpp", - "complex": "cpp", - "typeindex": "cpp" + "thread": "cpp" } } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 03a6a47..f807587 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,8 @@ cmake_minimum_required(VERSION 3.10) project(CrowHTMX) +set(TARGET_NAME lf-server-admin-panel ) + set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -30,9 +32,12 @@ foreach(file IN LISTS TEMPLATE_FILES) endforeach() # Use Crow from system include (installed via yay -S crow + asio) -include_directories(/usr/include) +include_directories(/usr/include src src/htmx src/shadowrun src/database) -add_executable(lf-server-admin-panel src/main.cpp +add_executable(${TARGET_NAME} + src/main.cpp + src/utils.hpp + src/utils.cpp src/htmx/HtmxTable.cpp src/htmx/HtmxTable.h src/systemd.cpp @@ -46,9 +51,29 @@ add_executable(lf-server-admin-panel src/main.cpp src/htmx_helper.h src/json_settings.cpp src/json_settings.h - src/json.hpp) + src/json.hpp -target_link_libraries(lf-server-admin-panel pthread) + src/database/database.cpp + src/database/database.hpp + + # Shadowrun + src/shadowrun/HtmxShItemList.cpp + src/shadowrun/HtmxShItemList.hpp + src/shadowrun/HtmxShAttributeList.cpp + src/shadowrun/HtmxShAttributeList.hpp + src/shadowrun/HtmxShCondition.cpp + src/shadowrun/HtmxShCondition.hpp + src/shadowrun/ShadowrunCharacterForm.hpp + src/shadowrun/ShadowrunCharacterForm.cpp + src/shadowrun/ShadowrunApi.cpp + src/shadowrun/ShadowrunApi.hpp + + + ) + +target_compile_definitions(${TARGET_NAME} PRIVATE APPLICATION_NAME="${TARGET_NAME}") + +target_link_libraries(${TARGET_NAME} pthread sqlite3) # Optional: Print build type at configuration time message(STATUS "Configuring build type: ${CMAKE_BUILD_TYPE}") \ No newline at end of file diff --git a/README.md b/README.md index c2e8ad4..b7bf241 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ## Setup -pacman -S crow asio gdb gcc cmake make +pacman -S crow asio gdb gcc cmake make sqlite3 ## Build diff --git a/src/database/database.cpp b/src/database/database.cpp new file mode 100644 index 0000000..f559b6c --- /dev/null +++ b/src/database/database.cpp @@ -0,0 +1,35 @@ +#include "crow.h" +#include "database.hpp" + +Database::Database() : + m_db(nullptr) +{} + +Database::~Database() { + sqlite3_close(m_db); +} + +bool Database::exec(const char* sqlQuery) { + char* errmsg = nullptr; + int rc = sqlite3_exec(m_db, sqlQuery, nullptr, nullptr, &errmsg); + if (rc != SQLITE_OK) { + CROW_LOG_ERROR << "SQL error: " << errmsg; + sqlite3_free(errmsg); + return false; + } + return true; +} + +bool Database::exec(const std::string& sqlQuery) +{ + exec(sqlQuery.c_str()); +} + +bool Database::open(){ + int rc = sqlite3_open("example.db", &m_db); + if (rc) { + CROW_LOG_ERROR << "Can't open database: " << sqlite3_errmsg(m_db); + return false; + } + return true; +} diff --git a/src/database/database.hpp b/src/database/database.hpp new file mode 100644 index 0000000..478ba44 --- /dev/null +++ b/src/database/database.hpp @@ -0,0 +1,21 @@ +#ifndef __DATABASE_H__ +#define __DATABASE_H__ + +#include "sqlite3.h" +#include + +class Database { + +public: + Database(); + ~Database(); + + bool open(); + bool exec(const char* sqlQuery); + bool exec(const std::string& sqlQuery); + +private: + sqlite3* m_db; +}; + +#endif // __DATABASE_H__ \ No newline at end of file diff --git a/src/htmx_helper.cpp b/src/htmx_helper.cpp index 74b63d7..0dc3144 100644 --- a/src/htmx_helper.cpp +++ b/src/htmx_helper.cpp @@ -5,6 +5,7 @@ #include "systemd.h" #include "htmx_helper.h" #include "json_settings.h" +#include "utils.hpp" using namespace std; diff --git a/src/main.cpp b/src/main.cpp index afca86d..0f636eb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,4 @@ #include -#include -#include #include #include #include @@ -8,16 +6,11 @@ #include "json_settings.h" #include "htmx_helper.h" #include "systemd.h" +#include "utils.hpp" +#include "ShadowrunApi.hpp" using namespace std; -string load_file(const string& path) { - ifstream f(path); - stringstream buffer; - buffer << f.rdbuf(); - return buffer.str(); -} - optional get_body_name(const string& body) { const auto pos = body.find('='); if (pos == std::string::npos) return {}; @@ -34,11 +27,15 @@ int main() { crow::SimpleApp app; CROW_ROUTE(app, "/")([] { - return crow::response(load_file("templates/index.html")); + return crow::response(utils::loadFile("templates/index.html")); }); CROW_ROUTE(app, "/static/")([](const std::string& file) { - return crow::response(load_file("static/" + file)); + return crow::response(utils::loadFile("static/" + file)); + }); + + CROW_ROUTE(app, "/templates/")([](const std::string& file) { + return crow::response(utils::loadFile("templates/" + file)); }); CROW_ROUTE(app, "/status")([] { @@ -80,8 +77,20 @@ int main() { } else { CROW_LOG_ERROR << "failed to load settings : " << opt_settings.error(); } + + auto opt_isPortOpen = utils::isLocalPortOpen(httpPort); + if (opt_isPortOpen.has_value()){ + if (opt_isPortOpen.value()){ + CROW_LOG_ERROR << "Local port : " << httpPort << " is already open"; + } + } + else { + CROW_LOG_ERROR << "failed to check if local port is open : " << opt_isPortOpen.error(); + } } + shadowrun::initApi(app); + app.loglevel(crow::LogLevel::INFO); app.port(httpPort).multithreaded().run(); } diff --git a/src/shadowrun/HtmxShAttributeList.cpp b/src/shadowrun/HtmxShAttributeList.cpp new file mode 100644 index 0000000..5a76fb9 --- /dev/null +++ b/src/shadowrun/HtmxShAttributeList.cpp @@ -0,0 +1,26 @@ +#include +#include "HtmxShAttributeList.hpp" +#include "utils.hpp" + +using namespace std; + +HtmxShAttributeList::HtmxShAttributeList(const std::string& id, const vector& itemList){ + html += format("

{}

", id); + html += "
"; + for (auto& item : itemList){ + string item_id = utils::to_id_format(id + "_" + item); + + html += format("", item, item_id); + } + html += "
"; +} + +HtmxShAttributeList::HtmxShAttributeList(const std::string& id, const std::vector>& itemValueList){ + html += format("

{}

", id); + html += "
"; + for (auto& item : itemValueList){ + string item_id = utils::to_id_format(id + "_" + item.first); + html += format("", item, item_id, item.second); + } + html += "
"; +} \ No newline at end of file diff --git a/src/shadowrun/HtmxShAttributeList.hpp b/src/shadowrun/HtmxShAttributeList.hpp new file mode 100644 index 0000000..f220b06 --- /dev/null +++ b/src/shadowrun/HtmxShAttributeList.hpp @@ -0,0 +1,18 @@ +#ifndef HTMXSHATTRIBUTELIST_H +#define HTMXSHATTRIBUTELIST_H + +#include "HtmxObject.h" +#include +#include + +class HtmxShAttributeList : public HtmxObject { + +public: + // create new item list + HtmxShAttributeList(const std::string& id, const std::vector& itemList); + + // create new item list where each item as a value + HtmxShAttributeList(const std::string& id, const std::vector>& itemValueList); +}; + +#endif // HTMXSHATTRIBUTELIST_H \ No newline at end of file diff --git a/src/shadowrun/HtmxShCondition.cpp b/src/shadowrun/HtmxShCondition.cpp new file mode 100644 index 0000000..32f837e --- /dev/null +++ b/src/shadowrun/HtmxShCondition.cpp @@ -0,0 +1,28 @@ +#include "HtmxShCondition.hpp" +#include "../utils.hpp" +#include + +using namespace std; + +HtmxShCondition::HtmxShCondition(std::string id, size_t nbrOfBoxes) +{ + html += "
"; + html += format("

{}

", id); + html += "
"; + + int con_value = -1; + + for (size_t i = 0; i < nbrOfBoxes; i++) + { + string item_id = utils::to_id_format(format("{}_{}",id, i)); + html += format("", item_id); + + if ( ((i + 1) % 3 == 0) && (i != 0) ) + { + html += format("
{}
", con_value); + con_value--; + } + + } + html += "
"; +} diff --git a/src/shadowrun/HtmxShCondition.hpp b/src/shadowrun/HtmxShCondition.hpp new file mode 100644 index 0000000..3ce877e --- /dev/null +++ b/src/shadowrun/HtmxShCondition.hpp @@ -0,0 +1,13 @@ +#ifndef __HTMXSHCONDITION_H__ +#define __HTMXSHCONDITION_H__ + +#include +#include "HtmxObject.h" + +class HtmxShCondition : public HtmxObject { + +public: + HtmxShCondition(std::string id, size_t nbrOfBoxes); +}; + +#endif // __HTMXSHCONDITION_H__ \ No newline at end of file diff --git a/src/shadowrun/HtmxShItemList.cpp b/src/shadowrun/HtmxShItemList.cpp new file mode 100644 index 0000000..9a14d11 --- /dev/null +++ b/src/shadowrun/HtmxShItemList.cpp @@ -0,0 +1,43 @@ +#include +#include "HtmxShItemList.hpp" +#include "../utils.hpp" + +using namespace std; + +HtmxShItemList::HtmxShItemList(const std::string& id, const std::vector& columns, size_t size){ + html += "
"; + html += format("

{}

", id); + html += format("
", columns.size()); + for (size_t i = 0; i < size; i++){ + for (auto& col : columns){ + string item_id = utils::to_id_format(format("{}_{}_{}", id, i, col)); + html += format("", item_id, col); + } + } + + html += "
"; +} + +/* +HtmxShItemList::HtmxShItemList(const std::string& id, const std::vector>& itemValueList){ + html += format("

{}

", id); + html += "
"; + for (auto& item : itemValueList){ + string item_id = utils::to_id_format(id + "_" + item.first); + html += format("", item, item_id, item.second); + } + html += "
"; + + html += "
"; + html += format("

{}

", id); + html += format("
", columns.size()); + for (size_t i = 0; i < size; i++){ + for (auto& col : columns){ + string item_id = utils::to_id_format(format("{}_{}_{}", id, i, col)); + html += format("", item_id, col); + } + } + + html += "
"; +} +*/ \ No newline at end of file diff --git a/src/shadowrun/HtmxShItemList.hpp b/src/shadowrun/HtmxShItemList.hpp new file mode 100644 index 0000000..47aa221 --- /dev/null +++ b/src/shadowrun/HtmxShItemList.hpp @@ -0,0 +1,18 @@ +#ifndef HTMXSHITEMLIST_H +#define HTMXSHITEMLIST_H + +#include "HtmxObject.h" +#include +#include + +class HtmxShItemList : public HtmxObject { + +public: + // create new item list, + HtmxShItemList(const std::string& id, const std::vector& columns, size_t size); + + // create new item list where each item as a value + HtmxShItemList(const std::string& id, const std::vector>& itemValueList); +}; + +#endif // HTMXSHITEMLIST_H \ No newline at end of file diff --git a/src/shadowrun/ShadowrunApi.cpp b/src/shadowrun/ShadowrunApi.cpp new file mode 100644 index 0000000..f7d399e --- /dev/null +++ b/src/shadowrun/ShadowrunApi.cpp @@ -0,0 +1,106 @@ + + +#include "ShadowrunApi.hpp" +#include "ShadowrunCharacterForm.hpp" +#include "database.hpp" + +namespace shadowrun +{ + +bool initDb() { + auto db = Database(); + + if (!db.open()){ + return false; + } + + // Create a tables + const char* create_sql_chars = "CREATE TABLE IF NOT EXISTS shadowrun_characters (" + "id INTEGER PRIMARY KEY," + "name TEXT," + "created_at DATETIME DEFAULT CURRENT_TIMESTAMP);"; + + if (!db.exec(create_sql_chars)){ + CROW_LOG_ERROR << "Failed to create shadowrun_characters table"; + return false; + } + + const char* create_sql_data = "CREATE TABLE IF NOT EXISTS shadowrun_data (" + "id INTEGER PRIMARY KEY," + "character_id INTEGER NOT NULL," + "name TEXT NOT NULL," + "value TEXT," + "created_at DATETIME DEFAULT CURRENT_TIMESTAMP," + "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP," + "FOREIGN KEY (character_id) REFERENCES characters(id) ON DELETE CASCADE);"; + + if (!db.exec(create_sql_data)){ + CROW_LOG_ERROR << "Failed to create shadowrun_data table"; + return false; + } + return true; + +} + +void initApi(crow::SimpleApp& app) +{ + CROW_ROUTE(app, "/api/shadowrun/submit-character").methods("POST"_method)( + [](const crow::request& req) { + auto params = crow::query_string(req.body); + + std::string name = params.get("name") ? params.get("name") : ""; + std::string metatype = params.get("metatype") ? params.get("metatype") : ""; + std::string age = params.get("age") ? params.get("age") : ""; + // ... extract more fields as needed + + // Optionally save to a DB or do logic here + + // Return response HTML + std::ostringstream out; + out << "
" + << "Character " << name << " submitted successfully!" + << "
"; + + return crow::response{out.str()}; + }); + + CROW_ROUTE(app, "/api/shadowrun/character-form") + ([](const crow::request& req) { + auto query = crow::query_string(req.url_params); + std::string name = query.get("name") ? query.get("name") : ""; + + // TODO: Load data from file or DB using `name` + std::string metatype = "Troll"; + int age = 28; + + return crow::response{ShadowrunCharacterForm().htmx()}; + }); + + CROW_ROUTE(app, "/api/shadowrun/character-list") + ([] { + std::ostringstream html; + + // Simulated character database + std::vector characters = { "Trogdor", "Alice", "Zigzag" }; + + html << "
" + << "" + << "" + << "
"; + + return crow::response{html.str()}; + }); + + if(initDb()){ + CROW_LOG_ERROR << "Failed to Init shadowrun database"; + } +} + +} \ No newline at end of file diff --git a/src/shadowrun/ShadowrunApi.hpp b/src/shadowrun/ShadowrunApi.hpp new file mode 100644 index 0000000..9f76086 --- /dev/null +++ b/src/shadowrun/ShadowrunApi.hpp @@ -0,0 +1,11 @@ +#ifndef __SHADOWRUNAPI_H__ +#define __SHADOWRUNAPI_H__ + +#include + +namespace shadowrun { + +void initApi(crow::SimpleApp& app); + +} +#endif // __SHADOWRUNAPI_H__ \ No newline at end of file diff --git a/src/shadowrun/ShadowrunCharacterForm.cpp b/src/shadowrun/ShadowrunCharacterForm.cpp new file mode 100644 index 0000000..1d7ba1b --- /dev/null +++ b/src/shadowrun/ShadowrunCharacterForm.cpp @@ -0,0 +1,122 @@ +#include +#include +#include "HtmxShItemList.hpp" +#include "HtmxShAttributeList.hpp" +#include "HtmxShCondition.hpp" +#include "ShadowrunCharacterForm.hpp" + +using namespace std; + +static const vector cCharacterInfo = { + "Name", + "Metatype", + "Age", + "Sex", + "Nuyen", + "Lifestyle", + "Total Karma", + "Current Karma", + "Street Cred", + "Notoriety", + "Public Awareness" +}; + +static const vector cAttributes = { + "Body", + "Agility", + "Reaction", + "Strength", + "Charisma", + "Intuition", + "Logic", + "Willpower", + "Edge", + "Essence", + "Initiative" +}; + +static const vector cSkillParameters = { + "Name", + "RTG.", + "ATT.", +}; + +static const vector cContactsParameters = { + "Name", + "Loyalty", +}; + +static const vector cRangedWeaponsParameters = { + "Weapon", + "Damage", + "AP", + "Mode", + "RC", + "Ammo" +}; + +static const vector cImplantParameters = { + "Implant", + "Rating", + "Essence", + "Notes", +}; + +static const vector cMeleeWeaponParameters = { + "Weapon", + "Reach", + "Damage", + "AP", +}; + +static const vector cArmorParamters = { + "Armor", + "Ballistic", + "Impact", + "Notes", +}; + +ShadowrunCharacterForm::ShadowrunCharacterForm() { + html.reserve(30000); + + html += "
"; + html += HtmxShAttributeList("Character Info", cCharacterInfo).htmx(); + html += HtmxShAttributeList("Attributes", cAttributes).htmx(); + + html += "
"; + html += HtmxShItemList("Active Skills", cSkillParameters, 6).htmx(); + html += HtmxShItemList("Knowledge Skills", cSkillParameters, 6).htmx(); + + // add Qualities + html += "
" + "

Qualities

" + "" + "" + "
"; + + // add datapack notes + html += "
" + "

Datajack / Commlink / Cyberdeck / Notes

" + "" + "
"; + + html += HtmxShCondition("Physical Condition", 18).htmx(); + html += HtmxShCondition("Stun Condition", 12).htmx(); + html += HtmxShItemList("Contacts", cContactsParameters, 6).htmx(); + html += HtmxShItemList("Ranged Weapons", cRangedWeaponsParameters, 7).htmx(); + html += HtmxShItemList("Cyberware and Bioware", cImplantParameters, 7).htmx(); + html += HtmxShItemList("Melee Weapons", cMeleeWeaponParameters, 7).htmx(); + html += HtmxShItemList("Armor", cArmorParamters , 3).htmx(); + html += "
"; + + html += "
" + "" + "
" + "
"; +} \ No newline at end of file diff --git a/src/shadowrun/ShadowrunCharacterForm.hpp b/src/shadowrun/ShadowrunCharacterForm.hpp new file mode 100644 index 0000000..b6d4f75 --- /dev/null +++ b/src/shadowrun/ShadowrunCharacterForm.hpp @@ -0,0 +1,14 @@ +#ifndef SHADOWRUN_CHARACTER_FORM_HPP +#define SHADOWRUN_CHARACTER_FORM_HPP + +#include "htmx/HtmxObject.h" + +class ShadowrunCharacterForm : public HtmxObject { + +public: + ShadowrunCharacterForm(); + +private: +}; + +#endif // SHADOWRUN_CHARACTER_FORM_HPP \ No newline at end of file diff --git a/src/utils.cpp b/src/utils.cpp new file mode 100644 index 0000000..3d375b5 --- /dev/null +++ b/src/utils.cpp @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include +#include +#include +#include "utils.hpp" +#include +#include +#include + +using namespace std; + +namespace utils { + +expected isLocalPortOpen(uint16_t portno) { + const char *hostname = "localhost"; + + int sockfd; + bool ret; + struct sockaddr_in serv_addr; + struct hostent *server; + + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + close(sockfd); + return unexpected("ERROR opening socket"); + } + + server = gethostbyname(hostname); + + if (server == NULL) { + close(sockfd); + return unexpected("ERROR, no such host"); + } + + bzero((char *) &serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + bcopy((char *)server->h_addr, + (char *)&serv_addr.sin_addr.s_addr, + server->h_length); + + serv_addr.sin_port = htons(portno); + if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) { + ret = false; + } else { + ret = true; + } + + close(sockfd); + return ret; +} + +string to_id_format(const string& s){ + string new_s = s; + + // transform(new_s.begin(), new_s.end(), new_s.begin(), + // [](unsigned char c){ return std::tolower(c); }); + + replace( new_s.begin(), new_s.end(), ' ', '-'); + + return new_s; +} + +string loadFile(const string& path) { + ifstream f(path); + stringstream buffer; + buffer << f.rdbuf(); + return buffer.str(); +} + +std::filesystem::path getDataDir(){ + return std::getenv("XDG_DATA_HOME") + ? std::filesystem::path(std::getenv("XDG_DATA_HOME")) / APPLICATION_NAME + : std::filesystem::path(std::getenv("HOME")) / ".local" / "share" / APPLICATION_NAME; +} + +} \ No newline at end of file diff --git a/src/utils.hpp b/src/utils.hpp new file mode 100644 index 0000000..99e049a --- /dev/null +++ b/src/utils.hpp @@ -0,0 +1,19 @@ +#ifndef UTILS_HPP +#define UTILS_HPP + +#include +#include +#include +#include + +namespace utils { + std::expected isLocalPortOpen(uint16_t portno); + + std::string to_id_format(const std::string& s); + + std::string loadFile(const std::string& path); + + std::filesystem::path getDataDir(); +} + +#endif diff --git a/templates/shadowrun.html b/templates/shadowrun.html new file mode 100644 index 0000000..460a573 --- /dev/null +++ b/templates/shadowrun.html @@ -0,0 +1,133 @@ + + + + + + Shadowrun Character Sheet + + + + +
+

Shadowrun Character Sheet

+ +
+
+
+ +
+ +
+ +