mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-05-20 23:10:39 -04:00
Allow only one instance for useLocalServer option activated. If exists,
pass to it arguments. For now, only allow to pass RsCollection file and retroshare:// protocol.
This commit is contained in:
parent
9871b37ef2
commit
10bb542e83
19 changed files with 547 additions and 426 deletions
|
@ -20,51 +20,67 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
****************************************************************/
|
||||
|
||||
#include <QDir>
|
||||
#include <QTimer>
|
||||
#include <QTextStream>
|
||||
#include <QShortcut>
|
||||
#include <QStyleFactory>
|
||||
#include <QStyle>
|
||||
#include <QString>
|
||||
#include <QLocale>
|
||||
#include <QRegExp>
|
||||
#include <QBuffer>
|
||||
#include <QDateTime>
|
||||
#include <gui/common/vmessagebox.h>
|
||||
#include <gui/common/html.h>
|
||||
#include <util/stringutil.h>
|
||||
#include <stdlib.h>
|
||||
#include <QDir>
|
||||
#include <QFileOpenEvent>
|
||||
#include <QLocale>
|
||||
#include <QLocalSocket>
|
||||
#include <QRegExp>
|
||||
#include <QSharedMemory>
|
||||
#include <QShortcut>
|
||||
#include <QString>
|
||||
#include <QStyle>
|
||||
#include <QStyleFactory>
|
||||
#include <QTextStream>
|
||||
#include <QTimer>
|
||||
#ifdef __APPLE__
|
||||
#include <QUrl>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <gui/common/html.h>
|
||||
#include <gui/common/vmessagebox.h>
|
||||
#include <gui/gxs/GxsIdDetails.h>
|
||||
#include <gui/settings/rsharesettings.h>
|
||||
#include <lang/languagesupport.h>
|
||||
#include <util/stringutil.h>
|
||||
|
||||
#include <retroshare/rsinit.h>
|
||||
#include <retroshare/rsversion.h>
|
||||
#include <retroshare/rsplugin.h>
|
||||
#include <lang/languagesupport.h>
|
||||
#include "gui/settings/rsharesettings.h"
|
||||
#include "gui/gxs/GxsIdDetails.h"
|
||||
|
||||
#include "rshare.h"
|
||||
|
||||
/* Available command-line arguments. */
|
||||
#define ARG_LANGUAGE "lang" /**< Argument specifying language. */
|
||||
#define ARG_GUISTYLE "style" /**< Argument specfying GUI style. */
|
||||
#define ARG_LANGUAGE "lang" /**< Argument specifying language. */
|
||||
#define ARG_GUISTYLE "style" /**< Argument specfying GUI style. */
|
||||
#define ARG_GUISTYLESHEET "stylesheet" /**< Argument specfying GUI style. */
|
||||
#define ARG_RESET "reset" /**< Reset Rshare's saved settings. */
|
||||
#define ARG_DATADIR "datadir" /**< Directory to use for data files. */
|
||||
#define ARG_LOGFILE "logfile" /**< Location of our logfile. */
|
||||
#define ARG_LOGLEVEL "loglevel" /**< Log verbosity. */
|
||||
|
||||
#define ARG_RESET "reset" /**< Reset Rshare's saved settings. */
|
||||
#define ARG_DATADIR "datadir" /**< Directory to use for data files. */
|
||||
#define ARG_LOGFILE "logfile" /**< Location of our logfile. */
|
||||
#define ARG_LOGLEVEL "loglevel" /**< Log verbosity. */
|
||||
#define ARG_RSLINK_S "r" /**< Open RsLink with protocol retroshare:// */
|
||||
#define ARG_RSLINK_L "link" /**< Open RsLink with protocol retroshare:// */
|
||||
#define ARG_RSFILE_S "f" /**< Open RsFile with or without arg */
|
||||
#define ARG_RSFILE_L "rsfile" /**< Open RsFile with or without arg */
|
||||
//Other defined for server in /libretroshare/src/rsserver/rsinit.cc:351
|
||||
|
||||
/* Static member variables */
|
||||
QMap<QString, QString> Rshare::_args; /**< List of command-line arguments. */
|
||||
QString Rshare::_style; /**< The current GUI style. */
|
||||
QString Rshare::_language; /**< The current language. */
|
||||
QString Rshare::_stylesheet; /**< The current GUI stylesheet. */
|
||||
QString Rshare::_language; /**< The current language. */
|
||||
QString Rshare::_dateformat; /**< The format of dates in feed items etc. */
|
||||
Log Rshare::_log;
|
||||
bool Rshare::useConfigDir;
|
||||
QString Rshare::configDir;
|
||||
Log Rshare::_log; /**< Logs debugging messages to file or stdout. */
|
||||
QStringList Rshare::_links; /**< List of links passed by arguments. */
|
||||
QStringList Rshare::_files; /**< List of files passed by arguments. */
|
||||
QDateTime Rshare::mStartupTime;
|
||||
bool Rshare::useConfigDir;
|
||||
QString Rshare::configDir;
|
||||
QLocalServer* Rshare::localServer;
|
||||
|
||||
/** Catches debugging messages from Qt and sends them to RetroShare's logs. If Qt
|
||||
* emits a QtFatalMsg, we will write the message to the log and then abort().
|
||||
|
@ -88,6 +104,10 @@ void qt_msg_handler(QtMsgType type, const char *msg)
|
|||
case QtFatalMsg:
|
||||
rError(QString("QtFatalMsg: %1").arg(msg));
|
||||
break;
|
||||
#if QT_VERSION >= QT_VERSION_CHECK (5, 5, 0)
|
||||
case QtInfoMsg:
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
if (type == QtFatalMsg) {
|
||||
rError("Fatal Qt error. Aborting.");
|
||||
|
@ -102,6 +122,61 @@ Rshare::Rshare(QStringList args, int &argc, char **argv, const QString &dir)
|
|||
: QApplication(argc, argv)
|
||||
{
|
||||
mStartupTime = QDateTime::currentDateTime();
|
||||
localServer = NULL;
|
||||
|
||||
//Initialize connection to LocalServer to know if other process runs.
|
||||
{
|
||||
QString serverName = QString(TARGET);
|
||||
|
||||
if (args.isEmpty()) args.append("Empty");
|
||||
// load into shared memory
|
||||
QBuffer buffer;
|
||||
buffer.open(QBuffer::ReadWrite);
|
||||
QDataStream out(&buffer);
|
||||
out << args;
|
||||
int size = buffer.size();
|
||||
|
||||
QSharedMemory newArgs;
|
||||
newArgs.setKey(serverName + "_newArgs");
|
||||
if (newArgs.isAttached()) newArgs.detach();
|
||||
|
||||
if (!newArgs.create(size)) {
|
||||
std::cerr << "(EE) Rshare::Rshare Unable to create shared memory segment of size:"
|
||||
<< size << " error:" << newArgs.errorString().toStdString() << "." << std::endl;
|
||||
#ifdef Q_OS_UNIX
|
||||
std::cerr << "Look with `ipcs -m` for nattch==0 segment. And remove it with `ipcrm -m 'shmid'`." << std::endl;
|
||||
//No need for windows, as it removes shared segment directly even when crash.
|
||||
#endif
|
||||
newArgs.detach();
|
||||
::exit(EXIT_FAILURE);
|
||||
}
|
||||
newArgs.lock();
|
||||
char *to = (char*)newArgs.data();
|
||||
const char *from = buffer.data().data();
|
||||
memcpy(to, from, qMin(newArgs.size(), size));
|
||||
newArgs.unlock();
|
||||
|
||||
// Connect to the Local Server of the main process to notify it
|
||||
// that a new process had been started
|
||||
QLocalSocket localSocket;
|
||||
localSocket.connectToServer(QString(TARGET));
|
||||
|
||||
std::cerr << "Rshare::Rshare waitForConnected to other instance." << std::endl;
|
||||
if( localSocket.waitForConnected(100) )
|
||||
{
|
||||
std::cerr << "Rshare::Rshare Connection etablished. Waiting for disconnection." << std::endl;
|
||||
localSocket.waitForDisconnected(1000);
|
||||
newArgs.detach();
|
||||
::exit(EXIT_SUCCESS); // Terminate the program using STDLib's exit function
|
||||
} else {
|
||||
newArgs.detach();
|
||||
// No main process exists
|
||||
// So we start a Local Server to listen for connections from new process
|
||||
localServer= new QLocalServer();
|
||||
QObject::connect(localServer, SIGNAL(newConnection()), this, SLOT(slotConnectionEstablished()));
|
||||
updateLocalServer();
|
||||
}
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK (5, 0, 0)
|
||||
qInstallMessageHandler(qt_msg_handler);
|
||||
|
@ -172,6 +247,48 @@ Rshare::~Rshare()
|
|||
{
|
||||
/* Cleanup GxsIdDetails */
|
||||
GxsIdDetails::cleanup();
|
||||
if (localServer)
|
||||
{
|
||||
localServer->close();
|
||||
delete localServer;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Executed when new instance connect command is sent to LocalServer
|
||||
*/
|
||||
void Rshare::slotConnectionEstablished()
|
||||
{
|
||||
QLocalSocket *socket = localServer->nextPendingConnection();
|
||||
socket->close();
|
||||
delete socket;
|
||||
|
||||
QSharedMemory newArgs;
|
||||
newArgs.setKey(QString(TARGET) + "_newArgs");
|
||||
|
||||
if (!newArgs.attach())
|
||||
{
|
||||
std::cerr << "(EE) Rshare::slotConnectionEstablished() Unable to attach to shared memory segment."
|
||||
<< newArgs.errorString().toStdString() << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
QBuffer buffer;
|
||||
QDataStream in(&buffer);
|
||||
QStringList args;
|
||||
|
||||
newArgs.lock();
|
||||
buffer.setData((char*)newArgs.constData(), newArgs.size());
|
||||
buffer.open(QBuffer::ReadOnly);
|
||||
in >> args;
|
||||
newArgs.unlock();
|
||||
newArgs.detach();
|
||||
|
||||
emit newArgsReceived(args);
|
||||
while (!args.empty())
|
||||
{
|
||||
std::cerr << "Rshare::slotConnectionEstablished args:" << QString(args.takeFirst()).toStdString() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
QString Rshare::retroshareVersion(bool withRevision)
|
||||
|
@ -271,39 +388,62 @@ Rshare::showUsageMessageBox()
|
|||
bool
|
||||
Rshare::argNeedsValue(QString argName)
|
||||
{
|
||||
return (argName == ARG_GUISTYLE ||
|
||||
argName == ARG_GUISTYLESHEET ||
|
||||
argName == ARG_LANGUAGE ||
|
||||
argName == ARG_DATADIR ||
|
||||
argName == ARG_LOGFILE ||
|
||||
argName == ARG_LOGLEVEL);
|
||||
|
||||
return (argName == ARG_GUISTYLE ||
|
||||
argName == ARG_GUISTYLESHEET ||
|
||||
argName == ARG_LANGUAGE ||
|
||||
argName == ARG_DATADIR ||
|
||||
argName == ARG_LOGFILE ||
|
||||
argName == ARG_LOGLEVEL ||
|
||||
argName == ARG_RSLINK_S ||
|
||||
argName == ARG_RSLINK_L ||
|
||||
argName == ARG_RSFILE_S ||
|
||||
argName == ARG_RSFILE_L );
|
||||
}
|
||||
|
||||
/** Parses the list of command-line arguments for their argument names and
|
||||
* values. */
|
||||
void
|
||||
Rshare::parseArguments(QStringList args)
|
||||
Rshare::parseArguments(QStringList args, bool firstRun)
|
||||
{
|
||||
QString arg, value;
|
||||
QString arg, value;
|
||||
|
||||
/* Loop through all command-line args/values and put them in a map */
|
||||
for (int i = 0; i < args.size(); ++i) {
|
||||
/* Get the argument name and set a blank value */
|
||||
arg = args.at(i).toLower();
|
||||
value = "";
|
||||
/* Loop through all command-line args/values and put them in a map */
|
||||
for (int i = 0; i < args.size(); ++i) {
|
||||
/* Get the argument name and set a blank value */
|
||||
arg = args.at(i);//.toLower(); Need Upper case for file name.
|
||||
if (arg.toLower() == "empty") continue;
|
||||
value = "";
|
||||
|
||||
/* Check if it starts with a - or -- */
|
||||
if (arg.startsWith("-")) {
|
||||
arg = arg.mid((arg.startsWith("--") ? 2 : 1));
|
||||
}
|
||||
/* Check if it takes a value and there is one on the command-line */
|
||||
if (i < args.size()-1 && argNeedsValue(arg)) {
|
||||
value = args.at(++i);
|
||||
}
|
||||
/* Place this arg/value in the map */
|
||||
_args.insert(arg, value);
|
||||
}
|
||||
/* Check if it starts with a - or -- */
|
||||
if (arg.startsWith("-")) {
|
||||
arg = arg.mid((arg.startsWith("--") ? 2 : 1));
|
||||
/* Check if it takes a value and there is one on the command-line */
|
||||
if (i < args.size()-1 && argNeedsValue(arg.toLower())) {
|
||||
value = args.at(++i);
|
||||
}
|
||||
} else {
|
||||
/* Check if links or files without arg */
|
||||
if (arg.toLower().startsWith("retroshare://")) {
|
||||
value = arg;
|
||||
arg = ARG_RSLINK_L;
|
||||
} else {
|
||||
if (QFile(arg).exists()) {
|
||||
value = arg;
|
||||
arg = ARG_RSFILE_L;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't send theses argument to _args map to allow multiple. */
|
||||
if (arg == ARG_RSLINK_S || arg == ARG_RSLINK_L) {
|
||||
_links.append(value);
|
||||
} else if (arg == ARG_RSFILE_S || arg == ARG_RSFILE_L) {
|
||||
_files.append(value);
|
||||
} else if (firstRun) {
|
||||
/* Place this arg/value in the map only first time*/
|
||||
_args.insert(arg, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Verifies that all specified arguments were valid. */
|
||||
|
@ -660,6 +800,29 @@ Rshare::createShortcut(const QKeySequence &key, QWidget *sender,
|
|||
connect(s, SIGNAL(activated()), receiver, slot);
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
bool Rshare::event(QEvent *event)
|
||||
{
|
||||
switch (event->type()) {
|
||||
case QEvent::FileOpen:{
|
||||
QFileOpenEvent* fileOE = static_cast<QFileOpenEvent *>(event);
|
||||
QStringList args;
|
||||
if (! fileOE->file().isEmpty()) {
|
||||
_files.append(fileOE->file());
|
||||
emit newArgsReceived(QStringList());
|
||||
return true;
|
||||
} else if (! fileOE->url().isEmpty()) {
|
||||
_links.append(fileOE->url().toString());
|
||||
emit newArgsReceived(QStringList());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return QApplication::event(event);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void Rshare::blinkTimer()
|
||||
{
|
||||
mBlink = !mBlink;
|
||||
|
@ -706,3 +869,17 @@ bool Rshare::loadCertificate(const RsPeerId &accountId, bool autoLogin)
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Rshare::updateLocalServer()
|
||||
{
|
||||
if (localServer) {
|
||||
QString serverName = QString(TARGET);
|
||||
if (Settings->getUseLocalServer()) {
|
||||
localServer->removeServer(serverName);
|
||||
localServer->listen(serverName);
|
||||
return true;
|
||||
}
|
||||
localServer->close();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue