Added two new commands

This commit is contained in:
WolverinDEV 2019-09-14 14:22:16 +02:00
parent c8a6449a45
commit 9cb069db5a
13 changed files with 390 additions and 259 deletions

@ -1 +1 @@
Subproject commit 6dd8f87281e6fd60df0c5babfc1303df74ce1c0a Subproject commit 2c928229b1aab0306a02d2b7820fd93f3a3623b9

View File

@ -227,7 +227,7 @@ target_link_libraries(PermMapHelper
SET(CPACK_PACKAGE_VERSION_MAJOR "1") SET(CPACK_PACKAGE_VERSION_MAJOR "1")
SET(CPACK_PACKAGE_VERSION_MINOR "3") SET(CPACK_PACKAGE_VERSION_MINOR "3")
SET(CPACK_PACKAGE_VERSION_PATCH "24") SET(CPACK_PACKAGE_VERSION_PATCH "25")
if(BUILD_TYPE_NAME EQUAL OFF) if(BUILD_TYPE_NAME EQUAL OFF)
SET(CPACK_PACKAGE_VERSION_DATA "beta") SET(CPACK_PACKAGE_VERSION_DATA "beta")
elseif(BUILD_TYPE_NAME STREQUAL "") elseif(BUILD_TYPE_NAME STREQUAL "")

View File

@ -171,7 +171,7 @@ int GroupManager::insertGroupFromDb(int count, char **values, char **column) {
else cerr << "Invalid group table row " << column[index] << endl; else cerr << "Invalid group table row " << column[index] << endl;
} }
if(groupId == 0 || target == 0xff || type == 0xff || targetName.empty()) { if((size_t) groupId == 0 || (size_t) target == 0xff || (size_t) type == 0xff || targetName.empty()) {
logCritical(this->getServerId(), "Found invalid group ad database! (GroupId " + to_string(groupId) + ", Target " + to_string(target) + ", Type " + to_string(type) + ", Name '" + targetName + "')"); logCritical(this->getServerId(), "Found invalid group ad database! (GroupId " + to_string(groupId) + ", Target " + to_string(target) + ", Type " + to_string(type) + ", Name '" + targetName + "')");
return 0; return 0;
} }
@ -225,11 +225,15 @@ int GroupManager::insertGroupFromDb(int count, char **values, char **column) {
return 0; return 0;
} }
void GroupManager::handleChannelDeleted(std::shared_ptr<BasicChannel> channel) { void GroupManager::handleChannelDeleted(const ChannelId& channel_id) {
cacheLock.lock(); unique_lock cache_lock(this->cacheLock);
for(const auto &entry : this->cachedClients) auto cached_clients = std::vector<shared_ptr<CachedClient>>{this->cachedClients.begin(), this->cachedClients.end()};
entry->channelGroups.erase(channel->channelId()); cache_lock.unlock();
cacheLock.unlock();
for(auto& entry : cached_clients) {
lock_guard entry_lock(entry->lock);
entry->channel_groups.erase(channel_id);
}
} }
bool GroupManager::isLocalGroup(std::shared_ptr<Group> gr) { bool GroupManager::isLocalGroup(std::shared_ptr<Group> gr) {
@ -373,24 +377,11 @@ bool GroupManager::deleteAllGroups() {
LOG_SQL_CMD(sql::command(this->sql, "DELETE FROM `assignedGroups` WHERE `serverId` = :sid", variable{":sid", this->getServerId()}).execute()); LOG_SQL_CMD(sql::command(this->sql, "DELETE FROM `assignedGroups` WHERE `serverId` = :sid", variable{":sid", this->getServerId()}).execute());
LOG_SQL_CMD(sql::command(this->sql, "DELETE FROM `permissions` WHERE `serverId` = :sid AND `type` = :type", variable{":sid", this->getServerId()}, variable{":type", SQL_PERM_GROUP}).execute()); LOG_SQL_CMD(sql::command(this->sql, "DELETE FROM `permissions` WHERE `serverId` = :sid AND `type` = :type", variable{":sid", this->getServerId()}, variable{":type", SQL_PERM_GROUP}).execute());
{ {
threads::MutexLock lock(this->cacheLock); lock_guard cache_lock(this->cacheLock);
for(const auto& entry : this->cachedClients) { for(const auto& entry : this->cachedClients) {
threads::MutexLock lock_entry(entry->lock); lock_guard entry_lock(entry->lock);
bool iterate = true; entry->server_groups.clear();
while(iterate) { entry->channel_groups.clear();
iterate = false;
for(const auto& assignment : entry->channelGroups) {
if(std::find(this->groups.begin(), this->groups.end(), assignment.second->group) != this->groups.end()) {
entry->channelGroups.erase(assignment.first);
iterate = true;
break;
}
}
}
entry->serverGroups.erase(std::remove_if(entry->serverGroups.begin(), entry->serverGroups.end(), [&](const shared_ptr<GroupAssignment>& assignment){
return std::find(this->groups.begin(), this->groups.end(), assignment->group) != this->groups.end();
}), entry->serverGroups.end());
} }
} }
this->groups.clear(); this->groups.clear();
@ -405,6 +396,25 @@ bool GroupManager::deleteGroup(std::shared_ptr<Group> group) {
this->groups.erase(std::find(this->groups.begin(), this->groups.end(), group)); this->groups.erase(std::find(this->groups.begin(), this->groups.end(), group));
/* erase the group out of our cache */
{
lock_guard cache_lock(this->cacheLock);
for(auto& entry : this->cachedClients) {
lock_guard entry_lock(entry->lock);
entry->server_groups.erase(std::remove_if(entry->server_groups.begin(), entry->server_groups.end(), [&](const std::shared_ptr<GroupAssignment>& group_assignment) {
return group_assignment->group == group;
}), entry->server_groups.end());
for(auto it = entry->channel_groups.begin(); it != entry->channel_groups.end();) {
if(it->second->group == group)
it = entry->channel_groups.erase(it);
else
it++;
}
}
}
bool flag_sql = false; bool flag_sql = false;
auto res = sql::command(this->sql, "DELETE FROM `groups` WHERE `serverId` = :sid AND `groupId` = :gid", variable{":sid", this->getServerId()}, variable{":gid", group->groupId()}).execute(); auto res = sql::command(this->sql, "DELETE FROM `groups` WHERE `serverId` = :sid AND `groupId` = :gid", variable{":sid", this->getServerId()}, variable{":gid", group->groupId()}).execute();
LOG_SQL_CMD(res); LOG_SQL_CMD(res);
@ -418,33 +428,6 @@ bool GroupManager::deleteGroup(std::shared_ptr<Group> group) {
if(flag_sql) if(flag_sql)
logError(this->getServerId(), "Could not delete group {} ({}) from database. May leader to invalid data", group->name(), group->groupId()); logError(this->getServerId(), "Could not delete group {} ({}) from database. May leader to invalid data", group->name(), group->groupId());
this->cacheLock.lock();
for(const auto &entry : this->cachedClients){
bool iterate = true;
while(iterate) {
iterate = false;
for(const auto &assignment : entry->serverGroups){
if(assignment->group == group){
entry->serverGroups.erase(std::find(entry->serverGroups.begin(), entry->serverGroups.end(), assignment));
iterate = true;
break;
}
}
}
iterate = true;
while(iterate) {
iterate = false;
for(const auto& pair : entry->channelGroups){
if(pair.second->group == group){
entry->channelGroups.erase(pair.first);
iterate = true;
break;
}
}
}
}
this->cacheLock.unlock();
return true; return true;
} }
@ -515,95 +498,93 @@ void GroupManager::cleanupAssignments(ClientDbId client) {
} }
} }
template <typename DataType>
struct DBLoadCacheParmStruct {
GroupManager* manager;
DataType* data;
};
void GroupManager::enableCache(const ClientDbId& client_database_id) {
void GroupManager::enableCache(std::shared_ptr<server::ConnectedClient> client) {
if(this->root) if(this->root)
this->root->enableCache(client); this->root->enableCache(client_database_id);
shared_ptr<CachedClient> entry = std::make_shared<CachedClient>(); unique_lock cache_lock(this->cacheLock);
entry->client = client; /* test if we're already having the client */
for(auto& entry : this->cachedClients)
if(entry->client_database_id == client_database_id) {
entry->use_count++;
return; /* client already cached, no need to cache client */
}
DBLoadCacheParmStruct<CachedClient> parm = {this, entry.get()}; auto entry = std::make_shared<CachedClient>();
entry->client_database_id = client_database_id;
entry->use_count++;
this->cachedClients.push_back(entry);
auto res = sql::command(this->sql, "SELECT `groupId`, `channelId`, `until` FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid", variable{":sid", this->getServerId()}, variable{":cldbid", client->getClientDatabaseId()}).query([&](DBLoadCacheParmStruct<CachedClient>* parms, int length, char** value, char** column) { lock_guard client_cache_lock(entry->lock); /* lock the client because we're currently loading the cache. */
cache_lock.unlock();
auto res = sql::command(this->sql, "SELECT `groupId`, `channelId`, `until` FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid", variable{":sid", this->getServerId()}, variable{":cldbid", client_database_id})
.query([&](int length, std::string* value, std::string* column) {
shared_ptr<Group> group = nullptr; shared_ptr<Group> group = nullptr;
time_point<system_clock> until; time_point<system_clock> until;
ChannelId channelId = 0; ChannelId channelId = 0;
for(int index = 0; index < length; index++){ for(int index = 0; index < length; index++){
if(value[index] == nullptr) { try {
logError(this->getServerId(), string() + "Invalid value at " + column[index]); if(column[index] == "groupId"){
continue; group = this->findGroup(stoll(value[index]));
} else if(column[index] == "until"){
until = time_point<system_clock>() + milliseconds(stoll(value[index]));
} else if(column[index] == "channelId"){
channelId = stoll(value[index]);
} else {
logError(this->getServerId(), "Unknown column in group assignment query: {}", column[index]);
continue;
}
} catch(std::exception& ex) {
logError(this->getServerId(), "Failed to load group assignment from database for client {}. Column {} contains an invalid value: {}", client_database_id, column[index], value[index]);
return 0;
} }
if(strcmp(column[index], "groupId") == 0){
group = parms->manager->findGroup(stoll(value[index]));
} else if(strcmp(column[index], "until") == 0){
until = time_point<system_clock>() + milliseconds(stoll(value[index]));
} else if(strcmp(column[index], "channelId") == 0){
channelId = stoll(value[index]);
} else cerr << "Invalid column " << column[index] << endl;
} }
if(!group) if(!group) {
return 0; return 0;
}
shared_ptr<GroupAssignment> assignment = std::make_shared<GroupAssignment>(); auto assignment = std::make_shared<GroupAssignment>();
assignment->group = group; assignment->group = group;
assignment->until = until; assignment->until = until;
assignment->parent = parms->data; assignment->parent = &*entry;
assignment->channelId = channelId; assignment->channelId = channelId;
assignment->server = this->getServerId(); assignment->server = this->getServerId();
if(channelId == 0)
parms->data->serverGroups.push_back(assignment);
else parms->data->channelGroups[channelId] = assignment;
return 0;
}, &parm);
this->cacheLock.lock(); if(channelId == 0)
this->cachedClients.push_back(entry); entry->server_groups.push_back(assignment);
this->cacheLock.unlock(); else
entry->channel_groups[channelId] = assignment;
return 0;
});
} }
void GroupManager::disableCache(const shared_ptr<ConnectedClient> &client) { //FIXME: This method till get far more often then it should be. We should add a flag if the group cache is loaded for each std::shared_ptr<ConnectedClient> instance
if(this->root) this->root->disableCache(client); void GroupManager::disableCache(const ClientDbId& client_database_id) {
if(this->root)
this->root->disableCache(client_database_id);
threads::MutexLock lock(this->cacheLock); lock_guard cache_lock(this->cacheLock);
bool found = false; this->cachedClients.erase(std::remove_if(this->cachedClients.begin(), this->cachedClients.end(), [&](const std::shared_ptr<CachedClient>& client) {
for(const auto& entry : this->cachedClients){ if(client->client_database_id != client_database_id)
if(entry->client == client){ return false;
this->cachedClients.erase(std::find(this->cachedClients.begin(), this->cachedClients.end(), entry));
found = true; lock_guard client_lock{client->lock};
break; return (--client->use_count) == 0;
} }), this->cachedClients.end());
}
if(!found)
;//debugMessage("Tried to attempt to delete a not existing cached manager. (" + manager->getDisplayName() + ")");
} }
void GroupManager::clearCache() { void GroupManager::clearCache() {
if(this->root) this->root->clearCache(); if(this->root) this->root->clearCache();
threads::MutexLock lock(cacheLock); lock_guard lock(this->cacheLock);
this->cachedClients.clear(); this->cachedClients.clear();
} }
bool GroupManager::isClientCached(const shared_ptr<ConnectedClient> &client) { bool GroupManager::isClientCached(const ClientDbId& client_database_id) {
{ return this->resolve_cached_client(client_database_id) == nullptr;
threads::MutexLock lock(cacheLock);
for(const auto &entry : this->cachedClients){
if(entry->client == client){
return true;
}
}
}
if(this->root) return this->root->isClientCached(client);
return false;
} }
typedef std::vector<std::shared_ptr<GroupMember>> ResList; typedef std::vector<std::shared_ptr<GroupMember>> ResList;
@ -644,19 +625,17 @@ std::vector<std::shared_ptr<GroupMember>> GroupManager::listGroupMembers(std::sh
return result; return result;
} }
typedef DBLoadCacheParmStruct<vector<std::shared_ptr<GroupAssignment>>> GAGroupCache;
vector<shared_ptr<GroupAssignment>> GroupManager::listGroupAssignments(ClientDbId cldbId) { vector<shared_ptr<GroupAssignment>> GroupManager::listGroupAssignments(ClientDbId cldbId) {
vector<std::shared_ptr<GroupAssignment>> result; vector<std::shared_ptr<GroupAssignment>> result;
GAGroupCache parm = {this, &result};
sql::result res; sql::result res;
auto cached = resolveCached(cldbId); auto cached = resolve_cached_client(cldbId);
if(cached) { if(cached) {
{ {
threads::MutexLock l(cached->lock); lock_guard lock{cached->lock};
for(const auto &serverGroup : cached->serverGroups) for(const auto &serverGroup : cached->server_groups)
result.push_back(serverGroup); result.push_back(serverGroup);
for(auto& channelGroup : cached->channelGroups) for(auto& channelGroup : cached->channel_groups)
result.push_back(channelGroup.second); result.push_back(channelGroup.second);
} }
@ -670,7 +649,8 @@ vector<shared_ptr<GroupAssignment>> GroupManager::listGroupAssignments(ClientDbI
} }
res = sql::command(this->sql, "SELECT `groupId`, `until`, `channelId` FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid", variable{":sid", this->getServerId()}, variable{":cldbid", cldbId}).query([&](GAGroupCache* parms, int length, char** value, char** column){ res = sql::command(this->sql, "SELECT `groupId`, `until`, `channelId` FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid", variable{":sid", this->getServerId()}, variable{":cldbid", cldbId})
.query([&](int length, char** value, char** column){
shared_ptr<Group> group = nullptr; shared_ptr<Group> group = nullptr;
time_point<system_clock> until; time_point<system_clock> until;
uint64_t channelId = 0; uint64_t channelId = 0;
@ -681,7 +661,7 @@ vector<shared_ptr<GroupAssignment>> GroupManager::listGroupAssignments(ClientDbI
continue; continue;
} }
if(strcmp(column[index], "groupId") == 0){ if(strcmp(column[index], "groupId") == 0){
group = parms->manager->findGroup(stoll(value[index])); group = this->findGroup(stoll(value[index]));
} else if(strcmp(column[index], "until") == 0){ } else if(strcmp(column[index], "until") == 0){
until = time_point<system_clock>() + milliseconds(stoll(value[index])); until = time_point<system_clock>() + milliseconds(stoll(value[index]));
} else if(strcmp(column[index], "channelId") == 0){ } else if(strcmp(column[index], "channelId") == 0){
@ -697,9 +677,9 @@ vector<shared_ptr<GroupAssignment>> GroupManager::listGroupAssignments(ClientDbI
assignment->until = until; assignment->until = until;
assignment->channelId = channelId; assignment->channelId = channelId;
assignment->server = this->getServerId(); assignment->server = this->getServerId();
parms->data->push_back(assignment); result.push_back(assignment);
return 0; return 0;
}, &parm); });
(LOG_SQL_CMD)(res); (LOG_SQL_CMD)(res);
if(this->root){ if(this->root){
@ -711,18 +691,19 @@ vector<shared_ptr<GroupAssignment>> GroupManager::listGroupAssignments(ClientDbI
return result; return result;
} }
std::shared_ptr<CachedClient> GroupManager::resolveCached(ClientDbId cldbId) { std::shared_ptr<CachedClient> GroupManager::resolve_cached_client(ClientDbId client_database_id) {
threads::MutexLock lock(this->cacheLock); {
for(const auto& cl : this->cachedClients) lock_guard lock(this->cacheLock);
if(cl->client->getClientDatabaseId() == cldbId){ for(auto& entry : this->cachedClients)
return cl; if(entry->client_database_id == client_database_id)
} return entry;
return nullptr; }
return nullptr;
} }
typedef DBLoadCacheParmStruct<std::vector<std::shared_ptr<GroupAssignment>>> SGroupCache;
std::vector<std::shared_ptr<GroupAssignment>> GroupManager::getAssignedServerGroups(ClientDbId cldbid) { std::vector<std::shared_ptr<GroupAssignment>> GroupManager::getAssignedServerGroups(ClientDbId cldbid) {
auto cached = this->resolveCached(cldbid); auto cached = this->resolve_cached_client(cldbid);
sql::result res; sql::result res;
std::vector<std::shared_ptr<GroupAssignment>> result; std::vector<std::shared_ptr<GroupAssignment>> result;
if(this->root) { if(this->root) {
@ -730,17 +711,15 @@ std::vector<std::shared_ptr<GroupAssignment>> GroupManager::getAssignedServerGro
result.insert(result.begin(), root.begin(), root.end()); result.insert(result.begin(), root.begin(), root.end());
} }
SGroupCache parm = {this, &result};
if(cached) { if(cached) {
threads::MutexLock l(cached->lock); lock_guard cache_lock{cached->lock};
for(const auto &elm : cached->serverGroups) result.push_back(elm); result.insert(result.end(), cached->server_groups.begin(), cached->server_groups.end());
return result; return result;
} }
debugMessage("DB query groups! for -> " + to_string(cldbid) + " - server " + to_string(this->getServerId())); debugMessage("DB query groups! for -> " + to_string(cldbid) + " - server " + to_string(this->getServerId()));
res = sql::command(this->sql, "SELECT `groupId`, `until` FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid AND `channelId` = 0", variable{":sid", this->getServerId()}, variable{":cldbid", cldbid}).query([&](SGroupCache* parms, int length, char** value, char** column){ res = sql::command(this->sql, "SELECT `groupId`, `until` FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid AND `channelId` = 0", variable{":sid", this->getServerId()}, variable{":cldbid", cldbid}).query([&](int length, char** value, char** column){
shared_ptr<Group> group = nullptr; shared_ptr<Group> group = nullptr;
time_point<system_clock> until; time_point<system_clock> until;
@ -750,7 +729,7 @@ std::vector<std::shared_ptr<GroupAssignment>> GroupManager::getAssignedServerGro
continue; continue;
} }
if(strcmp(column[index], "groupId") == 0 && value[index] != nullptr){ if(strcmp(column[index], "groupId") == 0 && value[index] != nullptr){
group = parms->manager->findGroup(stoll(value[index])); group = this->findGroup(stoll(value[index]));
} else if(strcmp(column[index], "until") == 0){ } else if(strcmp(column[index], "until") == 0){
until = time_point<system_clock>() + milliseconds(stoll(value[index] == nullptr ? "0" : value[index])); until = time_point<system_clock>() + milliseconds(stoll(value[index] == nullptr ? "0" : value[index]));
} else cerr << "Invalid column " << column[index] << endl; } else cerr << "Invalid column " << column[index] << endl;
@ -763,9 +742,9 @@ std::vector<std::shared_ptr<GroupAssignment>> GroupManager::getAssignedServerGro
assignment->group = group; assignment->group = group;
assignment->until = until; assignment->until = until;
assignment->server = this->getServerId(); assignment->server = this->getServerId();
parms->data->push_back(assignment); result.push_back(assignment);
return 0; return 0;
}, &parm); });
LOG_SQL_CMD(res); LOG_SQL_CMD(res);
return result; return result;
} }
@ -799,20 +778,18 @@ std::vector<std::shared_ptr<GroupAssignment>> GroupManager::defaultServerGroupGr
return result; return result;
} }
typedef DBLoadCacheParmStruct<std::shared_ptr<GroupAssignment>> CGroupCache;
std::shared_ptr<GroupAssignment> GroupManager::getChannelGroupExact(ClientDbId cldbId, const std::shared_ptr<BasicChannel>& channel, bool assign_default) { std::shared_ptr<GroupAssignment> GroupManager::getChannelGroupExact(ClientDbId cldbId, const std::shared_ptr<BasicChannel>& channel, bool assign_default) {
auto cached = resolveCached(cldbId); auto cached = resolve_cached_client(cldbId);
if(cached) { if(cached) {
threads::MutexLock l(cached->lock); lock_guard cache_lock(cached->lock);
if(cached->channelGroups.count(channel->channelId()) > 0) { if(cached->channel_groups.count(channel->channelId()) > 0) {
return cached->channelGroups[channel->channelId()]; return cached->channel_groups[channel->channelId()];
} else } else
return assign_default ? this->defaultChannelGroupAssignment(cldbId, channel) : nullptr; return assign_default ? this->defaultChannelGroupAssignment(cldbId, channel) : nullptr;
} }
std::shared_ptr<GroupAssignment> result; std::shared_ptr<GroupAssignment> result;
CGroupCache parm = {this, &result}; auto res = sql::command(this->sql, "SELECT `groupId`, `until` FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid AND `channelId` = :chid", variable{":sid", this->getServerId()}, variable{":cldbid", cldbId}, variable{":chid", channel->channelId()}).query([&](int length, char** value, char** column){
auto res = sql::command(this->sql, "SELECT `groupId`, `until` FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid AND `channelId` = :chid", variable{":sid", this->getServerId()}, variable{":cldbid", cldbId}, variable{":chid", channel->channelId()}).query([&](CGroupCache* parms, int length, char** value, char** column){
shared_ptr<Group> group = nullptr; shared_ptr<Group> group = nullptr;
time_point<system_clock> until; time_point<system_clock> until;
@ -822,7 +799,7 @@ std::shared_ptr<GroupAssignment> GroupManager::getChannelGroupExact(ClientDbId c
continue; continue;
} }
if(strcmp(column[index], "groupId") == 0){ if(strcmp(column[index], "groupId") == 0){
group = parms->manager->findGroup(stoll(value[index])); group = this->findGroup(stoll(value[index]));
} else if(strcmp(column[index], "until") == 0){ } else if(strcmp(column[index], "until") == 0){
until = time_point<system_clock>() + milliseconds(stoll(value[index])); until = time_point<system_clock>() + milliseconds(stoll(value[index]));
} else cerr << "Invalid column " << column[index] << endl; } else cerr << "Invalid column " << column[index] << endl;
@ -836,9 +813,9 @@ std::shared_ptr<GroupAssignment> GroupManager::getChannelGroupExact(ClientDbId c
assignment->until = until; assignment->until = until;
assignment->server = this->getServerId(); assignment->server = this->getServerId();
assignment->channelId = channel->channelId(); assignment->channelId = channel->channelId();
*parms->data = assignment; result = std::move(assignment);
return 0; return 0;
}, &parm); });
(LOG_SQL_CMD)(res); (LOG_SQL_CMD)(res);
return !result && assign_default ? this->defaultChannelGroupAssignment(cldbId, channel) : result; return !result && assign_default ? this->defaultChannelGroupAssignment(cldbId, channel) : result;
@ -873,10 +850,10 @@ void GroupManager::addServerGroup(ClientDbId cldbId, std::shared_ptr<Group> grou
if(hasServerGroup(cldbId, group)) return; if(hasServerGroup(cldbId, group)) return;
*/ */
auto cached = resolveCached(cldbId); auto cached = resolve_cached_client(cldbId);
if(cached) { if(cached) {
threads::MutexLock l(cached->lock); lock_guard cache_lock(cached->lock);
cached->serverGroups.push_back(std::make_shared<GroupAssignment>(cached.get(), this->getServerId(), 0, group, until)); cached->server_groups.push_back(std::make_shared<GroupAssignment>(cached.get(), this->getServerId(), 0, group, until));
} }
sql::command(this->sql, "INSERT INTO `assignedGroups` (`serverId`, `cldbid`, `groupId`, `channelId`, `until`) VALUES (:sid, :cldbid, :gid, :chid, :until)", sql::command(this->sql, "INSERT INTO `assignedGroups` (`serverId`, `cldbid`, `groupId`, `channelId`, `until`) VALUES (:sid, :cldbid, :gid, :chid, :until)",
@ -890,14 +867,12 @@ void GroupManager::addServerGroup(ClientDbId cldbId, std::shared_ptr<Group> grou
void GroupManager::removeServerGroup(ClientDbId cldbId, std::shared_ptr<Group> group) { void GroupManager::removeServerGroup(ClientDbId cldbId, std::shared_ptr<Group> group) {
if(!this->hasServerGroupAssigned(cldbId, group)) return; if(!this->hasServerGroupAssigned(cldbId, group)) return;
auto cached = resolveCached(cldbId); auto cached = resolve_cached_client(cldbId);
if(cached) { if(cached) {
threads::MutexLock l(cached->lock); lock_guard cache_lock(cached->lock);
for(const auto &entry : cached->serverGroups) cached->server_groups.erase(std::remove_if(cached->server_groups.begin(), cached->server_groups.end(), [&](const std::shared_ptr<GroupAssignment>& group_assignment) {
if(entry->group == group){ return group_assignment->group == group;
cached->serverGroups.erase(std::find(cached->serverGroups.begin(), cached->serverGroups.end(), entry)); }), cached->server_groups.end());
break;
}
} }
sql::command(this->sql, "DELETE FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid AND `groupId` = :gid AND `channelId` = :chid", sql::command(this->sql, "DELETE FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid AND `groupId` = :gid AND `channelId` = :chid",
@ -915,13 +890,13 @@ void GroupManager::setChannelGroup(ClientDbId cldbId, std::shared_ptr<Group> gro
} else if(!group) return; } else if(!group) return;
auto default_group = !group || group == this->defaultGroup(GroupTarget::GROUPTARGET_CHANNEL); auto default_group = !group || group == this->defaultGroup(GroupTarget::GROUPTARGET_CHANNEL);
auto cached = resolveCached(cldbId); auto cached = resolve_cached_client(cldbId);
if(cached) { if(cached) {
threads::MutexLock l(cached->lock); lock_guard cache_lock(cached->lock);
if(default_group) if(default_group)
cached->channelGroups.erase(channel->channelId()); cached->channel_groups.erase(channel->channelId());
else else
cached->channelGroups[channel->channelId()] = std::make_shared<GroupAssignment>(cached.get(), this->getServerId(), channel->channelId(), group, until); cached->channel_groups[channel->channelId()] = std::make_shared<GroupAssignment>(cached.get(), this->getServerId(), channel->channelId(), group, until);
} }
sql::command(this->sql, "DELETE FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid AND `channelId` = :chid", sql::command(this->sql, "DELETE FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid AND `channelId` = :chid",

View File

@ -17,7 +17,7 @@ namespace ts {
class ConnectedClient; class ConnectedClient;
} }
class CachedClient; struct CachedClient;
class GroupManager; class GroupManager;
class Group; class Group;
@ -66,10 +66,14 @@ namespace ts {
}; };
struct CachedClient { struct CachedClient {
std::shared_ptr<server::ConnectedClient> client; ClientDbId client_database_id;
std::vector<std::shared_ptr<GroupAssignment>> serverGroups;
std::map<ts::ChannelId, std::shared_ptr<GroupAssignment>> channelGroups; std::vector<std::shared_ptr<GroupAssignment>> server_groups;
threads::Mutex lock; std::map<ts::ChannelId, std::shared_ptr<GroupAssignment>> channel_groups;
size_t use_count = 0;
std::mutex lock; /* never lock this lock before the general client cache! */
}; };
class Group { class Group {
@ -160,6 +164,12 @@ namespace ts {
return false; return false;
} }
std::shared_ptr<GroupAssignment> get_group_assignment(const ClientDbId& client_database_id, const std::shared_ptr<Group>& group) {
for(const auto& assign : this->getAssignedServerGroups(client_database_id))
if(assign->group == group) return assign;
return nullptr;
}
std::vector<std::shared_ptr<GroupAssignment>> getServerGroups(ClientDbId cldbid, server::ClientType type); std::vector<std::shared_ptr<GroupAssignment>> getServerGroups(ClientDbId cldbid, server::ClientType type);
inline bool hasServerGroup(uint64_t cldbId, server::ClientType type, const std::shared_ptr<Group>& group){ inline bool hasServerGroup(uint64_t cldbId, server::ClientType type, const std::shared_ptr<Group>& group){
for(const auto& assign : this->getServerGroups(cldbId, type)) if(assign->group == group) return true; for(const auto& assign : this->getServerGroups(cldbId, type)) if(assign->group == group) return true;
@ -200,15 +210,15 @@ namespace ts {
std::shared_ptr<Group> defaultGroup(GroupTarget type, bool enforce_property = false); std::shared_ptr<Group> defaultGroup(GroupTarget type, bool enforce_property = false);
std::deque<property::ClientProperties> update_server_group_property(const std::shared_ptr<server::ConnectedClient> &client, bool channel_lock); std::deque<property::ClientProperties> update_server_group_property(const std::shared_ptr<server::ConnectedClient> &client, bool channel_lock);
void enableCache(std::shared_ptr<server::ConnectedClient> client); void enableCache(const ClientDbId& /* client database id */); /* if this called disableCache(...) MUST be called to decrease the reference count */
void disableCache(const std::shared_ptr<server::ConnectedClient> &client); void disableCache(const ClientDbId& /* client database id */);
bool isClientCached(const std::shared_ptr<server::ConnectedClient> &client); bool isClientCached(const ClientDbId& /* client database id */);
void clearCache(); void clearCache();
bool isLocalGroup(std::shared_ptr<Group>); bool isLocalGroup(std::shared_ptr<Group>);
protected: protected:
void handleChannelDeleted(std::shared_ptr<BasicChannel> ); void handleChannelDeleted(const ChannelId& /* channel id */);
private: private:
std::shared_ptr<GroupManager> root = nullptr; std::shared_ptr<GroupManager> root = nullptr;
std::weak_ptr<server::TSServer> server; std::weak_ptr<server::TSServer> server;
@ -221,6 +231,6 @@ namespace ts {
int insertGroupFromDb(int count, char** values, char** column); int insertGroupFromDb(int count, char** values, char** column);
inline std::shared_ptr<CachedClient> resolveCached(ClientDbId cldbId); inline std::shared_ptr<CachedClient> resolve_cached_client(ClientDbId client_database_id);
}; };
} }

View File

@ -531,9 +531,9 @@ void ServerChannelTree::on_channel_entry_deleted(const shared_ptr<BasicChannel>
auto server = this->server.lock(); auto server = this->server.lock();
if(server) if(server)
server->getGroupManager()->handleChannelDeleted(channel); server->getGroupManager()->handleChannelDeleted(channel->channelId());
else else
serverInstance->getGroupManager()->handleChannelDeleted(channel); serverInstance->getGroupManager()->handleChannelDeleted(channel->channelId());
auto sql_result = sql::command(this->sql, "DELETE FROM `channels` WHERE `serverId` = '" + to_string(this->getServerId()) + "' AND `channelId` = '" + to_string(channel->channelId()) + "'").execute(); auto sql_result = sql::command(this->sql, "DELETE FROM `channels` WHERE `serverId` = '" + to_string(this->getServerId()) + "' AND `channelId` = '" + to_string(channel->channelId()) + "'").execute();

View File

@ -30,6 +30,7 @@
#include <misc/digest.h> #include <misc/digest.h>
#include <misc/rnd.h> #include <misc/rnd.h>
#include <misc/timer.h> #include <misc/timer.h>
#include <misc/scope_guard.h>
#include <bbcode/bbcodes.h> #include <bbcode/bbcodes.h>
namespace fs = std::experimental::filesystem; namespace fs = std::experimental::filesystem;
@ -184,8 +185,8 @@ CommandResult ConnectedClient::handleCommand(Command &cmd) {
else if (command == "servergroupdel") return this->handleCommandServerGroupDel(cmd); else if (command == "servergroupdel") return this->handleCommandServerGroupDel(cmd);
else if (command == "servergrouprename") return this->handleCommandServerGroupRename(cmd); else if (command == "servergrouprename") return this->handleCommandServerGroupRename(cmd);
else if (command == "servergroupclientlist") return this->handleCommandServerGroupClientList(cmd); else if (command == "servergroupclientlist") return this->handleCommandServerGroupClientList(cmd);
else if (command == "servergroupaddclient") return this->handleCommandServerGroupAddClient(cmd); else if (command == "servergroupaddclient" || command == "clientaddservergroup") return this->handleCommandServerGroupAddClient(cmd);
else if (command == "servergroupdelclient") return this->handleCommandServerGroupDelClient(cmd); else if (command == "servergroupdelclient" || command == "clientdelservergroup") return this->handleCommandServerGroupDelClient(cmd);
else if (command == "servergrouppermlist") return this->handleCommandServerGroupPermList(cmd); else if (command == "servergrouppermlist") return this->handleCommandServerGroupPermList(cmd);
else if (command == "servergroupaddperm") return this->handleCommandServerGroupAddPerm(cmd); else if (command == "servergroupaddperm") return this->handleCommandServerGroupAddPerm(cmd);
else if (command == "servergroupdelperm") return this->handleCommandServerGroupDelPerm(cmd); else if (command == "servergroupdelperm") return this->handleCommandServerGroupDelPerm(cmd);
@ -2668,39 +2669,107 @@ CommandResult ConnectedClient::handleCommandServerGroupAddClient(Command &cmd) {
CMD_RESET_IDLE; CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(25); CMD_CHK_AND_INC_FLOOD_POINTS(25);
auto server = cmd[0].has("sid") && cmd["sid"] == 0 ? nullptr : this->server; auto target_server = cmd[0].has("sid") && cmd["sid"] == 0 ? nullptr : this->server;
auto groupManager = server ? this->server->groups : serverInstance->getGroupManager().get(); auto group_manager = target_server ? this->server->groups : serverInstance->getGroupManager().get();
auto serverGroup = groupManager->findGroup(cmd["sgid"].as<GroupId>());
if (!serverGroup) return {findError("parameter_invalid"), "invalid server group id"};
if((server != this->server || !this->server) && serverGroup->target() != GroupTarget::GROUPTARGET_SERVER && serverGroup->type() != GroupType::GROUP_TYPE_QUERY) return {findError("parameter_invalid"), "invalid group type"};
auto target_cldbid = cmd["cldbid"].as<ClientDbId>(); auto target_cldbid = cmd["cldbid"].as<ClientDbId>();
{ if (!serverInstance->databaseHelper()->validClientDatabaseId(target_server, cmd["cldbid"])) return {findError("client_invalid_id"), "invalid cldbid"};
if(!serverGroup->permission_granted(permission::i_server_group_needed_member_add_power, this->calculate_permission_value(permission::i_server_group_member_add_power, -1), true)) {
if(target_cldbid != this->getClientDatabaseId())
return CommandResultPermissionError{permission::i_server_group_member_add_power};
if(!serverGroup->permission_granted(permission::i_server_group_needed_member_add_power, this->calculate_permission_value(permission::i_server_group_self_add_power, -1), true))
return CommandResultPermissionError{permission::i_server_group_self_add_power};
}
auto needed_client_permission = this->server->calculatePermission(permission::PERMTEST_ORDERED, target_cldbid, permission::i_client_needed_permission_modify_power, ClientType::CLIENT_TEAMSPEAK,nullptr); auto needed_client_permission = this->server->calculatePermission(permission::PERMTEST_ORDERED, target_cldbid, permission::i_client_needed_permission_modify_power, ClientType::CLIENT_TEAMSPEAK, nullptr);
if(needed_client_permission != permNotGranted) { if(needed_client_permission != permNotGranted) {
if(!this->permission_granted(this->permissionValue(permission::i_client_permission_modify_power), needed_client_permission)) if(!this->permission_granted(this->permissionValue(permission::i_client_permission_modify_power), needed_client_permission))
return CommandResultPermissionError{permission::i_client_needed_permission_modify_power}; return CommandResultPermissionError{permission::i_client_needed_permission_modify_power};
}
vector<std::shared_ptr<Group>> target_groups;
vector<std::shared_ptr<Group>> applied_groups;
target_groups.reserve(cmd.bulkCount());
auto continue_on_error = cmd.hasParm("continueonerror");
{
auto permission_add_power = this->calculate_permission_value(permission::i_server_group_member_add_power, -1);
auto permission_self_add_power = this->calculate_permission_value(permission::i_server_group_member_add_power, -1);
for(auto index = 0; index < cmd.bulkCount(); index++) {
auto group_id = cmd[index]["sgid"];
if(!group_id.castable<GroupId>() && continue_on_error)
continue;
auto gid = group_id.as<GroupId>();
auto group = group_manager->findGroup(gid);
if(!group) {
if(continue_on_error)
continue;
return {findError("parameter_invalid"), "missing server group for id " + to_string(gid)};
}
if(!target_server && group->target() != GroupTarget::GROUPTARGET_SERVER && group->type() != GroupType::GROUP_TYPE_QUERY)
return {findError("parameter_invalid"), "invalid server group type for id " + to_string(gid)};
if(find(target_groups.begin(), target_groups.end(), group) != target_groups.end()) {
if(continue_on_error)
continue;
return {findError("parameter_invalid"), "duplicate server group for id " + to_string(gid)};
}
/* permission tests */
if(!group->permission_granted(permission::i_server_group_needed_member_add_power, permission_add_power, true)) {
if(target_cldbid != this->getClientDatabaseId()) {
if(continue_on_error)
continue;
return CommandResultPermissionError{permission::i_server_group_member_add_power};
}
if(!group->permission_granted(permission::i_server_group_needed_member_add_power, permission_self_add_power, true)) {
if(continue_on_error)
continue;
return CommandResultPermissionError{permission::i_server_group_self_add_power};
}
}
target_groups.push_back(std::move(group));
} }
} }
if (!serverInstance->databaseHelper()->validClientDatabaseId(server, cmd["cldbid"])) return {findError("client_invalid_id"), "invalid cldbid"}; applied_groups.reserve(target_groups.size());
if(groupManager->hasServerGroupAssigned(cmd["cldbid"], serverGroup)) return {findError("parameter_invalid"), "Client is already member of this group"}; if(target_groups.empty()) return CommandResult::Success;
else if(target_groups.size() == 1) {
/* speed up thing, don't try to load any cache */
auto group = target_groups[0];
if(group_manager->hasServerGroupAssigned(target_cldbid, group))
return {findError("parameter_invalid"), "Client is already member of server group " + to_string(group->groupId())};
groupManager->addServerGroup(target_cldbid, serverGroup); group_manager->addServerGroup(target_cldbid, group);
applied_groups.push_back(group);
} else {
group_manager->enableCache(target_cldbid);
scope_exit_callback cache_disable{[group_manager, target_cldbid]{
group_manager->disableCache(target_cldbid);
}};
for(const auto& _server : server ? std::deque<shared_ptr<TSServer>>{server} : serverInstance->getVoiceServerManager()->serverInstances()) { for(const auto& group : target_groups) {
if(group_manager->hasServerGroupAssigned(target_cldbid, group)) {
if(continue_on_error)
continue;
return {findError("parameter_invalid"), "Client is already member of server group " + to_string(group->groupId())};
}
group_manager->addServerGroup(target_cldbid, group);
applied_groups.push_back(group);
}
}
for(const auto& _server : target_server ? std::deque<shared_ptr<TSServer>>{target_server} : serverInstance->getVoiceServerManager()->serverInstances()) {
for (const auto &targetClient : _server->findClientsByCldbId(target_cldbid)) { for (const auto &targetClient : _server->findClientsByCldbId(target_cldbid)) {
if (_server->notifyClientPropertyUpdates(targetClient, _server->groups->update_server_group_property(targetClient,true))) { if (_server->notifyClientPropertyUpdates(targetClient, _server->groups->update_server_group_property(targetClient, true))) {
for (const auto &client : _server->getClients()) { for (const auto &client : _server->getClients()) {
if(client->isClientVisible(targetClient, true) || client == targetClient) if(client->isClientVisible(targetClient, true) || client == targetClient)
client->notifyServerGroupClientAdd(_this.lock(), targetClient, serverGroup); for(const auto& group : applied_groups)
client->notifyServerGroupClientAdd(_this.lock(), targetClient, group);
} }
if(targetClient->update_cached_permissions()) /* update cached calculated permissions */ if(targetClient->update_cached_permissions()) /* update cached calculated permissions */
targetClient->sendNeededPermissions(false); /* cached permissions had changed, notify the client */ targetClient->sendNeededPermissions(false); /* cached permissions had changed, notify the client */
@ -2713,53 +2782,130 @@ CommandResult ConnectedClient::handleCommandServerGroupAddClient(Command &cmd) {
} }
CommandResult ConnectedClient::handleCommandServerGroupDelClient(Command &cmd) { CommandResult ConnectedClient::handleCommandServerGroupDelClient(Command &cmd) {
CMD_RESET_IDLE; CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(25); CMD_CHK_AND_INC_FLOOD_POINTS(25);
auto server = cmd[0].has("sid") && cmd["sid"] == 0 ? nullptr : this->server; auto target_server = cmd[0].has("sid") && cmd["sid"] == 0 ? nullptr : this->server;
auto groupManager = server ? this->server->groups : serverInstance->getGroupManager().get(); auto group_manager = target_server ? this->server->groups : serverInstance->getGroupManager().get();
auto serverGroup = groupManager->findGroup(cmd["sgid"].as<GroupId>());
if (!serverGroup) return {findError("parameter_invalid"), "invalid server group id"};
if((server != this->server || !this->server) && serverGroup->target() != GroupTarget::GROUPTARGET_SERVER && serverGroup->type() != GroupType::GROUP_TYPE_QUERY) return {findError("parameter_invalid"), "invalid group type"};
auto target_cldbid = cmd["cldbid"].as<ClientDbId>(); auto target_cldbid = cmd["cldbid"].as<ClientDbId>();
{ if (!serverInstance->databaseHelper()->validClientDatabaseId(target_server, cmd["cldbid"])) return {findError("client_invalid_id"), "invalid cldbid"};
if(!serverGroup->permission_granted(permission::i_server_group_needed_member_remove_power, this->calculate_permission_value(permission::i_server_group_member_remove_power, -1), true)) {
if(target_cldbid != this->getClientDatabaseId())
return CommandResultPermissionError{permission::i_server_group_member_remove_power};
if(!serverGroup->permission_granted(permission::i_server_group_needed_member_remove_power, this->calculate_permission_value(permission::i_server_group_self_remove_power, -1), true))
return CommandResultPermissionError{permission::i_server_group_self_remove_power};
}
auto needed_client_permission = this->server->calculatePermission(permission::PERMTEST_ORDERED, target_cldbid, permission::i_client_needed_permission_modify_power, ClientType::CLIENT_TEAMSPEAK,nullptr); auto needed_client_permission = this->server->calculatePermission(permission::PERMTEST_ORDERED, target_cldbid, permission::i_client_needed_permission_modify_power, ClientType::CLIENT_TEAMSPEAK, nullptr);
if(needed_client_permission != permNotGranted) { if(needed_client_permission != permNotGranted) {
if(!this->permission_granted(this->permissionValue(permission::i_client_permission_modify_power), needed_client_permission)) if(!this->permission_granted(this->permissionValue(permission::i_client_permission_modify_power), needed_client_permission))
return CommandResultPermissionError{permission::i_client_needed_permission_modify_power}; return CommandResultPermissionError{permission::i_client_needed_permission_modify_power};
}
vector<std::shared_ptr<Group>> target_groups;
vector<std::shared_ptr<Group>> applied_groups;
target_groups.reserve(cmd.bulkCount());
auto continue_on_error = cmd.hasParm("continueonerror");
{
auto permission_remove_power = this->calculate_permission_value(permission::i_server_group_member_remove_power, -1);
auto permission_self_remove_power = this->calculate_permission_value(permission::i_server_group_member_remove_power, -1);
for(auto index = 0; index < cmd.bulkCount(); index++) {
auto group_id = cmd[index]["sgid"];
if(!group_id.castable<GroupId>() && continue_on_error)
continue;
auto gid = group_id.as<GroupId>();
auto group = group_manager->findGroup(gid);
if(!group) {
if(continue_on_error)
continue;
return {findError("parameter_invalid"), "missing server group for id " + to_string(gid)};
}
if(!target_server && group->target() != GroupTarget::GROUPTARGET_SERVER && group->type() != GroupType::GROUP_TYPE_QUERY)
return {findError("parameter_invalid"), "invalid server group type for id " + to_string(gid)};
if(find(target_groups.begin(), target_groups.end(), group) != target_groups.end()) {
if(continue_on_error)
continue;
return {findError("parameter_invalid"), "duplicate server group for id " + to_string(gid)};
}
/* permission tests */
if(!group->permission_granted(permission::i_server_group_needed_member_remove_power, permission_remove_power, true)) {
if(target_cldbid != this->getClientDatabaseId()) {
if(continue_on_error)
continue;
return CommandResultPermissionError{permission::i_server_group_member_remove_power};
}
if(!group->permission_granted(permission::i_server_group_needed_member_remove_power, permission_self_remove_power, true)) {
if(continue_on_error)
continue;
return CommandResultPermissionError{permission::i_server_group_self_remove_power};
}
}
target_groups.push_back(std::move(group));
} }
} }
if (!serverInstance->databaseHelper()->validClientDatabaseId(server, cmd["cldbid"])) return {findError("client_invalid_id"), "invalid cldbid"}; applied_groups.reserve(target_groups.size());
if(!groupManager->hasServerGroupAssigned(cmd["cldbid"], serverGroup)) return {findError("parameter_invalid"), "Client isn't a member of this group"}; if(target_groups.empty()) return CommandResult::Success;
for(const auto& assignment : groupManager->listGroupAssignments(cmd["cldbid"])) else if(target_groups.size() == 1) {
if(assignment->group == serverGroup && assignment->server != this->getServerId()) return {findError("parameter_invalid"), "Group wasn't assigned over this server (Assigned server: " + to_string(assignment->server) + ")"}; /* speed up thing, don't try to load any cache */
auto group = target_groups[0];
auto assignment = group_manager->get_group_assignment(target_cldbid, group);
if(!assignment) {
return {findError("parameter_invalid"), "Client is not member of server group " + to_string(group->groupId())};
}
if(assignment->server != (target_server ? target_server->getServerId() : 0)) {
return {findError("parameter_invalid"), "Group assignment for group " + to_string(assignment->group->groupId()) + " hasn't been made over the target server. Assignment origin server id " + to_string(assignment->server)};
}
groupManager->removeServerGroup(target_cldbid, serverGroup); group_manager->removeServerGroup(target_cldbid, group);
applied_groups.push_back(group);
} else {
group_manager->enableCache(target_cldbid);
scope_exit_callback cache_disable{[group_manager, target_cldbid]{
group_manager->disableCache(target_cldbid);
}};
for(const auto& _server : server ? std::deque<shared_ptr<TSServer>>{server} : serverInstance->getVoiceServerManager()->serverInstances()) { for(const auto& group : target_groups) {
for (const auto &targetClient : _server->findClientsByCldbId(target_cldbid)) { auto assignment = group_manager->get_group_assignment(target_cldbid, group);
if (_server->notifyClientPropertyUpdates(targetClient, _server->groups->update_server_group_property(targetClient, true))) { if(!assignment) {
for (const auto &client : _server->getClients()) { if(continue_on_error)
if (client->isClientVisible(targetClient, true) || client == targetClient) continue;
client->notifyServerGroupClientRemove(_this.lock(), targetClient, serverGroup); return {findError("parameter_invalid"), "Client is not member of server group " + to_string(group->groupId())};
} }
if(targetClient->update_cached_permissions()) /* update cached calculated permissions */ if(assignment->server != (target_server ? target_server->getServerId() : 0)) {
targetClient->sendNeededPermissions(false); /* cached permissions had changed, notify the client */ if(continue_on_error)
targetClient->updateChannelClientProperties(true, true); continue;
} return {findError("parameter_invalid"), "Group assignment for group " + to_string(assignment->group->groupId()) + " hasn't been made over the target server. Assignment origin server id " + to_string(assignment->server)};
} }
}
return CommandResult::Success; applied_groups.push_back(group);
group_manager->removeServerGroup(target_cldbid, group);
}
}
for(const auto& _server : target_server ? std::deque<shared_ptr<TSServer>>{target_server} : serverInstance->getVoiceServerManager()->serverInstances()) {
for (const auto &targetClient : _server->findClientsByCldbId(target_cldbid)) {
if (_server->notifyClientPropertyUpdates(targetClient, _server->groups->update_server_group_property(targetClient, true))) {
for (const auto &client : _server->getClients()) {
if(client->isClientVisible(targetClient, true) || client == targetClient)
for(const auto& group : applied_groups)
client->notifyServerGroupClientRemove(_this.lock(), targetClient, group);
}
if(targetClient->update_cached_permissions()) /* update cached calculated permissions */
targetClient->sendNeededPermissions(false); /* cached permissions had changed, notify the client */
targetClient->updateChannelClientProperties(true, true);
}
}
}
return CommandResult::Success;
} }
CommandResult ConnectedClient::handleCommandServerGroupPermList(Command &cmd) { CommandResult ConnectedClient::handleCommandServerGroupPermList(Command &cmd) {

View File

@ -347,7 +347,7 @@ CommandResult SpeakingClient::handleCommandClientInit(Command& cmd) {
TIMING_START(timings); TIMING_START(timings);
if(!DatabaseHelper::assignDatabaseId(this->server->getSql(), this->server->getServerId(), _this.lock())) return {findError("vs_critical"), "Could not assign database id!"}; if(!DatabaseHelper::assignDatabaseId(this->server->getSql(), this->server->getServerId(), _this.lock())) return {findError("vs_critical"), "Could not assign database id!"};
TIMING_STEP(timings, "db assign "); TIMING_STEP(timings, "db assign ");
this->server->getGroupManager()->enableCache(_this.lock()); this->server->getGroupManager()->enableCache(this->getClientDatabaseId());
TIMING_STEP(timings, "gr cache "); TIMING_STEP(timings, "gr cache ");
const static vector<string> available_parameters = { const static vector<string> available_parameters = {
@ -716,7 +716,7 @@ void SpeakingClient::processLeave() {
unique_lock server_channel_lock(this->server->channel_tree_lock); unique_lock server_channel_lock(this->server->channel_tree_lock);
server->unregisterClient(ownLock, "disconnected", server_channel_lock); /* already moves client to void if needed */ server->unregisterClient(ownLock, "disconnected", server_channel_lock); /* already moves client to void if needed */
} }
server->groups->disableCache(ownLock); server->groups->disableCache(ownLock->getClientDatabaseId());
server->musicManager->cleanup_client_bots(this->getClientDatabaseId()); server->musicManager->cleanup_client_bots(this->getClientDatabaseId());
//ref_server = nullptr; Removed caused nullptr exceptions //ref_server = nullptr; Removed caused nullptr exceptions
} }

View File

@ -159,7 +159,7 @@ bool QueryClient::closeConnection(const std::chrono::system_clock::time_point& f
unique_lock channel_lock(this->server->channel_tree_lock); unique_lock channel_lock(this->server->channel_tree_lock);
this->server->unregisterClient(_this.lock(), "disconnected", channel_lock); this->server->unregisterClient(_this.lock(), "disconnected", channel_lock);
} }
this->server->groups->disableCache(_this.lock()); this->server->groups->disableCache(this->getClientDatabaseId());
this->server = nullptr; this->server = nullptr;
} }
@ -234,7 +234,7 @@ void QueryClient::disconnectFinal() {
unique_lock channel_lock(this->server->channel_tree_lock); unique_lock channel_lock(this->server->channel_tree_lock);
this->server->unregisterClient(_this.lock(), "disconnected", channel_lock); this->server->unregisterClient(_this.lock(), "disconnected", channel_lock);
} }
this->server->groups->disableCache(_this.lock()); this->server->groups->disableCache(this->getClientDatabaseId());
this->server = nullptr; this->server = nullptr;
} }

View File

@ -177,8 +177,8 @@ CommandResult QueryClient::handleCommandLogin(Command& cmd) {
this->server->client_move(this->ref(), nullptr, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, tree_lock); this->server->client_move(this->ref(), nullptr, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, tree_lock);
this->server->unregisterClient(_this.lock(), "login", tree_lock); this->server->unregisterClient(_this.lock(), "login", tree_lock);
} }
this->server->groups->disableCache(_this.lock()); this->server->groups->disableCache(this->getClientDatabaseId());
} else serverInstance->getGroupManager()->disableCache(_this.lock()); } else serverInstance->getGroupManager()->disableCache(this->getClientDatabaseId());
logMessage(LOG_QUERY, "Got new authenticated client. Username: {}, Unique-ID: {}, Bounded Server: {}", account->username, account->unique_id, account->bound_server); logMessage(LOG_QUERY, "Got new authenticated client. Username: {}, Unique-ID: {}, Bounded Server: {}", account->username, account->unique_id, account->bound_server);
@ -198,7 +198,7 @@ CommandResult QueryClient::handleCommandLogin(Command& cmd) {
DatabaseHelper::assignDatabaseId(this->sql, static_cast<ServerId>(target_server ? target_server->getServerId() : 0), _this.lock()); DatabaseHelper::assignDatabaseId(this->sql, static_cast<ServerId>(target_server ? target_server->getServerId() : 0), _this.lock());
if(target_server) { if(target_server) {
target_server->groups->enableCache(_this.lock()); target_server->groups->enableCache(this->getClientDatabaseId());
target_server->registerClient(_this.lock()); target_server->registerClient(_this.lock());
{ {
@ -221,7 +221,7 @@ CommandResult QueryClient::handleCommandLogin(Command& cmd) {
else else
this->update_cached_permissions(); this->update_cached_permissions();
} else { } else {
serverInstance->getGroupManager()->enableCache(_this.lock()); serverInstance->getGroupManager()->enableCache(this->getClientDatabaseId());
this->update_cached_permissions(); this->update_cached_permissions();
} }
@ -245,15 +245,15 @@ CommandResult QueryClient::handleCommandLogout(Command &) {
this->server->client_move(this->ref(), nullptr, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, tree_lock); this->server->client_move(this->ref(), nullptr, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, tree_lock);
this->server->unregisterClient(_this.lock(), "logout", tree_lock); this->server->unregisterClient(_this.lock(), "logout", tree_lock);
} }
this->server->groups->disableCache(_this.lock()); this->server->groups->disableCache(this->getClientDatabaseId());
} else serverInstance->getGroupManager()->disableCache(_this.lock()); } else serverInstance->getGroupManager()->disableCache(this->getClientDatabaseId());
this->properties()[property::CLIENT_UNIQUE_IDENTIFIER] = "UnknownQuery"; //TODO load from table this->properties()[property::CLIENT_UNIQUE_IDENTIFIER] = "UnknownQuery"; //TODO load from table
this->properties()[property::CLIENT_NICKNAME] = string() + "ServerQuery#" + this->getLoggingPeerIp() + "/" + to_string(ntohs(this->getPeerPort())); this->properties()[property::CLIENT_NICKNAME] = string() + "ServerQuery#" + this->getLoggingPeerIp() + "/" + to_string(ntohs(this->getPeerPort()));
DatabaseHelper::assignDatabaseId(this->sql, static_cast<ServerId>(this->server ? this->server->getServerId() : 0), _this.lock()); DatabaseHelper::assignDatabaseId(this->sql, static_cast<ServerId>(this->server ? this->server->getServerId() : 0), _this.lock());
if(this->server){ if(this->server){
this->server->groups->enableCache(_this.lock()); this->server->groups->enableCache(this->getClientDatabaseId());
this->server->registerClient(this->ref()); this->server->registerClient(this->ref());
{ {
@ -274,7 +274,7 @@ CommandResult QueryClient::handleCommandLogout(Command &) {
this->update_cached_permissions(); this->update_cached_permissions();
} }
} else { } else {
serverInstance->getGroupManager()->enableCache(_this.lock()); serverInstance->getGroupManager()->enableCache(this->getClientDatabaseId());
this->update_cached_permissions(); this->update_cached_permissions();
} }
@ -322,10 +322,10 @@ CommandResult QueryClient::handleCommandServerSelect(Command &cmd) {
this->server->client_move(this->ref(), nullptr, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, tree_lock); this->server->client_move(this->ref(), nullptr, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, tree_lock);
this->server->unregisterClient(_this.lock(), "server switch", tree_lock); this->server->unregisterClient(_this.lock(), "server switch", tree_lock);
} }
server_locked->groups->disableCache(_this.lock()); server_locked->groups->disableCache(this->getClientDatabaseId());
this->channels->reset(); this->channels->reset();
} else } else
serverInstance->getGroupManager()->disableCache(_this.lock()); serverInstance->getGroupManager()->disableCache(this->getClientDatabaseId());
} }
this->resetEventMask(); this->resetEventMask();
@ -341,7 +341,7 @@ CommandResult QueryClient::handleCommandServerSelect(Command &cmd) {
DatabaseHelper::assignDatabaseId(this->sql, static_cast<ServerId>(this->server ? this->server->getServerId() : 0), _this.lock()); DatabaseHelper::assignDatabaseId(this->sql, static_cast<ServerId>(this->server ? this->server->getServerId() : 0), _this.lock());
if(this->server) { if(this->server) {
this->server->groups->enableCache(_this.lock()); this->server->groups->enableCache(this->getClientDatabaseId());
this->server->registerClient(_this.lock()); this->server->registerClient(_this.lock());
{ {
@ -359,7 +359,7 @@ CommandResult QueryClient::handleCommandServerSelect(Command &cmd) {
else else
this->update_cached_permissions(); this->update_cached_permissions();
} else { } else {
serverInstance->getGroupManager()->enableCache(_this.lock()); serverInstance->getGroupManager()->enableCache(this->getClientDatabaseId());
this->update_cached_permissions(); this->update_cached_permissions();
} }
this->updateChannelClientProperties(true, true); this->updateChannelClientProperties(true, true);

View File

@ -181,7 +181,7 @@ bool WebClient::closeConnection(const std::chrono::system_clock::time_point& tim
unique_lock server_channel_lock(this->server->channel_tree_lock); unique_lock server_channel_lock(this->server->channel_tree_lock);
this->server->unregisterClient(_this.lock(), "disconnected", server_channel_lock); this->server->unregisterClient(_this.lock(), "disconnected", server_channel_lock);
} }
this->server->groups->disableCache(_this.lock()); this->server->groups->disableCache(this->getClientDatabaseId());
//this->server = nullptr; //this->server = nullptr;
} }

View File

@ -83,7 +83,7 @@ std::shared_ptr<server::MusicClient> MusicBotManager::createBot(ClientDbId owner
(LOG_SQL_CMD)(sql::command(handle->getSql(), "INSERT INTO `musicbots` (`serverId`, `botId`, `uniqueId`, `owner`) VALUES (:sid, :botId, :uid, :owner)", (LOG_SQL_CMD)(sql::command(handle->getSql(), "INSERT INTO `musicbots` (`serverId`, `botId`, `uniqueId`, `owner`) VALUES (:sid, :botId, :uid, :owner)",
variable{":sid", handle->getServerId()}, variable{":botId", musicBot->getClientDatabaseId()}, variable{":uid", musicBot->getUid()}, variable{":owner", owner}).execute()); variable{":sid", handle->getServerId()}, variable{":botId", musicBot->getClientDatabaseId()}, variable{":uid", musicBot->getUid()}, variable{":owner", owner}).execute());
musicBot->properties()[property::CLIENT_OWNER] = owner; musicBot->properties()[property::CLIENT_OWNER] = owner;
handle->groups->enableCache(musicBot); handle->groups->enableCache(musicBot->getClientDatabaseId());
musicBot->setDisplayName("Im a music bot!"); musicBot->setDisplayName("Im a music bot!");
musicBot->properties()[property::CLIENT_LASTCONNECTED] = duration_cast<seconds>(system_clock::now().time_since_epoch()).count(); musicBot->properties()[property::CLIENT_LASTCONNECTED] = duration_cast<seconds>(system_clock::now().time_since_epoch()).count();
musicBot->properties()[property::CLIENT_CREATED] = duration_cast<seconds>(system_clock::now().time_since_epoch()).count(); musicBot->properties()[property::CLIENT_CREATED] = duration_cast<seconds>(system_clock::now().time_since_epoch()).count();
@ -139,7 +139,7 @@ void MusicBotManager::deleteBot(std::shared_ptr<server::MusicClient> musicBot) {
handle->client_move(musicBot, nullptr, nullptr, "Music bot deleted", ViewReasonId::VREASON_SERVER_LEFT, true, server_channel_lock); handle->client_move(musicBot, nullptr, nullptr, "Music bot deleted", ViewReasonId::VREASON_SERVER_LEFT, true, server_channel_lock);
handle->unregisterClient(musicBot, "bot deleted", server_channel_lock); handle->unregisterClient(musicBot, "bot deleted", server_channel_lock);
} }
handle->groups->disableCache(musicBot); handle->groups->disableCache(musicBot->getClientDatabaseId());
serverInstance->databaseHelper()->deleteClient(handle, musicBot->getClientDatabaseId()); serverInstance->databaseHelper()->deleteClient(handle, musicBot->getClientDatabaseId());
serverInstance->databaseHelper()->deleteClient(nullptr, musicBot->getClientDatabaseId()); serverInstance->databaseHelper()->deleteClient(nullptr, musicBot->getClientDatabaseId());
@ -233,7 +233,7 @@ int MusicBotManager::sqlCreateMusicBot(int length, std::string* values, std::str
musicBot->properties()[property::CLIENT_LASTCONNECTED] = duration_cast<seconds>(system_clock::now().time_since_epoch()).count(); musicBot->properties()[property::CLIENT_LASTCONNECTED] = duration_cast<seconds>(system_clock::now().time_since_epoch()).count();
} }
handle->groups->enableCache(musicBot); handle->groups->enableCache(musicBot->getClientDatabaseId());
if(musicBot->getClientDatabaseId() != botId) logCritical("Invalid music bot id mapping!"); if(musicBot->getClientDatabaseId() != botId) logCritical("Invalid music bot id mapping!");
{ {

View File

@ -45,9 +45,9 @@ void QueryServer::unregisterConnection(const shared_ptr<QueryClient> &client) {
} }
if(client->server) { if(client->server) {
client->server->getGroupManager()->disableCache(client); client->server->getGroupManager()->disableCache(client->getClientDatabaseId());
} else { } else {
serverInstance->getGroupManager()->disableCache(client); serverInstance->getGroupManager()->disableCache(client->getClientDatabaseId());
} }
/* client->handle = nullptr; */ /* client->handle = nullptr; */
} }

2
shared

@ -1 +1 @@
Subproject commit a086dcc214fe4ea7a983fecebb93b8e2fe3258ff Subproject commit 4a9d8f132fe9ca3411e2e3c245922ad778c56aa0