This patch correct the databasepath assignment from previous version
submitted.
It allow the usign of ProxyNode from http.
Cheers Carlo
#include <iostream>
#include <fstream>
#include <sstream>

#include <osg/Notify>

#include <osgDB/Input>
#include <osgDB/Registry>
#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgDB/FileUtils>
#include <osgDB/Archive>
#include <osg/MatrixTransform>
#include <osg/Group>
#include <osg/Timer>
#include "sockinet.h"

 /*
  *  Semantics:
  *    Two methods for using the .net loader.
  *      1) Add a hostname prefix and a '.net' suffix on a model when passing 
  *          to osgDB::readNodeFile() 
  *          e.g:    osgDB::readNodeFile( "openscenegraph.org:cow.osg.net" );
  *
  *     2) Explicitely load the .net plugin and pass the plugin options 
including
  *           hostname=<hostname>
  *
  *    Method #1 takes precedence.  SO, if the hostname option is passed the
  *    plugin, but the name also contains a hostname prefix, the hostname
  *    prefix on the file name will override the option
  *
  *  Plugin options:
  *           root_address=<url>      - Specify the web database path for an 
iterative
  *                                     call of the net plugin
  *           local_cache_dir=<dir>   - Specify a directory in which to cache 
files
  *                                     on the local machine once they've been 
fetched.  
  *                                     This directory is also searched before 
fetching
  *                                     the file from the server when Read mode 
is 
  *                                     enabled on the cache.
  *
  *           cache_mode=<mode>       - Set the mode for the local cache if 
local_cache
  *                                     was specified.  If local_cache was not 
specified
  *                                     this directive is ignored.  <mode> may
  *                                     be specified with ReadOnly, WriteOnly, 
or
  *                                     ReadWrite.  Behavior for the different 
modes is
  *                                     defined as:
  *
  *                                       ReadOnly   - When retrieving files, 
cache is 
  *                                                    searched first, and if 
the file is
  *                                                    not present, it is 
fetched from the
  *                                                    server.  If it is 
fetched from the
  *                                                    server it is not stored 
in local cache
  *
  *                                       WriteOnly  - When retrieving files, 
cache is not
  *                                                    searched, file is always 
retrieved
  *                                                    from the server and 
always written to
  *                                                    cache.
  *
  *                                       ReadWrite  - (the default).  When 
retrieving files
  *                                                    cache is searched first, 
if file is
  *                                                    not present in cache, it 
is fetched from
  *                                                    the server.  If fetched, 
it is written
  *                                                    to cache.
  *
  *            proxy_host=<hostname>   - Specify the name of a Proxy host.  
Proxies are not 
  *                                      used by default
  *
  *            proxy_port=<portnumber> - When using a Proxy host, specify the 
port.  The 
  *                                      internal variable defaults to 8080.
  *
  *      Environmental Variables:
  *
  *               OSG_PROXY_HOST        Specifies the name of a Proxy host.  
Overrides options.
  *
  *               OSG_PROXY_PORT        When using a Proxy, sets the proxy port 
deliberately.  
  *                                     The internal variable defaults to 8080.
  */


