source: branch_0_3_1/src/halTorrentInternal.hpp @ 616

Revision 616, 42.3 KB checked in by Eoin, 11 years ago (diff)

Queue adjustment almost implemented, one last bit to link up.

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