mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-01-14 08:59:50 -05:00
ApiServerLocal run on it's own thread to avoid stopping UI
ApiLocalConnectionHandler can now handle both buffered (QLocalSocket based) and unbuffered (like ncat or simple scripts) clients
This commit is contained in:
parent
70228ee405
commit
183ac22aba
@ -1,12 +1,39 @@
|
||||
/*
|
||||
* libresapi local socket server
|
||||
* Copyright (C) 2016 Gioacchino Mazzurco <gio@eigenlab.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ApiServerLocal.h"
|
||||
#include "JsonStream.h"
|
||||
|
||||
namespace resource_api{
|
||||
|
||||
ApiServerLocal::ApiServerLocal(ApiServer* server) : QThread(),
|
||||
mApiServer(server), mLocalServer(this)
|
||||
ApiServerLocal::ApiServerLocal(ApiServer* server, QObject *parent) :
|
||||
QObject(parent), serverThread(this),
|
||||
localListener(server) // Must have no parent to be movable to other thread
|
||||
{
|
||||
localListener.moveToThread(&serverThread);
|
||||
serverThread.start();
|
||||
}
|
||||
|
||||
ApiServerLocal::~ApiServerLocal() { serverThread.quit(); }
|
||||
|
||||
ApiLocalListener::ApiLocalListener(ApiServer *server, QObject *parent) :
|
||||
QObject(parent), mApiServer(server), mLocalServer(this)
|
||||
{
|
||||
start();
|
||||
mLocalServer.removeServer(serverName());
|
||||
#if QT_VERSION >= 0x050000
|
||||
mLocalServer.setSocketOptions(QLocalServer::UserAccessOption);
|
||||
@ -15,56 +42,72 @@ ApiServerLocal::ApiServerLocal(ApiServer* server) : QThread(),
|
||||
mLocalServer.listen(serverName());
|
||||
}
|
||||
|
||||
ApiServerLocal::~ApiServerLocal()
|
||||
void ApiLocalListener::handleConnection()
|
||||
{
|
||||
mLocalServer.close();
|
||||
quit();
|
||||
new ApiLocalConnectionHandler(mApiServer,
|
||||
mLocalServer.nextPendingConnection(), this);
|
||||
}
|
||||
|
||||
void ApiServerLocal::handleConnection()
|
||||
ApiLocalConnectionHandler::ApiLocalConnectionHandler(
|
||||
ApiServer* apiServer, QLocalSocket* sock, QObject *parent) :
|
||||
QObject(parent), mApiServer(apiServer), mLocalSocket(sock),
|
||||
mState(WAITING_PATH)
|
||||
{
|
||||
new ApiLocalConnectionHandler(mApiServer, mLocalServer.nextPendingConnection());
|
||||
connect(mLocalSocket, SIGNAL(disconnected()), this, SLOT(deleteLater()));
|
||||
connect(sock, SIGNAL(readyRead()), this, SLOT(handlePendingRequests()));
|
||||
}
|
||||
|
||||
ApiLocalConnectionHandler::ApiLocalConnectionHandler(ApiServer* apiServer, QLocalSocket* sock) :
|
||||
QThread(), mApiServer(apiServer), mLocalSocket(sock)
|
||||
ApiLocalConnectionHandler::~ApiLocalConnectionHandler()
|
||||
{
|
||||
sock->moveToThread(this);
|
||||
connect(this, SIGNAL(finished()), this, SLOT(deleteLater()));
|
||||
connect(mLocalSocket, SIGNAL(disconnected()), this, SLOT(quit()));
|
||||
connect(sock, SIGNAL(readyRead()), this, SLOT(handleRequest()));
|
||||
start();
|
||||
mLocalSocket->close();
|
||||
delete mLocalSocket;
|
||||
}
|
||||
|
||||
void ApiLocalConnectionHandler::handleRequest()
|
||||
void ApiLocalConnectionHandler::handlePendingRequests()
|
||||
{
|
||||
char path[1024];
|
||||
if(mLocalSocket->readLine(path, 1023) > 0)
|
||||
switch(mState)
|
||||
{
|
||||
reqPath = path;
|
||||
char jsonData[20480];
|
||||
if(mLocalSocket->read(jsonData, 20479) > 0)
|
||||
case WAITING_PATH:
|
||||
{
|
||||
if(mLocalSocket->canReadLine())
|
||||
{
|
||||
readPath:
|
||||
reqPath = mLocalSocket->readLine().constData();
|
||||
mState = WAITING_DATA;
|
||||
|
||||
/* Because QLocalSocket is SOCK_STREAM some clients implementations
|
||||
* like the one based on QLocalSocket feel free to send the whole
|
||||
* request (PATH + DATA) in a single write(), causing readyRead()
|
||||
* signal being emitted only once, in that case we should continue
|
||||
* processing without waiting for readyRead() being fired again, so
|
||||
* we don't break here as there may be more lines to read */
|
||||
}
|
||||
}
|
||||
case WAITING_DATA:
|
||||
{
|
||||
if(mLocalSocket->canReadLine())
|
||||
{
|
||||
resource_api::JsonStream reqJson;
|
||||
reqJson.setJsonString(std::string(jsonData));
|
||||
reqJson.setJsonString(std::string(mLocalSocket->readLine().constData()));
|
||||
resource_api::Request req(reqJson);
|
||||
req.setPath(reqPath);
|
||||
std::string resultString = mApiServer->handleRequest(req);
|
||||
mLocalSocket->write(resultString.c_str(), resultString.length());
|
||||
mLocalSocket->write("\n\0");
|
||||
mState = WAITING_PATH;
|
||||
|
||||
/* Because QLocalSocket is SOCK_STREAM some clients implementations
|
||||
* like the one based on QLocalSocket feel free to coalesce multiple
|
||||
* upper level write() into a single socket write(), causing
|
||||
* readyRead() signal being emitted only once, in that case we should
|
||||
* keep processing without waiting for readyRead() being fired again */
|
||||
if(mLocalSocket->canReadLine()) goto readPath;
|
||||
|
||||
// Now there are no more requests to process we can break
|
||||
break;
|
||||
}
|
||||
else mLocalSocket->write("\"{\"data\":null,\"debug_msg\":\"ApiLocalConnectionHandler::handleRequest() Error: timeout waiting for path.\\n\",\"returncode\":\"fail\"}\"\n\0");
|
||||
}
|
||||
else mLocalSocket->write("{\"data\":null,\"debug_msg\":\"ApiLocalConnectionHandler::handleRequest() Error: timeout waiting for JSON data.\\n\",\"returncode\":\"fail\"}\"\n\0");
|
||||
|
||||
quit();
|
||||
}
|
||||
|
||||
ApiLocalConnectionHandler::~ApiLocalConnectionHandler()
|
||||
{
|
||||
mLocalSocket->flush();
|
||||
mLocalSocket->close();
|
||||
mLocalSocket->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace resource_api
|
||||
|
@ -1,4 +1,21 @@
|
||||
#pragma once
|
||||
/*
|
||||
* libresapi local socket server
|
||||
* Copyright (C) 2016 Gioacchino Mazzurco <gio@eigenlab.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <QLocalServer>
|
||||
#include <QString>
|
||||
@ -11,22 +28,14 @@
|
||||
|
||||
namespace resource_api
|
||||
{
|
||||
class ApiServer;
|
||||
|
||||
class ApiServerLocal : public QThread
|
||||
class ApiLocalListener : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ApiServerLocal(ApiServer* server);
|
||||
~ApiServerLocal();
|
||||
|
||||
public slots:
|
||||
void handleConnection();
|
||||
|
||||
private:
|
||||
ApiServer* mApiServer;
|
||||
QLocalServer mLocalServer;
|
||||
ApiLocalListener(ApiServer* server, QObject *parent=0);
|
||||
~ApiLocalListener() { mLocalServer.close(); }
|
||||
|
||||
const static QString& serverName()
|
||||
{
|
||||
@ -34,24 +43,45 @@ private:
|
||||
.append("/libresapi.sock").c_str());
|
||||
return sockPath;
|
||||
}
|
||||
|
||||
public slots:
|
||||
void handleConnection();
|
||||
|
||||
private:
|
||||
ApiServer* mApiServer;
|
||||
QLocalServer mLocalServer;
|
||||
};
|
||||
|
||||
class ApiLocalConnectionHandler : public QThread
|
||||
class ApiServerLocal : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ApiLocalConnectionHandler(ApiServer* apiServer, QLocalSocket* sock);
|
||||
ApiServerLocal(ApiServer* server, QObject *parent=0);
|
||||
~ApiServerLocal();
|
||||
|
||||
private:
|
||||
QThread serverThread;
|
||||
ApiLocalListener localListener;
|
||||
};
|
||||
|
||||
class ApiLocalConnectionHandler : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ApiLocalConnectionHandler(ApiServer* apiServer, QLocalSocket* sock, QObject *parent = 0);
|
||||
~ApiLocalConnectionHandler();
|
||||
enum State {WAITING_PATH, WAITING_DATA};
|
||||
|
||||
public slots:
|
||||
void handleRequest();
|
||||
void handlePendingRequests();
|
||||
|
||||
private:
|
||||
ApiServer* mApiServer;
|
||||
QLocalSocket* mLocalSocket;
|
||||
State mState;
|
||||
std::string reqPath;
|
||||
void _die();
|
||||
};
|
||||
|
||||
} // namespace resource_api
|
||||
|
Loading…
Reference in New Issue
Block a user