David Rose 15 år sedan
förälder
incheckning
f451da1f34
2 ändrade filer med 111 tillägg och 52 borttagningar
  1. 109 51
      direct/src/plugin_activex/PPInstance.cpp
  2. 2 1
      direct/src/plugin_activex/PPInstance.h

+ 109 - 51
direct/src/plugin_activex/PPInstance.cpp

@@ -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 ) )
-        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;
+      }
 
-    } 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() );
     }
-
-    // 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;

+ 2 - 1
direct/src/plugin_activex/PPInstance.h

@@ -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;