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 }