mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 09:52:27 -04:00
contents.xml max_age; internal cache busting
This commit is contained in:
parent
9d14c7867b
commit
0b80f17c68
@ -1864,6 +1864,10 @@ class Packager:
|
|||||||
self.host = PandaSystem.getPackageHostUrl()
|
self.host = PandaSystem.getPackageHostUrl()
|
||||||
self.addHost(self.host)
|
self.addHost(self.host)
|
||||||
|
|
||||||
|
# The maximum amount of time a client should cache the
|
||||||
|
# contents.xml before re-querying the server, in seconds.
|
||||||
|
self.maxAge = 0
|
||||||
|
|
||||||
# A search list for previously-built local packages.
|
# A search list for previously-built local packages.
|
||||||
|
|
||||||
# We use a bit of caution to read the Filenames out of the
|
# We use a bit of caution to read the Filenames out of the
|
||||||
@ -1918,10 +1922,10 @@ class Packager:
|
|||||||
# client and is therefore readily available to any hacker.
|
# client and is therefore readily available to any hacker.
|
||||||
# Not only is this feature useless, but using it also
|
# Not only is this feature useless, but using it also
|
||||||
# increases the size of your patchfiles, since encrypted files
|
# increases the size of your patchfiles, since encrypted files
|
||||||
# don't patch as tightly as unencrypted files. But it's here
|
# can't really be patched. But it's here if you really want
|
||||||
# if you really want it.
|
# it. ** Note: Actually, this isn't implemented yet.
|
||||||
self.encryptExtensions = ['ptf', 'dna', 'txt', 'dc']
|
#self.encryptExtensions = []
|
||||||
self.encryptFiles = []
|
#self.encryptFiles = []
|
||||||
|
|
||||||
# This is the list of DC import suffixes that should be
|
# This is the list of DC import suffixes that should be
|
||||||
# available to the client. Other suffixes, like AI and UD,
|
# available to the client. Other suffixes, like AI and UD,
|
||||||
@ -2220,6 +2224,8 @@ class Packager:
|
|||||||
# Set up the namespace dictionary for exec.
|
# Set up the namespace dictionary for exec.
|
||||||
globals = {}
|
globals = {}
|
||||||
globals['__name__'] = packageDef.getBasenameWoExtension()
|
globals['__name__'] = packageDef.getBasenameWoExtension()
|
||||||
|
globals['__dir__'] = Filename(packageDef.getDirname()).toOsSpecific()
|
||||||
|
globals['packageDef'] = packageDef
|
||||||
|
|
||||||
globals['platform'] = self.platform
|
globals['platform'] = self.platform
|
||||||
globals['packager'] = self
|
globals['packager'] = self
|
||||||
@ -3156,6 +3162,7 @@ class Packager:
|
|||||||
# sure that our own host at least is added to the map.
|
# sure that our own host at least is added to the map.
|
||||||
self.addHost(self.host)
|
self.addHost(self.host)
|
||||||
|
|
||||||
|
self.maxAge = 0
|
||||||
self.contents = {}
|
self.contents = {}
|
||||||
self.contentsChanged = False
|
self.contentsChanged = False
|
||||||
|
|
||||||
@ -3171,6 +3178,10 @@ class Packager:
|
|||||||
|
|
||||||
xcontents = doc.FirstChildElement('contents')
|
xcontents = doc.FirstChildElement('contents')
|
||||||
if xcontents:
|
if xcontents:
|
||||||
|
maxAge = xcontents.Attribute('max_age')
|
||||||
|
if maxAge:
|
||||||
|
self.maxAge = int(maxAge)
|
||||||
|
|
||||||
xhost = xcontents.FirstChildElement('host')
|
xhost = xcontents.FirstChildElement('host')
|
||||||
if xhost:
|
if xhost:
|
||||||
he = self.HostEntry()
|
he = self.HostEntry()
|
||||||
@ -3199,6 +3210,9 @@ class Packager:
|
|||||||
doc.InsertEndChild(decl)
|
doc.InsertEndChild(decl)
|
||||||
|
|
||||||
xcontents = TiXmlElement('contents')
|
xcontents = TiXmlElement('contents')
|
||||||
|
if self.maxAge:
|
||||||
|
xcontents.SetAttribute('max_age', str(self.maxAge))
|
||||||
|
|
||||||
if self.host:
|
if self.host:
|
||||||
he = self.hosts.get(self.host, None)
|
he = self.hosts.get(self.host, None)
|
||||||
if he:
|
if he:
|
||||||
|
@ -67,6 +67,17 @@ get_timestamp() const {
|
|||||||
return _timestamp;
|
return _timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: FileSpec::has_hash
|
||||||
|
// Access: Public
|
||||||
|
// Description: Returns true if we have successfully read a hash
|
||||||
|
// value, false otherwise.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
inline bool FileSpec::
|
||||||
|
has_hash() const {
|
||||||
|
return _got_hash;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: FileSpec::get_actual_file
|
// Function: FileSpec::get_actual_file
|
||||||
// Access: Public
|
// Access: Public
|
||||||
|
@ -123,6 +123,30 @@ load_xml(TiXmlElement *xelement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: FileSpec::store_xml
|
||||||
|
// Access: Public
|
||||||
|
// Description: Stores the data to the indicated XML file.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void FileSpec::
|
||||||
|
store_xml(TiXmlElement *xelement) {
|
||||||
|
if (!_filename.empty()) {
|
||||||
|
xelement->SetAttribute("filename", _filename);
|
||||||
|
}
|
||||||
|
if (_size != 0) {
|
||||||
|
xelement->SetAttribute("size", _size);
|
||||||
|
}
|
||||||
|
if (_timestamp != 0) {
|
||||||
|
xelement->SetAttribute("timestamp", _timestamp);
|
||||||
|
}
|
||||||
|
if (_got_hash) {
|
||||||
|
char hash[hash_size * 2 + 1];
|
||||||
|
encode_hex(hash, _hash, hash_size);
|
||||||
|
hash[hash_size * 2] = '\0';
|
||||||
|
xelement->SetAttribute("hash", hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: FileSpec::quick_verify
|
// Function: FileSpec::quick_verify
|
||||||
// Access: Public
|
// Access: Public
|
||||||
@ -272,6 +296,7 @@ check_hash(const string &pathname) const {
|
|||||||
bool FileSpec::
|
bool FileSpec::
|
||||||
read_hash(const string &pathname) {
|
read_hash(const string &pathname) {
|
||||||
memset(_hash, 0, hash_size);
|
memset(_hash, 0, hash_size);
|
||||||
|
_got_hash = false;
|
||||||
|
|
||||||
ifstream stream(pathname.c_str(), ios::in | ios::binary);
|
ifstream stream(pathname.c_str(), ios::in | ios::binary);
|
||||||
if (!stream) {
|
if (!stream) {
|
||||||
@ -294,6 +319,7 @@ read_hash(const string &pathname) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MD5_Final(_hash, &ctx);
|
MD5_Final(_hash, &ctx);
|
||||||
|
_got_hash = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -34,12 +34,14 @@ public:
|
|||||||
~FileSpec();
|
~FileSpec();
|
||||||
|
|
||||||
void load_xml(TiXmlElement *xelement);
|
void load_xml(TiXmlElement *xelement);
|
||||||
|
void store_xml(TiXmlElement *xelement);
|
||||||
|
|
||||||
inline const string &get_filename() const;
|
inline const string &get_filename() const;
|
||||||
inline void set_filename(const string &filename);
|
inline void set_filename(const string &filename);
|
||||||
inline string get_pathname(const string &package_dir) const;
|
inline string get_pathname(const string &package_dir) const;
|
||||||
inline size_t get_size() const;
|
inline size_t get_size() const;
|
||||||
inline time_t get_timestamp() const;
|
inline time_t get_timestamp() const;
|
||||||
|
inline bool has_hash() const;
|
||||||
|
|
||||||
bool quick_verify(const string &package_dir);
|
bool quick_verify(const string &package_dir);
|
||||||
bool quick_verify_pathname(const string &pathname);
|
bool quick_verify_pathname(const string &pathname);
|
||||||
|
@ -107,7 +107,8 @@ get_contents_seq() const {
|
|||||||
// Function: P3DHost::check_contents_hash
|
// Function: P3DHost::check_contents_hash
|
||||||
// Access: Public
|
// Access: Public
|
||||||
// Description: Returns true if the indicated pathname has the same
|
// Description: Returns true if the indicated pathname has the same
|
||||||
// md5 hash as the contents.xml file, false otherwise.
|
// md5 hash as the contents.xml file (as provided by the
|
||||||
|
// server), false otherwise.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
inline bool P3DHost::
|
inline bool P3DHost::
|
||||||
check_contents_hash(const string &pathname) const {
|
check_contents_hash(const string &pathname) const {
|
||||||
|
@ -40,6 +40,7 @@ P3DHost(const string &host_url) :
|
|||||||
_descriptive_name = _host_url;
|
_descriptive_name = _host_url;
|
||||||
|
|
||||||
_xcontents = NULL;
|
_xcontents = NULL;
|
||||||
|
_contents_expiration = 0;
|
||||||
_contents_seq = 0;
|
_contents_seq = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,6 +107,25 @@ get_alt_host(const string &alt_host) {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DHost::has_current_contents_file
|
||||||
|
// Access: Public
|
||||||
|
// Description: Returns true if a contents.xml file has been
|
||||||
|
// successfully read for this host and is still current,
|
||||||
|
// false otherwise.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool P3DHost::
|
||||||
|
has_current_contents_file(P3DInstanceManager *inst_mgr) const {
|
||||||
|
if (!inst_mgr->get_verify_contents()) {
|
||||||
|
// If we're not asking to verify contents, then contents.xml files
|
||||||
|
// never expire.
|
||||||
|
return has_contents_file();
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t now = time(NULL);
|
||||||
|
return now < _contents_expiration && (_xcontents != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: P3DHost::read_contents_file
|
// Function: P3DHost::read_contents_file
|
||||||
// Access: Public
|
// Access: Public
|
||||||
@ -122,21 +142,21 @@ read_contents_file() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
string standard_filename = _host_dir + "/contents.xml";
|
string standard_filename = _host_dir + "/contents.xml";
|
||||||
return read_contents_file(standard_filename);
|
return read_contents_file(standard_filename, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: P3DHost::read_contents_file
|
// Function: P3DHost::read_contents_file
|
||||||
// Access: Public
|
// Access: Public
|
||||||
// Description: Reads the contents.xml file in the indicated
|
// Description: Reads the contents.xml file in the indicated
|
||||||
// filename. On success, copies the contents.xml file
|
// filename. On success, writes the contents.xml file
|
||||||
// into the standard location (if it's not there
|
// into the standard location (if it's not there
|
||||||
// already).
|
// already).
|
||||||
//
|
//
|
||||||
// Returns true on success, false on failure.
|
// Returns true on success, false on failure.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool P3DHost::
|
bool P3DHost::
|
||||||
read_contents_file(const string &contents_filename) {
|
read_contents_file(const string &contents_filename, bool fresh_download) {
|
||||||
TiXmlDocument doc(contents_filename.c_str());
|
TiXmlDocument doc(contents_filename.c_str());
|
||||||
if (!doc.LoadFile()) {
|
if (!doc.LoadFile()) {
|
||||||
return false;
|
return false;
|
||||||
@ -152,8 +172,51 @@ read_contents_file(const string &contents_filename) {
|
|||||||
}
|
}
|
||||||
_xcontents = (TiXmlElement *)xcontents->Clone();
|
_xcontents = (TiXmlElement *)xcontents->Clone();
|
||||||
++_contents_seq;
|
++_contents_seq;
|
||||||
|
_contents_spec = FileSpec();
|
||||||
|
|
||||||
|
int max_age = P3D_CONTENTS_DEFAULT_MAX_AGE;
|
||||||
|
xcontents->Attribute("max_age", &max_age);
|
||||||
|
|
||||||
|
// Get the latest possible expiration time, based on the max_age
|
||||||
|
// indication. Any expiration time later than this is in error.
|
||||||
|
time_t now = time(NULL);
|
||||||
|
_contents_expiration = now + (time_t)max_age;
|
||||||
|
|
||||||
|
if (fresh_download) {
|
||||||
_contents_spec.read_hash(contents_filename);
|
_contents_spec.read_hash(contents_filename);
|
||||||
|
|
||||||
|
// Update the XML with the new download information.
|
||||||
|
TiXmlElement *xorig = xcontents->FirstChildElement("orig");
|
||||||
|
while (xorig != NULL) {
|
||||||
|
xcontents->RemoveChild(xorig);
|
||||||
|
xorig = xcontents->FirstChildElement("orig");
|
||||||
|
}
|
||||||
|
|
||||||
|
xorig = new TiXmlElement("orig");
|
||||||
|
xcontents->LinkEndChild(xorig);
|
||||||
|
_contents_spec.store_xml(xorig);
|
||||||
|
|
||||||
|
xorig->SetAttribute("expiration", (int)_contents_expiration);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Read the download hash and expiration time from the XML.
|
||||||
|
int expiration = 0;
|
||||||
|
TiXmlElement *xorig = xcontents->FirstChildElement("orig");
|
||||||
|
if (xorig != NULL) {
|
||||||
|
_contents_spec.load_xml(xorig);
|
||||||
|
xorig->Attribute("expiration", &expiration);
|
||||||
|
}
|
||||||
|
if (!_contents_spec.has_hash()) {
|
||||||
|
_contents_spec.read_hash(contents_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
_contents_expiration = min(_contents_expiration, (time_t)expiration);
|
||||||
|
}
|
||||||
|
|
||||||
|
nout << "read contents.xml, max_age = " << max_age
|
||||||
|
<< ", expires in " << max(_contents_expiration, now) - now
|
||||||
|
<< " s\n";
|
||||||
|
|
||||||
TiXmlElement *xhost = _xcontents->FirstChildElement("host");
|
TiXmlElement *xhost = _xcontents->FirstChildElement("host");
|
||||||
if (xhost != NULL) {
|
if (xhost != NULL) {
|
||||||
const char *url = xhost->Attribute("url");
|
const char *url = xhost->Attribute("url");
|
||||||
@ -194,12 +257,18 @@ read_contents_file(const string &contents_filename) {
|
|||||||
mkdir_complete(_host_dir, nout);
|
mkdir_complete(_host_dir, nout);
|
||||||
|
|
||||||
string standard_filename = _host_dir + "/contents.xml";
|
string standard_filename = _host_dir + "/contents.xml";
|
||||||
|
if (fresh_download) {
|
||||||
|
if (!save_xml_file(&doc, standard_filename)) {
|
||||||
|
nout << "Couldn't save to " << standard_filename << "\n";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (standardize_filename(standard_filename) !=
|
if (standardize_filename(standard_filename) !=
|
||||||
standardize_filename(contents_filename)) {
|
standardize_filename(contents_filename)) {
|
||||||
if (!copy_file(contents_filename, standard_filename)) {
|
if (!copy_file(contents_filename, standard_filename)) {
|
||||||
nout << "Couldn't copy to " << standard_filename << "\n";
|
nout << "Couldn't copy to " << standard_filename << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||||
if (_host_url == inst_mgr->get_host_url()) {
|
if (_host_url == inst_mgr->get_host_url()) {
|
||||||
@ -208,14 +277,13 @@ read_contents_file(const string &contents_filename) {
|
|||||||
// iteration.
|
// iteration.
|
||||||
string top_filename = inst_mgr->get_root_dir() + "/contents.xml";
|
string top_filename = inst_mgr->get_root_dir() + "/contents.xml";
|
||||||
if (standardize_filename(top_filename) !=
|
if (standardize_filename(top_filename) !=
|
||||||
standardize_filename(contents_filename)) {
|
standardize_filename(standard_filename)) {
|
||||||
if (!copy_file(contents_filename, top_filename)) {
|
if (!copy_file(standard_filename, top_filename)) {
|
||||||
nout << "Couldn't copy to " << top_filename << "\n";
|
nout << "Couldn't copy to " << top_filename << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,24 +356,29 @@ get_package(const string &package_name, const string &package_version,
|
|||||||
|
|
||||||
PackageMap &package_map = _packages[alt_host];
|
PackageMap &package_map = _packages[alt_host];
|
||||||
|
|
||||||
|
P3DPackage *package = NULL;
|
||||||
|
|
||||||
string key = package_name + "_" + package_version;
|
string key = package_name + "_" + package_version;
|
||||||
PackageMap::iterator pi = package_map.find(key);
|
PackageMap::iterator pi = package_map.find(key);
|
||||||
if (pi != package_map.end()) {
|
if (pi != package_map.end()) {
|
||||||
P3DPackage *package = (*pi).second;
|
// We've previously installed this package.
|
||||||
if (!package->get_failed()) {
|
package = (*pi).second;
|
||||||
return package;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (package->get_failed()) {
|
||||||
// If the package has previously failed, move it aside and try
|
// If the package has previously failed, move it aside and try
|
||||||
// again (maybe it just failed because the user interrupted it).
|
// again (maybe it just failed because the user interrupted it).
|
||||||
nout << "Package " << key << " has previously failed; trying again.\n";
|
nout << "Package " << key << " has previously failed; trying again.\n";
|
||||||
_failed_packages.push_back(package);
|
_failed_packages.push_back(package);
|
||||||
(*pi).second = NULL;
|
(*pi).second = NULL;
|
||||||
|
package = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
P3DPackage *package =
|
if (package == NULL) {
|
||||||
|
package =
|
||||||
new P3DPackage(this, package_name, package_version, alt_host);
|
new P3DPackage(this, package_name, package_version, alt_host);
|
||||||
package_map[key] = package;
|
package_map[key] = package;
|
||||||
|
}
|
||||||
|
|
||||||
return package;
|
return package;
|
||||||
}
|
}
|
||||||
@ -694,3 +767,41 @@ copy_file(const string &from_filename, const string &to_filename) {
|
|||||||
unlink(temp_filename.c_str());
|
unlink(temp_filename.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DHost::save_xml_file
|
||||||
|
// Access: Private, Static
|
||||||
|
// Description: Stores the XML document to the file named by
|
||||||
|
// to_filename, safely.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool P3DHost::
|
||||||
|
save_xml_file(TiXmlDocument *doc, const string &to_filename) {
|
||||||
|
// Save to a temporary file first, in case (a) we have different
|
||||||
|
// processes writing to the same file, and (b) to prevent partially
|
||||||
|
// overwriting the file should something go wrong.
|
||||||
|
ostringstream strm;
|
||||||
|
strm << to_filename << ".t";
|
||||||
|
#ifdef _WIN32
|
||||||
|
strm << GetCurrentProcessId() << "_" << GetCurrentThreadId();
|
||||||
|
#else
|
||||||
|
strm << getpid();
|
||||||
|
#endif
|
||||||
|
string temp_filename = strm.str();
|
||||||
|
|
||||||
|
if (!doc->SaveFile(temp_filename.c_str())) {
|
||||||
|
unlink(temp_filename.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rename(temp_filename.c_str(), to_filename.c_str()) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
unlink(to_filename.c_str());
|
||||||
|
if (rename(temp_filename.c_str(), to_filename.c_str()) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
unlink(temp_filename.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@ -43,11 +43,12 @@ public:
|
|||||||
P3DHost *get_alt_host(const string &alt_host);
|
P3DHost *get_alt_host(const string &alt_host);
|
||||||
|
|
||||||
inline bool has_contents_file() const;
|
inline bool has_contents_file() const;
|
||||||
|
bool has_current_contents_file(P3DInstanceManager *inst_mgr) const;
|
||||||
inline int get_contents_seq() const;
|
inline int get_contents_seq() const;
|
||||||
inline bool check_contents_hash(const string &pathname) const;
|
inline bool check_contents_hash(const string &pathname) const;
|
||||||
|
|
||||||
bool read_contents_file();
|
bool read_contents_file();
|
||||||
bool read_contents_file(const string &contents_filename);
|
bool read_contents_file(const string &contents_filename, bool fresh_download);
|
||||||
void read_xhost(TiXmlElement *xhost);
|
void read_xhost(TiXmlElement *xhost);
|
||||||
|
|
||||||
P3DPackage *get_package(const string &package_name,
|
P3DPackage *get_package(const string &package_name,
|
||||||
@ -72,6 +73,7 @@ private:
|
|||||||
|
|
||||||
static string standardize_filename(const string &filename);
|
static string standardize_filename(const string &filename);
|
||||||
static bool copy_file(const string &from_filename, const string &to_filename);
|
static bool copy_file(const string &from_filename, const string &to_filename);
|
||||||
|
static bool save_xml_file(TiXmlDocument *doc, const string &to_filename);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
string _host_dir;
|
string _host_dir;
|
||||||
@ -80,6 +82,7 @@ private:
|
|||||||
string _download_url_prefix;
|
string _download_url_prefix;
|
||||||
string _descriptive_name;
|
string _descriptive_name;
|
||||||
TiXmlElement *_xcontents;
|
TiXmlElement *_xcontents;
|
||||||
|
time_t _contents_expiration;
|
||||||
int _contents_seq;
|
int _contents_seq;
|
||||||
FileSpec _contents_spec;
|
FileSpec _contents_spec;
|
||||||
|
|
||||||
|
@ -1141,6 +1141,11 @@ get_packages_info_ready() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool P3DInstance::
|
bool P3DInstance::
|
||||||
get_packages_ready() const {
|
get_packages_ready() const {
|
||||||
|
if (!_packages_specified) {
|
||||||
|
// We haven't even specified the full set of required packages yet.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Packages::const_iterator pi;
|
Packages::const_iterator pi;
|
||||||
for (pi = _packages.begin(); pi != _packages.end(); ++pi) {
|
for (pi = _packages.begin(); pi != _packages.end(); ++pi) {
|
||||||
if (!(*pi)->get_ready()) {
|
if (!(*pi)->get_ready()) {
|
||||||
@ -1384,6 +1389,7 @@ void P3DInstance::
|
|||||||
splash_button_clicked_main_thread() {
|
splash_button_clicked_main_thread() {
|
||||||
if (is_failed()) {
|
if (is_failed()) {
|
||||||
// Can't click the button after we've failed.
|
// Can't click the button after we've failed.
|
||||||
|
nout << "Ignoring click for failed instance\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1391,6 +1397,8 @@ splash_button_clicked_main_thread() {
|
|||||||
auth_button_clicked();
|
auth_button_clicked();
|
||||||
} else if (_session == NULL) {
|
} else if (_session == NULL) {
|
||||||
play_button_clicked();
|
play_button_clicked();
|
||||||
|
} else {
|
||||||
|
nout << "Ignoring click for already-started instance\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2360,9 +2368,6 @@ handle_notify_request(const string &message) {
|
|||||||
// Once Python is up and running, we can get the actual main
|
// Once Python is up and running, we can get the actual main
|
||||||
// object from the Python side, and merge it with our own.
|
// object from the Python side, and merge it with our own.
|
||||||
|
|
||||||
// But only if this web page is allowed to call our scripting
|
|
||||||
// functions.
|
|
||||||
if (_matches_script_origin) {
|
|
||||||
TiXmlDocument *doc = new TiXmlDocument;
|
TiXmlDocument *doc = new TiXmlDocument;
|
||||||
TiXmlElement *xcommand = new TiXmlElement("command");
|
TiXmlElement *xcommand = new TiXmlElement("command");
|
||||||
xcommand->SetAttribute("cmd", "pyobj");
|
xcommand->SetAttribute("cmd", "pyobj");
|
||||||
@ -2383,9 +2388,16 @@ handle_notify_request(const string &message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result != NULL) {
|
if (result != NULL) {
|
||||||
|
if (_matches_script_origin) {
|
||||||
|
// We only actually merge the objects if this web page is
|
||||||
|
// allowed to call our scripting functions.
|
||||||
_panda_script_object->set_pyobj(result);
|
_panda_script_object->set_pyobj(result);
|
||||||
P3D_OBJECT_DECREF(result);
|
} else {
|
||||||
|
// Otherwise, we just do a one-time application of the
|
||||||
|
// toplevel properties down to Python.
|
||||||
|
_panda_script_object->apply_properties(result);
|
||||||
}
|
}
|
||||||
|
P3D_OBJECT_DECREF(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
_panda_script_object->set_string_property("status", "starting");
|
_panda_script_object->set_string_property("status", "starting");
|
||||||
@ -3006,7 +3018,6 @@ mark_download_complete() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void P3DInstance::
|
void P3DInstance::
|
||||||
ready_to_start() {
|
ready_to_start() {
|
||||||
nout << "_instance_started = " << _instance_started << "\n";
|
|
||||||
if (_instance_started || is_failed()) {
|
if (_instance_started || is_failed()) {
|
||||||
// Already started--or never mind.
|
// Already started--or never mind.
|
||||||
return;
|
return;
|
||||||
|
@ -261,12 +261,11 @@ initialize(int api_version, const string &contents_filename,
|
|||||||
create_runtime_environment();
|
create_runtime_environment();
|
||||||
_is_initialized = true;
|
_is_initialized = true;
|
||||||
|
|
||||||
if (!_verify_contents &&
|
if (!host_url.empty() && !contents_filename.empty()) {
|
||||||
!host_url.empty() && !contents_filename.empty()) {
|
|
||||||
// Attempt to pre-read the supplied contents.xml file, to avoid an
|
// Attempt to pre-read the supplied contents.xml file, to avoid an
|
||||||
// unnecessary download later.
|
// unnecessary download later.
|
||||||
P3DHost *host = get_host(host_url);
|
P3DHost *host = get_host(host_url);
|
||||||
if (!host->read_contents_file(contents_filename)) {
|
if (!host->read_contents_file(contents_filename, false)) {
|
||||||
nout << "Couldn't read " << contents_filename << "\n";
|
nout << "Couldn't read " << contents_filename << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -289,12 +289,7 @@ set_pyobj(P3D_object *pyobj) {
|
|||||||
|
|
||||||
// Now that we have a pyobj, we have to transfer down all of the
|
// Now that we have a pyobj, we have to transfer down all of the
|
||||||
// properties we'd set locally.
|
// properties we'd set locally.
|
||||||
Properties::const_iterator pi;
|
apply_properties(_pyobj);
|
||||||
for (pi = _properties.begin(); pi != _properties.end(); ++pi) {
|
|
||||||
const string &property_name = (*pi).first;
|
|
||||||
P3D_object *value = (*pi).second;
|
|
||||||
P3D_OBJECT_SET_PROPERTY(_pyobj, property_name.c_str(), false, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -310,6 +305,41 @@ get_pyobj() const {
|
|||||||
return _pyobj;
|
return _pyobj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DMainObject::apply_properties
|
||||||
|
// Access: Public
|
||||||
|
// Description: Applies the locally-set properties onto the indicated
|
||||||
|
// Python object, but does not store the object. This
|
||||||
|
// is a one-time copy of the locally-set properties
|
||||||
|
// (like "coreapiHostUrl" and the like) onto the
|
||||||
|
// indicated Python object.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void P3DMainObject::
|
||||||
|
apply_properties(P3D_object *pyobj) {
|
||||||
|
P3DPythonObject *p3dpyobj = NULL;
|
||||||
|
if (pyobj->_class == &P3DObject::_object_class) {
|
||||||
|
p3dpyobj = ((P3DObject *)pyobj)->as_python_object();
|
||||||
|
}
|
||||||
|
|
||||||
|
Properties::const_iterator pi;
|
||||||
|
for (pi = _properties.begin(); pi != _properties.end(); ++pi) {
|
||||||
|
const string &property_name = (*pi).first;
|
||||||
|
P3D_object *value = (*pi).second;
|
||||||
|
if (p3dpyobj != NULL && P3D_OBJECT_GET_TYPE(value) != P3D_OT_object) {
|
||||||
|
// If we know we have an actual P3DPythonObject (we really
|
||||||
|
// expect this), then we can call set_property_insecure()
|
||||||
|
// directly, because we want to allow setting the initial
|
||||||
|
// properties even if Javascript has no permissions to write
|
||||||
|
// into Python. But we don't allow setting objects this way in
|
||||||
|
// any event.
|
||||||
|
p3dpyobj->set_property_insecure(property_name, false, value);
|
||||||
|
} else {
|
||||||
|
// Otherwise, we go through the generic interface.
|
||||||
|
P3D_OBJECT_SET_PROPERTY(pyobj, property_name.c_str(), false, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: P3DMainObject::set_instance
|
// Function: P3DMainObject::set_instance
|
||||||
// Access: Public
|
// Access: Public
|
||||||
|
@ -65,6 +65,7 @@ public:
|
|||||||
|
|
||||||
void set_pyobj(P3D_object *pyobj);
|
void set_pyobj(P3D_object *pyobj);
|
||||||
P3D_object *get_pyobj() const;
|
P3D_object *get_pyobj() const;
|
||||||
|
void apply_properties(P3D_object *pyobj);
|
||||||
|
|
||||||
void set_instance(P3DInstance *inst);
|
void set_instance(P3DInstance *inst);
|
||||||
|
|
||||||
|
@ -352,7 +352,7 @@ fill_xml(TiXmlElement *xvalue, P3DSession *session) {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: P3DObject::get_object_array
|
// Function: P3DObject::get_object_array
|
||||||
// Access: Public
|
// Access: Public, Virtual
|
||||||
// Description: Returns a pointer to the array of objects represented
|
// Description: Returns a pointer to the array of objects represented
|
||||||
// by this object, if any, or NULL if the object does
|
// by this object, if any, or NULL if the object does
|
||||||
// not represent an array of objects. This may also
|
// not represent an array of objects. This may also
|
||||||
@ -366,7 +366,7 @@ get_object_array() {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: P3DObject::get_object_array_size
|
// Function: P3DObject::get_object_array_size
|
||||||
// Access: Public
|
// Access: Public, Virtual
|
||||||
// Description: Returns the number of elements in the array returned
|
// Description: Returns the number of elements in the array returned
|
||||||
// by get_object_array(), or -1 if this object does not
|
// by get_object_array(), or -1 if this object does not
|
||||||
// representan array of objects.
|
// representan array of objects.
|
||||||
@ -376,6 +376,18 @@ get_object_array_size() {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DObject::as_python_object
|
||||||
|
// Access: Public, Virtual
|
||||||
|
// Description: Returns this object, downcast to a P3DPythonObject,
|
||||||
|
// if it is in fact an object of that type; or NULL if
|
||||||
|
// it is not.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
P3DPythonObject *P3DObject::
|
||||||
|
as_python_object() {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: P3DObject::get_bool_property
|
// Function: P3DObject::get_bool_property
|
||||||
// Access: Public
|
// Access: Public
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
#include "p3d_plugin_common.h"
|
#include "p3d_plugin_common.h"
|
||||||
|
|
||||||
|
class P3DPythonObject;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Class : P3DObject
|
// Class : P3DObject
|
||||||
// Description : The C++ implementation of P3D_value, corresponding
|
// Description : The C++ implementation of P3D_value, corresponding
|
||||||
@ -56,6 +58,8 @@ public:
|
|||||||
virtual P3D_object **get_object_array();
|
virtual P3D_object **get_object_array();
|
||||||
virtual int get_object_array_size();
|
virtual int get_object_array_size();
|
||||||
|
|
||||||
|
virtual P3DPythonObject *as_python_object();
|
||||||
|
|
||||||
// Convenience functions.
|
// Convenience functions.
|
||||||
bool get_bool_property(const string &property);
|
bool get_bool_property(const string &property);
|
||||||
void set_bool_property(const string &property, bool value);
|
void set_bool_property(const string &property, bool value);
|
||||||
|
@ -181,6 +181,17 @@ void P3DPackage::
|
|||||||
add_instance(P3DInstance *inst) {
|
add_instance(P3DInstance *inst) {
|
||||||
_instances.push_back(inst);
|
_instances.push_back(inst);
|
||||||
|
|
||||||
|
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||||
|
if (!_host->has_current_contents_file(inst_mgr)) {
|
||||||
|
// If the host needs to update its contents file, we're no longer
|
||||||
|
// sure that we're current.
|
||||||
|
_info_ready = false;
|
||||||
|
_ready = false;
|
||||||
|
_failed = false;
|
||||||
|
_allow_data_download = false;
|
||||||
|
nout << "No longer current: " << get_package_name() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
begin_info_download();
|
begin_info_download();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,13 +392,13 @@ begin_info_download() {
|
|||||||
void P3DPackage::
|
void P3DPackage::
|
||||||
download_contents_file() {
|
download_contents_file() {
|
||||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||||
if (!_host->has_contents_file() && !inst_mgr->get_verify_contents()) {
|
if (!_host->has_contents_file()) {
|
||||||
// If we're allowed to read a contents file without checking the
|
// First, read whatever contents file is already on disk. Maybe
|
||||||
// server first, try it now.
|
// it's current enough.
|
||||||
_host->read_contents_file();
|
_host->read_contents_file();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_host->has_contents_file()) {
|
if (_host->has_current_contents_file(inst_mgr)) {
|
||||||
// We've already got a contents.xml file; go straight to the
|
// We've already got a contents.xml file; go straight to the
|
||||||
// package desc file.
|
// package desc file.
|
||||||
host_got_contents_file();
|
host_got_contents_file();
|
||||||
@ -414,14 +425,15 @@ download_contents_file() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void P3DPackage::
|
void P3DPackage::
|
||||||
contents_file_download_finished(bool success) {
|
contents_file_download_finished(bool success) {
|
||||||
if (!_host->has_contents_file()) {
|
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||||
if (!success || !_host->read_contents_file(_temp_contents_file->get_filename())) {
|
if (!_host->has_current_contents_file(inst_mgr)) {
|
||||||
|
if (!success || !_host->read_contents_file(_temp_contents_file->get_filename(), true)) {
|
||||||
nout << "Couldn't read " << *_temp_contents_file << "\n";
|
nout << "Couldn't read " << *_temp_contents_file << "\n";
|
||||||
|
|
||||||
// Maybe we can read an already-downloaded contents.xml file.
|
// Maybe we can read an already-downloaded contents.xml file.
|
||||||
string standard_filename = _host->get_host_dir() + "/contents.xml";
|
string standard_filename = _host->get_host_dir() + "/contents.xml";
|
||||||
if (_host->get_host_dir().empty() ||
|
if (_host->get_host_dir().empty() ||
|
||||||
!_host->read_contents_file(standard_filename)) {
|
!_host->read_contents_file(standard_filename, false)) {
|
||||||
// Couldn't even read that. Fail.
|
// Couldn't even read that. Fail.
|
||||||
report_done(false);
|
report_done(false);
|
||||||
delete _temp_contents_file;
|
delete _temp_contents_file;
|
||||||
@ -503,7 +515,7 @@ contents_file_redownload_finished(bool success) {
|
|||||||
// from what we had before.
|
// from what we had before.
|
||||||
if (!_host->check_contents_hash(_temp_contents_file->get_filename())) {
|
if (!_host->check_contents_hash(_temp_contents_file->get_filename())) {
|
||||||
// It changed! Now see if we can read the new contents.
|
// It changed! Now see if we can read the new contents.
|
||||||
if (!_host->read_contents_file(_temp_contents_file->get_filename())) {
|
if (!_host->read_contents_file(_temp_contents_file->get_filename(), true)) {
|
||||||
// Huh, appears to have changed to something bad. Never mind.
|
// Huh, appears to have changed to something bad. Never mind.
|
||||||
nout << "Couldn't read " << *_temp_contents_file << "\n";
|
nout << "Couldn't read " << *_temp_contents_file << "\n";
|
||||||
|
|
||||||
@ -569,7 +581,8 @@ host_got_contents_file() {
|
|||||||
// host.
|
// host.
|
||||||
_alt_host.clear();
|
_alt_host.clear();
|
||||||
|
|
||||||
if (!_host->has_contents_file()) {
|
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||||
|
if (!_host->has_current_contents_file(inst_mgr)) {
|
||||||
// Now go back and get the contents.xml file for the new host.
|
// Now go back and get the contents.xml file for the new host.
|
||||||
download_contents_file();
|
download_contents_file();
|
||||||
return;
|
return;
|
||||||
@ -1434,6 +1447,12 @@ download_finished(bool success) {
|
|||||||
if (!_file_spec.full_verify(_package->_package_dir)) {
|
if (!_file_spec.full_verify(_package->_package_dir)) {
|
||||||
nout << "After downloading " << get_url()
|
nout << "After downloading " << get_url()
|
||||||
<< ", failed hash check\n";
|
<< ", failed hash check\n";
|
||||||
|
nout << "expected: ";
|
||||||
|
_file_spec.output_hash(nout);
|
||||||
|
nout << "\n got: ";
|
||||||
|
_file_spec.get_actual_file()->output_hash(nout);
|
||||||
|
nout << "\n";
|
||||||
|
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,6 +159,19 @@ set_property(const string &property, bool needs_response, P3D_object *value) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return set_property_insecure(property, needs_response, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DPythonObject::set_property_insecure
|
||||||
|
// Access: Public
|
||||||
|
// Description: Works as set_property(), but does not check the
|
||||||
|
// matches_script_origin flag. Intended to be called
|
||||||
|
// internally only, never to be called from Javascript.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool P3DPythonObject::
|
||||||
|
set_property_insecure(const string &property, bool needs_response,
|
||||||
|
P3D_object *value) {
|
||||||
bool bresult = !needs_response;
|
bool bresult = !needs_response;
|
||||||
|
|
||||||
P3D_object *params[2];
|
P3D_object *params[2];
|
||||||
@ -168,12 +181,12 @@ set_property(const string &property, bool needs_response, P3D_object *value) {
|
|||||||
|
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
// Delete an attribute.
|
// Delete an attribute.
|
||||||
result = call("__del_property__", needs_response, params, 1);
|
result = call_insecure("__del_property__", needs_response, params, 1);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Set a new attribute.
|
// Set a new attribute.
|
||||||
params[1] = value;
|
params[1] = value;
|
||||||
result = call("__set_property__", needs_response, params, 2);
|
result = call_insecure("__set_property__", needs_response, params, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
P3D_OBJECT_DECREF(params[0]);
|
P3D_OBJECT_DECREF(params[0]);
|
||||||
@ -244,6 +257,19 @@ call(const string &method_name, bool needs_response,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return call_insecure(method_name, needs_response, params, num_params);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DPythonObject::call_insecure
|
||||||
|
// Access: Public
|
||||||
|
// Description: Works as call(), but does not check the
|
||||||
|
// matches_script_origin flag. Intended to be called
|
||||||
|
// internally only, never to be called from Javascript.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
P3D_object *P3DPythonObject::
|
||||||
|
call_insecure(const string &method_name, bool needs_response,
|
||||||
|
P3D_object *params[], int num_params) {
|
||||||
TiXmlDocument *doc = new TiXmlDocument;
|
TiXmlDocument *doc = new TiXmlDocument;
|
||||||
TiXmlElement *xcommand = new TiXmlElement("command");
|
TiXmlElement *xcommand = new TiXmlElement("command");
|
||||||
xcommand->SetAttribute("cmd", "pyobj");
|
xcommand->SetAttribute("cmd", "pyobj");
|
||||||
@ -331,6 +357,18 @@ fill_xml(TiXmlElement *xvalue, P3DSession *session) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DPythonObject::as_python_object
|
||||||
|
// Access: Public, Virtual
|
||||||
|
// Description: Returns this object, downcast to a P3DPythonObject,
|
||||||
|
// if it is in fact an object of that type; or NULL if
|
||||||
|
// it is not.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
P3DPythonObject *P3DPythonObject::
|
||||||
|
as_python_object() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: P3DPythonObject::get_session
|
// Function: P3DPythonObject::get_session
|
||||||
// Access: Public
|
// Access: Public
|
||||||
|
@ -43,14 +43,20 @@ public:
|
|||||||
|
|
||||||
virtual P3D_object *get_property(const string &property);
|
virtual P3D_object *get_property(const string &property);
|
||||||
virtual bool set_property(const string &property, bool needs_response, P3D_object *value);
|
virtual bool set_property(const string &property, bool needs_response, P3D_object *value);
|
||||||
|
bool set_property_insecure(const string &property, bool needs_response,
|
||||||
|
P3D_object *value);
|
||||||
|
|
||||||
virtual bool has_method(const string &method_name);
|
virtual bool has_method(const string &method_name);
|
||||||
virtual P3D_object *call(const string &method_name, bool needs_response,
|
virtual P3D_object *call(const string &method_name, bool needs_response,
|
||||||
P3D_object *params[], int num_params);
|
P3D_object *params[], int num_params);
|
||||||
|
P3D_object *call_insecure(const string &method_name, bool needs_response,
|
||||||
|
P3D_object *params[], int num_params);
|
||||||
|
|
||||||
virtual void output(ostream &out);
|
virtual void output(ostream &out);
|
||||||
virtual bool fill_xml(TiXmlElement *xvalue, P3DSession *session);
|
virtual bool fill_xml(TiXmlElement *xvalue, P3DSession *session);
|
||||||
|
|
||||||
|
virtual P3DPythonObject *as_python_object();
|
||||||
|
|
||||||
P3DSession *get_session();
|
P3DSession *get_session();
|
||||||
int get_object_id();
|
int get_object_id();
|
||||||
|
|
||||||
|
@ -1096,6 +1096,12 @@ EXPCL_P3D_PLUGIN P3D_instance_handle_event_func P3D_instance_handle_event;
|
|||||||
|
|
||||||
#endif /* P3D_FUNCTION_PROTOTYPES */
|
#endif /* P3D_FUNCTION_PROTOTYPES */
|
||||||
|
|
||||||
|
// The default max_age, if none is specified in a particular
|
||||||
|
// contents.xml, is 5 seconds. This gives us enough time to start a
|
||||||
|
// few packages downloading, without re-querying the host for a new
|
||||||
|
// contents.xml at each operation.
|
||||||
|
#define P3D_CONTENTS_DEFAULT_MAX_AGE 5
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}; /* end of extern "C" */
|
}; /* end of extern "C" */
|
||||||
#endif
|
#endif
|
||||||
|
@ -58,6 +58,7 @@ PPInstance(NPMIMEType pluginType, NPP instance, uint16_t mode,
|
|||||||
_window_handle_type = window_handle_type;
|
_window_handle_type = window_handle_type;
|
||||||
_event_type = event_type;
|
_event_type = event_type;
|
||||||
_script_object = NULL;
|
_script_object = NULL;
|
||||||
|
_contents_expiration = 0;
|
||||||
_failed = false;
|
_failed = false;
|
||||||
_started = false;
|
_started = false;
|
||||||
|
|
||||||
@ -171,15 +172,30 @@ begin() {
|
|||||||
}
|
}
|
||||||
#endif // __APPLE__
|
#endif // __APPLE__
|
||||||
|
|
||||||
if (!is_plugin_loaded() && !_failed) {
|
|
||||||
// Go download the contents file, so we can download the core DLL.
|
|
||||||
string url = PANDA_PACKAGE_HOST_URL;
|
string url = PANDA_PACKAGE_HOST_URL;
|
||||||
if (!url.empty() && url[url.length() - 1] != '/') {
|
if (!url.empty() && url[url.length() - 1] != '/') {
|
||||||
url += '/';
|
url += '/';
|
||||||
}
|
}
|
||||||
_download_url_prefix = url;
|
_download_url_prefix = url;
|
||||||
|
|
||||||
|
if (!is_plugin_loaded() && !_failed) {
|
||||||
|
// We need to read the contents.xml file. First, check to see if
|
||||||
|
// the version on disk is already current enough.
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
string contents_filename = _root_dir + "/contents.xml";
|
||||||
|
if (read_contents_file(contents_filename, false)) {
|
||||||
|
if (time(NULL) < _contents_expiration) {
|
||||||
|
// Got the file, and it's good.
|
||||||
|
get_core_api();
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
// Go download the latest contents.xml file.
|
||||||
ostringstream strm;
|
ostringstream strm;
|
||||||
strm << url << "contents.xml";
|
strm << _download_url_prefix << "contents.xml";
|
||||||
|
|
||||||
// Append a uniquifying query string to the URL to force the
|
// Append a uniquifying query string to the URL to force the
|
||||||
// download to go all the way through any caches. We use the time
|
// download to go all the way through any caches. We use the time
|
||||||
@ -190,6 +206,7 @@ begin() {
|
|||||||
PPDownloadRequest *req = new PPDownloadRequest(PPDownloadRequest::RT_contents_file);
|
PPDownloadRequest *req = new PPDownloadRequest(PPDownloadRequest::RT_contents_file);
|
||||||
start_download(url, req);
|
start_download(url, req);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handle_request_loop();
|
handle_request_loop();
|
||||||
}
|
}
|
||||||
@ -562,7 +579,9 @@ url_notify(const char *url, NPReason reason, void *notifyData) {
|
|||||||
// there's an outstanding contents.xml file on disk, try to
|
// there's an outstanding contents.xml file on disk, try to
|
||||||
// load that one as a fallback.
|
// load that one as a fallback.
|
||||||
string contents_filename = _root_dir + "/contents.xml";
|
string contents_filename = _root_dir + "/contents.xml";
|
||||||
if (!read_contents_file(contents_filename)) {
|
if (read_contents_file(contents_filename, false)) {
|
||||||
|
get_core_api();
|
||||||
|
} else {
|
||||||
nout << "Unable to read contents file " << contents_filename << "\n";
|
nout << "Unable to read contents file " << contents_filename << "\n";
|
||||||
set_failed();
|
set_failed();
|
||||||
}
|
}
|
||||||
@ -1134,18 +1153,58 @@ start_download(const string &url, PPDownloadRequest *req) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: PPInstance::read_contents_file
|
// Function: PPInstance::read_contents_file
|
||||||
// Access: Private
|
// Access: Private
|
||||||
// Description: Reads the contents.xml file and starts the core API
|
// Description: Attempts to open and read the contents.xml file on
|
||||||
// DLL downloading, if necessary.
|
// disk. Copies the file to its standard location
|
||||||
|
// on success. Returns true on success, false on
|
||||||
|
// failure.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool PPInstance::
|
bool PPInstance::
|
||||||
read_contents_file(const string &contents_filename) {
|
read_contents_file(const string &contents_filename, bool fresh_download) {
|
||||||
TiXmlDocument doc(contents_filename.c_str());
|
TiXmlDocument doc(contents_filename.c_str());
|
||||||
if (!doc.LoadFile()) {
|
if (!doc.LoadFile()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool found_core_package = false;
|
||||||
|
|
||||||
TiXmlElement *xcontents = doc.FirstChildElement("contents");
|
TiXmlElement *xcontents = doc.FirstChildElement("contents");
|
||||||
if (xcontents != NULL) {
|
if (xcontents != NULL) {
|
||||||
|
int max_age = P3D_CONTENTS_DEFAULT_MAX_AGE;
|
||||||
|
xcontents->Attribute("max_age", &max_age);
|
||||||
|
|
||||||
|
// Get the latest possible expiration time, based on the max_age
|
||||||
|
// indication. Any expiration time later than this is in error.
|
||||||
|
time_t now = time(NULL);
|
||||||
|
_contents_expiration = now + (time_t)max_age;
|
||||||
|
|
||||||
|
if (fresh_download) {
|
||||||
|
// Update the XML with the new download information.
|
||||||
|
TiXmlElement *xorig = xcontents->FirstChildElement("orig");
|
||||||
|
while (xorig != NULL) {
|
||||||
|
xcontents->RemoveChild(xorig);
|
||||||
|
xorig = xcontents->FirstChildElement("orig");
|
||||||
|
}
|
||||||
|
|
||||||
|
xorig = new TiXmlElement("orig");
|
||||||
|
xcontents->LinkEndChild(xorig);
|
||||||
|
|
||||||
|
xorig->SetAttribute("expiration", (int)_contents_expiration);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Read the expiration time from the XML.
|
||||||
|
int expiration = 0;
|
||||||
|
TiXmlElement *xorig = xcontents->FirstChildElement("orig");
|
||||||
|
if (xorig != NULL) {
|
||||||
|
xorig->Attribute("expiration", &expiration);
|
||||||
|
}
|
||||||
|
|
||||||
|
_contents_expiration = min(_contents_expiration, (time_t)expiration);
|
||||||
|
}
|
||||||
|
|
||||||
|
nout << "read contents.xml, max_age = " << max_age
|
||||||
|
<< ", expires in " << max(_contents_expiration, now) - now
|
||||||
|
<< " s\n";
|
||||||
|
|
||||||
// Look for the <host> entry; it might point us at a different
|
// Look for the <host> entry; it might point us at a different
|
||||||
// download URL, and it might mention some mirrors.
|
// download URL, and it might mention some mirrors.
|
||||||
find_host(xcontents);
|
find_host(xcontents);
|
||||||
@ -1157,8 +1216,9 @@ read_contents_file(const string &contents_filename) {
|
|||||||
if (name != NULL && strcmp(name, "coreapi") == 0) {
|
if (name != NULL && strcmp(name, "coreapi") == 0) {
|
||||||
const char *platform = xpackage->Attribute("platform");
|
const char *platform = xpackage->Attribute("platform");
|
||||||
if (platform != NULL && strcmp(platform, DTOOL_PLATFORM) == 0) {
|
if (platform != NULL && strcmp(platform, DTOOL_PLATFORM) == 0) {
|
||||||
get_core_api(xpackage);
|
_core_api_dll.load_xml(xpackage);
|
||||||
return true;
|
found_core_package = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1166,10 +1226,23 @@ read_contents_file(const string &contents_filename) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!found_core_package) {
|
||||||
// Couldn't find the coreapi package description.
|
// Couldn't find the coreapi package description.
|
||||||
nout << "No coreapi package defined in contents file for "
|
nout << "No coreapi package defined in contents file for "
|
||||||
<< DTOOL_PLATFORM << "\n";
|
<< DTOOL_PLATFORM << "\n";
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success. Now save the file in its proper place.
|
||||||
|
string standard_filename = _root_dir + "/contents.xml";
|
||||||
|
|
||||||
|
mkfile_complete(standard_filename, nout);
|
||||||
|
if (!doc.SaveFile(standard_filename.c_str())) {
|
||||||
|
nout << "Couldn't rewrite " << standard_filename << "\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -1212,12 +1285,13 @@ void PPInstance::
|
|||||||
downloaded_file(PPDownloadRequest *req, const string &filename) {
|
downloaded_file(PPDownloadRequest *req, const string &filename) {
|
||||||
switch (req->_rtype) {
|
switch (req->_rtype) {
|
||||||
case PPDownloadRequest::RT_contents_file:
|
case PPDownloadRequest::RT_contents_file:
|
||||||
|
{
|
||||||
// Now we have the contents.xml file. Read this to get the
|
// Now we have the contents.xml file. Read this to get the
|
||||||
// filename and md5 hash of our core API DLL.
|
// filename and md5 hash of our core API DLL.
|
||||||
if (read_contents_file(filename)) {
|
if (read_contents_file(filename, true)) {
|
||||||
// Successfully read. Copy it into its normal place.
|
// Successfully downloaded and read, and it has been written
|
||||||
string contents_filename = _root_dir + "/contents.xml";
|
// into its normal place.
|
||||||
copy_file(filename, contents_filename);
|
get_core_api();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Error reading the contents.xml file, or in loading the core
|
// Error reading the contents.xml file, or in loading the core
|
||||||
@ -1227,11 +1301,14 @@ downloaded_file(PPDownloadRequest *req, const string &filename) {
|
|||||||
// If there's an outstanding contents.xml file on disk, try to
|
// If there's an outstanding contents.xml file on disk, try to
|
||||||
// load that one as a fallback.
|
// load that one as a fallback.
|
||||||
string contents_filename = _root_dir + "/contents.xml";
|
string contents_filename = _root_dir + "/contents.xml";
|
||||||
if (!read_contents_file(contents_filename)) {
|
if (read_contents_file(contents_filename, false)) {
|
||||||
|
get_core_api();
|
||||||
|
} else {
|
||||||
nout << "Unable to read contents file " << contents_filename << "\n";
|
nout << "Unable to read contents file " << contents_filename << "\n";
|
||||||
set_failed();
|
set_failed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PPDownloadRequest::RT_core_dll:
|
case PPDownloadRequest::RT_core_dll:
|
||||||
@ -1350,9 +1427,7 @@ send_p3d_temp_file_data() {
|
|||||||
// if necessary.
|
// if necessary.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void PPInstance::
|
void PPInstance::
|
||||||
get_core_api(TiXmlElement *xpackage) {
|
get_core_api() {
|
||||||
_core_api_dll.load_xml(xpackage);
|
|
||||||
|
|
||||||
if (_core_api_dll.quick_verify(_root_dir)) {
|
if (_core_api_dll.quick_verify(_root_dir)) {
|
||||||
// The DLL file is good. Just load it.
|
// The DLL file is good. Just load it.
|
||||||
do_load_plugin();
|
do_load_plugin();
|
||||||
@ -1477,7 +1552,9 @@ do_load_plugin() {
|
|||||||
#endif // P3D_PLUGIN_P3D_PLUGIN
|
#endif // P3D_PLUGIN_P3D_PLUGIN
|
||||||
|
|
||||||
nout << "Attempting to load core API from " << pathname << "\n";
|
nout << "Attempting to load core API from " << pathname << "\n";
|
||||||
if (!load_plugin(pathname, "", "", true, "", "", "", false, false,
|
string contents_filename = _root_dir + "/contents.xml";
|
||||||
|
if (!load_plugin(pathname, contents_filename, PANDA_PACKAGE_HOST_URL,
|
||||||
|
true, "", "", "", false, false,
|
||||||
_root_dir, nout)) {
|
_root_dir, nout)) {
|
||||||
nout << "Unable to launch core API in " << pathname << "\n";
|
nout << "Unable to launch core API in " << pathname << "\n";
|
||||||
set_failed();
|
set_failed();
|
||||||
|
@ -84,8 +84,8 @@ private:
|
|||||||
void open_p3d_temp_file();
|
void open_p3d_temp_file();
|
||||||
void send_p3d_temp_file_data();
|
void send_p3d_temp_file_data();
|
||||||
|
|
||||||
bool read_contents_file(const string &contents_filename);
|
bool read_contents_file(const string &contents_filename, bool fresh_download);
|
||||||
void get_core_api(TiXmlElement *xpackage);
|
void get_core_api();
|
||||||
void downloaded_plugin(const string &filename);
|
void downloaded_plugin(const string &filename);
|
||||||
void do_load_plugin();
|
void do_load_plugin();
|
||||||
|
|
||||||
@ -140,6 +140,7 @@ private:
|
|||||||
CoreUrls _core_urls;
|
CoreUrls _core_urls;
|
||||||
|
|
||||||
FileSpec _core_api_dll;
|
FileSpec _core_api_dll;
|
||||||
|
time_t _contents_expiration;
|
||||||
bool _failed;
|
bool _failed;
|
||||||
bool _started;
|
bool _started;
|
||||||
|
|
||||||
|
@ -353,13 +353,19 @@ post_arg_processing() {
|
|||||||
bool Panda3D::
|
bool Panda3D::
|
||||||
get_plugin() {
|
get_plugin() {
|
||||||
// First, look for the existing contents.xml file.
|
// First, look for the existing contents.xml file.
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
Filename contents_filename = Filename(Filename::from_os_specific(_root_dir), "contents.xml");
|
Filename contents_filename = Filename(Filename::from_os_specific(_root_dir), "contents.xml");
|
||||||
if (!_verify_contents && read_contents_file(contents_filename)) {
|
if (read_contents_file(contents_filename, false)) {
|
||||||
|
if (!_verify_contents || time(NULL) < _contents_expiration) {
|
||||||
// Got the file, and it's good.
|
// Got the file, and it's good.
|
||||||
return true;
|
success = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Couldn't read it, so go get it.
|
if (!success) {
|
||||||
|
// Couldn't read it (or it wasn't current enough), so go get a new
|
||||||
|
// one.
|
||||||
HTTPClient *http = HTTPClient::get_global_ptr();
|
HTTPClient *http = HTTPClient::get_global_ptr();
|
||||||
|
|
||||||
// Try the super_mirror first.
|
// Try the super_mirror first.
|
||||||
@ -377,19 +383,13 @@ get_plugin() {
|
|||||||
cerr << "Unable to download " << url << "\n";
|
cerr << "Unable to download " << url << "\n";
|
||||||
tempfile.unlink();
|
tempfile.unlink();
|
||||||
} else {
|
} else {
|
||||||
// Successfully downloaded from the super_mirror; move it into
|
// Successfully downloaded from the super_mirror; try to read it.
|
||||||
// place and try to read it.
|
success = read_contents_file(tempfile, true);
|
||||||
contents_filename.make_dir();
|
tempfile.unlink();
|
||||||
contents_filename.unlink();
|
|
||||||
tempfile.rename_to(contents_filename);
|
|
||||||
if (read_contents_file(contents_filename)) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Failed to download from the super_mirror.
|
if (!success) {
|
||||||
}
|
|
||||||
|
|
||||||
// Go download contents.xml from the actual host.
|
// Go download contents.xml from the actual host.
|
||||||
ostringstream strm;
|
ostringstream strm;
|
||||||
strm << _host_url_prefix << "contents.xml";
|
strm << _host_url_prefix << "contents.xml";
|
||||||
@ -407,45 +407,89 @@ get_plugin() {
|
|||||||
PT(HTTPChannel) channel = http->make_channel(false);
|
PT(HTTPChannel) channel = http->make_channel(false);
|
||||||
channel->get_document(request);
|
channel->get_document(request);
|
||||||
|
|
||||||
|
// Since we have to download some of it, might as well ask the core
|
||||||
|
// API to check all of it.
|
||||||
|
_verify_contents = true;
|
||||||
|
|
||||||
// First, download it to a temporary file.
|
// First, download it to a temporary file.
|
||||||
Filename tempfile = Filename::temporary("", "p3d_");
|
Filename tempfile = Filename::temporary("", "p3d_");
|
||||||
if (!channel->download_to_file(tempfile)) {
|
if (!channel->download_to_file(tempfile)) {
|
||||||
cerr << "Unable to download " << url << "\n";
|
cerr << "Unable to download " << url << "\n";
|
||||||
tempfile.unlink();
|
|
||||||
|
|
||||||
// Couldn't download, but fall through and try to read the
|
// Couldn't download, but try to read the existing contents.xml
|
||||||
// contents.xml file anyway. Maybe it's good enough.
|
// file anyway. Maybe it's good enough.
|
||||||
|
success = read_contents_file(contents_filename, false);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Successfully downloaded; move the temporary file into place.
|
// Successfully downloaded; read it and move it into place.
|
||||||
contents_filename.make_dir();
|
success = read_contents_file(tempfile, true);
|
||||||
contents_filename.unlink();
|
|
||||||
tempfile.rename_to(contents_filename);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since we had to download some of it, might as well ask the core
|
tempfile.unlink();
|
||||||
// API to check all of it.
|
}
|
||||||
_verify_contents = true;
|
}
|
||||||
|
|
||||||
return read_contents_file(contents_filename);
|
if (success) {
|
||||||
|
// Now that we've downloaded the contents file successfully, start
|
||||||
|
// the Core API.
|
||||||
|
success = get_core_api();
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: Panda3D::read_contents_file
|
// Function: Panda3D::read_contents_file
|
||||||
// Access: Protected
|
// Access: Protected
|
||||||
// Description: Attempts to open and read the contents.xml file on
|
// Description: Attempts to open and read the contents.xml file on
|
||||||
// disk, and uses that data to load the plugin, if
|
// disk. Copies the file to its standard location
|
||||||
// possible. Returns true on success, false on failure.
|
// on success. Returns true on success, false on
|
||||||
|
// failure.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool Panda3D::
|
bool Panda3D::
|
||||||
read_contents_file(const Filename &contents_filename) {
|
read_contents_file(const Filename &contents_filename, bool fresh_download) {
|
||||||
string os_contents_filename = contents_filename.to_os_specific();
|
string os_contents_filename = contents_filename.to_os_specific();
|
||||||
TiXmlDocument doc(os_contents_filename.c_str());
|
TiXmlDocument doc(os_contents_filename.c_str());
|
||||||
if (!doc.LoadFile()) {
|
if (!doc.LoadFile()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool found_core_package = false;
|
||||||
|
|
||||||
TiXmlElement *xcontents = doc.FirstChildElement("contents");
|
TiXmlElement *xcontents = doc.FirstChildElement("contents");
|
||||||
if (xcontents != NULL) {
|
if (xcontents != NULL) {
|
||||||
|
int max_age = P3D_CONTENTS_DEFAULT_MAX_AGE;
|
||||||
|
xcontents->Attribute("max_age", &max_age);
|
||||||
|
|
||||||
|
// Get the latest possible expiration time, based on the max_age
|
||||||
|
// indication. Any expiration time later than this is in error.
|
||||||
|
time_t now = time(NULL);
|
||||||
|
_contents_expiration = now + (time_t)max_age;
|
||||||
|
|
||||||
|
if (fresh_download) {
|
||||||
|
// Update the XML with the new download information.
|
||||||
|
TiXmlElement *xorig = xcontents->FirstChildElement("orig");
|
||||||
|
while (xorig != NULL) {
|
||||||
|
xcontents->RemoveChild(xorig);
|
||||||
|
xorig = xcontents->FirstChildElement("orig");
|
||||||
|
}
|
||||||
|
|
||||||
|
xorig = new TiXmlElement("orig");
|
||||||
|
xcontents->LinkEndChild(xorig);
|
||||||
|
|
||||||
|
xorig->SetAttribute("expiration", (int)_contents_expiration);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Read the expiration time from the XML.
|
||||||
|
int expiration = 0;
|
||||||
|
TiXmlElement *xorig = xcontents->FirstChildElement("orig");
|
||||||
|
if (xorig != NULL) {
|
||||||
|
xorig->Attribute("expiration", &expiration);
|
||||||
|
}
|
||||||
|
|
||||||
|
_contents_expiration = min(_contents_expiration, (time_t)expiration);
|
||||||
|
}
|
||||||
|
|
||||||
// Look for the <host> entry; it might point us at a different
|
// Look for the <host> entry; it might point us at a different
|
||||||
// download URL, and it might mention some mirrors.
|
// download URL, and it might mention some mirrors.
|
||||||
find_host(xcontents);
|
find_host(xcontents);
|
||||||
@ -457,7 +501,9 @@ read_contents_file(const Filename &contents_filename) {
|
|||||||
if (name != NULL && strcmp(name, "coreapi") == 0) {
|
if (name != NULL && strcmp(name, "coreapi") == 0) {
|
||||||
const char *platform = xpackage->Attribute("platform");
|
const char *platform = xpackage->Attribute("platform");
|
||||||
if (platform != NULL && _this_platform == string(platform)) {
|
if (platform != NULL && _this_platform == string(platform)) {
|
||||||
return get_core_api(contents_filename, xpackage);
|
_core_api_dll.load_xml(xpackage);
|
||||||
|
found_core_package = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -465,10 +511,38 @@ read_contents_file(const Filename &contents_filename) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!found_core_package) {
|
||||||
// Couldn't find the coreapi package description.
|
// Couldn't find the coreapi package description.
|
||||||
nout << "No coreapi package defined in contents file for "
|
nout << "No coreapi package defined in contents file for "
|
||||||
<< _this_platform << "\n";
|
<< _this_platform << "\n";
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success. Now copy the file into place.
|
||||||
|
Filename standard_filename = Filename(Filename::from_os_specific(_root_dir), "contents.xml");
|
||||||
|
if (fresh_download) {
|
||||||
|
Filename tempfile = Filename::temporary("", "p3d_");
|
||||||
|
string os_specific = tempfile.to_os_specific();
|
||||||
|
if (!doc.SaveFile(os_specific.c_str())) {
|
||||||
|
nout << "Couldn't write to " << tempfile << "\n";
|
||||||
|
tempfile.unlink();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
tempfile.rename_to(standard_filename);
|
||||||
|
nout << "rewrote " << standard_filename << "\n";
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (contents_filename != standard_filename) {
|
||||||
|
if (!contents_filename.rename_to(standard_filename)) {
|
||||||
|
nout << "Couldn't move contents.xml to " << standard_filename << "\n";
|
||||||
|
contents_filename.unlink();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
nout << "moved to " << standard_filename << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -598,9 +672,7 @@ choose_random_mirrors(vector_string &result, int num_mirrors) {
|
|||||||
// if necessary.
|
// if necessary.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool Panda3D::
|
bool Panda3D::
|
||||||
get_core_api(const Filename &contents_filename, TiXmlElement *xpackage) {
|
get_core_api() {
|
||||||
_core_api_dll.load_xml(xpackage);
|
|
||||||
|
|
||||||
if (!_core_api_dll.quick_verify(_root_dir)) {
|
if (!_core_api_dll.quick_verify(_root_dir)) {
|
||||||
// The DLL file needs to be downloaded. Build up our list of
|
// The DLL file needs to be downloaded. Build up our list of
|
||||||
// URL's to attempt to download it from, in reverse order.
|
// URL's to attempt to download it from, in reverse order.
|
||||||
@ -690,6 +762,7 @@ get_core_api(const Filename &contents_filename, TiXmlElement *xpackage) {
|
|||||||
|
|
||||||
bool trusted_environment = !_enable_security;
|
bool trusted_environment = !_enable_security;
|
||||||
|
|
||||||
|
Filename contents_filename = Filename(Filename::from_os_specific(_root_dir), "contents.xml");
|
||||||
if (!load_plugin(pathname, contents_filename.to_os_specific(),
|
if (!load_plugin(pathname, contents_filename.to_os_specific(),
|
||||||
_host_url, _verify_contents, _this_platform, _log_dirname,
|
_host_url, _verify_contents, _this_platform, _log_dirname,
|
||||||
_log_basename, trusted_environment, _console_environment,
|
_log_basename, trusted_environment, _console_environment,
|
||||||
|
@ -37,12 +37,12 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
bool post_arg_processing();
|
bool post_arg_processing();
|
||||||
bool get_plugin();
|
bool get_plugin();
|
||||||
bool read_contents_file(const Filename &contents_filename);
|
bool read_contents_file(const Filename &contents_filename, bool fresh_download);
|
||||||
void find_host(TiXmlElement *xcontents);
|
void find_host(TiXmlElement *xcontents);
|
||||||
void read_xhost(TiXmlElement *xhost);
|
void read_xhost(TiXmlElement *xhost);
|
||||||
void add_mirror(string mirror_url);
|
void add_mirror(string mirror_url);
|
||||||
void choose_random_mirrors(vector_string &result, int num_mirrors);
|
void choose_random_mirrors(vector_string &result, int num_mirrors);
|
||||||
bool get_core_api(const Filename &contents_filename, TiXmlElement *xplugin);
|
bool get_core_api();
|
||||||
|
|
||||||
void usage();
|
void usage();
|
||||||
|
|
||||||
|
@ -65,6 +65,7 @@ Panda3DBase(bool console_environment) {
|
|||||||
_host_url = PANDA_PACKAGE_HOST_URL;
|
_host_url = PANDA_PACKAGE_HOST_URL;
|
||||||
_this_platform = DTOOL_PLATFORM;
|
_this_platform = DTOOL_PLATFORM;
|
||||||
_verify_contents = false;
|
_verify_contents = false;
|
||||||
|
_contents_expiration = 0;
|
||||||
|
|
||||||
// Seed the lame random number generator in rand(); we use it to
|
// Seed the lame random number generator in rand(); we use it to
|
||||||
// select a mirror for downloading.
|
// select a mirror for downloading.
|
||||||
|
@ -74,6 +74,8 @@ protected:
|
|||||||
string _log_basename;
|
string _log_basename;
|
||||||
string _this_platform;
|
string _this_platform;
|
||||||
bool _verify_contents;
|
bool _verify_contents;
|
||||||
|
time_t _contents_expiration;
|
||||||
|
|
||||||
P3D_window_type _window_type;
|
P3D_window_type _window_type;
|
||||||
P3D_window_handle _parent_window;
|
P3D_window_handle _parent_window;
|
||||||
int _win_x, _win_y;
|
int _win_x, _win_y;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user