1 /***************************************************************************
2 * Copyright (C) 2010 by Ixonos Plc *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; version 2 of the License. *
8 * This program is distributed in the hope that it will be useful, *
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
11 * GNU General Public License for more details. *
13 * You should have received a copy of the GNU General Public License *
14 * along with this program; if not, write to the *
15 * Free Software Foundation, Inc., *
16 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
17 ***************************************************************************/
18 #include "TorrentSession.hpp"
19 #include "TorrentHandle.hpp"
20 #include "AlertWaiterThread.hpp"
21 #include "ServerDb.hpp"
22 #include <qtrapids/error.hpp>
29 TorrentSession::TorrentSession(QObject *parent, QSettings *settings)
32 , alertWaiter_(new AlertWaiterThread(&btSession_, this))
33 , settings_(new ServerSettings(*settings))
34 , db_(new ServerDb(settings_.get()))
36 qDBusRegisterMetaType<qtrapids::TorrentState>();
37 qDBusRegisterMetaType<qtrapids::ParamsMap_t>();
38 new QtRapidsServer(this);
40 QDBusConnection dbus = QDBusConnection::sessionBus();
41 dbus.registerObject("/qtrapids", this);
42 dbus.registerService("com.ixonos.qtrapids");
44 alertWaiter_->allAlerts();
45 connect(alertWaiter_, SIGNAL(alert()), this, SLOT(on_alert()));
46 alertWaiter_->start();
50 // Lets force applying rate limits to local network also, at least for testing.
51 // Also, on the N900 device, rate limiting is necessary due to limited processign power
52 session_settings_t sessionSettings;
53 sessionSettings.ignore_limits_on_local_network = false;
54 btSession_.set_settings(sessionSettings);
59 TorrentSession::~TorrentSession()
63 emit sessionTerminated();
67 void TorrentSession::loadState()
69 TorrentDownloadInfo info;
70 TorrentsStorage storage(*db_);
71 while (storage.nextTorrent(info)) {
73 qDebug() << "adding " << info.path;
75 addTorrent_(info.path, info.download_path, ParamsMap_t(), true);
77 btSession_.listen_on(settings_->getListenPorts());
80 void TorrentSession::on_alert()
82 std::auto_ptr<alert_t> alertPtr = btSession_.pop_alert();
84 if (alertPtr.get() != NULL) {
86 torrent_alert_t *ta = dynamic_cast<torrent_alert_t*> (alertPtr.get());
90 << "TorrentSession::on_alert(): "
91 << QString::fromStdString(alertPtr->message());
95 if (!ta->handle.is_valid()) {
97 qDebug() << "handle is invalid";
102 TorrentHandle handle(ta->handle);
105 state.hash = Hash2QStr(handle.hash());
106 state.action = TorrentState::action_update;
107 state.state = handle.state();
108 state.progress = handle.progress() * torrent_progress_max;
109 state.down_rate = handle.downloadRate();
110 state.up_rate = handle.uploadRate();
111 state.seeds = handle.numSeeds();
112 state.leeches = handle.numLeeches();
113 state.total_size = handle.getTotalSize();
114 state.total_done = handle.getTotalDone();
117 emit alert(state, params);
123 void TorrentSession::getState()
125 torrents_t::const_iterator p;
126 for (p = torrents_.constBegin(); p != torrents_.constEnd(); ++p) {
127 TorrentHandlePtr handle = *p;
129 QString hash = Hash2QStr(handle->hash());
132 state.name = handle->name();
133 state.action = TorrentState::action_add;
134 state.state = handle->state();
135 state.progress = handle->progress() * torrent_progress_max;
136 state.down_rate = handle->downloadRate();
137 state.up_rate = handle->uploadRate();
138 state.seeds = handle->numSeeds();
139 state.leeches = handle->numLeeches();
140 state.total_size = handle->getTotalSize();
142 emit alert(state, ParamsMap_t());
146 void TorrentSession::addTorrent(const QString &path, const QString &save_path
147 , qtrapids::ParamsMap_t other_params)
149 return addTorrent_(path, save_path, other_params, false);
152 void TorrentSession::addTorrent_(const QString &path, const QString &save_path
153 , const qtrapids::ParamsMap_t &other_params
154 , bool is_restore_session)
156 add_torrent_params_t addParams;
157 QFile torrent_file(path);
158 QDir::home().mkdir(settings_->getTorrentsSubDir());
160 if (!torrent_file.exists()) {
161 qWarning() << Q_FUNC_INFO << " Torrent file " << path << "doesn't exist";
165 QString new_torrent_fname(QDir(settings_->getTorrentsDir())
166 .filePath(QFileInfo(path).fileName()));
167 #ifdef QTRAPIDS_DEBUG
168 qDebug() << Q_FUNC_INFO << " copy to " << new_torrent_fname;
171 torrent_file.copy(new_torrent_fname);
173 #ifdef QTRAPIDS_DEBUG
174 qDebug() << Q_FUNC_INFO << path << " save to " << save_path;
177 boost::intrusive_ptr<libtorrent::torrent_info> tiTmp
178 = new libtorrent::torrent_info
179 (boost::filesystem::path(new_torrent_fname.toStdString()));
180 addParams.ti = tiTmp;
182 QString download_dir;
183 if (!save_path.isEmpty()) {
184 download_dir = save_path;
186 download_dir = settings_->getDownloadDir();
188 // save_path is the only mandatory parameter, rest are optional.
189 addParams.save_path = boost::filesystem::path(download_dir.toStdString());
190 //addParams.storage_mode = libtorrent::storage_mode_allocate;
192 TorrentHandlePtr handle(new TorrentHandle(btSession_.add_torrent(addParams)));
193 QString hash = Hash2QStr(handle->hash());
195 if (!is_restore_session) {
196 db_->addTorrent(hash, path, save_path);
202 state.name = handle->name();
203 state.action = TorrentState::action_add;
204 state.state = handle->state();
205 state.progress = handle->progress() * torrent_progress_max;
206 state.down_rate = handle->downloadRate();
207 state.up_rate = handle->uploadRate();
208 state.seeds = handle->numSeeds();
209 state.leeches = handle->numLeeches();
210 state.total_size = handle->getTotalSize();
212 torrents_[hash] = handle;
214 emit alert(state, ParamsMap_t());
217 void TorrentSession::removeTorrent(const QString &hash)
219 torrents_t::iterator p = torrents_.find(hash);
221 if (p == torrents_.end()) {
222 #ifdef QTRAPIDS_DEBUG
223 qDebug() << Q_FUNC_INFO << " Invalid request to remove torrent with hash " << hash;
228 btSession_.remove_torrent(p.value()->getHandle());
229 } catch (torrent_exception_t e) {
230 qDebug() << // e.what()
237 state.action = TorrentState::action_remove;
238 emit alert(state, ParamsMap_t());
240 db_->removeTorrent(hash);
244 void TorrentSession::setOptions(qtrapids::ParamsMap_t options)
246 qtrapids::ParamsMapConstIterator_t end = options.end();
247 qtrapids::ParamsMapConstIterator_t tmpIter = options.find("net/downloadRate");
250 // Apply settings immediately to Bittorrent session:
251 // NOTE: QHash interface is not quite STL-like
253 if (tmpIter != end) {
254 rate = tmpIter.value().toInt();
255 btSession_.set_download_rate_limit(rate);
258 tmpIter = options.find("net/uploadRate");
259 if (tmpIter != end) {
260 rate = tmpIter.value().toInt();
261 btSession_.set_upload_rate_limit(rate);
264 /// @todo Add more immediately applicable settings here, if needed.
266 // Finally, save settings to persistent storage:
267 settings_->setOptions(options);
271 qtrapids::ParamsMap_t TorrentSession::getOptions()
273 return settings_->getOptions();
277 void TorrentSession::terminateSession()
279 qDebug() << "Terminate called";
280 // Emiting terminate() here causes the server application to quit in main()
284 } // namespace qtrapids