/src/libtomahawk/infosystem/InfoSystemWorker.cpp
C++ | 397 lines | 288 code | 71 blank | 38 comment | 29 complexity | 645a5f73fde0d2c9c7a4390efd338388 MD5 | raw file
Possible License(s): LGPL-2.1, BSD-3-Clause, GPL-3.0, GPL-2.0
- /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
- *
- * Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
- * Copyright 2012 Leo Franchi <lfranchi@kde.org>
- * Copyright 2010-2011, Jeff Mitchell <jeff@tomahawk-player.org>
- *
- * Tomahawk is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Tomahawk 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
- */
- #include "InfoSystemWorker.h"
- #include "utils/Logger.h"
- #include "utils/ShortLinkHelper.h"
- #include "utils/TomahawkUtils.h"
- #include "config.h"
- #include "utils/LinkGenerator.h"
- #include "InfoSystemCache.h"
- #include "PlaylistEntry.h"
- #include "utils/TomahawkUtils.h"
- #include "utils/Logger.h"
- #include "utils/PluginLoader.h"
- #include "utils/Closure.h"
- #include "Source.h"
- #include <QCoreApplication>
- #include <QNetworkConfiguration>
- #include <QNetworkProxy>
- namespace Tomahawk
- {
- namespace InfoSystem
- {
- InfoSystemWorker::InfoSystemWorker()
- : QObject()
- , m_cache( 0 )
- {
- tDebug() << Q_FUNC_INFO;
- m_checkTimeoutsTimer.setInterval( 1000 );
- m_checkTimeoutsTimer.setSingleShot( false );
- connect( &m_checkTimeoutsTimer, SIGNAL( timeout() ), SLOT( checkTimeoutsTimerFired() ) );
- m_checkTimeoutsTimer.start();
- }
- InfoSystemWorker::~InfoSystemWorker()
- {
- tDebug() << Q_FUNC_INFO;
- }
- const QList< InfoPluginPtr >
- InfoSystemWorker::plugins() const
- {
- return m_plugins;
- }
- void
- InfoSystemWorker::init( Tomahawk::InfoSystem::InfoSystemCache* cache )
- {
- tDebug() << Q_FUNC_INFO;
- m_shortLinksWaiting = 0;
- m_cache = cache;
- loadInfoPlugins();
- }
- void
- InfoSystemWorker::addInfoPlugin( Tomahawk::InfoSystem::InfoPluginPtr plugin )
- {
- tDebug() << Q_FUNC_INFO << plugin;
- foreach ( InfoPluginPtr ptr, m_plugins )
- {
- if ( ptr == plugin )
- {
- tDebug() << Q_FUNC_INFO << "This plugin is already added to the infosystem.";
- return;
- }
- }
- if ( plugin.isNull() )
- {
- tDebug() << Q_FUNC_INFO << "passed-in plugin is null";
- return;
- }
- plugin.data()->moveToThread( this->thread() );
- m_plugins.append( plugin );
- registerInfoTypes( plugin, plugin.data()->supportedGetTypes(), plugin.data()->supportedPushTypes() );
- connect(
- plugin.data(),
- SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
- this,
- SLOT( infoSlot( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
- Qt::QueuedConnection
- );
- connect(
- plugin.data(),
- SIGNAL( getCachedInfo( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoRequestData ) ),
- m_cache,
- SLOT( getCachedInfoSlot( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoRequestData ) ),
- Qt::QueuedConnection
- );
- connect(
- plugin.data(),
- SIGNAL( updateCache( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) ),
- m_cache,
- SLOT( updateCacheSlot( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) ),
- Qt::QueuedConnection
- );
- QMetaObject::invokeMethod( plugin.data(), "init", Qt::QueuedConnection );
- emit updatedSupportedGetTypes( QSet< InfoType >::fromList( m_infoGetMap.keys() ) );
- emit updatedSupportedPushTypes( QSet< InfoType >::fromList( m_infoPushMap.keys() ) );
- }
- void
- InfoSystemWorker::removeInfoPlugin( Tomahawk::InfoSystem::InfoPluginPtr plugin )
- {
- tDebug() << Q_FUNC_INFO << plugin;
- if ( plugin.isNull() )
- {
- tDebug() << Q_FUNC_INFO << "passed-in plugin is null";
- return;
- }
- foreach ( InfoPluginPtr ptr, m_plugins )
- {
- if ( ptr == plugin )
- break;
- tDebug() << Q_FUNC_INFO << "This plugin does not exist in the infosystem.";
- return;
- }
- m_plugins.removeOne( plugin );
- deregisterInfoTypes( plugin, plugin.data()->supportedGetTypes(), plugin.data()->supportedPushTypes() );
- }
- void
- InfoSystemWorker::loadInfoPlugins()
- {
- QHash< QString, QObject* > plugins = Tomahawk::Utils::PluginLoader( "infoplugin" ).loadPlugins();
- foreach ( QObject* plugin, plugins.values() )
- {
- InfoPlugin* infoPlugin = qobject_cast< InfoPlugin* >( plugin );
- if ( infoPlugin )
- {
- tDebug() << Q_FUNC_INFO << "Loaded info plugin:" << plugins.key( plugin );
- infoPlugin->setFriendlyName( plugins.key( plugin ) );
- addInfoPlugin( InfoPluginPtr( infoPlugin ) );
- }
- else
- {
- tDebug() << Q_FUNC_INFO << "Loaded invalid plugin:" << plugins.key( plugin );
- }
- }
- }
- void
- InfoSystemWorker::registerInfoTypes( const InfoPluginPtr &plugin, const QSet< InfoType >& getTypes, const QSet< InfoType >& pushTypes )
- {
- Q_FOREACH( InfoType type, getTypes )
- m_infoGetMap[type].append( plugin );
- Q_FOREACH( InfoType type, pushTypes )
- m_infoPushMap[type].append( plugin );
- }
- void
- InfoSystemWorker::deregisterInfoTypes( const InfoPluginPtr &plugin, const QSet< InfoType >& getTypes, const QSet< InfoType >& pushTypes )
- {
- Q_FOREACH( InfoType type, getTypes )
- m_infoGetMap[type].removeOne( plugin );
- Q_FOREACH( InfoType type, pushTypes )
- m_infoPushMap[type].removeOne( plugin );
- }
- QList< InfoPluginPtr >
- InfoSystemWorker::determineOrderedMatches( const InfoType type ) const
- {
- //Dummy function for now that returns the various items in the QSet; at some point this will
- //probably need to support ordering based on the data source
- QList< InfoPluginPtr > providers;
- Q_FOREACH( InfoPluginPtr ptr, m_infoGetMap[type] )
- providers << ptr;
- return providers;
- }
- void
- InfoSystemWorker::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData )
- {
- //qDebug() << Q_FUNC_INFO << "type is " << requestData.type << " and allSources = " << (allSources ? "true" : "false" );
- QList< InfoPluginPtr > providers = determineOrderedMatches( requestData.type );
- if ( providers.isEmpty() )
- {
- // We're not ready yet, retry this request in a bit
- QTimer* timer = new QTimer();
- timer->setInterval( 500 );
- timer->setSingleShot( true );
- NewClosure( timer, SIGNAL( timeout() ), this, SLOT( getInfo( Tomahawk::InfoSystem::InfoRequestData ) ), requestData );
- timer->start();
- /* emit info( requestData, QVariant() );
- checkFinished( requestData );*/
- return;
- }
- if ( !requestData.allSources )
- providers = QList< InfoPluginPtr >( providers.mid( 0, 1 ) );
- bool foundOne = false;
- foreach ( InfoPluginPtr ptr, providers )
- {
- if ( !ptr )
- continue;
- // tDebug() << "Dispatching to worker:" << ptr->friendlyName() << requestData.type;
- foundOne = true;
- if ( requestData.allSources || m_savedRequestMap.contains( requestData.requestId ) )
- {
- if ( m_savedRequestMap.contains( requestData.requestId ) )
- tDebug() << Q_FUNC_INFO << "Warning: reassigning requestId because it already exists";
- requestData.internalId = TomahawkUtils::infosystemRequestId();
- }
- else
- requestData.internalId = requestData.requestId;
- quint64 requestId = requestData.internalId;
- m_requestSatisfiedMap[ requestId ] = false;
- if ( requestData.timeoutMillis != 0 )
- {
- qint64 currMs = QDateTime::currentMSecsSinceEpoch();
- m_timeRequestMapper.insert( currMs + requestData.timeoutMillis, requestId );
- }
- // qDebug() << "Assigning request with requestId" << requestId << "and type" << requestData.type;
- m_dataTracker[ requestData.caller ][ requestData.type ] = m_dataTracker[ requestData.caller ][ requestData.type ] + 1;
- // qDebug() << "Current count in dataTracker for target" << requestData.caller << "and type" << requestData.type << "is" << m_dataTracker[ requestData.caller ][ requestData.type ];
- InfoRequestData* data = new InfoRequestData;
- data->caller = requestData.caller;
- data->type = requestData.type;
- data->input = requestData.input;
- data->customData = requestData.customData;
- m_savedRequestMap[ requestId ] = data;
- QMetaObject::invokeMethod( ptr.data(), "getInfo", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoRequestData, requestData ) );
- }
- if ( !foundOne )
- {
- emit info( requestData, QVariant() );
- checkFinished( requestData );
- }
- }
- void
- InfoSystemWorker::pushInfo( Tomahawk::InfoSystem::InfoPushData pushData )
- {
- tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "type is " << pushData.type << "number of matching plugins: " << m_infoPushMap[ pushData.type ].size();
- Q_FOREACH( InfoPluginPtr ptr, m_infoPushMap[ pushData.type ] )
- {
- if( ptr )
- QMetaObject::invokeMethod( ptr.data(), "pushInfo", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPushData, pushData ) );
- }
- }
- void
- InfoSystemWorker::infoSlot( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output )
- {
- // qDebug() << Q_FUNC_INFO << "with requestId" << requestId;
- quint64 requestId = requestData.internalId;
- if ( m_dataTracker[ requestData.caller ][ requestData.type ] == 0 )
- {
- // qDebug() << Q_FUNC_INFO << "Caller was not waiting for that type of data!";
- return;
- }
- if ( !m_requestSatisfiedMap.contains( requestId ) || m_requestSatisfiedMap[ requestId ] )
- {
- // qDebug() << Q_FUNC_INFO << "Request was already taken care of!";
- return;
- }
- m_requestSatisfiedMap[ requestId ] = true;
- emit info( requestData, output );
- m_dataTracker[ requestData.caller ][ requestData.type ] = m_dataTracker[ requestData.caller ][ requestData.type ] - 1;
- // qDebug() << "Current count in dataTracker for target" << requestData.caller << "and type" << requestData.type << "is" << m_dataTracker[ requestData.caller ][ requestData.type ];
- delete m_savedRequestMap[ requestId ];
- m_savedRequestMap.remove( requestId );
- checkFinished( requestData );
- }
- void
- InfoSystemWorker::checkFinished( const Tomahawk::InfoSystem::InfoRequestData &requestData )
- {
- if ( m_dataTracker[ requestData.caller ][ requestData.type ] == 0 )
- emit finished( requestData.caller, requestData.type );
- Q_FOREACH( InfoType testtype, m_dataTracker[ requestData.caller ].keys() )
- {
- if ( m_dataTracker[ requestData.caller ][ testtype ] != 0 )
- return;
- }
- // qDebug() << "Emitting finished with target" << target;
- emit finished( requestData.caller );
- }
- void
- InfoSystemWorker::checkTimeoutsTimerFired()
- {
- qint64 currTime = QDateTime::currentMSecsSinceEpoch();
- Q_FOREACH( qint64 time, m_timeRequestMapper.keys() )
- {
- Q_FOREACH( quint64 requestId, m_timeRequestMapper.values( time ) )
- {
- if ( time < currTime )
- {
- if ( m_requestSatisfiedMap[ requestId ] )
- {
- // qDebug() << Q_FUNC_INFO << "Removing mapping of" << requestId << "which expired at time" << time << "and was already satisfied";
- m_timeRequestMapper.remove( time, requestId );
- if ( !m_timeRequestMapper.count( time ) )
- m_timeRequestMapper.remove( time );
- continue;
- }
- //doh, timed out
- // qDebug() << Q_FUNC_INFO << "Doh, timed out for requestId" << requestId;
- InfoRequestData *savedData = m_savedRequestMap[ requestId ];
- InfoRequestData returnData;
- returnData.caller = savedData->caller;
- returnData.type = savedData->type;
- returnData.input = savedData->input;
- returnData.customData = savedData->customData;
- emit info( returnData, QVariant() );
- delete savedData;
- m_savedRequestMap.remove( requestId );
- m_dataTracker[ returnData.caller ][ returnData.type ] = m_dataTracker[ returnData.caller ][ returnData.type ] - 1;
- // qDebug() << "Current count in dataTracker for target" << returnData.caller << "is" << m_dataTracker[ returnData.caller ][ returnData.type ];
- m_requestSatisfiedMap[ requestId ] = true;
- m_timeRequestMapper.remove( time, requestId );
- if ( !m_timeRequestMapper.count( time ) )
- m_timeRequestMapper.remove( time );
- checkFinished( returnData );
- }
- else
- {
- //we've caught up, the remaining requets still have time to work
- return;
- }
- }
- }
- }
- } //namespace InfoSystem
- } //namespace Tomahawk