diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Cache.cpp | 94 | ||||
-rw-r--r-- | src/IncomingMessage.cpp (renamed from src/MessageComposer.cpp) | 10 | ||||
-rw-r--r-- | src/OutgoingMessage.cpp | 136 | ||||
-rw-r--r-- | src/Room.cpp | 4 | ||||
-rw-r--r-- | src/Storage.cpp | 105 |
5 files changed, 249 insertions, 100 deletions
diff --git a/src/Cache.cpp b/src/Cache.cpp index 84bee97..0d5dd05 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -2,6 +2,7 @@ #include "../include/env.hpp" #include "../include/dchat/FileUtil.hpp" #include "../include/dchat/Gif.hpp" +#include "../include/dchat/Storage.hpp" #include <boost/filesystem/convenience.hpp> #include <process.hpp> #include <odhtdb/Hash.hpp> @@ -11,7 +12,6 @@ #include <gd.h> #if OS_FAMILY == OS_FAMILY_POSIX -#include <pwd.h> #define toNativeString(str) str #else #include <string> @@ -32,98 +32,6 @@ using namespace TinyProcessLib; namespace dchat { const i64 CONTENT_NOT_VISIBLE_AGE_MS = 30000; // Delete content from cache after a specified amount of time if the content is not visible on the screen - - static boost::filesystem::path getHomeDir() - { - #if OS_FAMILY == OS_FAMILY_POSIX - const char *homeDir = getenv("HOME"); - if(!homeDir) - { - passwd *pw = getpwuid(getuid()); - homeDir = pw->pw_dir; - } - return boost::filesystem::path(homeDir); - #elif OS_FAMILY == OS_FAMILY_WINDOWS - BOOL ret; - HANDLE hToken; - std::wstring homeDir; - DWORD homeDirLen = MAX_PATH; - homeDir.resize(homeDirLen); - - if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken)) - throw std::runtime_error("Failed to open process token"); - - if (!GetUserProfileDirectory(hToken, &homeDir[0], &homeDirLen)) - { - CloseHandle(hToken); - throw std::runtime_error("Failed to get home directory"); - } - - CloseHandle(hToken); - homeDir.resize(wcslen(homeDir.c_str())); - return boost::filesystem::path(homeDir); - #endif - } - - boost::filesystem::path Cache::getDchatDir() - { - boost::filesystem::path dchatHomeDir = getHomeDir() / ".local" / "share" / "dchat"; - boost::filesystem::create_directories(dchatHomeDir); - return dchatHomeDir; - } - - boost::filesystem::path Cache::getImagesDir() - { - boost::filesystem::path imagesDir = getDchatDir() / "images"; - boost::filesystem::create_directories(imagesDir); - return imagesDir; - } - - void Cache::loadBindsFromFile(LoadBindsCallbackFunc callbackFunc) - { - assert(callbackFunc); - 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); - - callbackFunc(key, value); - } - } - 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())); - } static bool downscaleImage(const boost::filesystem::path &filepath, void *data, const int size, const int newWidth, const int newHeight) { diff --git a/src/MessageComposer.cpp b/src/IncomingMessage.cpp index 71fa62e..e003a22 100644 --- a/src/MessageComposer.cpp +++ b/src/IncomingMessage.cpp @@ -1,4 +1,4 @@ -#include "../include/dchat/MessageComposer.hpp" +#include "../include/dchat/IncomingMessage.hpp" #include <assert.h> #include <string.h> @@ -131,7 +131,7 @@ namespace dchat Range typeDataRange; }; - void compose(const char *text, usize size, std::function<void(MessagePart)> callbackFunc) + void parseIncomingMessage(const char *text, usize size, std::function<void(IncomingMessagePart)> callbackFunc) { Tokenizer tokenizer(text, size); Token token = tokenizer.next(); @@ -139,19 +139,19 @@ namespace dchat { if(token == Token::TEXT) { - callbackFunc(MessagePart { MessagePart::Type::TEXT, tokenizer.identifierRange }); + callbackFunc(IncomingMessagePart { IncomingMessagePart::Type::TEXT, tokenizer.identifierRange }); token = tokenizer.next(); } else if(token == Token::TYPE) { if(tokenizer.typeRange.length() == 5 && memcmp(text + tokenizer.typeRange.start, "emoji", 5) == 0) { - callbackFunc(MessagePart { MessagePart::Type::EMOJI, tokenizer.typeDataRange }); + callbackFunc(IncomingMessagePart { IncomingMessagePart::Type::EMOJI, tokenizer.typeDataRange }); } else { Range typeToTextRange = { tokenizer.typeRange.start - 1, tokenizer.typeDataRange.end + 1 }; - callbackFunc(MessagePart{ MessagePart::Type::TEXT, typeToTextRange }); + callbackFunc(IncomingMessagePart{ IncomingMessagePart::Type::TEXT, typeToTextRange }); } token = tokenizer.next(); } diff --git a/src/OutgoingMessage.cpp b/src/OutgoingMessage.cpp new file mode 100644 index 0000000..e774940 --- /dev/null +++ b/src/OutgoingMessage.cpp @@ -0,0 +1,136 @@ +#include "../include/dchat/OutgoingMessage.hpp" +#include <assert.h> + +namespace dchat +{ + namespace OutgoingMessage + { + enum class Token + { + NONE, + END_OF_FILE, + + TEXT, + BIND + }; + + struct Tokenizer + { + Tokenizer(const char *_text, usize _size, const EmojiBindMap *_emojiBindMap) + { + assert(_text); + assert(_emojiBindMap); + text = _text; + size = _size; + index = 0; + emoji = nullptr; + emojiBindMap = _emojiBindMap; + textRange = { 0, 0 }; + } + + // returns -1 if character can't be found in the string + usize find(const char *str, usize size, char c) const + { + for(usize i = 0; i < size; ++i) + { + if(str[i] == c) + return i; + } + return -1; + } + + // Return nullptr if bind is not found + const std::string* getBindEmoji(const char *text, usize size) const + { + // TODO: unecessary conversion to string, convert emojibindmap to const char* and uses custom hasher + auto it = emojiBindMap->find(std::string(text, size)); + if(it != emojiBindMap->end()) + return &it->second; + return nullptr; + } + + Token next() + { + if(index >= size) + return Token::END_OF_FILE; + + char c = getChar(); + usize start = index; + ++index; + if(c == ':') + { + while(index < size) + { + c = getChar(); + ++index; + if(c == ':') + { + usize end = index - 1; + const std::string *_emoji = getBindEmoji(text + start + 1, end - (start + 1)); + if(_emoji) + { + emoji = _emoji; + return Token::BIND; + } + break; + } + } + + textRange.start = start; + textRange.end = index; + return Token::TEXT; + } + else + { + while(index < size) + { + c = getChar(); + if(c == ':') + break; + ++index; + } + + textRange.start = start; + textRange.end = index; + return Token::TEXT; + } + + assert(false); + return Token::NONE; + } + + char getChar() const + { + assert(index < size); + return text[index]; + } + + const char *text; + usize size; + usize index; + const std::string *emoji; + const EmojiBindMap *emojiBindMap; + + Range textRange; + }; + } + + void parseOutgoingMessage(const char *text, usize size, const EmojiBindMap &emojiBindMap, std::function<void(OutgoingMessagePart)> callbackFunc) + { + OutgoingMessage::Tokenizer tokenizer(text, size, &emojiBindMap); + OutgoingMessage::Token token = tokenizer.next(); + while(token != OutgoingMessage::Token::END_OF_FILE) + { + if(token == OutgoingMessage::Token::TEXT) + { + callbackFunc(OutgoingMessagePart { OutgoingMessagePart::Type::TEXT, tokenizer.textRange }); + token = tokenizer.next(); + } + else if(token == OutgoingMessage::Token::BIND) + { + callbackFunc(OutgoingMessagePart { OutgoingMessagePart::Type::EMOJI, tokenizer.emoji }); + token = tokenizer.next(); + } + } + } +}
\ No newline at end of file diff --git a/src/Room.cpp b/src/Room.cpp index c7135da..b526833 100644 --- a/src/Room.cpp +++ b/src/Room.cpp @@ -1,5 +1,5 @@ #include "../include/dchat/Room.hpp" -#include "../include/dchat/Cache.hpp" +#include "../include/dchat/Storage.hpp" #include "../include/dchat/FileUtil.hpp" #include "../include/dchat/RoomDataType.hpp" #include <odhtdb/Database.hpp> @@ -203,7 +203,7 @@ namespace dchat databaseCallbackFuncs.createNodeCallbackFunc = std::bind(&Rooms::createNodeCallbackFunc, this, std::placeholders::_1); databaseCallbackFuncs.addNodeCallbackFunc = std::bind(&Rooms::addNodeCallbackFunc, this, std::placeholders::_1); databaseCallbackFuncs.addUserCallbackFunc = std::bind(&Rooms::addUserCallbackFunc, this, std::placeholders::_1); - database = odhtdb::Database::connect(address, port, Cache::getDchatDir(), databaseCallbackFuncs).get(); + database = odhtdb::Database::connect(address, port, getDchatDir(), databaseCallbackFuncs).get(); } void Rooms::createNodeCallbackFunc(const odhtdb::DatabaseCreateNodeRequest &request) diff --git a/src/Storage.cpp b/src/Storage.cpp new file mode 100644 index 0000000..a0cc891 --- /dev/null +++ b/src/Storage.cpp @@ -0,0 +1,105 @@ +#include "../include/dchat/Storage.hpp" +#include "../include/dchat/env.hpp" +#include "../include/dchat/FileUtil.hpp" +#include <boost/filesystem/convenience.hpp> +#include <sibs/SafeSerializer.hpp> +#include <sibs/SafeDeserializer.hpp> + +#if OS_FAMILY == OS_FAMILY_POSIX +#include <pwd.h> +#endif + +namespace dchat +{ + boost::filesystem::path getHomeDir() + { + #if OS_FAMILY == OS_FAMILY_POSIX + const char *homeDir = getenv("HOME"); + if(!homeDir) + { + passwd *pw = getpwuid(getuid()); + homeDir = pw->pw_dir; + } + return boost::filesystem::path(homeDir); + #elif OS_FAMILY == OS_FAMILY_WINDOWS + BOOL ret; + HANDLE hToken; + std::wstring homeDir; + DWORD homeDirLen = MAX_PATH; + homeDir.resize(homeDirLen); + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken)) + throw std::runtime_error("Failed to open process token"); + + if (!GetUserProfileDirectory(hToken, &homeDir[0], &homeDirLen)) + { + CloseHandle(hToken); + throw std::runtime_error("Failed to get home directory"); + } + + CloseHandle(hToken); + homeDir.resize(wcslen(homeDir.c_str())); + return boost::filesystem::path(homeDir); + #endif + } + + boost::filesystem::path getDchatDir() + { + boost::filesystem::path dchatHomeDir = getHomeDir() / ".local" / "share" / "dchat"; + boost::filesystem::create_directories(dchatHomeDir); + return dchatHomeDir; + } + + boost::filesystem::path getImagesDir() + { + boost::filesystem::path imagesDir = getDchatDir() / "images"; + boost::filesystem::create_directories(imagesDir); + return imagesDir; + } + + void loadBindsFromFile(LoadBindsCallbackFunc callbackFunc) + { + assert(callbackFunc); + StringView fileContent; + try + { + fileContent = getFileContent(getDchatDir() / "binds"); + sibs::SafeDeserializer deserializer((const u8*)fileContent.data, fileContent.size); + + while(!deserializer.empty()) + { + u8 keySize = deserializer.extract<u8>(); + std::string key; + key.resize(keySize); + deserializer.extract((u8*)&key[0], keySize); + + u8 valueSize = deserializer.extract<u8>(); + std::string value; + value.resize(valueSize); + deserializer.extract((u8*)&value[0], valueSize); + + callbackFunc(key, value); + } + } + catch(FileException &e) + { + fprintf(stderr, "Failed to read binds from file, reason: %s\n", e.what()); + } + + delete[] fileContent.data; + } + + void replaceBindsInFile(const std::unordered_map<std::string, std::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())); + } +}
\ No newline at end of file |