Bläddra i källkod

wip: alt_host

David Rose 16 år sedan
förälder
incheckning
ec5f3ab053

+ 5 - 2
direct/src/p3d/FileSpec.py

@@ -119,9 +119,12 @@ class FileSpec:
         # The hash is OK after all.  Change the file's timestamp back
         # to what we expect it to be, so we can quick-verify it
         # successfully next time.
-        os.chmod(pathname.toOsSpecific(), 0644)
+
+        # On Windows, we have to change the file to read-write before
+        # we can successfully update its timestamp.
+        os.chmod(pathname.toOsSpecific(), 0755)
         os.utime(pathname.toOsSpecific(), (st.st_atime, self.timestamp))
-        os.chmod(pathname.toOsSpecific(), 0444)
+        os.chmod(pathname.toOsSpecific(), 0555)
 
         return True
         

+ 19 - 5
direct/src/p3d/Packager.py

@@ -921,14 +921,21 @@ class Packager:
 
             self.__addConfigs(xpackage)
 
+            requireThisHost = False
             for package in self.requires:
                 xrequires = TiXmlElement('requires')
                 xrequires.SetAttribute('name', package.packageName)
                 if package.version:
                     xrequires.SetAttribute('version', package.version)
                 xrequires.SetAttribute('host', package.host)
+                if package.host == self.packager.host:
+                    requireThisHost = True
                 xpackage.InsertEndChild(xrequires)
 
+            if requireThisHost:
+                xhost = self.packager.makeHostXml()
+                xpackage.InsertEndChild(xhost)
+
             doc.InsertEndChild(xpackage)
 
             # Write the xml file to a temporary file on disk, so we
@@ -2605,11 +2612,8 @@ class Packager:
 
         xcontents = TiXmlElement('contents')
 
-        xhost = self.makeHostXml('host', self.host, self.hostDescriptiveName, self.hostMirrors)
+        xhost = self.makeHostXml()
         xcontents.InsertEndChild(xhost)
-        for keyword, (host, descriptiveName, mirrors) in self.altHosts.items():
-            xhost = self.makeHostXml('alt_host', host, descriptiveName, mirrors)
-            xcontents.InsertEndChild(xhost)
 
         contents = self.contents.items()
         contents.sort()
@@ -2620,7 +2624,17 @@ class Packager:
         doc.InsertEndChild(xcontents)
         doc.SaveFile()
 
-    def makeHostXml(self, element, host, descriptiveName, mirrors):
+    def makeHostXml(self):
+        """ Constructs the <host> entry for this host. """
+        xhost = self.makeHostXmlLine('host', self.host, self.hostDescriptiveName, self.hostMirrors)
+
+        for keyword, (host, descriptiveName, mirrors) in self.altHosts.items():
+            xalthost = self.makeHostXmlLine('alt_host', host, descriptiveName, mirrors)
+            xalthost.SetAttribute('keyword', keyword)
+            xhost.InsertEndChild(xalthost)
+        return xhost
+
+    def makeHostXmlLine(self, element, host, descriptiveName, mirrors):
         """ Constructs the <host> or <alt_host> entry for the
         indicated host and its mirrors. """
 

+ 144 - 12
direct/src/plugin/p3dHost.cxx

@@ -49,13 +49,52 @@ P3DHost::
     delete _xcontents;
   }
 
