From 98d884d4e06eae56276c82f5d3c985a20404cbf7 Mon Sep 17 00:00:00 2001 From: APTX Date: Thu, 10 Feb 2011 17:30:54 +0100 Subject: [PATCH] Add proxy. --- abstractcommand.cpp | 3 +- abstractcommand.h | 8 +-- anidbudpclient.pro | 20 +++++- client.cpp | 93 +------------------------ client.h | 56 +++------------ clientinterface.cpp | 99 ++++++++++++++++++++++++++ clientinterface.h | 86 +++++++++++++++++++++++ file.cpp | 24 ++++++- file.h | 7 ++ proxyclient.cpp | 105 ++++++++++++++++++++++++++++ proxyclient.h | 59 ++++++++++++++++ proxyserver.cpp | 164 ++++++++++++++++++++++++++++++++++++++++++++ proxyserver.h | 67 ++++++++++++++++++ 13 files changed, 640 insertions(+), 151 deletions(-) create mode 100644 clientinterface.cpp create mode 100644 clientinterface.h create mode 100644 proxyclient.cpp create mode 100644 proxyclient.h create mode 100644 proxyserver.cpp create mode 100644 proxyserver.h diff --git a/abstractcommand.cpp b/abstractcommand.cpp index 40f8229..24f9573 100644 --- a/abstractcommand.cpp +++ b/abstractcommand.cpp @@ -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; } diff --git a/abstractcommand.h b/abstractcommand.h index 0484608..335018b 100644 --- a/abstractcommand.h +++ b/abstractcommand.h @@ -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; }; diff --git a/anidbudpclient.pro b/anidbudpclient.pro index cb49877..8c31222 100644 --- a/anidbudpclient.pro +++ b/anidbudpclient.pro @@ -33,7 +33,8 @@ SOURCES += client.cpp \ hashconsumer.cpp \ clientsentcommandsmodel.cpp \ clientqueuedcommandsmodel.cpp \ - filerenamedelegate.cpp + filerenamedelegate.cpp \ + clientinterface.cpp HEADERS += client.h \ anidbudpclient_global.h \ @@ -53,7 +54,8 @@ HEADERS += client.h \ circularbuffer.h \ clientsentcommandsmodel.h \ clientqueuedcommandsmodel.h \ - filerenamedelegate.h + filerenamedelegate.h \ + clientinterface.h CONV_HEADERS += include/AniDBUdpClient/Client \ include/AniDBUdpClient/AbstractCommand \ @@ -69,6 +71,20 @@ CONV_HEADERS += include/AniDBUdpClient/Client \ include/AniDBUdpClient/ClientQueuedCommandsModel \ include/AniDBUdpClient/FileRenameDelegate +# proxy files + +CONFIG += qxt +QXT *= network + +HEADERS += proxyclient.h \ + proxyserver.h \ + +SOURCES += proxyclient.cpp \ + proxyserver.cpp \ + +CONV_HEADERS += include/AniDBUdpClient/ProxyClient \ + include/AniDBUdpClient/ProxyServer + # RenameParser Files HEADERS += renameparser/renameengine.h \ diff --git a/client.cpp b/client.cpp index 4029366..c3b9a1f 100644 --- a/client.cpp +++ b/client.cpp @@ -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. diff --git a/client.h b/client.h index 3b1a4ee..78e7781 100644 --- a/client.h +++ b/client.h @@ -2,12 +2,9 @@ #define ANIDBUDPCLIENT_H #include "anidbudpclient_global.h" -#include +#include "clientinterface.h" #include #include -#include -#include -#include #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::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 index 0000000..2db90ec --- /dev/null +++ b/clientinterface.cpp @@ -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 index 0000000..9851ad4 --- /dev/null +++ b/clientinterface.h @@ -0,0 +1,86 @@ +#ifndef CLIENTINTERFACE_H +#define CLIENTINTERFACE_H + +#include "anidbudpclient_global.h" +#include +#include +#include +#include + +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::ReplyType *send(const T &command, QObject *parent = 0) + { + typename T::ReplyType *reply = createReply(command, parent); + send(reply); + return reply; + } + +protected: + template 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 diff --git a/file.cpp b/file.cpp index c58ab99..75375b9 100644 --- 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 8422ffc..3174f59 100644 --- 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 index 0000000..b8336b2 --- /dev/null +++ b/proxyclient.cpp @@ -0,0 +1,105 @@ +#include "proxyclient.h" + +#include + +#include "abstractcommand.h" + +#include + +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::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 index 0000000..c91c5ab --- /dev/null +++ b/proxyclient.h @@ -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::ReplyType *send(const T &command, QObject *parent = 0) + { + typename T::ReplyType *reply = createReply(command, parent); + send(reply); + return reply; + } + +protected: + template 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 commands; +}; + +} // namespace AniDBUdpClient + +#endif // PROXYCLIENT_H diff --git a/proxyserver.cpp b/proxyserver.cpp new file mode 100644 index 0000000..f57768e --- /dev/null +++ b/proxyserver.cpp @@ -0,0 +1,164 @@ +#include "proxyserver.h" +#include + +#include "client.h" +#include "rawcommand.h" + +#include + +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::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::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 index 0000000..df3a1a4 --- /dev/null +++ b/proxyserver.h @@ -0,0 +1,67 @@ +#ifndef PROXYSERVER_H +#define PROXYSERVER_H + +#include "anidbudpclient_global.h" +#include +#include + +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 clientInfo; + QMap clientCommands; + QMap idMapping; + QMap replyMapping; +}; + +} // namespace AniDBUdpClient + +#endif // PROXYSERVER_H -- 2.52.0