no command instance

This commit is contained in:
David Rose 2009-06-24 00:52:57 +00:00
parent 0cce656d0b
commit a6c1759080
8 changed files with 248 additions and 68 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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