qBittorrent
SearchController Class Reference

#include <searchcontroller.h>

Inheritance diagram for SearchController:
Collaboration diagram for SearchController:

Public Member Functions

 APIController (ISessionManager *sessionManager, QObject *parent=nullptr)
 
- Public Member Functions inherited from APIController
 APIController (ISessionManager *sessionManager, QObject *parent=nullptr)
 
QVariant run (const QString &action, const StringMap &params, const DataMap &data={})
 
ISessionManagersessionManager () const
 

Private Slots

void startAction ()
 
void stopAction ()
 
void statusAction ()
 
void resultsAction ()
 
void deleteAction ()
 
void pluginsAction ()
 
void installPluginAction ()
 
void uninstallPluginAction ()
 
void enablePluginAction ()
 
void updatePluginsAction ()
 

Private Member Functions

void checkForUpdatesFinished (const QHash< QString, PluginVersion > &updateInfo)
 
void checkForUpdatesFailed (const QString &reason)
 
void searchFinished (ISession *session, int id)
 
void searchFailed (ISession *session, int id)
 
int generateSearchId () const
 
QJsonObject getResults (const QList< SearchResult > &searchResults, bool isSearchActive, int totalResults) const
 
QJsonArray getPluginsInfo (const QStringList &plugins) const
 

Private Attributes

const int MAX_CONCURRENT_SEARCHES = 5
 

Additional Inherited Members

- Protected Member Functions inherited from APIController
const StringMapparams () const
 
const DataMapdata () const
 
void requireParams (const QVector< QString > &requiredParams) const
 
void setResult (const QString &result)
 
void setResult (const QJsonArray &result)
 
void setResult (const QJsonObject &result)
 

Detailed Description

Definition at line 42 of file searchcontroller.h.

Member Function Documentation

◆ APIController()

APIController::APIController
explicit

Definition at line 53 of file apicontroller.cpp.

41  : QObject {parent}
43 {
44 }
ISessionManager * m_sessionManager
Definition: apicontroller.h:69
ISessionManager * sessionManager() const

◆ checkForUpdatesFailed()

void SearchController::checkForUpdatesFailed ( const QString &  reason)
private

Definition at line 300 of file searchcontroller.cpp.

301 {
302  LogMsg(tr("Failed to check for plugin updates: %1").arg(reason), Log::INFO);
303 }
void LogMsg(const QString &message, const Log::MsgType &type)
Definition: logger.cpp:125
@ INFO
Definition: logger.h:46

References Log::INFO, and LogMsg().

Referenced by updatePluginsAction().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ checkForUpdatesFinished()

void SearchController::checkForUpdatesFinished ( const QHash< QString, PluginVersion > &  updateInfo)
private

Definition at line 282 of file searchcontroller.cpp.

283 {
284  if (updateInfo.isEmpty())
285  {
286  LogMsg(tr("All plugins are already up to date."), Log::INFO);
287  return;
288  }
289 
290  LogMsg(tr("Updating %1 plugins").arg(updateInfo.size()), Log::INFO);
291 
292  SearchPluginManager *const pluginManager = SearchPluginManager::instance();
293  for (const QString &pluginName : asConst(updateInfo.keys()))
294  {
295  LogMsg(tr("Updating plugin %1").arg(pluginName), Log::INFO);
296  pluginManager->updatePlugin(pluginName);
297  }
298 }
void updatePlugin(const QString &name)
static SearchPluginManager * instance()
constexpr std::add_const_t< T > & asConst(T &t) noexcept
Definition: global.h:42

References asConst(), Log::INFO, SearchPluginManager::instance(), LogMsg(), and SearchPluginManager::updatePlugin().

Referenced by updatePluginsAction().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ deleteAction

void SearchController::deleteAction ( )
privateslot

Definition at line 219 of file searchcontroller.cpp.

