more robust temp file and log handling

This commit is contained in:
David Rose 2009-08-20 00:24:00 +00:00
parent 19e866c803
commit 5289285624
32 changed files with 614 additions and 148 deletions

View File

@ -45,6 +45,7 @@
p3dSession.h p3dSession.I \ p3dSession.h p3dSession.I \
p3dSplashWindow.h p3dSplashWindow.I \ p3dSplashWindow.h p3dSplashWindow.I \
p3dStringObject.h \ p3dStringObject.h \
p3dTemporaryFile.h p3dTemporaryFile.I \
p3dToplevelObject.h \ p3dToplevelObject.h \
p3dUndefinedObject.h \ p3dUndefinedObject.h \
p3dWinSplashWindow.h p3dWinSplashWindow.I \ p3dWinSplashWindow.h p3dWinSplashWindow.I \
@ -74,6 +75,7 @@
p3dSession.cxx \ p3dSession.cxx \
p3dSplashWindow.cxx \ p3dSplashWindow.cxx \
p3dStringObject.cxx \ p3dStringObject.cxx \
p3dTemporaryFile.cxx \
p3dToplevelObject.cxx \ p3dToplevelObject.cxx \
p3dUndefinedObject.cxx \ p3dUndefinedObject.cxx \
p3dWinSplashWindow.cxx \ p3dWinSplashWindow.cxx \

View File

