mirror of
https://github.com/RetroShare/RetroShare.git
synced 2026-09-13 18:46:04 +05:00
The JSON API restart in stop() cost a RESTART_BURST_PROTECTION wait (7s) on every exit and brought the HTTP server back up in the middle of the core teardown, republishing resources whose backing services were about to stop. It was not gratuitous: it made "delete mJsonApiProvider" safe, because the running restbed service holds the resources this provider returned and their handlers capture it. libretroshare now stops the JSON API at the top of rsGlobalShutDown(), before stopPlugins(), so the resources are already gone by the time stop() runs and the provider can be deleted directly. Without that companion change this commit would turn a slow shutdown into a use-after-free, so the two go together. Also replace the five std::cerr traces with one RsDbg line on success and an RsInfo when the JSON API is not available, matching how the rest of the tree reports.
217 lines
6.6 KiB
C++
217 lines
6.6 KiB
C++
/*******************************************************************************
|
|
* plugins/FeedReader/FeedReaderPlugin.cpp *
|
|
* *
|
|
* Copyright (C) 2012 by Thunder <retroshare.project@gmail.com> *
|
|
* *
|
|
* 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 <https://www.gnu.org/licenses/>. *
|
|
* *
|
|
*******************************************************************************/
|
|
|
|
#include <QApplication>
|
|
#include <QIcon>
|
|
|
|
#include <retroshare/rsplugin.h>
|
|
#include <QTranslator>
|
|
|
|
#include "FeedReaderPlugin.h"
|
|
#include "gui/FeedReaderDialog.h"
|
|
#include "gui/FeedReaderNotify.h"
|
|
#include "gui/FeedReaderConfig.h"
|
|
#include "gui/FeedReaderFeedNotify.h"
|
|
#include "services/p3FeedReader.h"
|
|
#include "services/FeedReaderJsonApi.h"
|
|
#include <retroshare/rsjsonapi.h>
|
|
#include <util/rsdebug.h>
|
|
|
|
#include <libxml/xmlversion.h>
|
|
#include <libxslt/xsltconfig.h>
|
|
#include <curl/curlver.h>
|
|
|
|
#define IMAGE_FEEDREADER ":/images/FeedReader.png"
|
|
|
|
static void *inited = new FeedReaderPlugin();
|
|
|
|
extern "C" {
|
|
#ifdef WIN32
|
|
__declspec(dllexport)
|
|
#endif
|
|
RsPlugin *RETROSHARE_PLUGIN_provide()
|
|
{
|
|
return new FeedReaderPlugin();
|
|
}
|
|
|
|
// This symbol contains the svn revision number grabbed from the executable.
|
|
// It will be tested by RS to load the plugin automatically, since it is safe to load plugins
|
|
// with same revision numbers, assuming that the revision numbers are up-to-date.
|
|
//
|
|
#ifdef WIN32
|
|
__declspec(dllexport)
|
|
#endif
|
|
uint32_t RETROSHARE_PLUGIN_revision = (uint32_t)atoi(RS_EXTRA_VERSION);
|
|
|
|
// This symbol contains the svn revision number grabbed from the executable.
|
|
// It will be tested by RS to load the plugin automatically, since it is safe to load plugins
|
|
// with same revision numbers, assuming that the revision numbers are up-to-date.
|
|
//
|
|
#ifdef WIN32
|
|
__declspec(dllexport)
|
|
#endif
|
|
uint32_t RETROSHARE_PLUGIN_api = RS_PLUGIN_API_VERSION ;
|
|
}
|
|
|
|
void FeedReaderPlugin::getPluginVersion(int& major, int& minor, int &build, int& svn_rev) const
|
|
{
|
|
major = RS_MAJOR_VERSION;
|
|
minor = RS_MINOR_VERSION;
|
|
build = RS_MINI_VERSION;
|
|
svn_rev = abs(atoi(RS_EXTRA_VERSION)) ;
|
|
}
|
|
|
|
FeedReaderPlugin::FeedReaderPlugin()
|
|
{
|
|
mainpage = NULL ;
|
|
mIcon = NULL ;
|
|
mPlugInHandler = NULL;
|
|
mFeedReader = NULL;
|
|
mNotify = NULL;
|
|
mFeedNotify = NULL;
|
|
mJsonApiProvider = NULL;
|
|
|
|
Q_INIT_RESOURCE(FeedReader_images);
|
|
Q_INIT_RESOURCE(FeedReader_qss);
|
|
}
|
|
|
|
void FeedReaderPlugin::setInterfaces(RsPlugInInterfaces &interfaces)
|
|
{
|
|
mInterfaces = interfaces;
|
|
|
|
mFeedReader = new p3FeedReader(mPlugInHandler, mInterfaces.mGxsForums, mInterfaces.mPosted);
|
|
rsFeedReader = mFeedReader;
|
|
|
|
mNotify = new FeedReaderNotify();
|
|
mFeedReader->setNotify(mNotify);
|
|
|
|
if(mInterfaces.mJsonApi)
|
|
{
|
|
mJsonApiProvider = new FeedReaderJsonApi(*mFeedReader, *mInterfaces.mJsonApi);
|
|
mInterfaces.mJsonApi->registerResourceProvider(*mJsonApiProvider);
|
|
|
|
// No restart here: the core publishes every provider together once all
|
|
// plugins have received their interfaces, which avoids one
|
|
// burst-protected JSON API restart per plugin.
|
|
RsDbg() << "FeedReader: JSON API routes registered.";
|
|
}
|
|
else
|
|
RsInfo() << "FeedReader: JSON API not available, routes not registered.";
|
|
}
|
|
|
|
ConfigPage *FeedReaderPlugin::qt_config_page() const
|
|
{
|
|
return new FeedReaderConfig();
|
|
}
|
|
|
|
MainPage *FeedReaderPlugin::qt_page() const
|
|
{
|
|
if (mainpage == NULL) {
|
|
mainpage = new FeedReaderDialog(mFeedReader, mNotify);
|
|
}
|
|
|
|
return mainpage;
|
|
}
|
|
|
|
FeedNotify *FeedReaderPlugin::qt_feedNotify()
|
|
{
|
|
if (!mFeedNotify) {
|
|
mFeedNotify = new FeedReaderFeedNotify(mFeedReader, mNotify);
|
|
}
|
|
return mFeedNotify;
|
|
}
|
|
|
|
void FeedReaderPlugin::stop()
|
|
{
|
|
if(mJsonApiProvider)
|
|
{
|
|
if(mInterfaces.mJsonApi)
|
|
mInterfaces.mJsonApi->unregisterResourceProvider(*mJsonApiProvider);
|
|
|
|
/* No restart here. The core stops the JSON API before it stops the
|
|
* plugins, so the restbed resources whose handlers capture this
|
|
* provider are already gone by now and deleting it is safe. Restarting
|
|
* would only wait out RESTART_BURST_PROTECTION and bring the server
|
|
* back up in the middle of the core teardown. */
|
|
delete mJsonApiProvider;
|
|
mJsonApiProvider = NULL;
|
|
}
|
|
if (mFeedReader) {
|
|
mFeedReader->setNotify(NULL);
|
|
mFeedReader->stop();
|
|
}
|
|
if (mNotify) {
|
|
delete(mNotify);
|
|
mNotify = NULL;
|
|
}
|
|
if (mFeedNotify) {
|
|
delete mFeedNotify;
|
|
mFeedNotify = NULL;
|
|
}
|
|
}
|
|
|
|
void FeedReaderPlugin::setPlugInHandler(RsPluginHandler *pgHandler)
|
|
{
|
|
mPlugInHandler = pgHandler;
|
|
}
|
|
|
|
QIcon *FeedReaderPlugin::qt_icon() const
|
|
{
|
|
if (mIcon == NULL) {
|
|
mIcon = new QIcon(IMAGE_FEEDREADER);
|
|
}
|
|
|
|
return mIcon;
|
|
}
|
|
|
|
std::string FeedReaderPlugin::getShortPluginDescription() const
|
|
{
|
|
return QApplication::translate("FeedReaderPlugin", "This plugin provides a Feedreader.").toUtf8().constData();
|
|
}
|
|
|
|
std::string FeedReaderPlugin::getPluginName() const
|
|
{
|
|
return QApplication::translate("FeedReaderPlugin", "FeedReader").toUtf8().constData();
|
|
}
|
|
|
|
void FeedReaderPlugin::getLibraries(std::list<RsLibraryInfo> &libraries)
|
|
{
|
|
libraries.push_back(RsLibraryInfo("LibCurl", LIBCURL_VERSION));
|
|
libraries.push_back(RsLibraryInfo("Libxml2", LIBXML_DOTTED_VERSION));
|
|
libraries.push_back(RsLibraryInfo("libxslt", LIBXSLT_DOTTED_VERSION));
|
|
}
|
|
|
|
QTranslator* FeedReaderPlugin::qt_translator(QApplication */*app*/, const QString& languageCode, const QString& externalDir) const
|
|
{
|
|
if (languageCode == "en") {
|
|
return NULL;
|
|
}
|
|
|
|
QTranslator* translator = new QTranslator();
|
|
if (translator->load(externalDir + "/FeedReader_" + languageCode + ".qm")) {
|
|
return translator;
|
|
} else if (translator->load(":/lang/FeedReader_" + languageCode + ".qm")) {
|
|
return translator;
|
|
}
|
|
|
|
delete(translator);
|
|
return NULL;
|
|
}
|