220 {
221  requireParams({"id"});
222 
223  const int id = params()["id"].toInt();
224  ISession *const session = sessionManager()->session();
225 
226  auto searchHandlers = session->getData<SearchHandlerDict>(SEARCH_HANDLERS);
227  if (!searchHandlers.contains(id))
229 
230  const SearchHandlerPtr searchHandler = searchHandlers[id];
231  searchHandler->cancelSearch();
232  searchHandlers.remove(id);
233  session->setData(SEARCH_HANDLERS, QVariant::fromValue(searchHandlers));
234 
235  removeActiveSearch(session, id);
236 }
void requireParams(const QVector< QString > &requiredParams) const
const StringMap & params() const
const QLatin1String SEARCH_HANDLERS("searchHandlers")
void removeActiveSearch(ISession *session, const int id)
QSharedPointer< SearchHandler > SearchHandlerPtr
QMap< int, SearchHandlerPtr > SearchHandlerDict
virtual QVariant getData(const QString &id) const =0
virtual void setData(const QString &id, const QVariant &data)=0
virtual ISession * session()=0

References ISession::getData(), NotFound, APIController::params(), anonymous_namespace{searchcontroller.cpp}::removeActiveSearch(), APIController::requireParams(), anonymous_namespace{searchcontroller.cpp}::SEARCH_HANDLERS(), ISessionManager::session(), APIController::sessionManager(), and ISession::setData().

Here is the call graph for this function:

◆ enablePluginAction

void SearchController::enablePluginAction ( )
privateslot

Definition at line 262 of file searchcontroller.cpp.

263 {
264  requireParams({"names", "enable"});
265 
266  const QStringList names = params()["names"].split('|');
267  const bool enable = Utils::String::parseBool(params()["enable"].trimmed()).value_or(false);
268 
269  for (const QString &name : names)
270  SearchPluginManager::instance()->enablePlugin(name.trimmed(), enable);
271 }
void enablePlugin(const QString &name, bool enabled=true)
std::optional< bool > parseBool(const QString &string)
Definition: string.cpp:72

References SearchPluginManager::enablePlugin(), SearchPluginManager::instance(), APIController::params(), Utils::String::parseBool(), and APIController::requireParams().

Here is the call graph for this function:

◆ generateSearchId()

int SearchController::generateSearchId ( ) const
private

Definition at line 315 of file searchcontroller.cpp.

316 {
317  const auto searchHandlers = sessionManager()->session()->getData<SearchHandlerDict>(SEARCH_HANDLERS);
318 
319  while (true)
320  {
321  const int id = Utils::Random::rand(1, std::numeric_limits<int>::max());
322  if (!searchHandlers.contains(id))
323  return id;
324  }
325 }
uint32_t rand(uint32_t min=0, uint32_t max=std::numeric_limits< uint32_t >::max())
Definition: random.cpp:132

References ISession::getData(), Utils::Random::rand(), anonymous_namespace{searchcontroller.cpp}::SEARCH_HANDLERS(), ISessionManager::session(), and APIController::sessionManager().

Referenced by startAction().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getPluginsInfo()

QJsonArray SearchController::getPluginsInfo ( const QStringList &  plugins) const
private

Returns the search plugins in JSON format.

The return value is an array of dictionaries. The dictionary keys are:

  • "name"
  • "version"
  • "fullName"
  • "url"
  • "supportedCategories"
  • "iconPath"
  • "enabled"

Definition at line 380 of file searchcontroller.cpp.

381 {
382  QJsonArray pluginsArray;
383 
384  for (const QString &plugin : plugins)
385  {
386  const PluginInfo *const pluginInfo = SearchPluginManager::instance()->pluginInfo(plugin);
387 
388  pluginsArray << QJsonObject
389  {
390  {"name", pluginInfo->name},
391  {"version", QString(pluginInfo->version)},
392  {"fullName", pluginInfo->fullName},
393  {"url", pluginInfo->url},
394  {"supportedCategories", getPluginCategories(pluginInfo->supportedCategories)},
395  {"enabled", pluginInfo->enabled}
396  };
397  }
398 
399  return pluginsArray;
400 }
PluginInfo * pluginInfo(const QString &name) const
QJsonArray getPluginCategories(QStringList categories)
QStringList supportedCategories
PluginVersion version

