David Rose 16 лет назад
Родитель
Сommit
508b92005f

+ 15 - 10
direct/src/p3d/AppRunner.py

@@ -102,6 +102,13 @@ class AppRunner(DirectObject):
         # the instance starts up.
         self.rootDir = None
 
+        # self.superMirrorUrl, if nonempty, is the "super mirror" URL
+        # that should be contacted first before trying the actual
+        # host.  This is primarily used for "downloading" from a
+        # locally-stored Panda3D installation.  This is also filled in
+        # when the instance starts up.
+        self.superMirrorUrl = None
+
         # A list of the Panda3D packages that have been loaded.
         self.installedPackages = []
 
@@ -430,11 +437,7 @@ class AppRunner(DirectObject):
             interactiveConsole = self.interactiveConsole
             self.interactiveConsole = False
 
-            try:
-                __import__(moduleName)
-            except ImportError:
-                message = "No %s found in application." % (moduleName)
-                raise StandardError, message
+            __import__(moduleName)
             main = sys.modules[moduleName]
             if hasattr(main, 'main') and callable(main.main):
                 main.main(self)
@@ -469,15 +472,17 @@ class AppRunner(DirectObject):
                                needsResponse = False)
         self.deferredEvals = []
 
-    def setInstanceInfo(self, rootDir):
+    def setInstanceInfo(self, rootDir, superMirrorUrl):
         """ Called by the browser to set some global information about
         the instance. """
 
-        # At the present, this only includes rootDir, which is the
-        # root Panda3D install directory on the local machine.
-        
+        # rootDir is the root Panda3D install directory on the local
+        # machine.
         self.rootDir = Filename.fromOsSpecific(rootDir)
 
