root/libcore/LoadVariablesThread.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


// 
//   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
//   2011 Free Software Foundation, Inc
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
//


#ifndef GNASH_LOADVARIABLESTHREAD_H
#define GNASH_LOADVARIABLESTHREAD_H

#include "StreamProvider.h" // for inlines
#include "URL.h" // for inlines


#include <string>
#include <map>
#include <memory>
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp> 

// Forward declarations
namespace gnash {
        //class URL;
}

namespace gnash {

// Exception thrown by LoadVariablesThread constructor if unable to connect
// to the stream input.
class NetworkException {};

/// A manager for loadVariable requests
//
/// Provides services for starting a "load and parse" thread, checking
/// its status and getting a parsed variables structure back when done.
///
class LoadVariablesThread
{
public:
        typedef std::map<std::string, std::string> ValuesMap;

        /// Construct a LoadVariablesThread opening a stream for the given URL
        //
        /// Throws a NetworkException if unable.
        ///
        /// @param url
        ///     URL to post to and fetch from
        ///
        LoadVariablesThread(const StreamProvider& sp, const URL& url);

        /// \brief
        /// Construct a LoadVariablesThread opening a stream for the given URL,
        /// posting the given url-encoded data if using HTTP.
        //
        /// Throws a NetworkException if unable.
        ///
        /// @param url
        ///     URL to post to and fetch from
        ///
        /// @param postdata
        ///     Url-encoded post data.
        ///
        LoadVariablesThread(const StreamProvider& sp, const URL& url,
            const std::string& postdata);

        /// Destroy the LoadVariablesThread, joining the thread if spawned
        ~LoadVariablesThread();

        /// Return the name,value map parsed out of the loaded stream
        ValuesMap& getValues()
        {
                return _vals;
        }

        /// Start the load and parse thread
        void process()
        {
                assert(!_thread.get());
                assert(_stream.get());
                _thread.reset(new boost::thread(
                boost::bind(LoadVariablesThread::execLoadingThread, this)));
        }

        /// Cancel a download in progress
        //
        /// Locks _mutex
        ///
        void cancel();

        /// Return true if loading/parsing is in progress
        bool inProgress()
        {
                // TODO: should we mutex-protect this ?
                return ( _thread.get() != NULL );
        }

        /// Mutex-protected inspector for thread completion
        //
        /// Only call this method from the same thread that
        /// also called process(), as the thread will be joined
        /// if it completed.
        ///
        bool completed()
        {
                boost::mutex::scoped_lock lock(_mutex);
                if (  _completed && _thread.get() )
                {
                        _thread->join();
                        _thread.reset();
                }
                return _completed;
        }

        size_t getBytesLoaded() const
        {
                // TODO: should we mutex-protect this ?
                return _bytesLoaded;
        }

        size_t getBytesTotal() const
        {
                // TODO: should we mutex-protect this ?
                return _bytesTotal;
        }


private:

        /// Prevent copy
        LoadVariablesThread& operator==(const LoadVariablesThread&); 
        LoadVariablesThread(const LoadVariablesThread&); 

        /// Since I haven't found a way to pass boost::thread 
        /// constructor a non-static function, this is here to
        /// workaround that limitation (in either boost or more
        /// likely my own knowledge of it)
        static void execLoadingThread(LoadVariablesThread* ptr)
        {
                //log_debug("LoadVars loading thread started");
                ptr->completeLoad();
                //log_debug("LoadVars loading thread completed");
        }


        /// Mutex-protected mutator for thread completion
        void setCompleted()
        {
                boost::mutex::scoped_lock lock(_mutex);
                _completed = true;
                //log_debug("Completed");
        }


        /// Load all data from the _stream input.
        //
        /// This function should be run by a separate thread.
        ///
        void completeLoad();

        /// Parse an url-encoded query string
        //
        /// Variables in the string will be added as properties
        /// of this object.
        ///
        /// @param querystring
        ///     An url-encoded query string.
        ///     The string will be parsed using URL::parse_querystring
        ///
        /// @return the number of variables found in the string
        ///
        size_t parse(const std::string& str)
        {
                URL::parse_querystring(str, _vals);
                return _vals.size();
        }

        /// Check if download cancel was requested
        //
        /// Locks _mutex
        ///
        bool cancelRequested();

        size_t _bytesLoaded;

        size_t _bytesTotal;

        std::auto_ptr<IOChannel> _stream;

        std::auto_ptr<boost::thread> _thread;

        ValuesMap _vals;

        bool _completed;

        bool _canceled;

        boost::mutex _mutex;
};

} // namespace gnash

#endif // GNASH_LOADVARIABLESTHREAD_H

/* [<][>][^][v][top][bottom][index][help] */