References PluginInfo::enabled, PluginInfo::fullName, anonymous_namespace{searchcontroller.cpp}::getPluginCategories(), SearchPluginManager::instance(), PluginInfo::name, SearchPluginManager::pluginInfo(), PluginInfo::supportedCategories, PluginInfo::url, and PluginInfo::version.

Referenced by pluginsAction().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getResults()

QJsonObject SearchController::getResults ( const QList< SearchResult > &  searchResults,
bool  isSearchActive,
int  totalResults 
) const
private

Returns the search results in JSON format.

The return value is an object with a status and an array of dictionaries. The dictionary keys are:

  • "fileName"
  • "fileUrl"
  • "fileSize"
  • "nbSeeders"
  • "nbLeechers"
  • "siteUrl"
  • "descrLink"

Definition at line 340 of file searchcontroller.cpp.

341 {
342  QJsonArray searchResultsArray;
343  for (const SearchResult &searchResult : searchResults)
344  {
345  searchResultsArray << QJsonObject
346  {
347  {"fileName", searchResult.fileName},
348  {"fileUrl", searchResult.fileUrl},
349  {"fileSize", searchResult.fileSize},
350  {"nbSeeders", searchResult.nbSeeders},
351  {"nbLeechers", searchResult.nbLeechers},
352  {"siteUrl", searchResult.siteUrl},
353  {"descrLink", searchResult.descrLink}
354  };
355  }
356 
357  const QJsonObject result =
358  {
359  {"status", isSearchActive ? "Running" : "Stopped"},
360  {"results", searchResultsArray},
361  {"total", totalResults}
362  };
363 
364  return result;
365 }

Referenced by resultsAction().

Here is the caller graph for this function:

◆ installPluginAction

void SearchController::installPluginAction ( )
privateslot

Definition at line 244 of file searchcontroller.cpp.

245 {
246  requireParams({"sources"});
247 
248  const QStringList sources = params()["sources"].split('|');
249  for (const QString &source : sources)
251 }
void installPlugin(const QString &source)

References SearchPluginManager::installPlugin(), SearchPluginManager::instance(), APIController::params(), APIController::requireParams(), and anonymous_namespace{misc.cpp}::source.

Here is the call graph for this function:

◆ pluginsAction

void SearchController::pluginsAction ( )
privateslot

Definition at line 238 of file searchcontroller.cpp.

239 {
240  const QStringList allPlugins = SearchPluginManager::instance()->allPlugins();
241  setResult(getPluginsInfo(allPlugins));
242 }
void setResult(const QString &result)
QJsonArray getPluginsInfo(const QStringList &plugins) const
QStringList allPlugins() const

References SearchPluginManager::allPlugins(), getPluginsInfo(), SearchPluginManager::instance(), and APIController::setResult().

Here is the call graph for this function:

◆ resultsAction

void SearchController::resultsAction ( )
privateslot

Definition at line 186 of file searchcontroller.cpp.

187 {
188  requireParams({"id"});
189 
190  const int id = params()["id"].toInt();
191  int limit = params()["limit"].toInt();
192  int offset = params()["offset"].toInt();
193 
194  const auto searchHandlers = sessionManager()->session()->getData<SearchHandlerDict>(SEARCH_HANDLERS);
195  if (!searchHandlers.contains(id))
197 
198  const SearchHandlerPtr searchHandler = searchHandlers[id];
199  const QList<SearchResult> searchResults = searchHandler->results();
200  const int size = searchResults.size();
201 
202  if (offset > size)
203  throw APIError(APIErrorType::Conflict, tr("Offset is out of range"));
204 
205  // normalize values
206  if (offset < 0)
207  offset = size + offset;
208  if (offset < 0) // check again
209  throw APIError(APIErrorType::Conflict, tr("Offset is out of range"));
210  if (limit <= 0)
211  limit = -1;
212 
213  if ((limit > 0) || (offset > 0))
214  setResult(getResults(searchResults.mid(offset, limit), searchHandler->isActive(), size));
215  else
216  setResult(getResults(searchResults, searchHandler->isActive(), size));
217 }
QJsonObject getResults(const QList< SearchResult > &searchResults, bool isSearchActive, int totalResults) const

