better download rules

This commit is contained in:
David Rose 2009-07-29 19:58:26 +00:00
parent ee47d35695
commit 7293844e4a
23 changed files with 548 additions and 249 deletions

View File

@ -123,7 +123,8 @@ static void unload_dso();
// path.
////////////////////////////////////////////////////////////////////
bool
load_plugin(const string &p3d_plugin_filename) {
load_plugin(const string &p3d_plugin_filename,
const string &contents_filename) {
string filename = p3d_plugin_filename;
if (filename.empty()) {
// Look for the plugin along the path.
@ -292,26 +293,7 @@ load_plugin(const string &p3d_plugin_filename) {
// Successfully loaded.
plugin_loaded = true;
#ifdef P3D_PLUGIN_LOGFILE2
string logfilename = P3D_PLUGIN_LOGFILE2;
#else
string logfilename;
#endif // P3D_PLUGIN_LOGFILE2
if (logfilename.empty()) {
#ifdef _WIN32
static const size_t buffer_size = 4096;
char buffer[buffer_size];
if (GetTempPath(buffer_size, buffer) != 0) {
logfilename = buffer;
logfilename += "panda3d.2.log";
}
#else
logfilename = "/tmp/panda3d.2.log";
#endif // _WIN32
}
if (!P3D_initialize(P3D_API_VERSION, logfilename.c_str())) {
if (!P3D_initialize(P3D_API_VERSION, contents_filename.c_str())) {
// Oops, failure to initialize.
cerr << "Failed to initialize plugin (wrong API version?)\n";
unload_plugin();

View File

@ -58,7 +58,8 @@ extern P3D_instance_feed_url_stream_func *P3D_instance_feed_url_stream;
extern P3D_instance_handle_event_func *P3D_instance_handle_event;
string get_plugin_basename();
bool load_plugin(const string &p3d_plugin_filename);
bool load_plugin(const string &p3d_plugin_filename,
const string &contents_filename);
void unload_plugin();
bool is_plugin_loaded();

View File

@ -54,9 +54,9 @@ class ContentsMaker:
print >> f, '<?xml version="1.0" ?>'
print >> f, ''
print >> f, '<contents>'
for packageName, packageVersion, packagePlatform, file in self.packages:
print >> f, ' <package name="%s" version="%s" platform="%s" %s />' % (
packageName, packageVersion, packagePlatform or '', file.getParams())
for packageName, packagePlatform, packageVersion, file in self.packages:
print >> f, ' <package name="%s" platform="%s" version="%s" %s />' % (
packageName, packagePlatform or '', packageVersion, file.getParams())
print >> f, '</contents>'
f.close()
@ -93,14 +93,14 @@ class ContentsMaker:
file = FileSpec(localpath + xml,
Filename(self.stageDir, localpath + xml))
print file.filename
self.packages.append((packageName, packageVersion, packagePlatform, file))
self.packages.append((packageName, packagePlatform, packageVersion, file))
if localpath.count('/') == 3:
packageName, packageVersion, packagePlatform, junk = localpath.split('/')
packageName, packagePlatform, packageVersion, junk = localpath.split('/')
file = FileSpec(localpath + xml,
Filename(self.stageDir, localpath + xml))
print file.filename
self.packages.append((packageName, packageVersion, packagePlatform, file))
self.packages.append((packageName, packagePlatform, packageVersion, file))
def makeContents(args):

View File

@ -77,8 +77,9 @@ class PackageMaker:
self.packageStageDir = Filename(self.stageDir, '%s/%s' % (self.packageName, self.packageVersion))
if self.packagePlatform:
self.packageFullname += '_%s' % (self.packagePlatform)
self.packageStageDir = Filename(self.packageStageDir, self.packagePlatform)
self.packageFullname = '%s_%s_%s' % (
self.packageName, self.packagePlatform, self.packageVersion)
self.packageStageDir = Filename(self.stageDir, '%s/%s/%s' % (self.packageName, self.packagePlatform, self.packageVersion))
Filename(self.packageStageDir, '.').makeDir()
self.cleanDir(self.packageStageDir)
@ -121,7 +122,7 @@ class PackageMaker:
f = open(descFilePathname.toOsSpecific(), 'w')
print >> f, '<?xml version="1.0" ?>'
print >> f, ''
print >> f, '<package name="%s" version="%s" platform="%s">' % (self.packageName, self.packageVersion, self.packagePlatform or '')
print >> f, '<package name="%s" platform="%s" version="%s">' % (self.packageName, self.packagePlatform or '', self.packageVersion)
print >> f, ' <uncompressed_archive %s />' % (uncompressedArchive.getParams())
print >> f, ' <compressed_archive %s />' % (compressedArchive.getParams())
for file in self.components:
@ -209,9 +210,9 @@ def makePackage(args):
if len(tokens) >= 1:
pm.packageName = tokens[0]
if len(tokens) >= 2:
pm.packageVersion = tokens[1]
if len(tokens) >= 3:
pm.packagePlatform = tokens[2]
if len(tokens) >= 3:
pm.packageVersion = tokens[1]
if len(tokens) >= 4:
raise ArgumentError, 'Too many tokens in string: %s' % (value)

View File

@ -85,7 +85,7 @@ mkdir_complete(const string &dirname, ostream &logfile) {
return false;
#else //_WIN32
if (mkdir(dirname.c_str(), 0777) == 0) {
if (mkdir(dirname.c_str(), 0755) == 0) {
// Success!
return true;
}
@ -101,7 +101,7 @@ mkdir_complete(const string &dirname, ostream &logfile) {
string parent = get_dirname(dirname);
if (!parent.empty() && mkdir_complete(parent, logfile)) {
// Parent successfully created. Try again to make the child.
if (mkdir(dirname.c_str(), 0777) == 0) {
if (mkdir(dirname.c_str(), 0755) == 0) {
// Got it!
return true;
}
@ -147,13 +147,13 @@ mkfile_complete(const string &filename, ostream &logfile) {
return true;
#else // _WIN32
int fd = creat(filename.c_str(), 0777);
int fd = creat(filename.c_str(), 0755);
if (fd == -1) {
// Try to make the parent directory first.
string parent = get_dirname(filename);
if (!parent.empty() && mkdir_complete(parent, logfile)) {
// Parent successfully created. Try again to make the file.
fd = creat(filename.c_str(), 0777);
fd = creat(filename.c_str(), 0755);
}
if (fd == -1) {
logfile

View File

@ -131,6 +131,8 @@ download_progress() {
if (now != _last_reported_time || true) {
_last_reported_time = now;
}
nout << "Downloading " << get_url() << ": "
<< int(get_download_progress() * 1000.0) / 10.0 << "\n";
}
////////////////////////////////////////////////////////////////////
@ -143,6 +145,6 @@ download_progress() {
////////////////////////////////////////////////////////////////////
void P3DDownload::
download_finished(bool success) {
nout << "Downloading " << get_url() << ": "
nout << "Downloaded " << get_url() << ": "
<< int(get_download_progress() * 1000.0) / 10.0 << "\n";
}

View File

@ -25,15 +25,47 @@ P3DFileParams() {
}
////////////////////////////////////////////////////////////////////
// Function: P3DFileParams::Constructor
// Function: P3DFileParams::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
P3DFileParams::
P3DFileParams(const string &p3d_filename,
const P3D_token tokens[], size_t num_tokens) :
_p3d_filename(p3d_filename)
P3DFileParams(const P3DFileParams &copy) :
_p3d_filename(copy._p3d_filename),
_tokens(copy._tokens)
{
}
////////////////////////////////////////////////////////////////////
// Function: P3DFileParams::Copy Assignment
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void P3DFileParams::
operator = (const P3DFileParams &other) {
_p3d_filename = other._p3d_filename;
_tokens = other._tokens;
}
////////////////////////////////////////////////////////////////////
// Function: P3DFileParams::set_p3d_filename
// Access: Public
// Description: Specifies the file that contains the instance data.
////////////////////////////////////////////////////////////////////
void P3DFileParams::
set_p3d_filename(const string &p3d_filename) {
_p3d_filename = p3d_filename;
}
////////////////////////////////////////////////////////////////////
// Function: P3DFileParams::set_tokens
// Access: Public
// Description: Specifies the tokens associated with the instance.
////////////////////////////////////////////////////////////////////
void P3DFileParams::
set_tokens(const P3D_token tokens[], size_t num_tokens) {
_tokens.clear();
for (size_t i = 0; i < num_tokens; ++i) {
Token token;
if (tokens[i]._keyword != NULL) {
@ -50,17 +82,6 @@ P3DFileParams(const string &p3d_filename,
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DFileParams::Copy Assignment
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void P3DFileParams::
operator = (const P3DFileParams &other) {
_p3d_filename = other._p3d_filename;
_tokens = other._tokens;
}
////////////////////////////////////////////////////////////////////
// Function: P3DFileParams::lookup_token
// Access: Public

View File

@ -27,11 +27,12 @@
class P3DFileParams {
public:
P3DFileParams();
P3DFileParams(const string &p3d_filename,
const P3D_token tokens[], size_t num_tokens);
P3DFileParams(const P3DFileParams &copy);
void operator = (const P3DFileParams &other);
void set_p3d_filename(const string &p3d_filename);
void set_tokens(const P3D_token tokens[], size_t num_tokens);
inline const string &get_p3d_filename() const;
string lookup_token(const string &keyword) const;
bool has_token(const string &keyword) const;

View File

@ -49,7 +49,8 @@ typedef P3DSplashWindow SplashWindowType;
// Description:
////////////////////////////////////////////////////////////////////
P3DInstance::
P3DInstance(P3D_request_ready_func *func, void *user_data) :
P3DInstance(P3D_request_ready_func *func,
const P3D_token tokens[], size_t num_tokens, void *user_data) :
_func(func)
{
_browser_script_object = NULL;
@ -59,6 +60,8 @@ P3DInstance(P3D_request_ready_func *func, void *user_data) :
_got_fparams = false;
_got_wparams = false;
_fparams.set_tokens(tokens, num_tokens);
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
_instance_id = inst_mgr->get_unique_id();
@ -137,16 +140,17 @@ P3DInstance::
// download is still running? Who will crash when this happens?
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstance::set_fparams
// Function: P3DInstance::set_p3d_filename
// Access: Public
// Description: Sets up the initial file parameters for the instance.
// Description: Specifies the file that contains the instance data.
// Normally this is only called once.
////////////////////////////////////////////////////////////////////
void P3DInstance::
set_fparams(const P3DFileParams &fparams) {
set_p3d_filename(const string &p3d_filename) {
_got_fparams = true;
_fparams = fparams;
_fparams.set_p3d_filename(p3d_filename);
// This also sets up some internal data based on the contents of the
// above file and the associated tokens.
@ -176,13 +180,6 @@ set_fparams(const P3DFileParams &fparams) {
P3D_object *result = P3D_OBJECT_EVAL(_browser_script_object, expression.c_str());
P3D_OBJECT_XDECREF(result);
}
// Maybe create the splash window.
if (!_instance_window_opened && _got_wparams) {
if (_splash_window == NULL) {
make_splash_window();
}
}
}
////////////////////////////////////////////////////////////////////
@ -198,7 +195,7 @@ set_wparams(const P3DWindowParams &wparams) {
_wparams = wparams;
// Update or create the splash window.
if (!_instance_window_opened && _got_fparams) {
if (!_instance_window_opened) {
if (_splash_window == NULL) {
make_splash_window();
}

View File

@ -44,10 +44,11 @@ class P3DToplevelObject;
////////////////////////////////////////////////////////////////////
class P3DInstance : public P3D_instance, public P3DReferenceCount {
public:
P3DInstance(P3D_request_ready_func *func, void *user_data);
P3DInstance(P3D_request_ready_func *func,
const P3D_token tokens[], size_t num_tokens, void *user_data);
~P3DInstance();
void set_fparams(const P3DFileParams &fparams);
void set_p3d_filename(const string &p3d_filename);
inline const P3DFileParams &get_fparams() const;
void set_wparams(const P3DWindowParams &wparams);

View File

@ -60,6 +60,17 @@ get_platform() const {
return _platform;
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::has_contents_file
// Access: Public
// Description: Returns true if a contents.xml file has been
// successfully read, false otherwise.
////////////////////////////////////////////////////////////////////
inline bool P3DInstanceManager::
has_contents_file() const {
return (_xcontents != NULL);
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::get_num_instances
// Access: Public

View File

@ -22,6 +22,9 @@
#include "p3dNoneObject.h"
#include "p3dBoolObject.h"
#include "find_root_dir.h"
#include "mkdir_complete.h"
#include "fileSpec.h"
#include "get_tinyxml.h"
#ifdef _WIN32
#include <shlobj.h>
@ -40,6 +43,7 @@ P3DInstanceManager::
P3DInstanceManager() {
_is_initialized = false;
_unique_id = 0;
_xcontents = NULL;
_notify_thread_continue = false;
_started_notify_thread = false;
@ -77,6 +81,10 @@ P3DInstanceManager::
_started_notify_thread = false;
}
if (_xcontents != NULL) {
delete _xcontents;
}
assert(_instances.empty());
assert(_sessions.empty());
@ -112,13 +120,14 @@ P3DInstanceManager::
// redownloaded.
////////////////////////////////////////////////////////////////////
bool P3DInstanceManager::
initialize() {
initialize(const string &contents_filename) {
_root_dir = find_root_dir();
_download_url = P3D_PLUGIN_DOWNLOAD;
_platform = P3D_PLUGIN_PLATFORM;
nout << "_root_dir = " << _root_dir << ", download = "
<< _download_url << "\n";
nout << "_root_dir = " << _root_dir
<< ", download = " << _download_url
<< ", contents = " << contents_filename << "\n";
if (_root_dir.empty()) {
nout << "Could not find root directory.\n";
@ -127,6 +136,47 @@ initialize() {
_is_initialized = true;
// Attempt to read the supplied contents.xml file.
if (!contents_filename.empty()) {
if (!read_contents_file(contents_filename)) {
nout << "Couldn't read " << contents_filename << "\n";
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::read_contents_file
// Access: Public
// Description: Reads the contents.xml file in the indicated
// filename. On success, copies the contents.xml file
// into the standard location.
//
// Returns true on success, false on failure.
////////////////////////////////////////////////////////////////////
bool P3DInstanceManager::
read_contents_file(const string &contents_filename) {
TiXmlDocument doc(contents_filename.c_str());
if (!doc.LoadFile()) {
return false;
}
TiXmlElement *xcontents = doc.FirstChildElement("contents");
if (xcontents == NULL) {
return false;
}
if (_xcontents != NULL) {
delete _xcontents;
}
_xcontents = (TiXmlElement *)xcontents->Clone();
string standard_filename = _root_dir + "/contents.xml";
if (standard_filename != contents_filename) {
copy_file(contents_filename, standard_filename);
}
return true;
}
@ -137,8 +187,10 @@ initialize() {
// indicated startup information.
////////////////////////////////////////////////////////////////////
P3DInstance *P3DInstanceManager::
create_instance(P3D_request_ready_func *func, void *user_data) {
P3DInstance *inst = new P3DInstance(func, user_data);
create_instance(P3D_request_ready_func *func,
const P3D_token tokens[], size_t num_tokens,
void *user_data) {
P3DInstance *inst = new P3DInstance(func, tokens, num_tokens, user_data);
inst->ref();
_instances.insert(inst);
@ -154,13 +206,12 @@ create_instance(P3D_request_ready_func *func, void *user_data) {
// particular instance.
////////////////////////////////////////////////////////////////////
bool P3DInstanceManager::
start_instance(P3DInstance *inst, const string &p3d_filename,
const P3D_token tokens[], size_t num_tokens) {
start_instance(P3DInstance *inst, const string &p3d_filename) {
if (inst->is_started()) {
nout << "Instance started twice: " << inst << "\n";
return false;
}
inst->set_fparams(P3DFileParams(p3d_filename, tokens, num_tokens));
inst->set_p3d_filename(p3d_filename);
P3DSession *session;
Sessions::iterator si = _sessions.find(inst->get_session_key());
@ -192,7 +243,7 @@ finish_instance(P3DInstance *inst) {
_instances.erase(ii);
Sessions::iterator si = _sessions.find(inst->get_session_key());
assert(si != _sessions.end());
if (si != _sessions.end()) {
P3DSession *session = (*si).second;
session->terminate_instance(inst);
@ -203,6 +254,7 @@ finish_instance(P3DInstance *inst) {
session->shutdown();
unref_delete(session);
}
}
unref_delete(inst);
}
@ -284,20 +336,61 @@ P3DPackage *P3DInstanceManager::
get_package(const string &package_name, const string &package_version,
const string &package_display_name) {
string package_platform = get_platform();
string key = package_name + "_" + package_version + "_" + package_platform;
string key = package_name + "_" + package_platform + "_" + package_version;
Packages::iterator pi = _packages.find(key);
if (pi != _packages.end()) {
return (*pi).second;
}
P3DPackage *package = new P3DPackage(package_name, package_version,
package_platform, package_display_name);
P3DPackage *package = new P3DPackage(package_name, package_platform,
package_version, package_display_name);
bool inserted = _packages.insert(Packages::value_type(key, package)).second;
assert(inserted);
return package;
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::get_package_desc_file
// Access: Public
// Description: Fills the indicated FileSpec with the hash
// information for the package's desc file. Returns
// true if successful, false if the package is unknown.
// This requires has_contents_file() to return true in
// order to be successful.
////////////////////////////////////////////////////////////////////
bool P3DInstanceManager::
get_package_desc_file(FileSpec &desc_file,
const string &package_name,
const string &package_version) {
if (_xcontents == NULL) {
return false;
}
string package_platform = get_platform();
// Scan the contents data for the indicated package.
TiXmlElement *xpackage = _xcontents->FirstChildElement("package");
while (xpackage != NULL) {
const char *name = xpackage->Attribute("name");
const char *platform = xpackage->Attribute("platform");
const char *version = xpackage->Attribute("version");
if (name != NULL && platform != NULL && version != NULL &&
package_name == name &&
package_platform == platform &&
package_version == version) {
// Here's the matching package definition.
desc_file.load_xml(xpackage);
return true;
}
xpackage = xpackage->NextSiblingElement("package");
}
// Couldn't find the named package.
return false;
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::get_unique_id
// Access: Public
@ -384,6 +477,38 @@ delete_global_ptr() {
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::copy_file
// Access: Private
// Description: Copies the data in the file named by from_filename
// into the file named by to_filename.
////////////////////////////////////////////////////////////////////
bool P3DInstanceManager::
copy_file(const string &from_filename, const string &to_filename) {
ifstream in(from_filename.c_str(), ios::in | ios::binary);
ofstream out(to_filename.c_str(), ios::out | ios::binary);
static const size_t buffer_size = 4096;
char buffer[buffer_size];
in.read(buffer, buffer_size);
size_t count = in.gcount();
while (count != 0) {
out.write(buffer, count);
if (out.fail()) {
return false;
}
in.read(buffer, buffer_size);
count = in.gcount();
}
if (!in.eof()) {
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::nt_thread_run
// Access: Private

View File

@ -25,6 +25,8 @@
class P3DInstance;
class P3DSession;
class P3DPackage;
class FileSpec;
class TiXmlElement;
////////////////////////////////////////////////////////////////////
// Class : P3DInstanceManager
@ -37,7 +39,7 @@ private:
~P3DInstanceManager();
public:
bool initialize();
bool initialize(const string &contents_xml_filename);
inline bool is_initialized() const;
@ -45,11 +47,15 @@ public:
inline const string &get_download_url() const;
inline const string &get_platform() const;
P3DInstance *
create_instance(P3D_request_ready_func *func, void *user_data);
inline bool has_contents_file() const;
bool read_contents_file(const string &contents_filename);
bool start_instance(P3DInstance *inst, const string &p3d_filename,
const P3D_token tokens[], size_t num_tokens);
P3DInstance *
create_instance(P3D_request_ready_func *func,
const P3D_token tokens[], size_t num_tokens,
void *user_data);
bool start_instance(P3DInstance *inst, const string &p3d_filename);
void finish_instance(P3DInstance *inst);
P3DInstance *validate_instance(P3D_instance *instance);
@ -60,6 +66,9 @@ public:
P3DPackage *get_package(const string &package_name,
const string &package_version,
const string &package_display_name);
bool get_package_desc_file(FileSpec &desc_file,
const string &package_name,
const string &package_version);
inline int get_num_instances() const;
@ -75,6 +84,9 @@ public:
static P3DInstanceManager *get_global_ptr();
static void delete_global_ptr();
private:
bool copy_file(const string &from_filename, const string &to_filename);
private:
// The notify thread. This thread runs only for the purpose of
// generating asynchronous notifications of requests, to callers who
@ -88,6 +100,8 @@ private:
string _download_url;
string _platform;
TiXmlElement *_xcontents;
P3D_object *_undefined_object;
P3D_object *_none_object;
P3D_object *_true_object;

View File

@ -35,23 +35,25 @@ static const double extract_portion = 0.05;
// Description:
////////////////////////////////////////////////////////////////////
P3DPackage::
P3DPackage(const string &package_name, const string &package_version,
P3DPackage(const string &package_name,
const string &package_platform,
const string &package_version,
const string &package_display_name) :
_package_name(package_name),
_package_version(package_version),
_package_platform(package_platform),
_package_version(package_version),
_package_display_name(package_display_name)
{
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
_package_fullname = _package_name + "_" + _package_version;
_package_fullname = _package_name;
_package_dir = inst_mgr->get_root_dir() + string("/") + _package_name;
if (!_package_platform.empty()) {
_package_fullname += "_" + _package_platform;
_package_dir += "/" + _package_platform;
_package_fullname += string("_") + _package_platform;
_package_dir += string("/") + _package_platform;
}
_package_fullname += string("_") + _package_version;
_package_dir += string("/") + _package_version;
_ready = false;
_failed = false;
@ -59,7 +61,6 @@ P3DPackage(const string &package_name, const string &package_version,
_partial_download = false;
// Ensure the package directory exists; create it if it does not.
_package_dir += string("/") + _package_version;
mkdir_complete(_package_dir, nout);
_desc_file_basename = _package_fullname + ".xml";
@ -186,20 +187,68 @@ begin_download() {
return;
}
// TODO: we should check the desc file for updates with the server.
// Perhaps this should be done in a parent class.
download_contents_file();
}
// 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()) {
////////////////////////////////////////////////////////////////////
// Function: P3DPackage::download_contents_file
// 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.
////////////////////////////////////////////////////////////////////
void P3DPackage::
download_contents_file() {
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
if (inst_mgr->has_contents_file()) {
// We've already got a contents.xml file; go straight to the
// package desc file.
download_desc_file();
} else {
got_desc_file(&doc, false);
return;
}
*/
string url = inst_mgr->get_download_url();
url += "contents.xml";
// Download contents.xml to a temporary filename first, in case
// multiple packages are downloading it simultaneously.
_contents_file_pathname = tempnam(NULL, "p3d_");
cerr << "starting contents download\n";
start_download(DT_contents_file, url, _contents_file_pathname, false);
}
////////////////////////////////////////////////////////////////////
// Function: P3DPackage::contents_file_download_finished
// Access: Private
// Description: Called when the desc file has been fully downloaded.
////////////////////////////////////////////////////////////////////
void P3DPackage::
contents_file_download_finished(bool success) {
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
cerr << "done contents download: " << success
<< ", has_contents = " << inst_mgr->has_contents_file()
<< "\n";
if (!inst_mgr->has_contents_file()) {
if (!success || !inst_mgr->read_contents_file(_contents_file_pathname)) {
nout << "Couldn't read " << _contents_file_pathname << "\n";
// Maybe we can read an already-downloaded contents.xml file.
string standard_filename = inst_mgr->get_root_dir() + "/contents.xml";
if (!inst_mgr->read_contents_file(standard_filename)) {
// Couldn't even read that. Fail.
report_done(false);
unlink(_contents_file_pathname.c_str());
return;
}
}
}
// The file is correctly installed by now; we can remove the
// temporary file.
unlink(_contents_file_pathname.c_str());
download_desc_file();
}
@ -212,12 +261,40 @@ begin_download() {
void P3DPackage::
download_desc_file() {
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
// Attempt to check the desc file for freshness. If it already
// exists, and is consistent with the server contents file, we don't
// need to re-download it.
string root_dir = inst_mgr->get_root_dir();
FileSpec desc_file;
if (!inst_mgr->get_package_desc_file(desc_file, _package_name, _package_version)) {
nout << "Couldn't find package " << _package_fullname
<< " in contents file.\n";
} else if (desc_file.get_pathname(root_dir) != _desc_file_pathname) {
nout << "Wrong pathname for desc file: "
<< desc_file.get_pathname(root_dir)
<< " instead of " << _desc_file_pathname << "\n";
} else if (!desc_file.quick_verify(root_dir)) {
nout << _desc_file_pathname << " is stale.\n";
} else {
// The desc file is current. Attempt to read it.
TiXmlDocument doc(_desc_file_pathname.c_str());
if (doc.LoadFile()) {
got_desc_file(&doc, false);
return;
}
}
// The desc file is not current. Go download it.
string url = inst_mgr->get_download_url();
url += _package_name + "/" + _package_version;
url += _package_name;
if (!_package_platform.empty()) {
url += "/" + _package_platform;
}
url += "/" + _package_version;
url += "/" + _desc_file_basename;
start_download(DT_desc_file, url, _desc_file_pathname, false);
@ -321,11 +398,11 @@ void P3DPackage::
download_compressed_archive(bool allow_partial) {
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
string url = inst_mgr->get_download_url();
url += _package_name + "/" + _package_version;
url += _package_name;
if (!_package_platform.empty()) {
url += "/" + _package_platform;
}
url += "/" + _package_version;
url += "/" + _compressed_archive.get_filename();
string target_pathname = _package_dir + "/" + _compressed_archive.get_filename();
@ -667,6 +744,10 @@ download_finished(bool success) {
_package->_active_download = NULL;
switch (_dtype) {
case DT_contents_file:
_package->contents_file_download_finished(success);
break;
case DT_desc_file:
_package->desc_file_download_finished(success);
break;

View File

@ -36,8 +36,9 @@ class P3DInstance;
////////////////////////////////////////////////////////////////////
class P3DPackage {
public:
P3DPackage(const string &package_name, const string &package_version,
P3DPackage(const string &package_name,
const string &package_platform,
const string &package_version,
const string &package_display_name);
~P3DPackage();
@ -63,6 +64,7 @@ public:
private:
enum DownloadType {
DT_contents_file,
DT_desc_file,
DT_compressed_archive
};
@ -81,6 +83,9 @@ private:
};
void begin_download();
void download_contents_file();
void contents_file_download_finished(bool success);
void download_desc_file();
void desc_file_download_finished(bool success);
void got_desc_file(TiXmlDocument *doc, bool freshly_downloaded);
@ -105,6 +110,8 @@ private:
string _package_fullname;
string _package_dir;
string _contents_file_pathname;
string _desc_file_basename;
string _desc_file_pathname;

View File

@ -82,6 +82,7 @@ set_wparams(const P3DWindowParams &wparams) {
void P3DWinSplashWindow::
set_image_filename(const string &image_filename,
bool image_filename_temp) {
nout << "image_filename = " << image_filename << ", thread_id = " << _thread_id << "\n";
ACQUIRE_LOCK(_install_lock);
if (_image_filename != image_filename) {
_image_filename = image_filename;
@ -261,8 +262,8 @@ thread_run() {
TranslateMessage(&msg);
DispatchMessage(&msg);
if (_got_install) {
ACQUIRE_LOCK(_install_lock);
bool got_install = _got_install;
double install_progress = _install_progress;
if (_image_filename_changed) {
update_image_filename(_image_filename, _image_filename_temp);
@ -274,7 +275,7 @@ thread_run() {
_install_label_changed = false;
RELEASE_LOCK(_install_lock);
if (install_progress != last_progress) {
if (got_install && install_progress != last_progress) {
if (_progress_bar == NULL) {
// Is it time to create the progress bar?
int now = GetTickCount();
@ -290,7 +291,6 @@ thread_run() {
last_progress = install_progress;
}
}
}
retval = GetMessage(&msg, NULL, 0, 0);
}

View File

@ -13,6 +13,7 @@
////////////////////////////////////////////////////////////////////
#include "p3d_plugin_common.h"
#include "p3d_plugin_config.h"
#include "p3dInstanceManager.h"
#include "p3dInstance.h"
#include "p3dWindowParams.h"
@ -37,7 +38,7 @@ ostream *nout_stream;
bool
P3D_initialize(int api_version, const char *output_filename) {
P3D_initialize(int api_version, const char *contents_filename) {
if (api_version != P3D_API_VERSION) {
// Can't accept an incompatible version.
return false;
@ -49,21 +50,40 @@ P3D_initialize(int api_version, const char *output_filename) {
}
ACQUIRE_LOCK(_api_lock);
plugin_output_filename = string();
if (output_filename != NULL) {
plugin_output_filename = output_filename;
if (contents_filename == NULL){
contents_filename = "";
}
#ifdef P3D_PLUGIN_LOGFILE2
string logfilename = P3D_PLUGIN_LOGFILE2;
#else
string logfilename;
#endif // P3D_PLUGIN_LOGFILE2
if (logfilename.empty()) {
#ifdef _WIN32
static const size_t buffer_size = 4096;
char buffer[buffer_size];
if (GetTempPath(buffer_size, buffer) != 0) {
logfilename = buffer;
logfilename += "panda3d.2.log";
}
#else
logfilename = "/tmp/panda3d.2.log";
#endif // _WIN32
}
cerr << "logfile: " << logfilename << "\n";
nout_stream = &cerr;
if (!plugin_output_filename.empty()) {
logfile.open(plugin_output_filename.c_str(), ios::out | ios::trunc);
logfile.open(logfilename.c_str(), ios::out | ios::trunc);
if (logfile) {
logfile.setf(ios::unitbuf);
nout_stream = &logfile;
}
}
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
bool result = inst_mgr->initialize();
bool result = inst_mgr->initialize(contents_filename);
RELEASE_LOCK(_api_lock);
return result;
}
@ -74,18 +94,21 @@ P3D_finalize() {
}
P3D_instance *
P3D_new_instance(P3D_request_ready_func *func, void *user_data) {
P3D_new_instance(P3D_request_ready_func *func,
const P3D_token tokens[], size_t num_tokens,
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();
P3DInstance *result = inst_mgr->create_instance(func, user_data);
P3DInstance *result = inst_mgr->create_instance(func, tokens, num_tokens, user_data);
RELEASE_LOCK(_api_lock);
return result;
}
bool
P3D_instance_start(P3D_instance *instance, const char *p3d_filename,
const P3D_token tokens[], size_t num_tokens) {
P3D_instance_start(P3D_instance *instance, const char *p3d_filename) {
nout << "instance_start\n";
assert(P3DInstanceManager::get_global_ptr()->is_initialized());
if (p3d_filename == NULL) {
p3d_filename = "";
@ -95,7 +118,7 @@ P3D_instance_start(P3D_instance *instance, const char *p3d_filename,
P3DInstance *inst = inst_mgr->validate_instance(instance);
bool result = false;
if (inst != NULL) {
result = inst_mgr->start_instance(inst, p3d_filename, tokens, num_tokens);
result = inst_mgr->start_instance(inst, p3d_filename);
}
RELEASE_LOCK(_api_lock);
return result;
@ -119,6 +142,7 @@ 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);

View File

@ -79,7 +79,7 @@ extern "C" {
(below). This number will be incremented whenever there are changes
to any of the interface specifications defined in this header
file. */
#define P3D_API_VERSION 4
#define P3D_API_VERSION 5
/************************ GLOBAL FUNCTIONS **************************/
@ -91,17 +91,16 @@ extern "C" {
the DLL can verify that it has been built with the same version of
the API as the host.
The output_filename is usually NULL, but if you put a filename
here, it will be used as the log file for the output from the core
API. This is useful for debugging, particularly when running
within a browser that squelches stderr.
The contents_filename, if not NULL or empty, names a contents.xml
file that has already been downloaded and verified from the server.
If this is NULL, a new file will be downloaded as needed.
This function returns true if the core API is valid and uses a
compatible API, false otherwise. If it returns false, the host
should not call any more functions in this API, and should
immediately unload the DLL and (if possible) download a new one. */
typedef bool
P3D_initialize_func(int api_version, const char *output_filename);
P3D_initialize_func(int api_version, const char *contents_filename);
/* This function should be called to unload the core API. It will
release all internally-allocated memory and return the core API to
@ -210,16 +209,25 @@ typedef struct {
/* This function creates a new Panda3D instance.
For tokens, pass an array of P3D_token elements (above), which
correspond to the user-supplied keyword/value pairs that may appear
in the embed token within the HTML syntax; the host is responsible
for allocating this array, and for deallocating it after this call
(the core API will make its own copy of the array). The tokens are
passed to the application, who is free to decide how to interpret
them; they have no meaning at the system level.
The user_data pointer is any arbitrary pointer value; it will be
copied into the _user_data member of the new P3D_instance object.
This pointer is intended for the host to use to store private data
associated with each instance; the core API will not do anything with
this data.
*/
typedef P3D_instance *
P3D_new_instance_func(P3D_request_ready_func *func, void *user_data);
P3D_new_instance_func(P3D_request_ready_func *func,
const P3D_token tokens[], size_t num_tokens,
void *user_data);
/* This function should be called at some point after
P3D_new_instance(); it actually starts the instance running.
@ -230,29 +238,9 @@ P3D_new_instance_func(P3D_request_ready_func *func, void *user_data);
instance. If this is empty or NULL, the "src" token (below) will
be downloaded instead.
For tokens, pass an array of P3D_token elements (above), which
correspond to the user-supplied keyword/value pairs that may appear
in the embed token within the HTML syntax; the host is responsible
for allocating this array, and for deallocating it after this call
(the core API will make its own copy of the array).
Most tokens are implemented by the application and are undefined at
the system level. However, two tokens in particular are
system-defined:
"src" : names a URL that will be loaded for the contents of the
p3d file, if p3d_filename is empty or NULL.
"output_filename" : names a file to create on disk which contains
the console output from the application. This may be useful in
debugging. If this is omitted, or an empty string, the console
output is written to the standard error output, which may be
NULL on a gui application.
The return value is true on success, false on failure. */
typedef bool
P3D_instance_start_func(P3D_instance *instance, const char *p3d_filename,
const P3D_token tokens[], size_t num_tokens);
P3D_instance_start_func(P3D_instance *instance, const char *p3d_filename);
/* Call this function to interrupt a particular instance and stop it

View File

@ -51,6 +51,8 @@ PPInstance(NPMIMEType pluginType, NPP instance, uint16 mode,
_tokens.push_back(token);
}
_root_dir = find_root_dir();
_started_instance_data = false;
_got_instance_data = false;
_got_window = false;
@ -313,8 +315,16 @@ url_notify(const char *url, NPReason reason, void *notifyData) {
case PPDownloadRequest::RT_contents_file:
if (reason != NPRES_DONE) {
nout << "Failure downloading " << url << "\n";
// Couldn't download a fresh contents.xml for some reason. If
// there's an outstanding contents.xml file on disk, try to load
// that one as a fallback.
string contents_filename = _root_dir + "/contents.xml";
if (!read_contents_file(contents_filename)) {
nout << "Unable to read contents file " << contents_filename << "\n";
// TODO: fail
}
}
break;
default:
@ -361,11 +371,11 @@ stream_as_file(NPStream *stream, const char *fname) {
// Looks like we've converted it successfully.
filename = fname2;
// Here's another temporary hack. In addition to the weird
// filename format, the file that Safari tells us about appears
// to be a temporary file that Safari's about to delete. In
// order to protect ourselves from this, we need to temporarily
// copy the file somewhere else.
// Here's another crazy hack. In addition to the weird filename
// format, the file that Safari tells us about appears to be a
// temporary file that Safari's about to delete. In order to
// protect ourselves from this, we need to temporarily copy the
// file somewhere else.
char *name = tempnam(NULL, "p3d_");
// We prefer just making a hard link; it's quick and easy.
@ -373,19 +383,7 @@ stream_as_file(NPStream *stream, const char *fname) {
// But sometimes the hard link might fail, particularly if these
// are two different file systems. In this case we have to open
// the files and copy the data by hand.
ifstream in(filename.c_str(), ios::in | ios::binary);
ofstream out(name, ios::out | ios::binary);
static const size_t buffer_size = 4096;
char buffer[buffer_size];
in.read(buffer, buffer_size);
size_t count = in.gcount();
while (count != 0) {
out.write(buffer, count);
in.read(buffer, buffer_size);
count = in.gcount();
}
copy_file(filename, name);
}
filename = name;
@ -439,7 +437,7 @@ handle_request(P3D_request *request) {
if (strcmp(request->_request._notify._message, "onwindowopen") == 0) {
_python_window_open = true;
if (_got_window) {
NPRect rect = { 0, 0, _window.height, _window.width };
NPRect rect = { 0, 0, (unsigned short)_window.height, (unsigned short)_window.width };
browser->invalidaterect(_npp_instance, &rect);
}
}
@ -447,7 +445,7 @@ handle_request(P3D_request *request) {
case P3D_RT_refresh:
if (_got_window) {
NPRect rect = { 0, 0, _window.height, _window.width };
NPRect rect = { 0, 0, (unsigned short)_window.height, (unsigned short)_window.width };
browser->invalidaterect(_npp_instance, &rect);
}
break;
@ -700,8 +698,8 @@ start_download(const string &url, PPDownloadRequest *req) {
// DLL downloading, if necessary.
////////////////////////////////////////////////////////////////////
bool PPInstance::
read_contents_file(const string &filename) {
TiXmlDocument doc(filename.c_str());
read_contents_file(const string &contents_filename) {
TiXmlDocument doc(contents_filename.c_str());
if (!doc.LoadFile()) {
return false;
}
@ -765,10 +763,24 @@ downloaded_file(PPDownloadRequest *req, const string &filename) {
case PPDownloadRequest::RT_contents_file:
// Now we have the contents.xml file. Read this to get the
// filename and md5 hash of our core API DLL.
if (!read_contents_file(filename)) {
nout << "Unable to read contents file\n";
if (read_contents_file(filename)) {
// Successfully read. Copy it into its normal place.
string contents_filename = _root_dir + "/contents.xml";
copy_file(filename, contents_filename);
} else {
// Error reading the contents.xml file, or in loading the core
// API that it references.
nout << "Unable to read contents file " << filename << "\n";
// If there's an outstanding contents.xml file on disk, try to
// load that one as a fallback.
string contents_filename = _root_dir + "/contents.xml";
if (!read_contents_file(contents_filename)) {
nout << "Unable to read contents file " << contents_filename << "\n";
// TODO: fail
}
}
break;
case PPDownloadRequest::RT_core_dll:
@ -782,7 +794,10 @@ downloaded_file(PPDownloadRequest *req, const string &filename) {
// launch the instance.
_got_instance_data = true;
_p3d_filename = filename;
create_instance();
if (_p3d_inst != NULL) {
P3D_instance_start(_p3d_inst, _p3d_filename.c_str());
}
break;
case PPDownloadRequest::RT_user:
@ -821,8 +836,6 @@ void PPInstance::
get_core_api(TiXmlElement *xpackage) {
_core_api_dll.load_xml(xpackage);
_root_dir = find_root_dir();
if (_core_api_dll.quick_verify(_root_dir)) {
// The DLL file is good. Just load it.
do_load_plugin();
@ -919,7 +932,7 @@ do_load_plugin() {
}
#endif // P3D_PLUGIN_P3D_PLUGIN
if (!load_plugin(pathname)) {
if (!load_plugin(pathname, "")) {
nout << "Unable to launch core API in " << pathname << "\n";
return;
}
@ -944,12 +957,11 @@ create_instance() {
return;
}
if (!_got_instance_data) {
// No instance data yet.
return;
P3D_token *tokens = NULL;
if (!_tokens.empty()) {
tokens = &_tokens[0];
}
_p3d_inst = P3D_new_instance(request_ready, this);
_p3d_inst = P3D_new_instance(request_ready, tokens, _tokens.size(), this);
if (_p3d_inst != NULL) {
// Now get the browser's window object, to pass to the plugin.
@ -971,11 +983,7 @@ create_instance() {
}
if (_got_instance_data) {
P3D_token *tokens = NULL;
if (!_tokens.empty()) {
tokens = &_tokens[0];
}
P3D_instance_start(_p3d_inst, _p3d_filename.c_str(), tokens, _tokens.size());
P3D_instance_start(_p3d_inst, _p3d_filename.c_str());
}
if (_got_window) {
@ -1062,6 +1070,38 @@ send_window() {
parent_window);
}
////////////////////////////////////////////////////////////////////
// Function: PPInstance::copy_file
// Access: Public
// Description: Copies the data in the file named by from_filename
// into the file named by to_filename.
////////////////////////////////////////////////////////////////////
bool PPInstance::
copy_file(const string &from_filename, const string &to_filename) {
ifstream in(from_filename.c_str(), ios::in | ios::binary);
ofstream out(to_filename.c_str(), ios::out | ios::binary);
static const size_t buffer_size = 4096;
char buffer[buffer_size];
in.read(buffer, buffer_size);
size_t count = in.gcount();
while (count != 0) {
out.write(buffer, count);
if (out.fail()) {
return false;
}
in.read(buffer, buffer_size);
count = in.gcount();
}
if (!in.eof()) {
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PPInstance::output_np_variant
// Access: Public

View File

@ -71,13 +71,14 @@ private:
static string get_filename_from_url(const string &url);
void feed_file(PPDownloadRequest *req, const string &filename);
bool read_contents_file(const string &filename);
bool read_contents_file(const string &contents_filename);
void get_core_api(TiXmlElement *xpackage);
void downloaded_plugin(const string &filename);
void do_load_plugin();
void create_instance();
void send_window();
bool copy_file(const string &from_filename, const string &to_filename);
static void handle_request_loop();
static void browser_sync_callback(void *);

View File

@ -286,8 +286,8 @@ run(int argc, char *argv[]) {
bool Panda3D::
get_plugin(const string &root_url, const string &this_platform, bool force_download) {
// First, look for the existing contents.xml file.
Filename contents = Filename(Filename::from_os_specific(_root_dir), "contents.xml");
if (!force_download && read_contents_file(contents, root_url, this_platform)) {
Filename contents_filename = Filename(Filename::from_os_specific(_root_dir), "contents.xml");
if (!force_download && read_contents_file(contents_filename, root_url, this_platform)) {
// Got the file, and it's good.
return true;
}
@ -299,13 +299,13 @@ get_plugin(const string &root_url, const string &this_platform, bool force_downl
HTTPClient *http = HTTPClient::get_global_ptr();
PT(HTTPChannel) channel = http->get_document(url);
contents.make_dir();
if (!channel->download_to_file(contents)) {
contents_filename.make_dir();
if (!channel->download_to_file(contents_filename)) {
cerr << "Unable to download " << url << "\n";
return false;
}
return read_contents_file(contents, root_url, this_platform);
return read_contents_file(contents_filename, root_url, this_platform);
}
////////////////////////////////////////////////////////////////////
@ -316,12 +316,12 @@ get_plugin(const string &root_url, const string &this_platform, bool force_downl
// possible. Returns true on success, false on failure.
////////////////////////////////////////////////////////////////////
bool Panda3D::
read_contents_file(Filename contents, const string &root_url,
read_contents_file(Filename contents_filename, const string &root_url,
const string &this_platform) {
ifstream in;
contents.set_text();
if (!contents.open_read(in)) {
cerr << "Couldn't read " << contents.to_os_specific() << "\n";
contents_filename.set_text();
if (!contents_filename.open_read(in)) {
cerr << "Couldn't read " << contents_filename.to_os_specific() << "\n";
return false;
}
@ -336,7 +336,7 @@ read_contents_file(Filename contents, const string &root_url,
if (name != NULL && strcmp(name, "coreapi") == 0) {
const char *xplatform = xpackage->Attribute("platform");
if (xplatform != NULL && strcmp(xplatform, this_platform.c_str()) == 0) {
return get_core_api(root_url, xpackage);
return get_core_api(contents_filename, root_url, xpackage);
}
}
@ -359,7 +359,8 @@ read_contents_file(Filename contents, const string &root_url,
// if necessary.
////////////////////////////////////////////////////////////////////
bool Panda3D::
get_core_api(const string &root_url, TiXmlElement *xpackage) {
get_core_api(const Filename &contents_filename, const string &root_url,
TiXmlElement *xpackage) {
_core_api_dll.load_xml(xpackage);
if (!_core_api_dll.quick_verify(_root_dir)) {
@ -397,7 +398,7 @@ get_core_api(const string &root_url, TiXmlElement *xpackage) {
}
#endif // P3D_PLUGIN_P3D_PLUGIN
if (!load_plugin(pathname)) {
if (!load_plugin(pathname, contents_filename.to_os_specific())) {
cerr << "Unable to launch core API in " << pathname << "\n" << flush;
return false;
}
@ -592,12 +593,12 @@ create_instance(const string &arg, P3D_window_type window_type,
os_p3d_filename = p3d_filename.to_os_specific();
}
P3D_instance *inst = P3D_new_instance(NULL, NULL);
P3D_instance *inst = P3D_new_instance(NULL, tokens, num_tokens, NULL);
if (inst != NULL) {
P3D_instance_setup_window
(inst, window_type, win_x, win_y, win_width, win_height, parent_window);
P3D_instance_start(inst, os_p3d_filename.c_str(), tokens, num_tokens);
P3D_instance_start(inst, os_p3d_filename.c_str());
}
return inst;

View File

@ -44,9 +44,10 @@ public:
private:
bool get_plugin(const string &root_url, const string &this_platform,
bool force_download);
bool read_contents_file(Filename contents, const string &root_url,
bool read_contents_file(Filename contents_filename, const string &root_url,
const string &this_platform);
bool get_core_api(const string &root_url, TiXmlElement *xpackage);
bool get_core_api(const Filename &contents_filename, const string &root_url,
TiXmlElement *xpackage);
void run_getters();
void handle_request(P3D_request *request);
void make_parent_window(P3D_window_handle &parent_window,

View File

@ -55,7 +55,7 @@ if sys.platform == 'win32':
MSVC = Filename('/c/Program Files/Microsoft Visual Studio .NET 2003/Vc7').toOsSpecific()
else:
print 'Could not locate Microsoft Visual C++ Compiler! Try running from the Visual Studio Command Prompt.'
exit(1)
sys.exit(1)
if ('WindowsSdkDir' in os.environ):
PSDK = os.environ['WindowsSdkDir']
@ -65,7 +65,7 @@ if sys.platform == 'win32':
PSDK = os.path.join(MSVC, 'PlatformSDK')
else:
print 'Could not locate the Microsoft Windows Platform SDK! Try running from the Visual Studio Command Prompt.'
exit(1)
sys.exit(1)
# If it is run by makepanda, it handles the MSVC and PlatformSDK paths itself.
if ('MAKEPANDA' in os.environ):