source: branch_0_3_1/src/halTorrentInternal.hpp @ 530

Revision 530, 42.6 KB checked in by Eoin, 11 years ago (diff)
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, 1, 485
10#define HALITE_VERSION_STRING                   "v 0.3.1"
11#define HALITE_FINGERPRINT                              "HL", 0, 3, 1, 0
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_log.post(shared_ptr<EventDetail>(new EventMsg(
148                        wform(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_log.post(shared_ptr<EventDetail>(new EventMsg(
352                        wform(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_log.post(boost::shared_ptr<hal::EventDetail>(
379                                new hal::EventStdException(event_logger::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(wform(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_log.post(boost::shared_ptr<hal::EventDetail>(
609                                new hal::EventStdException(event_logger::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(wform(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_log.post(boost::shared_ptr<hal::EventDetail>(
645                                new hal::EventStdException(event_logger::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 
828                        return false;
829        }
830
831        bool is_seeding()
832        {
833                if (in_session())
834                {
835                        libt::torrent_status::state_t s = handle_.status().state;
836
837                        return (s == libt::torrent_status::seeding);
838                }
839                else 
840                        return false;
841        }
842       
843        void finished()
844        {
845                if (finishTime_.is_special())
846                        finishTime_ = boost::posix_time::second_clock::universal_time();
847
848                if (is_seeding())
849                {
850                        if (!move_to_directory_.empty() && 
851                                        move_to_directory_ !=  path_from_utf8(handle_.save_path()))
852                        {
853                                handle_.move_storage(path_to_utf8(move_to_directory_));
854                                save_directory_ = move_to_directory_;
855                        }
856                }
857        }
858       
859        bool is_active() const { return state_ == TorrentDetail::torrent_active; }
860       
861        unsigned state() const { return state_; }
862       
863        void setTrackerLogin(wstring username, wstring password)
864        {
865                trackerUsername_ = username;
866                trackerPassword_ = password;
867               
868                applyTrackerLogin();
869        }       
870       
871        std::pair<wstring, wstring> getTrackerLogin() const
872        {
873                return make_pair(trackerUsername_, trackerPassword_);
874        }
875       
876        const wstring& filename() const { return filename_; }
877       
878        const wstring& originalFilename() const { return originalFilename_; }
879       
880        const libt::torrent_handle& handle() const { return handle_; }
881
882        void resetTrackers()
883        {
884                if (in_session())
885                {
886                        handle_.replace_trackers(torrent_trackers_);           
887                        trackers_.clear();
888                }
889        }
890       
891        void setTrackers(const std::vector<tracker_detail>& tracker_details)
892        {
893                trackers_.clear();
894                trackers_.assign(tracker_details.begin(), tracker_details.end());
895               
896                applyTrackers();
897        }
898       
899        const std::vector<tracker_detail>& getTrackers()
900        {
901                if (trackers_.empty())
902                {
903                        std::vector<libt::announce_entry> trackers = infoMemory_.trackers();
904                       
905                        foreach (const libt::announce_entry& entry, trackers)
906                        {
907                                trackers_.push_back(
908                                        tracker_detail(hal::from_utf8(entry.url), entry.tier));
909                        }
910                }               
911                return trackers_;
912        }
913       
914        void setFilePriorities(std::vector<int> fileIndices, int priority)
915        {
916                if (!filePriorities_.empty())
917                {
918                        foreach(int i, fileIndices)
919                                filePriorities_[i] = priority;
920                               
921                        applyFilePriorities();
922                }
923        }
924
925        const wpath& saveDirectory() { return save_directory_; }
926       
927    friend class boost::serialization::access;
928    template<class Archive>
929    void serialize(Archive& ar, const unsigned int version)
930    {
931                using boost::serialization::make_nvp;
932
933                if (version > 1) {
934                        ar & make_nvp("transfer_limits", transferLimit_);
935                        ar & make_nvp("connection_limits", connections_);
936                        ar & make_nvp("upload_limits", uploads_);       
937
938                        ar & make_nvp("name", name_);
939                        ar & make_nvp("filename", filename_);   
940
941                        ar & make_nvp("ratio", ratio_); 
942                        ar & make_nvp("progress", progress_);
943                        ar & make_nvp("state", state_);
944                        ar & make_nvp("compact_storage", compactStorage_);     
945                        ar & make_nvp("resolve_countries", resolve_countries_); 
946
947                        ar & make_nvp("tracker_username", trackerUsername_);
948                        ar & make_nvp("tracker_password", trackerPassword_);
949                        ar & make_nvp("trackers", trackers_);
950
951                        ar & make_nvp("save_directory", save_directory_);
952                        ar & make_nvp("move_to_directory", move_to_directory_);
953                       
954                        ar & make_nvp("payload_uploaded", payloadUploaded_);
955                        ar & make_nvp("payload_downloaded", payloadDownloaded_);
956                        ar & make_nvp("uploaded", uploaded_);
957                        ar & make_nvp("downloaded", downloaded_);                       
958                                       
959                        ar & make_nvp("file_priorities", filePriorities_);
960                       
961                        ar & make_nvp("start_time", startTime_);
962                        ar & make_nvp("finish_time", finishTime_);
963                        ar & make_nvp("active_duration", activeDuration_);
964                        ar & make_nvp("seeding_duration", seedingDuration_);
965                                       
966                } 
967                else 
968                {
969                    ar & make_nvp("transferLimit", transferLimit_);
970                        ar & make_nvp("connections", connections_);
971                        ar & make_nvp("uploads", uploads_);                     
972                        ar & make_nvp("filename", filename_);   
973
974                        wstring s;
975                        ar & make_nvp("saveDirectory", s);
976                        save_directory_ = s;
977
978                        if (version == 2) {
979                                wstring m;
980                                ar & make_nvp("moveToDirectory", m);
981                                move_to_directory_ = m;
982                        } else {
983                                move_to_directory_ = save_directory_;
984                        }
985                       
986                        ar & make_nvp("payloadUploaded_", payloadUploaded_);
987                        ar & make_nvp("payloadDownloaded_", payloadDownloaded_);
988                        ar & make_nvp("uploaded_", uploaded_);
989                        ar & make_nvp("downloaded_", downloaded_);     
990                        ar & make_nvp("ratio", ratio_); 
991                        ar & make_nvp("trackerUsername", trackerUsername_);
992                        ar & make_nvp("trackerPassword", trackerPassword_);
993                       
994                        ar & make_nvp("state", state_);
995                        ar & make_nvp("trackers", trackers_);
996                       
997                        ar & make_nvp("resolve_countries", resolve_countries_);
998                       
999                        ar & make_nvp("file_priorities", filePriorities_);
1000                       
1001                        ar & make_nvp("startTime", startTime_);
1002                        ar & make_nvp("activeDuration", activeDuration_);
1003                        ar & make_nvp("seedingDuration", seedingDuration_);
1004                       
1005                        ar & make_nvp("name", name_);
1006                        ar & make_nvp("compactStorage", compactStorage_);
1007                        ar & make_nvp("finishTime", finishTime_);
1008                       
1009                        ar & make_nvp("progress", progress_);
1010        }
1011    }
1012
1013        void setEntryData(libtorrent::entry metadata, libtorrent::entry resumedata)
1014        {               
1015                metadata_ = metadata;
1016                resumedata_ = resumedata;
1017        }
1018
1019        std::vector<libt::peer_info>& peers() { return peers_; }
1020       
1021        boost::tuple<size_t, size_t, size_t, size_t> updatePeers()
1022        {
1023                if (in_session())
1024                        handle_.get_peer_info(peers_);
1025               
1026                size_t totalPeers = 0;
1027                size_t peersConnected = 0;
1028                size_t totalSeeds = 0;
1029                size_t seedsConnected = 0;
1030               
1031                foreach (libt::peer_info& peer, peers_) 
1032                {
1033                        float speedSum = peer.down_speed + peer.up_speed;
1034                       
1035                        if (!(peer.flags & libt::peer_info::seed))
1036                        {
1037                                ++totalPeers;
1038                               
1039                                if (speedSum > 0)
1040                                        ++peersConnected;
1041                        }
1042                        else
1043                        {
1044                                ++totalSeeds;
1045                               
1046                                if (speedSum > 0)
1047                                        ++seedsConnected;
1048                        }
1049                }       
1050               
1051                return boost::make_tuple(totalPeers, peersConnected, totalSeeds, seedsConnected);
1052        }
1053       
1054        void getPeerDetails(PeerDetails& peerDetails) const
1055        {
1056                if (in_session())
1057                {
1058                        foreach (libt::peer_info peer, peers_) 
1059                        {
1060                                peerDetails.push_back(peer);
1061                        }       
1062                }
1063        }
1064
1065        void getFileDetails(FileDetails& fileDetails)
1066        {
1067                if (fileDetailsMemory_.empty())
1068                {
1069                        libt::torrent_info& info = infoMemory();
1070                        std::vector<libt::file_entry> files;
1071                       
1072                        std::copy(info.begin_files(), info.end_files(), 
1073                                std::back_inserter(files));                                     
1074                               
1075                        if (filePriorities_.size() != files.size())
1076                        {
1077                                filePriorities_.clear();
1078                                filePriorities_.assign(files.size(), 1);
1079                        }
1080                       
1081                        for(size_t i=0, e=files.size(); i<e; ++i)
1082                        {
1083                                wstring fullPath = hal::from_utf8(files[i].path.string());
1084                                boost::int64_t size = static_cast<boost::int64_t>(files[i].size);
1085                               
1086                                fileDetailsMemory_.push_back(FileDetail(fullPath, size, 0, filePriorities_[i], i));
1087                        }       
1088                }               
1089               
1090                if (in_session())
1091                {                       
1092                        std::vector<float> fileProgress;                       
1093                        handle_.file_progress(fileProgress);
1094                       
1095                        for(size_t i=0, e=fileDetailsMemory_.size(); i<e; ++i)
1096                                fileDetailsMemory_[i].progress =  fileProgress[i];                     
1097                }
1098
1099                for(size_t i=0, e=fileDetailsMemory_.size(); i<e; ++i)
1100                        fileDetailsMemory_[i].priority =  filePriorities_[i];
1101               
1102                fileDetails = fileDetailsMemory_;
1103        }
1104       
1105        void prepare(wpath filename)
1106        {
1107                mutex_t::scoped_lock l(mutex_);
1108               
1109                if (fs::exists(filename)) 
1110                        metadata_ = haldecode(filename);
1111               
1112                extractNames(metadata_);                       
1113               
1114                const wpath resumeFile = workingDir_/L"resume"/filename_;
1115                const wpath torrentFile = workingDir_/L"torrents"/filename_;
1116               
1117                event_log.post(shared_ptr<EventDetail>(new EventMsg(
1118                        wform(L"File: %1%, %2%.") % resumeFile % torrentFile)));
1119               
1120                if (exists(resumeFile)) 
1121                        resumedata_ = haldecode(resumeFile);
1122
1123                if (!exists(workingDir_/L"torrents"))
1124                        create_directory(workingDir_/L"torrents");
1125
1126                if (!exists(torrentFile))
1127                        copy_file(filename.string(), torrentFile);
1128
1129                if (!fs::exists(save_directory_))
1130                        fs::create_directory(save_directory_);
1131
1132                if (state_ == TorrentDetail::torrent_stopping)
1133                        state_ = TorrentDetail::torrent_stopped;
1134                else if (state_ == TorrentDetail::torrent_pausing)
1135                        state_ = TorrentDetail::torrent_paused;
1136        }
1137       
1138        void extractNames(libt::entry& metadata)
1139        {
1140                mutex_t::scoped_lock l(mutex_);
1141               
1142                libt::torrent_info info(metadata);                             
1143                name_ = hal::from_utf8_safe(info.name());
1144               
1145                filename_ = name_;
1146                if (!boost::find_last(filename_, L".torrent")) 
1147                                filename_ += L".torrent";
1148               
1149                event_log.post(shared_ptr<EventDetail>(new EventMsg(
1150                        wform(L"Loaded names: %1%, %2%") % name_ % filename_)));
1151        }
1152       
1153        libt::torrent_info& infoMemory()
1154        {
1155                if (!infoMemory_.is_valid()) infoMemory_ = libt::torrent_info(metadata_);
1156               
1157                return infoMemory_;
1158        }
1159       
1160        signalers& signals()
1161        {
1162                mutex_t::scoped_lock l(mutex_);
1163                return signals_;
1164        }
1165
1166private:       
1167        signalers signals_;
1168
1169        void applySettings()
1170        {               
1171                applyTransferSpeed();
1172                applyConnectionLimit();
1173                apply_ratio();
1174                applyTrackers();
1175                applyTrackerLogin();
1176                applyFilePriorities();
1177                applyResolveCountries();
1178        }
1179       
1180        void applyTransferSpeed()
1181        {
1182                mutex_t::scoped_lock l(mutex_);
1183                if (in_session())
1184                {
1185                        int down = (transferLimit_.first > 0) ? static_cast<int>(transferLimit_.first*1024) : -1;
1186                        handle_.set_download_limit(down);
1187                       
1188                        int up = (transferLimit_.second > 0) ? static_cast<int>(transferLimit_.second*1024) : -1;
1189                        handle_.set_upload_limit(up);
1190
1191                        HAL_DEV_MSG(wform(L"Applying Transfer Speed %1% - %2%") % down % up);
1192                }
1193        }
1194
1195        void applyConnectionLimit()
1196        {
1197                mutex_t::scoped_lock l(mutex_);
1198                if (in_session())
1199                {
1200                        handle_.set_max_connections(connections_);
1201                        handle_.set_max_uploads(uploads_);
1202
1203                        HAL_DEV_MSG(wform(L"Applying Connection Limit %1% - %2%") % connections_ % uploads_);
1204                }
1205        }
1206       
1207        void apply_ratio()
1208        { 
1209                mutex_t::scoped_lock l(mutex_);
1210                if (in_session())
1211                {
1212                        handle_.set_ratio(ratio_);
1213
1214                        HAL_DEV_MSG(wform(L"Applying Ratio %1%") % ratio_);
1215                }
1216        }
1217       
1218        void applyTrackers()
1219        {
1220                mutex_t::scoped_lock l(mutex_);
1221                if (in_session())
1222                {
1223                        if (torrent_trackers_.empty())
1224                                torrent_trackers_ = handle_.trackers();
1225                       
1226                        if (!trackers_.empty())
1227                        {
1228                                std::vector<libt::announce_entry> trackers;
1229                               
1230                                foreach (const tracker_detail& tracker, trackers_)
1231                                {
1232                                        trackers.push_back(
1233                                                libt::announce_entry(hal::to_utf8(tracker.url)));
1234                                        trackers.back().tier = tracker.tier;
1235                                }
1236                                handle_.replace_trackers(trackers);
1237                        }
1238                       
1239                        HAL_DEV_MSG(L"Applying Trackers");
1240                }
1241        }
1242       
1243        void applyTrackerLogin()
1244        {
1245                mutex_t::scoped_lock l(mutex_);
1246                if (in_session())
1247                {
1248                        if (trackerUsername_ != L"")
1249                        {
1250                                handle_.set_tracker_login(hal::to_utf8(trackerUsername_),
1251                                        hal::to_utf8(trackerPassword_));
1252                        }
1253
1254                        HAL_DEV_MSG(wform(L"Applying Tracker Login User: %1%, Pass: %2%") % trackerUsername_ % trackerPassword_ );
1255                }
1256        }
1257       
1258        void applyFilePriorities()
1259        {               
1260                mutex_t::scoped_lock l(mutex_);
1261                if (in_session()) 
1262                {
1263                        if (!filePriorities_.empty())
1264                                handle_.prioritize_files(filePriorities_);
1265                       
1266                        HAL_DEV_MSG(L"Applying File Priorities");
1267                }
1268        }       
1269       
1270        void applyResolveCountries()
1271        {
1272                mutex_t::scoped_lock l(mutex_);
1273                if (in_session())
1274                {
1275                        handle_.resolve_countries(resolve_countries_);
1276                       
1277                        HAL_DEV_MSG(wform(L"Applying Resolve Countries %1%") % resolve_countries_);
1278                }
1279        }
1280       
1281        void completed_pause()
1282        {
1283                mutex_t::scoped_lock l(mutex_);
1284                assert(in_session());
1285                assert(handle_.is_paused());   
1286                               
1287                state_ = TorrentDetail::torrent_paused; 
1288
1289                HAL_DEV_MSG(L"completed_pause()");
1290        }
1291
1292        void completed_stop()
1293        {
1294                mutex_t::scoped_lock l(mutex_);
1295                assert(in_session());
1296                assert(handle_.is_paused());   
1297               
1298                state_ = TorrentDetail::torrent_stopped;
1299               
1300                remove_from_session();
1301                assert(!in_session());
1302
1303                HAL_DEV_MSG(L"completed_stop()");
1304        }
1305
1306        void handle_recheck()
1307        {
1308                mutex_t::scoped_lock l(mutex_);
1309                state_ = TorrentDetail::torrent_stopped;
1310
1311                remove_from_session(false);
1312                assert(!in_session());
1313
1314                clear_resume_data();
1315
1316                resume();
1317                assert(in_session());
1318
1319                HAL_DEV_MSG(L"handle_recheck()");
1320        }
1321               
1322        static libt::session* the_session_;
1323        static wpath workingDir_;
1324       
1325        mutable mutex_t mutex_;
1326       
1327        std::pair<float, float> transferLimit_;
1328       
1329        unsigned state_;
1330        int connections_;
1331        int uploads_;
1332        bool in_session_;
1333        float ratio_;
1334        bool resolve_countries_;
1335       
1336        wstring filename_;
1337        wstring name_;
1338        wpath save_directory_;
1339        wpath move_to_directory_;
1340        wstring originalFilename_;
1341        libt::torrent_handle handle_;   
1342       
1343        libt::entry metadata_;
1344        libt::entry resumedata_;
1345       
1346        wstring trackerUsername_;       
1347        wstring trackerPassword_;
1348       
1349        boost::int64_t totalUploaded_;
1350        boost::int64_t totalBase_;
1351       
1352        transfer_tracker<boost::int64_t> payloadUploaded_;
1353        transfer_tracker<boost::int64_t> payloadDownloaded_;
1354        transfer_tracker<boost::int64_t> uploaded_;
1355        transfer_tracker<boost::int64_t> downloaded_;
1356       
1357        pt::ptime startTime_;
1358        pt::ptime finishTime_;
1359        duration_tracker activeDuration_;
1360        duration_tracker seedingDuration_;
1361       
1362        std::vector<tracker_detail> trackers_;
1363        std::vector<libt::announce_entry> torrent_trackers_;
1364        std::vector<libt::peer_info> peers_;   
1365        std::vector<int> filePriorities_;
1366       
1367        float progress_;
1368       
1369        libt::torrent_info infoMemory_;
1370        libt::torrent_status statusMemory_;
1371        FileDetails fileDetailsMemory_;
1372       
1373        bool compactStorage_;
1374};
1375
1376typedef std::map<std::string, TorrentInternalOld> TorrentMap;
1377typedef std::pair<std::string, TorrentInternalOld> TorrentPair;
1378
1379class TorrentManager : 
1380        public hal::IniBase<TorrentManager>
1381{
1382        typedef TorrentManager thisClass;
1383        typedef hal::IniBase<thisClass> iniClass;
1384
1385        struct TorrentHolder
1386        {
1387                mutable torrent_internal_ptr torrent;
1388               
1389                wstring filename;
1390                wstring name;           
1391               
1392                TorrentHolder()
1393                {}
1394               
1395                explicit TorrentHolder(torrent_internal_ptr t) :
1396                        torrent(t), filename(torrent->filename()), name(torrent->name())
1397                {}
1398                                               
1399                friend class boost::serialization::access;
1400                template<class Archive>
1401                void serialize(Archive& ar, const unsigned int version)
1402                {
1403                        using boost::serialization::make_nvp;
1404
1405                        if (version < 1)
1406                        {
1407                                TorrentInternalOld t;
1408                                ar & make_nvp("torrent", t);
1409                               
1410                                torrent.reset(new torrent_internal(t));
1411                        }
1412                        else
1413                        {
1414                                ar & make_nvp("torrent", torrent);
1415                        } 
1416                       
1417                        ar & make_nvp("filename", filename);
1418                        ar & make_nvp("name", name);
1419                }
1420        };
1421       
1422        struct byFilename{};
1423        struct byName{};
1424       
1425        typedef boost::multi_index_container<
1426                TorrentHolder,
1427                boost::multi_index::indexed_by<
1428                        boost::multi_index::ordered_unique<
1429                                boost::multi_index::tag<byFilename>,
1430                                boost::multi_index::member<
1431                                        TorrentHolder, wstring, &TorrentHolder::filename> 
1432                                >,
1433                        boost::multi_index::ordered_unique<
1434                                boost::multi_index::tag<byName>,
1435                                boost::multi_index::member<
1436                                        TorrentHolder, wstring, &TorrentHolder::name> 
1437                                >
1438                >
1439        > TorrentMultiIndex;
1440       
1441public:
1442        typedef TorrentMultiIndex::index<byFilename>::type torrentByFilename;
1443        typedef TorrentMultiIndex::index<byName>::type torrentByName;
1444       
1445        TorrentManager(ini_file& ini) :
1446                iniClass("bittorrent", "TorrentManager", ini)
1447        {}
1448       
1449        TorrentManager& operator=(const TorrentMap& map)
1450        {
1451                torrents_.clear();
1452               
1453                for (TorrentMap::const_iterator i=map.begin(), e=map.end(); i != e; ++i)
1454                {       
1455                        torrent_internal_ptr TIp(new torrent_internal((*i).second));
1456                       
1457                        event_log.post(shared_ptr<EventDetail>(new EventMsg(
1458                                wform(L"Converting %1%.") % TIp->name())));
1459                       
1460                        torrents_.insert(TorrentHolder(TIp));
1461                }
1462               
1463                return *this;
1464        }
1465       
1466        std::pair<torrentByName::iterator, bool> insert(const TorrentHolder& h)
1467        {
1468                return torrents_.get<byName>().insert(h);
1469        }
1470       
1471        std::pair<torrentByName::iterator, bool> insert(torrent_internal_ptr t)
1472        {
1473                return insert(TorrentHolder(t));
1474        }
1475
1476        torrent_internal_ptr getByFile(const wstring& filename)
1477        {
1478                torrentByFilename::iterator it = torrents_.get<byFilename>().find(filename);
1479               
1480                if (it != torrents_.get<byFilename>().end() && (*it).torrent)
1481                {
1482                        return (*it).torrent;
1483                }
1484               
1485                throw invalidTorrent(filename);
1486        }
1487       
1488        torrent_internal_ptr get(const wstring& name)
1489        {
1490                torrentByName::iterator it = torrents_.get<byName>().find(name);
1491               
1492                if (it != torrents_.get<byName>().end() && (*it).torrent)
1493                {
1494                        return (*it).torrent;
1495                }
1496               
1497                throw invalidTorrent(name);
1498        }
1499       
1500        torrentByName::iterator erase(torrentByName::iterator where)
1501        {
1502                return torrents_.get<byName>().erase(where);
1503        }
1504       
1505        size_t size()
1506        {
1507                return torrents_.size();
1508        }
1509       
1510        size_t erase(const wstring& name)
1511        {
1512                return torrents_.get<byName>().erase(name);
1513        }
1514       
1515        bool exists(const wstring& name)
1516        {
1517                torrentByName::iterator it = torrents_.get<byName>().find(name);
1518               
1519                if (it != torrents_.get<byName>().end())
1520                        return true;
1521                else
1522                        return false;
1523        }
1524       
1525        torrentByName::iterator begin() { return torrents_.get<byName>().begin(); }
1526        torrentByName::iterator end() { return torrents_.get<byName>().end(); }
1527       
1528        friend class boost::serialization::access;
1529        template<class Archive>
1530        void serialize(Archive& ar, const unsigned int version)
1531        {
1532                ar & boost::serialization::make_nvp("torrents", torrents_);
1533        }       
1534       
1535private:
1536        TorrentMultiIndex torrents_;
1537};
1538
1539void torrent_internal::setConnectionLimit(int maxConn, int maxUpload)
1540{
1541        mutex_t::scoped_lock l(mutex_);
1542
1543        connections_ = maxConn;
1544        uploads_ = maxUpload;
1545       
1546        applyConnectionLimit();
1547}
1548
1549std::pair<int, int> torrent_internal::getConnectionLimit()
1550{
1551        return std::make_pair(connections_, uploads_);
1552}
1553
1554void torrent_internal::setTransferSpeed(float download, float upload)
1555{       
1556        mutex_t::scoped_lock l(mutex_);
1557
1558        transferLimit_ = std::make_pair(download, upload);
1559       
1560        applyTransferSpeed();
1561}
1562
1563std::pair<float, float> torrent_internal::getTransferSpeed()
1564{
1565        return transferLimit_;
1566}
1567
1568TorrentDetail_ptr torrent_internal::getTorrentDetail_ptr()
1569{       
1570        mutex_t::scoped_lock l(mutex_);
1571
1572        try
1573        {
1574
1575        if (in_session())
1576        {
1577                statusMemory_ = handle_.status();
1578                progress_ = statusMemory_.progress;
1579        }
1580        else
1581        {
1582                // Wipe these cause they don't make sense for a non-active torrent.
1583               
1584                statusMemory_.download_payload_rate = 0;
1585                statusMemory_.upload_payload_rate = 0;
1586                statusMemory_.next_announce = boost::posix_time::seconds(0);           
1587        }
1588       
1589        wstring state;
1590       
1591        switch (state_)
1592        {
1593        case TorrentDetail::torrent_paused:
1594                state = app().res_wstr(HAL_TORRENT_PAUSED);
1595                break;
1596               
1597        case TorrentDetail::torrent_pausing:
1598                state = app().res_wstr(HAL_TORRENT_PAUSING);
1599                break;
1600               
1601        case TorrentDetail::torrent_stopped:
1602                state = app().res_wstr(HAL_TORRENT_STOPPED);
1603                break;
1604               
1605        case TorrentDetail::torrent_stopping:
1606                state = app().res_wstr(HAL_TORRENT_STOPPING);
1607                break;
1608               
1609        default:
1610                switch (statusMemory_.state)
1611                {
1612                case libt::torrent_status::queued_for_checking:
1613                        state = app().res_wstr(HAL_TORRENT_QUEUED_CHECKING);
1614                        break;
1615                case libt::torrent_status::checking_files:
1616                        state = app().res_wstr(HAL_TORRENT_CHECKING_FILES);
1617                        break;
1618                case libt::torrent_status::connecting_to_tracker:
1619                        state = app().res_wstr(HAL_TORRENT_CONNECTING);
1620                        break;
1621                case libt::torrent_status::downloading_metadata:
1622                        state = app().res_wstr(HAL_TORRENT_METADATA);
1623                        break;
1624                case libt::torrent_status::downloading:
1625                        state = app().res_wstr(HAL_TORRENT_DOWNLOADING);
1626                        break;
1627                case libt::torrent_status::finished:
1628                        state = app().res_wstr(HAL_TORRENT_FINISHED);
1629                        break;
1630                case libt::torrent_status::seeding:
1631                        state = app().res_wstr(HAL_TORRENT_SEEDING);
1632                        break;
1633                case libt::torrent_status::allocating:
1634                        state = app().res_wstr(HAL_TORRENT_ALLOCATING);
1635                        break;
1636                }       
1637        }
1638       
1639        pt::time_duration td(pt::pos_infin);
1640       
1641        if (statusMemory_.download_payload_rate != 0)
1642        {
1643                td = boost::posix_time::seconds(       
1644                        long(float(statusMemory_.total_wanted-statusMemory_.total_wanted_done) / statusMemory_.download_payload_rate));
1645        }
1646       
1647        totalUploaded_ += (statusMemory_.total_payload_upload - totalBase_);
1648        totalBase_ = statusMemory_.total_payload_upload;
1649       
1650        uploaded_.update(statusMemory_.total_upload);
1651        payloadUploaded_.update(statusMemory_.total_payload_upload);
1652        downloaded_.update(statusMemory_.total_download);
1653        payloadDownloaded_.update(statusMemory_.total_payload_download);
1654       
1655        if (is_active())
1656        {
1657                activeDuration_.update();
1658               
1659                if (libt::torrent_status::seeding == statusMemory_.state)
1660                        seedingDuration_.update();
1661        }       
1662       
1663        boost::tuple<size_t, size_t, size_t, size_t> connections = updatePeers();       
1664
1665        return TorrentDetail_ptr(new TorrentDetail(name_, filename_, saveDirectory().string(), state, hal::from_utf8(statusMemory_.current_tracker), 
1666                std::pair<float, float>(statusMemory_.download_payload_rate, statusMemory_.upload_payload_rate),
1667                progress_, statusMemory_.distributed_copies, statusMemory_.total_wanted_done, statusMemory_.total_wanted, uploaded_, payloadUploaded_,
1668                downloaded_, payloadDownloaded_, connections, ratio_, td, statusMemory_.next_announce, activeDuration_, seedingDuration_, startTime_, finishTime_));
1669
1670        }
1671        catch (const libt::invalid_handle&)
1672        {
1673                event_log.post(shared_ptr<EventDetail>(
1674                        new EventInvalidTorrent(event_logger::critical, event_logger::invalidTorrent, to_utf8(name_), "getTorrentDetail_ptr")));
1675        }
1676        catch (const std::exception& e)
1677        {
1678                event_log.post(shared_ptr<EventDetail>(
1679                        new EventTorrentException(event_logger::critical, event_logger::torrentException, e.what(), to_utf8(name_), "getTorrentDetail_ptr")));
1680        }
1681       
1682        return TorrentDetail_ptr(new TorrentDetail(name_, filename_, saveDirectory().string(), app().res_wstr(HAL_TORRENT_STOPPED), app().res_wstr(HAL_NA)));
1683}
1684
1685} // namespace hal
1686
1687BOOST_CLASS_VERSION(hal::TorrentManager::TorrentHolder, 1)
1688
1689#endif // RC_INVOKED
1690
Note: See TracBrowser for help on using the repository browser.