diff options
| author | wuesk <wsk@tuta.com> | 2026-09-22 13:30:39 +0200 |
|---|---|---|
| committer | wuesk <wsk@tuta.com> | 2026-09-22 13:30:39 +0200 |
| commit | 72fafe4553e075c040734e31164e50c4cdc7f319 (patch) | |
| tree | 4a58557786185e993c11a5c4c27894333ab84842 /src | |
Diffstat (limited to 'src')
| -rw-r--r-- | src/guestbook.cpp | 78 | ||||
| -rw-r--r-- | src/main.cpp | 84 | ||||
| -rw-r--r-- | src/views.cpp | 40 |
3 files changed, 202 insertions, 0 deletions
diff --git a/src/guestbook.cpp b/src/guestbook.cpp new file mode 100644 index 0000000..0b58ddf --- /dev/null +++ b/src/guestbook.cpp @@ -0,0 +1,78 @@ +#include "guestbook.hpp" +#include "json.hpp" + +#include <filesystem> +#include <fstream> +#include <iostream> + +using json = nlohmann::json; + +namespace { + const std::filesystem::path guestbookFilePath = "data/guestbook.json"; +} + +std::vector<GuestbookEntry> loadGuestbook() +{ + std::ifstream file(guestbookFilePath); + + if (!file.is_open()) + { + return {}; + } + + if (file.peek() == std::ifstream::traits_type::eof()) + { + return {}; + } + + // An existing but empty file is not valid JSON. Treat it like a new + // guestbook so a partially initialized data directory cannot crash the + // server during startup. + json data = json::parse(file, nullptr, false); + + if (data.is_discarded() || !data.is_array()) + { + std::cerr << "Warning: ignoring invalid guestbook data in " + << guestbookFilePath << '\n'; + return {}; + } + + std::vector<GuestbookEntry> entries; + + for (const auto& item : data) + { + GuestbookEntry entry; + entry.name = item.at("name").get<std::string>(); + entry.message = item.at("message").get<std::string>(); + + entries.push_back(entry); + } + + return entries; +} + +bool saveGuestbook(const std::vector<GuestbookEntry>& entries) +{ + std::filesystem::create_directories(guestbookFilePath.parent_path()); + + json data = json::array(); + + for (const GuestbookEntry& entry : entries) + { + data.push_back({ + {"name", entry.name}, + {"message", entry.message} + }); + } + + std::ofstream file(guestbookFilePath); + + if (!file.is_open()) + { + return false; + } + + file << data.dump(4); + + return true; +} diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..ad0214a --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,84 @@ +#include <iostream> +#include "httplib.h" +#include "views.hpp" +#include "guestbook.hpp" +#include "json.hpp" + +using json = nlohmann::json; + +int main() +{ + httplib::Server server; + + int views = loadViews(); + std::vector<GuestbookEntry> guestbook = loadGuestbook(); + + server.Get("/health", [](const httplib::Request& request, httplib::Response& response) + { + response.set_content("OK", "text/plain"); + }); + + server.Get("/api/views", [&views](const httplib::Request& request, httplib::Response& response) + { + response.set_content(std::to_string(views), "text/plain"); + }); + + server.Post("/api/views", [&views](const httplib::Request& request, httplib::Response& response) + { + const int newViews = views + 1; + + if (!saveViews(newViews)) + { + response.status = 500; + response.set_content("Failed to save views", "text/plain"); + return; + } + + views = newViews; + + response.set_content(std::to_string(views), "text/plain"); + }); + + server.Get("/api/guestbook", [&guestbook](const httplib::Request& request, httplib::Response& response) + { + json data = json::array(); + + for (const GuestbookEntry& entry : guestbook) + { + data.push_back({ + {"name", entry.name}, + {"message", entry.message} + }); + } + + response.set_content(data.dump(), "application/json"); + }); + + server.Post("/api/guestbook", [&guestbook](const httplib::Request& request, httplib::Response& response) + { + json body = json::parse(request.body); + + GuestbookEntry entry; + entry.name = body.at("name").get<std::string>(); + entry.message = body.at("message").get<std::string>(); + + guestbook.push_back(entry); + + if (!saveGuestbook(guestbook)) + { + response.status = 500; + response.set_content("Failed to save guestbook", "text/plain"); + return; + } + + response.status = 201; + response.set_content("Entry created", "text/plain"); + }); + + std::cout << "Blog backend started\n"; + std::cout << "Port: 8080\n"; + + server.listen("0.0.0.0", 8080); + + return 0; +}
\ No newline at end of file diff --git a/src/views.cpp b/src/views.cpp new file mode 100644 index 0000000..f03d794 --- /dev/null +++ b/src/views.cpp @@ -0,0 +1,40 @@ +#include "views.hpp" + +#include <fstream> +#include <filesystem> + +namespace { + const std::filesystem::path viewsFilePath = "data/views.txt"; +} + +int loadViews() +{ + std::ifstream file(viewsFilePath); + + int views = 0; + + if (!file.is_open()) + { + return views; + } + + file >> views; + + return views; +} + +bool saveViews(int views) +{ + //Create directory if doesn't exist + std::filesystem::create_directories(viewsFilePath.parent_path()); + + std::ofstream file(viewsFilePath); + + if (!file.is_open()) { + return false; + } + + file << views; + + return true; +}
\ No newline at end of file |
