First implementation for the conversation system (not 100% finished yet)

This commit is contained in:
WolverinDEV
2019-07-19 22:55:03 +02:00
parent dd0eaf33e5
commit e507d1f75d
20 changed files with 1545 additions and 44 deletions
@@ -17,6 +17,7 @@
#include "music/MusicClient.h"
#include "query/QueryClient.h"
#include "../weblist/WebListManager.h"
#include "../manager/ConversationManager.h"
#include <experimental/filesystem>
#include <cstdint>
#include <StringVariable.h>
@@ -175,7 +176,7 @@ CommandResult ConnectedClient::handleCommand(Command &cmd) {
else if (command == "permissionlist") return this->handleCommandPermissionList(cmd);
else if (command == "propertylist") return this->handleCommandPropertyList(cmd);
//Server group
//Server group
else if (command == "servergrouplist") return this->handleCommandServerGroupList(cmd);
else if (command == "servergroupadd") return this->handleCommandServerGroupAdd(cmd);
else if (command == "servergroupcopy") return this->handleCommandServerGroupCopy(cmd);
@@ -190,19 +191,19 @@ CommandResult ConnectedClient::handleCommand(Command &cmd) {
else if (command == "setclientchannelgroup") return this->handleCommandSetClientChannelGroup(cmd);
//Channel basic actions
//Channel basic actions
else if (command == "channelcreate") return this->handleCommandChannelCreate(cmd);
else if (command == "channelmove") return this->handleCommandChannelMove(cmd);
else if (command == "channeledit") return this->handleCommandChannelEdit(cmd);
else if (command == "channeldelete") return this->handleCommandChannelDelete(cmd);
//Find a channel and get informations
//Find a channel and get informations
else if (command == "channelfind") return this->handleCommandChannelFind(cmd);
else if (command == "channelinfo") return this->handleCommandChannelInfo(cmd);
//Channel perm actions
//Channel perm actions
else if (command == "channelpermlist") return this->handleCommandChannelPermList(cmd);
else if (command == "channeladdperm") return this->handleCommandChannelAddPerm(cmd);
else if (command == "channeldelperm") return this->handleCommandChannelDelPerm(cmd);
//Channel group actions
//Channel group actions
else if (command == "channelgroupadd") return this->handleCommandChannelGroupAdd(cmd);
else if (command == "channelgroupcopy") return this->handleCommandChannelGroupCopy(cmd);
else if (command == "channelgrouprename") return this->handleCommandChannelGroupRename(cmd);
@@ -212,16 +213,16 @@ CommandResult ConnectedClient::handleCommand(Command &cmd) {
else if (command == "channelgrouppermlist") return this->handleCommandChannelGroupPermList(cmd);
else if (command == "channelgroupaddperm") return this->handleCommandChannelGroupAddPerm(cmd);
else if (command == "channelgroupdelperm") return this->handleCommandChannelGroupDelPerm(cmd);
//Channel sub/unsubscribe
//Channel sub/unsubscribe
else if (command == "channelsubscribe") return this->handleCommandChannelSubscribe(cmd);
else if (command == "channelsubscribeall") return this->handleCommandChannelSubscribeAll(cmd);
else if (command == "channelunsubscribe") return this->handleCommandChannelUnsubscribe(cmd);
else if (command == "channelunsubscribeall") return this->handleCommandChannelUnsubscribeAll(cmd);
//manager channel permissions
//manager channel permissions
else if (command == "channelclientpermlist") return this->handleCommandChannelClientPermList(cmd);
else if (command == "channelclientaddperm") return this->handleCommandChannelClientAddPerm(cmd);
else if (command == "channelclientdelperm") return this->handleCommandChannelClientDelPerm(cmd);
//Client actions
//Client actions
else if (command == "clientupdate") return this->handleCommandClientUpdate(cmd);
else if (command == "clientmove") return this->handleCommandClientMove(cmd);
else if (command == "clientgetids") return this->handleCommandClientGetIds(cmd);
@@ -237,14 +238,14 @@ CommandResult ConnectedClient::handleCommand(Command &cmd) {
else if (command == "clientaddperm") return this->handleCommandClientAddPerm(cmd);
else if (command == "clientdelperm") return this->handleCommandClientDelPerm(cmd);
else if (command == "clientpermlist") return this->handleCommandClientPermList(cmd);
//File transfare
//File transfare
else if (command == "ftgetfilelist") return this->handleCommandFTGetFileList(cmd);
else if (command == "ftcreatedir") return this->handleCommandFTCreateDir(cmd);
else if (command == "ftdeletefile") return this->handleCommandFTDeleteFile(cmd);
else if (command == "ftinitupload") return this->handleCommandFTInitUpload(cmd);
else if (command == "ftinitdownload") return this->handleCommandFTInitDownload(cmd);
else if (command == "ftgetfileinfo") return this->handleCommandFTGetFileInfo(cmd);
//Banlist
//Banlist
else if (command == "banlist") return this->handleCommandBanList(cmd);
else if (command == "banadd") return this->handleCommandBanAdd(cmd);
else if (command == "banedit") return this->handleCommandBanEdit(cmd);
@@ -252,13 +253,13 @@ CommandResult ConnectedClient::handleCommand(Command &cmd) {
else if (command == "bandel") return this->handleCommandBanDel(cmd);
else if (command == "bandelall") return this->handleCommandBanDelAll(cmd);
else if (command == "bantriggerlist") return this->handleCommandBanTriggerList(cmd);
//Tokens
//Tokens
else if (command == "tokenlist" || command == "privilegekeylist") return this->handleCommandTokenList(cmd);
else if (command == "tokenadd" || command == "privilegekeyadd") return this->handleCommandTokenAdd(cmd);
else if (command == "tokenuse" || command == "privilegekeyuse") return this->handleCommandTokenUse(cmd);
else if (command == "tokendelete" || command == "privilegekeydelete") return this->handleCommandTokenDelete(cmd);
//DB stuff
//DB stuff
else if (command == "clientdblist") return this->handleCommandClientDbList(cmd);
else if (command == "clientdbinfo") return this->handleCommandClientDbInfo(cmd);
else if (command == "clientdbedit") return this->handleCommandClientDBEdit(cmd);
@@ -345,6 +346,8 @@ CommandResult ConnectedClient::handleCommand(Command &cmd) {
else if (command == "playlistsongremove") return this->handleCommandPlaylistSongRemove(cmd);
else if (command == "dummy_ipchange") return this->handleCommandDummy_IpChange(cmd);
else if (command == "conversationhistory") return this->handleCommandConversationHistory(cmd);
else if (command == "conversationfetch") return this->handleCommandConversationFetch(cmd);
if (this->getType() == ClientType::CLIENT_QUERY) return CommandResult::NotImplemented; //Dont log query invalid commands
if (this->getType() == ClientType::CLIENT_TEAMSPEAK)
@@ -1162,8 +1165,8 @@ CommandResult ConnectedClient::handleCommandChannelGroupAddPerm(Command &cmd) {
permission::v2::PermissionUpdateType::set_value,
permission::v2::PermissionUpdateType::do_nothing,
cmd[index]["permnegated"].as<bool>() ? 1 : 0,
cmd[index]["permskip"].as<bool>() ? 1 : 0
cmd[index]["permskip"].as<bool>() ? 1 : 0,
cmd[index]["permnegated"].as<bool>() ? 1 : 0
);
updateList |= permission_is_group_property(permType);
}
@@ -2328,8 +2331,8 @@ CommandResult ConnectedClient::handleCommandChannelAddPerm(Command &cmd) {
permission::v2::PermissionUpdateType::set_value,
permission::v2::PermissionUpdateType::do_nothing,
cmd[index]["permnegated"].as<bool>() ? 1 : 0,
cmd[index]["permskip"].as<bool>() ? 1 : 0
cmd[index]["permskip"].as<bool>() ? 1 : 0,
cmd[index]["permnegated"].as<bool>() ? 1 : 0
);
updateClients |= permission_is_client_property(permType);
update_view |= permType == permission::i_channel_needed_view_power;
@@ -2813,8 +2816,8 @@ CommandResult ConnectedClient::handleCommandServerGroupAddPerm(Command &cmd) {
permission::v2::PermissionUpdateType::set_value,
permission::v2::PermissionUpdateType::do_nothing,
cmd[index]["permnegated"].as<bool>() ? 1 : 0,
cmd[index]["permskip"].as<bool>() ? 1 : 0
cmd[index]["permskip"].as<bool>() ? 1 : 0,
cmd[index]["permnegated"].as<bool>() ? 1 : 0
);
sgroupUpdate |= permission_is_group_property(permType);
checkTp |= permission_is_client_property(permType);
@@ -3210,6 +3213,10 @@ CommandResult ConnectedClient::handleCommandSendTextMessage(Command &cmd) {
if(this->handleTextMessage(ChatMessageMode::TEXTMODE_CHANNEL, cmd["msg"], nullptr)) return CommandResult::Success;
for (auto &cl : this->server->getClientsByChannel(this->currentChannel))
cl->notifyTextMessage(ChatMessageMode::TEXTMODE_CHANNEL, _this.lock(), this->getClientId(), cmd["msg"].string());
auto conversations = this->server->conversation_manager();
auto conversation = conversations->get_or_create(this->currentChannel->channelId());
conversation->register_message(this->getClientDatabaseId(), this->getUid(), this->getDisplayName(), cmd["msg"].string());
} else if (cmd["targetmode"] == ChatMessageMode::TEXTMODE_SERVER) {
CACHED_PERM_CHECK(permission::b_client_server_textmessage_send, 1);
@@ -7200,7 +7207,189 @@ CommandResult ConnectedClient::handleCommandDummy_IpChange(ts::Command &cmd) {
return CommandResult::Success;
}
//conversationhistory cid=1 [cpw=xxx] [timestamp_begin] [timestamp_end (0 := no end)] [message_count (default 25| max 100)] [-merge]
CommandResult ConnectedClient::handleCommandConversationHistory(ts::Command &command) {
CMD_REF_SERVER(ref_server);
CMD_CHK_AND_INC_FLOOD_POINTS(25);
if(!command[0].has("cid") || !command[0]["cid"].castable<ChannelId>())
return {findError("conversation_invalid_id")};
auto conversation_id = command[0]["cid"].as<ChannelId>();
/* test if we have access to the conversation */
{
/* test if we're able to see the channel */
{
shared_lock channel_view_lock(this->channel_lock);
auto channel = this->channel_view()->find_channel(conversation_id);
if(!channel)
return {findError("conversation_invalid_id")};
}
/* test if there is a channel password or join power which denies that we see the conversation */
{
shared_lock channel_view_lock(ref_server->channel_tree_lock);
auto channel = ref_server->getChannelTree()->findChannel(conversation_id);
if(!channel) /* should never happen! */
return {findError("conversation_invalid_id")};
if(!command[0].has("cpw"))
command[0]["cpw"] = "";
if (!channel->passwordMatch(command["cpw"], true))
if (!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_channel_join_ignore_password, 1, channel, true))
return {findError("channel_invalid_password"), "invalid password"};
if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_channel_ignore_join_power, 1, channel, true)) {
CHANNEL_PERMISSION_TEST(permission::i_channel_join_power, permission::i_channel_needed_join_power, channel, false);
}
}
}
auto conversation_manager = ref_server->conversation_manager();
auto conversation = conversation_manager->get(conversation_id);
if(!conversation)
return {ErrorType::DBEmpty};
system_clock::time_point timestamp_begin = system_clock::now();
system_clock::time_point timestamp_end;
size_t message_count = 25;
if(command[0].has("timestamp_begin"))
timestamp_begin = system_clock::time_point{} + milliseconds(command[0]["timestamp_begin"].as<uint64_t>());
if(command[0].has("timestamp_end"))
timestamp_end = system_clock::time_point{} + milliseconds(command[0]["timestamp_end"].as<uint64_t>());
if(command[0].has("message_count"))
message_count = command[0]["message_count"].as<uint64_t>();
if(timestamp_begin < timestamp_end)
return {findError("parameter_invalid")};
if(message_count > 100)
message_count = 100;
auto messages = conversation->message_history(timestamp_begin, message_count + 1, timestamp_end); /* query one more to test for more data */
if(messages.empty())
return {ErrorType::DBEmpty};
bool more_data = messages.size() > message_count;
if(more_data)
messages.pop_back();
Command notify(this->notify_response_command("notifyconversationhistory"));
size_t index = 0;
size_t length = 0;
bool merge = command.hasParm("merge");
for(auto& message : messages) {
if(index == 0)
notify[index]["cid"] = conversation_id;
notify[index]["timestamp"] = duration_cast<milliseconds>(message->message_timestamp.time_since_epoch()).count();
notify[index]["sender_database_id"] = message->sender_database_id;
notify[index]["sender_unique_id"] = message->sender_unique_id;
notify[index]["sender_name"] = message->sender_name;
notify[index]["msg"] = message->message;
length += message->message.size();
length += message->sender_name.size();
length += message->sender_unique_id.size();
if(length > 1024 * 8 || !merge) {
index = 0;
this->sendCommand(notify);
notify = Command{this->notify_response_command("notifyconversationhistory")};
} else
index++;
}
if(index > 0)
this->sendCommand(notify);
if(more_data)
return {findError("conversation_more_data")};
return CommandResult::Success;
}
CommandResult ConnectedClient::handleCommandConversationFetch(ts::Command &cmd) {
CMD_REF_SERVER(ref_server);
CMD_CHK_AND_INC_FLOOD_POINTS(25);
Command result(this->notify_response_command("notifyconversationindex"));
size_t result_index = 0;
auto conversation_manager = ref_server->conversation_manager();
for(size_t index = 0; index < cmd.bulkCount(); index++) {
auto& bulk = cmd[index];
if(!bulk.has("cid") || !bulk["cid"].castable<ChannelId>())
continue;
auto conversation_id = bulk["cid"].as<ChannelId>();
auto& result_bulk = result[result_index++];
result_bulk["cid"] = conversation_id;
/* test if we have access to the conversation */
{
/* test if we're able to see the channel */
{
shared_lock channel_view_lock(this->channel_lock);
auto channel = this->channel_view()->find_channel(conversation_id);
if(!channel) {
auto error = findError("conversation_invalid_id");
result_bulk["error_id"] = error.errorId;
result_bulk["error_msg"] = error.message;
continue;
}
}
/* test if there is a channel password or join power which denies that we see the conversation */
{
shared_lock channel_view_lock(ref_server->channel_tree_lock);
auto channel = ref_server->getChannelTree()->findChannel(conversation_id);
if(!channel) { /* should never happen! */
auto error = findError("conversation_invalid_id");
result_bulk["error_id"] = error.errorId;
result_bulk["error_msg"] = error.message;
continue;
}
if(!bulk.has("cpw"))
bulk["cpw"] = "";
if (!channel->passwordMatch(bulk["cpw"], true))
if (!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_channel_join_ignore_password, 1, channel, true)) {
auto error = findError("channel_invalid_password");
result_bulk["error_id"] = error.errorId;
result_bulk["error_msg"] = error.message;
continue;
}
if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_channel_ignore_join_power, 1, channel, true)) {
auto permission_granted = this->calculate_permission_value(permission::i_channel_join_power, channel->channelId());
if(!channel->permission_granted(permission::i_channel_needed_join_power, permission_granted, false)) {
auto error = findError("server_insufficeient_permissions");
result_bulk["error_id"] = error.errorId;
result_bulk["error_msg"] = error.message;
result_bulk["failed_permid"] = permission::i_channel_join_power;
continue;
}
}
}
}
auto conversation = conversation_manager->get(conversation_id);
if(conversation)
result_bulk["timestamp"] = duration_cast<milliseconds>(conversation->last_message().time_since_epoch()).count();
else
result_bulk["timestamp"] = 0;
}
if(result_index == 0)
return {ErrorType::DBEmpty};
this->sendCommand(result);
return CommandResult::Success;
}