fileslist.h

Go to the documentation of this file.
00001 /**
00002  *  Copyright (C) 2004-2005 Alo Sarv <madcat_@users.sourceforge.net>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017  */
00018 
00019 /** \file fileslist.h Interface for FilesList class */
00020 #ifndef __FILESLIST_H__
00021 #define __FILESLIST_H__
00022 
00023 /**
00024  * \page fms Files Management Subsystem Overview
00025  *
00026  * The three main classes in Files Management Subsystem are PartData,
00027  * SharedFile and FilesList. They are supported by MetaData data structures,
00028  * which contain useful information about these objects. PartData object
00029  * is owned by SharedFile, which in turn is owned by FilesList. Various
00030  * ***MetaData objects are owned by MetaData, which in turn is owned by
00031  * MetaDb. The usage of the subsystem goes as follows:
00032  *
00033  * \section newdl Starting a new download.
00034  * - The plugin which receives a request to start a new download creates a new
00035  *   PartData object. The plugin must pass the size of the new file as well as
00036  *   the expected (final) file name of the download. A temporary file will be
00037  *   then created in one of the temp directories.
00038  * - If the plugin has more information about the file, it can construct the
00039  *   neccesery MetaData objects, insert the data into those and push the
00040  *   MetaData into MetaDb.
00041  * - Finalizing the download creation, the plugin requests FilesList to
00042  *   construct a new download via the method createDownload(), which takes care
00043  *   of the remaining details.
00044  *
00045  * Example:
00046  * \code
00047  * SharedFile *sf = MetaDb::instance().findSharedFile(hash);
00048  * if (sf && sf->isPartial()) {
00049  *   logMsg(
00050  *     boost::format("You are already attempting to download %s")
00051  *     % sf->getName()
00052  *   );
00053  * } else if (sf) {
00054  *   logMsg(boost::format("You already have %s") % sf->getName());
00055  * } else {
00056  *   MetaData *md = new MetaData(size);
00057  *   md->addFileName(name);
00058  *   md->addHashSet(myhashset);
00059  *   MetaDb::instance().push(md);
00060  *   FilesList::instance().createDownload(name, md);
00061  * }
00062  * \endcode
00063  *
00064  * \section olddl Continueing an existing download.
00065  * When the application restarts, the plugins want to continue downloading
00066  * existing partial files. In order to do so, plugins must locate all the files
00067  * they are capable of downloading from FilesList. Here's the hard part. We
00068  * don't want to force plugins to keep internal list of their part files -
00069  * after all, its (a) our job, (b) de-centralizes this stuff, (c) its our job.
00070  * So, we need to provide the plugins with a list of files they can attempt to
00071  * download. Consider this example: We have been downloading files from various
00072  * networks for quite some time now, having large amount of partial files. Now,
00073  * a new plugin for a new network gets released. Naturally, the new plugin
00074  * joins the show and wants to catch up to things - e.g. what needs to be done.
00075  * So the plugin does what? Takes up FilesList and iterates on it. Only the
00076  * plugin itself can know what kind of files its looking for - for example,
00077  * some plugins might need a specific hash in order to download a file, others
00078  * might want http or ftp url ... god knows what. So - in short - FilesList
00079  * provides access to begin() and end() iterators, just as any standard c++
00080  * container, and let plugins do the hard part.
00081  *
00082  * Ok - enough discussion - so what do you do to get your files ? Call
00083  * FilesList::begin() to retrieve iterator to begin of list, and start
00084  * iterating on the list. The only guarantee I can give you at this point is
00085  * that if you dereference the iterator, you get a pointer to a SharedFile
00086  * object. You don't even know that its partial - use the SharedFile member
00087  * functions to check it. Where we go from here is up to you to decide. The
00088  * iterators are constant, so you can't modify them. And don't store them -
00089  * they are std::map iterators, and will become invalid when the integrity of
00090  * the map changes.
00091  */
00092 
00093 #include <boost/shared_ptr.hpp>
00094 #include <hn/osdep.h>
00095 #include <hn/object.h>
00096 #include <hn/sharedfile.h>
00097 #include <string>
00098 #include <set>
00099 #include <iosfwd>
00100 #include <boost/filesystem/path.hpp>
00101 #include <boost/multi_index_container.hpp>
00102 #include <boost/multi_index/indexed_by.hpp>
00103 #include <boost/multi_index/ordered_index.hpp>
00104 #include <boost/multi_index/key_extractors.hpp>
00105 
00106 class MetaData;
00107 
00108 /**
00109  * FilesList class owns all SharedFile objects and provides accessors for
00110  * managing shared files / directories as well as temporary files /
00111  * directories.
00112  */
00113 class DLLEXPORT FilesList : public Object {
00114 public:
00115         struct PathExtractor {
00116                 typedef boost::filesystem::path result_type;
00117                 result_type operator()(const SharedFile *const s) const {
00118                         return s->getPath();
00119                 }
00120         };
00121         struct PartExtractor {
00122                 typedef bool result_type;
00123                 result_type operator()(const SharedFile *const s) const {
00124                         return s->isPartial();
00125                 }
00126         };
00127         typedef boost::multi_index_container<
00128                 SharedFile*,
00129                 boost::multi_index::indexed_by<
00130                         boost::multi_index::ordered_unique<
00131                                 boost::multi_index::identity<SharedFile*>
00132                         >,
00133                         boost::multi_index::ordered_unique<PathExtractor>,
00134                         boost::multi_index::ordered_non_unique<PartExtractor>
00135                 >
00136         > MIFilesList;
00137         typedef MIFilesList::nth_index<0>::type::iterator SFIter;
00138         typedef MIFilesList::nth_index<0>::type::const_iterator CSFIter;
00139         typedef MIFilesList::nth_index<1>::type::iterator NIter;
00140         typedef MIFilesList::nth_index<1>::type::const_iterator CNIter;
00141 
00142         /**
00143          * Access to the single instance of this class
00144          */
00145         static FilesList& instance();
00146 
00147         /**
00148          * \brief Add new SharedFile to this list
00149          *
00150          * @param file     File to be added
00151          */
00152         void push(SharedFile *file);
00153 
00154         /**
00155          * \brief Scan a folder for shared files
00156          *
00157          * @param path     Path to folder to be scanned
00158          * @param recurse  If true, the path will be scanned recursivly
00159          */
00160         void addSharedDir(const std::string &path, bool recurse = false);
00161 
00162         /**
00163          * \brief Scan a temporary folder for shared files
00164          *
00165          * @param path     Path to the folder to be scanned
00166          * @param recurse  If true, the path will be scanned recurisvly
00167          */
00168         void addTempDir(const std::string &path);
00169 
00170         /**
00171          * \brief Remove a shared folder, un-sharing all files found in there
00172          *
00173          * @param path     Path to be un-shared
00174          * @param recurse  If all sub-dirs should be un-shared too
00175          */
00176         void remSharedDir(const std::string &path, bool recurse = false);
00177 
00178         /**
00179          * \brief Remove a temporary folder.
00180          *
00181          * @param path     Path to be removed
00182          *
00183          * The files in the temporary folder will not be modified; existing
00184          * downloads will be saved and then destroyed, the data on disk is
00185          * kept, so the path can be re-added later on to resume those downloads.
00186          */
00187         void remTempDir(const std::string &path);
00188 
00189         /**
00190          * Add a new download, constructed from the passed MetaData info.
00191          *
00192          * @param name      Name of the expected resulting file
00193          * @param info      Information about the new download
00194          */
00195         void createDownload(std::string name, MetaData *info);
00196 
00197         /**
00198          * @name Generic accessors
00199          */
00200         //@{
00201         size_t  size()  const { return m_list.size();  }
00202         CSFIter begin() const { return m_list.begin(); }
00203         CSFIter end()   const { return m_list.end();   }
00204         std::pair<CNIter, CNIter> equal_range(const std::string &name) const {
00205                 return m_list.get<1>().equal_range(name);
00206         }
00207         template<size_t N>
00208         typename MIFilesList::nth_index<N>::type::const_iterator end() {
00209                 return boost::multi_index::get<N>(m_list).end();
00210         }
00211         //@}
00212 
00213         //! Instructs FilesList to save the state of all SharedFiles which
00214         //! have PartData member.
00215         void savePartFiles();
00216 
00217         //! Returns number of files with PartData member
00218         uint32_t getPartialCount() const {
00219                 return m_list.get<2>().count(true);
00220         }
00221 
00222         //! Returns number of total entries in this list; equal to size()
00223         uint32_t getSharedCount() const { return size(); }
00224 private:
00225         void scanSharedDir(const std::string &path, bool recurse = false);
00226         void scanTempDir(const std::string &path);
00227 
00228         //! @name Singleton class - constructors/destructors hidden
00229         //@{
00230         FilesList();
00231         ~FilesList();
00232         FilesList(FilesList &);
00233         FilesList operator=(const FilesList&);
00234         //@}
00235 
00236         //! Main list
00237         MIFilesList m_list;
00238 
00239         //! Map of shared directories. boolean indicates recursion
00240         std::map<std::string, bool> m_sharedDirs;
00241         typedef std::map<std::string, bool>::iterator SDIter;
00242 
00243         //! Temporary directories
00244         std::set<std::string> m_tempDirs;
00245         typedef std::set<std::string>::iterator TDIter;
00246 
00247         //! Output operator to streams
00248         friend std::ostream& operator<<(std::ostream &o, const FilesList &fl);
00249 
00250         /**
00251          * Verify that the string contains a valid existing path.
00252          *
00253          * @param path   Path to verify.
00254          *
00255          * \throws std::runtime_error if verification fails.
00256          */
00257         static void verifyPath(const std::string &path);
00258 
00259         /**
00260          * Event handler for SharedFile events
00261          *
00262          * @param sf      SharedFile triggering the event.
00263          * @param evt     Event type.
00264          */
00265          void onSharedFileEvent(SharedFile *sf, int evt);
00266 
00267          /**
00268           * Attempts to load a temp file from designated path.
00269           *
00270           * @param file    Path to the file
00271           * @return        True if load was successful, false otherwise
00272           */
00273          bool loadTempFile(const boost::filesystem::path &file);
00274 
00275          //! @name Make operations/data available for Object hierarcy
00276          //@{
00277          virtual uint8_t getOperCount() const;
00278          virtual Object::Operation getOper(uint8_t n) const;
00279          virtual void doOper(const Operation &oper);
00280          //@}
00281 };
00282 
00283 #endif