+        # The "super mirror" URL, generally used only by panda3d.exe.
+        self.superMirrorUrl = superMirrorUrl
+
     def addPackageInfo(self, name, platform, version, hostUrl):
         """ Called by the browser to list all of the "required"
         packages that were preloaded before starting the
@@ -809,7 +814,7 @@ def dummyAppRunner(tokens = [], argv = None):
 
     if AppRunnerGlobal.appRunner:
         print "Already have AppRunner, not creating a new one."
-        return
+        return AppRunnerGlobal.appRunner
 
     appRunner = AppRunner()
     appRunner.dummy = True

+ 1 - 0
direct/src/p3d/HostInfo.py

@@ -25,6 +25,7 @@ class HostInfo:
         assert appRunner or hostDir
         
         self.hostUrl = hostUrl
+        self.appRunner = appRunner
         self.hostDir = hostDir
         self.asMirror = asMirror
 

+ 12 - 4
direct/src/p3d/PackageInfo.py

@@ -532,16 +532,24 @@ class PackageInfo:
         if not urlbase:
             urlbase = self.descFileDirname + '/' + fileSpec.filename
 
-        # Build up a list of URL's to try downloading from.
+        # Build up a list of URL's to try downloading from.  Unlike
+        # the C++ implementation in P3DPackage.cxx, here we build the
+        # URL's in forward order.
         tryUrls = []
+
+        if self.host.appRunner and self.host.appRunner.superMirrorUrl:
+            # We start with the "super mirror", if it's defined.
+            url = self.host.appRunner.superMirrorUrl + urlbase
+            tryUrls.append(url)
+
         if self.host.mirrors:
-            # Choose a mirror at random first, then a different
-            # mirror.
+            # Choose two mirrors at random.
             mirrors = self.host.mirrors[:]
             for i in range(2):
                 mirror = random.choice(mirrors)
                 mirrors.remove(mirror)
-                tryUrls.append(mirror + urlbase)
+                url = mirror + urlbase
+                tryUrls.append(url)
                 if not mirrors:
                     break
 

+ 2 - 4
direct/src/p3d/Packager.py

@@ -458,7 +458,7 @@ class Packager:
                     continue
 
                 if mdef.exclude and mdef.implicit:
-                    # Don't bother mentioning implicity-excluded
+                    # Don't bother mentioning implicitly-excluded
                     # (i.e. missing) modules.
                     continue
 
@@ -1529,10 +1529,8 @@ class Packager:
         # The following are config settings that the caller may adjust
         # before calling any of the command methods.
 
-        # These should each be a Filename, or None if they are not
-        # filled in.
+        # This should be set to a Filename.
         self.installDir = None
-        self.persistDir = None
 
         # The download URL at which these packages will eventually be
         # hosted.

+ 7 - 0
direct/src/p3d/panda3d.pdef

@@ -14,6 +14,12 @@ from pandac.PandaModules import getModelPath, Filename, ConfigVariableFilename
 # and then a number of smaller, optional packages, which may or may
 # not be needed by any one particular application.
 
+packager.setHost('file:///home/drose/p3dstage',
+                 mirrors = ['file:///home/drose/p3dstage_mirror1',
+                            'file:///home/drose/p3dstage_mirror2',
+                            'file:///home/drose/p3dstage_mirror3',
+                            'file:///home/drose/p3dstage_mirror4'])
+
 class coreapi(solo):
     # The special "coreapi" package.  As a "solo", this is just a
     # single .dll (or dylib, or whatever).
@@ -102,6 +108,7 @@ class panda3d(package):
            'direct.gui.*',
            'direct.interval.*',
            'direct.particles.*',
+           'direct.p3d.*',
            'direct.showbase.*',
            'direct.showutil.*',
            'direct.stdpy.*')

+ 1 - 12
direct/src/p3d/ppackage.py

@@ -61,15 +61,6 @@ Options:
      This option may be repeated as necessary.  These directories may
      also be specified with the pdef-path Config.prc variable.
 
-  -d persist_dir
-     The full path to a local directory that retains persistant state
-     between publishes.  This directory structure keeps files that are
-     used to build patches for future releases.  You should keep this
-     directory structure around for as long as you plan to support
-     this package.  If this directory structure does not exist or is
-     empty, patches will not be created for this publish; but the
-     directory structure will be populated for the next publish.
-
   -u host_url
      Specifies the URL to the download server that will eventually
      host these packages (that is, the public URL of the install
@@ -119,7 +110,7 @@ packager = Packager.Packager()
 buildPatches = False
 
 try:
-    opts, args = getopt.getopt(sys.argv[1:], 'i:ps:d:DP:u:n:h')
+    opts, args = getopt.getopt(sys.argv[1:], 'i:ps:DP:u:n:h')
 except getopt.error, msg:
     usage(1, msg)
 
@@ -130,8 +121,6 @@ for opt, arg in opts:
         buildPatches = True
     elif opt == '-s':
         packager.installSearch.appendDirectory(Filename.fromOsSpecific(arg))
-    elif opt == '-d':
-        packager.persistDir = Filename.fromOsSpecific(arg)
     elif opt == '-D':
         packager.allowPythonDev = True
     elif opt == '-P':

+ 5 - 0
direct/src/plugin/load_plugin.cxx

@@ -36,6 +36,7 @@ static const string default_plugin_filename = "p3d_plugin";
 
 P3D_initialize_func *P3D_initialize;
 P3D_finalize_func *P3D_finalize;
+P3D_set_super_mirror_func *P3D_set_super_mirror;
 P3D_new_instance_func *P3D_new_instance;
 P3D_instance_start_func *P3D_instance_start;
 P3D_instance_finish_func *P3D_instance_finish;
@@ -187,6 +188,7 @@ load_plugin(const string &p3d_plugin_filename,
   // Now get all of the function pointers.
   P3D_initialize = (P3D_initialize_func *)get_func(module, "P3D_initialize");  
   P3D_finalize = (P3D_finalize_func *)get_func(module, "P3D_finalize");  
+  P3D_set_super_mirror = (P3D_set_super_mirror_func *)get_func(module, "P3D_set_super_mirror");  
   P3D_new_instance = (P3D_new_instance_func *)get_func(module, "P3D_new_instance");  
   P3D_instance_start = (P3D_instance_start_func *)get_func(module, "P3D_instance_start");  
   P3D_instance_finish = (P3D_instance_finish_func *)get_func(module, "P3D_instance_finish");  
@@ -226,6 +228,7 @@ load_plugin(const string &p3d_plugin_filename,
   // Ensure that all of the function pointers have been found.
   if (P3D_initialize == NULL ||
       P3D_finalize == NULL ||
+      P3D_set_super_mirror == NULL ||
       P3D_new_instance == NULL ||
       P3D_instance_start == NULL ||
       P3D_instance_finish == NULL ||
@@ -265,6 +268,7 @@ load_plugin(const string &p3d_plugin_filename,
       << "Some function pointers not found:"
       << "\nP3D_initialize = " << P3D_initialize
       << "\nP3D_finalize = " << P3D_finalize
+      << "\nP3D_set_super_mirror = " << P3D_set_super_mirror
       << "\nP3D_new_instance = " << P3D_new_instance
       << "\nP3D_instance_start = " << P3D_instance_start
       << "\nP3D_instance_finish = " << P3D_instance_finish
@@ -358,6 +362,7 @@ unload_dso() {
   
   P3D_initialize = NULL;
   P3D_finalize = NULL;
+  P3D_set_super_mirror = NULL;
   P3D_new_instance = NULL;
   P3D_instance_start = NULL;
   P3D_instance_finish = NULL;

+ 1 - 0
direct/src/plugin/load_plugin.h

@@ -22,6 +22,7 @@ using namespace std;
 
 extern P3D_initialize_func *P3D_initialize;
 extern P3D_finalize_func *P3D_finalize;
+extern P3D_set_super_mirror_func *P3D_set_super_mirror;
 extern P3D_new_instance_func *P3D_new_instance;
 extern P3D_instance_start_func *P3D_instance_start;
 extern P3D_instance_finish_func *P3D_instance_finish;

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

@@ -847,10 +847,6 @@ start_download(P3DDownload *download) {
 
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
 
-  // Since we're downloading something, we might as well check all
-  // contents files from this point on.
-  inst_mgr->reset_verify_contents();
-
   int download_id = inst_mgr->get_unique_id();
   download->set_download_id(download_id);
 
@@ -912,6 +908,9 @@ make_xml() {
 
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
   xinstance->SetAttribute("root_dir", inst_mgr->get_root_dir());
+  if (!inst_mgr->get_super_mirror().empty()) {
+    xinstance->SetAttribute("super_mirror", inst_mgr->get_super_mirror());
+  }
 
   TiXmlElement *xfparams = _fparams.make_xml();
   xinstance->LinkEndChild(xfparams);

+ 10 - 0
direct/src/plugin/p3dInstanceManager.I

@@ -122,6 +122,16 @@ get_trusted_environment() const {
   return _trusted_environment;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstanceManager::get_super_mirror
+//       Access: Public
+//  Description: Returns the "super mirror" URL.  See p3d_plugin.h.
+////////////////////////////////////////////////////////////////////
+inline const string &P3DInstanceManager::
+get_super_mirror() const {
+  return _super_mirror_url;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstanceManager::get_num_instances
 //       Access: Public

+ 15 - 0
direct/src/plugin/p3dInstanceManager.cxx

@@ -296,6 +296,21 @@ initialize(const string &contents_filename, const string &download_url,
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstanceManager::set_super_mirror
+//       Access: Public
+//  Description: Specifies the "super mirror" URL.  See p3d_plugin.h.
+////////////////////////////////////////////////////////////////////
+void P3DInstanceManager::
+set_super_mirror(const string &super_mirror_url) {
+  _super_mirror_url = super_mirror_url;
+
+  // Make sure it ends with a slash.
+  if (!_super_mirror_url.empty() && _super_mirror_url[_super_mirror_url.size() - 1] != '/') {
+    _super_mirror_url += '/';
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstanceManager::create_instance
 //       Access: Public

+ 4 - 0
direct/src/plugin/p3dInstanceManager.h

@@ -67,6 +67,9 @@ public:
   inline const string &get_log_pathname() const;
   inline bool get_trusted_environment() const;
 
+  void set_super_mirror(const string &super_mirror_url);
+  inline const string &get_super_mirror() const;
+
   P3DInstance *
   create_instance(P3D_request_ready_func *func, 
                   const P3D_token tokens[], size_t num_tokens, 
@@ -129,6 +132,7 @@ private:
   string _log_pathname;
   string _temp_directory;
   bool _trusted_environment;
+  string _super_mirror_url;
 
   P3D_object *_undefined_object;
   P3D_object *_none_object;

+ 16 - 0
direct/src/plugin/p3dPackage.cxx

@@ -945,6 +945,22 @@ start_download(P3DPackage::DownloadType dtype, const string &urlbase,
     }
   }
 
+  P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
+
+  if (dtype == DT_contents_file && inst_mgr->get_verify_contents()) {
+    // When we're dowloading the contents file with verify_contents
+    // true, we always go straight to the authoritative host, not even
+    // to the super-mirror.
+
+  } else {
+    // In other cases, if the "super mirror" is enabled, we try that
+    // first.
+    if (!inst_mgr->get_super_mirror().empty()) {
+      string url = inst_mgr->get_super_mirror() + urlbase;
+      download->_try_urls.push_back(url);
+    }
+  }
+
   // OK, start the download.
   assert(!download->_try_urls.empty());
   url = download->_try_urls.back();

+ 6 - 1
direct/src/plugin/p3dPythonRun.cxx

@@ -1116,8 +1116,13 @@ set_instance_info(P3DCInstance *inst, TiXmlElement *xinstance) {
     root_dir = "";
   }
 
+  const char *super_mirror = xinstance->Attribute("super_mirror");
+  if (super_mirror == NULL) {
+    super_mirror = "";
+  }
+
   PyObject *result = PyObject_CallMethod
-    (_runner, (char *)"setInstanceInfo", (char *)"s", root_dir);
+    (_runner, (char *)"setInstanceInfo", (char *)"ss", root_dir, super_mirror);
 
   if (result == NULL) {
     PyErr_Print();

+ 2 - 1
direct/src/plugin/p3dSession.cxx

@@ -850,8 +850,9 @@ start_p3dpython(P3DInstance *inst) {
   _env += python_path;
   _env += '\0';
 
+  // Let's leave PYTHONHOME empty.  Setting it adds junk to our
+  // carefully-constructed PYTHONPATH.
   _env += "PYTHONHOME=";
-  _env += _python_root_dir;
   _env += '\0';
 
   _env += "PRC_PATH=";

+ 13 - 3
direct/src/plugin/p3d_plugin.cxx

@@ -84,11 +84,23 @@ P3D_finalize() {
   P3DInstanceManager::delete_global_ptr();
 }
 
+void
+P3D_set_super_mirror(const char *super_mirror_url) {
+  assert(P3DInstanceManager::get_global_ptr()->is_initialized());
+  if (super_mirror_url == NULL) {
+    super_mirror_url = "";
+  }
+
+  ACQUIRE_LOCK(_api_lock);
+  P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
+  inst_mgr->set_super_mirror(super_mirror_url);
+  RELEASE_LOCK(_api_lock);
+}
+
 P3D_instance *
 P3D_new_instance(P3D_request_ready_func *func, 
                  const P3D_token tokens[], size_t num_tokens,
                  int argc, const char *argv[], void *user_data) {
-  nout << "new_instance\n";
   assert(P3DInstanceManager::get_global_ptr()->is_initialized());
   ACQUIRE_LOCK(_api_lock);
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
@@ -101,7 +113,6 @@ P3D_new_instance(P3D_request_ready_func *func,
 bool
 P3D_instance_start(P3D_instance *instance, bool is_local, 
                    const char *p3d_filename) {
-  nout << "instance_start\n";
   assert(P3DInstanceManager::get_global_ptr()->is_initialized());
   if (p3d_filename == NULL) {
     p3d_filename = "";
@@ -138,7 +149,6 @@ P3D_instance_setup_window(P3D_instance *instance,
                           int win_x, int win_y,
                           int win_width, int win_height,
                           P3D_window_handle parent_window) {
-  nout << "setup_window\n";
   assert(P3DInstanceManager::get_global_ptr()->is_initialized());
   P3DWindowParams wparams(window_type, win_x, win_y,
                           win_width, win_height, parent_window);

+ 17 - 0
direct/src/plugin/p3d_plugin.h

@@ -145,6 +145,22 @@ P3D_initialize_func(int api_version, const char *contents_filename,
 typedef void
 P3D_finalize_func();
 
+/* This function defines a "super mirror" URL: a special URL that is
+   consulted first whenever downloading any package referenced by a
+   p3d file.  This setting is global, and affects all package
+   downloads across all instances.  The main purpose of this is to
+   facilitate local distribution of the Panda3D runtime build, to
+   allow applications to ship themselves totally self-contained.  If
+   you install the appropriate Panda3D package files into a directory
+   on disk, and set the "super mirror" to a file:// URL that
+   references that directory, then users will be able to run your p3d
+   file without necessarily having an internet connection.
+
+   This normally should be set only by the panda3d standalone runtime
+   executable, not by a web plugin. */
+typedef void
+P3D_set_super_mirror_func(const char *super_mirror_url);
+
 /********************** INSTANCE MANAGEMENT **************************/
 
 /* The following interfaces define the API to manage individual
@@ -852,6 +868,7 @@ P3D_instance_handle_event_func(P3D_instance *instance, P3D_event_data event);
 /* Define all of the actual prototypes for the above functions. */
 EXPCL_P3D_PLUGIN P3D_initialize_func P3D_initialize;
 EXPCL_P3D_PLUGIN P3D_finalize_func P3D_finalize;
+EXPCL_P3D_PLUGIN P3D_set_super_mirror_func P3D_set_super_mirror;
 
 EXPCL_P3D_PLUGIN P3D_new_instance_func P3D_new_instance;
 EXPCL_P3D_PLUGIN P3D_instance_start_func P3D_instance_start;

+ 76 - 10
direct/src/plugin_standalone/panda3d.cxx

@@ -22,6 +22,7 @@
 // definition, even though we don't link with dtool.
 #include "dtool_platform.h"
 
+#include <ctype.h>
 #include <sstream>
 #ifdef _WIN32
 #include <windows.h>
@@ -66,10 +67,11 @@ run(int argc, char *argv[]) {
   // We prefix a "+" sign to tell gnu getopt not to parse options
   // following the first not-option parameter.  (These will be passed
   // into the sub-process.)
-  const char *optstr = "+mu:p:fw:t:s:o:l:ih";
+  const char *optstr = "+mu:M:p:fw:t:s:o:l:ih";
 
   bool allow_multiple = false;
   string download_url = PANDA_PACKAGE_HOST_URL;
+  string super_mirror_url;
   string this_platform = DTOOL_PLATFORM;
   bool verify_contents = false;
 
@@ -89,6 +91,10 @@ run(int argc, char *argv[]) {
       download_url = optarg;
       break;
 
+    case 'M':
+      super_mirror_url = optarg;
+      break;
+
     case 'p':
       this_platform = optarg;
       break;
@@ -181,16 +187,36 @@ run(int argc, char *argv[]) {
     return 1;
   }
 
-  // Make sure it ends with a slash.
+  // Make sure the download URL ends with a slash.
   if (!download_url.empty() && download_url[download_url.length() - 1] != '/') {
     download_url += '/';
   }
 
+  // If the "super mirror" URL is a filename, convert it to a file:// url.
+  if (!super_mirror_url.empty()) {
+    if (!is_url(super_mirror_url)) {
+      Filename filename = Filename::from_os_specific(super_mirror_url);
+      filename.make_absolute();
+      string path = filename.to_os_generic();
+      if (!path.empty() && path[0] != '/') {
+        // On Windows, a leading drive letter must be preceded by an
+        // additional slash.
+        path = "/" + path;
+      }
+      super_mirror_url = "file://" + path;
+    }
+  }
+
   if (!get_plugin(download_url, this_platform, verify_contents)) {
     cerr << "Unable to load Panda3D plugin.\n";
     return 1;
   }
 
+  // Set up the "super mirror" URL, if specified.
+  if (!super_mirror_url.empty()) {
+    P3D_set_super_mirror(super_mirror_url.c_str());
+  }
+
   int num_instance_filenames, num_instance_args;
   char **instance_filenames, **instance_args;
 
@@ -682,16 +708,14 @@ P3D_instance *Panda3D::
 create_instance(const string &p3d, P3D_window_type window_type,
                 int win_x, int win_y, int win_width, int win_height,
                 P3D_window_handle parent_window, char **args, int num_args) {
-  // If the supplied parameter name is a real file, pass it in on the
-  // parameter list.  Otherwise, assume it's a URL and let the plugin
-  // download it.
+  // Check to see if the p3d filename we were given is a URL, or a
+  // local file.
   Filename p3d_filename = Filename::from_os_specific(p3d);
   string os_p3d_filename = p3d;
-  bool is_local = false;
-  if (p3d_filename.exists()) {
+  bool is_local = !is_url(p3d);
+  if (is_local) {
     p3d_filename.make_absolute();
     os_p3d_filename = p3d_filename.to_os_specific();
-    is_local = true;
   } 
 
   // Build up the token list.
@@ -832,8 +856,17 @@ usage() {
     << "    code.\n\n"
 
     << "  -u url\n"
-    << "    Specify the URL of the Panda3D download server.  The default is\n"
-    << "    \"" << PANDA_PACKAGE_HOST_URL << "\" .\n\n"
+
+    << "    Specify the URL of the Panda3D download server.  This is the host\n"
+    << "    from which the plugin itself will be downloaded if necessary.  The\n"
+    << "    default is\n \"" << PANDA_PACKAGE_HOST_URL << "\" .\n\n"
+
+    << "  -M super_mirror_url\n"
+    << "    Specifies the \"super mirror\" URL, the special URL that is consulted\n"
+    << "    first before downloading any package file referenced by a p3d file.\n"
+    << "    This is primarily intended to support pre-installing a downloadable\n"
+    << "    Panda3D tree on the local machine, to allow p3d applications to\n"
+    << "    execute without requiring an internet connection.\n\n"
 
     << "  -p platform\n"
     << "    Specify the platform to masquerade as.  The default is \""
@@ -888,6 +921,39 @@ parse_int_pair(char *arg, int &x, int &y) {
   return false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Panda3D::is_url
+//       Access: Private, Static
+//  Description: Returns true if the indicated string appears to be a
+//               URL, with a leading http:// or file:// or whatever,
+//               or false if it must be a local filename instead.
+////////////////////////////////////////////////////////////////////
+bool Panda3D::
+is_url(const string &param) {
+  // We define a URL prefix as a sequence of at least two letters,
+  // followed by a colon, followed by at least one slash.
+  size_t p = 0;
+  while (p < param.size() && isalpha(param[p])) {
+    ++p;
+  }
+  if (p < 2) {
+    // Not enough letters.
+    return false;
+  }
+  if (p >= param.size() || param[p] != ':') {
+    // No colon.
+    return false;
+  }
+  ++p;
+  if (p >= param.size() || param[p] != '/') {
+    // No slash.
+    return false;
+  }
+
+  // It matches the rules.
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Panda3D::report_downloading_package
 //       Access: Private

+ 1 - 0
direct/src/plugin_standalone/panda3d.h

@@ -65,6 +65,7 @@ private:
   void usage();
   bool parse_token(char *arg);
   bool parse_int_pair(char *arg, int &x, int &y);
+  static bool is_url(const string &param);
 
   void report_downloading_package(P3D_instance *instance);
   void report_download_complete(P3D_instance *instance);

+ 2 - 0
direct/src/showutil/FreezeTool.py

@@ -786,6 +786,8 @@ class Freezer:
                 continue
             if origName in self.previousModules:
                 continue
+            if origName in self.modules:
+                continue
 
             # This module is missing.  Let it be missing in the
             # runtime also.