]> Some of my projects - anidbudpclient.git/commitdiff
Add proxy.
authorAPTX <marek321@gmail.com>
Thu, 10 Feb 2011 16:30:54 +0000 (17:30 +0100)
committerAPTX <marek321@gmail.com>
Thu, 10 Feb 2011 16:30:54 +0000 (17:30 +0100)
13 files changed:
abstractcommand.cpp
abstractcommand.h
anidbudpclient.pro
client.cpp
client.h
clientinterface.cpp [new file with mode: 0644]
clientinterface.h [new file with mode: 0644]
file.cpp
file.h
proxyclient.cpp [new file with mode: 0644]
proxyclient.h [new file with mode: 0644]
proxyserver.cpp [new file with mode: 0644]
proxyserver.h [new file with mode: 0644]

index 40f822945b1cebb9efbb728c7f46d31727559bf1..24f95730ee58b5dbf22d3af349cb56e75ec50f5d 100644 (file)
@@ -27,11 +27,10 @@ bool AbstractCommand::requiresSession() const
 
 // ===
 
-AbstractReply::AbstractReply(const QByteArray &id, Client *client, QObject *parent) : QObject(parent)
+AbstractReply::AbstractReply(const QByteArray &id, QObject *parent) : QObject(parent)
 {
        m_replyCode = UNKNOWN_REPLY;
        m_id = id;
-       m_client = client;
        m_commandPtr = 0;
        m_controlCommand = false;
 }
index 0484608d5d3fd9a352e4b6c5102d8d49f1c87c3b..335018b564e455b10ff7bbcc9e62d7f8a95e207b 100644 (file)
@@ -34,13 +34,13 @@ public:
 };
 
 #define REPLY_DEFINITION_HELPER_INTERNAL(name, constructor) \
+friend class ClientInterface; \
 friend class Client; \
 public: \
 typedef name##Command CommandType; \
 private: \
 CommandType m_command; \
-Client *m_client; \
-name##Reply(const CommandType command, const QByteArray &id, Client *client, QObject *parent) : AbstractReply(id, client, parent), m_command(command), m_client(client) {constructor} \
+name##Reply(const CommandType command, const QByteArray &id, QObject *parent) : AbstractReply(id, parent), m_command(command) {constructor} \
 inline const CommandType &command() const { return m_command; }
 
 #define REPLY_DEFINITION_HELPER(name) \
@@ -63,7 +63,7 @@ class ANIDBUDPCLIENTSHARED_EXPORT AbstractReply : public QObject
 public:
        typedef AbstractCommand CommandType;
 
-       AbstractReply(const QByteArray &id, Client *client, QObject *parent = 0);
+       AbstractReply(const QByteArray &id, QObject *parent = 0);
        virtual ~AbstractReply();
 
        const CommandType &command() const;
@@ -92,8 +92,6 @@ protected:
        QDateTime m_timeSent;
        bool m_controlCommand;
 
-       Client *m_client;
-
        AbstractCommand *m_commandPtr;
        AbstractCommand m_command;
 };
index cb49877e92c1f70eef7aab12eea279312dfd86da..8c31222159dd3f4475f72b8e513a3f347c3bd218 100644 (file)
@@ -33,7 +33,8 @@ SOURCES += client.cpp \
        hashconsumer.cpp \\r
     clientsentcommandsmodel.cpp \\r
        clientqueuedcommandsmodel.cpp \\r
-    filerenamedelegate.cpp\r
+       filerenamedelegate.cpp \\r
+    clientinterface.cpp\r
 \r
 HEADERS += client.h \\r
     anidbudpclient_global.h \\r
@@ -53,7 +54,8 @@ HEADERS += client.h \
        circularbuffer.h \\r
     clientsentcommandsmodel.h \\r
        clientqueuedcommandsmodel.h \\r
-       filerenamedelegate.h\r
+       filerenamedelegate.h \\r
+    clientinterface.h\r
 \r
 CONV_HEADERS += include/AniDBUdpClient/Client \\r
     include/AniDBUdpClient/AbstractCommand \\r
@@ -69,6 +71,20 @@ CONV_HEADERS += include/AniDBUdpClient/Client \
        include/AniDBUdpClient/ClientQueuedCommandsModel \\r
        include/AniDBUdpClient/FileRenameDelegate\r
 \r
