- Added daemon start functionality
[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
42 TorrentSession::~TorrentSession()
43 {
44         alertWaiter_->stop();
45         alertWaiter_->wait();
46         emit sessionTerminated();
47 }
48
49
50 void TorrentSession::loadState()
51 {
52         TorrentDownloadInfo info;
53         TorrentsStorage storage(*db_);
54         while (storage.nextTorrent(info)) {
55 #ifdef QTRAPIDS_DEBUG
56                 qDebug() << "adding " << info.path;
57 #endif
58                 addTorrent_(info.path, info.download_path, ParamsMap_t(), true);
59         }
60         btSession_.listen_on(settings_->getListenPorts());
61 }
62
63 void TorrentSession::on_alert()
64 {
65         std::auto_ptr<alert_t> alertPtr = btSession_.pop_alert();
66
67         if (alertPtr.get() != NULL) {
68
69                 torrent_alert_t *ta = dynamic_cast<torrent_alert_t*> (alertPtr.get());
70
71 #ifdef QTRAPIDS_DEBUG
72                 qDebug()
73                 << "TorrentSession::on_alert(): "
74                 << QString::fromStdString(alertPtr->message());
75 #endif
76
77                 if (ta) {
78                         if (!ta->handle.is_valid()) {
79 #ifdef QTRAPIDS_DEBUG
80                                 qDebug() << "handle is invalid";
81 #endif
82                                 return;
83                         }
84
85                         TorrentHandle handle(ta->handle);
86                         TorrentState state;
87
88                         state.hash = Hash2QStr(handle.hash());
89                         state.action = TorrentState::action_update;
90                         state.state = handle.state();
91                         state.progress = handle.progress() * torrent_progress_max;
92                         state.down_rate = handle.downloadRate();
93                         state.up_rate = handle.uploadRate();
94                         state.seeds = handle.numSeeds();
95                         state.leeches = handle.numLeeches();
96                         state.total_size = handle.getTotalSize();
97                         state.total_done = handle.getTotalDone();
98                         
99                         ParamsMap_t params;
100                         emit alert(state, params);
101                 }
102
103         }
104 }
105
106 void TorrentSession::getState()
107 {
108         torrents_t::const_iterator p;
109         for (p = torrents_.constBegin(); p != torrents_.constEnd(); ++p) {
110                 TorrentHandlePtr handle = *p;
111                 TorrentState state;
112                 QString hash = Hash2QStr(handle->hash());
113
114                 state.hash = hash;
115                 state.name = handle->name();
116                 state.action = TorrentState::action_add;
117                 state.state = handle->state();
118                 state.progress = handle->progress() * torrent_progress_max;
119                 state.down_rate = handle->downloadRate();
120                 state.up_rate = handle->uploadRate();
121                 state.seeds = handle->numSeeds();
122                 state.leeches = handle->numLeeches();
123                 state.total_size = handle->getTotalSize();
124
125                 emit alert(state, ParamsMap_t());
126         }
127 }
128
129 void TorrentSession::addTorrent(const QString &path, const QString &save_path
130                                 , qtrapids::ParamsMap_t other_params)
131 {
132         return addTorrent_(path, save_path, other_params, false);
133 }
134
135 void TorrentSession::addTorrent_(const QString &path, const QString &save_path
136                                  , const qtrapids::ParamsMap_t &other_params
137                                  , bool is_restore_session)
138 {
139         add_torrent_params_t addParams;
140         QFile torrent_file(path);
141         QDir::home().mkdir(settings_->getTorrentsSubDir());
142
143         if (!torrent_file.exists()) {
144                 qWarning() << "Torrent file " << path << "doesn't exist";
145                 return;
146         }
147
148         QString new_torrent_fname(QDir(settings_->getTorrentsDir())
149                                   .filePath(QFileInfo(path).fileName()));
150 #ifdef QTRAPIDS_DEBUG
151         qDebug() << "copy to " << new_torrent_fname;
152 #endif
153
154         torrent_file.copy(new_torrent_fname);
155         
156 #ifdef QTRAPIDS_DEBUG
157         qDebug() << "addTorrent: " << path << " save to " << save_path;
158 #endif
159
160         boost::intrusive_ptr<libtorrent::torrent_info> tiTmp
161         = new libtorrent::torrent_info
162         (boost::filesystem::path(new_torrent_fname.toStdString()));
163         addParams.ti = tiTmp;
164
165         QString download_dir;
166         if (!save_path.isEmpty()) {
167                 download_dir = save_path;
168         } else {
169                 download_dir = settings_->getDownloadDir();
170         }
171         // save_path is the only mandatory parameter, rest are optional.
172         addParams.save_path = boost::filesystem::path(download_dir.toStdString());
173         //addParams.storage_mode = libtorrent::storage_mode_allocate;
174
175         TorrentHandlePtr handle(new TorrentHandle(btSession_.add_torrent(addParams)));
176         QString hash = Hash2QStr(handle->hash());
177
178         if (!is_restore_session) {
179                 db_->addTorrent(hash, path, save_path);
180         }
181
182         TorrentState state;
183
184         state.hash = hash;
185         state.name = handle->name();
186         state.action = TorrentState::action_add;
187         state.state = handle->state();
188         state.progress = handle->progress() * torrent_progress_max;
189         state.down_rate = handle->downloadRate();
190         state.up_rate = handle->uploadRate();
191         state.seeds = handle->numSeeds();
192         state.leeches = handle->numLeeches();
193         state.total_size = handle->getTotalSize();
194
195         torrents_[hash] = handle;
196
197         emit alert(state, ParamsMap_t());
198 }
199
200 void TorrentSession::removeTorrent(const QString &hash)
201 {
202         torrents_t::iterator p = torrents_.find(hash);
203
204         if (p == torrents_.end()) {
205 #ifdef QTRAPIDS_DEBUG
206                 qDebug() << "Invalid request to remove torrent with hash " << hash;
207 #endif
208                 return;
209         }
210         try {
211                 btSession_.remove_torrent(p.value()->getHandle());
212         } catch (torrent_exception_t e) {
213                 qDebug() << // e.what()
214                 "exception catched"
215                 ;
216         }
217
218         TorrentState state;
219         state.hash = hash;
220         state.action = TorrentState::action_remove;
221         emit alert(state, ParamsMap_t());
222         torrents_.erase(p);
223         db_->removeTorrent(hash);
224 }
225
226
227 void TorrentSession::setOptions(qtrapids::ParamsMap_t options)
228 {
229         qtrapids::ParamsMapConstIterator_t end = options.end();
230         qtrapids::ParamsMapConstIterator_t tmpIter = options.find("net/downloadRate");
231         int rate = -1;
232
233         // Apply settings immediately to Bittorrent session:
234         // NOTE: QHash interface is not quite STL-like
235         
236         if (tmpIter != end) {
237                 rate = tmpIter.value().toInt();
238                 btSession_.set_download_rate_limit(rate);
239         }
240         
241         tmpIter = options.find("net/uploadRate");
242         if (tmpIter != end) {
243                 rate = tmpIter.value().toInt();
244                 btSession_.set_upload_rate_limit(rate);
245         }
246         
247         /// @todo Add more immediately applicable settings here, if needed.
248         
249         // Finally, save settings to persistent storage:
250         settings_->setOptions(options);
251 }
252
253
254 qtrapids::ParamsMap_t TorrentSession::getOptions()
255 {
256         return settings_->getOptions();
257 }
258
259
260 void TorrentSession::terminateSession()
261 {
262         qDebug() << "Terminate called";
263         // Emiting terminate() here causes the server application to quit in main()
264         emit terminate();
265 }
266
267 } // namespace qtrapids