mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-10-01 02:35:48 -04:00
Merge pull request #464 from G10h4ck/libresapilocal
ApiServerLocal run on it's own thread to avoid stopping UI
This commit is contained in:
commit
c0c7ede97b
@ -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