References Conflict, ISession::getData(), getResults(), NotFound, APIController::params(), APIController::requireParams(), anonymous_namespace{searchcontroller.cpp}::SEARCH_HANDLERS(), ISessionManager::session(), APIController::sessionManager(), and APIController::setResult().

Here is the call graph for this function:

◆ searchFailed()

void SearchController::searchFailed ( ISession session,
int  id 
)
private

Definition at line 310 of file searchcontroller.cpp.

311 {
312  removeActiveSearch(session, id);
313 }

References anonymous_namespace{searchcontroller.cpp}::removeActiveSearch().

Here is the call graph for this function:

◆ searchFinished()

void SearchController::searchFinished ( ISession session,
int  id 
)
private

Definition at line 305 of file searchcontroller.cpp.

306 {
307  removeActiveSearch(session, id);
308 }

References anonymous_namespace{searchcontroller.cpp}::removeActiveSearch().

Here is the call graph for this function:

◆ startAction

void SearchController::startAction ( )
privateslot

Definition at line 93 of file searchcontroller.cpp.

94 {
95  requireParams({"pattern", "category", "plugins"});
96 
97  if (!Utils::ForeignApps::pythonInfo().isValid())
98  throw APIError(APIErrorType::Conflict, tr("Python must be installed to use the Search Engine."));
99 
100  const QString pattern = params()["pattern"].trimmed();
101  const QString category = params()["category"].trimmed();
102  const QStringList plugins = params()["plugins"].split('|');
103 
104  QStringList pluginsToUse;
105  if (plugins.size() == 1)
106  {
107  const QString pluginsLower = plugins[0].toLower();
108  if (pluginsLower == "all")
109  pluginsToUse = SearchPluginManager::instance()->allPlugins();
110  else if ((pluginsLower == "enabled") || (pluginsLower == "multi"))
111  pluginsToUse = SearchPluginManager::instance()->enabledPlugins();
112  else
113  pluginsToUse << plugins;
114  }
115  else
116  {
117  pluginsToUse << plugins;
118  }
119 
120  ISession *const session = sessionManager()->session();
121  auto activeSearches = session->getData<QSet<int>>(ACTIVE_SEARCHES);
122  if (activeSearches.size() >= MAX_CONCURRENT_SEARCHES)
123  throw APIError(APIErrorType::Conflict, tr("Unable to create more than %1 concurrent searches.").arg(MAX_CONCURRENT_SEARCHES));
124 
125  const auto id = generateSearchId();
126  const SearchHandlerPtr searchHandler {SearchPluginManager::instance()->startSearch(pattern, category, pluginsToUse)};
127  QObject::connect(searchHandler.data(), &SearchHandler::searchFinished, this, [session, id, this]() { searchFinished(session, id); });
128  QObject::connect(searchHandler.data(), &SearchHandler::searchFailed, this, [session, id, this]() { searchFailed(session, id); });
129 
130  auto searchHandlers = session->getData<SearchHandlerDict>(SEARCH_HANDLERS);
131  searchHandlers.insert(id, searchHandler);
132  session->setData(SEARCH_HANDLERS, QVariant::fromValue(searchHandlers));
133 
134  activeSearches.insert(id);
135  session->setData(ACTIVE_SEARCHES, QVariant::fromValue(activeSearches));
136 
137  const QJsonObject result = {{"id", id}};
138  setResult(result);
139 }
int generateSearchId() const
const int MAX_CONCURRENT_SEARCHES
void searchFinished(bool cancelled=false)
void searchFailed()
QStringList enabledPlugins() const
SearchHandler * startSearch(const QString &pattern, const QString &category, const QStringList &usedPlugins)
PythonInfo pythonInfo()
const QLatin1String ACTIVE_SEARCHES("activeSearches")

References anonymous_namespace{searchcontroller.cpp}::ACTIVE_SEARCHES(), SearchPluginManager::allPlugins(), Conflict, SearchPluginManager::enabledPlugins(), generateSearchId(), ISession::getData(), SearchPluginManager::instance(), MAX_CONCURRENT_SEARCHES, APIController::params(), Utils::ForeignApps::pythonInfo(), APIController::requireParams(), anonymous_namespace{searchcontroller.cpp}::SEARCH_HANDLERS(), SearchHandler::searchFailed(), SearchHandler::searchFinished(), ISessionManager::session(), APIController::sessionManager(), ISession::setData(), APIController::setResult(), and SearchPluginManager::startSearch().

