Browse Source

Implemented threadless design for querying.

Mihawk 12 years ago
parent
commit
5c3f145036
8 changed files with 153 additions and 84 deletions
  1. 42 24
      ActiveClient.cpp
  2. 18 9
      ActiveClient.h
  3. 4 7
      App.cpp
  4. 63 27
      ServerQuery.cpp
  5. 20 10
      ServerQuery.h
  6. 3 3
      Settings.cpp
  7. 1 1
      Settings.h
  8. 2 3
      SshClient.cpp

+ 42 - 24
ActiveClient.cpp

@@ -19,35 +19,36 @@ along with this program.  If not, see < http://www.gnu.org/licenses/ >.
 
 #include <QTimer>
 #include <QTime>
-#include "ServerQueryThread.h"
+#include "ServerQuery.h"
 #include "ActiveClient.h"
 #include "Client.h"
 #include "App.h"
+#include "Settings.h"
 
-ActiveClient::ActiveClient(App *app):
+ActiveClient::ActiveClient(App *app, QObject *parent):
+  QObject(parent),
   myApp(app),
   myClient(new Client(app)),
-  myQueryThread(new ServerQueryThread()),
+  myQuery(new ServerQuery(this)),
   myDisconnectTime(new QTime()),
-  myBroadcastReplyTimer(new QTimer()),
+  myBroadcastReplyTimer(new QTimer(this)),
+  myQueryTimer(new QTimer(this)),
+  myQueryInterval(Settings::globalInstance()->queryInterval()),
   myUniqueUserCount(0),
   myUniqueChannelCount(0),
   myUniqueServerCount(0),
   myUniquePlayerCount(0),
   myReplyTimerWasActive(false)
 {
+  connect(myQuery, SIGNAL(finished()), SLOT(queryFinished()));
+  connect(myQuery, SIGNAL(error(ServerQuery::Error)), SLOT(queryError(ServerQuery::Error)));
+
+  myQueryTimer->setSingleShot(true);
 }
 
 ActiveClient::~ActiveClient()
 {
   delete myClient;
-
-  if(myQueryThread->isRunning())
-    myQueryThread->stopQueryThread();
-  while(myQueryThread->isRunning());
-
-  delete myQueryThread;
-  delete myBroadcastReplyTimer;
   delete myDisconnectTime;
 }
 
@@ -56,28 +57,35 @@ Client* ActiveClient::client()
   return myClient;
 }
 
-ServerQueryThread* ActiveClient::queryThread()
+quint8 ActiveClient::playerCount() const
 {
-  return myQueryThread;
+  return myQuery->playerList().size();
 }
 
-void ActiveClient::setAddressAndStartThread(const QHostAddress &address, quint16 port)
+void ActiveClient::setAddress(const QHostAddress &address, quint16 port)
 {
-  myQueryThread->setAddress(address, port);
-  myQueryThread->startQueryThread();
+  myQuery->setAddress(address, port);
   return;
 }
 
-void ActiveClient::run()
+void ActiveClient::queryError(ServerQuery::Error)
+{
+  myQueryTimer->start(myQueryInterval);
+}
+
+void ActiveClient::queryFinished()
 {
+  int playerCount = myQuery->playerList().size();
+
+  myQueryTimer->start(myQueryInterval);
+
   /* If the client is disconnect check if there is at least one player connected to the server */
   if(myClient->state() == Client::DisconnectedState)
   {
-    int playerCount = myQueryThread->playerCount();
     if(playerCount > 0 && myDisconnectTime->elapsed() > 10000)
     {
-      myApp->print("Players online on server " + myQueryThread->serverAddress().toString() + ":" + QString::number(myQueryThread->serverPort()) + ". Joining...\n");
-      myClient->connect(myQueryThread->serverAddress().toString().toAscii(), myQueryThread->serverPort());
+      myApp->print("Players online on server " + serverAddressString() + ". Joining...\n");
+      myClient->connect(myQuery->address().toString().toAscii(), myQuery->port());
     }
     return;
   }
@@ -85,16 +93,18 @@ void ActiveClient::run()
   /* If the client is connected and left alone on the server, disconnect yourself */
   if(myClient->state() == Client::ConnectedState)
   {
-    int playerCount = myQueryThread->playerCount();
     if(playerCount == 1 && myClient->isOnServer())
     {
-      myApp->print("I was left alone on " + myQueryThread->serverAddress().toString() + ":" + QString::number(myQueryThread->serverPort()) + ". Leaving...\n");
+      myApp->print("I was left alone on " + serverAddressString() + ". Leaving...\n");
       myClient->disconnect();
       myDisconnectTime->restart();
       return;
     }
   }
+}
 
