source: trunk/src/halTorrentInternal.hpp @ 680

Revision 680, 39.4 KB checked in by Eoin, 12 years ago (diff)

Using session pause all instead of per torrent. Need to hook in paused alert to shutdown cleanly.

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