Sfoglia il codice sorgente

no command instance

David Rose 16 anni fa
parent
commit
a6c1759080

+ 26 - 0
direct/src/plugin/p3dInstance.cxx

@@ -16,8 +16,10 @@
 #include "p3dInstanceManager.h"
 #include "p3dDownload.h"
 #include "p3dSession.h"
+#include "p3dPackage.h"
 
 #include <sstream>
+#include <algorithm>
 
 int P3DInstance::_next_instance_id = 0;
 
@@ -61,6 +63,14 @@ P3DInstance::
 
   DESTROY_LOCK(_request_lock);
 
+  // Tell all of the packages that we're no longer in business for
+  // them.
+  Packages::iterator pi;
+  for (pi = _packages.begin(); pi != _packages.end(); ++pi) {
+    (*pi)->cancel_instance(this);
+  }
+  _packages.clear();
+
   // TODO: empty _pending_requests queue and _downloads map.
 
   // TODO: Is it possible for someone to delete an instance while a
@@ -239,6 +249,22 @@ feed_url_stream(int unique_id,
   return download_ok;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstance::add_package
+//       Access: Public
+//  Description: Adds the package to the list of packages used by this
+//               instance.  The instance will share responsibility for
+//               downloading the package will any of the other
+//               instances that use the same package.
+////////////////////////////////////////////////////////////////////
+void P3DInstance::
+add_package(P3DPackage *package) {
+  assert(find(_packages.begin(), _packages.end(), package) == _packages.end());
+
+  _packages.push_back(package);
+  package->set_instance(this);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstance::start_download
 //       Access: Public

+ 6 - 0
direct/src/plugin/p3dInstance.h

@@ -26,6 +26,7 @@
 
 class P3DSession;
 class P3DDownload;
+class P3DPackage;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : P3DInstance
@@ -64,6 +65,8 @@ public:
   inline const string &get_session_key() const;
   inline const string &get_python_version() const;
 
+  void add_package(P3DPackage *package);
+  
   void start_download(P3DDownload *download);
   void request_stop();
 
@@ -80,6 +83,9 @@ private:
   string _python_version;
   P3DSession *_session;
 
+  typedef vector<P3DPackage *> Packages;
+  Packages _packages;
+
   typedef map<int, P3DDownload *> Downloads;
   Downloads _downloads;
 

+ 21 - 14
direct/src/plugin/p3dInstanceManager.I

@@ -60,20 +60,6 @@ get_platform() const {
   return _platform;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: P3DInstanceManager::get_command_instance
-//       Access: Public
-//  Description: Returns a global P3DInstance object that exists for
-//               the lifetime of the instance manager.  This instance
-//               object has no reality onscreen, but can be used as a
-//               download host for downloading files that aren't
-//               specifically needed by any user-created instance.
-////////////////////////////////////////////////////////////////////
-inline P3DInstance *P3DInstanceManager::
-get_command_instance() const {
-  return _command_instance;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstanceManager::get_num_instances
 //       Access: Public
@@ -84,3 +70,24 @@ inline int P3DInstanceManager::
 get_num_instances() const {
   return _instances.size();
 }
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstanceManager::is_pathsep
+//       Access: Private, Static
+//  Description: Returns true if the indicated character is a path
+//               separator character (e.g. slash or backslash), false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+inline bool P3DInstanceManager::
+is_pathsep(char ch) {
+  if (ch == '/') {
+    return true;
+  }
+#ifdef _WIN32
+  if (ch == '\\') {
+    return true;
+  }
+#endif
+  return false;
+}

+ 93 - 30
direct/src/plugin/p3dInstanceManager.cxx

@@ -54,8 +54,6 @@ P3DInstanceManager() {
   icc.dwICC = ICC_PROGRESS_CLASS;
   InitCommonControlsEx(&icc);
 #endif
-
-  _command_instance = NULL;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -71,8 +69,6 @@ P3DInstanceManager::
   assert(_instances.empty());
   assert(_sessions.empty());
 
-  delete _command_instance;
-
 #ifdef _WIN32
   CloseHandle(_request_ready);
 #else
@@ -145,8 +141,6 @@ create_instance(P3D_request_ready_func *func,
 ////////////////////////////////////////////////////////////////////
 void P3DInstanceManager::
 finish_instance(P3DInstance *inst) {
-  assert(inst != _command_instance);
-
   Instances::iterator ii;
   ii = _instances.find(inst);
   assert(ii != _instances.end());
@@ -183,10 +177,6 @@ check_request() {
     }
   }
 
-  if (_command_instance->has_request()) {
-    return _command_instance;
-  }
-
   return NULL;
 }
 
@@ -290,9 +280,11 @@ signal_request_ready() {
 //     Function: P3DInstanceManager::mkdir_public
 //       Access: Public, Static
 //  Description: Creates a new directory with wide-open access
-//               priviledges.
+//               priviledges.  Returns true on success, false on
+//               failure.  Will create intervening directories if
+//               necessary.
 ////////////////////////////////////////////////////////////////////
-void P3DInstanceManager::
+bool P3DInstanceManager::
 mkdir_public(const string &dirname) {
 #ifdef _WIN32
   SECURITY_DESCRIPTOR sd;
@@ -302,10 +294,55 @@ mkdir_public(const string &dirname) {
   SECURITY_ATTRIBUTES sa;
   sa.nLength = sizeof(sa);
   sa.lpSecurityDescriptor = &sd;
-  CreateDirectory(dirname.c_str(), &sa);
+  if (CreateDirectory(dirname.c_str(), &sa) != 0) {
+    // Success!
+    return true;
+  }
+
+  // Failed.
+  DWORD last_error = GetLastError();
+  if (last_error == ERROR_ALREADY_EXISTS) {
+    // Not really an error: the directory is already there.
+    return true;
+  }
+
+  if (last_error == ERROR_PATH_NOT_FOUND) {
+    // We need to make the parent directory first.
+    string parent = get_dirname(dirname);
+    if (!parent.empty() && mkdir_public(parent)) {
+      // Parent successfully created.  Try again to make the child.
+      if (CreateDirectory(dirname.c_str(), &sa) != 0) {
+        // Got it!
+        return true;
+      }
+    }
+  }
+  return false;
 
 #else  //_WIN32
-  mkdir(dirname.c_str(), 0777);
+  if (mkdir(dirname.c_str(), 0777) == 0) {
+    // Success!
+    return true;
+  }
+
+  // Failed.
+  if (errno == EEXIST) {
+    // Not really an error: the directory is already there.
+    return true;
+  }
+
+  if (errno == ENOENT) {
+    // We need to make the parent directory first.
+    string parent = get_dirname(dirname);
+    if (!parent.empty() && mkdir_public(parent)) {
+      // Parent successfully created.  Try again to make the child.
+      if (mkdir(dirname.c_str(), 0777) == 0) {
+        // Got it!
+        return true;
+      }
+    }
+  }
+  return false;
 
 #endif  // _WIN32
 }
@@ -314,7 +351,9 @@ mkdir_public(const string &dirname) {
 //     Function: P3DInstanceManager::mkfile_public
 //       Access: Public, Static
 //  Description: Creates a new file with wide-open access
-//               priviledges.
+//               priviledges.  Returns true on success, false on
+//               failure.  This will create intervening directories if
+//               needed.
 ////////////////////////////////////////////////////////////////////
 bool P3DInstanceManager::
 mkfile_public(const string &filename) {
@@ -331,7 +370,17 @@ mkfile_public(const string &filename) {
                            FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
                            &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
   if (file == INVALID_HANDLE_VALUE) {
-    return false;
+    // Try to make the parent directory first.
+    string parent = get_dirname(filename);
+    if (!parent.empty() && mkdir_public(parent)) {
+      // Parent successfully created.  Try again to make the file.
+      file = CreateFile(filename.c_str(), GENERIC_READ | GENERIC_WRITE,
+                        FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+                        &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+    }
+    if (file == INVALID_HANDLE_VALUE) {
+      return false;
+    }
   }
   CloseHandle(file);
   return true;
@@ -339,7 +388,15 @@ mkfile_public(const string &filename) {
 #else  // _WIN32
   int fd = creat(filename.c_str(), 0777);
   if (fd == -1) {
-    return false;
+    // Try to make the parent directory first.
+    string parent = get_dirname(filename);
+    if (!parent.empty() && mkdir_public(parent)) {
+      // Parent successfully created.  Try again to make the file.
+      fd = creat(filename.c_str(), 0777);
+    }
+    if (fd == -1) {
+      return false;
+    }
   }
   close(fd);
   return true;
@@ -356,23 +413,10 @@ P3DInstanceManager *P3DInstanceManager::
 get_global_ptr() {
   if (_global_ptr == NULL) {
     _global_ptr = new P3DInstanceManager;
-    _global_ptr->create_command_instance();
   }
   return _global_ptr;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: P3DInstanceManager::create_command_instance;
-//       Access: Private
-//  Description: Create a command instance.  This is used to handle
-//               requests that have nothing to do with any particular
-//               host-created instance.
-////////////////////////////////////////////////////////////////////
-void P3DInstanceManager::
-create_command_instance() {
-  _command_instance = new P3DInstance(NULL, "", NULL, 0);
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstanceManager::find_root_dir
 //       Access: Private
@@ -488,4 +532,23 @@ find_root_dir() const {
 #endif
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstanceManager::get_dirname
+//       Access: Private, Static
+//  Description: Returns the directory component of the indicated
+//               pathname, or the empty string if there is no
+//               directory prefix.
+////////////////////////////////////////////////////////////////////
+string P3DInstanceManager::
+get_dirname(const string &filename) {
+  size_t p = filename.length();
+  while (p > 0) {
+    --p;
+    if (is_pathsep(filename[p])) {
+      return filename.substr(0, p);
+    }
+  }
+
+  return string();
+}
 

+ 3 - 5
direct/src/plugin/p3dInstanceManager.h

@@ -58,20 +58,20 @@ public:
                           const string &package_version,
                           const string &package_display_name);
 
-  inline P3DInstance *get_command_instance() const;
   inline int get_num_instances() const;
 
   int get_unique_session_index();
   void signal_request_ready();
 
-  static void mkdir_public(const string &dirname);
+  static bool mkdir_public(const string &dirname);
   static bool mkfile_public(const string &dirname);
 
   static P3DInstanceManager *get_global_ptr();
 
 private:
-  void create_command_instance();
   string find_root_dir() const;
+  static inline bool is_pathsep(char ch);
+  static string get_dirname(const string &filename);
 
 private:
   bool _is_initialized;
@@ -79,8 +79,6 @@ private:
   string _download_url;
   string _platform;
 
-  P3DInstance *_command_instance;
-
   typedef set<P3DInstance *> Instances;
   Instances _instances;
 

+ 88 - 19
direct/src/plugin/p3dPackage.cxx

@@ -14,6 +14,7 @@
 
 #include "p3dPackage.h"
 #include "p3dInstanceManager.h"
+#include "p3dInstance.h"
 #include "p3dMultifileReader.h"
 
 #include "openssl/md5.h"
@@ -81,23 +82,6 @@ P3DPackage(const string &package_name, const string &package_version,
 
   _desc_file_basename = _package_fullname + ".xml";
   _desc_file_pathname = _package_dir + "/" + _desc_file_basename;
-  
-  // TODO: we should check the desc file for updates with the server.
-  // Perhaps this should be done in a parent class.
-
-  // TODO: if the desc file exists, and is consistent with the server
-  // contents file, don't re-download it.
-  /*
-  // Load the desc file, if it exists.
-  TiXmlDocument doc(_desc_file_pathname.c_str());
-  if (!doc.LoadFile()) {
-    download_desc_file();
-  } else {
-    got_desc_file(&doc, false);
-  }
-  */
-
-  download_desc_file();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -116,6 +100,8 @@ P3DPackage::
     delete _active_download;
     _active_download = NULL;
   }
+
+  assert(_instances.empty());
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -155,6 +141,87 @@ cancel_callback(Callback *callback) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPackage::set_instance
+//       Access: Public
+//  Description: Specifies an instance that may be responsible for
+//               downloading this package.
+////////////////////////////////////////////////////////////////////
+void P3DPackage::
+set_instance(P3DInstance *inst) {
+  _instances.push_back(inst);
+
+  begin_download();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPackage::cancel_instance
+//       Access: Public
+//  Description: Indicates that the given instance will no longer be
+//               responsible for downloading this package.
+////////////////////////////////////////////////////////////////////
+void P3DPackage::
+cancel_instance(P3DInstance *inst) {
+  assert(!_instances.empty());
+
+  if (inst == _instances[0]) {
+    // This was the primary instance.  Cancel any pending download and
+    // move to the next instance.
+    if (_active_download != NULL) {
+      _active_download->cancel();
+      delete _active_download;
+      _active_download = NULL;
+    }
+  }
+
+  Instances::iterator ii = find(_instances.begin(), _instances.end(), inst);
+  assert(ii != _instances.end());
+  _instances.erase(ii);
+
+  begin_download();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPackage::begin_download
+//       Access: Public
+//  Description: Begins downloading and installing the package, if
+//               needed.
+////////////////////////////////////////////////////////////////////
+void P3DPackage::
+begin_download() {  
+  if (_instances.empty()) {
+    // Can't download without any instances.
+    return;
+  }
+
+  if (_ready) {
+    // Already downloaded.
+    return;
+  }
+
+  if (_active_download != NULL) {
+    // In the middle of downloading.
+    return;
+  }
+
+  // TODO: we should check the desc file for updates with the server.
+  // Perhaps this should be done in a parent class.
+
+  // TODO: if the desc file exists, and is consistent with the server
+  // contents file, don't re-download it.
+  /*
+  // Load the desc file, if it exists.
+  TiXmlDocument doc(_desc_file_pathname.c_str());
+  if (!doc.LoadFile()) {
+    download_desc_file();
+  } else {
+    got_desc_file(&doc, false);
+  }
+  */
+
+  download_desc_file();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DPackage::download_desc_file
 //       Access: Private
@@ -554,8 +621,10 @@ start_download(P3DPackage::DownloadType dtype, const string &url,
 
   _active_download = download;
   _partial_download = false;
-  P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
-  inst_mgr->get_command_instance()->start_download(download);
+
+  assert(!_instances.empty());
+
+  _instances[0]->start_download(download);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 9 - 0
direct/src/plugin/p3dPackage.h

@@ -18,6 +18,8 @@
 #include "p3d_plugin_common.h"
 #include "p3dFileDownload.h"
 
+class P3DInstance;
+
 ////////////////////////////////////////////////////////////////////
 //       Class : P3DPackage
 // Description : This corresponds to a downloadable, patchable
@@ -54,6 +56,9 @@ public:
   void set_callback(Callback *callback);
   void cancel_callback(Callback *callback);
 
+  void set_instance(P3DInstance *inst);
+  void cancel_instance(P3DInstance *inst);
+
 private:
   enum DownloadType {
     DT_desc_file,
@@ -73,6 +78,7 @@ private:
     DownloadType _dtype;
   };
 
+  void begin_download();
   void download_desc_file();
   void desc_file_download_finished(bool success);
   void got_desc_file(TiXmlDocument *doc, bool freshly_downloaded);
@@ -115,6 +121,9 @@ private:
   typedef vector<Callback *> Callbacks;
   Callbacks _callbacks;
 
+  typedef vector<P3DInstance *> Instances;
+  Instances _instances;
+
   enum { hash_size = 16 };
 
   class FileSpec {

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

@@ -52,6 +52,8 @@ P3DSession(P3DInstance *inst) {
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
 
   _panda3d = inst_mgr->get_package("panda3d", "dev", "Panda3D");
+  inst->add_package(_panda3d);
+
   _panda3d_callback = NULL;
   _python_root_dir = _panda3d->get_package_dir();