-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4a47ec3
commit 82f54df
Showing
14 changed files
with
311 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,26 @@ | ||
# hazel | ||
|
||
|
||
Internal metaserver for my homelab. It's going to be a while before it's generally usable by anyone else, so the docs are going to be thin for the near foreseeable future. | ||
Internal metaserver for my homelab. It's going to be a while before it's generally usable by anyone else, so the docs are going to be thin for the near foreseeable future, and stuff will be ugly, broken, or both. | ||
|
||
The entire theme is scope creep, so Hazel is designed for a lot of random shit I need, but don't feel like making an entire dedicated project for. Some planned ideas include: | ||
|
||
* The obligatory link dashboard | ||
* Status monitoring | ||
* The obligatory real-time (ish) overview | ||
* Practical monitoring of stuff like miniflux unreads | ||
* System information | ||
* Service information | ||
* Long-running job tracking (with NTFY integration for failure or completion) | ||
* Automation with scripting for easier expansion | ||
|
||
The overall goal of the project is primarily to join together other self-hosted services, and to implement a few things from scratch. But for the most part, where possible, main functionality is deferred to other (primarily self-hosted) services, with Hazel serving as an aggregator. | ||
|
||
## Requirements | ||
|
||
* A Linux-based server | ||
* C++20 compiler | ||
* CMake 3.28 (Pro tip: [CMake is available via pip](https://pypi.org/project/cmake/)) | ||
* libpq-dev, uuid-dev, libasio-dev (Debian-based names; look up your distro's package manager for the applicable packages). Additional dependencies are sourced automagically during the build process | ||
* Postgresql | ||
* uuid-dev, libasio-dev (Debian-based names; look up your distro's package manager for the applicable packages). Additional dependencies are sourced automagically during the build process | ||
|
||
Docker is not supported, because it's annoying to work with and in this case, there's absolutely 0 advantages to supporting it. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
#include "Database.hpp" | ||
#include "SQLiteCpp/Database.h" | ||
|
||
#include "db/Migration.hpp" | ||
|
||
namespace hazel { | ||
|
||
Database::Database(const std::filesystem::path& dbPath) | ||
: db( | ||
SQLite::Database( | ||
dbPath.string().c_str(), | ||
SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE | ||
) | ||
) | ||
{ | ||
|
||
} | ||
|
||
void Database::initDatabase() { | ||
|
||
this->db.write([](auto& sdb) { | ||
Migration::prepMetatables(sdb); | ||
|
||
Migration m; | ||
m.pushVersion(R"( | ||
CREATE TABLE Users ( | ||
ID INTEGER PRIMARY KEY AUTOINCREMENT, | ||
Username TEXT, | ||
Password TEXT, | ||
IsAdmin BOOLEAN | ||
); | ||
)") | ||
.exec(sdb); | ||
|
||
}); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
#pragma once | ||
|
||
#include "SQLiteCpp/Database.h" | ||
#include "hazel/sync/RWContainer.hpp" | ||
#include <SQLiteCpp/SQLiteCpp.h> | ||
#include <filesystem> | ||
#include <shared_mutex> | ||
|
||
namespace hazel { | ||
|
||
class Database { | ||
private: | ||
RWContainer<SQLite::Database> db; | ||
|
||
public: | ||
Database(const std::filesystem::path& dbPath); | ||
void initDatabase(); | ||
|
||
RWContainer<SQLite::Database>* operator->() { | ||
return &db; | ||
} | ||
|
||
}; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
#pragma once | ||
|
||
#include <string> | ||
#include <map> | ||
|
||
namespace hazel { | ||
|
||
namespace Modules { | ||
|
||
#define E2S(en) {#en, en} | ||
#define S2E(en) {en, #en} | ||
enum Modules { | ||
AUTOMATION, | ||
LINKS | ||
}; | ||
|
||
|
||
const static std::map<std::string, Modules> stringModuleMap { | ||
E2S(AUTOMATION), | ||
E2S(LINKS) | ||
}; | ||
|
||
const static std::map<Modules, std::string> moduleStringMap { | ||
S2E(AUTOMATION), | ||
S2E(LINKS) | ||
}; | ||
|
||
#undef E2S | ||
#undef S2E | ||
} | ||
|
||
struct EnabledModules { | ||
Modules::Modules moduleIdentifier; | ||
bool enabled; | ||
}; | ||
|
||
struct GlobalAdminConfig { | ||
bool allowAccountCreation; | ||
|
||
}; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
#pragma once | ||
|
||
#include <string> | ||
|
||
namespace hazel { | ||
|
||
struct User { | ||
long long userId; | ||
|
||
std::string username; | ||
std::string password; | ||
|
||
bool isAdmin; | ||
|
||
}; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
#include "Migration.hpp" | ||
#include "SQLiteCpp/Statement.h" | ||
#include "SQLiteCpp/Transaction.h" | ||
|
||
#include <hazel/data/Database.hpp> | ||
|
||
#include <spdlog/spdlog.h> | ||
#include <stdexcept> | ||
|
||
namespace hazel { | ||
|
||
Migration& Migration::pushVersion(const std::string &query) { | ||
this->queries.push_back(query); | ||
|
||
return *this; | ||
} | ||
|
||
void Migration::exec(SQLite::Database& db) { | ||
SQLite::Transaction tx(db); | ||
|
||
SQLite::Statement stmt(db, R"( | ||
SELECT Version FROM Migrations WHERE Name = 'Version' | ||
)"); | ||
|
||
int64_t headVersion = 0; | ||
if (stmt.executeStep()) { | ||
headVersion = stmt.getColumn(0).getInt64(); | ||
} | ||
|
||
if (headVersion < 0) { | ||
spdlog::error( | ||
"The Migrations table has been tampered with. Cannot resolve the current database state. " | ||
"If you've fucked around with the Migrations table, first, why? Second, this is not a bug. " | ||
"You have to purge your entire database. If you haven't, please open a bug report. This should not normally " | ||
"happen, unless you've done something weird to the database." | ||
); | ||
tx.rollback(); | ||
throw std::runtime_error("Database fucked"); | ||
} | ||
|
||
if (headVersion < (int64_t) this->queries.size() + versionOffset) { | ||
spdlog::info("Database out of date (current version: {}, new version: {})", headVersion, queries.size()); | ||
for (size_t i = headVersion - versionOffset; i < queries.size(); ++i) { | ||
spdlog::info("Updating to v{}", i + 1 + versionOffset); | ||
db.exec(queries.at(i + versionOffset)); | ||
} | ||
|
||
SQLite::Statement stmt(db, R"( | ||
INSERT OR REPLACE INTO Migrations (Name, Version) | ||
VALUES | ||
('Version', ?) | ||
)"); | ||
stmt.bind(1, int64_t(queries.size()) + versionOffset); | ||
|
||
if (stmt.exec() == 0) { | ||
tx.rollback(); | ||
spdlog::error("Failed to upgrade database"); | ||
throw std::runtime_error("Migration error"); | ||
} | ||
|
||
spdlog::info("Update successful."); | ||
|
||
} else { | ||
spdlog::info("Database up-to-date (version: {})", headVersion); | ||
} | ||
|
||
|
||
|
||
tx.commit(); | ||
} | ||
|
||
void Migration::prepMetatables(SQLite::Database& db) { | ||
spdlog::info("Initialising migration table..."); | ||
SQLite::Transaction tx(db); | ||
db.exec(R"( | ||
CREATE TABLE IF NOT EXISTS Migrations ( | ||
Name TEXT PRIMARY KEY, | ||
Version INTEGER NOT NULL | ||
); | ||
)"); | ||
tx.commit(); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
#include "SQLiteCpp/Database.h" | ||
#include <string> | ||
#include <vector> | ||
|
||
namespace hazel { | ||
|
||
/** | ||
* Note: this is just a version control wrapper. The queries and migration controls are still | ||
* manually managed. This is so I don't have to spend an eterity writng this clusterfuck, | ||
* because there are an extreme number of edge-cases in migrations. There's defaults to consider when | ||
* rows are added to an existing table, different col types, etc. It's far easier to build | ||
* it for just query versioning. | ||
*/ | ||
class Migration { | ||
private: | ||
std::vector<std::string> queries; | ||
|
||
/** | ||
* Used to provide an offset to the versions | ||
* | ||
* This is currently not possible to set anywhere, | ||
* and is kept purely for a hypothetical future | ||
* scenario, because why the fuck not? Let's | ||
* overengineer this class :D | ||
*/ | ||
constexpr static int64_t versionOffset = 0; | ||
public: | ||
Migration() {} | ||
|
||
Migration& pushVersion(const std::string& query); | ||
void exec(SQLite::Database& db); | ||
|
||
static void prepMetatables(SQLite::Database& db); | ||
|
||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
#pragma once | ||
|
||
#include "crow/mustache.h" | ||
namespace hazel { | ||
|
||
class DashboardModule { | ||
public: | ||
virtual ~DashboardModule() = default; | ||
virtual void makeEndpoints() = 0; | ||
|
||
virtual void render(crow::mustache::context& ctx) = 0; | ||
|
||
virtual bool isConfigAdminOnly() = 0; | ||
virtual bool isModulePublic() = 0; | ||
}; | ||
|
||
} |
Oops, something went wrong.