source: trunk/src/halTorrentInternal.hpp @ 452

Revision 452, 42.5 KB checked in by Eoin, 12 years ago (diff)

Update libtorrent fixed +4GB bug.

Line 
1
2//         Copyright Eóin O'Callaghan 2006 - 2008.
3// Distributed under the Boost Software License, Version 1.0.
4//    (See accompanying file LICENSE_1_0.txt or copy at
5//          http://www.boost.org/LICENSE_1_0.txt)
6
7#pragma once
8
9#define HALITE_VERSION                                  0, 3, 0, 437
10#define HALITE_VERSION_STRING                   "v 0.3.0.6 dev 437"
11#define HALITE_FINGERPRINT                              "HL", 0, 3, 0, 6
12
13#ifndef HAL_NA
14#define HAL_NA 40013
15#endif
16
17#define HAL_TORRENT_EXT_BEGIN                           41000
18#define LBT_EVENT_TORRENT_FINISHED                      HAL_TORRENT_EXT_BEGIN + 1
19#define HAL_PEER_BAN_ALERT                                      HAL_TORRENT_EXT_BEGIN + 2
20#define HAL_HASH_FAIL_ALERT                                     HAL_TORRENT_EXT_BEGIN + 3
21#define HAL_URL_SEED_ALERT                                      HAL_TORRENT_EXT_BEGIN + 5
22#define HAL_TRACKER_WARNING_ALERT                       HAL_TORRENT_EXT_BEGIN + 4
23#define HAL_TRACKER_ANNOUNCE_ALERT                      HAL_TORRENT_EXT_BEGIN + 6
24#define HAL_TRACKER_ALERT                                       HAL_TORRENT_EXT_BEGIN + 7
25#define HAL_TRACKER_REPLY_ALERT                         HAL_TORRENT_EXT_BEGIN + 8
26#define LBT_EVENT_TORRENT_PAUSED                        HAL_TORRENT_EXT_BEGIN + 9
27#define HAL_FAST_RESUME_ALERT                           HAL_TORRENT_EXT_BEGIN + 10
28#define HAL_PIECE_FINISHED_ALERT                        HAL_TORRENT_EXT_BEGIN + 11
29#define HAL_BLOCK_FINISHED_ALERT                        HAL_TORRENT_EXT_BEGIN + 12
30#define HAL_BLOCK_DOWNLOADING_ALERT                     HAL_TORRENT_EXT_BEGIN + 13
31#define HAL_LISTEN_SUCCEEDED_ALERT                      HAL_TORRENT_EXT_BEGIN + 14
32#define HAL_LISTEN_FAILED_ALERT                         HAL_TORRENT_EXT_BEGIN + 15
33#define HAL_IPFILTER_ALERT                                      HAL_TORRENT_EXT_BEGIN + 16
34#define HAL_INCORRECT_ENCODING_LEVEL            HAL_TORRENT_EXT_BEGIN + 17
35#define HAL_INCORRECT_CONNECT_POLICY            HAL_TORRENT_EXT_BEGIN + 18
36#define HAL_PEER_ALERT                                          HAL_TORRENT_EXT_BEGIN + 19
37#define HAL_LISTEN_V6_FAILED_ALERT                      HAL_TORRENT_EXT_BEGIN + 20
38#define HAL_TORRENT_LOAD_FILTERS                                HAL_TORRENT_EXT_BEGIN + 21
39
40#define HAL_TORRENT_INT_BEGIN                           42000
41#define HAL_PEER_INTERESTING                    HAL_TORRENT_INT_BEGIN + 1
42#define HAL_PEER_CHOKED                         HAL_TORRENT_INT_BEGIN + 2
43#define HAL_PEER_REMOTE_INTERESTING                     HAL_TORRENT_INT_BEGIN + 3
44#define HAL_PEER_REMOTE_CHOKED                          HAL_TORRENT_INT_BEGIN + 4
45#define HAL_PEER_SUPPORT_EXTENSIONS                     HAL_TORRENT_INT_BEGIN + 5
46#define HAL_PEER_LOCAL_CONNECTION                       HAL_TORRENT_INT_BEGIN + 6
47#define HAL_PEER_HANDSHAKE                                      HAL_TORRENT_INT_BEGIN + 7
48#define HAL_PEER_CONNECTING                                     HAL_TORRENT_INT_BEGIN + 8
49#define HAL_PEER_QUEUED                                         HAL_TORRENT_INT_BEGIN + 9
50#define HAL_PEER_RC4_ENCRYPTED                          HAL_TORRENT_INT_BEGIN + 10
51#define HAL_PEER_PLAINTEXT_ENCRYPTED            HAL_TORRENT_INT_BEGIN + 11
52#define HAL_TORRENT_QUEUED_CHECKING                     HAL_TORRENT_INT_BEGIN + 12
53#define HAL_TORRENT_CHECKING_FILES                      HAL_TORRENT_INT_BEGIN + 13
54#define HAL_TORRENT_CONNECTING                          HAL_TORRENT_INT_BEGIN + 14
55#define HAL_TORRENT_DOWNLOADING                         HAL_TORRENT_INT_BEGIN + 15
56#define HAL_TORRENT_FINISHED                            HAL_TORRENT_INT_BEGIN + 16
57#define HAL_TORRENT_SEEDING                                     HAL_TORRENT_INT_BEGIN + 17
58#define HAL_TORRENT_ALLOCATING                          HAL_TORRENT_INT_BEGIN + 18
59#define HAL_TORRENT_QUEUED                                      HAL_TORRENT_INT_BEGIN + 19
60#define HAL_TORRENT_STOPPED                                     HAL_TORRENT_INT_BEGIN + 20
61#define HAL_TORRENT_PAUSED                                      HAL_TORRENT_INT_BEGIN + 21
62#define HAL_TORRENT_STOPPING                            HAL_TORRENT_INT_BEGIN + 22
63#define HAL_TORRENT_PAUSING                                     HAL_TORRENT_INT_BEGIN + 23
64#define HAL_TORRENT_METADATA                    HAL_TORRENT_INT_BEGIN + 24
65#define HAL_NEWT_CREATING_TORRENT                       HAL_TORRENT_INT_BEGIN + 25
66#define HAL_NEWT_HASHING_PIECES                 HAL_TORRENT_INT_BEGIN + 26
67#define HAL_TORRENT_IMPORT_FILTERS              HAL_TORRENT_INT_BEGIN + 27
68#define HAL_INT_NEWT_ADD_PEERS_WEB              HAL_TORRENT_INT_BEGIN + 28
69#define HAL_INT_NEWT_ADD_PEERS_DHT              HAL_TORRENT_INT_BEGIN + 29
70#define HAL_NEWT_CREATION_CANCELED              HAL_TORRENT_INT_BEGIN + 30
71
72
73#ifndef RC_INVOKED
74
75#include <boost/tuple/tuple.hpp>
76#include <boost/enable_shared_from_this.hpp>
77#include <boost/multi_index_container.hpp>
78#include <boost/multi_index/ordered_index.hpp>
79#include <boost/multi_index/indexed_by.hpp>
80#include <boost/multi_index/identity.hpp>
81#include <boost/multi_index/member.hpp>
82#include <boost/multi_index/tag.hpp>
83#include <boost/serialization/shared_ptr.hpp>
84
85#include "halIni.hpp"
86#include "halTypes.hpp"
87#include "halSignaler.hpp"
88
89namespace hal
90{
91class TorrentInternalOld;
92class torrent_internal;
93}
94
95BOOST_CLASS_VERSION(hal::TorrentInternalOld, 9)
96BOOST_CLASS_VERSION(hal::torrent_internal, 2)
97
98namespace hal
99{
100
101namespace libt = libtorrent;
102
103libt::entry haldecode(const wpath &file) 
104{
105        fs::ifstream ifs(file, fs::ifstream::binary);
106        if (ifs.is_open()) 
107        {
108                ifs.unsetf(fs::ifstream::skipws);
109                return libt::bdecode(std::istream_iterator<char>(ifs), std::istream_iterator<char>());
110        }
111        else return libt::entry();
112}
113
114bool halencode(const wpath &file, const libt::entry &e) 
115{
116        fs::ofstream ofs(file, fs::ofstream::binary);
117
118        if (!ofs.is_open()) 
119                return false;
120       
121        libt::bencode(std::ostream_iterator<char>(ofs), e);
122        return true;
123}
124
125inline path path_to_utf8(const wpath& wp)
126{
127        return path(to_utf8(wp.string()));
128}
129
130inline wpath path_from_utf8(const path& p)
131{
132        return wpath(from_utf8(p.string()));
133}
134
135std::pair<std::string, std::string> extract_names(const wpath &file)
136{
137        if (fs::exists(file)) 
138        {       
139                libt::torrent_info info(haldecode(file));
140
141                std::string name = info.name(); 
142                std::string filename = name;
143
144                if (!boost::find_last(filename, ".torrent")) 
145                                filename += ".torrent";
146               
147                event().post(shared_ptr<EventDetail>(new EventMsg(
148                        wformat(L"Loaded names: %1%, %2%") % from_utf8(name) % from_utf8(filename))));
149
150                return std::make_pair(name, filename);
151        }
152        else
153                return std::make_pair("", "");
154}
155
156class invalidTorrent : public std::exception
157{
158public:
159        invalidTorrent(const wstring& who) :
160                who_(who)
161        {}
162       
163        virtual ~invalidTorrent() throw () {}
164
165        wstring who() const throw ()
166        {
167                return who_;
168        }       
169       
170private:
171        wstring who_;   
172};
173       
174template<typename T>
175class transfer_tracker
176{
177public:
178        transfer_tracker() :
179                total_(0),
180                total_offset_(0)
181        {}
182       
183        transfer_tracker(T total) :
184                total_(total),
185                total_offset_(0)
186        {}
187       
188        transfer_tracker(T total, T offset) :
189                total_(total),
190                total_offset_(offset)
191        {}
192       
193        void reset(T total) const
194        {
195                total_ = total;
196                total_offset_ = 0;
197        }
198       
199        T update(T rel_total) const
200        {
201                total_ += (rel_total - total_offset_);
202                total_offset_ = rel_total;
203               
204                return total_;
205        }
206       
207        void setOffset(T offset) const
208        {
209                total_offset_ = offset;
210        }
211       
212        operator T() const { return total_; }
213       
214        friend class boost::serialization::access;
215        template<class Archive>
216        void serialize(Archive& ar, const unsigned int version)
217        {
218                ar & boost::serialization::make_nvp("total", total_);
219        }
220       
221private:
222        mutable T total_;
223        mutable T total_offset_;
224};
225
226class duration_tracker
227{
228public:
229        duration_tracker() :
230                total_(boost::posix_time::time_duration(0,0,0,0), 
231                        boost::posix_time::time_duration(0,0,0,0))
232        {}
233       
234        boost::posix_time::time_duration update() const
235        {
236                if (start_.is_not_a_date_time()) 
237                        start_ = boost::posix_time::second_clock::universal_time();
238
239                if (static_cast<boost::posix_time::time_duration>(total_).is_special()) 
240                        total_.setOffset(boost::posix_time::time_duration(0,0,0,0));
241               
242                return total_.update(boost::posix_time::second_clock::universal_time() - start_);
243        }
244       
245        void reset() const
246        {
247                total_.setOffset(boost::posix_time::time_duration(0,0,0,0));
248                start_ = boost::posix_time::second_clock::universal_time();
249        }
250       
251        friend class boost::serialization::access;
252        template<class Archive>
253        void serialize(Archive& ar, const unsigned int version)
254        {
255                ar & boost::serialization::make_nvp("total", total_);
256        }
257       
258        operator boost::posix_time::time_duration() const { return total_; }
259       
260private:
261        transfer_tracker<boost::posix_time::time_duration> total_;     
262        mutable boost::posix_time::ptime start_;               
263};
264       
265class TorrentInternalOld
266{
267public: 
268    friend class boost::serialization::access;
269    template<class Archive>
270    void serialize(Archive& ar, const unsigned int version)
271    {
272                using boost::serialization::make_nvp;
273
274        ar & make_nvp("transferLimit", transferLimit_);
275        ar & make_nvp("connections", connections_);
276        ar & make_nvp("uploads", uploads_);     
277               
278                if (version > 6) {
279                        ar & make_nvp("filename", filename_);
280                }
281                else 
282                {
283                        wstring originalFilename;
284                        ar & make_nvp("filename", originalFilename);
285                       
286                        updatePreVersion7Files(originalFilename);
287                }
288               
289        ar & make_nvp("saveDirectory", save_directory_);
290               
291                if (version > 7) {
292                        ar & make_nvp("payloadUploaded_", payloadUploaded_);
293                        ar & make_nvp("payloadDownloaded_", payloadDownloaded_);
294                        ar & make_nvp("uploaded_", uploaded_);
295                        ar & make_nvp("downloaded_", downloaded_);     
296                        ar & make_nvp("ratio", ratio_); 
297                } 
298                else if (version > 3) {
299                        ar & make_nvp("payloadUploaded_", payloadUploaded_);
300                        ar & make_nvp("payloadDownloaded_", payloadDownloaded_);
301                        ar & make_nvp("uploaded_", uploaded_);
302                        ar & make_nvp("downloaded_", downloaded_);             
303                } 
304                else if (version > 1)
305                {
306                        ar & make_nvp("totalUploaded", totalUploaded_);
307                        ar & make_nvp("ratio", ratio_);
308                       
309                        payloadUploaded_.reset(totalUploaded_);
310                }
311               
312                if (version > 0) {
313                        ar & make_nvp("trackerUsername", trackerUsername_);
314                        ar & make_nvp("trackerPassword", trackerPassword_);
315                }
316                if (version > 1) {
317                        ar & make_nvp("state", state_);
318                        ar & make_nvp("trackers", trackers_);
319                }
320       
321                if (version > 2) {
322                        ar & make_nvp("resolve_countries", resolve_countries_);
323                }
324                if (version > 4) {
325                        ar & make_nvp("file_priorities", filePriorities_);
326                }
327                if (version > 5) {
328                        ar & make_nvp("startTime", startTime_);
329                        ar & make_nvp("activeDuration", activeDuration_);
330                        ar & make_nvp("seedingDuration", seedingDuration_);
331                }
332                if (version > 6) {
333                        ar & make_nvp("name", name_);
334                        ar & make_nvp("compactStorage", compactStorage_);
335                        ar & make_nvp("finishTime", finishTime_);
336                }
337                if (version > 8) {
338                        ar & make_nvp("progress", progress_);
339                }
340    }
341       
342        void extractNames(libt::entry& metadata)
343        {               
344                libt::torrent_info info(metadata);                             
345                name_ = hal::from_utf8_safe(info.name());
346               
347                filename_ = name_;
348                if (!boost::find_last(filename_, L".torrent")) 
349                                filename_ += L".torrent";
350               
351                event().post(shared_ptr<EventDetail>(new EventMsg(
352                        wformat(L"Loaded names: %1%, %2%") % name_ % filename_)));
353        }
354       
355        void updatePreVersion7Files(wstring originalFilename)
356        {
357                try 
358                {
359
360                wpath oldFile = app().working_directory()/L"torrents"/originalFilename;
361               
362                if (fs::exists(oldFile)) 
363                        extractNames(haldecode(oldFile));
364               
365                wpath oldResumeFile = app().working_directory()/L"resume"/originalFilename;
366               
367                if (filename_ != originalFilename)
368                {
369                        fs::rename(oldFile, app().working_directory()/L"torrents"/filename_);
370                       
371                        if (fs::exists(oldResumeFile))
372                                fs::rename(oldResumeFile, app().working_directory()/L"resume"/filename_);
373                }
374               
375                }
376                catch(std::exception &e) 
377                {               
378                        hal::event().post(boost::shared_ptr<hal::EventDetail>(
379                                new hal::EventStdException(Event::critical, e, L"updatePreVersion7Files"))); 
380                }
381        }
382       
383        std::pair<float, float> transferLimit_;
384       
385        unsigned state_;
386        int connections_;
387        int uploads_;
388        bool in_session_;
389        float ratio_;
390        bool resolve_countries_;
391       
392        wstring filename_;
393        wstring name_;
394        wstring save_directory_;
395        wstring originalFilename_;
396        libt::torrent_handle handle_;   
397       
398        libt::entry metadata_;
399        libt::entry resumedata_;
400       
401        wstring trackerUsername_;       
402        wstring trackerPassword_;
403       
404        boost::int64_t totalUploaded_;
405        boost::int64_t totalBase_;
406       
407        transfer_tracker<boost::int64_t> payloadUploaded_;
408        transfer_tracker<boost::int64_t> payloadDownloaded_;
409        transfer_tracker<boost::int64_t> uploaded_;
410        transfer_tracker<boost::int64_t> downloaded_;
411       
412        boost::posix_time::ptime startTime_;
413        boost::posix_time::ptime finishTime_;
414        duration_tracker activeDuration_;
415        duration_tracker seedingDuration_;
416       
417        std::vector<tracker_detail> trackers_;
418        std::vector<libt::announce_entry> torrent_trackers_;
419        std::vector<libt::peer_info> peers_;   
420        std::vector<int> filePriorities_;
421       
422        float progress_;
423       
424        libt::torrent_info infoMemory_;
425        libt::torrent_status statusMemory_;
426        FileDetails fileDetailsMemory_;
427       
428        bool compactStorage_;
429};
430
431
432struct signalers
433{
434        signaler<> torrent_finished;
435        signaler<> torrent_paused;
436};
437
438
439class torrent_internal;
440typedef shared_ptr<torrent_internal> torrent_internal_ptr;
441
442struct torrent_standalone :
443        public hal::IniBase<torrent_standalone>
444{
445        typedef torrent_standalone thisClass;
446        typedef hal::IniBase<thisClass> iniClass;
447
448        torrent_standalone() :
449                iniClass("torrent")
450        {}
451
452        torrent_standalone(torrent_internal_ptr t) :
453                iniClass("torrent"),
454                torrent(t),
455                save_time(pt::second_clock::universal_time())
456        {}
457
458        torrent_internal_ptr torrent;
459        pt::ptime save_time;
460
461    friend class boost::serialization::access;
462    template<class Archive>
463    void serialize(Archive& ar, const unsigned int version)
464    {
465                ar & boost::serialization::make_nvp("torrent", torrent);
466                ar & boost::serialization::make_nvp("save_time", save_time);
467    }
468};
469
470class torrent_internal :
471        public boost::enable_shared_from_this<torrent_internal>,
472        private boost::noncopyable
473{
474        friend class bit_impl; 
475        friend class bit::torrent::exec_around_ptr::proxy;
476
477public:
478        #define TORRENT_INTERNALS_DEFAULTS \
479                originalFilename_(L""), \
480                transferLimit_(std::pair<float, float>(-1, -1)), \
481                connections_(-1), \
482                uploads_(-1), \
483                ratio_(0), \
484                resolve_countries_(true), \
485                totalUploaded_(0), \
486                totalBase_(0), \
487                progress_(0), \
488                startTime_(boost::posix_time::second_clock::universal_time()), \
489                in_session_(false)
490               
491        torrent_internal() :   
492                TORRENT_INTERNALS_DEFAULTS,
493                compactStorage_(true),
494                state_(TorrentDetail::torrent_stopped)
495        {}
496       
497        torrent_internal(wpath filename, wpath saveDirectory, bool compactStorage, wpath move_to_directory=L"") :
498                TORRENT_INTERNALS_DEFAULTS,
499                save_directory_(saveDirectory.string()),
500                move_to_directory_(move_to_directory.string()),
501                compactStorage_(compactStorage),       
502                state_(TorrentDetail::torrent_stopped)
503        {
504                assert(the_session_);           
505                prepare(filename);
506        }
507       
508        torrent_internal(const TorrentInternalOld& t) :
509                transferLimit_(t.transferLimit_),
510                state_(t.state_),
511                connections_(t.connections_),
512                uploads_(t.uploads_),
513                ratio_(t.ratio_),
514                resolve_countries_(t.resolve_countries_),
515                filename_(t.filename_),
516                name_(t.name_),
517                save_directory_(t.save_directory_),
518                originalFilename_(t.originalFilename_),
519                handle_(t.handle_),
520                metadata_(t.metadata_),
521                resumedata_(t.resumedata_),
522                trackerUsername_(t.trackerUsername_),   
523                trackerPassword_(t.trackerPassword_),
524                totalUploaded_(t.totalUploaded_),
525                totalBase_(t.totalBase_),
526                payloadUploaded_(t.payloadUploaded_),
527                payloadDownloaded_(t.payloadDownloaded_),
528                uploaded_(t.uploaded_),
529                downloaded_(t.downloaded_),
530                startTime_(t.startTime_),
531                finishTime_(t.finishTime_),
532                activeDuration_(t.activeDuration_),
533                seedingDuration_(t.seedingDuration_),
534                trackers_(t.trackers_),
535                torrent_trackers_(t.torrent_trackers_),
536                peers_(t.peers_),
537                filePriorities_(t.filePriorities_),
538                progress_(t.progress_),
539                infoMemory_(t.infoMemory_),
540                statusMemory_(t.statusMemory_),
541                fileDetailsMemory_(t.fileDetailsMemory_),
542                compactStorage_(t.compactStorage_)
543        {}
544       
545        #undef TORRENT_INTERNALS_DEFAULTS
546       
547        TorrentDetail_ptr getTorrentDetail_ptr();
548        void setTransferSpeed(float down, float up);
549        void setConnectionLimit(int maxConn, int maxUpload);
550        std::pair<float, float> getTransferSpeed();
551        std::pair<int, int> getConnectionLimit();
552       
553        const wstring& name() const { return name_; }
554       
555        void set_ratio(float ratio) 
556        { 
557                if (ratio < 0) ratio = 0;
558                ratio_ = ratio; 
559               
560                apply_ratio();
561        }
562       
563        float get_ratio()
564        {
565                return ratio_;
566        }
567       
568        void add_to_session(bool paused = false)
569        {
570                try
571                {
572
573                mutex_t::scoped_lock l(mutex_); 
574                assert(the_session_ != 0);
575
576                HAL_DEV_MSG(wformat(L"add_to_session() paused=%1%") % paused);
577               
578                if (!in_session()) 
579                {                       
580                        path dir = path_to_utf8(save_directory_);
581                       
582                        libt::storage_mode_t storage = libt::storage_mode_sparse;
583                       
584                        if (compactStorage_)
585                                storage = libt::storage_mode_compact;
586                       
587                        handle_ = the_session_->add_torrent(metadata_, dir, resumedata_, storage, paused);                     
588                        assert(handle_.is_valid());
589                       
590                        clear_resume_data();
591                       
592                        in_session_ = true;
593                        if (paused)
594                                state_ = TorrentDetail::torrent_paused; 
595                        else
596                                state_ = TorrentDetail::torrent_active; 
597                               
598                        applySettings();
599                        handle_.force_reannounce();
600                }       
601
602                assert(in_session());
603                HAL_DEV_MSG(L"Added to session");
604
605                }
606                catch(std::exception& e)
607                {
608                        hal::event().post(boost::shared_ptr<hal::EventDetail>(
609                                new hal::EventStdException(Event::critical, e, L"addToSession"))); 
610                }
611        }
612       
613        void remove_from_session(bool writeData=true)
614        {
615                try
616                {
617
618                mutex_t::scoped_lock l(mutex_);
619                assert(in_session());
620
621                HAL_DEV_MSG(wformat(L"remove_from_session() writeData=%1%") % writeData);
622               
623                if (writeData)
624                {
625                        HAL_DEV_MSG(L"getting resume data");
626                        resumedata_ = handle_.write_resume_data(); // Update the fast-resume data
627                        HAL_DEV_MSG(L"writing resume data");
628                        write_resume_data();
629
630                        torrent_standalone tsa(shared_from_this());
631                        tsa.save_standalone(workingDir_/L"torrents"/(name_+L".xml"));
632                }
633               
634                HAL_DEV_MSG(L"removing handle from session");
635                the_session_->remove_torrent(handle_);
636                in_session_ = false;
637
638                assert(!in_session()); 
639                HAL_DEV_MSG(L"Removed from session!");
640
641                }
642                catch(std::exception& e)
643                {
644                        hal::event().post(boost::shared_ptr<hal::EventDetail>(
645                                new hal::EventStdException(Event::critical, e, L"removeFromSession"))); 
646                }
647        }
648       
649        bool in_session() const
650        { 
651                mutex_t::scoped_lock l(mutex_);
652
653                return (in_session_ && the_session_ != 0 && handle_.is_valid());
654        }
655       
656        void resume()
657        {
658                mutex_t::scoped_lock l(mutex_);
659
660                if (state_ == TorrentDetail::torrent_stopped)
661                {       
662                        add_to_session(false);
663                        assert(in_session());                   
664                }
665                else
666                {
667                        assert(in_session());
668                        handle_.resume();
669                }       
670               
671                state_ = TorrentDetail::torrent_active;                 
672                assert(!handle_.is_paused());
673        }
674       
675        void pause()
676        {
677                mutex_t::scoped_lock l(mutex_);
678
679                if (state_ == TorrentDetail::torrent_stopped)
680                {       
681                        add_to_session(true);
682
683                        assert(in_session());
684                //      assert(handle_.is_paused());
685                }
686                else
687                {
688                        assert(in_session());
689
690                        handle_.pause();
691                        signals().torrent_paused.disconnect_all_once();
692                        signals().torrent_paused.connect_once(bind(&torrent_internal::completed_pause, this));
693
694                        state_ = TorrentDetail::torrent_pausing;       
695                }                       
696        }
697       
698        void stop()
699        {
700                mutex_t::scoped_lock l(mutex_);
701
702                if (state_ != TorrentDetail::torrent_stopped)
703                {
704                        if (state_ == TorrentDetail::torrent_active)
705                        {
706                                assert(in_session());
707
708                                signals().torrent_paused.disconnect_all_once();
709                                signals().torrent_paused.connect_once(bind(&torrent_internal::completed_stop, this));
710                                handle_.pause();
711
712                                state_ = TorrentDetail::torrent_stopping;
713                        }
714                        else if (state_ == TorrentDetail::torrent_paused)
715                        {                       
716                                remove_from_session();
717                                state_ = TorrentDetail::torrent_stopped;                               
718                        }
719                }
720        }
721
722        void set_state_stopped()
723        {
724                state_ = TorrentDetail::torrent_stopped;
725        }
726
727        void force_recheck()
728        {
729                mutex_t::scoped_lock l(mutex_);         
730                HAL_DEV_MSG(L"force_recheck()");
731
732                switch (state_)
733                {
734                case TorrentDetail::torrent_stopped:
735                        clear_resume_data();
736                        resume();
737                        break;
738
739                case TorrentDetail::torrent_stopping:
740                case TorrentDetail::torrent_pausing:
741                        signals().torrent_paused.disconnect_all_once();
742
743                case TorrentDetail::torrent_active:
744                        signals().torrent_paused.disconnect_all_once();
745                        signals().torrent_paused.connect_once(bind(&torrent_internal::handle_recheck, this));
746                        handle_.pause();
747                        state_ = TorrentDetail::torrent_pausing;
748                        break;
749
750                default:
751                        assert(false);
752                };
753        }
754       
755        void write_resume_data()
756        {                                       
757                HAL_DEV_MSG(L"write_resume_data()");
758                wpath resumeDir = workingDir_/L"resume";
759               
760                if (!exists(resumeDir))
761                        create_directory(resumeDir);
762                               
763                bool halencode_result = halencode(resumeDir/filename_, resumedata_);
764                assert(halencode_result);
765                HAL_DEV_MSG(L"Written!");
766        }
767       
768        void clear_resume_data()
769        {
770                wpath resumeFile = workingDir_/L"resume"/filename_;
771               
772                if (exists(resumeFile))
773                        remove(resumeFile);
774
775                resumedata_ = libt::entry();
776        }
777
778        const wpath get_save_directory()
779        {
780                return save_directory_;
781        }
782
783        void set_save_directory(wpath s, bool force=false)
784        {
785                if (in_session() && !is_finished() &&
786                                s != path_from_utf8(handle_.save_path()))
787                {
788                        handle_.move_storage(path_to_utf8(s));
789                        save_directory_ = s;
790                }
791                else if (!in_session() && force)
792                {
793                        save_directory_ = s;
794                }
795        }
796
797        const wpath get_move_to_directory()
798        {
799                return move_to_directory_;
800        }
801       
802        void set_move_to_directory(wpath m)
803        {
804                if (is_finished() && !m.empty())
805                {
806                        if (m != path_from_utf8(handle_.save_path()))
807                        {
808                                handle_.move_storage(path_to_utf8(m));
809                                save_directory_ = move_to_directory_ = m;
810                        }
811                }
812                else
813                {
814                        move_to_directory_ = m;
815                }
816        }
817
818        bool is_finished()
819        {
820                if (in_session())
821                {
822                        libt::torrent_status::state_t s = handle_.status().state;
823
824                        return (s == libt::torrent_status::seeding ||
825                                                s == libt::torrent_status::finished);
826                }
827                else return false;
828        }
829       
830        void finished()
831        {
832                if (finishTime_.is_special())
833                        finishTime_ = boost::posix_time::second_clock::universal_time();
834
835                if (is_finished())
836                {
837                        if (!move_to_directory_.empty() && 
838                                        move_to_directory_ !=  path_from_utf8(handle_.save_path()))
839                        {
840                                handle_.move_storage(path_to_utf8(move_to_directory_));
841                                save_directory_ = move_to_directory_;
842                        }
843                }
844        }
845       
846        bool is_active() const { return state_ == TorrentDetail::torrent_active; }
847       
848        unsigned state() const { return state_; }
849       
850        void setTrackerLogin(wstring username, wstring password)
851        {
852                trackerUsername_ = username;
853                trackerPassword_ = password;
854               
855                applyTrackerLogin();
856        }       
857       
858        std::pair<wstring, wstring> getTrackerLogin() const
859        {
860                return make_pair(trackerUsername_, trackerPassword_);
861        }
862       
863        const wstring& filename() const { return filename_; }
864       
865        const wstring& originalFilename() const { return originalFilename_; }
866       
867        const libt::torrent_handle& handle() const { return handle_; }
868
869        void resetTrackers()
870        {
871                if (in_session())
872                {
873                        handle_.replace_trackers(torrent_trackers_);           
874                        trackers_.clear();
875                }
876        }
877       
878        void setTrackers(const std::vector<tracker_detail>& tracker_details)
879        {
880                trackers_.clear();
881                trackers_.assign(tracker_details.begin(), tracker_details.end());
882               
883                applyTrackers();
884        }
885       
886        const std::vector<tracker_detail>& getTrackers()
887        {
888                if (trackers_.empty())
889                {
890                        std::vector<libt::announce_entry> trackers = infoMemory_.trackers();
891                       
892                        foreach (const libt::announce_entry& entry, trackers)
893                        {
894                                trackers_.push_back(
895                                        tracker_detail(hal::from_utf8(entry.url), entry.tier));
896                        }
897                }               
898                return trackers_;
899        }
900       
901        void setFilePriorities(std::vector<int> fileIndices, int priority)
902        {
903                if (!filePriorities_.empty())
904                {
905                        foreach(int i, fileIndices)
906                                filePriorities_[i] = priority;
907                               
908                        applyFilePriorities();
909                }
910        }
911
912        const wpath& saveDirectory() { return save_directory_; }
913       
914    friend class boost::serialization::access;
915    template<class Archive>
916    void serialize(Archive& ar, const unsigned int version)
917    {
918                using boost::serialization::make_nvp;
919
920                if (version > 1) {
921                        ar & make_nvp("transfer_limits", transferLimit_);
922                        ar & make_nvp("connection_limits", connections_);
923                        ar & make_nvp("upload_limits", uploads_);       
924
925                        ar & make_nvp("name", name_);
926                        ar & make_nvp("filename", filename_);   
927
928                        ar & make_nvp("ratio", ratio_); 
929                        ar & make_nvp("progress", progress_);
930                        ar & make_nvp("state", state_);
931                        ar & make_nvp("compact_storage", compactStorage_);     
932                        ar & make_nvp("resolve_countries", resolve_countries_); 
933
934                        ar & make_nvp("tracker_username", trackerUsername_);
935                        ar & make_nvp("tracker_password", trackerPassword_);
936                        ar & make_nvp("trackers", trackers_);
937
938                        ar & make_nvp("save_directory", save_directory_);
939                        ar & make_nvp("move_to_directory", move_to_directory_);
940                       
941                        ar & make_nvp("payload_uploaded", payloadUploaded_);
942                        ar & make_nvp("payload_downloaded", payloadDownloaded_);
943                        ar & make_nvp("uploaded", uploaded_);
944                        ar & make_nvp("downloaded", downloaded_);                       
945                                       
946                        ar & make_nvp("file_priorities", filePriorities_);
947                       
948                        ar & make_nvp("start_time", startTime_);
949                        ar & make_nvp("finish_time", finishTime_);
950                        ar & make_nvp("active_duration", activeDuration_);
951                        ar & make_nvp("seeding_duration", seedingDuration_);
952                                       
953                } 
954                else 
955                {
956                    ar & make_nvp("transferLimit", transferLimit_);
957                        ar & make_nvp("connections", connections_);
958                        ar & make_nvp("uploads", uploads_);                     
959                        ar & make_nvp("filename", filename_);   
960
961                        wstring s;
962                        ar & make_nvp("saveDirectory", s);
963                        save_directory_ = s;
964
965                        if (version == 2) {
966                                wstring m;
967                                ar & make_nvp("moveToDirectory", m);
968                                move_to_directory_ = m;
969                        } else {
970                                move_to_directory_ = save_directory_;
971                        }
972                       
973                        ar & make_nvp("payloadUploaded_", payloadUploaded_);
974                        ar & make_nvp("payloadDownloaded_", payloadDownloaded_);
975                        ar & make_nvp("uploaded_", uploaded_);
976                        ar & make_nvp("downloaded_", downloaded_);     
977                        ar & make_nvp("ratio", ratio_); 
978                        ar & make_nvp("trackerUsername", trackerUsername_);
979                        ar & make_nvp("trackerPassword", trackerPassword_);
980                       
981                        ar & make_nvp("state", state_);
982                        ar & make_nvp("trackers", trackers_);
983                       
984                        ar & make_nvp("resolve_countries", resolve_countries_);
985                       
986                        ar & make_nvp("file_priorities", filePriorities_);
987                       
988                        ar & make_nvp("startTime", startTime_);
989                        ar & make_nvp("activeDuration", activeDuration_);
990                        ar & make_nvp("seedingDuration", seedingDuration_);
991                       
992                        ar & make_nvp("name", name_);
993                        ar & make_nvp("compactStorage", compactStorage_);
994                        ar & make_nvp("finishTime", finishTime_);
995                       
996                        ar & make_nvp("progress", progress_);
997        }
998    }
999
1000        void setEntryData(libtorrent::entry metadata, libtorrent::entry resumedata)
1001        {               
1002                metadata_ = metadata;
1003                resumedata_ = resumedata;
1004        }
1005
1006        std::vector<libt::peer_info>& peers() { return peers_; }
1007       
1008        boost::tuple<size_t, size_t, size_t, size_t> updatePeers()
1009        {
1010                if (in_session())
1011                        handle_.get_peer_info(peers_);
1012               
1013                size_t totalPeers = 0;
1014                size_t peersConnected = 0;
1015                size_t totalSeeds = 0;
1016                size_t seedsConnected = 0;
1017               
1018                foreach (libt::peer_info& peer, peers_) 
1019                {
1020                        float speedSum = peer.down_speed + peer.up_speed;
1021                       
1022                        if (!(peer.flags & libt::peer_info::seed))
1023                        {
1024                                ++totalPeers;
1025                               
1026                                if (speedSum > 0)
1027                                        ++peersConnected;
1028                        }
1029                        else
1030                        {
1031                                ++totalSeeds;
1032                               
1033                                if (speedSum > 0)
1034                                        ++seedsConnected;
1035                        }
1036                }       
1037               
1038                return boost::make_tuple(totalPeers, peersConnected, totalSeeds, seedsConnected);
1039        }
1040       
1041        void getPeerDetails(PeerDetails& peerDetails) const
1042        {
1043                if (in_session())
1044                {
1045                        foreach (libt::peer_info peer, peers_) 
1046                        {
1047                                peerDetails.push_back(peer);
1048                        }       
1049                }
1050        }
1051
1052        void getFileDetails(FileDetails& fileDetails)
1053        {
1054                if (fileDetailsMemory_.empty())
1055                {
1056                        libt::torrent_info& info = infoMemory();
1057                        std::vector<libt::file_entry> files;
1058                       
1059                        std::copy(info.begin_files(), info.end_files(), 
1060                                std::back_inserter(files));                                     
1061                               
1062                        if (filePriorities_.size() != files.size())
1063                        {
1064                                filePriorities_.clear();
1065                                filePriorities_.assign(files.size(), 1);
1066                        }
1067                       
1068                        for(size_t i=0, e=files.size(); i<e; ++i)
1069                        {
1070                                wstring fullPath = hal::from_utf8(files[i].path.string());
1071                                boost::int64_t size = static_cast<boost::int64_t>(files[i].size);
1072                               
1073                                fileDetailsMemory_.push_back(FileDetail(fullPath, size, 0, filePriorities_[i], i));
1074                        }       
1075                }               
1076               
1077                if (in_session())
1078                {                       
1079                        std::vector<float> fileProgress;                       
1080                        handle_.file_progress(fileProgress);
1081                       
1082                        for(size_t i=0, e=fileDetailsMemory_.size(); i<e; ++i)
1083                                fileDetailsMemory_[i].progress =  fileProgress[i];                     
1084                }
1085
1086                for(size_t i=0, e=fileDetailsMemory_.size(); i<e; ++i)
1087                        fileDetailsMemory_[i].priority =  filePriorities_[i];
1088               
1089                fileDetails = fileDetailsMemory_;
1090        }
1091       
1092        void prepare(wpath filename)
1093        {
1094                mutex_t::scoped_lock l(mutex_);
1095               
1096                if (fs::exists(filename)) 
1097                        metadata_ = haldecode(filename);
1098               
1099                extractNames(metadata_);                       
1100               
1101                const wpath resumeFile = workingDir_/L"resume"/filename_;
1102                const wpath torrentFile = workingDir_/L"torrents"/filename_;
1103               
1104                event().post(shared_ptr<EventDetail>(new EventMsg(
1105                        wformat(L"File: %1%, %2%.") % resumeFile % torrentFile)));
1106               
1107                if (exists(resumeFile)) 
1108                        resumedata_ = haldecode(resumeFile);
1109
1110                if (!exists(workingDir_/L"torrents"))
1111                        create_directory(workingDir_/L"torrents");
1112
1113                if (!exists(torrentFile))
1114                        copy_file(filename.string(), torrentFile);
1115
1116                if (!fs::exists(save_directory_))
1117                        fs::create_directory(save_directory_);
1118
1119                if (state_ == TorrentDetail::torrent_stopping)
1120                        state_ = TorrentDetail::torrent_stopped;
1121                else if (state_ == TorrentDetail::torrent_pausing)
1122                        state_ = TorrentDetail::torrent_paused;
1123        }
1124       
1125        void extractNames(libt::entry& metadata)
1126        {
1127                mutex_t::scoped_lock l(mutex_);
1128               
1129                libt::torrent_info info(metadata);                             
1130                name_ = hal::from_utf8_safe(info.name());
1131               
1132                filename_ = name_;
1133                if (!boost::find_last(filename_, L".torrent")) 
1134                                filename_ += L".torrent";
1135               
1136                event().post(shared_ptr<EventDetail>(new EventMsg(
1137                        wformat(L"Loaded names: %1%, %2%") % name_ % filename_)));
1138        }
1139       
1140        libt::torrent_info& infoMemory()
1141        {
1142                if (!infoMemory_.is_valid()) infoMemory_ = libt::torrent_info(metadata_);
1143               
1144                return infoMemory_;
1145        }
1146       
1147        signalers& signals()
1148        {
1149                mutex_t::scoped_lock l(mutex_);
1150                return signals_;
1151        }
1152
1153private:       
1154        signalers signals_;
1155
1156        void applySettings()
1157        {               
1158                applyTransferSpeed();
1159                applyConnectionLimit();
1160                apply_ratio();
1161                applyTrackers();
1162                applyTrackerLogin();
1163                applyFilePriorities();
1164                applyResolveCountries();
1165        }
1166       
1167        void applyTransferSpeed()
1168        {
1169                mutex_t::scoped_lock l(mutex_);
1170                if (in_session())
1171                {
1172                        int down = (transferLimit_.first > 0) ? static_cast<int>(transferLimit_.first*1024) : -1;
1173                        handle_.set_download_limit(down);
1174                       
1175                        int up = (transferLimit_.second > 0) ? static_cast<int>(transferLimit_.second*1024) : -1;
1176                        handle_.set_upload_limit(up);
1177
1178                        HAL_DEV_MSG(wformat(L"Applying Transfer Speed %1% - %2%") % down % up);
1179                }
1180        }
1181
1182        void applyConnectionLimit()
1183        {
1184                mutex_t::scoped_lock l(mutex_);
1185                if (in_session())
1186                {
1187                        handle_.set_max_connections(connections_);
1188                        handle_.set_max_uploads(uploads_);
1189
1190                        HAL_DEV_MSG(wformat(L"Applying Connection Limit %1% - %2%") % connections_ % uploads_);
1191                }
1192        }
1193       
1194        void apply_ratio()
1195        { 
1196                mutex_t::scoped_lock l(mutex_);
1197                if (in_session())
1198                {
1199                        handle_.set_ratio(ratio_);
1200
1201                        HAL_DEV_MSG(wformat(L"Applying Ratio %1%") % ratio_);
1202                }
1203        }
1204       
1205        void applyTrackers()
1206        {
1207                mutex_t::scoped_lock l(mutex_);
1208                if (in_session())
1209                {
1210                        if (torrent_trackers_.empty())
1211                                torrent_trackers_ = handle_.trackers();
1212                       
1213                        if (!trackers_.empty())
1214                        {
1215                                std::vector<libt::announce_entry> trackers;
1216                               
1217                                foreach (const tracker_detail& tracker, trackers_)
1218                                {
1219                                        trackers.push_back(
1220                                                libt::announce_entry(hal::to_utf8(tracker.url)));
1221                                        trackers.back().tier = tracker.tier;
1222                                }
1223                                handle_.replace_trackers(trackers);
1224                        }
1225                       
1226                        HAL_DEV_MSG(L"Applying Trackers");
1227                }
1228        }
1229       
1230        void applyTrackerLogin()
1231        {
1232                mutex_t::scoped_lock l(mutex_);
1233                if (in_session())
1234                {
1235                        if (trackerUsername_ != L"")
1236                        {
1237                                handle_.set_tracker_login(hal::to_utf8(trackerUsername_),
1238                                        hal::to_utf8(trackerPassword_));
1239                        }
1240
1241                        HAL_DEV_MSG(wformat(L"Applying Tracker Login User: %1%, Pass: %2%") % trackerUsername_ % trackerPassword_ );
1242                }
1243        }
1244       
1245        void applyFilePriorities()
1246        {               
1247                mutex_t::scoped_lock l(mutex_);
1248                if (in_session()) 
1249                {
1250                        if (!filePriorities_.empty())
1251                                handle_.prioritize_files(filePriorities_);
1252                       
1253                        HAL_DEV_MSG(L"Applying File Priorities");
1254                }
1255        }       
1256       
1257        void applyResolveCountries()
1258        {
1259                mutex_t::scoped_lock l(mutex_);
1260                if (in_session())
1261                {
1262                        handle_.resolve_countries(resolve_countries_);
1263                       
1264                        HAL_DEV_MSG(wformat(L"Applying Resolve Countries %1%") % resolve_countries_);
1265                }
1266        }
1267       
1268        void completed_pause()
1269        {
1270                mutex_t::scoped_lock l(mutex_);
1271                assert(in_session());
1272                assert(handle_.is_paused());   
1273                               
1274                state_ = TorrentDetail::torrent_paused; 
1275
1276                HAL_DEV_MSG(L"completed_pause()");
1277        }
1278
1279        void completed_stop()
1280        {
1281                mutex_t::scoped_lock l(mutex_);
1282                assert(in_session());
1283                assert(handle_.is_paused());   
1284               
1285                state_ = TorrentDetail::torrent_stopped;
1286               
1287                remove_from_session();
1288                assert(!in_session());
1289
1290                HAL_DEV_MSG(L"completed_stop()");
1291        }
1292
1293        void handle_recheck()
1294        {
1295                mutex_t::scoped_lock l(mutex_);
1296                state_ = TorrentDetail::torrent_stopped;
1297
1298                remove_from_session(false);
1299                assert(!in_session());
1300
1301                clear_resume_data();
1302
1303                resume();
1304                assert(in_session());
1305
1306                HAL_DEV_MSG(L"handle_recheck()");
1307        }
1308               
1309        static libt::session* the_session_;
1310        static wpath workingDir_;
1311       
1312        mutable mutex_t mutex_;
1313       
1314        std::pair<float, float> transferLimit_;
1315       
1316        unsigned state_;
1317        int connections_;
1318        int uploads_;
1319        bool in_session_;
1320        float ratio_;
1321        bool resolve_countries_;
1322       
1323        wstring filename_;
1324        wstring name_;
1325        wpath save_directory_;
1326        wpath move_to_directory_;
1327        wstring originalFilename_;
1328        libt::torrent_handle handle_;   
1329       
1330        libt::entry metadata_;
1331        libt::entry resumedata_;
1332       
1333        wstring trackerUsername_;       
1334        wstring trackerPassword_;
1335       
1336        boost::int64_t totalUploaded_;
1337        boost::int64_t totalBase_;
1338       
1339        transfer_tracker<boost::int64_t> payloadUploaded_;
1340        transfer_tracker<boost::int64_t> payloadDownloaded_;
1341        transfer_tracker<boost::int64_t> uploaded_;
1342        transfer_tracker<boost::int64_t> downloaded_;
1343       
1344        pt::ptime startTime_;
1345        pt::ptime finishTime_;
1346        duration_tracker activeDuration_;
1347        duration_tracker seedingDuration_;
1348       
1349        std::vector<tracker_detail> trackers_;
1350        std::vector<libt::announce_entry> torrent_trackers_;
1351        std::vector<libt::peer_info> peers_;   
1352        std::vector<int> filePriorities_;
1353       
1354        float progress_;
1355       
1356        libt::torrent_info infoMemory_;
1357        libt::torrent_status statusMemory_;
1358        FileDetails fileDetailsMemory_;
1359       
1360        bool compactStorage_;
1361};
1362
1363typedef std::map<std::string, TorrentInternalOld> TorrentMap;
1364typedef std::pair<std::string, TorrentInternalOld> TorrentPair;
1365
1366class TorrentManager : 
1367        public hal::IniBase<TorrentManager>
1368{
1369        typedef TorrentManager thisClass;
1370        typedef hal::IniBase<thisClass> iniClass;
1371
1372        struct TorrentHolder
1373        {
1374                mutable torrent_internal_ptr torrent;
1375               
1376                wstring filename;
1377                wstring name;           
1378               
1379                TorrentHolder()
1380                {}
1381               
1382                explicit TorrentHolder(torrent_internal_ptr t) :
1383                        torrent(t), filename(torrent->filename()), name(torrent->name())
1384                {}
1385                                               
1386                friend class boost::serialization::access;
1387                template<class Archive>
1388                void serialize(Archive& ar, const unsigned int version)
1389                {
1390                        using boost::serialization::make_nvp;
1391
1392                        if (version < 1)
1393                        {
1394                                TorrentInternalOld t;
1395                                ar & make_nvp("torrent", t);
1396                               
1397                                torrent.reset(new torrent_internal(t));
1398                        }
1399                        else
1400                        {
1401                                ar & make_nvp("torrent", torrent);
1402                        } 
1403                       
1404                        ar & make_nvp("filename", filename);
1405                        ar & make_nvp("name", name);
1406                }
1407        };
1408       
1409        struct byFilename{};
1410        struct byName{};
1411       
1412        typedef boost::multi_index_container<
1413                TorrentHolder,
1414                boost::multi_index::indexed_by<
1415                        boost::multi_index::ordered_unique<
1416                                boost::multi_index::tag<byFilename>,
1417                                boost::multi_index::member<
1418                                        TorrentHolder, wstring, &TorrentHolder::filename> 
1419                                >,
1420                        boost::multi_index::ordered_unique<
1421                                boost::multi_index::tag<byName>,
1422                                boost::multi_index::member<
1423                                        TorrentHolder, wstring, &TorrentHolder::name> 
1424                                >
1425                >
1426        > TorrentMultiIndex;
1427       
1428public:
1429        typedef TorrentMultiIndex::index<byFilename>::type torrentByFilename;
1430        typedef TorrentMultiIndex::index<byName>::type torrentByName;
1431       
1432        TorrentManager(ini_file& ini) :
1433                iniClass("bittorrent", "TorrentManager", ini)
1434        {}
1435       
1436        TorrentManager& operator=(const TorrentMap& map)
1437        {
1438                torrents_.clear();
1439               
1440                for (TorrentMap::const_iterator i=map.begin(), e=map.end(); i != e; ++i)
1441                {       
1442                        torrent_internal_ptr TIp(new torrent_internal((*i).second));
1443                       
1444                        event().post(shared_ptr<EventDetail>(new EventMsg(
1445                                wformat(L"Converting %1%.") % TIp->name())));
1446                       
1447                        torrents_.insert(TorrentHolder(TIp));
1448                }
1449               
1450                return *this;
1451        }
1452       
1453        std::pair<torrentByName::iterator, bool> insert(const TorrentHolder& h)
1454        {
1455                return torrents_.get<byName>().insert(h);
1456        }
1457       
1458        std::pair<torrentByName::iterator, bool> insert(torrent_internal_ptr t)
1459        {
1460                return insert(TorrentHolder(t));
1461        }
1462
1463        torrent_internal_ptr getByFile(const wstring& filename)
1464        {
1465                torrentByFilename::iterator it = torrents_.get<byFilename>().find(filename);
1466               
1467                if (it != torrents_.get<byFilename>().end() && (*it).torrent)
1468                {
1469                        return (*it).torrent;
1470                }
1471               
1472                throw invalidTorrent(filename);
1473        }
1474       
1475        torrent_internal_ptr get(const wstring& name)
1476        {
1477                torrentByName::iterator it = torrents_.get<byName>().find(name);
1478               
1479                if (it != torrents_.get<byName>().end() && (*it).torrent)
1480                {
1481                        return (*it).torrent;
1482                }
1483               
1484                throw invalidTorrent(name);
1485        }
1486       
1487        torrentByName::iterator erase(torrentByName::iterator where)
1488        {
1489                return torrents_.get<byName>().erase(where);
1490        }
1491       
1492        size_t size()
1493        {
1494                return torrents_.size();
1495        }
1496       
1497        size_t erase(const wstring& name)
1498        {
1499                return torrents_.get<byName>().erase(name);
1500        }
1501       
1502        bool exists(const wstring& name)
1503        {
1504                torrentByName::iterator it = torrents_.get<byName>().find(name);
1505               
1506                if (it != torrents_.get<byName>().end())
1507                        return true;
1508                else
1509                        return false;
1510        }
1511       
1512        torrentByName::iterator begin() { return torrents_.get<byName>().begin(); }
1513        torrentByName::iterator end() { return torrents_.get<byName>().end(); }
1514       
1515        friend class boost::serialization::access;
1516        template<class Archive>
1517        void serialize(Archive& ar, const unsigned int version)
1518        {
1519                ar & boost::serialization::make_nvp("torrents", torrents_);
1520        }       
1521       
1522private:
1523        TorrentMultiIndex torrents_;
1524};
1525
1526void torrent_internal::setConnectionLimit(int maxConn, int maxUpload)
1527{
1528        mutex_t::scoped_lock l(mutex_);
1529
1530        connections_ = maxConn;
1531        uploads_ = maxUpload;
1532       
1533        applyConnectionLimit();
1534}
1535
1536std::pair<int, int> torrent_internal::getConnectionLimit()
1537{
1538        return std::make_pair(connections_, uploads_);
1539}
1540
1541void torrent_internal::setTransferSpeed(float download, float upload)
1542{       
1543        mutex_t::scoped_lock l(mutex_);
1544
1545        transferLimit_ = std::make_pair(download, upload);
1546       
1547        applyTransferSpeed();
1548}
1549
1550std::pair<float, float> torrent_internal::getTransferSpeed()
1551{
1552        return transferLimit_;
1553}
1554
1555TorrentDetail_ptr torrent_internal::getTorrentDetail_ptr()
1556{       
1557        mutex_t::scoped_lock l(mutex_);
1558
1559        try
1560        {
1561
1562        if (in_session())
1563        {
1564                statusMemory_ = handle_.status();
1565                progress_ = statusMemory_.progress;
1566        }
1567        else
1568        {
1569                // Wipe these cause they don't make sense for a non-active torrent.
1570               
1571                statusMemory_.download_payload_rate = 0;
1572                statusMemory_.upload_payload_rate = 0;
1573                statusMemory_.next_announce = boost::posix_time::seconds(0);           
1574        }
1575       
1576        wstring state;
1577       
1578        switch (state_)
1579        {
1580        case TorrentDetail::torrent_paused:
1581                state = app().res_wstr(HAL_TORRENT_PAUSED);
1582                break;
1583               
1584        case TorrentDetail::torrent_pausing:
1585                state = app().res_wstr(HAL_TORRENT_PAUSING);
1586                break;
1587               
1588        case TorrentDetail::torrent_stopped:
1589                state = app().res_wstr(HAL_TORRENT_STOPPED);
1590                break;
1591               
1592        case TorrentDetail::torrent_stopping:
1593                state = app().res_wstr(HAL_TORRENT_STOPPING);
1594                break;
1595               
1596        default:
1597                switch (statusMemory_.state)
1598                {
1599                case libt::torrent_status::queued_for_checking:
1600                        state = app().res_wstr(HAL_TORRENT_QUEUED_CHECKING);
1601                        break;
1602                case libt::torrent_status::checking_files:
1603                        state = app().res_wstr(HAL_TORRENT_CHECKING_FILES);
1604                        break;
1605                case libt::torrent_status::connecting_to_tracker:
1606                        state = app().res_wstr(HAL_TORRENT_CONNECTING);
1607                        break;
1608                case libt::torrent_status::downloading_metadata:
1609                        state = app().res_wstr(HAL_TORRENT_METADATA);
1610                        break;
1611                case libt::torrent_status::downloading:
1612                        state = app().res_wstr(HAL_TORRENT_DOWNLOADING);
1613                        break;
1614                case libt::torrent_status::finished:
1615                        state = app().res_wstr(HAL_TORRENT_FINISHED);
1616                        break;
1617                case libt::torrent_status::seeding:
1618                        state = app().res_wstr(HAL_TORRENT_SEEDING);
1619                        break;
1620                case libt::torrent_status::allocating:
1621                        state = app().res_wstr(HAL_TORRENT_ALLOCATING);
1622                        break;
1623                }       
1624        }
1625       
1626        pt::time_duration td(pt::pos_infin);
1627       
1628        if (statusMemory_.download_payload_rate != 0)
1629        {
1630                td = boost::posix_time::seconds(       
1631                        long(float(statusMemory_.total_wanted-statusMemory_.total_wanted_done) / statusMemory_.download_payload_rate));
1632        }
1633       
1634        totalUploaded_ += (statusMemory_.total_payload_upload - totalBase_);
1635        totalBase_ = statusMemory_.total_payload_upload;
1636       
1637        uploaded_.update(statusMemory_.total_upload);
1638        payloadUploaded_.update(statusMemory_.total_payload_upload);
1639        downloaded_.update(statusMemory_.total_download);
1640        payloadDownloaded_.update(statusMemory_.total_payload_download);
1641       
1642        if (is_active())
1643        {
1644                activeDuration_.update();
1645               
1646                if (libt::torrent_status::seeding == statusMemory_.state)
1647                        seedingDuration_.update();
1648        }       
1649       
1650        boost::tuple<size_t, size_t, size_t, size_t> connections = updatePeers();       
1651
1652        wstring wanted = lexical_cast<wstring>(statusMemory_.total_wanted);
1653        HAL_DEV_MSG(wformat(L"**** wanted: %1%") % wanted);     
1654
1655        return TorrentDetail_ptr(new TorrentDetail(name_, filename_, saveDirectory().string(), state, hal::from_utf8(statusMemory_.current_tracker), 
1656                std::pair<float, float>(statusMemory_.download_payload_rate, statusMemory_.upload_payload_rate),
1657                progress_, statusMemory_.distributed_copies, statusMemory_.total_wanted_done, statusMemory_.total_wanted, uploaded_, payloadUploaded_,
1658                downloaded_, payloadDownloaded_, connections, ratio_, td, statusMemory_.next_announce, activeDuration_, seedingDuration_, startTime_, finishTime_));
1659
1660        }
1661        catch (const libt::invalid_handle&)
1662        {
1663                event().post(shared_ptr<EventDetail>(
1664                        new EventInvalidTorrent(Event::critical, Event::invalidTorrent, to_utf8(name_), "getTorrentDetail_ptr")));
1665        }
1666        catch (const std::exception& e)
1667        {
1668                event().post(shared_ptr<EventDetail>(
1669                        new EventTorrentException(Event::critical, Event::torrentException, e.what(), to_utf8(name_), "getTorrentDetail_ptr")));
1670        }
1671       
1672        return TorrentDetail_ptr(new TorrentDetail(name_, filename_, saveDirectory().string(), app().res_wstr(HAL_TORRENT_STOPPED), app().res_wstr(HAL_NA)));
1673}
1674
1675} // namespace hal
1676
1677BOOST_CLASS_VERSION(hal::TorrentManager::TorrentHolder, 1)
1678
1679#endif // RC_INVOKED
1680
Note: See TracBrowser for help on using the repository browser.