summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/guestbook.cpp78
-rw-r--r--src/main.cpp84
-rw-r--r--src/views.cpp40
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