-  Packages::iterator pi;
-  for (pi = _packages.begin(); pi != _packages.end(); ++pi) {
-    delete (*pi).second;
+  Packages::iterator mi;
+  for (mi = _packages.begin(); mi != _packages.end(); ++mi) {
+    PackageMap &package_map = (*mi).second;
+    PackageMap::iterator pi;
+    for (pi = package_map.begin(); pi != package_map.end(); ++pi) {
+      delete (*pi).second;
+    }
   }
   _packages.clear();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DHost::get_alt_host
+//       Access: Public
+//  Description: Returns the pre-defined alternate host with the
+//               indicated token, if one is defined for this token, or
+//               the original host if there is no alternate host
+//               defined for this token.
+//
+//               This is intended to implement test versions and the
+//               like, for instance in which a particular p3d file may
+//               reference a package on one particular host, but there
+//               is an alternate version to be tested on a different
+//               host.  The HTML code that embeds the p3d file can
+//               choose to set the alt_host token to redirect the p3d
+//               file to the alternate host.
+//
+//               The actual URL for the alternate host is embedded
+//               within the host's contents.xml as a security measure,
+//               to prevent people from tricking a p3d file into
+//               running untrusted code by redirecting it to an
+//               arbitrary URL.
+////////////////////////////////////////////////////////////////////
+P3DHost *P3DHost::
+get_alt_host(const string &alt_host) {
+  assert(_xcontents != NULL);
+
+  AltHosts::iterator hi;
+  hi = _alt_hosts.find(alt_host);
+  if (hi != _alt_hosts.end() && (*hi).second != _host_url) {
+    P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
+    return inst_mgr->get_host((*hi).second);
+  }
+  return this;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DHost::read_contents_file
 //       Access: Public
@@ -97,9 +136,38 @@ read_contents_file(const string &contents_filename) {
   }
   _xcontents = (TiXmlElement *)xcontents->Clone();
 
-  const char *descriptive_name = _xcontents->Attribute("descriptive_name");
-  if (descriptive_name != NULL) {
-    _descriptive_name = descriptive_name;
+  TiXmlElement *xhost = _xcontents->FirstChildElement("host");
+  if (xhost != NULL) {
+    const char *url = xhost->Attribute("url");
+    if (url != NULL && _host_url == string(url)) {
+      // We're the primary host.  This is the normal case.
+      read_xhost(xhost);
+
+      // Build up the list of alternate hosts.
+      TiXmlElement *xalthost = xhost->FirstChildElement("alt_host");
+      while (xalthost != NULL) {
+        const char *keyword = xalthost->Attribute("keyword");
+        const char *url = xalthost->Attribute("url");
+        if (keyword != NULL && url != NULL) {
+          cerr << "got alt host " << keyword << ": " << url << "\n";
+          _alt_hosts[keyword] = url;
+        }
+        xalthost = xalthost->NextSiblingElement("alt_host");
+      }
+
+    } else {
+      // We're not the primary host; perhaps we're an alternate host.
+      TiXmlElement *xalthost = xhost->FirstChildElement("alt_host");
+      while (xalthost != NULL) {
+        const char *url = xalthost->Attribute("url");
+        if (url != NULL && _host_url == string(url)) {
+          // Yep, we're this alternate host.
+          read_xhost(xhost);
+          break;
+        }
+        xalthost = xalthost->NextSiblingElement("alt_host");
+      }
+    }
   }
 
   string standard_filename = _host_dir + "/contents.xml";
@@ -118,16 +186,33 @@ read_contents_file(const string &contents_filename) {
 //               package.
 ////////////////////////////////////////////////////////////////////
 P3DPackage *P3DHost::
-get_package(const string &package_name, const string &package_version) {
+get_package(const string &package_name, const string &package_version,
+            const string &alt_host) {
+  if (!alt_host.empty()) {
+    if (_xcontents != NULL) {
+      // If we're asking for an alt host and we've already read our
+      // contents.xml file, then we already know all of our hosts, and
+      // we can start the package off with the correct host immediately.
+      P3DHost *new_host = get_alt_host(alt_host);
+      return new_host->get_package(package_name, package_version);
+    }
+
+    // If we haven't read contents.xml yet, we need to create the
+    // package first, then let it be responsible for downloading our
+    // contents.xml, and it can migrate to its alt_host after that.
+  }
+
+  PackageMap &package_map = _packages[alt_host];
+
   string key = package_name + "_" + package_version;
-  Packages::iterator pi = _packages.find(key);
-  if (pi != _packages.end()) {
+  PackageMap::iterator pi = package_map.find(key);
+  if (pi != package_map.end()) {
     return (*pi).second;
   }
 
   P3DPackage *package = 
-    new P3DPackage(this, package_name, package_version);
-  bool inserted = _packages.insert(Packages::value_type(key, package)).second;
+    new P3DPackage(this, package_name, package_version, alt_host);
+  bool inserted = package_map.insert(PackageMap::value_type(key, package)).second;
   assert(inserted);
 
   return package;
@@ -217,6 +302,31 @@ get_package_desc_file(FileSpec &desc_file,              // out
   return false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DHost::migrate_package
+//       Access: Public
+//  Description: This is called by P3DPackage when it migrates from
+//               this host to its final alt_host, after downloading
+//               the contents.xml file for this file and learning the
+//               true URL for its target alt_host.
+////////////////////////////////////////////////////////////////////
+void P3DHost::
+migrate_package(P3DPackage *package, const string &alt_host, P3DHost *new_host) {
+  assert(new_host != this);
+  assert(new_host == get_alt_host(alt_host));
+
+  string key = package->get_package_name() + "_" + package->get_package_version();
+
+  PackageMap &package_map = _packages[alt_host];
+  PackageMap::iterator pi = package_map.find(key);
+  assert(pi != package_map.end());
+  package_map.erase(pi);
+
+  PackageMap &new_package_map = new_host->_packages[""];
+  bool inserted = new_package_map.insert(PackageMap::value_type(key, package)).second;
+  assert(inserted);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DHost::determine_host_dir
 //       Access: Private
@@ -270,7 +380,6 @@ determine_host_dir() {
   // be safe since they have the same hostname), there will be minimal
   // redownloading.
 
-
   static const size_t hash_size = 16;
   unsigned char md[hash_size];
 
@@ -298,6 +407,29 @@ determine_host_dir() {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DHost::read_xhost
+//       Access: Private
+//  Description: Reads the host data from the <host> (or <alt_host>)
+//               entry in the contents.xml file.
+////////////////////////////////////////////////////////////////////
+void P3DHost::
+read_xhost(TiXmlElement *xhost) {
+  const char *descriptive_name = xhost->Attribute("descriptive_name");
+  if (descriptive_name != NULL) {
+    _descriptive_name = descriptive_name;
+  }
+        
+  TiXmlElement *xmirror = xhost->FirstChildElement("mirror");
+  while (xmirror != NULL) {
+    const char *url = xmirror->Attribute("url");
+    if (url != NULL) {
+      _mirrors.push_back(url);
+    }
+    xmirror = xmirror->NextSiblingElement("mirror");
+  }
+}
+
 
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DHost::standardize_filename

+ 15 - 2
direct/src/plugin/p3dHost.h

@@ -39,20 +39,26 @@ public:
   inline const string &get_host_url_prefix() const;
   inline const string &get_descriptive_name() const;
 
+  P3DHost *get_alt_host(const string &alt_host);
+
   inline bool has_contents_file() const;
   bool read_contents_file();
   bool read_contents_file(const string &contents_filename);
 
   P3DPackage *get_package(const string &package_name, 
-                          const string &package_version);
+                          const string &package_version,
+                          const string &alt_host = "");
   bool get_package_desc_file(FileSpec &desc_file, 
                              string &package_platform,
                              bool &package_solo,
                              const string &package_name,
                              const string &package_version);
 
+  void migrate_package(P3DPackage *package, const string &alt_host, P3DHost *new_host);
+
 private:
   void determine_host_dir();
+  void read_xhost(TiXmlElement *xhost);
 
   static string standardize_filename(const string &filename);
   static bool copy_file(const string &from_filename, const string &to_filename);
@@ -64,7 +70,14 @@ private:
   string _descriptive_name;
   TiXmlElement *_xcontents;
 
-  typedef map<string, P3DPackage *> Packages;
+  typedef vector<string> Mirrors;
+  Mirrors _mirrors;
+
+  typedef map<string, string> AltHosts;
+  AltHosts _alt_hosts;
+
+  typedef map<string, P3DPackage *> PackageMap;
+  typedef map<string, PackageMap> Packages;
   Packages _packages;
 
   friend class P3DInstanceManager;

+ 3 - 1
direct/src/plugin/p3dInstance.cxx

@@ -1243,6 +1243,8 @@ scan_app_desc_file(TiXmlDocument *doc) {
     _wparams.set_window_type(P3D_WT_hidden);
   }
 
+  string alt_host = _fparams.lookup_token("alt_host");
+
   TiXmlElement *xrequires = xpackage->FirstChildElement("requires");
   while (xrequires != NULL) {
     const char *name = xrequires->Attribute("name");
@@ -1253,7 +1255,7 @@ scan_app_desc_file(TiXmlDocument *doc) {
         version = "";
       }
       P3DHost *host = inst_mgr->get_host(host_url);
-      P3DPackage *package = host->get_package(name, version);
+      P3DPackage *package = host->get_package(name, version, alt_host);
       add_package(package);
     }
 

+ 53 - 12
direct/src/plugin/p3dPackage.cxx

@@ -41,17 +41,15 @@ static const double extract_portion = 0.05;
 ////////////////////////////////////////////////////////////////////
 P3DPackage::
 P3DPackage(P3DHost *host, const string &package_name,
-           const string &package_version) :
+           const string &package_version, const string &alt_host) :
   _host(host),
   _package_name(package_name),
-  _package_version(package_version)
+  _package_version(package_version),
+  _alt_host(alt_host)
 {
   _package_fullname = _package_name;
-  _package_dir = _host->get_host_dir() + string("/") + _package_name;
-
   if (!_package_version.empty()) {
     _package_fullname += string(".") + _package_version;
-    _package_dir += string("/") + _package_version;
   }
 
   // This is set true if the package is a "solo", i.e. a single
@@ -68,9 +66,6 @@ P3DPackage(P3DHost *host, const string &package_name,
   _failed = false;
   _active_download = NULL;
   _partial_download = false;
-
-  // Ensure the package directory exists; create it if it does not.
-  mkdir_complete(_package_dir, nout);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -232,7 +227,7 @@ begin_info_download() {
 //       Access: Private
 //  Description: Starts downloading the root-level contents.xml file.
 //               This is only done for the first package, and only if
-//               the instance manager doesn't have the file already.
+//               the host doesn't have the file already.
 ////////////////////////////////////////////////////////////////////
 void P3DPackage::
 download_contents_file() {
@@ -246,7 +241,7 @@ download_contents_file() {
   if (_host->has_contents_file()) {
     // We've already got a contents.xml file; go straight to the
     // package desc file.
-    download_desc_file();
+    host_got_contents_file();
     return;
   }
 
@@ -261,7 +256,10 @@ download_contents_file() {
 
   // Download contents.xml to a temporary filename first, in case
   // multiple packages are downloading it simultaneously.
-  assert(_temp_contents_file == NULL);
+  if (_temp_contents_file != NULL) {
+    delete _temp_contents_file;
+    _temp_contents_file = NULL;
+  }
   _temp_contents_file = new P3DTemporaryFile(".xml");
 
   start_download(DT_contents_file, url, _temp_contents_file->get_filename(), false);
@@ -270,7 +268,8 @@ download_contents_file() {
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DPackage::contents_file_download_finished
 //       Access: Private
-//  Description: Called when the desc file has been fully downloaded.
+//  Description: Called when the contents.xml file has been fully
+//               downloaded.
 ////////////////////////////////////////////////////////////////////
 void P3DPackage::
 contents_file_download_finished(bool success) {
@@ -295,6 +294,48 @@ contents_file_download_finished(bool success) {
   delete _temp_contents_file;
   _temp_contents_file = NULL;
 
+  host_got_contents_file();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPackage::host_got_contents_file
+//       Access: Private
+//  Description: We come here when we've successfully downloaded and
+//               read the host's contents.xml file.
+////////////////////////////////////////////////////////////////////
+void P3DPackage::
+host_got_contents_file() {
+  if (!_alt_host.empty()) {
+    // If we have an alt host specification, maybe we need to change
+    // the host now.
+    P3DHost *new_host = _host->get_alt_host(_alt_host);
+    nout << "Migrating " << get_package_name() << " to alt_host " 
+         << _alt_host << ": " << new_host->get_host_url() << "\n";
+    if (new_host != _host) {
+      _host->migrate_package(this, _alt_host, new_host);
+      _host = new_host;
+    }
+
+    // Clear the alt_host string now that we're migrated to our final
+    // host.
+    _alt_host.clear();
+
+    if (!_host->has_contents_file()) {
+      // Now go back and get the contents.xml file for the new host.
+      download_contents_file();
+      return;
+    }
+  }
+
+  // Now that we have a valid host, we can define the _package_dir.
+  _package_dir = _host->get_host_dir() + string("/") + _package_name;
+  if (!_package_version.empty()) {
+    _package_dir += string("/") + _package_version;
+  }
+
+  // Ensure the package directory exists; create it if it does not.
+  mkdir_complete(_package_dir, nout);
+
   download_desc_file();
 }
 

+ 4 - 1
direct/src/plugin/p3dPackage.h

@@ -41,7 +41,8 @@ class P3DPackage {
 private:
   P3DPackage(P3DHost *host,
              const string &package_name, 
-             const string &package_version);
+             const string &package_version,
+             const string &alt_host);
   ~P3DPackage();
 
 public:
@@ -89,6 +90,7 @@ private:
   void begin_info_download();
   void download_contents_file();
   void contents_file_download_finished(bool success);
+  void host_got_contents_file();
 
   void download_desc_file();
   void desc_file_download_finished(bool success);
@@ -116,6 +118,7 @@ private:
   string _package_name;
   string _package_version;
   string _package_platform;
+  string _alt_host;
   bool _package_solo;
   string _package_display_name;
   string _package_fullname;

+ 7 - 2
direct/src/plugin/p3dWinSplashWindow.cxx

@@ -380,10 +380,15 @@ make_window() {
       WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
       WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
       WS_SIZEBOX | WS_MAXIMIZEBOX;
-    
+
+    RECT win_rect = { 0, 0, width, height };
+    // Adjust window size based on desired client area size
+    AdjustWindowRect(&win_rect, window_style, FALSE);
     _hwnd = 
       CreateWindow("panda3d_splash", "Panda3D", window_style,
-                   x, y, width, height,
+                   x, y,
+                   win_rect.right - win_rect.left,
+                   win_rect.bottom - win_rect.top,
                    NULL, NULL, application, 0);
     if (!_hwnd) {
       nout << "Could not create toplevel window!\n";