+# proxy files\r
+\r
+CONFIG  += qxt\r
+QXT     *= network\r
+\r
+HEADERS += proxyclient.h \\r
+       proxyserver.h \\r
+\r
+SOURCES += proxyclient.cpp \\r
+       proxyserver.cpp \\r
+\r
+CONV_HEADERS += include/AniDBUdpClient/ProxyClient \\r
+       include/AniDBUdpClient/ProxyServer\r
+\r
 # RenameParser Files\r
 \r
 HEADERS += renameparser/renameengine.h \\r
index 40293666866cc223230c5bc7cd4e902c603eb54f..c3b9a1fe18d192ec6ef32b37743d8b26624e4124 100644 (file)
@@ -22,14 +22,13 @@ const QByteArray Client::clientName = CLIENT_NAME;
 const int Client::clientVersion = CLIENT_VERSION;
 const int Client::protocolVersion = PROTOCOL_VERSION;
 
-Client::Client(QObject *parent) : QObject(parent)
+Client::Client(QObject *parent) : ClientInterface(parent)
 {
 qDebug() << "Api instance init!";
 
        authReply = 0;
        uptimeReply = 0;
 
-       m_error = NoError;
        m_idlePolicy = DoNothingIdlePolicy;
 
        disconnecting = false;
@@ -48,10 +47,6 @@ qDebug() << "Api instance init!";
        replyTimeoutTimer->setSingleShot(true);
        QObject::connect(replyTimeoutTimer, SIGNAL(timeout()), this, SLOT(commandTimeout()));
 
-       m_localPort = 9001;
-       m_host = "api.anidb.info";
-       m_hostPort = 9000;
-
        setFloodInterval(3);
 
        stateMachine = new QStateMachine(this);
@@ -167,39 +162,6 @@ Client::~Client()
        }
 }
 
-QString Client::host() const
-{
-       return m_host;
-}
-
-void Client::setHost(const QString &host, quint16 port)
-{
-       m_host = host;
-       if (port)
-               m_hostPort = port;
-       m_hostAddress = QHostAddress();
-}
-
-quint16 Client::hostPort() const
-{
-       return m_hostPort;
-}
-
-void Client::setHostPort(quint16 port)
-{
-       m_hostPort = port;
-}
-
-quint16 Client::localPort() const
-{
-       return m_localPort;
-}
-
-void Client::setLocalPort(quint16 port)
-{
-       m_localPort = port;
-}
-
 QString Client::user() const
 {
        return authCommand.user();
@@ -250,16 +212,6 @@ void Client::setIdlePolicy(IdlePolicy policy)
        m_idlePolicy = policy;
 }
 
-Error Client::error() const
-{
-       return m_error;
-}
-
-QString Client::errorString() const
-{
-       return m_errorString;
-}
-
 // ------------------------------------------------------------------------------
 
 void Client::enterErrorState()
@@ -886,49 +838,6 @@ void Client::removeDeletedFromQueue(QObject *object)
        if (cmd) cancel(cmd);
 }
 
-QByteArray Client::buildCmd(const QString &cmd, const QVariantMap &args)
-{
-       QString result = cmd;
-       for (QVariantMap::const_iterator it = args.constBegin(); it != args.constEnd(); ++it)
-       {
-               if (!it.value().canConvert(QVariant::String))
-               {
-                       qWarning("Passed value cannot be converted to string!");
-                       continue;
-               }
-
-               // The string version of bool is "true" or "false", but the API expects 1 or 0
-               QString value;
-               if (it.value().type() == QVariant::Bool)
-               {
-                       value = it.value().toBool() ? "1" : "0";
-               }
-               else
-               {
-                       value = it.value().toString();
-               }
-
-               if (it == args.constBegin())
-                       result += QString(" %1=%2").arg(it.key(), value);
-               else
-                       result += QString("&%1=%2").arg(it.key(), value);
-       }
-       return result.toUtf8();
-}
-
-QByteArray Client::nextCommandId(int len)
-{
-       static const char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789";
-       static const int numChars = sizeof(chars) - 1;
-
-       QByteArray result(len, '-');
-       while (len--)
-               result[len] = chars[qrand() % numChars];
-
-qDebug() << QString("Generated id %1").arg(result.constData());
-       return result;
-}
-
 Client *Client::m_instance = 0;
 
 // TODO, figure out why GCC can't export it like it could before, because this doesn't work in other compilers.
