/src/libtomahawk/infosystem/InfoSystem.cpp

http://github.com/tomahawk-player/tomahawk · C++ · 408 lines · 294 code · 92 blank · 22 comment · 30 complexity · c2a3601842e28131aae54ba332a449c5 MD5 · raw file

  1. /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
  2. *
  3. * Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  4. * Copyright 2012 Leo Franchi <lfranchi@kde.org>
  5. * Copyright 2010-2011, Jeff Mitchell <jeff@tomahawk-player.org>
  6. *
  7. * Tomahawk is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * Tomahawk is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include <QCoreApplication>
  21. #include "InfoSystem.h"
  22. #include "TomahawkSettings.h"
  23. #include "InfoSystemCache.h"
  24. #include "InfoSystemWorker.h"
  25. #include "utils/TomahawkUtils.h"
  26. #include "utils/Logger.h"
  27. #include "Source.h"
  28. namespace Tomahawk
  29. {
  30. namespace InfoSystem
  31. {
  32. static const int DEFAULT_TIMEOUT_MILLIS = 10000;
  33. InfoRequestData::InfoRequestData()
  34. : requestId( TomahawkUtils::infosystemRequestId() )
  35. {
  36. init( QString() , Tomahawk::InfoSystem::InfoNoInfo, QVariant(), QVariantMap() );
  37. }
  38. InfoRequestData::InfoRequestData( const quint64 rId, const QString& callr, const InfoType typ, const QVariant& inputvar, const QVariantMap& custom )
  39. : requestId( rId )
  40. {
  41. init( callr, typ, inputvar, custom );
  42. }
  43. void
  44. InfoRequestData::init( const QString& callr, const InfoType typ, const QVariant& inputvar, const QVariantMap& custom )
  45. {
  46. internalId = TomahawkUtils::infosystemRequestId();
  47. caller = callr;
  48. type = typ;
  49. input = inputvar;
  50. customData = custom;
  51. timeoutMillis = DEFAULT_TIMEOUT_MILLIS;
  52. allSources = false;
  53. }
  54. InfoPlugin::InfoPlugin()
  55. : QObject()
  56. {
  57. }
  58. InfoPlugin::~InfoPlugin()
  59. {
  60. }
  61. void
  62. InfoPlugin::setFriendlyName( const QString& friendlyName )
  63. {
  64. m_friendlyName = friendlyName;
  65. }
  66. const QString
  67. InfoPlugin::friendlyName() const
  68. {
  69. return m_friendlyName;
  70. }
  71. InfoSystem* InfoSystem::s_instance = 0;
  72. InfoSystem*
  73. InfoSystem::instance()
  74. {
  75. if ( !s_instance )
  76. s_instance = new InfoSystem( 0 );
  77. return s_instance;
  78. }
  79. InfoSystem::InfoSystem( QObject* parent )
  80. : QObject( parent )
  81. , m_inited( false )
  82. , m_infoSystemCacheThreadController( 0 )
  83. , m_infoSystemWorkerThreadController( 0 )
  84. {
  85. s_instance = this;
  86. m_infoSystemCacheThreadController = new InfoSystemCacheThread( this );
  87. m_infoSystemCacheThreadController->start( QThread::IdlePriority );
  88. m_infoSystemWorkerThreadController = new InfoSystemWorkerThread( this );
  89. m_infoSystemWorkerThreadController->start();
  90. QTimer::singleShot( 0, this, SLOT( init() ) );
  91. }
  92. InfoSystem::~InfoSystem()
  93. {
  94. tDebug() << Q_FUNC_INFO << "beginning";
  95. if ( m_infoSystemWorkerThreadController )
  96. {
  97. m_infoSystemWorkerThreadController->quit();
  98. m_infoSystemWorkerThreadController->wait( 60000 );
  99. delete m_infoSystemWorkerThreadController;
  100. m_infoSystemWorkerThreadController = 0;
  101. }
  102. tDebug() << Q_FUNC_INFO << "done deleting worker";
  103. if ( m_infoSystemCacheThreadController )
  104. {
  105. m_infoSystemCacheThreadController->quit();
  106. m_infoSystemCacheThreadController->wait( 60000 );
  107. delete m_infoSystemCacheThreadController;
  108. m_infoSystemCacheThreadController = 0;
  109. }
  110. tDebug() << Q_FUNC_INFO << "done deleting cache";
  111. }
  112. void
  113. InfoSystem::init()
  114. {
  115. if ( m_inited )
  116. return;
  117. if ( !m_infoSystemCacheThreadController->cache() || !m_infoSystemWorkerThreadController->worker() )
  118. {
  119. // tLog() << "Worker not found";
  120. QTimer::singleShot( 0, this, SLOT( init() ) );
  121. return;
  122. }
  123. Tomahawk::InfoSystem::InfoSystemCache* cache = m_infoSystemCacheThreadController->cache();
  124. Tomahawk::InfoSystem::InfoSystemWorker* worker = m_infoSystemWorkerThreadController->worker();
  125. connect( cache, SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
  126. worker, SLOT( infoSlot( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), Qt::UniqueConnection );
  127. connect( worker, SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
  128. this, SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), Qt::UniqueConnection );
  129. connect( worker, SIGNAL( finished( QString ) ), this, SIGNAL( finished( QString ) ), Qt::UniqueConnection );
  130. connect( worker, SIGNAL( finished( QString, Tomahawk::InfoSystem::InfoType ) ),
  131. this, SIGNAL( finished( QString, Tomahawk::InfoSystem::InfoType ) ), Qt::UniqueConnection );
  132. qRegisterMetaType< Tomahawk::InfoSystem::InfoTypeSet >();
  133. connect( worker, SIGNAL( updatedSupportedGetTypes( Tomahawk::InfoSystem::InfoTypeSet ) ),
  134. this, SLOT( receiveUpdatedSupportedGetTypes( Tomahawk::InfoSystem::InfoTypeSet ) ) );
  135. connect( worker, SIGNAL( updatedSupportedPushTypes( Tomahawk::InfoSystem::InfoTypeSet ) ),
  136. this, SLOT( receiveUpdatedSupportedPushTypes( Tomahawk::InfoSystem::InfoTypeSet ) ) );
  137. QMetaObject::invokeMethod( worker, "init", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoSystemCache*, cache ) );
  138. m_inited = true;
  139. emit ready();
  140. }
  141. bool
  142. InfoSystem::getInfo( const InfoRequestData& requestData )
  143. {
  144. if ( !m_inited || !m_infoSystemWorkerThreadController->worker() )
  145. {
  146. init();
  147. return false;
  148. }
  149. QMetaObject::invokeMethod( m_infoSystemWorkerThreadController->worker(), "getInfo", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoRequestData, requestData ) );
  150. return true;
  151. }
  152. bool
  153. InfoSystem::getInfo( const QString& caller, const QVariantMap& customData, const InfoTypeMap& inputMap, const InfoTimeoutMap& timeoutMap, bool allSources )
  154. {
  155. if ( !m_inited || !m_infoSystemWorkerThreadController->worker() )
  156. {
  157. init();
  158. return false;
  159. }
  160. InfoRequestData requestData;
  161. requestData.caller = caller;
  162. requestData.customData = customData;
  163. requestData.allSources = allSources;
  164. foreach ( InfoType type, inputMap.keys() )
  165. {
  166. requestData.type = type;
  167. requestData.input = inputMap[ type ];
  168. requestData.timeoutMillis = timeoutMap.contains( type ) ? timeoutMap[ type ] : DEFAULT_TIMEOUT_MILLIS;
  169. QMetaObject::invokeMethod( m_infoSystemWorkerThreadController->worker(), "getInfo", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoRequestData, requestData ) );
  170. }
  171. return false;
  172. }
  173. bool
  174. InfoSystem::pushInfo( InfoPushData pushData )
  175. {
  176. tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "type is" << pushData.type;
  177. if ( !m_inited || !m_infoSystemWorkerThreadController->worker() )
  178. {
  179. init();
  180. return false;
  181. }
  182. PushInfoPair pushInfoPair( QVariantMap(), pushData.input );
  183. pushData.infoPair = pushInfoPair;
  184. QMetaObject::invokeMethod( m_infoSystemWorkerThreadController->worker(), "pushInfo", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPushData, pushData ) );
  185. return true;
  186. }
  187. bool
  188. InfoSystem::pushInfo( const QString& caller, const InfoTypeMap& input, const PushInfoFlags pushFlags )
  189. {
  190. if ( !m_inited || !m_infoSystemWorkerThreadController->worker() )
  191. {
  192. init();
  193. return false;
  194. }
  195. foreach ( InfoType type, input.keys() )
  196. {
  197. InfoPushData pushData( caller, type, input[ type ], pushFlags );
  198. pushData.infoPair = PushInfoPair( QVariantMap(), pushData.input );
  199. QMetaObject::invokeMethod( m_infoSystemWorkerThreadController->worker(), "pushInfo", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPushData, pushData ) );
  200. }
  201. return true;
  202. }
  203. void
  204. InfoSystem::addInfoPlugin( Tomahawk::InfoSystem::InfoPluginPtr plugin )
  205. {
  206. // Init is not complete (waiting for worker thread to start and create worker object) so keep trying till then
  207. if ( !m_inited || !m_infoSystemWorkerThreadController->worker() )
  208. {
  209. QMetaObject::invokeMethod( this, "addInfoPlugin", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPluginPtr, plugin ) );
  210. return;
  211. }
  212. if ( plugin.isNull() )
  213. {
  214. tDebug() << Q_FUNC_INFO << "Given plugin is null!";
  215. return;
  216. }
  217. if ( plugin.data()->thread() != m_infoSystemWorkerThreadController->worker()->thread() )
  218. {
  219. tLog() << Q_FUNC_INFO << "The object must be moved to the worker thread first, see InfoSystem::workerThread(): " << plugin->friendlyName();
  220. Q_ASSERT( false );
  221. return;
  222. }
  223. tDebug( LOGVERBOSE ) << Q_FUNC_INFO << plugin.data();
  224. QMetaObject::invokeMethod( m_infoSystemWorkerThreadController->worker(), "addInfoPlugin", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPluginPtr, plugin ) );
  225. }
  226. void
  227. InfoSystem::removeInfoPlugin( Tomahawk::InfoSystem::InfoPluginPtr plugin )
  228. {
  229. // Init is not complete (waiting for worker th read to start and create worker object) so keep trying till then
  230. if ( !m_inited || !m_infoSystemWorkerThreadController->worker() )
  231. {
  232. QMetaObject::invokeMethod( this, "removeInfoPlugin", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPluginPtr, plugin ) );
  233. return;
  234. }
  235. if ( plugin.isNull() )
  236. {
  237. tDebug() << Q_FUNC_INFO << "Given plugin is null!";
  238. return;
  239. }
  240. if ( plugin.data()->thread() != m_infoSystemWorkerThreadController->worker()->thread() )
  241. {
  242. tDebug() << Q_FUNC_INFO << "The object must be moved to the worker thread first, see InfoSystem::workerThread()";
  243. return;
  244. }
  245. tDebug( LOGVERBOSE ) << Q_FUNC_INFO << plugin.data();
  246. QMetaObject::invokeMethod( m_infoSystemWorkerThreadController->worker(), "removeInfoPlugin", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPluginPtr, plugin ) );
  247. }
  248. void
  249. InfoSystem::receiveUpdatedSupportedGetTypes( InfoTypeSet supportedTypes )
  250. {
  251. m_supportedGetTypes = supportedTypes;
  252. emit updatedSupportedGetTypes( m_supportedGetTypes );
  253. }
  254. void
  255. InfoSystem::receiveUpdatedSupportedPushTypes( InfoTypeSet supportedTypes )
  256. {
  257. m_supportedPushTypes = supportedTypes;
  258. emit updatedSupportedPushTypes( m_supportedPushTypes );
  259. }
  260. QPointer< QThread >
  261. InfoSystem::workerThread() const
  262. {
  263. if ( m_infoSystemWorkerThreadController->isRunning() && m_infoSystemWorkerThreadController->worker() )
  264. return QPointer< QThread >( m_infoSystemWorkerThreadController->worker()->thread() );
  265. return QPointer< QThread >();
  266. }
  267. InfoSystemCacheThread::InfoSystemCacheThread( QObject* parent )
  268. : QThread( parent )
  269. {
  270. tDebug() << Q_FUNC_INFO;
  271. }
  272. InfoSystemCacheThread::~InfoSystemCacheThread()
  273. {
  274. tDebug() << Q_FUNC_INFO;
  275. }
  276. void
  277. InfoSystemCacheThread::InfoSystemCacheThread::run()
  278. {
  279. m_cache = QPointer< InfoSystemCache >( new InfoSystemCache() );
  280. exec();
  281. if ( !m_cache.isNull() )
  282. delete m_cache.data();
  283. }
  284. InfoSystemCache*
  285. InfoSystemCacheThread::cache() const
  286. {
  287. if ( m_cache.isNull() )
  288. return 0;
  289. return m_cache.data();
  290. }
  291. InfoSystemWorkerThread::InfoSystemWorkerThread( QObject* parent )
  292. : QThread( parent )
  293. {
  294. tDebug() << Q_FUNC_INFO;
  295. }
  296. InfoSystemWorkerThread::~InfoSystemWorkerThread()
  297. {
  298. tDebug() << Q_FUNC_INFO;
  299. }
  300. void
  301. InfoSystemWorkerThread::InfoSystemWorkerThread::run()
  302. {
  303. m_worker = QPointer< InfoSystemWorker >( new InfoSystemWorker() );
  304. exec();
  305. if ( !m_worker.isNull() )
  306. delete m_worker.data();
  307. }
  308. InfoSystemWorker*
  309. InfoSystemWorkerThread::worker() const
  310. {
  311. if ( m_worker.isNull() )
  312. return 0;
  313. return m_worker.data();
  314. }
  315. } //namespace InfoSystem
  316. } //namespace Tomahawk