class NetReader : public osgDB::ReaderWriter
{
    public:
        NetReader() {}
                                                                                
            
        virtual const char* className() const { return "HTTP Protocol Model 
Reader"; }
                                                                                
            
        virtual bool acceptsExtension(const std::string& extension) const
        {
            return osgDB::equalCaseInsensitive(extension,"net");
        }

        enum ObjectType
        {
            OBJECT,
            ARCHIVE,
            IMAGE,
            HEIGHTFIELD,
            NODE
        };
                                                                                
            
        virtual ReadResult openArchive(const std::string& 
fileName,ArchiveStatus status, unsigned int , const Options* options) const
        {
            if (status!=READ) return ReadResult(ReadResult::FILE_NOT_HANDLED);
            else return readFile(ARCHIVE,fileName,options);
        }

        virtual ReadResult readObject(const std::string& fileName, const 
Options* options) const
        {
            return readFile(OBJECT,fileName,options);
        }
                                                                                
            
        virtual ReadResult readImage(const std::string& fileName, const Options 
*options) const
        {
            return readFile(IMAGE,fileName,options);
        }

        virtual ReadResult readHeightField(const std::string& fileName, const 
Options *options) const
        {
            return readFile(HEIGHTFIELD,fileName,options);
        }

        virtual ReadResult readNode(const std::string& fileName, const Options 
*options) const
        {
            return readFile(NODE,fileName,options);
        }

        ReadResult readFile(ObjectType objectType, osgDB::ReaderWriter* rw, 
std::istream& fin, const Options *options) const
        {
            switch(objectType)
            {
            case(OBJECT): return rw->readObject(fin,options);
            case(ARCHIVE): return rw->openArchive(fin,options);
            case(IMAGE): return rw->readImage(fin,options);
            case(HEIGHTFIELD): return rw->readHeightField(fin,options);
            case(NODE): return rw->readNode(fin,options);
            default: break;
            }
            return ReadResult::FILE_NOT_HANDLED;
        }

        virtual ReadResult readFile(ObjectType objectType, const std::string& 
inFileName, const Options *options) const
        {
                        ReadResult readResult = ReadResult::FILE_NOT_HANDLED;

            osg::Timer_t start = osg::Timer::instance()->tick();

            osg::notify(osg::DEBUG_INFO) << "osgPlugin .net: readFile " << 
inFileName << std::endl;

            std::string hostname;
                        std::string rootaddress;
                        std::string relativeaddress;
            std::string localCacheDir;
            int port = 80;

            std::string proxyHost;
            int proxyPort = 8080;

            enum CacheMode {
                Read      = 1,
                Write     = 2,
                ReadWrite = 3
            };

            std::string cacheFile;
            CacheMode cacheMode = ReadWrite;

                        bool set_master_root = false;
                        bool set_rootaddress_in_localopt = false;

            if (options)
            {
                std::istringstream iss(options->getOptionString());
                std::string opt;
                while (iss >> opt) 
                {
                    int index = opt.find( "=" );
                                        if( opt.substr( 0, index ) == 
"root_address" ||
                        opt.substr( 0, index ) == "ROOT_ADDRESS" )
                    {
                        rootaddress = opt.substr( index+1 );
                                                set_master_root = true;
                    }
                    else if( opt.substr( 0, index ) == "proxy_hostname" ||
                             opt.substr( 0, index ) == "PROXY_HOSTNAME" ) 
//CARLO: proxy modf
                    {
                        proxyHost = opt.substr(index+1);
                        osg::notify(osg::WARN) << "proxy host " << proxyHost << 
std::endl;
                    }
                    else if( opt.substr( 0, index ) == "proxy_port" ||
                             opt.substr( 0, index ) == "PROXY_PORT" )
                    {
                        proxyPort = atoi( opt.substr(index+1).c_str() );
                    }
                    else if( opt.substr( 0, index ) == "local_cache_dir" ||
                             opt.substr( 0, index ) == "LOCAL_CACHE_DIR" )
                    {
                        localCacheDir = opt.substr(index+1);
                    }
                    else if( opt.substr( 0, index ) == "cache_mode" ||
                             opt.substr( 0, index ) == "CACHE_MODE" )
                    {
                        if( opt.substr(index+1) == "ReadOnly" )
                            cacheMode = Read;
                        else if(  opt.substr(index+1) == "WriteOnly" )
                            cacheMode = Write;
                        else if(  opt.substr(index+1) == "ReadWrite" )
                            cacheMode = ReadWrite;
                        else
                            osg::notify(osg::WARN) << "NET plug-in warning:  
cache_mode " << opt.substr(index+1) << " not understood.  Defaulting to 
ReadWrite." << std::endl;
                    }
                }
            }

            // Env variables should override plug-in options.
            {
                char * env_proxyHost = getenv("OSG_PROXY_HOST"); //Checking 
proxy environment variables 
                char * env_proxyPort = getenv("OSG_PROXY_PORT");

                if( env_proxyHost )
                {
                                        proxyHost = std::string(env_proxyHost);
                                        osg::notify(osg::DEBUG_INFO) << 
"osgPlugin .net reader: Proxy HostName Environment Variable sets " << proxyHost 
<< std::endl;
                                        if( env_proxyPort )
                                        {
                        proxyPort = atoi(std::string(env_proxyPort).c_str());
                                                osg::notify(osg::DEBUG_INFO) << 
"osgPlugin .net reader: Proxy Port Environment Variable sets " << proxyPort << 
std::endl;
                                        }
                }
            }

                //We use the entire address instead the division with ":" marker
                        //This issue resolve the confusion between window path 
and old OSG address subdivision
            std::string fileName;
                        bool saddress = 
osgDB::containsServerAddress(inFileName);
            if( saddress == true )
            {
                                //Root Address
                                rootaddress = osgDB::getFilePath( inFileName );
                                //Relative Address
                                relativeaddress = osgDB::getSimpleFileName( 
inFileName );

                                // hostname
                                hostname = osgDB::getServerAddress(inFileName);
                // need to strip the inFileName of the hostname prefix
                                fileName = osgDB::getServerFileName(inFileName);

                                if(!set_master_root) //If the hostname isn't 
setted explicitly
                                        set_rootaddress_in_localopt = true; 
//It sets the hostname for the recursive calls
            }
            else
            {
                if( rootaddress.empty() )
                                {
                    return readResult; //Return ReadResult::FILE_NOT_HANDLED;
                                }
                else
                                {
                                        //Relative Address
                                        relativeaddress = 
osgDB::convertFileNameToUnixStyle(inFileName);
                                        
                                        // hostname
                                        hostname = 
osgDB::getServerAddress(rootaddress + '/' + relativeaddress);
                                        // need to strip
                                        fileName = 
osgDB::getServerFileName(rootaddress + '/' + relativeaddress);
                                }
            }

            //Find the Port Number specified in URL
            int index = hostname.find_last_of(":");
            if( index != -1 )
            {
                port = atoi( hostname.substr( index + 1 ).c_str() );
                hostname = hostname.substr( 0, index );            
            }

            // Let's also strip the possible .net extension
            if( osgDB::getFileExtension( fileName ) == "net" )
            {
                int rindex = fileName.rfind( "." );
                fileName = fileName.substr( 0, rindex );
            }

            // Invoke the reader corresponding to the extension
            osgDB::ReaderWriter *reader = 
osgDB::Registry::instance()->getReaderWriterForExtension( 
osgDB::getFileExtension(fileName) );

            if( reader == 0L )
                return ReadResult::FILE_NOT_HANDLED;

                        // code for setting up the database path so that any 
paged
            // databases can be automatically located. 
            osg::ref_ptr<Options> local_opt = const_cast<Options*>(options);
            
                        if (!local_opt) 
                                local_opt = new Options;

                        if(set_rootaddress_in_localopt)
                        {
                                bool present = false;

                                std::string loptstr = 
local_opt->getOptionString();
                                loptstr += " ROOT_ADDRESS=" + rootaddress;
                                local_opt->setOptionString(loptstr);

                                //Sets databasepath
                                osgDB::FilePathList dbfplist = 
local_opt->getDatabasePathList();

                                osgDB::FilePathList::iterator itr = 
dbfplist.begin();
                                for( ; itr != dbfplist.end(); itr++)
                                {
                                        if((*itr) == rootaddress)
                                                present = true;
                                }

                                if(!present)
                                        local_opt->setDatabasePath(rootaddress);
                        }

            // Before we go to the network, lets see if it is in local cache, 
if cache
            // was specified and Read bit is set
            if( !localCacheDir.empty() && (cacheMode & Read) )
            {
                                std::string cacheFile = 
osgDB::convertFileNameToNativeStyle( localCacheDir + '/' + relativeaddress );
                if( osgDB::fileExists( cacheFile ))
                {
                    std::ifstream  in(cacheFile.c_str());
                    readResult = readFile(objectType, reader, in, 
local_opt.get() );

                    in.close();
                    osg::notify(osg::DEBUG_INFO) << "osgPlugin .net: " << 
cacheFile << " fetched from local cache." << std::endl;
                    return readResult;
                }
            }

            // Fetch from the network
            osg::ref_ptr<iosockinet> sio = new iosockinet(sockbuf::sock_stream);

            std::string requestAdd;

            if(!proxyHost.empty())
            {
                try {
                    sio->rdbuf()->connect( proxyHost.c_str(), proxyPort );
                    osg::notify(osg::DEBUG_FP) << "osgPlugin .net reader: 
connected to Proxy " << proxyHost << " with Port " << proxyPort <<  std::endl;
                }
                catch( sockerr e )
                {
                    osg::notify(osg::WARN) << "osgPlugin .net reader: Unable to 
connect to Proxy " << proxyHost << std::endl;
                    return ReadResult::FILE_NOT_FOUND;
                }
                
                if(port != 80) //Default HTTP Port
                {
                    std::ostringstream portstream;
                    portstream << port << std::flush; 

                    requestAdd = std::string("http://";) + hostname + 
std::string(":") + portstream.str() + std::string("/") + fileName;
                }
                else 
                    requestAdd = std::string("http://";) + hostname + 
std::string("/") + fileName;
            }
            else
            {
                try {
                    sio->rdbuf()->connect( hostname.c_str(), port );
                    osg::notify(osg::DEBUG_FP) << "osgPlugin .net reader: 
connected to Hostname " << hostname << " with Port " << port <<  std::endl;
                }
                catch( sockerr e )
                {
                    osg::notify(osg::WARN) << "osgPlugin .net reader: Unable to 
connect to host " << hostname << std::endl;
                    return ReadResult::FILE_NOT_FOUND;
                }
                requestAdd = "/" + fileName; 
            }

            *sio << 
                    "GET " << requestAdd << " HTTP/1.1\n" 
                    "User-Agent: OSGNetPlugin/1.0\n"
                    "Accept: */*\n"
                    "Host: " << hostname << "\n"
                    "Connection: close\n"
                    "\n";    

            sio->flush();
                                                                                
                           
            char linebuff[512];
            do
            {
                sio->getline( linebuff, sizeof( linebuff ));

                std::istringstream iss(linebuff);
                std::string directive;
                iss >> directive;
                if( directive.substr(0,4) == "HTTP" )
                {
                    iss >> directive;
                    // Code 200.  We be ok.
                    if( directive == "200" )
                        ;
                    // Code 400 Bad Request
                    else if( directive == "400" )
                    {
                        osg::notify(osg::WARN) << 
                            "osgPlugin .net: http server response 400 - Bad 
Request" << std::endl;
                        return ReadResult::FILE_NOT_FOUND;
                    }
                    // Code 401 Bad Request
                    else if( directive == "401" )
                    {
                        osg::notify(osg::WARN) << 
                            "osgPlugin .net: http server response 401 - 
Unauthorized Access" << std::endl;
                        return ReadResult::FILE_NOT_FOUND;
                    }
                    // Code 403 Bad Request
                    else if( directive == "403" )
                    {
                        osg::notify(osg::WARN) << 
                            "osgPlugin .net: http server response 403 - Access 
Forbidden" << std::endl;
                        return ReadResult::FILE_NOT_FOUND;
                    }
                    // Code 404 File not found
                    else if( directive == "404" )
                    {
                        osg::notify(osg::WARN) << 
                            "osgPlugin .net: http server response 404 - File 
Not Found" << std::endl;
                        return ReadResult::FILE_NOT_FOUND;
                    }
                    // Code 405 Method not allowed
                    else if( directive == "405" )
                    {
                        osg::notify(osg::WARN) << 
                            "osgPlugin .net: http server response 405 - Method 
Not Allowed" << std::endl;
                        return ReadResult::FILE_NOT_FOUND;
                    }
                    // There's more....
                }

            } while( linebuff[0] != '\r' );

                        //Start Reading
            if( reader != 0L )
                readResult = readFile(objectType, reader, *sio, local_opt.get() 
);

            double ms = 
osg::Timer::instance()->delta_m(start,osg::Timer::instance()->tick());

            osg::notify(osg::DEBUG_INFO) << "osgPlugin .net: " << fileName << " 
fetched from server. in " << ms <<" ms"<< std::endl;

            if (objectType == ARCHIVE && readResult.validArchive())
            {
                // attach the socket istream to the archive to keep it alive.
                osgDB::Archive* archive = readResult.getArchive();
                archive->setUserData(sio.get());
            }

            if( !localCacheDir.empty() && cacheMode & Write )
            {
                std::string cacheFile = osgDB::convertFileNameToNativeStyle( 
localCacheDir + '/' + fileName );
                if( osgDB::makeDirectoryForFile( cacheFile ) )
                {
 
                    switch(objectType)
                    {
                    case(OBJECT): osgDB::writeObjectFile( 
*(readResult.getObject()), cacheFile );
                    case(IMAGE): osgDB::writeImageFile( 
*(readResult.getImage()), cacheFile );
                    case(HEIGHTFIELD): osgDB::writeHeightFieldFile( 
*(readResult.getHeightField()), cacheFile );
                    case(NODE): osgDB::writeNodeFile( *(readResult.getNode()), 
cacheFile );;
                    default: break;
                    }
 
                     
                    osg::notify(osg::DEBUG_INFO) << "osgPlugin .net: " << 
fileName << 
                                         " stored to local cache." << std::endl;
                }
            }

            return readResult;
        }
        
};

REGISTER_OSGPLUGIN(net, NetReader)
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

Reply via email to