KDEGames

kmessageclient.h
1 /*
2  This file is part of the KDE games library
3  SPDX-FileCopyrightText: 2001 Burkhard Lehner <[email protected]>
4 
5  SPDX-License-Identifier: LGPL-2.0-only
6 */
7 
8 #ifndef __KMESSAGECLIENT_H__
9 #define __KMESSAGECLIENT_H__
10 
11 // own
12 #include "kdegamesprivate_export.h"
13 // Qt
14 #include <QObject>
15 #include <QString>
16 // Std
17 #include <memory>
18 
19 class KMessageIO;
20 class KMessageServer;
21 class KMessageClientPrivate;
22 
23 /**
24  \class KMessageClient kmessageclient.h <KGame/KMessageClient>
25 
26  @short A client to connect to a KMessageServer
27 
28  This class implements a client that can connect to a KMessageServer object.
29  It can be used to exchange messages between clients.
30 
31  Usually you will connect the signals broadcastReceived and forwardReceived to
32  some specific slots. In these slot methods you can analyze the messages that are
33  sent to you from other clients.
34 
35  To send messages to other clients, use the methods sendBroadcast() (to send to all
36  clients) or sendForward() (to send to a list of selected clients).
37 
38  If you want to communicate with the KMessageServer object directly (on a more low
39  level base), use the method sendServerMessage to send a command to the server and
40  connect to the signal serverMessageReceived to see all the incoming messages.
41  In that case the messages must be of the format specified in KMessageServer.
42  @author Burkhard Lehner <[email protected]>
43 */
44 class KDEGAMESPRIVATE_EXPORT KMessageClient : public QObject
45 {
46  Q_OBJECT
47 
48 public:
49  /**
50  Constructor.
51  Creates an unconnected KMessageClient object. Use setServer() later to connect to a
52  KMessageServer object.
53  */
54  explicit KMessageClient(QObject *parent = nullptr);
55 
56  /**
57  Destructor.
58  Disconnects from the server, if any connection was established.
59  */
60  ~KMessageClient() override;
61 
62  /**
63  @return The client ID of this client. Every client that is connected to a KMessageServer
64  has a unique ID number.
65 
66  NOTE: As long as the object is not yet connected to the server, and as long as the server
67  hasn't sent the client ID, this method returns 0.
68  */
69  quint32 id() const;
70 
71  /**
72  @return Whether or not this client is the server admin.
73  One of the clients connected to the server is the admin and can administrate the server
74  (set maximum number of clients, remove clients, ...).
75 
76  If you use admin commands without being the admin, these commands are simply ignored by
77  the server.
78 
79  NOTE: As long as you are not connected to a server, this method returns false.
80  */
81  bool isAdmin() const;
82 
83  /**
84  @return The ID of the admin client on the message server.
85  */
86  quint32 adminId() const;
87 
88  /**
89  @return The list of the IDs of all the message clients connected to the message server.
90  */
91  QList<quint32> clientList() const;
92 
93  /**
94  Connects the client to (another) server.
95 
96  Tries to connect via a TCP/IP socket to a KMessageServer object
97  on the given host, listening on the specified port.
98 
99  If we were already connected, the old connection is closed.
100  @param host The name of the host to connect to. Must be either a hostname which can
101  be resolved to an IP or just an IP
102  @param port The port to connect to
103  */
104  void setServer(const QString &host, quint16 port);
105 
106  /**
107  Connects the client to (another) server.
108 
109  Connects to the given server, using KMessageDirect.
110  (The server object has to be in the same process.)
111 
112  If we were already connected, the old connection is closed.
113  @param server The KMessageServer to connect to
114  */
115  void setServer(KMessageServer *server);
116 
117  /**
118  * Corresponds to setServer(0); but also emits the connectionBroken signal
119  */
120  void disconnect();
121 
122  /**
123  Connects the client to (another) server.
124 
125  To use this method, you have to create a KMessageIO object with new (indeed you must
126  create an instance of a subclass of KMessageIO, e.g. KMessageSocket or KMessageDirect).
127  This object must already be connected to the new server.
128 
129  Calling this method disconnects any earlier connection, and uses the new KMessageIO
130  object instead. This object gets owned by the KMessageClient object, so don't delete
131  or manipulate it afterwards.
132 
133  With this method it is possible to change the server on the fly. But be careful that
134  there are no important messages from the old server not yet delivered.
135 
136  NOTE: It is very likely that we will have another client ID on the new server. The
137  value returned by clientID may be a little outdated until the new server tells us
138  our new ID.
139 
140  NOTE: The two other setServer methods are for convenience. If you use them, you don't
141  have to create a KMessageIO object yourself.
142  */
143  virtual void setServer(KMessageIO *connection);
144 
145  /**
146  @return True, if a connection to a KMessageServer has been started, and if the
147  connection is ready for transferring data. (It will return false e.g. as long as
148  a socket connection hasn't been established, and it will also return false after
149  a socket connection is broken.)
150  */
151  bool isConnected() const;
152 
153  /**
154  @return TRUE if isConnected() is true AND this is not a local (like
155  KMessageDirect) connection.
156  */
157  bool isNetwork() const;
158 
159  /**
160  @return 0 if isConnected() is FALSE, otherwise the port number this client is
161  connected to. See also KMessageIO::peerPort and QSocket::peerPort.
162  */
163  quint16 peerPort() const;
164 
165  /**
166  @return "localhost" if isConnected() is FALSE, otherwise the hostname this client is
167  connected to. See also KMessageIO::peerName() and QSocket::peerName().
168  */
169  QString peerName() const;
170 
171  /**
172  Sends a message to the KMessageServer. If we are not yet connected to one, nothing
173  happens.
174 
175  Use this method to send a low level command to the server. It has to be in the
176  format specified in KMessageServer.
177 
178  If you want to send messages to other clients, you should use sendBroadcast()
179  and sendForward().
180  @param msg The message to be sent to the server. Must be in the format specified in KMessageServer.
181  */
182  void sendServerMessage(const QByteArray &msg);
183 
184  /**
185  Sends a message to all the clients connected to the server, including ourself.
186  The message consists of an arbitrary block of data with arbitrary length.
187 
188  All the clients will receive an exact copy of this block of data, which will be
189  processed in their processBroadcast() method.
190  @param msg The message to be sent to the clients
191  */
192  // AB: processBroadcast doesn't exist!! is processIncomingMessage meant?
193  void sendBroadcast(const QByteArray &msg);
194 
195  /**
196  Sends a message to all the clients in a list.
197  The message consists of an arbitrary block of data with arbitrary length.
198 
199  All clients will receive an exact copy of this block of data, which will be
200  processed in their processForward() method.
201 
202  If the list contains client IDs that are not defined, they are ignored. If
203  it contains an ID several times, that client will receive the message several
204  times.
205 
206  To send a message to the admin of the KMessageServer, you can use 0 as clientID,
207  instead of using the real client ID.
208  @param msg The message to be sent to the clients
209  @param clients A list of clients the message should be sent to
210  */
211  // AB: processForward doesn't exist!! is processIncomingMessage meant?
212  void sendForward(const QByteArray &msg, const QList<quint32> &clients);
213 
214  /**
215  Sends a message to a single client. This is a convenience method. It calls
216  sendForward (const QByteArray &msg, const QValueList &ltquint32> &clients)
217  with a list containing only one client ID.
218 
219  To send a message to the admin of the KMessageServer, you can use 0 as clientID,
220  instead of using the real client ID.
221  @param msg The message to be sent to the client
222  @param client The id of the client the message shall be sent to
223  */
224  void sendForward(const QByteArray &msg, quint32 client);
225 
226  /**
227  Once this function is called no message will be received anymore.
228  processIncomingMessage() gets delayed until unlock() is called.
229 
230  Note that all messages are still received, but their delivery (like
231  broadcastReceived()) get delayed only.
232  */
233  void lock();
234 
235  /**
236  Deliver every message that was delayed by lock() and actually deliver
237  all messages that get received from now on.
238  */
239  void unlock();
240 
241  /**
242  @return The number of messages that got delayed since lock() was called
243  */
244  unsigned int delayedMessageCount() const;
245 
246 Q_SIGNALS:
247  /**
248  This signal is emitted when the client receives a broadcast message from the
249  KMessageServer, sent by another client. Connect to this signal to analyze the
250  received message and do the right reaction.
251 
252  senderID contains the ID of the client that sent the broadcast message. You can
253  use this e.g. to send a reply message to only that client. Or you can use it
254  to ignore broadcast messages that were sent by yourself:
255 
256  \code
257  void myObject::myBroadcastSlot (const QByteArray &msg, quint32 senderID)
258  {
259  if (senderID == ((KMessageClient *)sender())->id())
260  return;
261  ...
262  }
263  \endcode
264  @param msg The message that has been sent to us
265  @param senderID The ID of the client which sent the message
266  */
267  void broadcastReceived(const QByteArray &msg, quint32 senderID);
268 
269  /**
270  This signal is emitted when the client receives a forward message from the
271  KMessageServer, sent by another client. Connect to this signal to analyze the
272  received message and do the right reaction.
273 
274  senderID contains the ID of the client that sent the broadcast message. You can
275  use this e.g. to send a reply message to only that client.
276 
277  receivers contains the list of the clients that got the message. (If this list
278  only contains one number, this will be your client ID, and it was exclusively
279  sent to you.)
280 
281  If you don't want to distinguish between broadcast and forward messages and
282  treat them the same, you can connect forwardReceived signal to the
283  broadcastReceived signal. (Yes, that's possible! You can connect a Qt signal to
284  a Qt signal, and the second one can have less parameters.)
285 
286  \code
287  KMessageClient *client = new KMessageClient ();
288  connect (client, SIGNAL (forwardReceived (const QByteArray &, quint32, const QValueList <quint32>&)),
289  client, SIGNAL (broadcastReceived (const QByteArray &, quint32)));
290  \endcode
291 
292  Then connect the broadcast signal to your slot that analyzes the message.
293  @param msg The message that has been sent to us
294  @param senderID The ID of the client which sent the message
295  @param receivers All clients which receive this message
296  */
297  void forwardReceived(const QByteArray &msg, quint32 senderID, const QList<quint32> &receivers);
298 
299  /**
300  This signal is emitted when the connection to the KMessageServer is broken.
301  Reasons for this can be: a network error, a server breakdown, or you were just kicked
302  from the server.
303 
304  When this signal is sent, the connection is already lost and the client is unconnected.
305  You can connect to another server by calling setServer() afterwards. But keep in mind that
306  some important messages might have vanished.
307  */
308  void connectionBroken();
309 
310  /**
311  This signal is emitted right before the client disconnects. It can be used
312  to this store the id of the client which is about to be lost.
313  */
314  void aboutToDisconnect(quint32 id);
315 
316  /**
317  This signal is emitted when this client becomes the admin client or when it loses
318  the admin client status. Connect to this signal if you have to do any initialization
319  or cleanup.
320  @param isAdmin Whether we are now admin or not
321  */
322  void adminStatusChanged(bool isAdmin);
323 
324  /**
325  This signal is emitted when another client has connected
326  to the server. Connect to this method if that clients needs initialization.
327  This should usually only be done in one client, e.g. the admin client.
328  @param clientID The ID of the client that has newly connected.
329  */
330  void eventClientConnected(quint32 clientID);
331 
332  /**
333  This signal is emitted when the server has lost the
334  connection to one of the clients (This could be because of a bad internet connection
335  or because the client disconnected on purpose).
336  @param clientID The ID of the client that has disconnected
337  @param broken true if it was disconnected because of a network error
338  */
339  void eventClientDisconnected(quint32 clientID, bool broken);
340 
341  /**
342  This signal is emitted on every message that came from the server. You can connect to this
343  signal to see the messages directly. They are in the format specified in KMessageServer.
344 
345  @param msg The message that has been sent to us
346  @param unknown True when KMessageClient didn't recognize the message, i.e. it contained an unknown
347  message ID. If you want to add additional message types to the client, connect to this signal,
348  and if unknown is true, analyze the message by yourself. If you recognized the message,
349  set unknown to false (Otherwise a debug message will be printed).
350  */
351  // AB: maybe add a setNoEmit() so that the other signals can be deactivated?
352  // Could be a performance benefit (note: KMessageClient is a time critical
353  // class!!!)
354  void serverMessageReceived(const QByteArray &msg, bool &unknown);
355 
356 protected:
357  /**
358  This slot is called from processIncomingMessage or
359  processFirstMessage, depending on whether the client is locked or a delayed
360  message is still here (see lock)
361 
362  It processes the message and analyzes it. If it is a broadcast or a forward message from
363  another client, it emits the signal processBroadcast or processForward accordingly.
364 
365  If you want to treat additional server messages, you can overwrite this method. Don't
366  forget to call processIncomingMessage of your superclass!
367 
368  At the moment, the following server messages are interpreted:
369 
370  MSG_BROADCAST, MSG_FORWARD, ANS_CLIENT_ID, ANS_ADMIN_ID, ANS_CLIENT_LIST
371  @param msg The incoming message
372  */
373 
374  virtual void processMessage(const QByteArray &msg);
375 
376 protected Q_SLOTS:
377  /**
378  This slot is called from the signal KMessageIO::received whenever a message from the
379  KMessageServer arrives.
380 
381  It processes the message and analyzes it. If it is a broadcast or a forward message from
382  another client, it emits the signal processBroadcast or processForward accordingly.
383 
384  If you want to treat additional server messages, you can overwrite this method. Don't
385  forget to call processIncomingMessage() of your superclass!
386 
387  At the moment, the following server messages are interpreted:
388 
389  MSG_BROADCAST, MSG_FORWARD, ANS_CLIENT_ID, ANS_ADMIN_ID, ANS_CLIENT_LIST
390  @param msg The incoming message
391  */
392  virtual void processIncomingMessage(const QByteArray &msg);
393 
394  /**
395  Called from unlock() (using QTimer::singleShot) until all delayed
396  messages are delivered.
397  */
398  void processFirstMessage();
399 
400  /**
401  This slot is called from the signal KMessageIO::connectionBroken.
402 
403  It deletes the internal KMessageIO object, and resets the client to default
404  values. To connect again to another server, use setServer.
405  */
406  virtual void removeBrokenConnection();
407  void removeBrokenConnection2();
408 
409 private:
410  std::unique_ptr<KMessageClientPrivate> const d;
411 };
412 
413 #endif
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
Q_SLOTSQ_SLOTS
Q_SIGNALSQ_SIGNALS
ScriptableExtension * host() const
A server for message sending and broadcasting, using TCP/IP connections.
A client to connect to a KMessageServer.
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Wed Dec 6 2023 04:08:10 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.