- Corrected CMakeLists.txt files to allow proper out-of-source build (separate build...
[qtrapids] / src / server / TorrentSession.cpp
1 #include "TorrentSession.hpp"
2 #include "TorrentHandle.hpp"
3 #include "AlertWaiterThread.hpp"
4 #include "ServerDb.hpp"
5 #include <qtrapids/error.hpp>
6
7 namespace qtrapids
8 {
9
10
11
12 TorrentSession::TorrentSession(QObject *parent, QSettings *settings)
13                 : QObject(parent)
14                 , btSession_()
15                 , alertWaiter_(new AlertWaiterThread(&btSession_, this))
16                 , settings_(new ServerSettings(*settings))
17                 , db_(new ServerDb(settings_.get()))
18 {
19         qDBusRegisterMetaType<qtrapids::TorrentState>();
20         qDBusRegisterMetaType<qtrapids::ParamsMap_t>();
21         new QtRapidsServer(this);
22
23         QDBusConnection dbus = QDBusConnection::sessionBus();
24         dbus.registerObject("/qtrapids", this);
25         dbus.registerService("com.ixonos.qtrapids");
26         
27         alertWaiter_->allAlerts();
28         connect(alertWaiter_, SIGNAL(alert()), this, SLOT(on_alert()));
29         alertWaiter_->start();
30
31         loadState();
32         
33         // Lets force applying rate limits to local network also, at least for testing.
34         // Also, on the N900 device, rate limiting is necessary due to limited processign power
35         session_settings_t sessionSettings;
36         sessionSettings.ignore_limits_on_local_network = false;
37         btSession_.set_settings(sessionSettings);
38         
39 }
40
41 void TorrentSession::loadState()
42 {
43         TorrentDownloadInfo info;
44         TorrentsStorage storage(*db_);
45         while (storage.nextTorrent(info)) {
46 #ifdef QTRAPIDS_DEBUG
47                 qDebug() << "adding " << info.path;
48 #endif
49                 addTorrent_(info.path, info.download_path, ParamsMap_t(), true);
50         }
51         btSession_.listen_on(settings_->getListenPorts());
52 }
53
54 void TorrentSession::on_alert()
55 {
56         std::auto_ptr<alert_t> alertPtr = btSession_.pop_alert();
57
58         if (alertPtr.get() != NULL) {
59
60                 torrent_alert_t *ta = dynamic_cast<torrent_alert_t*> (alertPtr.get());
61
62 #ifdef QTRAPIDS_DEBUG
63                 qDebug()
64                 << "TorrentSession::on_alert(): "
65                 << QString::fromStdString(alertPtr->message());
66 #endif
67
68                 if (ta) {
69                         if (!ta->handle.is_valid()) {
70 #ifdef QTRAPIDS_DEBUG
71                                 qDebug() << "handle is invalid";
72 #endif
73                                 return;
74                         }
75
76                         TorrentHandle handle(ta->handle);
77                         TorrentState state;
78
79                         state.hash = Hash2QStr(handle.hash());
80                         state.action = TorrentState::action_update;
81                         state.state = handle.state();
82                         state.progress = handle.progress() * torrent_progress_max;
83                         state.down_rate = handle.downloadRate();
84                         state.up_rate = handle.uploadRate();
85                         state.seeds = handle.numSeeds();
86                         state.leeches = handle.numLeeches();
87                         state.total_size = handle.getTotalSize();
88                         state.total_done = handle.getTotalDone();
89                         
90                         ParamsMap_t params;
91                         emit alert(state, params);
92                 }
93
94         }
95 }
96
97 void TorrentSession::getState()
98 {
99         torrents_t::const_iterator p;
100         for (p = torrents_.constBegin(); p != torrents_.constEnd(); ++p) {
101                 TorrentHandlePtr handle = *p;
102                 TorrentState state;
103                 QString hash = Hash2QStr(handle->hash());
104
105                 state.hash = hash;
106                 state.name = handle->name();
107                 state.action = TorrentState::action_add;
108                 state.state = handle->state();
109                 state.progress = handle->progress() * torrent_progress_max;
110                 state.down_rate = handle->downloadRate();
111                 state.up_rate = handle->uploadRate();
112                 state.seeds = handle->numSeeds();
113                 state.leeches = handle->numLeeches();
114                 state.total_size = handle->getTotalSize();
115
116                 emit alert(state, ParamsMap_t());
117         }
118 }
119
120 void TorrentSession::addTorrent(const QString &path, const QString &save_path
121                                 , qtrapids::ParamsMap_t other_params)
122 {
123         return addTorrent_(path, save_path, other_params, false);
124 }
125
126 void TorrentSession::addTorrent_(const QString &path, const QString &save_path
127                                  , const qtrapids::ParamsMap_t &other_params
128                                  , bool is_restore_session)
129 {
130         add_torrent_params_t addParams;
131         QFile torrent_file(path);
132         QDir::home().mkdir(settings_->getTorrentsSubDir());
133
134         if (!torrent_file.exists()) {
135                 qWarning() << "Torrent file " << path << "doesn't exist";
136                 return;
137         }
138
139         QString new_torrent_fname(QDir(settings_->getTorrentsDir())
140                                   .filePath(QFileInfo(path).fileName()));
141 #ifdef QTRAPIDS_DEBUG
142         qDebug() << "copy to " << new_torrent_fname;
143 #endif
144
145         torrent_file.copy(new_torrent_fname);
146         
147 #ifdef QTRAPIDS_DEBUG
148         qDebug() << "addTorrent: " << path << " save to " << save_path;
149 #endif
150
151         boost::intrusive_ptr<libtorrent::torrent_info> tiTmp
152         = new libtorrent::torrent_info
153         (boost::filesystem::path(new_torrent_fname.toStdString()));
154         addParams.ti = tiTmp;
155
156         QString download_dir;
157         if (!save_path.isEmpty()) {
158                 download_dir = save_path;
159         } else {
160                 download_dir = settings_->getDownloadDir();
161         }
162         // save_path is the only mandatory parameter, rest are optional.
163         addParams.save_path = boost::filesystem::path(download_dir.toStdString());
164         //addParams.storage_mode = libtorrent::storage_mode_allocate;
165
166         TorrentHandlePtr handle(new TorrentHandle(btSession_.add_torrent(addParams)));
167         QString hash = Hash2QStr(handle->hash());
168
169         if (!is_restore_session) {
170                 db_->addTorrent(hash, path, save_path);
171         }
172
173         TorrentState state;
174
175         state.hash = hash;
176         state.name = handle->name();
177         state.action = TorrentState::action_add;
178         state.state = handle->state();
179         state.progress = handle->progress() * torrent_progress_max;
180         state.down_rate = handle->downloadRate();
181         state.up_rate = handle->uploadRate();
182         state.seeds = handle->numSeeds();
183         state.leeches = handle->numLeeches();
184         state.total_size = handle->getTotalSize();
185
186         torrents_[hash] = handle;
187
188         emit alert(state, ParamsMap_t());
189 }
190
191 void TorrentSession::removeTorrent(const QString &hash)
192 {
193         torrents_t::iterator p = torrents_.find(hash);
194
195         if (p == torrents_.end()) {
196 #ifdef QTRAPIDS_DEBUG
197                 qDebug() << "Invalid request to remove torrent with hash " << hash;
198 #endif
199                 return;
200         }
201         try {
202                 btSession_.remove_torrent(p.value()->getHandle());
203         } catch (torrent_exception_t e) {
204                 qDebug() << // e.what()
205                 "exception catched"
206                 ;
207         }
208
209         TorrentState state;
210         state.hash = hash;
211         state.action = TorrentState::action_remove;
212         emit alert(state, ParamsMap_t());
213         torrents_.erase(p);
214         db_->removeTorrent(hash);
215 }
216
217
218 void TorrentSession::setOptions(qtrapids::ParamsMap_t options)
219 {
220         qtrapids::ParamsMapConstIterator_t end = options.end();
221         qtrapids::ParamsMapConstIterator_t tmpIter = options.find("net/downloadRate");
222         int rate = -1;
223
224         // Apply settings immediately to Bittorrent session:
225         // NOTE: QHash interface is not quite STL-like
226         
227         if (tmpIter != end) {
228                 rate = tmpIter.value().toInt();
229                 btSession_.set_download_rate_limit(rate);
230         }
231         
232         tmpIter = options.find("net/uploadRate");
233         if (tmpIter != end) {
234                 rate = tmpIter.value().toInt();
235                 btSession_.set_upload_rate_limit(rate);
236         }
237         
238         /// @todo Add more immediately applicable settings here, if needed.
239         
240         // Finally, save settings to persistent storage:
241         settings_->setOptions(options);
242 }
243
244
245 qtrapids::ParamsMap_t TorrentSession::getOptions()
246 {
247         return settings_->getOptions();
248 }
249
250
251 void TorrentSession::terminateSession()
252 {
253         qDebug() << "Terminate called";
254         emit terminate();
255 }
256
257 } // namespace qtrapids