index 3b1a4eefe0b6f74abcb416170e377b65c00fc884..78e77812a763b8bda022c42b762aef5002975cf2 100644 (file)
--- a/client.h
+++ b/client.h
@@ -2,12 +2,9 @@
 #define ANIDBUDPCLIENT_H
 
 #include "anidbudpclient_global.h"
-#include <QObject>
+#include "clientinterface.h"
 #include <QQueue>
 #include <QTimer>
-#include <QHostAddress>
-#include <QHostInfo>
-#include <QVariantMap>
 
 #include "authcommand.h"
 
@@ -24,7 +21,7 @@ class AbstractCommand;
 class LogoutReply;
 class UptimeReply;
 
-class ANIDBUDPCLIENTSHARED_EXPORT Client : public QObject
+class ANIDBUDPCLIENTSHARED_EXPORT Client : public ClientInterface
 {
        friend class AbstractReply;
        friend class ClientQueuedCommandsModel;
@@ -33,20 +30,12 @@ class ANIDBUDPCLIENTSHARED_EXPORT Client : public QObject
        Q_OBJECT
        Q_ENUMS(AniDBUdpClient::State AniDBUdpClient::Error AniDBUdpClient::IdlePolicy AniDBUdpClient::ReplyCode);
 
-       Q_PROPERTY(QString host READ host WRITE setHost);
-       Q_PROPERTY(quint16 hostPort READ hostPort WRITE setHostPort);
-       Q_PROPERTY(quint16 localPort READ localPort WRITE setLocalPort);
-
-       Q_PROPERTY(QString user READ user WRITE setUser);
-       Q_PROPERTY(QString pass READ pass WRITE setPass);
-
        /*
-         Send commands in \interval seconds intervals
+         Send commands in interval seconds intervals
        */
-       Q_PROPERTY(int floodInterval READ floodInterval WRITE setFloodInterval);
-       Q_PROPERTY(IdlePolicy idlePolicy READ idlePolicy WRITE setIdlePolicy);
-       Q_PROPERTY(Error error READ error);
-       Q_PROPERTY(QString errorString READ errorString);
+       Q_PROPERTY(int floodInterval READ floodInterval WRITE setFloodInterval)
+       Q_PROPERTY(IdlePolicy idlePolicy READ idlePolicy WRITE setIdlePolicy)
+       Q_PROPERTY(Error error READ error)
 
 public:
        static const QByteArray clientName;
@@ -59,13 +48,6 @@ protected:
 
 public:
        // ------------------ Properties ------------------
-       QString host() const;
-       void setHost(const QString &host, quint16 port = 0);
-       quint16 hostPort() const;
-       void setHostPort(quint16 port);
-       quint16 localPort() const;
-       void setLocalPort(quint16 port);
-
        QString user() const;
        void setUser(const QString &user);
        QString pass() const;
@@ -80,9 +62,6 @@ public:
        IdlePolicy idlePolicy() const;
        void setIdlePolicy(IdlePolicy policy);
 
-       Error error() const;
-       QString errorString() const;
-
        // ---------------- END Properties ----------------
 
        void clearCommandQueue();
@@ -92,11 +71,6 @@ public:
 
 public slots:
        void connect();
-
-       /*
-         Disconnect from host.
-         If \graceful is true send all enququed messages first.
-       */
        void disconnect(bool graceful = false);
 
 public:
@@ -107,11 +81,12 @@ public:
                return reply;
        }
 
-private:
+protected:
        template<typename T> typename T::ReplyType *createReply(const T &command, QObject *parent = 0)
        {
-               return new typename T::ReplyType(command, nextCommandId(), this, parent);
+               return new typename T::ReplyType(command, nextCommandId(), parent);
        }
+
 public slots:
 
        void send(AbstractReply *reply);
@@ -137,8 +112,6 @@ signals:
        void replyRecieved();
        void sendFailed();
 
-       void connectionError();
-
        void model_queuedCommandAdded(int index);
        void model_queuedCommandRemoved(int index);
        void model_sentCommandAdded(int index);
@@ -178,9 +151,6 @@ private:
 
        void logout(bool force);
 
