From 519cd3d4da218a8daea3575b2c4f17fc4fcbfea7 Mon Sep 17 00:00:00 2001 From: defnax <9952056+defnax@users.noreply.github.com> Date: Fri, 28 Aug 2026 13:45:50 +0200 Subject: [PATCH] Added changes to retrieve stickers for the webui --- src/jsonapi/p3webui.cc | 99 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/src/jsonapi/p3webui.cc b/src/jsonapi/p3webui.cc index e2b3521ee..99108ff66 100644 --- a/src/jsonapi/p3webui.cc +++ b/src/jsonapi/p3webui.cc @@ -22,6 +22,10 @@ #include "p3webui.h" +#include +#include +#include +#include #include #include #include @@ -32,9 +36,11 @@ #include "util/rsthreads.h" #include "util/rsdebug.h" #include "retroshare/rswebui.h" +#include "retroshare/rsinit.h" #include "rsserver/rsaccounts.h" #include "retroshare/rsjsonapi.h" #include "util/rsdir.h" +#include "util/rsbase64.h" /*extern*/ RsWebUi* rsWebUi = new p3WebUI; @@ -106,6 +112,94 @@ public: } }; +static std::string jsonEscape(const std::string& value) +{ + std::string escaped; + for(char c : value) + switch(c) + { + case '\\': escaped += "\\\\"; break; + case '"': escaped += "\\\""; break; + case '\n': escaped += "\\n"; break; + case '\r': escaped += "\\r"; break; + case '\t': escaped += "\\t"; break; + default: escaped += c; + } + return escaped; +} + +static const char* stickerMime(const std::filesystem::path& path) +{ + std::string ext = path.extension().string(); + std::transform(ext.begin(), ext.end(), ext.begin(), + [](unsigned char c) { return static_cast(std::tolower(c)); }); + if(ext == ".png") return "image/png"; + if(ext == ".jpg" || ext == ".jpeg") return "image/jpeg"; + if(ext == ".gif") return "image/gif"; + if(ext == ".webp") return "image/webp"; + return nullptr; +} + +static void stickers_handler(const std::shared_ptr session) +{ + namespace fs = std::filesystem; + const std::vector roots = { + fs::path(RsAccounts::AccountDirectory()) / "stickers", + fs::path(RsAccounts::ConfigDirectory()) / "stickers", + fs::path(RsAccounts::systemDataDirectory()) / "stickers" + }; + std::ostringstream json; + json << "{\"groups\":["; + bool firstGroup = true; + for(const fs::path& root : roots) + { + std::error_code ec; + if(!fs::is_directory(root, ec)) continue; + std::vector directories = { root }; + for(fs::recursive_directory_iterator it(root, fs::directory_options::skip_permission_denied, ec), end; + it != end; it.increment(ec)) + if(!ec && it->is_directory()) directories.push_back(it->path()); + for(const fs::path& directory : directories) + { + std::vector images; + for(fs::directory_iterator it(directory, fs::directory_options::skip_permission_denied, ec), end; + it != end; it.increment(ec)) + if(!ec && it->is_regular_file() && stickerMime(it->path()) + && it->path().filename() != "groupicon.png") images.push_back(it->path()); + if(images.empty()) continue; + std::sort(images.begin(), images.end()); + if(!firstGroup) json << ','; + firstGroup = false; + json << "{\"name\":\"" << jsonEscape(directory.filename().string()) << "\",\"stickers\":["; + bool firstSticker = true; + for(const fs::path& image : images) + { + std::ifstream stream(image, std::ios::binary); + if(!stream) continue; + const std::vector bytes { + std::istreambuf_iterator(stream), + std::istreambuf_iterator() }; + std::string encoded; + RsBase64::encode(bytes.data(), bytes.size(), encoded, true, false); + if(!firstSticker) json << ','; + firstSticker = false; + json << "{\"name\":\"" << jsonEscape(image.filename().string()) + << "\",\"src\":\"data:" << stickerMime(image) << ";base64," << encoded << "\"}"; + } + json << "]}"; + } + } + json << "]}"; + const std::string bodyString = json.str(); + const std::vector body(bodyString.begin(), bodyString.end()); + const std::multimap headers { + { "Content-Type", "application/json" }, + { "Content-Length", std::to_string(body.size()) }, + { "Cache-Control", "no-store" } + }; + session->close(restbed::OK, body, headers); +} + std::vector< std::shared_ptr > p3WebUI::getResources() const { static std::vector< std::shared_ptr > rtab; @@ -183,6 +277,10 @@ std::vector< std::shared_ptr > p3WebUI::getResources() const } ); resource7->set_method_handler( "GET", handler::get_handler ); + auto stickersResource = std::make_shared(); + stickersResource->set_paths( { "/{dir: stickers}/{filename: index.json}" } ); + stickersResource->set_method_handler("GET", stickers_handler); + rtab.push_back(resource1); rtab.push_back(resource2); rtab.push_back(resource3); @@ -190,6 +288,7 @@ std::vector< std::shared_ptr > p3WebUI::getResources() const rtab.push_back(resource5); rtab.push_back(resource6); rtab.push_back(resource7); + rtab.push_back(stickersResource); } return rtab;