source: trunk/src/halTorrentInternal.hpp @ 660

Revision 660, 39.4 KB checked in by Eoin, 11 years ago (diff)

FileDetail? struct converted to file_details along with other related naming changes.

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