-       QByteArray buildCmd(const QString &cmd, const QVariantMap &args);
-       QByteArray nextCommandId(int len = 5);
-
        QTimer *commandTimer;
        QTimer *idleTimer;
        QTimer *replyTimeoutTimer;
@@ -192,13 +162,6 @@ private:
        QUdpSocket *socket;
 
 
-
-       // Connection params
-       QString m_host;
-       QHostAddress m_hostAddress;
-       quint16 m_hostPort;
-       quint16 m_localPort;
-
        int m_floodInterval;
 
        QByteArray m_sessionId;
@@ -206,7 +169,6 @@ private:
        // Misc params
        IdlePolicy m_idlePolicy;
        Error m_error;
-       QString m_errorString;
 
        bool disconnecting;
        bool authenticatingStarted;
diff --git a/clientinterface.cpp b/clientinterface.cpp
new file mode 100644 (file)
index 0000000..2db90ec
--- /dev/null
@@ -0,0 +1,99 @@
+#include "clientinterface.h"
+
+namespace AniDBUdpClient {
+
+ClientInterface::ClientInterface(QObject *parent) :
+       QObject(parent), m_error(NoError)
+{
+       m_localPort = 9001;
+       m_host = "api.anidb.info";
+       m_hostPort = 9000;
+}
+
+QString ClientInterface::host() const
+{
+       return m_host;
+}
+
+void ClientInterface::setHost(const QString &host, quint16 port)
+{
+       m_host = host;
+       if (port)
+               m_hostPort = port;
+       m_hostAddress = QHostAddress();
+}
+
+quint16 ClientInterface::hostPort() const
+{
+       return m_hostPort;
+}
+
+void ClientInterface::setHostPort(quint16 port)
+{
+       m_hostPort = port;
+}
+
+quint16 ClientInterface::localPort() const
+{
+       return m_localPort;
+}
+
+void ClientInterface::setLocalPort(quint16 port)
+{
+       m_localPort = port;
+}
+
+Error ClientInterface::error() const
+{
+       return m_error;
+}
+
+QString ClientInterface::errorString() const
+{
+       return m_errorString;
+}
+
+QByteArray ClientInterface::nextCommandId(int len)
+{
+       static const char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789";
+       static const int numChars = sizeof(chars) - 1;
+
+       QByteArray result(len, '-');
+       while (len--)
+               result[len] = chars[qrand() % numChars];
+
+qDebug() << QString("Generated id %1").arg(result.constData());
+       return result;
+}
+
+QByteArray ClientInterface::buildCmd(const QString &cmd, const QVariantMap &args)
+{
+       QString result = cmd;
+       for (QVariantMap::const_iterator it = args.constBegin(); it != args.constEnd(); ++it)
+       {
+               if (!it.value().canConvert(QVariant::String))
+               {
+                       qWarning("Passed value cannot be converted to string!");
+                       continue;
+               }
+
+               // The string version of bool is "true" or "false", but the API expects 1 or 0
+               QString value;
+               if (it.value().type() == QVariant::Bool)
+               {
+                       value = it.value().toBool() ? "1" : "0";
+               }
+               else
+               {
+                       value = it.value().toString();
+               }
+
+               if (it == args.constBegin())
+                       result += QString(" %1=%2").arg(it.key(), value);
+               else
+                       result += QString("&%1=%2").arg(it.key(), value);
+       }
+       return result.toUtf8();
+}
+
+} // namespace AniDBUdpClient
diff --git a/clientinterface.h b/clientinterface.h
new file mode 100644 (file)
index 0000000..9851ad4
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef CLIENTINTERFACE_H
+#define CLIENTINTERFACE_H
+
+#include "anidbudpclient_global.h"
+#include <QObject>
+#include <QHostAddress>
+#include <QHostInfo>
+#include <QVariantMap>
+
+namespace AniDBUdpClient {
+
+class AbstractReply;
+
+class ANIDBUDPCLIENTSHARED_EXPORT ClientInterface : public QObject
+{
+       Q_OBJECT
+       Q_PROPERTY(QString host READ host WRITE setHost)
+       Q_PROPERTY(quint16 hostPort READ hostPort WRITE setHostPort)
+       Q_PROPERTY(quint16 localPort READ localPort WRITE setLocalPort)
+
+       Q_PROPERTY(QString user READ user WRITE setUser)
+       Q_PROPERTY(QString pass READ pass WRITE setPass)
+
+       Q_PROPERTY(QString errorString READ errorString)
+
+public:
+       ClientInterface(QObject *parent = 0);
+       virtual ~ClientInterface() {}
+
+       QString host() const;
+       void setHost(const QString &host, quint16 port = 0);
+       quint16 hostPort() const;
+       void setHostPort(quint16 port);
+       quint16 localPort() const;
+       void setLocalPort(quint16 port);
+
+       virtual QString user() const = 0;
+       virtual void setUser(const QString &user) = 0;
+       virtual QString pass() const = 0;
+       virtual void setPass(const QString &user) = 0;
+
+       Error error() const;
+       QString errorString() const;
+
+       template<typename T> typename T::ReplyType *send(const T &command, QObject *parent = 0)
+       {
+               typename T::ReplyType *reply = createReply(command, parent);
+               send(reply);
+               return reply;
+       }
+
+protected:
+       template<typename T> typename T::ReplyType *createReply(const T &command, QObject *parent = 0)
+       {
+               return new typename T::ReplyType(command, nextCommandId(), parent);
+       }
+
+public slots:
+       virtual void connect() = 0;
+       virtual void disconnect(bool graceful = false) = 0;
+
+       virtual void send(AbstractReply *reply) = 0;
+
+//     virtual void sendRaw(QByteArray command) = 0;
+       virtual void cancel(AbstractReply *command) = 0;
+
+signals:
+       void connectionError();
+
+protected:
+       QByteArray nextCommandId(int len = 5);
+       QByteArray buildCmd(const QString &cmd, const QVariantMap &args);
+
+       // Connection params
+       QString m_host;
+       QHostAddress m_hostAddress;
+       quint16 m_hostPort;
+       quint16 m_localPort;
+
+       Error m_error;
+       QString m_errorString;
+};
+
+} // namespace AniDBUdpClient
+
+#endif // CLIENTINTERFACE_H
index c58ab991b214cd4ac629b4cacdc2ec11e2b44fa7..75375b956c9294515655953580112282f8897004 100644 (file)
--- a/file.cpp
+++ b/file.cpp
@@ -353,7 +353,7 @@ qDebug() << "startRenaming";
                fileCommand.setFmask(m_renameDelegate->requiredFMask());
        }
 
