source: src/halTorrentInternal.hpp @ 260

Revision 260, 12.1 KB checked in by Eoin, 13 years ago (diff)
Line 
1
2#pragma once
3
4namespace hal
5{
6class TorrentInternal;
7}
8
9BOOST_CLASS_VERSION(hal::TorrentInternal, 4)
10
11namespace hal
12{
13
14namespace lbt = libtorrent;
15namespace fs = boost::filesystem;
16
17using fs::path;
18using fs::ifstream;
19using fs::ofstream;
20using boost::serialization::make_nvp;
21
22class TorrentInternal
23{
24        friend class BitTorrent_impl;
25       
26        template<typename T>
27        class TransferTracker
28        {
29        public:
30                TransferTracker() :
31                        total_(0),
32                        total_offset_(0)
33                {}
34               
35                TransferTracker(T total) :
36                        total_(total),
37                        total_offset_(0)
38                {}
39               
40                void reset(T total) const
41                {
42                        total_ = total;
43                        total_offset_ = 0;
44                }
45               
46                T update(T rel_total) const
47                {
48                        total_ += (rel_total - total_offset_);
49                        total_offset_ = rel_total;
50                                               
51                        return total_;
52                }
53               
54                operator T() const { return total_; }
55               
56                friend class boost::serialization::access;
57                template<class Archive>
58                void serialize(Archive& ar, const unsigned int version)
59                {
60                        ar & make_nvp("total", total_);
61                }
62               
63        private:
64                mutable T total_;
65                mutable T total_offset_;
66        };
67       
68public:
69        TorrentInternal() :     
70                transferLimit_(std::pair<float, float>(-1, -1)),
71                connections_(-1),
72                uploads_(-1),
73                ratio_(0),
74                resolve_countries_(true),
75                state_(TorrentDetail::torrent_active),
76                in_session_(false),
77                totalUploaded_(0),
78                totalBase_(0)
79        {}
80       
81        TorrentInternal(libtorrent::torrent_handle h, std::wstring f, wpath saveDirectory) :
82                transferLimit_(std::pair<float, float>(bittorrent().defTorrentDownload(), bittorrent().defTorrentUpload())),
83                connections_(bittorrent().defTorrentMaxConn()),
84                uploads_(bittorrent().defTorrentMaxUpload()),
85                ratio_(0),
86                resolve_countries_(true),                            // **********
87                state_(TorrentDetail::torrent_active),
88                filename_(f),
89                save_directory_(saveDirectory.string()),
90                in_session_(true),
91                handle_(h),
92                totalUploaded_(0),
93                totalBase_(0)
94        {}
95       
96        TorrentDetail_ptr getTorrentDetail_ptr() const;
97        void setTransferSpeed(float down, float up);
98        void setConnectionLimit(int maxConn, int maxUpload);
99        void setTransferSpeed();
100        void setConnectionLimit();
101        pair<float, float> getTransferSpeed();
102        pair<int, int> getConnectionLimit();
103       
104        void setRatio(float ratio) 
105        { 
106                if (ratio < 0) ratio = 0;
107               
108                handle_.set_ratio(ratio);
109                ratio_ = ratio; 
110        }
111       
112        void setRatio()
113        {               
114                handle_.set_ratio(ratio_);
115        }
116       
117        float getRatio()
118        {
119                return ratio_;
120        }
121       
122        void setResolveCountries()
123        {
124                handle_.resolve_countries(resolve_countries_);
125        }
126       
127        void resume()
128        {
129                if (!in_session_ && the_session_) 
130                {
131                        handle_ = the_session_->add_torrent(metadata_, 
132                                to_utf8(save_directory_.c_str()), resumedata_);
133                               
134                        in_session_ = true;
135                        applySettings();
136                }               
137                assert(in_session_);
138               
139                handle_.resume();
140                state_ = TorrentDetail::torrent_active;
141        }
142       
143        void pause()
144        {
145                if (state_ != TorrentDetail::torrent_stopped)
146                {       
147                        if (!in_session_ && the_session_) 
148                        {
149                                handle_ = the_session_->add_torrent(metadata_, 
150                                        to_utf8(save_directory_.c_str()), resumedata_);
151                                       
152                                in_session_ = true;
153                                applySettings();
154                        }
155                        assert(in_session_);
156                       
157                        handle_.pause();
158                        state_ = TorrentDetail::torrent_paused; 
159                }
160        }
161       
162        void stop()
163        {
164                if (in_session_ && the_session_) 
165                {
166                        the_session_->remove_torrent(handle_);
167                        in_session_ = false;
168                }
169                assert(!in_session_);
170               
171                state_ = TorrentDetail::torrent_stopped;       
172        }
173       
174        bool isActive() const { return state_ == TorrentDetail::torrent_active; }
175       
176        unsigned state() const { return state_; }
177       
178        void setTrackerLogin()
179        {
180                if (trackerUsername_ != L"")
181                {
182                        handle_.set_tracker_login(hal::to_utf8(trackerUsername_),
183                                hal::to_utf8(trackerPassword_));
184                }
185        }
186       
187        void setTrackerLogin(wstring username, wstring password)
188        {
189                trackerUsername_ = username;
190                trackerPassword_ = password;
191                setTrackerLogin();
192        }       
193       
194        pair<wstring, wstring> getTrackerLogin() const
195        {
196                return make_pair(trackerUsername_, trackerPassword_);
197        }
198       
199        const std::wstring& filename() const { return filename_; }
200       
201        const libtorrent::torrent_handle& handle() const { return handle_; }
202
203        void setHandle(libtorrent::torrent_handle h) 
204        { 
205                handle_ = h; 
206                in_session_ = true;
207        }
208       
209        void resetTrackers()
210        {
211                handle_.replace_trackers(torrent_trackers_);           
212                trackers_.clear();     
213        }
214       
215        const std::vector<TrackerDetail>& getTrackers()
216        {
217                if (trackers_.empty())
218                {
219                        std::vector<lbt::announce_entry> trackers = handle_.trackers();
220                       
221                        foreach (const lbt::announce_entry& entry, trackers)
222                        {
223                                trackers_.push_back(
224                                        TrackerDetail(hal::from_utf8(entry.url), entry.tier));
225                        }
226                }               
227                return trackers_;
228        }
229       
230        void applyTrackers()
231        {
232                if (torrent_trackers_.empty())
233                        torrent_trackers_ = handle_.trackers();
234               
235                if (!trackers_.empty())
236                {
237                        std::vector<lbt::announce_entry> trackers;
238                       
239                        foreach (const TrackerDetail& tracker, trackers_)
240                        {
241                                trackers.push_back(
242                                        lbt::announce_entry(hal::to_utf8(tracker.url)));
243                                trackers.back().tier = tracker.tier;
244                        }
245                        handle_.replace_trackers(trackers);
246                }
247        }
248       
249        void setTrackers(const std::vector<TrackerDetail>& trackerDetails)
250        {
251                trackers_.clear();
252                trackers_.assign(trackerDetails.begin(), trackerDetails.end());
253               
254                applyTrackers();
255        }
256
257        bool inSession() const { return in_session_; }
258        const wstring& saveDirectory() { return save_directory_; }
259       
260    friend class boost::serialization::access;
261    template<class Archive>
262    void serialize(Archive& ar, const unsigned int version)
263    {
264        ar & make_nvp("transferLimit", transferLimit_);
265        ar & make_nvp("connections", connections_);
266        ar & make_nvp("uploads", uploads_);
267        ar & make_nvp("filename", filename_);
268        ar & make_nvp("saveDirectory", save_directory_);
269               
270                if (version > 3) {
271                        ar & make_nvp("payloadUploaded_", payloadUploaded_);
272                        ar & make_nvp("payloadDownloaded_", payloadDownloaded_);
273                        ar & make_nvp("uploaded_", uploaded_);
274                        ar & make_nvp("downloaded_", downloaded_);             
275                } 
276                else if (version > 1)
277                {
278                        ar & make_nvp("totalUploaded", totalUploaded_);
279                        ar & make_nvp("ratio", ratio_);
280                       
281                        payloadUploaded_.reset(totalUploaded_);
282                }
283               
284                if (version > 0) {
285                        ar & make_nvp("trackerUsername", trackerUsername_);
286                        ar & make_nvp("trackerPassword", trackerPassword_);
287                }
288                if (version > 1) {
289                        ar & make_nvp("state", state_);
290                        ar & make_nvp("trackers", trackers_);
291                }
292       
293                if (version > 2) {
294                        ar & make_nvp("resolve_countries", resolve_countries_);
295                }
296    }
297       
298        void setEntryData(libtorrent::entry metadata, libtorrent::entry resumedata)
299        {               
300                metadata_ = metadata;
301                resumedata_ = resumedata;
302        }
303       
304        void applySettings()
305        {               
306                setTransferSpeed();
307                setConnectionLimit();
308                setRatio();
309                applyTrackers();
310                setResolveCountries();
311        }
312       
313        std::vector<lbt::peer_info>& peers() { return peers_; }
314       
315        void updatePeers() const
316        {
317                if (in_session_)
318                        handle_.get_peer_info(peers_);
319        }
320       
321        void getPeerDetails(PeerDetails& peerDetails) const
322        {
323                if (in_session_)
324                        foreach (lbt::peer_info peer, peers_) 
325                        {
326                                peerDetails.push_back(peer);
327                        }       
328        }
329       
330private:
331        static libtorrent::session* the_session_;
332       
333        std::pair<float, float> transferLimit_;
334       
335        unsigned state_;
336        int connections_;
337        int uploads_;
338        bool in_session_;
339        float ratio_;
340        bool resolve_countries_;
341       
342        std::wstring filename_;
343        std::wstring save_directory_;
344        libtorrent::torrent_handle handle_;     
345       
346        libtorrent::entry metadata_;
347        libtorrent::entry resumedata_;
348       
349        std::wstring trackerUsername_; 
350        std::wstring trackerPassword_;
351       
352        mutable boost::int64_t totalUploaded_;
353        mutable boost::int64_t totalBase_;
354       
355        TransferTracker<boost::int64_t> payloadUploaded_;
356        TransferTracker<boost::int64_t> payloadDownloaded_;
357        TransferTracker<boost::int64_t> uploaded_;
358        TransferTracker<boost::int64_t> downloaded_;
359       
360        std::vector<TrackerDetail> trackers_;
361        std::vector<lbt::announce_entry> torrent_trackers_;
362        mutable std::vector<lbt::peer_info> peers_;
363};
364
365typedef std::map<std::string, TorrentInternal> TorrentMap;
366typedef std::pair<std::string, TorrentInternal> TorrentPair;
367
368void TorrentInternal::setConnectionLimit(int maxConn, int maxUpload)
369{
370        handle_.set_max_connections(maxConn);
371        handle_.set_max_uploads(maxUpload);
372
373        connections_ =  maxConn;
374        uploads_ = maxUpload;
375}
376
377void TorrentInternal::setConnectionLimit()
378{
379        handle_.set_max_connections(connections_);
380        handle_.set_max_uploads(uploads_);
381}
382
383pair<int, int> TorrentInternal::getConnectionLimit()
384{
385        return make_pair(connections_, uploads_);
386}
387
388void TorrentInternal::setTransferSpeed(float download, float upload)
389{
390        int down = (download > 0) ? static_cast<int>(download*1024) : -1;
391        handle_.set_download_limit(down);
392        int up = (upload > 0) ? static_cast<int>(upload*1024) : -1;
393        handle_.set_upload_limit(up);
394       
395        transferLimit_ = make_pair(download, upload);
396}
397
398void TorrentInternal::setTransferSpeed()
399{
400        int down = (transferLimit_.first > 0) ? static_cast<int>(transferLimit_.first*1024) : -1;
401        handle_.set_download_limit(down);
402        int up = (transferLimit_.second > 0) ? static_cast<int>(transferLimit_.second*1024) : -1;
403        handle_.set_upload_limit(up);
404}
405
406pair<float, float> TorrentInternal::getTransferSpeed()
407{
408        return transferLimit_;
409}
410
411TorrentDetail_ptr TorrentInternal::getTorrentDetail_ptr() const
412{       
413        if (inSession())
414        {
415                lbt::torrent_status tS = handle_.status();
416                wstring state;
417               
418                if (state_ == TorrentDetail::torrent_paused)
419                        state = app().res_wstr(HAL_TORRENT_PAUSED);
420                else if (state_ == TorrentDetail::torrent_stopped)
421                        state = app().res_wstr(HAL_TORRENT_STOPPED);
422                else
423                {
424                        switch (tS.state)
425                        {
426                        case lbt::torrent_status::queued_for_checking:
427                                state = app().res_wstr(HAL_TORRENT_QUEUED_CHECKING);
428                                break;
429                        case lbt::torrent_status::checking_files:
430                                state = app().res_wstr(HAL_TORRENT_CHECKING_FILES);
431                                break;
432                        case lbt::torrent_status::connecting_to_tracker:
433                                state = app().res_wstr(HAL_TORRENT_CONNECTING);
434                                break;
435                        case lbt::torrent_status::downloading_metadata:
436                                state = app().res_wstr(HAL_TORRENT_METADATA);
437                                break;
438                        case lbt::torrent_status::downloading:
439                                state = app().res_wstr(HAL_TORRENT_DOWNLOADING);
440                                break;
441                        case lbt::torrent_status::finished:
442                                state = app().res_wstr(HAL_TORRENT_FINISHED);
443                                break;
444                        case lbt::torrent_status::seeding:
445                                state = app().res_wstr(HAL_TORRENT_SEEDING);
446                                break;
447                        case lbt::torrent_status::allocating:
448                                state = app().res_wstr(HAL_TORRENT_ALLOCATING);
449                                break;
450                        }       
451                }
452               
453                boost::posix_time::time_duration td(boost::posix_time::pos_infin);
454               
455                if (tS.download_payload_rate != 0)
456                {
457                        td = boost::posix_time::seconds(       
458                                long( float(tS.total_wanted-tS.total_wanted_done) / tS.download_payload_rate ));
459                }
460               
461                totalUploaded_ += (tS.total_payload_upload - totalBase_);
462                totalBase_ = tS.total_payload_upload;
463               
464                uploaded_.update(tS.total_upload);
465                payloadUploaded_.update(tS.total_payload_upload);
466                downloaded_.update(tS.total_download);
467                payloadDownloaded_.update(tS.total_payload_download);
468               
469                updatePeers();
470               
471                size_t totalPeers = 0;
472                size_t peersConnected = 0;
473                size_t totalSeeds = 0;
474                size_t seedsConnected = 0;
475               
476                foreach (lbt::peer_info peer, peers_) 
477                {
478                        float speedSum = peer.down_speed + peer.up_speed;
479                       
480                        if (!peer.flags & lbt::peer_info::seed)
481                        {
482                                ++totalPeers;
483                               
484                                if (speedSum > 0)
485                                        ++peersConnected;
486                        }
487                        else
488                        {
489                                ++totalSeeds;
490                               
491                                if (speedSum > 0)
492                                        ++seedsConnected;
493                        }
494                }                       
495
496                return TorrentDetail_ptr(new TorrentDetail(filename_, state, hal::from_utf8(tS.current_tracker), 
497                        pair<float, float>(tS.download_payload_rate, tS.upload_payload_rate),
498                        tS.progress, tS.distributed_copies, tS.total_wanted_done, tS.total_wanted, uploaded_, payloadUploaded_,
499                        downloaded_, payloadDownloaded_, totalPeers, peersConnected, totalSeeds, seedsConnected, ratio_, td, tS.next_announce));
500        }
501        else
502        {
503                return TorrentDetail_ptr(new TorrentDetail(filename_, L"Not in Session", L"No tracker"));
504        }
505}
506
507} //namespace hal
Note: See TracBrowser for help on using the repository browser.