38140b11049c1ae1290b7967cde8594d2bb2209c
[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
88                         ParamsMap_t params;
89                         emit alert(state, params);
90                 }
91
92         }
93 }
94
95 void TorrentSession::getState()
96 {
97         torrents_t::const_iterator p;
98         for (p = torrents_.constBegin(); p != torrents_.constEnd(); ++p) {
99                 TorrentHandlePtr handle = *p;
100                 TorrentState state;
101                 QString hash = Hash2QStr(handle->hash());
102
103                 state.hash = hash;
104                 state.name = handle->name();
105                 state.action = TorrentState::action_add;
106                 state.state = handle->state();
107                 state.progress = handle->progress() * torrent_progress_max;
108                 state.down_rate = handle->downloadRate();
109                 state.up_rate = handle->uploadRate();
110                 state.seeds = handle->numSeeds();
111                 state.leeches = handle->numLeeches();
112                 state.total_size = handle->getTotalSize();
113
114                 emit alert(state, ParamsMap_t());
115         }
116 }
117
118 void TorrentSession::addTorrent(const QString &path, const QString &save_path
119                                 , qtrapids::ParamsMap_t other_params)
120 {
121         return addTorrent_(path, save_path, other_params, false);
122 }
123
124 void TorrentSession::addTorrent_(const QString &path, const QString &save_path
125                                  , const qtrapids::ParamsMap_t &other_params
126                                  , bool is_restore_session)
127 {
128         add_torrent_params_t addParams;
129         QFile torrent_file(path);
130         QDir::home().mkdir(settings_->getTorrentsSubDir());
131
132         if (!torrent_file.exists()) {
133                 qWarning() << "Torrent file " << path << "doesn't exist";
134                 return;
135         }
136
137         QString new_torrent_fname(QDir(settings_->getTorrentsDir())
138                                   .filePath(QFileInfo(path).fileName()));
139 #ifdef QTRAPIDS_DEBUG
140         qDebug() << "copy to " << new_torrent_fname;
141 #endif
142
143         torrent_file.copy(new_torrent_fname);
144         
145 #ifdef QTRAPIDS_DEBUG
146         qDebug() << "addTorrent: " << path << " save to " << save_path;
147 #endif
148
149         boost::intrusive_ptr<libtorrent::torrent_info> tiTmp
150         = new libtorrent::torrent_info
151         (boost::filesystem::path(new_torrent_fname.toStdString()));
152         addParams.ti = tiTmp;
153
154         QString download_dir;
155         if (!save_path.isEmpty()) {
156                 download_dir = save_path;
157         } else {
158                 download_dir = settings_->getDownloadDir();
159         }
160         // save_path is the only mandatory parameter, rest are optional.
161         addParams.save_path = boost::filesystem::path(download_dir.toStdString());
162         //addParams.storage_mode = libtorrent::storage_mode_allocate;
163
164         TorrentHandlePtr handle(new TorrentHandle(btSession_.add_torrent(addParams)));
165         QString hash = Hash2QStr(handle->hash());
166
167         if (!is_restore_session) {
168                 db_->addTorrent(hash, path, save_path);
169         }
170
171         TorrentState state;
172
173         state.hash = hash;
174         state.name = handle->name();
175         state.action = TorrentState::action_add;
176         state.state = handle->state();
177         state.progress = handle->progress() * torrent_progress_max;
178         state.down_rate = handle->downloadRate();
179         state.up_rate = handle->uploadRate();
180         state.seeds = handle->numSeeds();
181         state.leeches = handle->numLeeches();
182         state.total_size = handle->getTotalSize();
183
184         torrents_[hash] = handle;
185
186         emit alert(state, ParamsMap_t());
187 }
188
189 void TorrentSession::removeTorrent(const QString &hash)
190 {
191         torrents_t::iterator p = torrents_.find(hash);
192
193         if (p == torrents_.end()) {
194 #ifdef QTRAPIDS_DEBUG
195                 qDebug() << "Invalid request to remove torrent with hash " << hash;
196 #endif
197                 return;
198         }
199         try {
200                 btSession_.remove_torrent(p.value()->getHandle());
201         } catch (torrent_exception_t e) {
202                 qDebug() << // e.what()
203                 "exception catched"
204                 ;
205         }
206
207         TorrentState state;
208         state.hash = hash;
209         state.action = TorrentState::action_remove;
210         emit alert(state, ParamsMap_t());
211         torrents_.erase(p);
212         db_->removeTorrent(hash);
213 }
214
215
216 void TorrentSession::setOptions(qtrapids::ParamsMap_t options)
217 {
218         qtrapids::ParamsMapConstIterator_t end = options.end();
219         qtrapids::ParamsMapConstIterator_t tmpIter = options.find("net/downloadRate");
220         int rate = -1;
221
222         // Apply settings immediately to Bittorrent session:
223         // NOTE: QHash interface is not quite STL-like
224         
225         if (tmpIter != end) {
226                 rate = tmpIter.value().toInt();
227                 btSession_.set_download_rate_limit(rate);
228         }
229         
230         tmpIter = options.find("net/uploadRate");
231         if (tmpIter != end) {
232                 rate = tmpIter.value().toInt();
233                 btSession_.set_upload_rate_limit(rate);
234         }
235         
236         /// @todo Add more immediately applicable settings here, if needed.
237         
238         // Finally, save settings to persistent storage:
239         settings_->setOptions(options);
240 }
241
242
243 qtrapids::ParamsMap_t TorrentSession::getOptions()
244 {
245         return settings_->getOptions();
246 }
247
248
249 } // namespace qtrapids