Some more work for the new group manager
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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_;
|
||||
|
||||
Reference in New Issue
Block a user