diff options
author | dec05eba <dec05eba@protonmail.com> | 2018-05-03 08:29:45 +0200 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2018-05-03 08:29:48 +0200 |
commit | 9bb631f1e1861c63f38125fffb91081c98a1cfcc (patch) | |
tree | ad852904b8ae278c789e7f636ed4107038231c3f | |
parent | 9cde35c64c9f569055b101a80419d900f58806a9 (diff) |
Add/remove/list binds, saving to file
-rw-r--r-- | include/Cache.hpp | 4 | ||||
-rw-r--r-- | include/Chatbar.hpp | 6 | ||||
-rw-r--r-- | include/FileUtil.hpp | 3 | ||||
-rw-r--r-- | src/Cache.cpp | 48 | ||||
-rw-r--r-- | src/Chatbar.cpp | 58 | ||||
-rw-r--r-- | src/FileUtil.cpp | 22 | ||||
-rw-r--r-- | src/main.cpp | 82 |
7 files changed, 222 insertions, 1 deletions
diff --git a/include/Cache.hpp b/include/Cache.hpp index 429f652..19b811a 100644 --- a/include/Cache.hpp +++ b/include/Cache.hpp @@ -3,6 +3,7 @@ #include <boost/filesystem/path.hpp> #include <SFML/Graphics/Texture.hpp> #include <string> +#include <unordered_map> #include <thread> #include <mutex> #include <vector> @@ -49,6 +50,9 @@ namespace dchat // Creates directory if it doesn't exist (recursively). Throws boost exception on failure static boost::filesystem::path getDchatDir(); + static void loadBindsFromFile(); + static void replaceBindsInFile(const std::unordered_map<std::string, std::string> &binds); + // Get cached image or downloads it. // Default download file limit is 12MB // Returns ImageByUrlResult describing texture status. diff --git a/include/Chatbar.hpp b/include/Chatbar.hpp index 6ae2190..27b57f9 100644 --- a/include/Chatbar.hpp +++ b/include/Chatbar.hpp @@ -6,6 +6,8 @@ #include <SFML/Graphics/RectangleShape.hpp> #include <SFML/Window/Event.hpp> #include <SFML/System/Clock.hpp> +#include <string> +#include <unordered_map> namespace dchat { @@ -32,6 +34,10 @@ namespace dchat void draw(sf::RenderWindow &window); static float getHeight(); + + static bool addBind(const std::string &key, const std::string &value, bool updateFile = true); + static bool removeBind(const std::string &key, bool updateFile = true); + static const std::unordered_map<std::string, std::string>& getBinds(); private: void processChatCommand(const StringView &cmd); private: diff --git a/include/FileUtil.hpp b/include/FileUtil.hpp index 0cfc808..097b607 100644 --- a/include/FileUtil.hpp +++ b/include/FileUtil.hpp @@ -15,4 +15,7 @@ namespace dchat // Throws FileException on error. // Returned value is allocated with malloc and should be free'd by caller. StringView getFileContent(const boost::filesystem::path &filepath); + + // Throws FileException on error + void fileReplace(const boost::filesystem::path &filepath, const StringView data); } diff --git a/src/Cache.cpp b/src/Cache.cpp index d402d36..f3c5830 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -3,10 +3,13 @@ #include "../include/ResourceCache.hpp" #include "../include/FileUtil.hpp" #include "../include/Gif.hpp" +#include "../include/Chatbar.hpp" #include <boost/filesystem/convenience.hpp> #include <unordered_map> #include <process.hpp> #include <odhtdb/Hash.hpp> +#include <sibs/SafeSerializer.hpp> +#include <sibs/SafeDeserializer.hpp> #if OS_FAMILY == OS_FAMILY_POSIX #include <pwd.h> @@ -60,6 +63,51 @@ namespace dchat return dchatHomeDir; } + void Cache::loadBindsFromFile() + { + StringView fileContent; + try + { + fileContent = getFileContent(getDchatDir() / "binds"); + sibs::SafeDeserializer deserializer((const u8*)fileContent.data, fileContent.size); + + while(!deserializer.empty()) + { + u8 keySize = deserializer.extract<u8>(); + string key; + key.resize(keySize); + deserializer.extract((u8*)&key[0], keySize); + + u8 valueSize = deserializer.extract<u8>(); + string value; + value.resize(valueSize); + deserializer.extract((u8*)&value[0], valueSize); + + Chatbar::addBind(key, value, false); + } + } + catch(FileException &e) + { + fprintf(stderr, "Failed to read binds from file, reason: %s\n", e.what()); + } + + delete fileContent.data; + } + + void Cache::replaceBindsInFile(const unordered_map<string, string> &binds) + { + sibs::SafeSerializer serializer; + for(auto &it : binds) + { + serializer.add((u8)it.first.size()); + serializer.add((const u8*)it.first.data(), it.first.size()); + + serializer.add((u8)it.second.size()); + serializer.add((const u8*)it.second.data(), it.second.size()); + } + fileReplace(getDchatDir() / "binds", StringView((const char*)serializer.getBuffer().data(), serializer.getBuffer().size())); + } + ImageByUrlResult loadImageFromFile(const boost::filesystem::path &filepath) { try diff --git a/src/Chatbar.cpp b/src/Chatbar.cpp index cd2daa4..dd5a925 100644 --- a/src/Chatbar.cpp +++ b/src/Chatbar.cpp @@ -6,6 +6,7 @@ #include "../include/UsersSidePanel.hpp" #include "../include/Command.hpp" #include "../include/ColorScheme.hpp" +#include "../include/Cache.hpp" #include <cmath> #include <cstring> #include <process.hpp> @@ -25,6 +26,8 @@ namespace dchat const float LINE_PADDING_SIDE = 20.0f; const float LINE_HEIGHT = 1.0f; + unordered_map<string, string> binds; + Chatbar::Chatbar() : text("", *ResourceCache::getFont("fonts/Roboto-Regular.ttf"), FONT_SIZE * Settings::getScaling()), caretIndex(0), @@ -204,7 +207,7 @@ namespace dchat } } - string getClipboard() + static string getClipboard() { string result; TinyProcessLib::Process process("xsel -o -b", "", [&result](const char *bytes, size_t n) @@ -216,6 +219,28 @@ namespace dchat return result; } + static void findReplaceAll(string &str, const string &substrToReplace, const string &stringToReplaceWith) + { + size_t findOffset = 0; + while(findOffset < (size_t)str.size()) + { + findOffset = str.find(substrToReplace, findOffset); + if(findOffset != string::npos) + { + string substr = str.replace(findOffset, substrToReplace.size(), stringToReplaceWith); + findOffset += substrToReplace.size() + stringToReplaceWith.size(); + } + } + } + + static void replaceBinds(string &msg) + { + for(auto &it : binds) + { + findReplaceAll(msg, it.first, it.second); + } + } + void Chatbar::processEvent(const sf::Event &event, Channel *channel) { if(!focused) return; @@ -241,7 +266,10 @@ namespace dchat if(msg[0] == '/') processChatCommand(StringView(msg.data() + 1, msg.size() - 1)); else + { + replaceBinds(msg); channel->addMessage(msg); + } clear(); } } @@ -314,4 +342,32 @@ namespace dchat const float fontHeight = ResourceCache::getFont("fonts/Roboto-Regular.ttf")->getLineSpacing(fontSize); return PADDING_TOP * Settings::getScaling() + floor(fontHeight * 1.7f + BOX_PADDING_Y * Settings::getScaling() * 2.0f) + PADDING_BOTTOM * Settings::getScaling(); } + + bool Chatbar::addBind(const std::string &key, const std::string &value, bool updateFile) + { + if(binds.find(key) != binds.end()) + return false; + + binds[key] = value; + if(updateFile) + Cache::replaceBindsInFile(binds); + return true; + } + + bool Chatbar::removeBind(const std::string &key, bool updateFile) + { + auto it = binds.find(key); + if(it == binds.end()) + return false; + + binds.erase(it); + if(updateFile) + Cache::replaceBindsInFile(binds); + return true; + } + + const unordered_map<string, string>& Chatbar::getBinds() + { + return binds; + } } diff --git a/src/FileUtil.cpp b/src/FileUtil.cpp index 53687dd..c2746ed 100644 --- a/src/FileUtil.cpp +++ b/src/FileUtil.cpp @@ -32,4 +32,26 @@ namespace dchat fclose(file); return { fileData, fileSize }; } + + void fileReplace(const boost::filesystem::path &filepath, const StringView data) + { +#if OS_FAMILY == OS_FAMILY_POSIX + FILE *file = fopen(filepath.string().c_str(), "wb+"); +#else + FILE *file = _wfopen(filepath.wstring().c_str(), L"wb+"); +#endif + if(!file) + { + int error = errno; + string errMsg = "Failed to replace file: "; + errMsg += filepath.string(); + errMsg += ", reason: "; + errMsg += strerror(error); + throw FileException(errMsg); + } + + setbuf(file, NULL); + fwrite(data.data, 1, data.size, file); + fclose(file); + } } diff --git a/src/main.cpp b/src/main.cpp index 014c9ff..59b89a5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -103,6 +103,7 @@ int main(int argc, char **argv) //Video video(500, 500, "https://www.youtube.com/watch?v=bs0-EX9mJmg"); Cache cache; + Cache::loadBindsFromFile(); Channel offlineChannel("Offline"); ChannelSidePanel::addChannel(&offlineChannel); @@ -422,6 +423,87 @@ int main(int argc, char **argv) printf("UI scaling set to %f\n", scaling); }); + Command::add("addbind", [](const vector<string> &args) + { + if(args.size() != 2) + { + string errMsg = "Expected 2 arguments for command addbind, got %u argument("; + errMsg += to_string(args.size()); + errMsg += ")"; + Channel::getCurrent()->addLocalMessage(errMsg, Channel::getCurrent()->getSystemUser()); + return; + } + + string key = ":"; + key += args[0]; + key += ":"; + + if(key.size() > 255) + { + // 253 = bind + two colons + Channel::getCurrent()->addLocalMessage("Bind is too long. Max size is 253 bytes", Channel::getCurrent()->getSystemUser()); + return; + } + + bool bindAdded = Chatbar::addBind(key, args[1]); + if(bindAdded) + Channel::getCurrent()->addLocalMessage("Bind added", Channel::getCurrent()->getSystemUser()); + else + Channel::getCurrent()->addLocalMessage("Bind already exists. Remove it first if you want to replace it", Channel::getCurrent()->getSystemUser()); + }); + + Command::add("removebind", [](const vector<string> &args) + { + if(args.size() != 1) + { + string errMsg = "Expected 1 argument for command removebind, got %u argument("; + errMsg += to_string(args.size()); + errMsg += ")"; + Channel::getCurrent()->addLocalMessage(errMsg, Channel::getCurrent()->getSystemUser()); + return; + } + + string key = ":"; + key += args[0]; + key += ":"; + + if(key.size() > 255) + { + // 253 = bind + two colons + Channel::getCurrent()->addLocalMessage("Bind is too long. Max size is 253 bytes", Channel::getCurrent()->getSystemUser()); + return; + } + + bool bindRemoved = Chatbar::removeBind(key); + if(bindRemoved) + Channel::getCurrent()->addLocalMessage("Bind removed", Channel::getCurrent()->getSystemUser()); + else + Channel::getCurrent()->addLocalMessage("Bind doesn't exist, nothing was removed", Channel::getCurrent()->getSystemUser()); + }); + + Command::add("binds", [](const vector<string> &args) + { + if(args.size() != 0) + { + string errMsg = "Expected 0 arguments for command removebind, got %u argument("; + errMsg += to_string(args.size()); + errMsg += ")"; + Channel::getCurrent()->addLocalMessage(errMsg, Channel::getCurrent()->getSystemUser()); + return; + } + + string msg = "Binds:"; + auto binds = Chatbar::getBinds(); + for(auto &bind : binds) + { + msg += "\n"; + msg += bind.first; + msg += " "; + msg += bind.second; + } + Channel::getCurrent()->addLocalMessage(msg, Channel::getCurrent()->getSystemUser()); + }); + // Get username and id (public key) Command::add("whoami", [¤tUserKeyPair, ¤tUserName](const vector<string> &args) { |