source: trunk/src/halTorrentInternal.hpp @ 668

Revision 668, 39.4 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
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%") % tracker_username_ % tracker_password_ );
1308                }
1309        }
1310       
1311        void apply_file_priorities()
1312        {               
1313                mutex_t::scoped_lock l(mutex_);
1314                if (in_session()) 
1315                {
1316                        if (!file_priorities_.empty())
1317                                handle_.prioritize_files(file_priorities_);
1318                       
1319                        HAL_DEV_MSG(L"Applying File Priorities");
1320                }
1321        }       
1322       
1323        void apply_resolve_countries()
1324        {
1325                mutex_t::scoped_lock l(mutex_);
1326                if (in_session())
1327                {
1328                        handle_.resolve_countries(resolve_countries_);
1329                       
1330                        HAL_DEV_MSG(hal::wform(L"Applying Resolve Countries %1%") % resolve_countries_);
1331                }
1332        }
1333       
1334        bool completed_pause()
1335        {
1336                mutex_t::scoped_lock l(mutex_);
1337                assert(in_session());
1338//              assert(handle_.is_paused());   
1339
1340                HAL_DEV_MSG(L"completed_pause()");
1341                               
1342                state(torrent_details::torrent_paused);
1343
1344                return true;
1345        }
1346
1347        bool completed_stop()
1348        {
1349                mutex_t::scoped_lock l(mutex_);
1350                assert(in_session());
1351//              assert(handle_.is_paused());                   
1352               
1353                if (remove_from_session())
1354                {
1355                        assert(!in_session());
1356                        HAL_DEV_MSG(L"completed_stop()");
1357                }
1358
1359                state(torrent_details::torrent_stopped);
1360
1361                return true;
1362        }
1363
1364        void handle_recheck()
1365        {
1366                mutex_t::scoped_lock l(mutex_);
1367                state(torrent_details::torrent_stopped);
1368
1369                remove_from_session(false);
1370                assert(!in_session());
1371
1372                clear_resume_data();
1373
1374                resume();
1375                assert(in_session());
1376
1377                HAL_DEV_MSG(L"handle_recheck()");
1378        }
1379
1380        void state(unsigned s)
1381        {
1382                switch (s)
1383                {
1384                case torrent_details::torrent_stopped:
1385                        HAL_DEV_MSG(L"state() - stopped");
1386                        break;
1387                case torrent_details::torrent_stopping:
1388                        HAL_DEV_MSG(L"state() - stopping");
1389                        break;
1390                case torrent_details::torrent_pausing:
1391                        HAL_DEV_MSG(L"state() - pausing");
1392                        break;
1393                case torrent_details::torrent_active:
1394                        HAL_DEV_MSG(L"state() - active");
1395                        break;
1396                case torrent_details::torrent_paused:
1397                        HAL_DEV_MSG(L"state() - paused");
1398                        break;
1399                default:
1400                        HAL_DEV_MSG(L"state() - unknown");
1401                        break;
1402                };
1403                state_ = s;
1404        }       
1405       
1406        unsigned state() const 
1407        { 
1408                if (in_session())
1409                {
1410                        if (handle_.is_paused())
1411                        {
1412                                if (state_ != torrent_details::torrent_paused)
1413                                {                       
1414                                        HAL_DEV_MSG(L"Should really be paused!");
1415                                        state_ = torrent_details::torrent_paused;
1416                                }
1417                        }
1418                        else                           
1419                        {                       
1420                                if (state_ != torrent_details::torrent_active &&
1421                                        state_ != torrent_details::torrent_pausing &&
1422                                        state_ != torrent_details::torrent_stopping)
1423                                {                       
1424                                        HAL_DEV_MSG(L"Should really be active!");
1425                                        state_ = torrent_details::torrent_active;
1426                                }
1427                        }                       
1428                }
1429                else
1430                {
1431                        if (state_ != torrent_details::torrent_stopped)
1432                        {                       
1433                                HAL_DEV_MSG(L"Should really be stopped!");
1434                                state_ = torrent_details::torrent_stopped;
1435                        }
1436                }
1437               
1438                return state_; 
1439        }
1440               
1441        static libt::session* the_session_;     
1442        mutable mutex_t mutex_;
1443
1444        torrent_state_machine machine_;
1445       
1446        std::pair<float, float> transfer_limit_;
1447       
1448        mutable unsigned state_;
1449        int connections_;
1450        int uploads_;
1451        bool in_session_;
1452        float ratio_;
1453        bool resolve_countries_;
1454       
1455        wstring filename_;
1456        wstring name_;
1457        wpath save_directory_;
1458        wpath move_to_directory_;
1459        wstring original_filename_;
1460        libt::torrent_handle handle_;   
1461       
1462//      boost::intrusive_ptr<libt::torrent_info> metadata_;
1463//      boost::shared_ptr<libt::entry> resumedata_;
1464       
1465        wstring tracker_username_;     
1466        wstring tracker_password_;
1467       
1468        boost::int64_t total_uploaded_;
1469        boost::int64_t total_base_;
1470       
1471        transfer_tracker<boost::int64_t> payload_uploaded_;
1472        transfer_tracker<boost::int64_t> payload_downloaded_;
1473        transfer_tracker<boost::int64_t> uploaded_;
1474        transfer_tracker<boost::int64_t> downloaded_;
1475       
1476        pt::ptime start_time_;
1477        pt::ptime finish_time_;
1478        duration_tracker active_duration_;
1479        duration_tracker seeding_duration_;
1480       
1481        std::vector<tracker_detail> trackers_;
1482        std::vector<libt::announce_entry> torrent_trackers_;
1483        std::vector<libt::peer_info> peers_;   
1484        std::vector<int> file_priorities_;
1485       
1486        float progress_;
1487       
1488        boost::intrusive_ptr<libt::torrent_info> info_memory_;
1489        libt::torrent_status status_memory_;
1490        file_details_vec file_details_memory_;
1491       
1492        int queue_position_;
1493        bool compact_storage_;
1494        bool managed_;
1495        bit::allocations allocation_;
1496};
1497
1498typedef std::map<std::string, TorrentInternalOld> TorrentMap;
1499typedef std::pair<std::string, TorrentInternalOld> TorrentPair;
1500
1501class torrent_manager : 
1502        public hal::IniBase<torrent_manager>
1503{
1504        typedef torrent_manager thisClass;
1505        typedef hal::IniBase<thisClass> iniClass;
1506
1507        struct torrent_holder
1508        {
1509                mutable torrent_internal_ptr torrent;
1510               
1511                wstring filename;
1512                wstring name;           
1513               
1514                torrent_holder()
1515                {}
1516               
1517                explicit torrent_holder(torrent_internal_ptr t) :
1518                        torrent(t), filename(torrent->filename()), name(torrent->name())
1519                {}
1520                                               
1521                friend class boost::serialization::access;
1522                template<class Archive>
1523                void serialize(Archive& ar, const unsigned int version)
1524                {
1525                        using boost::serialization::make_nvp;
1526
1527                        ar & make_nvp("torrent", torrent);
1528                        ar & make_nvp("filename", filename);
1529                        ar & make_nvp("name", name);
1530                }
1531        };
1532       
1533        struct by_filename{};
1534        struct by_name{};
1535       
1536        typedef boost::multi_index_container<
1537                torrent_holder,
1538                boost::multi_index::indexed_by<
1539                        boost::multi_index::ordered_unique<
1540                                boost::multi_index::tag<by_filename>,
1541                                boost::multi_index::member<
1542                                        torrent_holder, wstring, &torrent_holder::filename> 
1543                                >,
1544                        boost::multi_index::ordered_unique<
1545                                boost::multi_index::tag<by_name>,
1546                                boost::multi_index::member<
1547                                        torrent_holder, wstring, &torrent_holder::name> 
1548                                >
1549                >
1550        > torrent_multi_index;
1551       
1552public:
1553        typedef torrent_multi_index::index<by_filename>::type torrent_by_filename;
1554        typedef torrent_multi_index::index<by_name>::type torrent_by_name;
1555       
1556        torrent_manager(ini_file& ini) :
1557                iniClass("bittorrent", "torrent_manager", ini)
1558        {}
1559
1560        std::pair<torrent_by_name::iterator, bool> insert(const torrent_holder& h)
1561        {
1562                return torrents_.get<by_name>().insert(h);
1563        }
1564       
1565        std::pair<torrent_by_name::iterator, bool> insert(torrent_internal_ptr t)
1566        {
1567                return insert(torrent_holder(t));
1568        }
1569
1570        torrent_internal_ptr get_by_file(const wstring& filename)
1571        {
1572                torrent_by_filename::iterator it = torrents_.get<by_filename>().find(filename);
1573               
1574                if (it != torrents_.get<by_filename>().end() && (*it).torrent)
1575                {
1576                        return (*it).torrent;
1577                }
1578               
1579                throw invalid_torrent(filename);
1580        }
1581       
1582        torrent_internal_ptr get(const wstring& name)
1583        {
1584                torrent_by_name::iterator it = torrents_.get<by_name>().find(name);
1585               
1586                if (it != torrents_.get<by_name>().end() && (*it).torrent)
1587                {
1588                        return (*it).torrent;
1589                }
1590               
1591                throw invalid_torrent(name);
1592        }
1593       
1594        torrent_by_name::iterator erase(torrent_by_name::iterator where)
1595        {
1596                return torrents_.get<by_name>().erase(where);
1597        }
1598       
1599        size_t size()
1600        {
1601                return torrents_.size();
1602        }
1603       
1604        size_t erase(const wstring& name)
1605        {
1606                return torrents_.get<by_name>().erase(name);
1607        }
1608       
1609        bool exists(const wstring& name)
1610        {
1611                torrent_by_name::iterator it = torrents_.get<by_name>().find(name);
1612               
1613                if (it != torrents_.get<by_name>().end())
1614                        return true;
1615                else
1616                        return false;
1617        }
1618       
1619        torrent_by_name::iterator begin() { return torrents_.get<by_name>().begin(); }
1620        torrent_by_name::iterator end() { return torrents_.get<by_name>().end(); }
1621       
1622        friend class boost::serialization::access;
1623        template<class Archive>
1624        void serialize(Archive& ar, const unsigned int version)
1625        {
1626                ar & boost::serialization::make_nvp("torrents", torrents_);
1627        }       
1628       
1629private:
1630        torrent_multi_index torrents_;
1631};
1632
1633} // namespace hal
1634
1635BOOST_CLASS_VERSION(hal::torrent_manager::torrent_holder, 1)
Note: See TracBrowser for help on using the repository browser.