aboutsummaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp361
1 files changed, 349 insertions, 12 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 0836278..efb354f 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -11,6 +11,9 @@
#include "../include/GlobalContextMenu.hpp"
#include "../include/StringUtils.hpp"
#include "../include/ImagePreview.hpp"
+#include "../include/Rpc.hpp"
+#include <msgpack.hpp>
+#include <sstream>
#include <string>
#include <SFML/Graphics.hpp>
#include <cstring>
@@ -94,6 +97,13 @@ static void channelChangeChannelName(Channel *channel, const StringView data, co
fprintf(stderr, "Channel change name: user with public key %s not found in channel %s\n", userPublicKey.toString().c_str(), channel->getName().c_str());
return;
}
+
+ int userPermissionLevel = channel->getUserLowestPermissionLevel(user);
+ if(userPermissionLevel != odhtdb::PERMISSION_LEVEL_ADMIN)
+ {
+ fprintf(stderr, "Channel change name: attempted by user %s who is not an admin\n", user->getName().c_str());
+ return;
+ }
sibs::SafeDeserializer deserializer((const u8*)data.data, data.size);
u16 channelNameLength = deserializer.extract<u16>();
@@ -107,6 +117,40 @@ static void channelChangeChannelName(Channel *channel, const StringView data, co
// We dont care if there is more data to read (malicious packet), we already got all the data we need
}
+static void channelAddDiscordMessage(Channel *channel, const StringView data, const odhtdb::Signature::PublicKey &userPublicKey, u64 timestamp, const odhtdb::Hash &requestHash)
+{
+ auto bridgeOwner = channel->getUserByPublicKey(userPublicKey);
+ if(!bridgeOwner)
+ {
+ fprintf(stderr, "Channel add discord message: user with public key %s not found in channel %s\n", userPublicKey.toString().c_str(), channel->getName().c_str());
+ return;
+ }
+
+ int userPermissionLevel = channel->getUserLowestPermissionLevel(bridgeOwner);
+ if(userPermissionLevel != odhtdb::PERMISSION_LEVEL_ADMIN)
+ {
+ fprintf(stderr, "Channel add discord message: attempted by user %s who is not an admin\n", bridgeOwner->getName().c_str());
+ return;
+ }
+
+ sibs::SafeDeserializer deserializer((const u8*)data.data, data.size);
+ u64 discordUserId = deserializer.extract<u64>();
+ u8 discordNameLength = deserializer.extract<u8>();
+ if(discordNameLength == 0) return;
+
+ string discordUserName;
+ discordUserName.resize(discordNameLength);
+ deserializer.extract((u8*)&discordUserName[0], discordNameLength);
+
+ usize msgSize = deserializer.getSize();
+ if(msgSize == 0) return;
+ string msg(deserializer.getBuffer(), deserializer.getBuffer() + deserializer.getSize());
+
+ auto timestampSeconds = ntp::NtpTimestamp::fromCombined(timestamp).seconds;
+ channel->addLocalDiscordMessage(discordUserName, discordUserId, msg, bridgeOwner, timestampSeconds, requestHash);
+ // We dont care if there is more data to read (malicious packet), we already got all the data we need
+}
+
static void channelAddStoredMessage(Channel *channel, const odhtdb::Hash &requestHash, const odhtdb::Signature::PublicKey &creatorPublicKey, const StringView decryptedObject, u64 timestamp, bool loadedFromCache)
{
User *user = channel->getUserByPublicKey(creatorPublicKey);
@@ -187,6 +231,18 @@ static void channelAddStoredMessage(Channel *channel, const odhtdb::Hash &reques
}
break;
}
+ case ChannelDataType::ADD_DISCORD_MESSAGE:
+ {
+ try
+ {
+ channelAddDiscordMessage(channel, decryptedData, creatorPublicKey, timestamp, requestHash);
+ }
+ catch(sibs::DeserializeException &e)
+ {
+ fprintf(stderr, "Failed to deserialize channel add discord message\n");
+ }
+ break;
+ }
default:
fprintf(stderr, "Got unexpected channel data type: %u\n", channelDataType);
break;
@@ -207,7 +263,7 @@ int main(int argc, char **argv)
printf("Resource path set to: %s\n", resourcesPath.string().c_str());
}
else
- printf("Resource directory not defined, using currently directory");
+ printf("Resource directory not defined, using currently directory\n");
const sf::Int64 FRAMERATE_FOCUSED = 144;
const sf::Int64 FRAMERATE_NOT_FOCUSED = 10;
@@ -239,6 +295,9 @@ int main(int argc, char **argv)
odhtdb::Database *database = nullptr;
odhtdb::DatabaseCallbackFuncs callbackFuncs;
+
+ using LocalUserMessageCallback = function<void(const odhtdb::DatabaseAddNodeRequest &request)>;
+ LocalUserMessageCallback onMessageByLocalUser = nullptr;
callbackFuncs.createNodeCallbackFunc = [&waitingToJoinChannels, &database, &channels, &channelMessageMutex, &waitingToJoin, &localNodeUsers, &lastFocusedTimer](const odhtdb::DatabaseCreateNodeRequest &request)
{
@@ -280,7 +339,7 @@ int main(int argc, char **argv)
}
};
- callbackFuncs.addNodeCallbackFunc = [&channels, &channelMessageMutex, &lastFocusedTimer](const odhtdb::DatabaseAddNodeRequest &request)
+ callbackFuncs.addNodeCallbackFunc = [&channels, &channelMessageMutex, &lastFocusedTimer, &onMessageByLocalUser](const odhtdb::DatabaseAddNodeRequest &request)
{
lock_guard<recursive_mutex> lock(channelMessageMutex);
//printf("Add node callback func %s\n", request.requestHash->toString().c_str());
@@ -291,6 +350,12 @@ int main(int argc, char **argv)
channelAddStoredMessage(channel, *request.requestHash, *request.creatorPublicKey, StringView((const char*)request.decryptedData.data, request.decryptedData.size), request.timestamp, request.loadedFromCache);
if(channel == Channel::getCurrent())
lastFocusedTimer.restart();
+
+ if(!request.loadedFromCache && *request.creatorPublicKey == static_cast<OnlineLocalUser*>(channel->getLocalUser())->getPublicKey())
+ {
+ if(onMessageByLocalUser)
+ onMessageByLocalUser(request);
+ }
return;
}
}
@@ -808,7 +873,7 @@ int main(int argc, char **argv)
});
// Change name of the current channel
- Command::add("channelname", [&loggedIn, &offlineChannel, addSystemMessage](const vector<string> &args)
+ Command::add("channelname", [&offlineChannel, addSystemMessage](const vector<string> &args)
{
if(args.size() != 1)
{
@@ -818,16 +883,17 @@ int main(int argc, char **argv)
addSystemMessage(errMsg);
return;
}
-
- if(!loggedIn)
+
+ Channel *currentChannel = Channel::getCurrent();
+ if(currentChannel == &offlineChannel)
{
- addSystemMessage("You need to be logged in to change channel name");
+ addSystemMessage("You need to be in a channel to change channel name");
return;
}
- if(Channel::getCurrent() == &offlineChannel)
+ if(!currentChannel->getLocalUser()->isOnlineUser())
{
- addSystemMessage("You need to be in a channel to change channel name");
+ addSystemMessage("You need to be logged in to change channel name");
return;
}
@@ -836,8 +902,15 @@ int main(int argc, char **argv)
addSystemMessage("Channel name has to be between 1 and 32 bytes long");
return;
}
+
+ int localUserPermissionLevel = currentChannel->getUserLowestPermissionLevel(static_cast<OnlineLocalUser*>(currentChannel->getLocalUser()));
+ if(localUserPermissionLevel != odhtdb::PERMISSION_LEVEL_ADMIN)
+ {
+ addSystemMessage("You need to be admin to change channel name");
+ return;
+ }
- Channel::getCurrent()->setName(args[0]);
+ currentChannel->setName(args[0]);
string msg = "Channel name has been changed to ";
msg += args[0];
addSystemMessage(msg);
@@ -855,10 +928,268 @@ int main(int argc, char **argv)
commandsMsg += commandIt.first;
}
addSystemMessage(commandsMsg);
+
+ odhtdb::MapHash<u64> myDiscordIdsByChannel;
+
+ bool running = true;
+ thread rpcThread([&running, &onMessageByLocalUser, &channels, &lastFocusedTimer, &myDiscordIdsByChannel]()
+ {
+ Rpc rpc(5555);
+ mutex messageMutex;
+ vector<msgpack::sbuffer> messagesToSend;
+ onMessageByLocalUser = [&messagesToSend, &messageMutex](const odhtdb::DatabaseAddNodeRequest &request)
+ {
+ lock_guard<mutex> lock(messageMutex);
+ auto channelDataType = (ChannelDataType)static_cast<const char*>(request.decryptedData.data)[0];
+ usize size = request.decryptedData.size - 1;
+ const char *data = (const char*)request.decryptedData.data + 1;
+ const char *action = nullptr;
+ if(channelDataType == ChannelDataType::ADD_MESSAGE)
+ action = "addMessage";
+
+ if(!action) return;
+ vector<string> msg = { action, string(data, data + size), request.nodeHash->toString() };
+ msgpack::sbuffer buffer;
+ msgpack::pack(buffer, msg);
+ messagesToSend.emplace_back(move(buffer));
+ };
+
+ while(running)
+ {
+ rpc.recv([&channels, &lastFocusedTimer, &myDiscordIdsByChannel](zmq::message_t *message)
+ {
+ try
+ {
+ msgpack::object_handle oh = msgpack::unpack((const char*)message->data(), message->size());
+ auto deserialized = oh.get();
+ vector<string> msg;
+ deserialized.convert(msg);
+ if(msg.size() < 2)
+ {
+ fprintf(stderr, "Rpc receive, data length expected to be at least 2, was %u\n", msg.size());
+ return;
+ }
+ auto &action = msg[0];
+
+ string dchatChannelIdRaw = odhtdb::hex2bin(msg[1].c_str(), msg[1].size());
+ odhtdb::Hash dchatChannelId;
+ memcpy(dchatChannelId.getData(), dchatChannelIdRaw.data(), dchatChannelIdRaw.size());
+ Channel *bridgedChannel = nullptr;
+ for(Channel *channel : channels)
+ {
+ if(*channel->getNodeInfo().getRequestHash() == dchatChannelId)
+ {
+ bridgedChannel = channel;
+ break;
+ }
+ }
+
+ if(!bridgedChannel)
+ {
+ fprintf(stderr, "Rcp addMessage, invalid dchat channel %s\n", msg[1].c_str());
+ return;
+ }
+
+ if(bridgedChannel == Channel::getCurrent())
+ lastFocusedTimer.restart();
+
+ fprintf(stderr, "Received rpc, action: %s\n", action.c_str());
+ if(action == "addMessage")
+ {
+ if((msg.size() - 2) % 4 != 0)
+ {
+ fprintf(stderr, "Rpc addMessage, request was malformed\n");
+ return;
+ }
+
+ for(size_t i = 2; i < msg.size(); i += 4)
+ {
+ auto &content = msg[i];
+ auto &discordUserId = msg[i + 1];
+ u64 discordUserIdNumber = 0;
+ auto &discordUserName = msg[i + 2];
+ auto &messageTimestampMillisec = msg[i + 3];
+ u64 messageTimestampSecondsNumber = 0;
+
+ try
+ {
+ discordUserIdNumber = stoull(discordUserId);
+ }
+ catch(...)
+ {
+ fprintf(stderr, "Rpc receive, failed to convert discord id to uint64_t: %s\n", discordUserId.c_str());
+ return;
+ }
+
+ try
+ {
+ messageTimestampSecondsNumber = stoull(messageTimestampMillisec) / 1000;
+ }
+ catch(...)
+ {
+ fprintf(stderr, "Rpc receive, failed to convert discord message timestamp to uint64_t: %s\n", messageTimestampMillisec.c_str());
+ return;
+ }
+
+ auto myDiscordIdIt = myDiscordIdsByChannel.find(dchatChannelId);
+ if(myDiscordIdIt != myDiscordIdsByChannel.end() && myDiscordIdIt->second == discordUserIdNumber)
+ {
+ auto &channelMessages = bridgedChannel->getMessageBoard().getMessages();
+ Message *myLatestMessage = nullptr;
+ for(auto it = channelMessages.rbegin(), end = channelMessages.rend(); it != end; ++it)
+ {
+ if((*it)->user == bridgedChannel->getLocalUser())
+ {
+ myLatestMessage = *it;
+ break;
+ }
+ }
+
+ if(myLatestMessage && (i64)messageTimestampSecondsNumber - (i64)myLatestMessage->timestampSeconds <= 3)
+ {
+ return;
+ /*
+ auto myMessageUtf8 = myLatestMessage->text.getString().toUtf8();
+ odhtdb::Hash myMessageHash(myMessageUtf8.data(), myMessageUtf8.size());
+ odhtdb::Hash myDiscordMessageHash(content.data(), content.size());
+ if(myMessageHash == myDiscordMessageHash)
+ return;
+ */
+ }
+ }
+
+ bridgedChannel->addLocalDiscordMessage(discordUserName, discordUserIdNumber, content, bridgedChannel->getLocalUser(), messageTimestampSecondsNumber, odhtdb::Hash(messageTimestampMillisec.c_str(), messageTimestampMillisec.size()));
+ }
+ }
+ else if(action == "addUser")
+ {
+ if((msg.size() - 2) % 4 != 0)
+ {
+ fprintf(stderr, "Rpc addUser, request was malformed\n");
+ return;
+ }
+
+ for(size_t i = 2; i < msg.size(); i += 4)
+ {
+ auto &discordUsername = msg[i];
+ auto &discordUserId = msg[i + 1];
+ auto &userStatus = msg[i + 2];
+ auto &avatarURL = msg[i + 3];
+
+ try
+ {
+ u64 discordUserIdNumber = stoull(discordUserId);
+ bool online = (userStatus != "offline");
+ printf("Rpc, adding user %s with status %s\n", discordUsername.c_str(), userStatus.c_str());
+ DiscordServiceUser *discordUser = bridgedChannel->getDiscordService()->getUserById(discordUserIdNumber);
+ if(discordUser)
+ {
+ discordUser->connected = online;
+ }
+ else
+ {
+ discordUser = new DiscordServiceUser(discordUsername, discordUserIdNumber, online);
+ bridgedChannel->getDiscordService()->addUser(discordUser);
+ }
+ discordUser->avatarUrl = avatarURL;
+ }
+ catch(...)
+ {
+ fprintf(stderr, "Warning: Rpc receive, failed to convert discord id to uint64_t: %s\n", discordUserId.c_str());
+ // Ignore for now.. should we really handle this error other than showing warning?
+ }
+ }
+ }
+ else if(action == "removeUser")
+ {
+ for(size_t i = 2; i < msg.size(); ++i)
+ {
+ auto &discordUserId = msg[i];
+ try
+ {
+ u64 discordUserIdNumber = stoull(discordUserId);
+ bridgedChannel->getDiscordService()->removeUser(discordUserIdNumber);
+ }
+ catch(...)
+ {
+ fprintf(stderr, "Warning: Rpc receive, failed to convert discord id to uint64_t: %s\n", discordUserId.c_str());
+ // Ignore for now.. should we really handle this error other than showing warning?
+ }
+ }
+ }
+ else if(action == "statusChange")
+ {
+ if((msg.size() - 2) != 2)
+ {
+ fprintf(stderr, "Rpc statusChange, request was malformed\n");
+ return;
+ }
+
+ auto &discordUserId = msg[2];
+ auto &userStatus = msg[3];
+
+ try
+ {
+ u64 discordUserIdNumber = stoull(discordUserId);
+ DiscordServiceUser *discordUser = bridgedChannel->getDiscordService()->getUserById(discordUserIdNumber);
+ if(discordUser)
+ {
+ discordUser->connected = (userStatus != "offline");
+ printf("Rcp statusChange, changed user %s (%s) status to %s\n", discordUserId.c_str(), discordUser->getName().c_str(), userStatus.c_str());
+ }
+ }
+ catch(...)
+ {
+ fprintf(stderr, "Warning: Rpc receive, failed to convert discord id to uint64_t: %s\n", discordUserId.c_str());
+ // Ignore for now.. should we really handle this error other than showing warning?
+ }
+ }
+ else if(action == "addMe")
+ {
+ if((msg.size() - 2) != 1)
+ {
+ fprintf(stderr, "Rpc addMe, request was malformed\n");
+ return;
+ }
+
+ auto &myDiscordId = msg[2];
+ try
+ {
+ u64 myDiscordIdNumber = stoull(myDiscordId);
+ myDiscordIdsByChannel[dchatChannelId] = myDiscordIdNumber;
+ }
+ catch(...)
+ {
+ fprintf(stderr, "Warning: Rpc receive, failed to convert discord id to uint64_t: %s\n", myDiscordId.c_str());
+ // Ignore for now.. should we really handle this error other than showing warning?
+ }
+ }
+ else
+ {
+ fprintf(stderr, "Rcp received unknown action %s\n", action.c_str());
+ }
+ }
+ catch(msgpack::type_error &e)
+ {
+ fprintf(stderr, "Failed to deserialize received rpc, error: %s\n", e.what());
+ }
+ });
+ {
+ lock_guard<mutex> lock(messageMutex);
+ for(auto &messageToSend : messagesToSend)
+ {
+ fprintf(stderr, "Rpc, sending message\n");
+ rpc.send(messageToSend.data(), messageToSend.size());
+ }
+ messagesToSend.clear();
+ }
+ this_thread::sleep_for(chrono::milliseconds(50));
+ }
+ });
sf::Clock frameTimer;
- while (window.isOpen())
+ while (running)
{
frameTimer.restart();
Channel *currentChannel = Channel::getCurrent();
@@ -867,11 +1198,14 @@ int main(int argc, char **argv)
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
+ {
window.close();
+ running = false;
+ }
else if(event.type == sf::Event::Resized)
{
sf::FloatRect viewRect(0.0f, 0.0f, event.size.width, event.size.height);
- /* // TODO: Use xlib to set window minimum size instead
+ /* // TODO: Use xlib/xcb to set window minimum size instead
const int minWidth = 800;
if(event.size.width < minWidth)
{
@@ -916,7 +1250,7 @@ int main(int argc, char **argv)
channel->update();
}
- if(lastFocusedTimer.getElapsedTime().asMilliseconds() > 5000)
+ if((!windowFocused || !focused) && lastFocusedTimer.getElapsedTime().asMilliseconds() > 5000)
{
this_thread::sleep_for(chrono::milliseconds(250));
continue;
@@ -948,6 +1282,9 @@ int main(int argc, char **argv)
//video.draw(window);
window.display();
}
+
+ onMessageByLocalUser = nullptr;
+ rpcThread.join();
for(Channel *channel : channels)
{