aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2019-01-27 02:09:50 +0100
committerdec05eba <dec05eba@protonmail.com>2020-08-18 23:38:23 +0200
commit6778e3b87cc9a6f5d195a2c80e5b499e3d94558b (patch)
treed37e25d48168465bdf0fb29559fe6e186a15e1d7 /src
parent2446736bc775b22cf5aaae88c2c69c9504e5eb17 (diff)
Add binds to emoji parsing, refactor
Diffstat (limited to 'src')
-rw-r--r--src/Cache.cpp94
-rw-r--r--src/IncomingMessage.cpp (renamed from src/MessageComposer.cpp)10
-rw-r--r--src/OutgoingMessage.cpp136
-rw-r--r--src/Room.cpp4
-rw-r--r--src/Storage.cpp105
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