+void ActiveClient::run()
+{
   /* Say the broadcast count */
   if(!myBroadcastReplyTimer->isActive() && myReplyTimerWasActive)
   {
@@ -105,12 +115,20 @@ void ActiveClient::run()
   }
   myReplyTimerWasActive = myBroadcastReplyTimer->isActive();
 
-  myClient->run();
+  /* Query the serverinfo for player count if not already querying */
+  if(!myQuery->isActive() && !myQueryTimer->isActive())
+    myQuery->query();
+  else
+    myQuery->run();
+
+  /* Run the client */
+  if(myClient->state() != Client::DisconnectedState)
+    myClient->run();
 }
 
 const QString ActiveClient::serverAddressString()
 {
-  return QString(myQueryThread->serverAddress().toString() + ':' + QString::number(myQueryThread->serverPort()));
+  return QString(myQuery->address().toString() + ':' + QString::number(myQuery->port()));
 }
 
 void ActiveClient::setReplyHash(const QString &hash)

+ 18 - 9
ActiveClient.h

@@ -20,40 +20,51 @@ along with this program.  If not, see < http://www.gnu.org/licenses/ >.
 #ifndef ACTIVECLIENT_H
 #define ACTIVECLIENT_H
 
+#include <QObject>
 #include <QString>
+#include "ServerQuery.h"
 
 class QHostAddress;
-class ServerQueryThread;
 class QTimer;
 class QTime;
 class Client;
 class App;
 
-class ActiveClient
+class ActiveClient: public QObject
 {
+  Q_OBJECT
+
 public:
-  ActiveClient(App* app);
-  ~ActiveClient();
+  ActiveClient(App* app, QObject *parent = 0);
+  virtual ~ActiveClient();
 
   Client*           client();
-  ServerQueryThread*queryThread();
+
   void              run();
-  void              setAddressAndStartThread(const QHostAddress &address, quint16 port);
+  void              setAddress(const QHostAddress &address, quint16 port);
   const QString     serverAddressString();
+  quint8            playerCount() const;
+
   void              setReplyHash(const QString& hash); //this activates the 5 seconds reply timer too
   const QString&    replyHash() const;
   void              incrementReplyCounters(int userCount, int channelCount, int playerCount, int serverCount);
   bool              isWaitingReply() const;
 
+private slots:
+  void              queryFinished();
+  void              queryError(ServerQuery::Error err);
+
 private:
   App*              myApp;
   Client*           myClient;
-  ServerQueryThread*myQueryThread;
+  ServerQuery*      myQuery;
   QTime*            myDisconnectTime;
 
   /* Count server reply while timer is active */
   QString           myReplyHash;
   QTimer*           myBroadcastReplyTimer;
+  QTimer*           myQueryTimer;
+  quint32           myQueryInterval;
 
   int               myUniqueUserCount;
   int               myUniqueChannelCount;
@@ -61,8 +72,6 @@ private:
   int               myUniquePlayerCount;
 
   bool              myReplyTimerWasActive;
-
-  ActiveClient(const ActiveClient&) {}
 };
 
 #endif // ACTIVECLIENT_H

+ 4 - 7
App.cpp

@@ -10,7 +10,6 @@
 #include <QtSql/QSqlQuery>
 #include <QCryptographicHash>
 #include <QHostAddress>
-#include <QThreadPool>
 #include "SshClient.h"
 #include "ActiveClient.h"
 #include "ServerQueryThread.h"
@@ -36,8 +35,6 @@ App::App(int &argc, char **argv) :
 
   myQWNETSshClient->connectToHost("stomp", "b4r.org");
 
-  QThreadPool::globalInstance()->setMaxThreadCount(Settings::globalInstance()->maxThreads());
-
   loadServerList();
 
   Settings::globalInstance()->save();
@@ -97,7 +94,7 @@ void App::loadServerList()
   {
     ActiveClient* ac = new ActiveClient(this);
     QStringList parms = sv.split(':');
-    ac->setAddressAndStartThread(QHostAddress(parms.at(0)), parms.at(1).toUShort());
+    ac->setAddress(QHostAddress(parms.at(0)), parms.at(1).toUShort());
     ac->client()->setQuakeFolder(Settings::globalInstance()->quakeFolder().toAscii().data());
     ac->client()->setName(Settings::globalInstance()->botName().toAscii().data());
     ac->client()->setSpectator(Settings::globalInstance()->botSpectator());
@@ -366,7 +363,7 @@ void App::addClient(const QString &host, quint16 port)
       ac->client()->setSocket(mySocket);
 		}
 	}
-  ac->setAddressAndStartThread(ha, port);
+  ac->setAddress(ha, port);
   ac->client()->setQuakeFolder(Settings::globalInstance()->quakeFolder().toAscii().data());
   ac->client()->setName(Settings::globalInstance()->botName().toAscii().data());
   ac->client()->setSpectator(Settings::globalInstance()->botSpectator());
