This commit is contained in:
David Rose 2010-06-09 00:58:48 +00:00
parent c80eba7088
commit f451da1f34
2 changed files with 113 additions and 54 deletions

View File

@ -83,6 +83,7 @@ PPInstance::PPInstance( CP3DActiveXCtrl& parentCtrl ) :
m_logger.Open( m_rootDir );
m_pluginLoaded = false;
_contents_expiration = 0;
_failed = false;
// Ensure this event is initially in the "set" state, in case we
@ -142,18 +143,58 @@ int PPInstance::CopyFile( const std::string& from, const std::string& to )
////////////////////////////////////////////////////////////////////
// Function: PPInstance::read_contents_file
// Access: Private
// Description: Reads the contents.xml file and starts the core API
// DLL downloading, if necessary.
// Description: Attempts to open and read the contents.xml file on
// disk. Copies the file to its standard location
// on success. Returns true on success, false on
// failure.
////////////////////////////////////////////////////////////////////
bool PPInstance::
read_contents_file(const string &contents_filename) {
read_contents_file(const string &contents_filename, bool fresh_download) {
TiXmlDocument doc(contents_filename.c_str());
if (!doc.LoadFile()) {
return false;
}
bool found_core_package = false;
TiXmlElement *xcontents = doc.FirstChildElement("contents");
if (xcontents != NULL) {
int max_age = P3D_CONTENTS_DEFAULT_MAX_AGE;
xcontents->Attribute("max_age", &max_age);
// Get the latest possible expiration time, based on the max_age
// indication. Any expiration time later than this is in error.
time_t now = time(NULL);
_contents_expiration = now + (time_t)max_age;
if (fresh_download) {
// Update the XML with the new download information.
TiXmlElement *xorig = xcontents->FirstChildElement("orig");
while (xorig != NULL) {
xcontents->RemoveChild(xorig);
xorig = xcontents->FirstChildElement("orig");
}
xorig = new TiXmlElement("orig");
xcontents->LinkEndChild(xorig);
xorig->SetAttribute("expiration", (int)_contents_expiration);
} else {
// Read the expiration time from the XML.
int expiration = 0;
TiXmlElement *xorig = xcontents->FirstChildElement("orig");
if (xorig != NULL) {
xorig->Attribute("expiration", &expiration);
}
_contents_expiration = min(_contents_expiration, (time_t)expiration);
}
nout << "read contents.xml, max_age = " << max_age
<< ", expires in " << max(_contents_expiration, now) - now
<< " s\n";
// Look for the <host> entry; it might point us at a different
// download URL, and it might mention some mirrors.
find_host(xcontents);
@ -166,7 +207,8 @@ read_contents_file(const string &contents_filename) {
const char *platform = xpackage->Attribute("platform");
if (platform != NULL && strcmp(platform, DTOOL_PLATFORM) == 0) {
_core_api_dll.load_xml(xpackage);
return true;
found_core_package = true;
break;
}
}
@ -174,10 +216,23 @@ read_contents_file(const string &contents_filename) {
}
}
// Couldn't find the coreapi package description.
nout << "No coreapi package defined in contents file for "
<< DTOOL_PLATFORM << "\n";
return false;
if (!found_core_package) {
// Couldn't find the coreapi package description.
nout << "No coreapi package defined in contents file for "
<< DTOOL_PLATFORM << "\n";
return false;
}
// Success. Now save the file in its proper place.
string standard_filename = m_rootDir + "/contents.xml";
mkfile_complete(standard_filename, nout);
if (!doc.SaveFile(standard_filename.c_str())) {
nout << "Couldn't rewrite " << standard_filename << "\n";
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////
@ -299,58 +354,59 @@ int PPInstance::DownloadP3DComponents( std::string& p3dDllFilename )
{
int error(0);
// Start off by downloading contents.xml into a local temporary
// file. We get a unique temporary filename each time; this is a
// small file and it's very important that we get the most current
// version, not an old cached version.
TCHAR tempFileName[ MAX_PATH ];
if (!::GetTempFileName( m_rootDir.c_str(), "p3d", 0, tempFileName )) {
nout << "GetTempFileName failed (folder is " << m_rootDir << ")\n";
return 1;
}
std::string localContentsFileName( tempFileName );
// We'll also get the final installation path of the contents.xml
// file.
// Get the pathname of the local copy of the contents.xml file.
std::string finalContentsFileName( m_rootDir );
finalContentsFileName += "/";
finalContentsFileName += P3D_CONTENTS_FILENAME;
std::string hostUrl( PANDA_PACKAGE_HOST_URL );
if (!hostUrl.empty() && hostUrl[hostUrl.size() - 1] != '/') {
hostUrl += '/';
// Check to see if the version on disk is already current enough.
bool already_got = false;
if (read_contents_file(finalContentsFileName, false)) {
if (time(NULL) < _contents_expiration) {
// Got the file, and it's good.
already_got = true;
}
}
// Append a query string to the contents.xml URL to uniquify it
// and ensure we don't get a cached version.
std::ostringstream strm;
strm << hostUrl << P3D_CONTENTS_FILENAME << "?" << time(NULL);
std::string remoteContentsUrl( strm.str() );
if (!already_got) {
// OK, we need to download a new contents.xml file. Start off
// by downloading it into a local temporary file.
TCHAR tempFileName[ MAX_PATH ];
if (!::GetTempFileName( m_rootDir.c_str(), "p3d", 0, tempFileName )) {
nout << "GetTempFileName failed (folder is " << m_rootDir << ")\n";
return 1;
}
std::string localContentsFileName( tempFileName );
error = DownloadFile( remoteContentsUrl, localContentsFileName );
if ( !error )
{
if ( !read_contents_file( localContentsFileName ) )
error = 1;
std::string hostUrl( PANDA_PACKAGE_HOST_URL );
if (!hostUrl.empty() && hostUrl[hostUrl.size() - 1] != '/') {
hostUrl += '/';
}
// Append a query string to the contents.xml URL to uniquify it
// and ensure we don't get a cached version.
std::ostringstream strm;
strm << hostUrl << P3D_CONTENTS_FILENAME << "?" << time(NULL);
std::string remoteContentsUrl( strm.str() );
error = DownloadFile( remoteContentsUrl, localContentsFileName );
if ( !error ) {
if ( !read_contents_file( localContentsFileName, true ) )
error = 1;
}
if ( error ) {
// If we couldn't download or read the contents.xml file, check
// to see if there's a good one on disk already, as a fallback.
if ( !read_contents_file( finalContentsFileName, false ) )
error = 1;
}
// We don't need the temporary file any more.
::DeleteFile( localContentsFileName.c_str() );
}
if ( error ) {
// If we couldn't download or read the contents.xml file, check
// to see if there's a good one on disk already, as a fallback.
if ( !read_contents_file( finalContentsFileName ) )
error = 1;
} else {
// If we have successfully read the downloaded version,
// then move the downloaded version into the final location.
mkfile_complete( finalContentsFileName, nout );
CopyFile( localContentsFileName, finalContentsFileName );
}
// We don't need the temporary file any more.
::DeleteFile( localContentsFileName.c_str() );
if (!error) {
// OK, at this point we have successfully read contents.xml,
// and we have a good file spec in _core_api_dll.
@ -441,7 +497,9 @@ int PPInstance::LoadPlugin( const std::string& dllFilename )
#endif // P3D_PLUGIN_P3D_PLUGIN
nout << "Attempting to load core API from " << pathname << "\n";
if (!load_plugin(pathname, "", "", true, "", "", "", false, false,
string contents_filename = m_rootDir + "/contents.xml";
if (!load_plugin(pathname, contents_filename, PANDA_PACKAGE_HOST_URL,
true, "", "", "", false, false,
m_rootDir, nout)) {
nout << "Unable to launch core API in " << pathname << "\n";
error = 1;

View File

@ -68,7 +68,7 @@ protected:
int DownloadFile( const std::string& from, const std::string& to );
int CopyFile( const std::string& from, const std::string& to );
bool read_contents_file(const std::string &contents_filename);
bool read_contents_file(const std::string &contents_filename, bool fresh_download);
void find_host(TiXmlElement *xcontents);
void read_xhost(TiXmlElement *xhost);
void add_mirror(std::string mirror_url);
@ -91,6 +91,7 @@ protected:
typedef std::vector<std::string> Mirrors;
Mirrors _mirrors;
FileSpec _core_api_dll;
time_t _contents_expiration;
bool _failed;
std::string m_rootDir;