Skip to content

Commit

Permalink
do not expose task and make it thread safe
Browse files Browse the repository at this point in the history
  • Loading branch information
3nids committed May 7, 2018
1 parent 25108e5 commit 648562d
Show file tree
Hide file tree
Showing 9 changed files with 401 additions and 89 deletions.
1 change: 1 addition & 0 deletions python/core/core_auto.sip
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@
%Include qgsmessageoutput.sip
%Include qgsnetworkaccessmanager.sip
%Include qgsnetworkcontentfetcher.sip
%Include qgsnetworkcontentfetcherregistry.sip
%Include qgsnetworkcontentfetchertask.sip
%Include qgsofflineediting.sip
%Include qgspluginlayer.sip
Expand Down
3 changes: 1 addition & 2 deletions python/core/qgsapplication.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -645,8 +645,7 @@ within SVG files.

static QgsNetworkContentFetcherRegistry *networkContentFetcherRegistry();
%Docstring
Returns the application's SVG cache, used for caching SVG images and handling parameter replacement
within SVG files.
Returns the application's network content registry used for fetching temporary files during QGIS session

.. versionadded:: 3.2
%End
Expand Down
131 changes: 131 additions & 0 deletions python/core/qgsnetworkcontentfetcherregistry.sip.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsnetworkcontentfetcherregistry.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/








class QgsFetchedContent : QObject
{
%Docstring
FetchedContent holds useful information about a network content being fetched

.. seealso:: :py:class:`QgsNetworkContentFetcherRegistry`

.. versionadded:: 3.2
%End

%TypeHeaderCode
#include "qgsnetworkcontentfetcherregistry.h"
%End
public:
enum ContentStatus
{
NotStarted,
Downloading,
Finished,
Failed
};

explicit QgsFetchedContent( QTemporaryFile *file = 0, ContentStatus status = NotStarted );
%Docstring
Constructs a FetchedContent with pointer to the downloaded file and status of the download
%End


const QString filePath() const;
%Docstring
Return the path to the local file, an empty string if the file is not accessible yet.
%End

ContentStatus status() const;
%Docstring
Return the status of the download
%End

QNetworkReply::NetworkError error() const;
%Docstring
Return the potential error of the download
%End

public slots:

void download( bool redownload = false );
%Docstring
Start the download

:param redownload: if set to true, it will restart any achieved or pending download.
%End

signals:
void fetched();
%Docstring
Sent when the file is fetched and accessible
%End

void downloadStarted( const bool redownload );
%Docstring
Sent went the download actually starts
%End

};

class QgsNetworkContentFetcherRegistry : QObject
{
%Docstring
Registry for temporary fetched files

This provides a simple way of downloading and accessing
remote files during QGIS application running.

.. seealso:: :py:class:`QgsFetchedContent`

.. versionadded:: 3.2
%End

%TypeHeaderCode
#include "qgsnetworkcontentfetcherregistry.h"
%End
public:
enum FetchingMode
{
DownloadLater,
DownloadImmediately,
};

explicit QgsNetworkContentFetcherRegistry();
%Docstring
Create the registry for temporary downloaded files
%End

~QgsNetworkContentFetcherRegistry();

const QgsFetchedContent *fetch( const QUrl &url, const FetchingMode &fetchingMode = DownloadLater );
%Docstring
Initialize a download for the given URL

:param url: the URL to be fetched
:param fetchingMode: defines if the download will start immediately or shall be manually triggered

.. note::

If the download starts immediately, it will not redownload any already fetched or currently fetching file.
%End

};

/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsnetworkcontentfetcherregistry.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
6 changes: 3 additions & 3 deletions src/core/qgsapplication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1667,7 +1667,7 @@ QgsSvgCache *QgsApplication::svgCache()

QgsNetworkContentFetcherRegistry *QgsApplication::networkContentFetcherRegistry()
{
return members()->mNetworkContentFertcherRegistry;
return members()->mNetworkContentFetcherRegistry;
}

QgsSymbolLayerRegistry *QgsApplication::symbolLayerRegistry()
Expand Down Expand Up @@ -1749,7 +1749,7 @@ QgsApplication::ApplicationMembers::ApplicationMembers()
mAnnotationRegistry = new QgsAnnotationRegistry();
m3DRendererRegistry = new Qgs3DRendererRegistry();
mProjectStorageRegistry = new QgsProjectStorageRegistry();
mNetworkContentFertcherRegistry = new QgsNetworkContentFetcherRegistry();
mNetworkContentFetcherRegistry = new QgsNetworkContentFetcherRegistry();
}

QgsApplication::ApplicationMembers::~ApplicationMembers()
Expand All @@ -1773,7 +1773,7 @@ QgsApplication::ApplicationMembers::~ApplicationMembers()
delete mSvgCache;
delete mSymbolLayerRegistry;
delete mTaskManager;
delete mNetworkContentFertcherRegistry;
delete mNetworkContentFetcherRegistry;
}

QgsApplication::ApplicationMembers *QgsApplication::members()
Expand Down
5 changes: 2 additions & 3 deletions src/core/qgsapplication.h
Original file line number Diff line number Diff line change
Expand Up @@ -588,8 +588,7 @@ class CORE_EXPORT QgsApplication : public QApplication
static QgsSvgCache *svgCache();