-       fileReply = Client::instance()->send(fileCommand);
+       fileReply = clientInstance()->send(fileCommand);
        connect(fileReply, SIGNAL(replyReady(bool)), this, SLOT(finishRenaming(bool)));
 
        updateStatus(Renaming, InProgress);
@@ -373,7 +373,7 @@ void File::startAdding()
        MyListAddCommand addCommand(m_ed2k, size(), false);
        addCommand.setState(StateOnHdd);
 
-       addReply = Client::instance()->send(addCommand);
+       addReply = clientInstance()->send(addCommand);
 
        connect(addReply, SIGNAL(replyReady(bool)), this, SLOT(finishAdding(bool)));
 
@@ -396,7 +396,7 @@ void File::startMarking()
        markCommand.setViewed(true);
 
        if (markReply) markReply->deleteLater();
-       markReply = Client::instance()->send(markCommand);
+       markReply = clientInstance()->send(markCommand);
        connect(markReply, SIGNAL(replyReady(bool)), this, SLOT(finishMarking(bool)));
 
        updateStatus(MarkingWatched, InProgress);
@@ -443,4 +443,22 @@ void File::updateStatus(Action action, ActionState actionState)
        emit statusUpdate(action, actionState);
 }
 
+
+ClientInterface *File::clientInstance() const
+{
+       return m_clientInterface ? m_clientInterface : Client::instance();
+}
+
+ClientInterface *File::m_clientInterface = 0;
+
+ClientInterface *File::clientInterface()
+{
+       return m_clientInterface;
+}
+
+void File::setClientInterface(ClientInterface *clientInterface)
+{
+       m_clientInterface = clientInterface;
+}
+
 } // namespace AniDBUdpClient
