File indexing completed on 2024-05-05 05:40:31
0001 /************************************************************************* 0002 * Copyright (C) 2018 by Renaud Guezennec * 0003 * * 0004 * https://rolisteam.org/ * 0005 * * 0006 * Rolisteam is free software; you can redistribute it and/or modify * 0007 * it under the terms of the GNU General Public License as published * 0008 * by the Free Software Foundation; either version 2 of the License, * 0009 * or (at your option) any later version. * 0010 * * 0011 * This program is distributed in the hope that it will be useful, * 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0014 * GNU General Public License for more details. * 0015 * * 0016 * You should have received a copy of the GNU General Public License * 0017 * along with this program; if not, write to the * 0018 * Free Software Foundation, Inc., * 0019 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 0020 *************************************************************************/ 0021 0022 #include "network/channel.h" 0023 #include "network/serverconnection.h" 0024 0025 Channel::Channel() {} 0026 0027 Channel::Channel(QString str) 0028 { 0029 m_name= str; 0030 } 0031 0032 Channel::~Channel() {} 0033 0034 QByteArray Channel::password() const 0035 { 0036 return m_password; 0037 } 0038 0039 void Channel::setPassword(const QByteArray& password) 0040 { 0041 m_password= password; 0042 } 0043 0044 int Channel::childCount() const 0045 { 0046 return m_child.size(); 0047 } 0048 0049 int Channel::indexOf(TreeItem* child) 0050 { 0051 return m_child.indexOf(child); 0052 } 0053 0054 QString Channel::description() const 0055 { 0056 return m_description; 0057 } 0058 0059 void Channel::setDescription(const QString& description) 0060 { 0061 m_description= description; 0062 } 0063 0064 bool Channel::usersListed() const 0065 { 0066 return m_usersListed; 0067 } 0068 0069 void Channel::setUsersListed(bool usersListed) 0070 { 0071 m_usersListed= usersListed; 0072 } 0073 0074 bool Channel::isLeaf() const 0075 { 0076 return false; 0077 } 0078 0079 TreeItem* Channel::getChildAt(int row) 0080 { 0081 if(m_child.isEmpty()) 0082 return nullptr; 0083 if(m_child.size() > row) 0084 { 0085 return m_child.at(row); 0086 } 0087 return nullptr; 0088 } 0089 0090 const QList<QPointer<TreeItem>> Channel::childrenItem() const 0091 { 0092 return m_child; 0093 } 0094 0095 void Channel::sendMessage(NetworkMessage* msg, ServerConnection* emitter, bool mustBeSaved) 0096 { 0097 if(msg->getRecipientMode() == NetworkMessage::All) 0098 { 0099 sendToAll(msg, emitter); 0100 if(mustBeSaved) 0101 { 0102 m_dataToSend.append(msg); 0103 setMemorySize(m_memorySize + msg->getSize()); 0104 } 0105 } 0106 else if(msg->getRecipientMode() == NetworkMessage::OneOrMany) 0107 { 0108 sendToMany(msg, emitter); 0109 } 0110 } 0111 void Channel::sendToMany(NetworkMessage* msg, ServerConnection* tcp, bool deleteMsg) 0112 { 0113 auto const recipient= msg->getRecipientList(); 0114 int i= 0; 0115 for(auto& client : m_child) 0116 { 0117 auto other= dynamic_cast<ServerConnection*>(client.data()); 0118 0119 if((nullptr != other) && (other != tcp) && (recipient.contains(other->uuid()))) 0120 { 0121 bool b= false; 0122 if(i + 1 == recipient.size()) 0123 b= deleteMsg; 0124 0125 QMetaObject::invokeMethod(other, "sendMessage", Qt::QueuedConnection, Q_ARG(NetworkMessage*, msg), 0126 Q_ARG(bool, b)); 0127 ++i; 0128 } 0129 } 0130 } 0131 0132 void Channel::sendToAll(NetworkMessage* msg, ServerConnection* tcp, bool deleteMsg) 0133 { 0134 int i= 0; 0135 for(auto& client : m_child) 0136 { 0137 ServerConnection* other= dynamic_cast<ServerConnection*>(client.data()); 0138 if((nullptr != other) && (other != tcp)) 0139 { 0140 bool b= false; 0141 if(i + 1 == m_child.size()) 0142 b= deleteMsg; // TODO Copy message 0143 0144 QMetaObject::invokeMethod(other, "sendMessage", Qt::QueuedConnection, Q_ARG(NetworkMessage*, msg), 0145 Q_ARG(bool, b)); 0146 } 0147 0148 ++i; 0149 } 0150 } 0151 0152 bool Channel::contains(QString id) 0153 { 0154 auto dupplicate= std::find_if(m_child.begin(), m_child.end(), [id](TreeItem* item) { return item->uuid() == id; }); 0155 0156 return dupplicate != m_child.end(); 0157 } 0158 0159 int Channel::addChild(TreeItem* item) 0160 { 0161 if(nullptr == item) 0162 return -1; 0163 0164 m_child.append(item); 0165 item->uuid(); 0166 item->setParentItem(this); 0167 0168 auto result= m_child.size(); 0169 0170 if(item->isLeaf()) 0171 { 0172 QPointer<ServerConnection> tcp= dynamic_cast<ServerConnection*>(item); 0173 QPointer<TreeItem> itemp= item; 0174 if(tcp.isNull()) 0175 return result; 0176 0177 connect(tcp, &ServerConnection::clientSaysGoodBye, this, [this, itemp, tcp](const QString& playerId) { 0178 qDebug() << itemp->uuid() << playerId << "say good bye - debug"; 0179 if(m_child.isEmpty() || itemp.isNull()) 0180 return; 0181 m_child.removeAll(itemp); 0182 if(m_child.isEmpty()) 0183 return; 0184 qInfo() << QStringLiteral("Client left from channel"); 0185 removeClient(tcp); 0186 }); 0187 0188 // TODO make this connection as oneshot 0189 connect(tcp, &ServerConnection::playerInfoDefined, this, [this, tcp]() { updateNewClient(tcp); }); 0190 if(tcp->isGM()) 0191 { 0192 if(m_currentGm == nullptr) 0193 setCurrentGM(tcp); 0194 sendOffGmStatus(tcp); 0195 } 0196 } 0197 else 0198 { 0199 auto chan= dynamic_cast<Channel*>(item); 0200 if(nullptr == chan) 0201 return result; 0202 0203 connect(chan, &Channel::memorySizeChanged, this, &Channel::memorySizeChanged); 0204 } 0205 return result; 0206 } 0207 0208 bool Channel::addChildInto(QString id, TreeItem* child) 0209 { 0210 if(m_id == id) 0211 { 0212 addChild(child); 0213 return true; 0214 } 0215 else 0216 { 0217 for(auto& item : m_child) 0218 { 0219 if(item->addChildInto(id, child)) 0220 { 0221 return true; 0222 } 0223 } 0224 } 0225 return false; 0226 } 0227 0228 void Channel::updateNewClient(ServerConnection* newComer) 0229 { 0230 NetworkMessageWriter* msg1= new NetworkMessageWriter(NetMsg::AdministrationCategory, NetMsg::ClearTable); 0231 msg1->string8(newComer->uuid()); 0232 QMetaObject::invokeMethod(newComer, "sendMessage", Qt::QueuedConnection, Q_ARG(NetworkMessage*, msg1), 0233 Q_ARG(bool, true)); 0234 // Sending players infos 0235 for(auto& child : m_child) 0236 { 0237 if(!child->isLeaf()) 0238 continue; 0239 0240 ServerConnection* tcpConnection= dynamic_cast<ServerConnection*>(child.data()); 0241 if(nullptr == tcpConnection) 0242 continue; 0243 0244 if(tcpConnection == newComer || !tcpConnection->isFullyDefined()) 0245 continue; 0246 0247 NetworkMessageWriter* msg= new NetworkMessageWriter(NetMsg::UserCategory, NetMsg::PlayerConnectionAction); 0248 tcpConnection->fill(msg); 0249 QMetaObject::invokeMethod(newComer, "sendMessage", Qt::QueuedConnection, Q_ARG(NetworkMessage*, msg), 0250 Q_ARG(bool, true)); 0251 0252 NetworkMessageWriter* msg2= new NetworkMessageWriter(NetMsg::UserCategory, NetMsg::PlayerConnectionAction); 0253 newComer->fill(msg2); 0254 QMetaObject::invokeMethod(tcpConnection, "sendMessage", Qt::QueuedConnection, Q_ARG(NetworkMessage*, msg2), 0255 Q_ARG(bool, true)); 0256 } 0257 // resend all previous data received 0258 for(auto& msg : m_dataToSend) 0259 { 0260 // tcp->sendMessage(msg); 0261 QMetaObject::invokeMethod(newComer, "sendMessage", Qt::QueuedConnection, Q_ARG(NetworkMessage*, msg), 0262 Q_ARG(bool, false)); 0263 } 0264 } 0265 0266 void Channel::kick(const QString& str, bool isAdmin, const QString& sourceId) 0267 { 0268 if(!isAdmin && sourceId.isEmpty()) 0269 return; 0270 0271 bool hasRightToKick= isAdmin; 0272 QPointer<TreeItem> toKick; 0273 for(auto& item : m_child) 0274 { 0275 if(item == nullptr) 0276 continue; 0277 if(!hasRightToKick && item->uuid() == sourceId) 0278 { 0279 ServerConnection* source= dynamic_cast<ServerConnection*>(toKick.data()); 0280 if(source) 0281 hasRightToKick= source->isGM(); 0282 } 0283 if(item->uuid() == str) 0284 { 0285 toKick= item; 0286 } 0287 } 0288 0289 if(!hasRightToKick || toKick.isNull()) 0290 return; 0291 0292 if(m_child.removeAll(toKick) == 0) 0293 return; 0294 0295 emit itemChanged(); 0296 0297 ServerConnection* client= dynamic_cast<ServerConnection*>(toKick.data()); 0298 if(nullptr == client) 0299 return; 0300 0301 removeClient(client); 0302 QMetaObject::invokeMethod(client, "closeConnection", Qt::QueuedConnection); 0303 0304 // NOTE - could be useless 0305 for(auto& item : m_child) 0306 { 0307 item->kick(str, isAdmin, sourceId); 0308 } 0309 } 0310 0311 void Channel::clear() 0312 { 0313 for(auto& item : m_child) 0314 { 0315 item->clear(); 0316 } 0317 qDeleteAll(m_child); 0318 m_child.clear(); 0319 } 0320 TreeItem* Channel::getChildById(QString id) 0321 { 0322 for(auto& item : m_child) 0323 { 0324 if(item.isNull()) 0325 continue; 0326 0327 if(item->uuid() == id) 0328 { 0329 return item; 0330 } 0331 else 0332 { 0333 auto itemChild= item->getChildById(id); 0334 if(nullptr != itemChild) 0335 { 0336 return itemChild; 0337 } 0338 } 0339 } 0340 return nullptr; 0341 } 0342 0343 ServerConnection* Channel::getClientById(QString id) 0344 { 0345 ServerConnection* result= nullptr; 0346 for(auto& item : m_child) 0347 { 0348 if(nullptr == item) 0349 continue; 0350 0351 if(item->isLeaf()) 0352 { 0353 auto client= dynamic_cast<ServerConnection*>(item.data()); 0354 if(client->uuid() == id) 0355 { 0356 result= client; 0357 } 0358 } 0359 else 0360 { 0361 auto channel= dynamic_cast<Channel*>(item.data()); 0362 if(nullptr != channel) 0363 { 0364 result= channel->getClientById(id); 0365 } 0366 } 0367 if(result != nullptr) 0368 break; 0369 } 0370 return result; 0371 } 0372 0373 bool Channel::removeClient(ServerConnection* client) 0374 { 0375 if(!client) 0376 return false; 0377 0378 // must be the first line 0379 int i= m_child.removeAll(client); 0380 if(i == 0) 0381 { 0382 return false; 0383 } 0384 0385 disconnect(client); 0386 0387 // notify all remaining chan member to remove former player 0388 NetworkMessageWriter* message= new NetworkMessageWriter(NetMsg::UserCategory, NetMsg::DelPlayerAction); 0389 message->string8(client->playerId()); 0390 sendMessage(message, nullptr, false); 0391 0392 if(hasNoClient()) 0393 { 0394 clearData(); 0395 } 0396 if((m_currentGm != nullptr) && (m_currentGm == client)) 0397 { 0398 findNewGM(); 0399 } 0400 0401 emit itemChanged(); 0402 return (0 < i); 0403 } 0404 0405 void Channel::clearData() 0406 { 0407 m_dataToSend.clear(); 0408 setMemorySize(0); 0409 } 0410 0411 bool Channel::removeChild(TreeItem* itm) 0412 { 0413 if(itm->isLeaf()) 0414 { 0415 return removeClient(static_cast<ServerConnection*>(itm)); 0416 } 0417 else 0418 { 0419 if(itm->childCount() == 0) 0420 { 0421 m_child.removeAll(itm); 0422 return true; 0423 } 0424 } 0425 return false; 0426 } 0427 0428 bool Channel::hasNoClient() 0429 { 0430 bool hasNoClient= true; 0431 for(auto& child : m_child) 0432 { 0433 if(child->isLeaf()) 0434 { 0435 hasNoClient= false; 0436 } 0437 } 0438 return hasNoClient; 0439 } 0440 0441 void Channel::sendOffGmStatus(ServerConnection* client) 0442 { 0443 if(nullptr == client) 0444 return; 0445 0446 bool isRealGM= (m_currentGm == client); 0447 0448 NetworkMessageWriter* message= new NetworkMessageWriter(NetMsg::AdministrationCategory, NetMsg::GMStatus); 0449 QStringList idList; 0450 idList << client->playerId(); 0451 message->setRecipientList(idList, NetworkMessage::OneOrMany); 0452 message->int8(static_cast<qint8>(isRealGM)); 0453 sendToMany(message, nullptr); 0454 } 0455 void Channel::findNewGM() 0456 { 0457 auto result= std::find_if(m_child.begin(), m_child.end(), [=](QPointer<TreeItem>& item) { 0458 auto client= dynamic_cast<ServerConnection*>(item.data()); 0459 if(nullptr != client) 0460 { 0461 if(client->isGM()) 0462 { 0463 return true; 0464 } 0465 } 0466 return false; 0467 }); 0468 0469 if(result == m_child.end()) 0470 setCurrentGM(nullptr); 0471 else 0472 setCurrentGM(dynamic_cast<ServerConnection*>(result->data())); 0473 0474 sendOffGmStatus(m_currentGm); 0475 } 0476 0477 ServerConnection* Channel::currentGM() const 0478 { 0479 return m_currentGm.data(); 0480 } 0481 void Channel::setCurrentGM(ServerConnection* currentGM) 0482 { 0483 if(currentGM == m_currentGm) 0484 return; 0485 m_currentGm= currentGM; 0486 emit currentGMChanged(); 0487 } 0488 0489 QString Channel::getCurrentGmId() 0490 { 0491 if(m_currentGm) 0492 return m_currentGm->playerId(); 0493 return {}; 0494 } 0495 quint64 Channel::memorySize() const 0496 { 0497 return m_memorySize; 0498 } 0499 void Channel::setMemorySize(quint64 size) 0500 { 0501 if(size == m_memorySize) 0502 return; 0503 m_memorySize= size; 0504 emit memorySizeChanged(m_memorySize, this); 0505 } 0506 void Channel::renamePlayer(const QString& id, const QString& name) 0507 { 0508 auto player= getClientById(id); 0509 if(nullptr == player) 0510 return; 0511 player->setName(name); 0512 } 0513 bool Channel::locked() const 0514 { 0515 return m_locked; 0516 } 0517 void Channel::setLocked(bool locked) 0518 { 0519 if(locked == m_locked) 0520 return; 0521 m_locked= locked; 0522 emit lockedChanged(); 0523 } 0524 bool Channel::removeChildById(const QString& id) 0525 { 0526 auto dupplicate= std::find_if(m_child.begin(), m_child.end(), [id](TreeItem* item) { return item->uuid() == id; }); 0527 0528 if(dupplicate == m_child.end()) 0529 return false; 0530 0531 m_child.erase(dupplicate); 0532 return true; 0533 }