source: trunk/src/halTorrentInternal.hpp @ 683

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