@ -124,7 +124,8 @@ static void unload_dso();
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool bool
load_plugin(const string &p3d_plugin_filename, const string &contents_filename, load_plugin(const string &p3d_plugin_filename, const string &contents_filename,
const string &download_url, const string &platform) { const string &download_url, const string &platform,
const string &log_directory, const string &log_basename) {
string filename = p3d_plugin_filename; string filename = p3d_plugin_filename;
if (filename.empty()) { if (filename.empty()) {
// Look for the plugin along the path. // Look for the plugin along the path.
@ -294,7 +295,8 @@ load_plugin(const string &p3d_plugin_filename, const string &contents_filename,
plugin_loaded = true; plugin_loaded = true;
if (!P3D_initialize(P3D_API_VERSION, contents_filename.c_str(), if (!P3D_initialize(P3D_API_VERSION, contents_filename.c_str(),
download_url.c_str(), platform.c_str())) { download_url.c_str(), platform.c_str(),
log_directory.c_str(), log_basename.c_str())) {
// Oops, failure to initialize. // Oops, failure to initialize.
cerr << "Failed to initialize plugin (wrong API version?)\n"; cerr << "Failed to initialize plugin (wrong API version?)\n";
unload_plugin(); unload_plugin();

View File

@ -60,7 +60,8 @@ extern P3D_instance_handle_event_func *P3D_instance_handle_event;
string get_plugin_basename(); string get_plugin_basename();
bool bool
load_plugin(const string &p3d_plugin_filename, const string &contents_filename, load_plugin(const string &p3d_plugin_filename, const string &contents_filename,
const string &download_url, const string &platform); const string &download_url, const string &platform,
const string &log_directory, const string &log_basename);
void unload_plugin(); void unload_plugin();
bool is_plugin_loaded(); bool is_plugin_loaded();

View File

@ -122,6 +122,19 @@ lookup_token(const string &keyword) const {
return string(); return string();
} }
////////////////////////////////////////////////////////////////////
// Function: P3DFileParams::lookup_token_int
// Access: Public
// Description: Returns the integer value associated with the first
// appearance of the named token, or zero if the
// token does not appear or is not an integer.
////////////////////////////////////////////////////////////////////
int P3DFileParams::
lookup_token_int(const string &keyword) const {
string value = lookup_token(keyword);
return atoi(value.c_str());
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: P3DFileParams::has_token // Function: P3DFileParams::has_token
// Access: Public // Access: Public

View File

@ -36,6 +36,7 @@ public:
inline const string &get_p3d_filename() const; inline const string &get_p3d_filename() const;
string lookup_token(const string &keyword) const; string lookup_token(const string &keyword) const;
int lookup_token_int(const string &keyword) const;
bool has_token(const string &keyword) const; bool has_token(const string &keyword) const;
TiXmlElement *make_xml(); TiXmlElement *make_xml();

View File

@ -25,6 +25,7 @@
#include "p3dToplevelObject.h" #include "p3dToplevelObject.h"
#include "p3dUndefinedObject.h" #include "p3dUndefinedObject.h"
#include "p3dMultifileReader.h" #include "p3dMultifileReader.h"
#include "p3dTemporaryFile.h"
#include <sstream> #include <sstream>
#include <algorithm> #include <algorithm>
@ -59,6 +60,8 @@ P3DInstance(P3D_request_ready_func *func,
_panda_script_object = new P3DToplevelObject; _panda_script_object = new P3DToplevelObject;
_user_data = user_data; _user_data = user_data;
_request_pending = false; _request_pending = false;
_temp_p3d_filename = NULL;
_temp_splash_image = NULL;
_got_fparams = false; _got_fparams = false;
_got_wparams = false; _got_wparams = false;
@ -68,6 +71,7 @@ P3DInstance(P3D_request_ready_func *func,
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
_instance_id = inst_mgr->get_unique_id(); _instance_id = inst_mgr->get_unique_id();
_full_disk_access = false; _full_disk_access = false;
_hidden = false;
_session = NULL; _session = NULL;
_panda3d = NULL; _panda3d = NULL;
_splash_window = NULL; _splash_window = NULL;
@ -122,6 +126,16 @@ P3DInstance::
_splash_window = NULL; _splash_window = NULL;
} }
if (_temp_p3d_filename != NULL) {
delete _temp_p3d_filename;
_temp_p3d_filename = NULL;
}
if (_temp_splash_image != NULL) {
delete _temp_splash_image;
_temp_splash_image = NULL;
}
#ifdef __APPLE__ #ifdef __APPLE__
if (_frame_timer != NULL) { if (_frame_timer != NULL) {
CFRunLoopTimerInvalidate(_frame_timer); CFRunLoopTimerInvalidate(_frame_timer);
@ -167,9 +181,8 @@ void P3DInstance::
set_p3d_url(const string &p3d_url) { set_p3d_url(const string &p3d_url) {
nout << "set_p3d_url(" << p3d_url << ")\n"; nout << "set_p3d_url(" << p3d_url << ")\n";
// Make a temporary file to receive the instance data. // Make a temporary file to receive the instance data.
char *name = tempnam(NULL, "p3d_"); assert(_temp_p3d_filename == NULL);
string filename = name; _temp_p3d_filename = new P3DTemporaryFile(".p3d");
free(name);
// Mark the time we started downloading, so we'll know when to set // Mark the time we started downloading, so we'll know when to set
// the install label. // the install label.
@ -183,7 +196,7 @@ set_p3d_url(const string &p3d_url) {
// Start downloading the data. // Start downloading the data.
InstanceDownload *download = new InstanceDownload(this); InstanceDownload *download = new InstanceDownload(this);
download->set_url(p3d_url); download->set_url(p3d_url);
download->set_filename(filename); download->set_filename(_temp_p3d_filename->get_filename());
_panda_script_object->set_string_property("status", "downloading_instance"); _panda_script_object->set_string_property("status", "downloading_instance");
start_download(download); start_download(download);
@ -243,10 +256,15 @@ set_p3d_filename(const string &p3d_filename) {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void P3DInstance:: void P3DInstance::
set_wparams(const P3DWindowParams &wparams) { set_wparams(const P3DWindowParams &wparams) {
nout << "set_wparams, _session = " << _session << "\n";
_got_wparams = true; _got_wparams = true;
_wparams = wparams; _wparams = wparams;
nout << "set window_type = " << _wparams.get_window_type() << "\n";
if (_hidden || _wparams.get_win_width() == 0 || _wparams.get_win_height() == 0) {
// If we're a hidden app, or if the window has no size, then it is
// really a hidden window, regardless of what type it claims to
// be.
_wparams.set_window_type(P3D_WT_hidden);
}
if (_wparams.get_window_type() != P3D_WT_hidden) { if (_wparams.get_window_type() != P3D_WT_hidden) {
// Update or create the splash window. // Update or create the splash window.
@ -854,6 +872,15 @@ scan_app_desc_file(TiXmlDocument *doc) {
_full_disk_access = (full_disk_access != 0); _full_disk_access = (full_disk_access != 0);
} }
int hidden = 0;
if (xpackage->QueryIntAttribute("hidden", &hidden) == TIXML_SUCCESS) {
_hidden = (hidden != 0);
}
if (_hidden && _got_wparams) {
_wparams.set_window_type(P3D_WT_hidden);
}
TiXmlElement *xrequires = xpackage->FirstChildElement("requires"); TiXmlElement *xrequires = xpackage->FirstChildElement("requires");
while (xrequires != NULL) { while (xrequires != NULL) {
const char *name = xrequires->Attribute("name"); const char *name = xrequires->Attribute("name");
@ -1015,6 +1042,11 @@ handle_notify_request(const string &message) {
_splash_window = NULL; _splash_window = NULL;
} }
if (_temp_splash_image != NULL) {
delete _temp_splash_image;
_temp_splash_image = NULL;
}
_panda_script_object->set_string_property("status", "open"); _panda_script_object->set_string_property("status", "open");
#ifdef __APPLE__ #ifdef __APPLE__
@ -1112,7 +1144,6 @@ handle_script_request(const string &operation, P3D_object *object,
char *buffer = new char[size + 1]; char *buffer = new char[size + 1];
P3D_OBJECT_GET_STRING(value, buffer, size + 1); P3D_OBJECT_GET_STRING(value, buffer, size + 1);
result = P3D_OBJECT_EVAL(object, buffer); result = P3D_OBJECT_EVAL(object, buffer);
logfile << " eval " << *object << ": " << buffer << ", result = " << result << "\n";
delete[] buffer; delete[] buffer;
if (result != NULL) { if (result != NULL) {
@ -1157,14 +1188,13 @@ make_splash_window() {
} }
// Make a temporary file to receive the splash image. // Make a temporary file to receive the splash image.
char *name = tempnam(NULL, "p3d_"); assert(_temp_splash_image == NULL);
string filename = name; _temp_splash_image = new P3DTemporaryFile(".jpg");
free(name);
// Start downloading the requested splash image. // Start downloading the requested splash image.
SplashDownload *download = new SplashDownload(this); SplashDownload *download = new SplashDownload(this);
download->set_url(splash_image_url); download->set_url(splash_image_url);
download->set_filename(filename); download->set_filename(_temp_splash_image->get_filename());
start_download(download); start_download(download);
} }
@ -1202,6 +1232,8 @@ report_package_info_ready(P3DPackage *package) {
_splash_window->set_install_progress(0.0); _splash_window->set_install_progress(0.0);
} }
_panda_script_object->set_string_property("status", "downloading"); _panda_script_object->set_string_property("status", "downloading");
_panda_script_object->set_int_property("numDownloadingPackages", _downloading_packages.size());
_panda_script_object->set_int_property("totalDownloadSize", _total_download_size);
send_notify("ondownloadbegin"); send_notify("ondownloadbegin");
start_next_download(); start_next_download();
@ -1232,6 +1264,8 @@ start_next_download() {
} }
_panda_script_object->set_string_property("downloadPackageName", package->get_package_name()); _panda_script_object->set_string_property("downloadPackageName", package->get_package_name());
_panda_script_object->set_string_property("downloadPackageDisplayName", name); _panda_script_object->set_string_property("downloadPackageDisplayName", name);
_panda_script_object->set_int_property("downloadPackageNumber", _download_package_index + 1);
_panda_script_object->set_int_property("downloadPackageSize", package->get_download_size());
set_install_label("Installing " + name); set_install_label("Installing " + name);
nout << "Downloading " << package->get_package_name() nout << "Downloading " << package->get_package_name()
@ -1241,6 +1275,7 @@ start_next_download() {
<< " bytes.\n"; << " bytes.\n";
package->activate_download(); package->activate_download();
send_notify("ondownloadnext");
return; return;
} }
@ -1253,10 +1288,12 @@ start_next_download() {
_downloading_packages.clear(); _downloading_packages.clear();
if (get_packages_ready()) { if (get_packages_ready()) {
_panda_script_object->set_bool_property("downloadComplete", true); if (!_panda_script_object->get_bool_property("downloadComplete")) {
_panda_script_object->set_string_property("status", "starting"); _panda_script_object->set_bool_property("downloadComplete", true);
send_notify("ondownloadcomplete"); _panda_script_object->set_string_property("status", "starting");
send_notify("ondownloadcomplete");
}
// Notify the session also. // Notify the session also.
if (_session != NULL) { if (_session != NULL) {
_session->report_packages_done(this, true); _session->report_packages_done(this, true);

View File

@ -40,6 +40,7 @@ class P3DDownload;
class P3DPackage; class P3DPackage;
class P3DObject; class P3DObject;
class P3DToplevelObject; class P3DToplevelObject;
class P3DTemporaryFile;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Class : P3DInstance // Class : P3DInstance
@ -145,6 +146,9 @@ private:
P3D_object *_browser_script_object; P3D_object *_browser_script_object;
P3DToplevelObject *_panda_script_object; P3DToplevelObject *_panda_script_object;
P3DTemporaryFile *_temp_p3d_filename;
P3DTemporaryFile *_temp_splash_image;
bool _got_fparams; bool _got_fparams;
P3DFileParams _fparams; P3DFileParams _fparams;
@ -156,6 +160,7 @@ private:
string _python_version; string _python_version;
string _log_basename; string _log_basename;
bool _full_disk_access; bool _full_disk_access;
bool _hidden;
// Not ref-counted: session is the parent. // Not ref-counted: session is the parent.
P3DSession *_session; P3DSession *_session;

View File

@ -60,6 +60,20 @@ get_platform() const {
return _platform; return _platform;
} }
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::get_log_directory
// Access: Public
// Description: Returns the pathname of the directory into which all
// log files should be written. This filename will end
// with a slash or backslash, as appropriate, so that
// logfile pathnames may be made by concatenting
// directly with this string.
////////////////////////////////////////////////////////////////////
inline const string &P3DInstanceManager::
get_log_directory() const {
return _log_directory;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::has_contents_file // Function: P3DInstanceManager::has_contents_file
// Access: Public // Access: Public

View File

@ -24,6 +24,7 @@
#include "find_root_dir.h" #include "find_root_dir.h"
#include "fileSpec.h" #include "fileSpec.h"
#include "get_tinyxml.h" #include "get_tinyxml.h"
#include "mkdir_complete.h"
// We can include this header file to get the DTOOL_PLATFORM // We can include this header file to get the DTOOL_PLATFORM
// definition, even though we don't link with dtool. // definition, even though we don't link with dtool.
@ -32,9 +33,12 @@
#ifdef _WIN32 #ifdef _WIN32
#include <shlobj.h> #include <shlobj.h>
#else #else
//#include <sys/stat.h> #include <sys/stat.h>
#endif #endif
static ofstream logfile;
ostream *nout_stream = &logfile;
P3DInstanceManager *P3DInstanceManager::_global_ptr; P3DInstanceManager *P3DInstanceManager::_global_ptr;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -45,6 +49,7 @@ P3DInstanceManager *P3DInstanceManager::_global_ptr;
P3DInstanceManager:: P3DInstanceManager::
P3DInstanceManager() { P3DInstanceManager() {
_is_initialized = false; _is_initialized = false;
_next_temp_filename_counter = 0;
_unique_id = 0; _unique_id = 0;
_xcontents = NULL; _xcontents = NULL;
@ -105,6 +110,15 @@ P3DInstanceManager::
assert(_instances.empty()); assert(_instances.empty());
assert(_sessions.empty()); assert(_sessions.empty());
// Delete any remaining temporary files.
TempFilenames::iterator ti;
for (ti = _temp_filenames.begin(); ti != _temp_filenames.end(); ++ti) {
const string &filename = (*ti);
nout << "Removing delinquent temp file " << filename << "\n";
unlink(filename.c_str());
}
_temp_filenames.clear();
nout << "counts: " << _undefined_object->_ref_count nout << "counts: " << _undefined_object->_ref_count
<< " " << _none_object->_ref_count << " " << _none_object->_ref_count
<< " " << _true_object->_ref_count << " " << _true_object->_ref_count
@ -138,23 +152,104 @@ P3DInstanceManager::
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool P3DInstanceManager:: bool P3DInstanceManager::
initialize(const string &contents_filename, const string &download_url, initialize(const string &contents_filename, const string &download_url,
const string &platform) { const string &platform, const string &log_directory,
const string &log_basename) {
_root_dir = find_root_dir(); _root_dir = find_root_dir();
_download_url = download_url; _download_url = download_url;
#ifdef P3D_PLUGIN_DOWNLOAD
if (_download_url.empty()) { if (_download_url.empty()) {
_download_url = P3D_PLUGIN_DOWNLOAD; _download_url = P3D_PLUGIN_DOWNLOAD;
} }
#endif
_platform = platform; _platform = platform;
if (_platform.empty()) { if (_platform.empty()) {
_platform = DTOOL_PLATFORM; _platform = DTOOL_PLATFORM;
} }
_log_directory = log_directory;
#ifdef P3D_PLUGIN_LOG_DIRECTORY
if (_log_directory.empty()) {
_log_directory = P3D_PLUGIN_LOG_DIRECTORY;
}
#endif
// Determine the temporary directory.
#ifdef _WIN32
size_t needs_size_1 = GetTempPath(0, NULL);
char *buffer_1 = new char[needs_size_1];
if (GetTempPath(needs_size_1, buffer_1) != 0) {
_temp_directory = buffer_1;
}
delete[] buffer_1;
static const size_t buffer_size = 4096;
char buffer[buffer_size];
if (GetTempPath(buffer_size, buffer) != 0) {
_temp_directory = buffer;
}
// Also insist that the temp directory is fully specified.
size_t needs_size_2 = GetFullPathName(_temp_directory.c_str(), 0, NULL, NULL);
char *buffer_2 = new char[needs_size_2];
if (GetFullPathName(_temp_directory.c_str(), needs_size_2, buffer_2, NULL) != 0) {
_temp_directory = buffer_2;
}
delete[] buffer_2;
// Also make sure the directory actually exists.
mkdir_complete(_temp_directory, nout);
#else
_temp_directory = "/tmp/";
#endif // _WIN32
// If the log directory is still empty, use the temp directory.
if (_log_directory.empty()) {
_log_directory = _temp_directory;
}
_log_basename = log_basename;
#ifdef P3D_PLUGIN_LOG_BASENAME2
if (_log_basename.empty()) {
_log_basename = P3D_PLUGIN_LOG_BASENAME2;
}
#endif
// Ensure that the download URL ends with a slash. // Ensure that the download URL ends with a slash.
if (!_download_url.empty() && _download_url[_download_url.size() - 1] != '/') { if (!_download_url.empty() && _download_url[_download_url.size() - 1] != '/') {
_download_url += "/"; _download_url += "/";
} }
// Ensure that the temp directory ends with a slash.
if (!_temp_directory.empty() && _temp_directory[_temp_directory.size() - 1] != '/') {
#ifdef _WIN32
if (_temp_directory[_temp_directory.size() - 1] != '\\')
#endif
_temp_directory += "/";
}
// Ensure that the log directory ends with a slash.
if (!_log_directory.empty() && _log_directory[_log_directory.size() - 1] != '/') {
#ifdef _WIN32
if (_log_directory[_log_directory.size() - 1] != '\\')
#endif
_log_directory += "/";
}
// Construct the logfile pathname.
if (!_log_basename.empty()) {
_log_pathname = _log_directory;
_log_pathname += _log_basename;
_log_pathname += ".log";
logfile.open(_log_pathname.c_str(), ios::out | ios::trunc);
if (logfile) {
logfile.setf(ios::unitbuf);
nout_stream = &logfile;
}
}
nout << "_root_dir = " << _root_dir nout << "_root_dir = " << _root_dir
<< ", contents = " << contents_filename << ", contents = " << contents_filename
<< ", download = " << _download_url << ", download = " << _download_url
@ -497,6 +592,82 @@ make_class_definition() const {
return new_class; return new_class;
} }
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::make_temp_filename
// Access: Public
// Description: Constructs a new, unique temporary filename with the
// indicated extension. You should use the
// P3DTemporaryFilename interface instead of calling
// this method directly.
////////////////////////////////////////////////////////////////////
string P3DInstanceManager::
make_temp_filename(const string &extension) {
string result;
bool exists;
do {
int tid;
#ifdef _WIN32
tid = GetCurrentProcessId();
#else
tid = getpid();
#endif
if (tid == 0) {
tid = 1;
}
int hash = ((clock() + _next_temp_filename_counter) * ((time(NULL) * tid) >> 8)) & 0xffffff;
++_next_temp_filename_counter;
char hex_code[10];
sprintf(hex_code, "%06x", hash);
result = _temp_directory;
result += "p3d_";
result += hex_code;
result += extension;
exists = false;
if (_temp_filenames.find(result) != _temp_filenames.end()) {
// We've previously allocated this file.
exists = true;
} else {
// Check if the file exists on disk.
#ifdef _WIN32
DWORD results = GetFileAttributes(result.c_str());
if (results != -1) {
exists = true;
}
#else // _WIN32
struct stat this_buf;
if (stat(result.c_str(), &this_buf) == 0) {
exists = true;
}
#endif
}
} while (exists);
nout << "make_temp_filename: " << result << "\n";
return result;
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::release_temp_filename
// Access: Public
// Description: Releases a temporary filename assigned earlier via
// make_temp_filename(). If the file exists, it will be
// removed. You should use the P3DTemporaryFilename
// interface instead of calling this method directly.
////////////////////////////////////////////////////////////////////
void P3DInstanceManager::
release_temp_filename(const string &filename) {
nout << "release_temp_filename: " << filename << "\n";
_temp_filenames.erase(filename);
unlink(filename.c_str());
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::get_global_ptr // Function: P3DInstanceManager::get_global_ptr
// Access: Public, Static // Access: Public, Static

View File

@ -45,13 +45,16 @@ private:
public: public:
bool initialize(const string &contents_filename, bool initialize(const string &contents_filename,
const string &download_url, const string &download_url,
const string &platform); const string &platform,
const string &log_directory,
const string &log_basename);
inline bool is_initialized() const; inline bool is_initialized() const;
inline const string &get_root_dir() const; inline const string &get_root_dir() const;
inline const string &get_download_url() const; inline const string &get_download_url() const;
inline const string &get_platform() const; inline const string &get_platform() const;
inline const string &get_log_directory() const;
inline bool has_contents_file() const; inline bool has_contents_file() const;
bool read_contents_file(const string &contents_filename); bool read_contents_file(const string &contents_filename);
@ -88,6 +91,9 @@ public:
inline P3D_object *new_none_object(); inline P3D_object *new_none_object();
inline P3D_object *new_bool_object(bool value); inline P3D_object *new_bool_object(bool value);
string make_temp_filename(const string &extension);
void release_temp_filename(const string &filename);
static P3DInstanceManager *get_global_ptr(); static P3DInstanceManager *get_global_ptr();
static void delete_global_ptr(); static void delete_global_ptr();
@ -106,6 +112,10 @@ private:
string _root_dir; string _root_dir;
string _download_url; string _download_url;
string _platform; string _platform;
string _log_directory;
string _log_basename;
string _log_pathname;
string _temp_directory;
TiXmlElement *_xcontents; TiXmlElement *_xcontents;
@ -123,6 +133,10 @@ private:
typedef map<string, P3DPackage *> Packages; typedef map<string, P3DPackage *> Packages;
Packages _packages; Packages _packages;
typedef set<string> TempFilenames;
TempFilenames _temp_filenames;
int _next_temp_filename_counter;
int _unique_id; int _unique_id;
// This condition var is waited on the main thread and signaled in a // This condition var is waited on the main thread and signaled in a

View File

@ -16,6 +16,7 @@
#include "p3dInstanceManager.h" #include "p3dInstanceManager.h"
#include "p3dInstance.h" #include "p3dInstance.h"
#include "p3dMultifileReader.h" #include "p3dMultifileReader.h"
#include "p3dTemporaryFile.h"
#include "mkdir_complete.h" #include "mkdir_complete.h"
#include "zlib.h" #include "zlib.h"
@ -53,6 +54,8 @@ P3DPackage(const string &package_name,
_package_fullname += string("_") + _package_version; _package_fullname += string("_") + _package_version;
_package_dir += string("/") + _package_version; _package_dir += string("/") + _package_version;
_temp_contents_file = NULL;
_info_ready = false; _info_ready = false;
_download_size = 0; _download_size = 0;
_allow_data_download = false; _allow_data_download = false;
@ -85,6 +88,7 @@ P3DPackage::
_active_download = NULL; _active_download = NULL;
} }
assert(_temp_contents_file == NULL);
assert(_instances.empty()); assert(_instances.empty());
} }
@ -179,10 +183,10 @@ download_contents_file() {
// Download contents.xml to a temporary filename first, in case // Download contents.xml to a temporary filename first, in case
// multiple packages are downloading it simultaneously. // multiple packages are downloading it simultaneously.
_contents_file_pathname = tempnam(NULL, "p3d_"); assert(_temp_contents_file == NULL);
_temp_contents_file = new P3DTemporaryFile(".xml");
cerr << "starting contents download\n"; start_download(DT_contents_file, url, _temp_contents_file->get_filename(), false);
start_download(DT_contents_file, url, _contents_file_pathname, false);
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -193,20 +197,18 @@ download_contents_file() {
void P3DPackage:: void P3DPackage::
contents_file_download_finished(bool success) { contents_file_download_finished(bool success) {
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); 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 (!inst_mgr->has_contents_file()) {
if (!success || !inst_mgr->read_contents_file(_contents_file_pathname)) { if (!success || !inst_mgr->read_contents_file(_temp_contents_file->get_filename())) {
nout << "Couldn't read " << _contents_file_pathname << "\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 = inst_mgr->get_root_dir() + "/contents.xml"; string standard_filename = inst_mgr->get_root_dir() + "/contents.xml";
if (!inst_mgr->read_contents_file(standard_filename)) { if (!inst_mgr->read_contents_file(standard_filename)) {
// Couldn't even read that. Fail. // Couldn't even read that. Fail.
report_done(false); report_done(false);
unlink(_contents_file_pathname.c_str()); delete _temp_contents_file;
_temp_contents_file = NULL;
return; return;
} }
} }
@ -214,7 +216,8 @@ contents_file_download_finished(bool success) {
// The file is correctly installed by now; we can remove the // The file is correctly installed by now; we can remove the
// temporary file. // temporary file.
unlink(_contents_file_pathname.c_str()); delete _temp_contents_file;
_temp_contents_file = NULL;
download_desc_file(); download_desc_file();
} }

View File

@ -21,6 +21,7 @@
#include "get_tinyxml.h" #include "get_tinyxml.h"
class P3DInstance; class P3DInstance;
class P3DTemporaryFile;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Class : P3DPackage // Class : P3DPackage
@ -107,7 +108,7 @@ private:
string _package_fullname; string _package_fullname;
string _package_dir; string _package_dir;
string _contents_file_pathname; P3DTemporaryFile *_temp_contents_file;
string _desc_file_basename; string _desc_file_basename;
string _desc_file_pathname; string _desc_file_pathname;

View File

@ -978,7 +978,7 @@ set_p3d_filename(P3DCInstance *inst, TiXmlElement *xfparams) {
xarg = xarg->NextSiblingElement("arg"); xarg = xarg->NextSiblingElement("arg");
} }
PyObject *result = PyObject_CallMethod PyObject *result = PyObject_CallMethod
(_runner, (char *)"setP3DFilename", (char *)"sOOi", p3d_filename.c_str(), (_runner, (char *)"setP3DFilename", (char *)"sOOi", p3d_filename.c_str(),
token_list, arg_list, inst->get_instance_id()); token_list, arg_list, inst->get_instance_id());

View File

@ -650,6 +650,8 @@ start_p3dpython(P3DInstance *inst) {
return; return;
} }
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
_python_root_dir = inst->_panda3d->get_package_dir(); _python_root_dir = inst->_panda3d->get_package_dir();
// We'll be changing the directory to the standard start directory // We'll be changing the directory to the standard start directory
@ -699,7 +701,7 @@ start_p3dpython(P3DInstance *inst) {
const char *keep[] = { const char *keep[] = {
"TMP", "TEMP", "HOME", "USER", "TMP", "TEMP", "HOME", "USER",
#ifdef _WIN32 #ifdef _WIN32
"SYSTEMROOT", "USERPROFILE", "COMSPEC", "SYSTEMROOT", "USERPROFILE", "COMSPEC", "PANDA_ROOT",
#endif #endif
NULL NULL
}; };
@ -766,7 +768,17 @@ start_p3dpython(P3DInstance *inst) {
log_basename = inst->get_fparams().lookup_token("log_basename"); log_basename = inst->get_fparams().lookup_token("log_basename");
} }
// However, it is always written into the temp directory only; the bool console_output = (inst->get_fparams().lookup_token_int("console_output") != 0);
#ifdef P3D_PLUGIN_LOG_BASENAME3
if (log_basename.empty()) {
// No log_basename specified for the app; use the compiled-in
// default.
log_basename = P3D_PLUGIN_LOG_BASENAME3;
}
#endif
// However, it is always written into the log directory only; the
// user may not override the log file to put it anywhere else. // user may not override the log file to put it anywhere else.
size_t slash = log_basename.rfind('/'); size_t slash = log_basename.rfind('/');
if (slash != string::npos) { if (slash != string::npos) {
@ -779,32 +791,24 @@ start_p3dpython(P3DInstance *inst) {
} }
#endif // _WIN32 #endif // _WIN32
if (!log_basename.empty()) { if (!console_output && !log_basename.empty()) {
#ifdef _WIN32 _log_pathname = inst_mgr->get_log_directory();
static const size_t buffer_size = 4096; _log_pathname += log_basename;
char buffer[buffer_size];
if (GetTempPath(buffer_size, buffer) != 0) {
_output_filename = buffer;
}
#else
_output_filename = "/tmp/";
#endif // _WIN32
_output_filename += log_basename;
// We always tack on the extension ".log", to make it even more // We always tack on the extension ".log", to make it even more
// difficult to overwrite a system file. // difficult to overwrite a system file.
_output_filename += ".log"; _log_pathname += ".log";
} }
nout << "Attempting to start python from " << p3dpython << "\n"; nout << "Attempting to start python from " << p3dpython << "\n";
#ifdef _WIN32 #ifdef _WIN32
_p3dpython_handle = win_create_process _p3dpython_handle = win_create_process
(p3dpython, start_dir, env, _output_filename, (p3dpython, start_dir, env, _log_pathname,
_pipe_read, _pipe_write); _pipe_read, _pipe_write);
bool started_p3dpython = (_p3dpython_handle != INVALID_HANDLE_VALUE); bool started_p3dpython = (_p3dpython_handle != INVALID_HANDLE_VALUE);
#else #else
_p3dpython_pid = posix_create_process _p3dpython_pid = posix_create_process
(p3dpython, start_dir, env, _output_filename, (p3dpython, start_dir, env, _log_pathname,
_pipe_read, _pipe_write); _pipe_read, _pipe_write);
bool started_p3dpython = (_p3dpython_pid > 0); bool started_p3dpython = (_p3dpython_pid > 0);
#endif #endif
@ -976,7 +980,7 @@ rt_terminate() {
// Access: Private, Static // Access: Private, Static
// Description: Creates a sub-process to run the named program // Description: Creates a sub-process to run the named program
// executable, with the indicated environment string. // executable, with the indicated environment string.
// Standard error is logged to output_filename, if that // Standard error is logged to log_pathname, if that
// string is nonempty. // string is nonempty.
// //
// Opens the two HandleStreams as the read and write // Opens the two HandleStreams as the read and write
@ -988,7 +992,7 @@ rt_terminate() {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
HANDLE P3DSession:: HANDLE P3DSession::
win_create_process(const string &program, const string &start_dir, win_create_process(const string &program, const string &start_dir,
const string &env, const string &output_filename, const string &env, const string &log_pathname,
HandleStream &pipe_read, HandleStream &pipe_write) { HandleStream &pipe_read, HandleStream &pipe_write) {
// Create a bi-directional pipe to communicate with the sub-process. // Create a bi-directional pipe to communicate with the sub-process.
@ -1013,19 +1017,19 @@ win_create_process(const string &program, const string &start_dir,
} }
HANDLE error_handle = GetStdHandle(STD_ERROR_HANDLE); HANDLE error_handle = GetStdHandle(STD_ERROR_HANDLE);
bool got_output_filename = !output_filename.empty(); bool got_log_pathname = !log_pathname.empty();
if (got_output_filename) { if (got_log_pathname) {
// Open the named file for output and redirect the child's stderr // Open the named file for output and redirect the child's stderr
// into it. // into it.
HANDLE handle = CreateFile HANDLE handle = CreateFile
(output_filename.c_str(), GENERIC_WRITE, (log_pathname.c_str(), GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, CREATE_ALWAYS, 0, NULL); NULL, CREATE_ALWAYS, 0, NULL);
if (handle != INVALID_HANDLE_VALUE) { if (handle != INVALID_HANDLE_VALUE) {
error_handle = handle; error_handle = handle;
SetHandleInformation(error_handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); SetHandleInformation(error_handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
} else { } else {
nout << "Unable to open " << output_filename << "\n"; nout << "Unable to open " << log_pathname << "\n";
} }
} }
@ -1063,7 +1067,7 @@ win_create_process(const string &program, const string &start_dir,
// Close the pipe handles that are now owned by the child. // Close the pipe handles that are now owned by the child.
CloseHandle(w_from); CloseHandle(w_from);
CloseHandle(r_to); CloseHandle(r_to);
if (got_output_filename) { if (got_log_pathname) {
CloseHandle(error_handle); CloseHandle(error_handle);
} }
@ -1099,7 +1103,7 @@ win_create_process(const string &program, const string &start_dir,
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
int P3DSession:: int P3DSession::
posix_create_process(const string &program, const string &start_dir, posix_create_process(const string &program, const string &start_dir,
const string &env, const string &output_filename, const string &env, const string &log_pathname,
HandleStream &pipe_read, HandleStream &pipe_write) { HandleStream &pipe_read, HandleStream &pipe_write) {
// Create a bi-directional pipe to communicate with the sub-process. // Create a bi-directional pipe to communicate with the sub-process.
int to_fd[2]; int to_fd[2];
@ -1124,14 +1128,14 @@ posix_create_process(const string &program, const string &start_dir,
if (child == 0) { if (child == 0) {
// Here we are in the child process. // Here we are in the child process.
bool got_output_filename = !output_filename.empty(); bool got_log_pathname = !log_pathname.empty();
if (got_output_filename) { if (got_log_pathname) {
// Open the named file for output and redirect the child's stderr // Open the named file for output and redirect the child's stderr
// into it. // into it.
int logfile_fd = open(output_filename.c_str(), int logfile_fd = open(log_pathname.c_str(),
O_WRONLY | O_CREAT | O_TRUNC, 0666); O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (logfile_fd < 0) { if (logfile_fd < 0) {
nout << "Unable to open " << output_filename << "\n"; nout << "Unable to open " << log_pathname << "\n";
} else { } else {
dup2(logfile_fd, STDERR_FILENO); dup2(logfile_fd, STDERR_FILENO);
close(logfile_fd); close(logfile_fd);

View File

@ -90,7 +90,7 @@ private:
int _session_id; int _session_id;
string _session_key; string _session_key;
string _python_version; string _python_version;
string _output_filename; string _log_pathname;
string _python_root_dir; string _python_root_dir;
string _start_dir; string _start_dir;

View File

@ -0,0 +1,24 @@
// Filename: p3dTemporaryFile.I
// Created by: drose (19Aug09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: P3DTemporaryFile::get_filename
// Access: Public
// Description: Returns the temporary filename.
////////////////////////////////////////////////////////////////////
inline const string &P3DTemporaryFile::
get_filename() const {
return _filename;
}

View File

@ -0,0 +1,38 @@
// Filename: p3dTemporaryFile.cxx
// Created by: drose (19Aug09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "p3dTemporaryFile.h"
#include "p3dInstanceManager.h"
////////////////////////////////////////////////////////////////////
// Function: P3DTemporaryFile::Constructor
// Access: Public
// Description: Constructs a new, unique temporary filename.
////////////////////////////////////////////////////////////////////
P3DTemporaryFile::
P3DTemporaryFile(const string &extension) {
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
_filename = inst_mgr->make_temp_filename(extension);
}
////////////////////////////////////////////////////////////////////
// Function: P3DTemporaryFile::Destructor
// Access: Public
// Description: Deletes the temporary file, if it exists.
////////////////////////////////////////////////////////////////////
P3DTemporaryFile::
~P3DTemporaryFile() {
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
inst_mgr->release_temp_filename(_filename);
}

View File

@ -0,0 +1,47 @@
// Filename: p3dTemporaryFile.h
// Created by: drose (19Aug09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef P3DTEMPORARYFILE_H
#define P3DTEMPORARYFILE_H
#include "p3d_plugin_common.h"
////////////////////////////////////////////////////////////////////
// Class : P3DTemporaryFile
// Description : This represents a temporary filename for some
// transitory purpose. This returns a filename which is
// guaranteed to be unique at the time the constructor
// was called.
//
// The file on disk, if it exists, will automatically be
// deleted when the destructor is called.
////////////////////////////////////////////////////////////////////
class P3DTemporaryFile {
public:
P3DTemporaryFile(const string &extension);
~P3DTemporaryFile();
inline const string &get_filename() const;
private:
string _filename;
};
inline ostream &operator << (ostream &out, P3DTemporaryFile &tfile) {
return out << tfile.get_filename();
}
#include "p3dTemporaryFile.I"
#endif

View File

@ -17,13 +17,23 @@
// Function: P3DWindowParams::get_window_type // Function: P3DWindowParams::get_window_type
// Access: Public // Access: Public
// Description: Returns the window_type that was passed to the // Description: Returns the window_type that was passed to the
// constructor. // constructor, or to set_window_type().
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
inline P3D_window_type P3DWindowParams:: inline P3D_window_type P3DWindowParams::
get_window_type() const { get_window_type() const {
return _window_type; return _window_type;
} }
////////////////////////////////////////////////////////////////////
// Function: P3DWindowParams::set_window_type
// Access: Public
// Description: Changes the window_type.
////////////////////////////////////////////////////////////////////
inline void P3DWindowParams::
set_window_type(P3D_window_type window_type) {
_window_type = window_type;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: P3DWindowParams::get_window_x // Function: P3DWindowParams::get_window_x
// Access: Public // Access: Public

View File

@ -35,6 +35,8 @@ public:
void operator = (const P3DWindowParams &other); void operator = (const P3DWindowParams &other);
inline P3D_window_type get_window_type() const; inline P3D_window_type get_window_type() const;
inline void set_window_type(P3D_window_type window_type);
inline int get_win_x() const; inline int get_win_x() const;
inline int get_win_y() const; inline int get_win_y() const;
inline int get_win_width() const; inline int get_win_width() const;

View File

@ -32,14 +32,10 @@
bool initialized_lock = false; bool initialized_lock = false;
LOCK _api_lock; LOCK _api_lock;
ofstream logfile;
string plugin_output_filename;
ostream *nout_stream;
bool bool
P3D_initialize(int api_version, const char *contents_filename, P3D_initialize(int api_version, const char *contents_filename,
const char *download_url, const char *platform) { const char *download_url, const char *platform,
const char *log_directory, const char *log_basename) {
if (api_version != P3D_API_VERSION) { if (api_version != P3D_API_VERSION) {
// Can't accept an incompatible version. // Can't accept an incompatible version.
return false; return false;
@ -63,36 +59,17 @@ P3D_initialize(int api_version, const char *contents_filename,
platform = ""; platform = "";
} }
#ifdef P3D_PLUGIN_LOGFILE2 if (log_directory == NULL) {
string logfilename = P3D_PLUGIN_LOGFILE2; log_directory = "";
#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"; if (log_basename == NULL) {
log_basename = "";
nout_stream = &cerr;
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(); P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
bool result = inst_mgr->initialize(contents_filename, download_url, platform); bool result = inst_mgr->initialize(contents_filename, download_url,
platform, log_directory, log_basename);
RELEASE_LOCK(_api_lock); RELEASE_LOCK(_api_lock);
return result; return result;
} }

View File

@ -101,13 +101,26 @@ extern "C" {
If platform is not NULL or empty, it specifies the current platform If platform is not NULL or empty, it specifies the current platform
string; otherwise, the compiled-in default is used. string; otherwise, the compiled-in default is used.
If log_directory is not NULL or empty, it specifies the directory
into which all log files will be written; otherwise, the
compiled-in default will be used, or the system temp directory if
no default is compiled in.
If log_basename is not NULL or empty, it specifies the filename in
log_directory to which the core API's logfile output will be
written. Otherwise, the compiled-in default is used; if there is
no compiled-in default, no logfile output will be generated by the
core API. Note that the individual instances also have their own
log_basename values.
This function returns true if the core API is valid and uses a This function returns true if the core API is valid and uses a
compatible API, false otherwise. If it returns false, the host compatible API, false otherwise. If it returns false, the host
should not call any more functions in this API, and should should not call any more functions in this API, and should
immediately unload the DLL and (if possible) download a new one. */ immediately unload the DLL and (if possible) download a new one. */
typedef bool typedef bool
P3D_initialize_func(int api_version, const char *contents_filename, P3D_initialize_func(int api_version, const char *contents_filename,
const char *download_url, const char *platform); const char *download_url, const char *platform,
const char *log_directory, const char *log_basename);
/* This function should be called to unload the core API. It will /* This function should be called to unload the core API. It will
release all internally-allocated memory and return the core API to release all internally-allocated memory and return the core API to

View File

@ -38,8 +38,7 @@
using namespace std; using namespace std;
// Appears in p3d_plugin.cxx. // Appears in p3dInstanceManager.cxx.
extern string plugin_output_filename;
extern ostream *nout_stream; extern ostream *nout_stream;
#define nout (*nout_stream) #define nout (*nout_stream)

View File

@ -20,6 +20,7 @@
#include "p3dSession.cxx" #include "p3dSession.cxx"
#include "p3dSplashWindow.cxx" #include "p3dSplashWindow.cxx"
#include "p3dStringObject.cxx" #include "p3dStringObject.cxx"
#include "p3dTemporaryFile.cxx"
#include "p3dToplevelObject.cxx" #include "p3dToplevelObject.cxx"
#include "p3dUndefinedObject.cxx" #include "p3dUndefinedObject.cxx"
#include "p3dWinSplashWindow.cxx" #include "p3dWinSplashWindow.cxx"

View File

@ -13,8 +13,10 @@
/* The filename(s) to generate output to when the plugin is running. /* The filename(s) to generate output to when the plugin is running.
For debugging purposes only. */ For debugging purposes only. */
#$[]define P3D_PLUGIN_LOGFILE1 "$[subst \,\\,$[osfilename $[P3D_PLUGIN_LOGFILE1]]]" #$[]define P3D_PLUGIN_LOG_DIRECTORY "$[subst \,\\,$[osfilename $[P3D_PLUGIN_LOG_DIRECTORY]]]"
#$[]define P3D_PLUGIN_LOGFILE2 "$[subst \,\\,$[osfilename $[P3D_PLUGIN_LOGFILE2]]]" #$[]define P3D_PLUGIN_LOG_BASENAME1 "$[P3D_PLUGIN_LOG_BASENAME1]"
#$[]define P3D_PLUGIN_LOG_BASENAME2 "$[P3D_PLUGIN_LOG_BASENAME2]"
#$[]define P3D_PLUGIN_LOG_BASENAME3 "$[P3D_PLUGIN_LOG_BASENAME3]"
/* For development only: the location at which p3dpython.exe can be /* For development only: the location at which p3dpython.exe can be
found. Empty string for the default. */ found. Empty string for the default. */

View File

@ -928,7 +928,7 @@ 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, "", "", "")) { if (!load_plugin(pathname, "", "", "", "", "")) {
nout << "Unable to launch core API in " << pathname << "\n"; nout << "Unable to launch core API in " << pathname << "\n";
return; return;
} }

View File

@ -30,26 +30,44 @@ static bool logfile_is_open = false;
static void static void
open_logfile() { open_logfile() {
if (!logfile_is_open) { if (!logfile_is_open) {
#ifdef P3D_PLUGIN_LOGFILE1 // Note that this logfile name may not be specified at runtime. It
string logfilename = P3D_PLUGIN_LOGFILE1; // must be compiled in if it is specified at all.
#else
string logfilename;
#endif // P3D_PLUGIN_LOGFILE1
if (logfilename.empty()) { string log_basename;
#ifdef P3D_PLUGIN_LOG_BASENAME1
log_basename = P3D_PLUGIN_LOG_BASENAME1;
#endif
if (!log_basename.empty()) {
// Get the log directory.
string log_directory;
#ifdef P3D_PLUGIN_LOG_DIRECTORY
log_directory = P3D_PLUGIN_LOG_DIRECTORY;
#endif
if (log_directory.empty()) {
#ifdef _WIN32 #ifdef _WIN32
static const size_t buffer_size = 4096; static const size_t buffer_size = 4096;
char buffer[buffer_size]; char buffer[buffer_size];
if (GetTempPath(buffer_size, buffer) != 0) { if (GetTempPath(buffer_size, buffer) != 0) {
logfilename = buffer; log_directory = buffer;
logfilename += "panda3d.1.log"; }
}
#else #else
logfilename = "/tmp/panda3d.1.log"; log_directory = "/tmp/";
#endif // _WIN32 #endif // _WIN32
}
// Construct the full logfile pathname.
string log_pathname = log_directory;
log_pathname += log_basename;
log_pathname += ".log";
logfile.open(log_pathname.c_str());
logfile.setf(ios::unitbuf);
} }
logfile.open(logfilename.c_str());
logfile.setf(ios::unitbuf); // If we didn't have a logfile name compiled in, we throw away log
// output by the simple expedient of never actually opening the
// ofstream.
logfile_is_open = true; logfile_is_open = true;
} }
} }

View File

@ -44,6 +44,7 @@
Panda3D:: Panda3D::
Panda3D() { Panda3D() {
_root_dir = find_root_dir(); _root_dir = find_root_dir();
_reporting_download = false;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -60,7 +61,7 @@ run(int argc, char *argv[]) {
// We prefix a "+" sign to tell gnu getopt not to parse options // We prefix a "+" sign to tell gnu getopt not to parse options
// following the first not-option parameter. (These will be passed // following the first not-option parameter. (These will be passed
// into the sub-process.) // into the sub-process.)
const char *optstr = "+mu:p:ft:s:o:h"; const char *optstr = "+mu:p:ft:s:o:l:h";
bool allow_multiple = false; bool allow_multiple = false;
string download_url = P3D_PLUGIN_DOWNLOAD; string download_url = P3D_PLUGIN_DOWNLOAD;
@ -69,7 +70,7 @@ run(int argc, char *argv[]) {
P3D_window_type window_type = P3D_WT_toplevel; P3D_window_type window_type = P3D_WT_toplevel;
int win_x = 0, win_y = 0; int win_x = 0, win_y = 0;
int win_width = 0, win_height = 0; int win_width = 640, win_height = 480;
int flag = getopt(argc, argv, optstr); int flag = getopt(argc, argv, optstr);
@ -120,6 +121,11 @@ run(int argc, char *argv[]) {
} }
break; break;
case 'l':
_log_dirname = Filename::from_os_specific(optarg).to_os_specific();
_log_basename = "panda3d";
break;
case 'h': case 'h':
case '?': case '?':
case '+': case '+':
@ -321,7 +327,6 @@ get_plugin(const string &download_url, const string &this_platform, bool force_d
// Couldn't read it, so go get it. // Couldn't read it, so go get it.
string url = download_url; string url = download_url;
url += "contents.xml"; url += "contents.xml";
cerr << "Getting URL " << url << "\n";
HTTPClient *http = HTTPClient::get_global_ptr(); HTTPClient *http = HTTPClient::get_global_ptr();
PT(HTTPChannel) channel = http->get_document(url); PT(HTTPChannel) channel = http->get_document(url);
@ -436,7 +441,8 @@ get_core_api(const Filename &contents_filename, const string &download_url,
#endif // P3D_PLUGIN_P3D_PLUGIN #endif // P3D_PLUGIN_P3D_PLUGIN
if (!load_plugin(pathname, contents_filename.to_os_specific(), if (!load_plugin(pathname, contents_filename.to_os_specific(),
download_url, this_platform)) { download_url, this_platform, _log_dirname,
_log_basename)) {
cerr << "Unable to launch core API in " << pathname << "\n" << flush; cerr << "Unable to launch core API in " << pathname << "\n" << flush;
return false; return false;
} }
@ -481,7 +487,6 @@ handle_request(P3D_request *request) {
switch (request->_request_type) { switch (request->_request_type) {
case P3D_RT_stop: case P3D_RT_stop:
cerr << "Got P3D_RT_stop\n";
delete_instance(request->_instance); delete_instance(request->_instance);
#ifdef _WIN32 #ifdef _WIN32
// Post a silly message to spin the event loop. // Post a silly message to spin the event loop.
@ -491,8 +496,6 @@ handle_request(P3D_request *request) {
break; break;
case P3D_RT_get_url: case P3D_RT_get_url:
cerr << "Got P3D_RT_get_url: " << request->_request._get_url._url
<< "\n";
{ {
int unique_id = request->_request._get_url._unique_id; int unique_id = request->_request._get_url._unique_id;
const string &url = request->_request._get_url._url; const string &url = request->_request._get_url._url;
@ -504,8 +507,6 @@ handle_request(P3D_request *request) {
break; break;
case P3D_RT_post_url: case P3D_RT_post_url:
cerr << "Got P3D_RT_post_url: " << request->_request._post_url._url
<< "\n";
{ {
int unique_id = request->_request._post_url._unique_id; int unique_id = request->_request._post_url._unique_id;
const string &url = request->_request._post_url._url; const string &url = request->_request._post_url._url;
@ -519,9 +520,15 @@ handle_request(P3D_request *request) {
break; break;
case P3D_RT_notify: case P3D_RT_notify:
cerr << "Got P3D_RT_notify: " << request->_request._notify._message {
<< "\n"; if (strcmp(request->_request._notify._message, "ondownloadnext") == 0) {
// Ignore notifications. // Tell the user we're downloading a package.
report_downloading_package(request->_instance);
} else if (strcmp(request->_request._notify._message, "ondownloadcomplete") == 0) {
// Tell the user we're done downloading.
report_download_complete(request->_instance);
}
}
break; break;
default: default:
@ -624,6 +631,30 @@ create_instance(const string &p3d, P3D_window_type window_type,
is_local = true; is_local = true;
} }
// Build up the token list.
pvector<P3D_token> tokens;
string log_basename;
if (!_log_dirname.empty()) {
// Generate output to a logfile.
log_basename = p3d_filename.get_basename_wo_extension();
P3D_token token;
token._keyword = "log_basename";
token._value = log_basename.c_str();
tokens.push_back(token);
} else {
// Send output to the console.
P3D_token token;
token._keyword = "console_output";
token._value = "1";
tokens.push_back(token);
}
P3D_token *tokens_p;
size_t num_tokens = tokens.size();
if (!tokens.empty()) {
tokens_p = &tokens[0];
}
// Build up the argument list, beginning with the p3d_filename. // Build up the argument list, beginning with the p3d_filename.
pvector<const char *> argv; pvector<const char *> argv;
argv.push_back(os_p3d_filename.c_str()); argv.push_back(os_p3d_filename.c_str());
@ -631,13 +662,15 @@ create_instance(const string &p3d, P3D_window_type window_type,
argv.push_back(args[i]); argv.push_back(args[i]);
} }
P3D_instance *inst = P3D_new_instance(NULL, NULL, 0, P3D_instance *inst = P3D_new_instance(NULL, tokens_p, num_tokens,
argv.size(), &argv[0], NULL); argv.size(), &argv[0], NULL);
if (inst != NULL) { if (inst != NULL) {
// We call start() first, to give the core API a chance to notice
// the "hidden" attrib before we set the window parameters.
P3D_instance_start(inst, is_local, os_p3d_filename.c_str());
P3D_instance_setup_window P3D_instance_setup_window
(inst, window_type, win_x, win_y, win_width, win_height, parent_window); (inst, window_type, win_x, win_y, win_width, win_height, parent_window);
P3D_instance_start(inst, is_local, os_p3d_filename.c_str());
} }
return inst; return inst;
@ -682,10 +715,10 @@ usage() {
<< " panda3d -m [opts] file_a.p3d file_b.p3d [file_c.p3d ...]\n\n" << " panda3d -m [opts] file_a.p3d file_b.p3d [file_c.p3d ...]\n\n"
<< "This program is used to execute a Panda3D application bundle stored\n" << "This program is used to execute a Panda3D application bundle stored\n"
<< "in a .p3d file. In the first form, without a -m option, it\n" << "in a .p3d file. In the first form, without the -m option, it\n"
<< "executes one application; remaining arguments following the\n" << "executes one application; remaining arguments following the\n"
<< "application name are passed into the application. In the second\n" << "application name are passed into the application. In the second\n"
<< "form, with a -m option, it can execute multiple applications\n" << "form, with the -m option, it can execute multiple applications\n"
<< "simultaneously, though in this form arguments cannot be passed into\n" << "simultaneously, though in this form arguments cannot be passed into\n"
<< "the applications.\n\n" << "the applications.\n\n"
@ -708,6 +741,11 @@ usage() {
<< " Specify the position (origin) of the graphic window on the\n" << " Specify the position (origin) of the graphic window on the\n"
<< " screen, or on the parent window.\n\n" << " screen, or on the parent window.\n\n"
<< " -l log_dirname\n"
<< " Specify the full path to the directory in which log files are\n"
<< " to be written. If this is not specified, the default is to send\n"
<< " the application output to the console.\n\n"
<< " -f\n" << " -f\n"
<< " Force a HTTP contact to the Panda3D download server, to check\n" << " Force a HTTP contact to the Panda3D download server, to check\n"
<< " if a new version is available. Normally, this is done only\n" << " if a new version is available. Normally, this is done only\n"
@ -743,6 +781,44 @@ parse_int_pair(char *arg, int &x, int &y) {
return false; return false;
} }
////////////////////////////////////////////////////////////////////
// Function: Panda3D::report_downloading_package
// Access: Private
// Description: Tells the user we have to download a package.
////////////////////////////////////////////////////////////////////
void Panda3D::
report_downloading_package(P3D_instance *instance) {
P3D_object *obj = P3D_instance_get_panda_script_object(instance);
P3D_object *display_name = P3D_object_get_property(obj, "downloadPackageDisplayName");
if (display_name == NULL) {
cerr << "no name: " << obj << "\n";
return;
}
int name_length = P3D_object_get_string(display_name, NULL, 0);
char *name = new char[name_length + 1];
P3D_object_get_string(display_name, name, name_length + 1);
cerr << "Downloading " << name << "\n";
delete[] name;
P3D_object_decref(display_name);
_reporting_download = true;
}
////////////////////////////////////////////////////////////////////
// Function: Panda3D::report_download_complete
// Access: Private
// Description: Tells the user we're done downloading packages
////////////////////////////////////////////////////////////////////
void Panda3D::
report_download_complete(P3D_instance *instance) {
if (_reporting_download) {
cerr << "Download complete.\n";
}
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: Panda3D::URLGetter::Constructor // Function: Panda3D::URLGetter::Constructor
// Access: Public // Access: Public
@ -758,8 +834,6 @@ URLGetter(P3D_instance *instance, int unique_id,
{ {
HTTPClient *http = HTTPClient::get_global_ptr(); HTTPClient *http = HTTPClient::get_global_ptr();
cerr << "Getting URL " << _url << "\n";
_channel = http->make_channel(false); _channel = http->make_channel(false);
if (_post_data.empty()) { if (_post_data.empty()) {
_channel->begin_get_document(_url); _channel->begin_get_document(_url);
@ -815,8 +889,6 @@ run() {
status = P3D_RC_generic_error; status = P3D_RC_generic_error;
} }
cerr << "Error getting URL " << _url << "\n"; cerr << "Error getting URL " << _url << "\n";
} else {
cerr << "Done getting URL " << _url << ", got " << _bytes_sent << " bytes\n";
} }
P3D_instance_feed_url_stream P3D_instance_feed_url_stream

View File

@ -65,9 +65,15 @@ private:
void usage(); void usage();
bool parse_int_pair(char *arg, int &x, int &y); bool parse_int_pair(char *arg, int &x, int &y);
void report_downloading_package(P3D_instance *instance);
void report_download_complete(P3D_instance *instance);
private: private:
string _root_dir; string _root_dir;
string _log_dirname;
string _log_basename;
FileSpec _core_api_dll; FileSpec _core_api_dll;
bool _reporting_download;
typedef pset<P3D_instance *> Instances; typedef pset<P3D_instance *> Instances;
Instances _instances; Instances _instances;

View File

@ -84,7 +84,7 @@ def makePackedApp(args):
elif option == '-h': elif option == '-h':
print __doc__ print __doc__
sys.exit(1) sys.exit(1)
if not args: if not args:
raise ArgumentError, "No destination app specified. Use:\npackp3d.py app.p3d" raise ArgumentError, "No destination app specified. Use:\npackp3d.py app.p3d"
@ -133,10 +133,6 @@ def main(appRunner):
""" This function is called when this module is invoked as """ This function is called when this module is invoked as
packp3d.p3d. """ packp3d.p3d. """
print "args = %s" % (appRunner.argv,)
vfs = VirtualFileSystem.getGlobalPtr()
print "cwd = %s, %s" % (vfs.getCwd(), ExecutionEnvironment.getCwd())
print "sys.path = %s" % (sys.path,)
try: try:
makePackedApp(appRunner.argv[1:]) makePackedApp(appRunner.argv[1:])
except ArgumentError, e: except ArgumentError, e:
@ -145,7 +141,6 @@ def main(appRunner):
sys.exit(0) sys.exit(0)
if __name__ == '__main__': if __name__ == '__main__':
print "sys.path = %s" % (sys.path,)
try: try:
makePackedApp(sys.argv[1:]) makePackedApp(sys.argv[1:])
except ArgumentError, e: except ArgumentError, e:

View File

@ -244,7 +244,6 @@ class AppRunner(DirectObject):
same page with the Panda3D plugin. """ same page with the Panda3D plugin. """
self.dom = dom self.dom = dom
print "setBrowserScriptObject(%s)" % (dom)
# Now evaluate any deferred expressions. # Now evaluate any deferred expressions.
for expression in self.deferredEvals: for expression in self.deferredEvals:
@ -334,11 +333,6 @@ class AppRunner(DirectObject):
settings, for future windows; or applies them directly to the settings, for future windows; or applies them directly to the
main window if the window has already been opened. """ main window if the window has already been opened. """
print "session %s, nextScriptId = %s" % (self.sessionId, self.nextScriptId)
print "setupWindow %s, %s, %s, %s, %s, %s, %s" % (windowType, x, y, width, height, parent, subprocessWindow)
if self.started and base.win: if self.started and base.win:
# If we've already got a window, this must be a # If we've already got a window, this must be a
# resize/reposition request. # resize/reposition request.

View File

@ -248,7 +248,7 @@ open = file
def listdir(path): def listdir(path):
""" Implements os.listdir over vfs. """ """ Implements os.listdir over vfs. """
files = [] files = []
dirlist = _vfs.scanDirectory(path) dirlist = _vfs.scanDirectory(pm.Filename.fromOsSpecific(path))
if dirlist is None: if dirlist is None:
message = 'No such file or directory: %s' % (path) message = 'No such file or directory: %s' % (path)
raise OSError, message raise OSError, message