Some more work for the new group manager

This commit is contained in:
WolverinDEV
2021-03-07 19:17:20 +01:00
parent 449df23a4b
commit 2d0b9da08d
19 changed files with 956 additions and 834 deletions
+6 -6
View File
@@ -5,17 +5,17 @@
namespace ts::server::groups {
enum GroupType {
GROUP_TYPE_QUERY,
GROUP_TYPE_TEMPLATE,
GROUP_TYPE_NORMAL,
GROUP_TYPE_TEMPLATE = 0x00,
GROUP_TYPE_NORMAL = 0x01,
GROUP_TYPE_QUERY = 0x02,
GROUP_TYPE_UNKNOWN = 0xFF
};
enum GroupNameMode {
GROUP_NAME_MODE_HIDDEN,
GROUP_NAME_MODE_BEFORE,
GROUP_NAME_MODE_BEHIND
GROUP_NAME_MODE_HIDDEN = 0x00,
GROUP_NAME_MODE_BEFORE = 0x01,
GROUP_NAME_MODE_BEHIND = 0x02
};
typedef uint32_t GroupSortId;
+93 -8
View File
@@ -4,6 +4,7 @@
#include <log/LogUtils.h>
#include "./GroupAssignmentManager.h"
#include "./GroupManager.h"
#include "BasicChannel.h"
using namespace ts::server::groups;
@@ -217,7 +218,7 @@ std::vector<ts::GroupId> GroupAssignmentManager::server_groups_of_client(ts::ser
return result;
}
std::vector<ChannelGroupAssignment> GroupAssignmentManager::channel_groups_of_client(GroupAssignmentCalculateMode mode, ClientDbId cldbid) {
std::vector<ChannelGroupAssignment> GroupAssignmentManager::exact_channel_groups_of_client(GroupAssignmentCalculateMode mode, ClientDbId cldbid) {
std::vector<ChannelGroupAssignment> result{};
bool cache_found{false};
{
@@ -262,7 +263,7 @@ std::vector<ChannelGroupAssignment> GroupAssignmentManager::channel_groups_of_cl
if(mode == GroupAssignmentCalculateMode::GLOBAL) {
if(auto parent = this->manager_->parent_manager(); parent) {
auto parent_groups = parent->assignments().channel_groups_of_client(mode, cldbid);
auto parent_groups = parent->assignments().exact_channel_groups_of_client(mode, cldbid);
result.reserve(result.size() + parent_groups.size());
result.insert(result.begin(), parent_groups.begin(), parent_groups.end());
}
@@ -271,10 +272,10 @@ std::vector<ChannelGroupAssignment> GroupAssignmentManager::channel_groups_of_cl
return result;
}
std::optional<ChannelGroupAssignment> GroupAssignmentManager::channel_group_of_client(GroupAssignmentCalculateMode mode,
ClientDbId client_database_id, ChannelId channel_id) {
std::optional<ChannelGroupAssignment> GroupAssignmentManager::exact_channel_group_of_client(GroupAssignmentCalculateMode mode,
ClientDbId client_database_id, ChannelId channel_id) {
/* TODO: Improve performance by not querying all groups */
auto assignments = this->channel_groups_of_client(mode, client_database_id);
auto assignments = this->exact_channel_groups_of_client(mode, client_database_id);
for(const auto& assignment : assignments) {
if(assignment.channel_id != channel_id) {
continue;
@@ -286,6 +287,29 @@ std::optional<ChannelGroupAssignment> GroupAssignmentManager::channel_group_of_c
return std::nullopt;
}
std::optional<ts::GroupId> GroupAssignmentManager::calculate_channel_group_of_client(GroupAssignmentCalculateMode mode,
ClientDbId client_database_id,
std::shared_ptr<BasicChannel> &channel) {
auto assignments = this->exact_channel_groups_of_client(mode, client_database_id);
while(channel) {
for(const auto& assignment : assignments) {
if(assignment.channel_id != channel->channelId()) {
continue;
}
return std::make_optional(assignment.group_id);
}
if(permission::v2::permission_granted(1, channel->permissions()->permission_value_flagged(permission::b_channel_group_inheritance_end))) {
break;
}
channel = channel->parent();
}
return std::nullopt;
}
std::deque<ts::ClientDbId> GroupAssignmentManager::server_group_clients(GroupId group_id) {
std::deque<ts::ClientDbId> result{};
if constexpr(kCacheAllClients) {
@@ -330,6 +354,59 @@ std::deque<ts::ClientDbId> GroupAssignmentManager::server_group_clients(GroupId
return result;
}
std::deque<std::tuple<ts::GroupId, ts::ChannelId, ts::ClientDbId>> GroupAssignmentManager::channel_group_list(
GroupId group_id,
ChannelId channel_id,
ClientDbId client_database_id
) {
std::string sql_query{};
sql_query += "SELECT `groupId`, `cldbid`, `channelId` FROM `assignedGroups` WHERE `serverId` = :sid";
if(group_id > 0) {
sql_query += " AND `groupId` = :groupId";
}
if(channel_id > 0) {
sql_query += " AND `channelId` = :cid";
}
if(client_database_id > 0) {
sql_query += " AND `cldbid` = :cldbid";
}
sql::command sql{this->sql_manager(), sql_query};
sql.value(":groupId", group_id);
sql.value(":cid", channel_id);
sql.value(":cldbid", client_database_id);
std::deque<std::tuple<ts::GroupId, ts::ChannelId, ts::ClientDbId>> result{};
LOG_SQL_CMD(sql.query([&](int length, std::string* values, std::string* names) {
GroupId group_id;
ChannelId channel_id;
ClientDbId client_database_id;
int index{0};
try {
assert(names[index] == "groupId");
group_id = std::stoull(values[index++]);
assert(names[index] == "cldbid");
channel_id = std::stoull(values[index++]);
assert(names[index] == "channelId");
client_database_id = std::stoull(values[index++]);
assert(index == length);
} catch (std::exception& ex) {
logError(this->server_id(), "Failed to parse client group assignment at index {}: {}",
index - 1,
ex.what()
);
return;
}
result.emplace_back(group_id, channel_id, client_database_id);
}));
return result;
}
GroupAssignmentResult GroupAssignmentManager::add_server_group(ClientDbId client, GroupId group) {
bool cache_verified{false};
{
@@ -340,8 +417,9 @@ GroupAssignmentResult GroupAssignmentManager::add_server_group(ClientDbId client
auto it = std::find_if(entry->server_group_assignments.begin(), entry->server_group_assignments.end(), [&](const ServerGroupAssignment& assignment) {
return assignment.group_id == group;
});
if(it != entry->server_group_assignments.end())
if(it != entry->server_group_assignments.end()) {
return GroupAssignmentResult::ADD_ALREADY_MEMBER_OF_GROUP;
}
entry->server_group_assignments.emplace_back(group);
cache_verified = true;
break;
@@ -384,8 +462,9 @@ GroupAssignmentResult GroupAssignmentManager::remove_server_group(ClientDbId cli
auto it = std::find_if(entry->server_group_assignments.begin(), entry->server_group_assignments.end(), [&](const ServerGroupAssignment& assignment) {
return assignment.group_id == group;
});
if(it == entry->server_group_assignments.end())
if(it == entry->server_group_assignments.end()) {
return GroupAssignmentResult::REMOVE_NOT_MEMBER_OF_GROUP;
}
entry->server_group_assignments.erase(it);
cache_verified = true;
break;
@@ -507,8 +586,14 @@ void GroupAssignmentManager::cleanup_channel_temporary_assignment(ClientDbId cli
auto assignment = std::find_if(client->channel_group_assignments.begin(), client->channel_group_assignments.end(), [&](const ChannelGroupAssignment& assignment) {
return assignment.channel_id == channel;
});
if(assignment->temporary_assignment)
if(assignment == client->channel_group_assignments.end()) {
break;
}
if(assignment->temporary_assignment) {
client->channel_group_assignments.erase(assignment);
}
break;
}
}
+25 -3
View File
@@ -1,5 +1,6 @@
#pragma once
#include <optional>
#include <mutex>
#include <deque>
#include <string>
@@ -12,6 +13,10 @@ namespace sql {
class SqlManager;
}
namespace ts {
class BasicChannel;
}
namespace ts::server {
class ConnectedClient;
@@ -63,17 +68,30 @@ namespace ts::server {
bool load_data(std::string& /* error */);
void unload_data();
void reset_all();
/* client specific cache methods */
void enable_cache_for_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */);
void disable_cache_for_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */);
/* info/query methods */
[[nodiscard]] std::vector<GroupId> server_groups_of_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */);
[[nodiscard]] std::vector<ChannelGroupAssignment> channel_groups_of_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */);
[[nodiscard]] std::optional<ChannelGroupAssignment> channel_group_of_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */, ChannelId /* channel id */);
[[nodiscard]] std::vector<ChannelGroupAssignment> exact_channel_groups_of_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */);
[[nodiscard]] std::optional<ChannelGroupAssignment> exact_channel_group_of_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */, ChannelId /* channel id */);
/**
* Calculate the target channel group for the client.
* The parameters `target channel` will contain the channel where the group has been inherited from.
* Note: `target channel` will be altered if the resutl is empty.
* @return The target channel group id
*/
[[nodiscard]] std::optional<GroupId> calculate_channel_group_of_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */, std::shared_ptr<BasicChannel>& /* target channel */);
[[nodiscard]] std::deque<ClientDbId> server_group_clients(GroupId /* group id */);
//[[nodiscard]] std::deque<ClientDbId> channel_group_clients(GroupId /* group id */, ChannelId /* channel id */);
[[nodiscard]] std::deque<std::tuple<GroupId, ChannelId, ClientDbId>> channel_group_list(GroupId /* group id */, ChannelId /* channel id */, ClientDbId /* client database id */);
[[nodiscard]] bool is_server_group_empty(GroupId /* group id */);
[[nodiscard]] bool is_channel_group_empty(GroupId /* group id */);
/* change methods */
GroupAssignmentResult add_server_group(ClientDbId /* client database id */, GroupId /* group id */);
@@ -84,6 +102,10 @@ namespace ts::server {
void cleanup_assignments();
void cleanup_channel_assignments(ChannelId /* channel */);
void cleanup_channel_temporary_assignment(ClientDbId /* client database id */, ChannelId /* channel */);
void handle_channel_deleted(ChannelId /* channel id */);
void handle_server_group_deleted(GroupId /* group id */);
void handle_channel_group_deleted(GroupId /* group id */);
private:
struct ClientCache {
ClientDbId client_database_id{0};
+36 -4
View File
@@ -114,6 +114,27 @@ void AbstractGroupManager::unload_data() {
}
}
void AbstractGroupManager::reset_groups(const std::shared_ptr<GroupManager> &template_provider, std::map<GroupId, GroupId> &mapping) {
std::lock_guard manage_lock{this->group_manage_mutex_};
this->unload_data();
/* Delete all old groups */
{
/* FIXME: Only delete groups with our database target! */
LOG_SQL_CMD(sql::command(this->sql_manager(), "DELETE FROM `permissions` WHERE `serverId` = :serverId AND `type` = :type",
variable{":serverId", this->server_id()},
variable{":type", ts::permission::SQL_PERM_GROUP}).execute());
LOG_SQL_CMD(sql::command(this->sql_manager(), "DELETE FROM `assignedGroups` WHERE `serverId` = :serverId",
variable{":serverId", this->server_id()}).execute());
LOG_SQL_CMD(sql::command(this->sql_manager(), "DELETE FROM `groups` WHERE `serverId` = :serverId",
variable{":serverId", this->server_id()}).execute());
}
if(auto error = this->load_data(true); error != GroupLoadResult::SUCCESS) {
logCritical(this->server_id(), "Failed to load groups after group unload ({}). There might be no groups loaded now!", (int) error);
}
}
void AbstractGroupManager::reset_groups(bool db_cleanup) {
std::lock_guard manage_lock{this->group_manage_mutex_};
this->unload_data();
@@ -224,6 +245,12 @@ std::shared_ptr<Group> AbstractGroupManager::find_group_by_name_(GroupCalculateM
}
GroupCreateResult AbstractGroupManager::create_group_(GroupType type, const std::string &name, std::shared_ptr<Group>& result) {
if(name.empty()) {
return GroupCreateResult::NAME_TOO_SHORT;
} else if(name.length() > 30) {
return GroupCreateResult::NAME_TOO_LONG;
}
std::lock_guard manage_lock{this->group_manage_mutex_};
if(this->find_group_by_name_(GroupCalculateMode::LOCAL, name)) {
return GroupCreateResult::NAME_ALREADY_IN_USED;
@@ -264,9 +291,6 @@ GroupCopyResult AbstractGroupManager::copy_group_(GroupId source, GroupType targ
case GroupCreateResult::NAME_ALREADY_IN_USED:
return GroupCopyResult::NAME_ALREADY_IN_USE;
case GroupCreateResult::FAILED_TO_GENERATE_ID:
return GroupCopyResult::FAILED_TO_GENERATE_ID;
}
assert(result);
@@ -335,12 +359,17 @@ GroupDeleteResult AbstractGroupManager::delete_group_(GroupId group_id) {
std::lock_guard manage_lock{this->group_manage_mutex_};
{
std::lock_guard glock{this->group_mutex_};
std::unique_lock glock{this->group_mutex_};
auto it = std::find_if(this->groups_.begin(), this->groups_.begin(), [&](const std::shared_ptr<Group>& group) {
return group->group_id() == group_id;
});
if(it == this->groups_.end()) {
if(this->parent_manager_) {
glock.unlock();
return this->parent_manager_->delete_group_(group_id);
}
return GroupDeleteResult::INVALID_GROUP_ID;
}
@@ -354,6 +383,9 @@ GroupDeleteResult AbstractGroupManager::delete_group_(GroupId group_id) {
return GroupDeleteResult::SUCCESS;
}
void AbstractGroupManager::reset_groups_(const std::shared_ptr<GroupManager> &source, std::map<GroupId, GroupId> &mapping) {
}
/* Server group manager */
ServerGroupManager::ServerGroupManager(const std::shared_ptr<GroupManager> &handle, std::shared_ptr<ServerGroupManager> parent)
+8 -3
View File
@@ -24,7 +24,8 @@ namespace ts::server::groups {
enum struct GroupCreateResult {
SUCCESS,
NAME_ALREADY_IN_USED,
FAILED_TO_GENERATE_ID,
NAME_TOO_SHORT,
NAME_TOO_LONG,
DATABASE_ERROR
};
@@ -33,7 +34,6 @@ namespace ts::server::groups {
UNKNOWN_SOURCE_GROUP,
UNKNOWN_TARGET_GROUP,
NAME_ALREADY_IN_USE,
FAILED_TO_GENERATE_ID,
DATABASE_ERROR
};
@@ -73,9 +73,14 @@ namespace ts::server::groups {
bool initialize(std::string& /* error */);
GroupLoadResult load_data(bool /* initialize */ = false);
void unload_data();
void reset_groups(bool /* cleanup database */);
void save_permissions(size_t& /* total groups */, size_t& /* saved groups */);
/**
* Reset all known groups.
* If the template group provider is empty no new groups will be created.
*/
void reset_groups(const std::shared_ptr<GroupManager>& /* template group provider */, std::map<GroupId, GroupId>& /* mapping */);
protected:
std::shared_ptr<AbstractGroupManager> parent_manager_;
DatabaseGroupTarget database_target_;