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
+136 -161
View File
@@ -171,7 +171,7 @@ int GroupManager::insertGroupFromDb(int count, char **values, char **column) {
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 + "')");
return 0;
}
@@ -225,11 +225,15 @@ int GroupManager::insertGroupFromDb(int count, char **values, char **column) {
return 0;
}
void GroupManager::handleChannelDeleted(std::shared_ptr<BasicChannel> channel) {
cacheLock.lock();
for(const auto &entry : this->cachedClients)
entry->channelGroups.erase(channel->channelId());
cacheLock.unlock();
void GroupManager::handleChannelDeleted(const ChannelId& channel_id) {
unique_lock cache_lock(this->cacheLock);
auto cached_clients = std::vector<shared_ptr<CachedClient>>{this->cachedClients.begin(), this->cachedClients.end()};
cache_lock.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) {
@@ -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 `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) {
threads::MutexLock lock_entry(entry->lock);
bool iterate = true;
while(iterate) {
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());
lock_guard entry_lock(entry->lock);
entry->server_groups.clear();
entry->channel_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));
/* 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;
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);
@@ -418,33 +428,6 @@ bool GroupManager::deleteGroup(std::shared_ptr<Group> group) {
if(flag_sql)
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;
}
@@ -515,95 +498,93 @@ void GroupManager::cleanupAssignments(ClientDbId client) {
}
}
template <typename DataType>
struct DBLoadCacheParmStruct {
GroupManager* manager;
DataType* data;
};
void GroupManager::enableCache(std::shared_ptr<server::ConnectedClient> client) {
void GroupManager::enableCache(const ClientDbId& client_database_id) {
if(this->root)
this->root->enableCache(client);
this->root->enableCache(client_database_id);
shared_ptr<CachedClient> entry = std::make_shared<CachedClient>();
entry->client = client;
unique_lock cache_lock(this->cacheLock);
/* 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;
time_point<system_clock> until;
ChannelId channelId = 0;
for(int index = 0; index < length; index++){
if(value[index] == nullptr) {
logError(this->getServerId(), string() + "Invalid value at " + column[index]);
continue;
try {
if(column[index] == "groupId"){
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)
return 0;
if(!group) {
return 0;
}
shared_ptr<GroupAssignment> assignment = std::make_shared<GroupAssignment>();
auto assignment = std::make_shared<GroupAssignment>();
assignment->group = group;
assignment->until = until;
assignment->parent = parms->data;
assignment->parent = &*entry;
assignment->channelId = channelId;
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();
this->cachedClients.push_back(entry);
this->cacheLock.unlock();
if(channelId == 0)
entry->server_groups.push_back(assignment);
else
entry->channel_groups[channelId] = assignment;
return 0;
});
}
void GroupManager::disableCache(const shared_ptr<ConnectedClient> &client) {
if(this->root) this->root->disableCache(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
void GroupManager::disableCache(const ClientDbId& client_database_id) {
if(this->root)
this->root->disableCache(client_database_id);
threads::MutexLock lock(this->cacheLock);
bool found = false;
for(const auto& entry : this->cachedClients){
if(entry->client == client){
this->cachedClients.erase(std::find(this->cachedClients.begin(), this->cachedClients.end(), entry));
found = true;
break;
}
}
if(!found)
;//debugMessage("Tried to attempt to delete a not existing cached manager. (" + manager->getDisplayName() + ")");
lock_guard cache_lock(this->cacheLock);
this->cachedClients.erase(std::remove_if(this->cachedClients.begin(), this->cachedClients.end(), [&](const std::shared_ptr<CachedClient>& client) {
if(client->client_database_id != client_database_id)
return false;
lock_guard client_lock{client->lock};
return (--client->use_count) == 0;
}), this->cachedClients.end());
}
void GroupManager::clearCache() {
if(this->root) this->root->clearCache();
threads::MutexLock lock(cacheLock);
lock_guard lock(this->cacheLock);
this->cachedClients.clear();
}
bool GroupManager::isClientCached(const shared_ptr<ConnectedClient> &client) {
{
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;
bool GroupManager::isClientCached(const ClientDbId& client_database_id) {
return this->resolve_cached_client(client_database_id) == nullptr;
}
typedef std::vector<std::shared_ptr<GroupMember>> ResList;
@@ -644,19 +625,17 @@ std::vector<std::shared_ptr<GroupMember>> GroupManager::listGroupMembers(std::sh
return result;
}
typedef DBLoadCacheParmStruct<vector<std::shared_ptr<GroupAssignment>>> GAGroupCache;
vector<shared_ptr<GroupAssignment>> GroupManager::listGroupAssignments(ClientDbId cldbId) {
vector<std::shared_ptr<GroupAssignment>> result;
GAGroupCache parm = {this, &result};
sql::result res;
auto cached = resolveCached(cldbId);
auto cached = resolve_cached_client(cldbId);
if(cached) {
{
threads::MutexLock l(cached->lock);
for(const auto &serverGroup : cached->serverGroups)
lock_guard lock{cached->lock};
for(const auto &serverGroup : cached->server_groups)
result.push_back(serverGroup);
for(auto& channelGroup : cached->channelGroups)
for(auto& channelGroup : cached->channel_groups)
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;
time_point<system_clock> until;
uint64_t channelId = 0;
@@ -681,7 +661,7 @@ vector<shared_ptr<GroupAssignment>> GroupManager::listGroupAssignments(ClientDbI
continue;
}
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){
until = time_point<system_clock>() + milliseconds(stoll(value[index]));
} else if(strcmp(column[index], "channelId") == 0){
@@ -697,9 +677,9 @@ vector<shared_ptr<GroupAssignment>> GroupManager::listGroupAssignments(ClientDbI
assignment->until = until;
assignment->channelId = channelId;
assignment->server = this->getServerId();
parms->data->push_back(assignment);
result.push_back(assignment);
return 0;
}, &parm);
});
(LOG_SQL_CMD)(res);
if(this->root){
@@ -711,18 +691,19 @@ vector<shared_ptr<GroupAssignment>> GroupManager::listGroupAssignments(ClientDbI
return result;
}
std::shared_ptr<CachedClient> GroupManager::resolveCached(ClientDbId cldbId) {
threads::MutexLock lock(this->cacheLock);
for(const auto& cl : this->cachedClients)
if(cl->client->getClientDatabaseId() == cldbId){
return cl;
}
return nullptr;
std::shared_ptr<CachedClient> GroupManager::resolve_cached_client(ClientDbId client_database_id) {
{
lock_guard lock(this->cacheLock);
for(auto& entry : this->cachedClients)
if(entry->client_database_id == client_database_id)
return entry;
}
return nullptr;
}
typedef DBLoadCacheParmStruct<std::vector<std::shared_ptr<GroupAssignment>>> SGroupCache;
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;
std::vector<std::shared_ptr<GroupAssignment>> result;
if(this->root) {
@@ -730,17 +711,15 @@ std::vector<std::shared_ptr<GroupAssignment>> GroupManager::getAssignedServerGro
result.insert(result.begin(), root.begin(), root.end());
}
SGroupCache parm = {this, &result};
if(cached) {
threads::MutexLock l(cached->lock);
for(const auto &elm : cached->serverGroups) result.push_back(elm);
lock_guard cache_lock{cached->lock};
result.insert(result.end(), cached->server_groups.begin(), cached->server_groups.end());
return result;
}
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;
time_point<system_clock> until;
@@ -750,7 +729,7 @@ std::vector<std::shared_ptr<GroupAssignment>> GroupManager::getAssignedServerGro
continue;
}
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){
until = time_point<system_clock>() + milliseconds(stoll(value[index] == nullptr ? "0" : value[index]));
} else cerr << "Invalid column " << column[index] << endl;
@@ -763,9 +742,9 @@ std::vector<std::shared_ptr<GroupAssignment>> GroupManager::getAssignedServerGro
assignment->group = group;
assignment->until = until;
assignment->server = this->getServerId();
parms->data->push_back(assignment);
result.push_back(assignment);
return 0;
}, &parm);
});
LOG_SQL_CMD(res);
return result;
}
@@ -799,20 +778,18 @@ std::vector<std::shared_ptr<GroupAssignment>> GroupManager::defaultServerGroupGr
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) {
auto cached = resolveCached(cldbId);
auto cached = resolve_cached_client(cldbId);
if(cached) {
threads::MutexLock l(cached->lock);
if(cached->channelGroups.count(channel->channelId()) > 0) {
return cached->channelGroups[channel->channelId()];
lock_guard cache_lock(cached->lock);
if(cached->channel_groups.count(channel->channelId()) > 0) {
return cached->channel_groups[channel->channelId()];
} else
return assign_default ? this->defaultChannelGroupAssignment(cldbId, channel) : nullptr;
}
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([&](CGroupCache* parms, 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([&](int length, char** value, char** column){
shared_ptr<Group> group = nullptr;
time_point<system_clock> until;
@@ -822,7 +799,7 @@ std::shared_ptr<GroupAssignment> GroupManager::getChannelGroupExact(ClientDbId c
continue;
}
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){
until = time_point<system_clock>() + milliseconds(stoll(value[index]));
} else cerr << "Invalid column " << column[index] << endl;
@@ -836,9 +813,9 @@ std::shared_ptr<GroupAssignment> GroupManager::getChannelGroupExact(ClientDbId c
assignment->until = until;
assignment->server = this->getServerId();
assignment->channelId = channel->channelId();
*parms->data = assignment;
result = std::move(assignment);
return 0;
}, &parm);
});
(LOG_SQL_CMD)(res);
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;
*/
auto cached = resolveCached(cldbId);
auto cached = resolve_cached_client(cldbId);
if(cached) {
threads::MutexLock l(cached->lock);
cached->serverGroups.push_back(std::make_shared<GroupAssignment>(cached.get(), this->getServerId(), 0, group, until));
lock_guard cache_lock(cached->lock);
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)",
@@ -890,14 +867,12 @@ void GroupManager::addServerGroup(ClientDbId cldbId, std::shared_ptr<Group> grou
void GroupManager::removeServerGroup(ClientDbId cldbId, std::shared_ptr<Group> group) {
if(!this->hasServerGroupAssigned(cldbId, group)) return;
auto cached = resolveCached(cldbId);
auto cached = resolve_cached_client(cldbId);
if(cached) {
threads::MutexLock l(cached->lock);
for(const auto &entry : cached->serverGroups)
if(entry->group == group){
cached->serverGroups.erase(std::find(cached->serverGroups.begin(), cached->serverGroups.end(), entry));
break;
}
lock_guard cache_lock(cached->lock);
cached->server_groups.erase(std::remove_if(cached->server_groups.begin(), cached->server_groups.end(), [&](const std::shared_ptr<GroupAssignment>& group_assignment) {
return group_assignment->group == group;
}), cached->server_groups.end());
}
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;
auto default_group = !group || group == this->defaultGroup(GroupTarget::GROUPTARGET_CHANNEL);
auto cached = resolveCached(cldbId);
auto cached = resolve_cached_client(cldbId);
if(cached) {
threads::MutexLock l(cached->lock);
lock_guard cache_lock(cached->lock);
if(default_group)
cached->channelGroups.erase(channel->channelId());
cached->channel_groups.erase(channel->channelId());
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",