Here is the call graph for this function:

◆ statusAction

void SearchController::statusAction ( )
privateslot

Definition at line 161 of file searchcontroller.cpp.

162 {
163  const int id = params()["id"].toInt();
164 
165  const auto searchHandlers = sessionManager()->session()->getData<SearchHandlerDict>(SEARCH_HANDLERS);
166  if ((id != 0) && !searchHandlers.contains(id))
168 
169  QJsonArray statusArray;
170  const QList<int> searchIds {(id == 0) ? searchHandlers.keys() : QList<int> {id}};
171 
172  for (const int searchId : searchIds)
173  {
174  const SearchHandlerPtr searchHandler = searchHandlers[searchId];
175  statusArray << QJsonObject
176  {
177  {"id", searchId},
178  {"status", searchHandler->isActive() ? "Running" : "Stopped"},
179  {"total", searchHandler->results().size()}
180  };
181  }
182 
183  setResult(statusArray);
184 }

References ISession::getData(), NotFound, APIController::params(), anonymous_namespace{searchcontroller.cpp}::SEARCH_HANDLERS(), ISessionManager::session(), APIController::sessionManager(), and APIController::setResult().

Here is the call graph for this function:

◆ stopAction

void SearchController::stopAction ( )
privateslot

Definition at line 141 of file searchcontroller.cpp.

142 {
143  requireParams({"id"});
144 
145  const int id = params()["id"].toInt();
146  ISession *const session = sessionManager()->session();
147 
148  const auto searchHandlers = session->getData<SearchHandlerDict>(SEARCH_HANDLERS);
149  if (!searchHandlers.contains(id))
151 
152  const SearchHandlerPtr searchHandler = searchHandlers[id];
153 
154  if (searchHandler->isActive())
155  {
156  searchHandler->cancelSearch();
157  removeActiveSearch(session, id);
158  }
159 }

References ISession::getData(), NotFound, APIController::params(), anonymous_namespace{searchcontroller.cpp}::removeActiveSearch(), APIController::requireParams(), anonymous_namespace{searchcontroller.cpp}::SEARCH_HANDLERS(), ISessionManager::session(), and APIController::sessionManager().

Here is the call graph for this function:

◆ uninstallPluginAction

void SearchController::uninstallPluginAction ( )
privateslot

Definition at line 253 of file searchcontroller.cpp.

254 {
255  requireParams({"names"});
256 
257  const QStringList names = params()["names"].split('|');
258  for (const QString &name : names)
260 }
bool uninstallPlugin(const QString &name)

References SearchPluginManager::instance(), APIController::params(), APIController::requireParams(), and SearchPluginManager::uninstallPlugin().

Here is the call graph for this function:

◆ updatePluginsAction

void SearchController::updatePluginsAction ( )
privateslot

Definition at line 273 of file searchcontroller.cpp.

274 {
275  SearchPluginManager *const pluginManager = SearchPluginManager::instance();
276 
279  pluginManager->checkForUpdates();
280 }
void checkForUpdatesFailed(const QString &reason)
void checkForUpdatesFinished(const QHash< QString, PluginVersion > &updateInfo)
void checkForUpdatesFinished(const QHash< QString, PluginVersion > &updateInfo)
void checkForUpdatesFailed(const QString &reason)

References SearchPluginManager::checkForUpdates(), SearchPluginManager::checkForUpdatesFailed(), checkForUpdatesFailed(), SearchPluginManager::checkForUpdatesFinished(), checkForUpdatesFinished(), and SearchPluginManager::instance().

Here is the call graph for this function:

Member Data Documentation

◆ MAX_CONCURRENT_SEARCHES

const int SearchController::MAX_CONCURRENT_SEARCHES = 5
private

Definition at line 63 of file searchcontroller.h.

Referenced by startAction().


The documentation for this class was generated from the following files: