source: trunk/src/halTorrentInternal.hpp @ 564

Revision 564, 43.7 KB checked in by Eoin, 11 years ago (diff)

Added win32_exception class.

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