File indexing completed on 2024-05-26 04:09:57
0001 /* 0002 This file is part of the KDE games library 0003 SPDX-FileCopyrightText: 2001 Burkhard Lehner <Burkhard.Lehner@gmx.de> 0004 0005 SPDX-License-Identifier: LGPL-2.0-only 0006 */ 0007 0008 #ifndef __KMESSAGECLIENT_H__ 0009 #define __KMESSAGECLIENT_H__ 0010 0011 // own 0012 #include "kdegamesprivate_export.h" 0013 // Qt 0014 #include <QObject> 0015 #include <QString> 0016 // Std 0017 #include <memory> 0018 0019 class KMessageIO; 0020 class KMessageServer; 0021 class KMessageClientPrivate; 0022 0023 /** 0024 \class KMessageClient kmessageclient.h <KGame/KMessageClient> 0025 0026 @short A client to connect to a KMessageServer 0027 0028 This class implements a client that can connect to a KMessageServer object. 0029 It can be used to exchange messages between clients. 0030 0031 Usually you will connect the signals broadcastReceived and forwardReceived to 0032 some specific slots. In these slot methods you can analyze the messages that are 0033 sent to you from other clients. 0034 0035 To send messages to other clients, use the methods sendBroadcast() (to send to all 0036 clients) or sendForward() (to send to a list of selected clients). 0037 0038 If you want to communicate with the KMessageServer object directly (on a more low 0039 level base), use the method sendServerMessage to send a command to the server and 0040 connect to the signal serverMessageReceived to see all the incoming messages. 0041 In that case the messages must be of the format specified in KMessageServer. 0042 @author Burkhard Lehner <Burkhard.Lehner@gmx.de> 0043 */ 0044 class KDEGAMESPRIVATE_EXPORT KMessageClient : public QObject 0045 { 0046 Q_OBJECT 0047 0048 public: 0049 /** 0050 Constructor. 0051 Creates an unconnected KMessageClient object. Use setServer() later to connect to a 0052 KMessageServer object. 0053 */ 0054 explicit KMessageClient(QObject *parent = nullptr); 0055 0056 /** 0057 Destructor. 0058 Disconnects from the server, if any connection was established. 0059 */ 0060 ~KMessageClient() override; 0061 0062 /** 0063 @return The client ID of this client. Every client that is connected to a KMessageServer 0064 has a unique ID number. 0065 0066 NOTE: As long as the object is not yet connected to the server, and as long as the server 0067 hasn't sent the client ID, this method returns 0. 0068 */ 0069 quint32 id() const; 0070 0071 /** 0072 @return Whether or not this client is the server admin. 0073 One of the clients connected to the server is the admin and can administrate the server 0074 (set maximum number of clients, remove clients, ...). 0075 0076 If you use admin commands without being the admin, these commands are simply ignored by 0077 the server. 0078 0079 NOTE: As long as you are not connected to a server, this method returns false. 0080 */ 0081 bool isAdmin() const; 0082 0083 /** 0084 @return The ID of the admin client on the message server. 0085 */ 0086 quint32 adminId() const; 0087 0088 /** 0089 @return The list of the IDs of all the message clients connected to the message server. 0090 */ 0091 QList<quint32> clientList() const; 0092 0093 /** 0094 Connects the client to (another) server. 0095 0096 Tries to connect via a TCP/IP socket to a KMessageServer object 0097 on the given host, listening on the specified port. 0098 0099 If we were already connected, the old connection is closed. 0100 @param host The name of the host to connect to. Must be either a hostname which can 0101 be resolved to an IP or just an IP 0102 @param port The port to connect to 0103 */ 0104 void setServer(const QString &host, quint16 port); 0105 0106 /** 0107 Connects the client to (another) server. 0108 0109 Connects to the given server, using KMessageDirect. 0110 (The server object has to be in the same process.) 0111 0112 If we were already connected, the old connection is closed. 0113 @param server The KMessageServer to connect to 0114 */ 0115 void setServer(KMessageServer *server); 0116 0117 /** 0118 * Corresponds to setServer(0); but also emits the connectionBroken signal 0119 */ 0120 void disconnect(); 0121 0122 /** 0123 Connects the client to (another) server. 0124 0125 To use this method, you have to create a KMessageIO object with new (indeed you must 0126 create an instance of a subclass of KMessageIO, e.g. KMessageSocket or KMessageDirect). 0127 This object must already be connected to the new server. 0128 0129 Calling this method disconnects any earlier connection, and uses the new KMessageIO 0130 object instead. This object gets owned by the KMessageClient object, so don't delete 0131 or manipulate it afterwards. 0132 0133 With this method it is possible to change the server on the fly. But be careful that 0134 there are no important messages from the old server not yet delivered. 0135 0136 NOTE: It is very likely that we will have another client ID on the new server. The 0137 value returned by clientID may be a little outdated until the new server tells us 0138 our new ID. 0139 0140 NOTE: The two other setServer methods are for convenience. If you use them, you don't 0141 have to create a KMessageIO object yourself. 0142 */ 0143 virtual void setServer(KMessageIO *connection); 0144 0145 /** 0146 @return True, if a connection to a KMessageServer has been started, and if the 0147 connection is ready for transferring data. (It will return false e.g. as long as 0148 a socket connection hasn't been established, and it will also return false after 0149 a socket connection is broken.) 0150 */ 0151 bool isConnected() const; 0152 0153 /** 0154 @return TRUE if isConnected() is true AND this is not a local (like 0155 KMessageDirect) connection. 0156 */ 0157 bool isNetwork() const; 0158 0159 /** 0160 @return 0 if isConnected() is FALSE, otherwise the port number this client is 0161 connected to. See also KMessageIO::peerPort and QSocket::peerPort. 0162 */ 0163 quint16 peerPort() const; 0164 0165 /** 0166 @return "localhost" if isConnected() is FALSE, otherwise the hostname this client is 0167 connected to. See also KMessageIO::peerName() and QSocket::peerName(). 0168 */ 0169 QString peerName() const; 0170 0171 /** 0172 Sends a message to the KMessageServer. If we are not yet connected to one, nothing 0173 happens. 0174 0175 Use this method to send a low level command to the server. It has to be in the 0176 format specified in KMessageServer. 0177 0178 If you want to send messages to other clients, you should use sendBroadcast() 0179 and sendForward(). 0180 @param msg The message to be sent to the server. Must be in the format specified in KMessageServer. 0181 */ 0182 void sendServerMessage(const QByteArray &msg); 0183 0184 /** 0185 Sends a message to all the clients connected to the server, including ourself. 0186 The message consists of an arbitrary block of data with arbitrary length. 0187 0188 All the clients will receive an exact copy of this block of data, which will be 0189 processed in their processBroadcast() method. 0190 @param msg The message to be sent to the clients 0191 */ 0192 // AB: processBroadcast doesn't exist!! is processIncomingMessage meant? 0193 void sendBroadcast(const QByteArray &msg); 0194 0195 /** 0196 Sends a message to all the clients in a list. 0197 The message consists of an arbitrary block of data with arbitrary length. 0198 0199 All clients will receive an exact copy of this block of data, which will be 0200 processed in their processForward() method. 0201 0202 If the list contains client IDs that are not defined, they are ignored. If 0203 it contains an ID several times, that client will receive the message several 0204 times. 0205 0206 To send a message to the admin of the KMessageServer, you can use 0 as clientID, 0207 instead of using the real client ID. 0208 @param msg The message to be sent to the clients 0209 @param clients A list of clients the message should be sent to 0210 */ 0211 // AB: processForward doesn't exist!! is processIncomingMessage meant? 0212 void sendForward(const QByteArray &msg, const QList<quint32> &clients); 0213 0214 /** 0215 Sends a message to a single client. This is a convenience method. It calls 0216 sendForward (const QByteArray &msg, const QValueList <quint32> &clients) 0217 with a list containing only one client ID. 0218 0219 To send a message to the admin of the KMessageServer, you can use 0 as clientID, 0220 instead of using the real client ID. 0221 @param msg The message to be sent to the client 0222 @param client The id of the client the message shall be sent to 0223 */ 0224 void sendForward(const QByteArray &msg, quint32 client); 0225 0226 /** 0227 Once this function is called no message will be received anymore. 0228 processIncomingMessage() gets delayed until unlock() is called. 0229 0230 Note that all messages are still received, but their delivery (like 0231 broadcastReceived()) get delayed only. 0232 */ 0233 void lock(); 0234 0235 /** 0236 Deliver every message that was delayed by lock() and actually deliver 0237 all messages that get received from now on. 0238 */ 0239 void unlock(); 0240 0241 /** 0242 @return The number of messages that got delayed since lock() was called 0243 */ 0244 unsigned int delayedMessageCount() const; 0245 0246 Q_SIGNALS: 0247 /** 0248 This signal is emitted when the client receives a broadcast message from the 0249 KMessageServer, sent by another client. Connect to this signal to analyze the 0250 received message and do the right reaction. 0251 0252 senderID contains the ID of the client that sent the broadcast message. You can 0253 use this e.g. to send a reply message to only that client. Or you can use it 0254 to ignore broadcast messages that were sent by yourself: 0255 0256 \code 0257 void myObject::myBroadcastSlot (const QByteArray &msg, quint32 senderID) 0258 { 0259 if (senderID == ((KMessageClient *)sender())->id()) 0260 return; 0261 ... 0262 } 0263 \endcode 0264 @param msg The message that has been sent to us 0265 @param senderID The ID of the client which sent the message 0266 */ 0267 void broadcastReceived(const QByteArray &msg, quint32 senderID); 0268 0269 /** 0270 This signal is emitted when the client receives a forward message from the 0271 KMessageServer, sent by another client. Connect to this signal to analyze the 0272 received message and do the right reaction. 0273 0274 senderID contains the ID of the client that sent the broadcast message. You can 0275 use this e.g. to send a reply message to only that client. 0276 0277 receivers contains the list of the clients that got the message. (If this list 0278 only contains one number, this will be your client ID, and it was exclusively 0279 sent to you.) 0280 0281 If you don't want to distinguish between broadcast and forward messages and 0282 treat them the same, you can connect forwardReceived signal to the 0283 broadcastReceived signal. (Yes, that's possible! You can connect a Qt signal to 0284 a Qt signal, and the second one can have less parameters.) 0285 0286 \code 0287 KMessageClient *client = new KMessageClient (); 0288 connect (client, SIGNAL (forwardReceived (const QByteArray &, quint32, const QValueList <quint32>&)), 0289 client, SIGNAL (broadcastReceived (const QByteArray &, quint32))); 0290 \endcode 0291 0292 Then connect the broadcast signal to your slot that analyzes the message. 0293 @param msg The message that has been sent to us 0294 @param senderID The ID of the client which sent the message 0295 @param receivers All clients which receive this message 0296 */ 0297 void forwardReceived(const QByteArray &msg, quint32 senderID, const QList<quint32> &receivers); 0298 0299 /** 0300 This signal is emitted when the connection to the KMessageServer is broken. 0301 Reasons for this can be: a network error, a server breakdown, or you were just kicked 0302 from the server. 0303 0304 When this signal is sent, the connection is already lost and the client is unconnected. 0305 You can connect to another server by calling setServer() afterwards. But keep in mind that 0306 some important messages might have vanished. 0307 */ 0308 void connectionBroken(); 0309 0310 /** 0311 This signal is emitted right before the client disconnects. It can be used 0312 to this store the id of the client which is about to be lost. 0313 */ 0314 void aboutToDisconnect(quint32 id); 0315 0316 /** 0317 This signal is emitted when this client becomes the admin client or when it loses 0318 the admin client status. Connect to this signal if you have to do any initialization 0319 or cleanup. 0320 @param isAdmin Whether we are now admin or not 0321 */ 0322 void adminStatusChanged(bool isAdmin); 0323 0324 /** 0325 This signal is emitted when another client has connected 0326 to the server. Connect to this method if that clients needs initialization. 0327 This should usually only be done in one client, e.g. the admin client. 0328 @param clientID The ID of the client that has newly connected. 0329 */ 0330 void eventClientConnected(quint32 clientID); 0331 0332 /** 0333 This signal is emitted when the server has lost the 0334 connection to one of the clients (This could be because of a bad internet connection 0335 or because the client disconnected on purpose). 0336 @param clientID The ID of the client that has disconnected 0337 @param broken true if it was disconnected because of a network error 0338 */ 0339 void eventClientDisconnected(quint32 clientID, bool broken); 0340 0341 /** 0342 This signal is emitted on every message that came from the server. You can connect to this 0343 signal to see the messages directly. They are in the format specified in KMessageServer. 0344 0345 @param msg The message that has been sent to us 0346 @param unknown True when KMessageClient didn't recognize the message, i.e. it contained an unknown 0347 message ID. If you want to add additional message types to the client, connect to this signal, 0348 and if unknown is true, analyze the message by yourself. If you recognized the message, 0349 set unknown to false (Otherwise a debug message will be printed). 0350 */ 0351 // AB: maybe add a setNoEmit() so that the other signals can be deactivated? 0352 // Could be a performance benefit (note: KMessageClient is a time critical 0353 // class!!!) 0354 void serverMessageReceived(const QByteArray &msg, bool &unknown); 0355 0356 protected: 0357 /** 0358 This slot is called from processIncomingMessage or 0359 processFirstMessage, depending on whether the client is locked or a delayed 0360 message is still here (see lock) 0361 0362 It processes the message and analyzes it. If it is a broadcast or a forward message from 0363 another client, it emits the signal processBroadcast or processForward accordingly. 0364 0365 If you want to treat additional server messages, you can overwrite this method. Don't 0366 forget to call processIncomingMessage of your superclass! 0367 0368 At the moment, the following server messages are interpreted: 0369 0370 MSG_BROADCAST, MSG_FORWARD, ANS_CLIENT_ID, ANS_ADMIN_ID, ANS_CLIENT_LIST 0371 @param msg The incoming message 0372 */ 0373 0374 virtual void processMessage(const QByteArray &msg); 0375 0376 protected Q_SLOTS: 0377 /** 0378 This slot is called from the signal KMessageIO::received whenever a message from the 0379 KMessageServer arrives. 0380 0381 It processes the message and analyzes it. If it is a broadcast or a forward message from 0382 another client, it emits the signal processBroadcast or processForward accordingly. 0383 0384 If you want to treat additional server messages, you can overwrite this method. Don't 0385 forget to call processIncomingMessage() of your superclass! 0386 0387 At the moment, the following server messages are interpreted: 0388 0389 MSG_BROADCAST, MSG_FORWARD, ANS_CLIENT_ID, ANS_ADMIN_ID, ANS_CLIENT_LIST 0390 @param msg The incoming message 0391 */ 0392 virtual void processIncomingMessage(const QByteArray &msg); 0393 0394 /** 0395 Called from unlock() (using QTimer::singleShot) until all delayed 0396 messages are delivered. 0397 */ 0398 void processFirstMessage(); 0399 0400 /** 0401 This slot is called from the signal KMessageIO::connectionBroken. 0402 0403 It deletes the internal KMessageIO object, and resets the client to default 0404 values. To connect again to another server, use setServer. 0405 */ 0406 virtual void removeBrokenConnection(); 0407 void removeBrokenConnection2(); 0408 0409 private: 0410 std::unique_ptr<KMessageClientPrivate> const d; 0411 }; 0412 0413 #endif