/**
* Returns the application's SVG cache, used for caching SVG images and handling parameter replacement
* within SVG files.
* Returns the application's network content registry used for fetching temporary files during QGIS session
* \since QGIS 3.2
*/
static QgsNetworkContentFetcherRegistry *networkContentFetcherRegistry();
Expand Down Expand Up @@ -810,7 +809,7 @@ class CORE_EXPORT QgsApplication : public QApplication
QgsColorSchemeRegistry *mColorSchemeRegistry = nullptr;
QgsFieldFormatterRegistry *mFieldFormatterRegistry = nullptr;
QgsGpsConnectionRegistry *mGpsConnectionRegistry = nullptr;
QgsNetworkContentFetcherRegistry *mNetworkContentFertcherRegistry = nullptr;
QgsNetworkContentFetcherRegistry *mNetworkContentFetcherRegistry = nullptr;
QgsMessageLog *mMessageLog = nullptr;
QgsPaintEffectRegistry *mPaintEffectRegistry = nullptr;
QgsPluginLayerRegistry *mPluginLayerRegistry = nullptr;
Expand Down
78 changes: 45 additions & 33 deletions src/core/qgsnetworkcontentfetcherregistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
-------------------
begin : April, 2018
copyright : (C) 2018 by Denis Rouzaud
email : denis.rouzaud@gmail.com
email : denis@opengis.ch
***************************************************************************/

Expand All @@ -28,66 +28,78 @@ QgsNetworkContentFetcherRegistry::QgsNetworkContentFetcherRegistry()

QgsNetworkContentFetcherRegistry::~QgsNetworkContentFetcherRegistry()
{
QMap<QUrl, FetchedContent>::const_iterator it = mFileRegistry.constBegin();
QMap<QUrl, QgsFetchedContent *>::const_iterator it = mFileRegistry.constBegin();
for ( ; it != mFileRegistry.constEnd(); ++it )
{
it.value().mFile->deleteLater();
it.value()->mFile->close();
delete it.value()->mFile;
}
mFileRegistry.clear();
}

const QgsNetworkContentFetcherTask *QgsNetworkContentFetcherRegistry::fetch( const QUrl &url, const bool reload )
const QgsFetchedContent *QgsNetworkContentFetcherRegistry::fetch( const QUrl &url, const FetchingMode &fetchingMode )
{
if ( mFileRegistry.contains( url ) )
{
if ( !reload )
{
return mFileRegistry.value( url ).mFetchingTask;
}
else
return mFileRegistry.value( url );
}

QgsFetchedContent *content = new QgsFetchedContent( nullptr, QgsFetchedContent::NotStarted );
QgsNetworkContentFetcherTask *fetcher = new QgsNetworkContentFetcherTask( url );

QObject::connect( content, &QgsFetchedContent::downloadStarted, this, [ = ]( const bool redownload )
{
QMutexLocker locker( &mMutex );
if ( mFileRegistry.contains( url ) && redownload )
{
FetchedContent content = mFileRegistry.take( url );
if ( content.mFetchingTask )
const QgsFetchedContent *content = mFileRegistry[url];
if ( mFileRegistry.value( url )->status() == QgsFetchedContent::Downloading && content->mFetchingTask )
{
content.mFetchingTask->cancel();
content->mFetchingTask->cancel();
}
if ( content.mFile )
if ( content->mFile )
{
content.mFile->deleteLater();
content->mFile->deleteLater();
mFileRegistry[url]->setFilePath( QStringLiteral() );
}
}
}

QgsNetworkContentFetcherTask *fetcher = new QgsNetworkContentFetcherTask( url );
QgsApplication::instance()->taskManager()->addTask( fetcher );
mFileRegistry.insert( url,
FetchedContent( nullptr,
QgsNetworkContentFetcherRegistry::Downloading ) );
if ( ( mFileRegistry.contains( url ) && mFileRegistry.value( url )->status() == QgsFetchedContent::NotStarted ) || redownload )
{
QgsApplication::instance()->taskManager()->addTask( fetcher );
}
} );

QObject::connect( fetcher, &QgsNetworkContentFetcherTask::fetched, this, [ = ]()
{
QMutexLocker locker( &mMutex );
QNetworkReply *reply = fetcher->reply();
FetchedContent content = mFileRegistry.take( url );
QgsFetchedContent *content = mFileRegistry.value( url );
if ( reply->error() == QNetworkReply::NoError )
{
content.setFile( new QTemporaryFile( QStringLiteral( "XXXXXX" ) ) );
content.mFile->write( reply->readAll() );
content.setStatus( Finished );
QTemporaryFile *tf = new QTemporaryFile( QStringLiteral( "XXXXXX" ) );
content->setFile( tf );
tf->open();
content->mFile->write( reply->readAll() );
// Qt docs notes that on some system if fileName is not called before close, file might get deleted
content->setFilePath( tf->fileName() );
tf->close();
content->setStatus( QgsFetchedContent::Finished );
}
else
{
content.setStatus( Failed );
content.setError( reply->error() );
content->setStatus( QgsFetchedContent::Failed );
content->setError( reply->error() );
content->setFilePath( QStringLiteral() );
}
mFileRegistry.insert( url, content );
content->emitFetched();
} );

if ( fetchingMode == DownloadImmediately )
content->download();
mFileRegistry.insert( url, content );

return fetcher;
return content;
}



QgsNetworkContentFetcherRegistry::FetchedContent QgsNetworkContentFetcherRegistry::file( const QUrl &url )
{
return mFileRegistry.value( url );
}
Loading

0 comments on commit 648562d

Please sign in to comment.