diff --git a/file.h b/file.h
index 8422ffcfbad73341a655ff5f7e889b72c4655de4..3174f5911484e479bf719bea929f1981f501ef07 100644 (file)
--- a/file.h
+++ b/file.h
@@ -128,6 +128,13 @@ private:
 
        FileRenameDelegate *m_renameDelegate;
 
+       ClientInterface *clientInstance() const;
+
+       static ClientInterface *m_clientInterface;
+public:
+       static ClientInterface *clientInterface();
+       static void setClientInterface(ClientInterface *clientInterface);
+
 };
 
 } // namespace AniDBUdpClient
diff --git a/proxyclient.cpp b/proxyclient.cpp
new file mode 100644 (file)
index 0000000..b8336b2
--- /dev/null
@@ -0,0 +1,105 @@
+#include "proxyclient.h"
+
+#include <QxtRPCPeer>
+
+#include "abstractcommand.h"
+
+#include <QDebug>
+
+namespace AniDBUdpClient {
+
+ProxyClient::ProxyClient(QObject *parent) :
+       ClientInterface(parent), peer(new QxtRPCPeer)
+{
+       m_hostPort = 9001;
+       peer->attachSlot("replyRecieved", this, SLOT(replyRecieved(QByteArray,int,QString)));
+       peer->attachSlot("errorRecieved", this, SLOT(errorRecieved(int)));
+}
+
+ProxyClient::~ProxyClient()
+{
+       disconnect();
+       delete peer;
+}
+
+QString ProxyClient::user() const
+{
+       return m_user;
+}
+
+void ProxyClient::setUser(const QString &user)
+{
+       m_user = user;
+}
+
+QString ProxyClient::pass() const
+{
+       return m_pass;
+}
+
+void ProxyClient::setPass(const QString &pass)
+{
+       m_pass = pass;
+}
+
+void ProxyClient::connect()
+{
+       peer->connect(m_host, m_hostPort);
+       peer->call("auth", m_user, m_pass);
+qDebug() << "[CLIENT] CALL auth" << m_user << m_pass;
+}
+
+void ProxyClient::disconnect(bool graceful)
+{
+       Q_UNUSED(graceful);
+       peer->disconnectServer();
+
+       for (QMap<QByteArray, AbstractReply *>::const_iterator i = commands.constBegin(); i != commands.constEnd(); ++i)
+       {
+               i.value()->setRawReply(CLIENT_DESTROYED, "");
+       }
+       commands.clear();
+}
+
+void ProxyClient::send(AbstractReply *reply)
+{
+       if (reply->command().waitForResult())
+               commands[reply->id()] = reply;
+
+       Command cmd = reply->command().rawCommand();
+       peer->call("sendCommand", reply->id(), buildCmd(cmd.first, cmd.second));
+qDebug() << "[CLIENT] CALL sendCommand" << reply->id() << buildCmd(cmd.first, cmd.second);
+       if (!reply->command().waitForResult())
+               delete reply;
+}
+
+void ProxyClient::cancel(AbstractReply *command)
+{
+       peer->call("cancel", command->id());
+qDebug() << "[CLIENT] CALL cancel";
+}
+
+void ProxyClient::replyRecieved(const QByteArray &id, int replyCodeAsInt, const QString &reply)
+{
+       ReplyCode replyCode = (ReplyCode) replyCodeAsInt;
+qDebug() << "[CLIENT] RECV replyRecieved" << id << replyCode << reply;
+       AbstractReply *command = commands.value(id, 0);
+
+       if (!command)
+       {
+               // Not interested in this reply
+               return;
+       }
+
+       command->setRawReply(replyCode, reply);
+}
+
+void ProxyClient::errorRecieved(int errorAsInt)
+{
+       Error error = (Error) errorAsInt;
+qDebug() << "[CLIENT] RECV errorRecieved" << error;
+       m_error = error;
+       emit connectionError();
+}
+
+} // namespace AniDBUdpClient
diff --git a/proxyclient.h b/proxyclient.h
new file mode 100644 (file)
index 0000000..c91c5ab
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef PROXYCLIENT_H
+#define PROXYCLIENT_H
+
+#include "anidbudpclient_global.h"
+#include "clientinterface.h"
+
+class QxtRPCPeer;
+
+namespace AniDBUdpClient {
+
+class ANIDBUDPCLIENTSHARED_EXPORT ProxyClient : public ClientInterface
+{
+    Q_OBJECT
+public:
+    explicit ProxyClient(QObject *parent = 0);
+       ~ProxyClient();
+
+       QString user() const;
+       void setUser(const QString &user);
+       QString pass() const;
+       void setPass(const QString &pass);
+
+       template<typename T> typename T::ReplyType *send(const T &command, QObject *parent = 0)
+       {
+               typename T::ReplyType *reply = createReply(command, parent);
+               send(reply);
+               return reply;
+       }
+
+protected:
+       template<typename T> typename T::ReplyType *createReply(const T &command, QObject *parent = 0)
+       {
+               return new typename T::ReplyType(command, nextCommandId(), parent);
+       }
+
+public slots:
+       void connect();
+       void disconnect(bool graceful = false);
+
+       void send(AbstractReply *reply);
+
+       void cancel(AbstractReply *command);
+
+private slots:
+       void replyRecieved(const QByteArray &id, int replyCodeAsInt, const QString &reply);
+       void errorRecieved(int errorAsInt);
+
+private:
+       QString m_user;
+       QString m_pass;
+
+       QxtRPCPeer *peer;
+
+       QMap<QByteArray, AbstractReply *> commands;
+};
+
+} // namespace AniDBUdpClient
+
+#endif // PROXYCLIENT_H
diff --git a/proxyserver.cpp b/proxyserver.cpp
new file mode 100644 (file)
index 0000000..f57768e
--- /dev/null
@@ -0,0 +1,164 @@
+#include "proxyserver.h"
+#include <QxtRPCPeer>
+
+#include "client.h"
+#include "rawcommand.h"
+
+#include <QDebug>
+
+namespace AniDBUdpClient {
+
+ProxyServer::ProxyServer(QObject *parent) :
+       QObject(parent), peer(new QxtRPCPeer)
+{
+       connect(peer, SIGNAL(clientConnected(quint64)), this, SLOT(clientConnected(quint64)));
+       connect(peer, SIGNAL(clientDisconnected(quint64)), this, SLOT(clientDisconnected(quint64)));
+       peer->attachSlot("auth", this, SLOT(auth(quint64,QString,QString)));
+       peer->attachSlot("sendCommand", this, SLOT(sendCommand(quint64,QByteArray,QByteArray)));
+       peer->attachSlot("cancel", this, SLOT(cancel(quint64,QByteArray)));
+}
+
+ProxyServer::~ProxyServer()
+{
+       peer->disconnectAll();
+
+       clientInfo.clear();
+       clientCommands.clear();
+       qDeleteAll(idMapping);
+       idMapping.clear();
+/*     for (QMap<RawReply *, QByteArray>::const_iterator i = replyMapping.constBegin(); i != replyMapping.constEnd(); ++i)
+       {
+               i.key()->deleteLater();
+       }
+*/
+       replyMapping.clear();
+
+       delete peer;
+}
+
+QString ProxyServer::user() const
+{
+       return m_user;
+}
+
+void ProxyServer::setUser(const QString &user)
+{
+       m_user = user;
+}
+
+QString ProxyServer::pass() const
+{
+       return m_pass;
+}
+
+void ProxyServer::setPass(const QString &pass)
+{
+       m_pass = pass;
+}
+
+bool ProxyServer::listen(QHostAddress iface, int port)
+{
+       return peer->listen(iface, port);
+}
+
+void ProxyServer::diconnect()
+{
+       peer->disconnectAll();
+}
+
+void ProxyServer::auth(quint64 client, const QString &user, const QString &pass)
+{
+qDebug() << "[SERVER] RECV auth" << client << user << pass;
+       if (isAuthed(client))
+               return;
+
+       if (m_user != user || m_pass != pass)
+       {
+               peer->call(client, "errorRecieved", (int) AuthenticationError);
+qDebug() << "[SERVER] CALL errorRecieved" << AuthenticationError;
+               peer->disconnectClient(client);
+               return;
+       }
+       clientInfo[client].authed = true;
+       qDebug() << "[SERVER] Auth successful" << client;
+
+}
+
+void ProxyServer::sendCommand(quint64 client, const QByteArray &id, const QByteArray &rawCommand)
+{
+qDebug() << "[SERVER] RECV sendCommand" << client << id << rawCommand;
+       if (!isAuthed(client))
+               return;
+
+       RawReply *reply = Client::instance()->send(RawCommand(rawCommand));
+       connect(reply, SIGNAL(replyReady(bool)), this, SLOT(replyReady(bool)));
+
+       clientCommands[id] = client;
+       replyMapping[reply] = id;
+       idMapping[id] = reply;
+}
+
+void ProxyServer::cancel(quint64 client, const QByteArray &id)
+{
+       if (!isAuthed(client))
+               return;
+
+       if (!idMapping.contains(id))
+               return;
+
+       RawReply *reply = idMapping.take(id);
+       replyMapping.remove(reply);
+       clientCommands.remove(id);
+
+       Client::instance()->cancel(reply);
+       reply->deleteLater();
+}
+
+void ProxyServer::clientConnected(quint64 client)
+{
+qDebug() << "client connected" << client;
+       clientInfo.insert(client, ClientInfo());
+}
+
+void ProxyServer::clientDisconnected(quint64 client)
+{
+qDebug() << "[SERVER] RECV client disconnected" << client;
+       for (QMap<QByteArray, quint64>::iterator i = clientCommands.begin(); i != clientCommands.end(); )
+       {
+               if (i.value() != client)
+               {
+                       ++i;
+                       continue;
+               }
+
+               RawReply *reply = idMapping.take(i.key());
+               Client::instance()->cancel(reply);
+               replyMapping.remove(reply);
+               reply->deleteLater();
+               clientCommands.erase(i);
+       }
+
+       clientInfo.remove(client);
+}
+
+void ProxyServer::replyReady(bool success)
+{
+       Q_UNUSED(success);
+
+       RawReply *reply = (RawReply *) sender();
+
+       QByteArray id = replyMapping.take(reply);
+       quint64 client = clientCommands.take(id);
+       idMapping.remove(id);
+
+       peer->call(client, "replyRecieved", id, (int) reply->replyCode(), reply->rawReply());
+qDebug() << "[SERVER] CALL replyRecieved" << id << reply->replyCode() << reply->rawReply();
+       reply->deleteLater();
+}
+
+bool ProxyServer::isAuthed(quint64 client) const
+{
+       return clientInfo[client].authed;
+}
+
+} // namespace AniDBUdpClient
diff --git a/proxyserver.h b/proxyserver.h
new file mode 100644 (file)
index 0000000..df3a1a4
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef PROXYSERVER_H
+#define PROXYSERVER_H
+
+#include "anidbudpclient_global.h"
+#include <QObject>
+#include <QHostAddress>
+
+class QxtRPCPeer;
+
+namespace AniDBUdpClient {
+
+class RawReply;
+
+class ANIDBUDPCLIENTSHARED_EXPORT ProxyServer : public QObject
+{
+    Q_OBJECT
+       Q_PROPERTY(QString user READ user WRITE setUser)
+       Q_PROPERTY(QString pass READ pass WRITE setPass)
+
+       struct ClientInfo {
+               bool authed;
+
+               explicit ClientInfo() : authed(false) {}
+       };
+
+public:
+    explicit ProxyServer(QObject *parent = 0);
+       ~ProxyServer();
+
+       QString user() const;
+       void setUser(const QString &user);
+       QString pass() const;
+       void setPass(const QString &pass);
+
+signals:
+
+public slots:
+       bool listen(QHostAddress iface = QHostAddress::Any, int port = 9001);
+       void diconnect();
+
+private slots:
+       void auth(quint64 client, const QString &user, const QString &pass);
+       void sendCommand(quint64 client, const QByteArray &id, const QByteArray &rawCommand);
+       void cancel(quint64 client, const QByteArray &id);
+
+       void clientConnected(quint64 client);
+       void clientDisconnected(quint64 client);
+
+       void replyReady(bool success);
+
+private:
+       bool isAuthed(quint64 client) const;
+
+       QString m_user;
+       QString m_pass;
+
+       QxtRPCPeer *peer;
+
+       QMap<quint64, ClientInfo> clientInfo;
+       QMap<QByteArray, quint64> clientCommands;
+       QMap<QByteArray, RawReply *> idMapping;
+       QMap<RawReply *, QByteArray> replyMapping;
+};
+
+} // namespace AniDBUdpClient
+
+#endif // PROXYSERVER_H