+/***************************************************************************
+ * Copyright (C) 2010 by Ixonos Plc *
+ * *
+ * This program 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; version 2 of the License. *
+ * *
+ * 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 General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
#include "TorrentSession.hpp"
#include "TorrentHandle.hpp"
#include "AlertWaiterThread.hpp"
-
+#include "ServerDb.hpp"
+#include <qtrapids/error.hpp>
namespace qtrapids
{
- TorrentSession::TorrentSession(QObject *parent, QSettings *settings)
- : QObject(parent)
- , btSession_()
+TorrentSession::TorrentSession(QObject *parent, QSettings *settings)
+ : QObject(parent)
+ , btSession_()
, alertWaiter_(new AlertWaiterThread(&btSession_, this))
- {
- qDBusRegisterMetaType<qtrapids::TorrentState>();
- qDBusRegisterMetaType<qtrapids::ParamsMap_t>();
- new QtRapidsServer(this);
-
- QDBusConnection dbus = QDBusConnection::sessionBus();
- dbus.registerObject("/qtrapids", this);
- dbus.registerService("com.ixonos.qtrapids");
-
- alertWaiter_->allAlerts();
- connect(alertWaiter_, SIGNAL(alert()), this, SLOT(on_alert()));
- alertWaiter_->start();
-
-
- }
-
- void TorrentSession::on_alert()
- //NOTE: al parameter not necessarily needed here, as we pop_alert() now!
- {
-
- //qDebug() << "QBittorrentSession:on_alert(" << al << ")";
- // if (al)
- // qDebug() << "on_alert():" << QString::fromStdString(al->message());
-
- std::auto_ptr<alert_t> alertPtr = btSession_.pop_alert();
-
- if (alertPtr.get() != NULL) {
-
- torrent_alert_t *ta = dynamic_cast<torrent_alert_t*> (alertPtr.get());
-
- qDebug()
- << "QBittorrentSession::on_alert(): "
- << QString::fromStdString(alertPtr->message());
-
-
- if (ta) {
-
- if (!ta->handle.is_valid()) {
- qDebug() << "handle is invalid";
- return;
- }
-
- TorrentHandle handle(ta->handle);
- TorrentState state;
-
- state.hash = Hash2QStr(handle.hash());
- state.action = TorrentState::action_update;
- state.state = handle.state();
- state.progress = handle.progress() * torrent_progress_max;
- state.down_rate = handle.downloadRate();
- state.up_rate = handle.uploadRate();
- state.seeds = handle.numSeeds();
- state.leeches = handle.numLeeches();
-
- ParamsMap_t params;
- emit alert(state, params);
- }
-
- }
- }
-
- void TorrentSession::getState()
- {
- torrents_t::const_iterator p;
- for (p = torrents_.constBegin(); p != torrents_.constEnd(); ++p) {
- TorrentHandlePtr handle = *p;
- TorrentState state;
- QString hash = Hash2QStr(handle->hash());
-
- state.hash = hash;
- state.name = handle->name();
- state.action = TorrentState::action_add;
- state.state = handle->state();
- state.progress = handle->progress() * torrent_progress_max;
- state.down_rate = handle->downloadRate();
- state.up_rate = handle->uploadRate();
- state.seeds = handle->numSeeds();
- state.leeches = handle->numLeeches();
- state.total_size = handle->getTotalSize();
-
- emit alert(state, ParamsMap_t());
- }
- }
-
- void TorrentSession::addTorrent(const QString &path, const QString &save_path
- , qtrapids::ParamsMap_t other_params)
- {
- add_torrent_params_t addParams;
- QFile torrent_file(path);
- if (!torrent_file.exists()) {
- qWarning() << "Torrent file " << path << "doesn't exist";
- return;
- }
-
- qDebug() << "addTorrent: " << path << " save to " << save_path;
- boost::intrusive_ptr<libtorrent::torrent_info> tiTmp
- = new libtorrent::torrent_info
- (boost::filesystem::path(path.toStdString()));
- addParams.ti = tiTmp;
-
- // save_path is the only mandatory parameter, rest are optional.
- addParams.save_path = boost::filesystem::path(save_path.toStdString());
- //addParams.storage_mode = libtorrent::storage_mode_allocate;
-
- TorrentHandlePtr handle(new TorrentHandle(btSession_.add_torrent(addParams)));
- QString hash = Hash2QStr(handle->hash());
-
- TorrentState state;
-
- state.hash = hash;
- state.name = handle->name();
- state.action = TorrentState::action_add;
- state.state = handle->state();
- state.progress = handle->progress() * torrent_progress_max;
- state.down_rate = handle->downloadRate();
- state.up_rate = handle->uploadRate();
- state.seeds = handle->numSeeds();
- state.leeches = handle->numLeeches();
- state.total_size = handle->getTotalSize();
-
- torrents_[hash] = handle;
-
- emit alert(state, ParamsMap_t());
- }
-
- void TorrentSession::removeTorrent(const QString &hash)
- {
- torrents_t::iterator p = torrents_.find(hash);
-
- if (p == torrents_.end()) {
- qDebug() << "Invalid request to remove torrent with hash " << hash;
- return;
- }
- try {
- btSession_.remove_torrent(p.value()->getHandle());
- } catch (torrent_exception_t e) {
- qDebug() << // e.what()
- "exception catched"
- ;
- }
-
- TorrentState state;
- state.hash = hash;
- state.action = TorrentState::action_remove;
- emit alert(state, ParamsMap_t());
- torrents_.erase(p);
- }
+ , settings_(new ServerSettings(*settings))
+ , db_(new ServerDb(settings_.get()))
+{
+ qDBusRegisterMetaType<qtrapids::TorrentState>();
+ qDBusRegisterMetaType<qtrapids::ParamsMap_t>();
+ new QtRapidsServer(this);
+
+ QDBusConnection dbus = QDBusConnection::sessionBus();
+ dbus.registerObject("/qtrapids", this);
+ dbus.registerService("com.ixonos.qtrapids");
+
+ alertWaiter_->allAlerts();
+ connect(alertWaiter_, SIGNAL(alert()), this, SLOT(on_alert()));
+ alertWaiter_->start();
+
+ loadState();
+
+ // Lets force applying rate limits to local network also, at least for testing.
+ // Also, on the N900 device, rate limiting is necessary due to limited processign power
+ session_settings_t sessionSettings;
+ sessionSettings.ignore_limits_on_local_network = false;
+ btSession_.set_settings(sessionSettings);
+
+}
+
+
+TorrentSession::~TorrentSession()
+{
+ alertWaiter_->stop();
+ alertWaiter_->wait();
+ emit sessionTerminated();
+}
+
+
+void TorrentSession::loadState()
+{
+ TorrentDownloadInfo info;
+ TorrentsStorage storage(*db_);
+ while (storage.nextTorrent(info)) {
+#ifdef QTRAPIDS_DEBUG
+ qDebug() << "adding " << info.path;
+#endif
+ addTorrent_(info.path, info.download_path, ParamsMap_t(), true);
+ }
+ btSession_.listen_on(settings_->getListenPorts());
+}
+
+void TorrentSession::on_alert()
+{
+ std::auto_ptr<alert_t> alertPtr = btSession_.pop_alert();
+
+ if (alertPtr.get() != NULL) {
+
+ torrent_alert_t *ta = dynamic_cast<torrent_alert_t*> (alertPtr.get());
+
+#ifdef QTRAPIDS_DEBUG
+ qDebug()
+ << "TorrentSession::on_alert(): "
+ << QString::fromStdString(alertPtr->message());
+#endif
+
+ if (ta) {
+ if (!ta->handle.is_valid()) {
+#ifdef QTRAPIDS_DEBUG
+ qDebug() << "handle is invalid";
+#endif
+ return;
+ }
+
+ TorrentHandle handle(ta->handle);
+ TorrentState state;
+
+ state.hash = Hash2QStr(handle.hash());
+ state.action = TorrentState::action_update;
+ state.state = handle.state();
+ state.progress = handle.progress() * torrent_progress_max;
+ state.down_rate = handle.downloadRate();
+ state.up_rate = handle.uploadRate();
+ state.seeds = handle.numSeeds();
+ state.leeches = handle.numLeeches();
+ state.total_size = handle.getTotalSize();
+ state.total_done = handle.getTotalDone();
+
+ ParamsMap_t params;
+ emit alert(state, params);
+ }
+
+ }
+}
+
+void TorrentSession::getState()
+{
+ torrents_t::const_iterator p;
+ for (p = torrents_.constBegin(); p != torrents_.constEnd(); ++p) {
+ TorrentHandlePtr handle = *p;
+ TorrentState state;
+ QString hash = Hash2QStr(handle->hash());
+
+ state.hash = hash;
+ state.name = handle->name();
+ state.action = TorrentState::action_add;
+ state.state = handle->state();
+ state.progress = handle->progress() * torrent_progress_max;
+ state.down_rate = handle->downloadRate();
+ state.up_rate = handle->uploadRate();
+ state.seeds = handle->numSeeds();
+ state.leeches = handle->numLeeches();
+ state.total_size = handle->getTotalSize();
+
+ emit alert(state, ParamsMap_t());
+ }
+}
+
+void TorrentSession::addTorrent(const QString &path, const QString &save_path
+ , qtrapids::ParamsMap_t other_params)
+{
+ return addTorrent_(path, save_path, other_params, false);
+}
+
+void TorrentSession::addTorrent_(const QString &path, const QString &save_path
+ , const qtrapids::ParamsMap_t &other_params
+ , bool is_restore_session)
+{
+ add_torrent_params_t addParams;
+ QFile torrent_file(path);
+ QDir::home().mkdir(settings_->getTorrentsSubDir());
+
+ if (!torrent_file.exists()) {
+ qWarning() << Q_FUNC_INFO << " Torrent file " << path << "doesn't exist";
+ return;
+ }
+
+ QString new_torrent_fname(QDir(settings_->getTorrentsDir())
+ .filePath(QFileInfo(path).fileName()));
+#ifdef QTRAPIDS_DEBUG
+ qDebug() << Q_FUNC_INFO << " copy to " << new_torrent_fname;
+#endif
+
+ torrent_file.copy(new_torrent_fname);
+
+#ifdef QTRAPIDS_DEBUG
+ qDebug() << Q_FUNC_INFO << path << " save to " << save_path;
+#endif
+
+ boost::intrusive_ptr<libtorrent::torrent_info> tiTmp
+ = new libtorrent::torrent_info
+ (boost::filesystem::path(new_torrent_fname.toStdString()));
+ addParams.ti = tiTmp;
+
+ QString download_dir;
+ if (!save_path.isEmpty()) {
+ download_dir = save_path;
+ } else {
+ download_dir = settings_->getDownloadDir();
+ }
+ // save_path is the only mandatory parameter, rest are optional.
+ addParams.save_path = boost::filesystem::path(download_dir.toStdString());
+ //addParams.storage_mode = libtorrent::storage_mode_allocate;
+
+ TorrentHandlePtr handle(new TorrentHandle(btSession_.add_torrent(addParams)));
+ QString hash = Hash2QStr(handle->hash());
+
+ if (!is_restore_session) {
+ db_->addTorrent(hash, path, save_path);
+ }
+
+ TorrentState state;
+
+ state.hash = hash;
+ state.name = handle->name();
+ state.action = TorrentState::action_add;
+ state.state = handle->state();
+ state.progress = handle->progress() * torrent_progress_max;
+ state.down_rate = handle->downloadRate();
+ state.up_rate = handle->uploadRate();
+ state.seeds = handle->numSeeds();
+ state.leeches = handle->numLeeches();
+ state.total_size = handle->getTotalSize();
+
+ torrents_[hash] = handle;
+
+ emit alert(state, ParamsMap_t());
+}
+
+void TorrentSession::removeTorrent(const QString &hash)
+{
+ torrents_t::iterator p = torrents_.find(hash);
+
+ if (p == torrents_.end()) {
+#ifdef QTRAPIDS_DEBUG
+ qDebug() << Q_FUNC_INFO << " Invalid request to remove torrent with hash " << hash;
+#endif
+ return;
+ }
+ try {
+ btSession_.remove_torrent(p.value()->getHandle());
+ } catch (torrent_exception_t e) {
+ qDebug() << // e.what()
+ "exception catched"
+ ;
+ }
+
+ TorrentState state;
+ state.hash = hash;
+ state.action = TorrentState::action_remove;
+ emit alert(state, ParamsMap_t());
+ torrents_.erase(p);
+ db_->removeTorrent(hash);
+}
+
+
+void TorrentSession::setOptions(qtrapids::ParamsMap_t options)
+{
+ qtrapids::ParamsMapConstIterator_t end = options.end();
+ qtrapids::ParamsMapConstIterator_t tmpIter = options.find("net/downloadRate");
+ int rate = -1;
+
+ // Apply settings immediately to Bittorrent session:
+ // NOTE: QHash interface is not quite STL-like
+
+ if (tmpIter != end) {
+ rate = tmpIter.value().toInt();
+ btSession_.set_download_rate_limit(rate);
+ }
+
+ tmpIter = options.find("net/uploadRate");
+ if (tmpIter != end) {
+ rate = tmpIter.value().toInt();
+ btSession_.set_upload_rate_limit(rate);
+ }
+
+ /// @todo Add more immediately applicable settings here, if needed.
+
+ // Finally, save settings to persistent storage:
+ settings_->setOptions(options);
+}
+
+
+qtrapids::ParamsMap_t TorrentSession::getOptions()
+{
+ return settings_->getOptions();
+}
+void TorrentSession::terminateSession()
+{
+ qDebug() << "Terminate called";
+ // Emiting terminate() here causes the server application to quit in main()
+ emit terminate();
+}
+
} // namespace qtrapids