@@ -413,7 +410,7 @@ void App::say(const QString &msg, int *serverCount, int *userCount)
     if(ac->client()->state() == Client::ConnectedState)
     {
       ac->client()->say(msg);
-      *userCount += ac->queryThread()->playerCount() - 1;
+      *userCount += ac->playerCount() - 1;
       (*serverCount)++;
     }
 	}
@@ -461,7 +458,7 @@ void App::activeClientsReplyCounters(int *serverCount, int *playerCount)
   {
     if(ac->client()->state() == Client::ConnectedState)
     {
-      int pc = ac->queryThread()->playerCount();
+      int pc = ac->playerCount();
       if(pc == 255 || pc == 0)
         pc = 0;
       else

+ 63 - 27
ServerQuery.cpp

@@ -28,8 +28,11 @@ along with this program.  If not, see < http://www.gnu.org/licenses/ >.
 ServerQuery::ServerQuery(QObject *parent) :
   QObject(parent),
   mySocket(new QUdpSocket(this)),
-  myPort(27500)
+  myPort(27500),
+  myActiveFlag(false)
 {
+  //  connect(mySocket, SIGNAL(readyRead()), SLOT(parseServerInfo()));
+  connect(mySocket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketError(QAbstractSocket::SocketError)));
 }
 
 ServerQuery::~ServerQuery()
@@ -37,13 +40,20 @@ ServerQuery::~ServerQuery()
   delete mySocket;
 }
 
+void ServerQuery::run()
+{
+  if(mySocket->hasPendingDatagrams())
+    parseServerInfo();
+}
+
 bool ServerQuery::query(bool pingServer)
 {
-  myLastErrorCode = NoError;
+  myActiveFlag = true;
 
   if(myAddress.isNull() || !myPort)
   {
-    myLastErrorCode = HostLookupError;
+    emit error(HostLookupError);
+    myActiveFlag = false;
 		return false;
   }
 
@@ -51,15 +61,17 @@ bool ServerQuery::query(bool pingServer)
 		mySocket->close();
 
   mySocket->connectToHost(myAddress, myPort);
-  if(mySocket->write("\xff\xff\xff\xffstatus 23\n", 14) == -1)
-	{
-    myLastErrorCode = SendError;
-		return false;
-	}
+  if(!mySocket->waitForConnected(100))
+  {
+    emit error(ConnectionError);
+    myActiveFlag = false;
+    return false;
+  }
 
-	if(!mySocket->waitForReadyRead(3000))
+  if(mySocket->write("\xff\xff\xff\xffstatus 23\n", 14) == -1)
 	{
-    myLastErrorCode = TimedOutError;
+    emit error(SendError);
+    myActiveFlag = false;
 		return false;
 	}
 
@@ -68,7 +80,17 @@ bool ServerQuery::query(bool pingServer)
   else
     myPing = 0;
 
-  return parseServerInfo();
+  return true;
+}
+
+const QHostAddress &ServerQuery::address() const
+{
+  return myAddress;
+}
+
+quint16 ServerQuery::port() const
+{
+  return myPort;
 }
 
 bool ServerQuery::setAddress(const QHostAddress &address, quint16 port)
@@ -83,7 +105,7 @@ bool ServerQuery::setAddress(const QString &address, quint16 port)
   QHostInfo hi = QHostInfo::fromName(address);
   if(hi.error() != QHostInfo::NoError)
   {
-    myLastErrorCode = HostLookupError;
+    emit error(HostLookupError);
     return false;
   }
   myAddress = hi.addresses().at(0);
@@ -92,20 +114,22 @@ bool ServerQuery::setAddress(const QString &address, quint16 port)
   return true;
 }
 
-bool ServerQuery::parseServerInfo()
+void ServerQuery::parseServerInfo()
 {
-	QByteArray serverData = mySocket->readAll();
+  QByteArray serverData = mySocket->readAll();
 
   if(serverData.isEmpty())
 	{
-    myLastErrorCode = EmptyResponseError;
-		return false;
+    emit error(EmptyResponseError);
+    myActiveFlag = false;
+    return;
 	}
 
 	if(!serverData.startsWith("\xff\xff\xff\xffn"))
 	{
-    myLastErrorCode = InvalidResponseError;
-		return false;
+    emit error(InvalidResponseError);
+    myActiveFlag = false;
+    return;
 	}
 
   /* Parse server rules */
@@ -116,8 +140,9 @@ bool ServerQuery::parseServerInfo()
   QStringList rules = splitInfoString.at(0).split("\\", QString::SkipEmptyParts);
   if((rules.size() % 2) != 0)
 	{
-    myLastErrorCode = InvalidInfoStringError;
-		return false;
+    emit error(InvalidInfoStringError);
+    myActiveFlag = false;
+    return;
 	}
 
 	ServerRule	rule;
@@ -154,7 +179,7 @@ bool ServerQuery::parseServerInfo()
 	{
 		if(regex.indexIn(splitInfoString.at(i)) == -1)
 		{
-      myLastErrorCode = InvalidPlayerInfoError;
+      emit error(InvalidPlayerInfoError);
 			continue;
 		}
 
@@ -183,7 +208,23 @@ bool ServerQuery::parseServerInfo()
 		}
     myPlayers.append(player);
 	}
-  return true;
+
+  myActiveFlag = false;
+
+  emit finished();
+
+  return;
+}
+
+bool ServerQuery::isActive() const
+{
+  return myActiveFlag;
+}
+
+void ServerQuery::socketError(QAbstractSocket::SocketError)
+{
+  emit error(UnknownError);
+  myActiveFlag = false;
 }
 
 int ServerQuery::ping(int count, int timeout)
@@ -212,11 +253,6 @@ int ServerQuery::ping(int count, int timeout)
 	return pong/count;
 }
 
-ServerQuery::Error ServerQuery::lastError() const
-{
-  return myLastErrorCode;
-}
-
 PlayerList ServerQuery::playerList() const
 {
   return myPlayers;

+ 20 - 10
ServerQuery.h

@@ -55,37 +55,47 @@ class ServerQuery : public QObject
 	Q_OBJECT
 public:
 
-	enum Error { NoError, TimedOutError, EmptyResponseError, InvalidResponseError, InvalidInfoStringError, InvalidPlayerInfoError, SendError, HostLookupError, UnknownError };
+  enum Error { NoError, TimedOutError, EmptyResponseError, InvalidResponseError, InvalidInfoStringError, InvalidPlayerInfoError, SendError, HostLookupError, ConnectionError, UnknownError };
 
 	explicit ServerQuery(QObject *parent = 0);
   ~ServerQuery();
 
   bool          setAddress(const QString &address, quint16 port = 27500);
   bool          setAddress(const QHostAddress &address, quint16 port = 27500);
+  const QHostAddress&  address() const;
+  quint16       port() const;
+
   bool          query(bool pingServer = false);
-  Error         lastError() const;
+  void          run();
+  bool          isActive() const;
+
   PlayerList    playerList() const;
   ServerRules   serverRules() const;
 
+signals:
+  void          error(ServerQuery::Error err);
+  void          finished();
+
+private slots:
+  void          parseServerInfo();
+  void          socketError(QAbstractSocket::SocketError err);
+
 private:
   QUdpSocket*   mySocket;
   QHostAddress	myAddress;
-	quint16				myPort;
-  Error					myLastErrorCode;
+  quint16				myPort;
   PlayerList    myPlayers;
   ServerRules   myRules;
   quint16       myPing;
   bool          myIsProxyFlag;
+  bool          myActiveFlag;
 
-  bool          parseServerInfo();
-  int           ping(int count = 3, int timeout = 1000);
-
-
-  //========================================================================
-  /* Name fun conversion */
   static char   ourReadableCharsTable[256];
   static bool   ourReadableCharsTableInitialized;
+
+  int           ping(int count = 3, int timeout = 1000);
   static void   fillReadableCharsTable();
+
 public:
   static QString convertNameFun(const QString &name);
 };

+ 3 - 3
Settings.cpp

@@ -103,9 +103,9 @@ int Settings::floodProtTime() const
   return ourSettings->value("floodProtTime", 30).toInt();
 }
 
-unsigned int Settings::maxThreads() const
+unsigned int Settings::queryInterval() const
 {
-  return ourSettings->value("maxThreads", 50).toUInt();
+  return ourSettings->value("queryInterval", 1000).toUInt();
 }
 
 void Settings::save()
@@ -117,7 +117,7 @@ void Settings::save()
   ourSettings->setValue("botBottomColor", botBottomColor());
   ourSettings->setValue("botSpectator", botSpectator());
   ourSettings->setValue("floodProtTime", floodProtTime());
-  ourSettings->setValue("maxThreads", maxThreads());
+  ourSettings->setValue("queryInterval", queryInterval());
   QStringList list = serverList();
   setServerList(list);
 }

+ 1 - 1
Settings.h

@@ -39,7 +39,7 @@ public:
   int               botBottomColor() const;
   bool              botSpectator() const;
   int               floodProtTime() const;
-  unsigned int      maxThreads() const;
+  unsigned int      queryInterval() const;
 
   void              save();
 

+ 2 - 3
SshClient.cpp

@@ -76,10 +76,9 @@ void SshClient::read()
   }
 }
 
-void SshClient::exited(int exitCode)
+void SshClient::exited(int)
 {
-  if(exitCode)
-    reconnect();
+  reconnect();
 }
 
 void SshClient::ping()