diff --git a/direct/src/distributed/ConnectionRepository.py b/direct/src/distributed/ConnectionRepository.py index 41858e4a3f..e6fddd39a3 100644 --- a/direct/src/distributed/ConnectionRepository.py +++ b/direct/src/distributed/ConnectionRepository.py @@ -641,9 +641,9 @@ class ConnectionRepository( # Zero-length datagrams might freak out the server. No point # in sending them, anyway. if datagram.getLength() > 0: - if self.notify.getDebug(): - print "ConnectionRepository sending datagram:" - datagram.dumpHex(ostream) +## if self.notify.getDebug(): +## print "ConnectionRepository sending datagram:" +## datagram.dumpHex(ostream) self.sendDatagram(datagram) diff --git a/direct/src/distributed/ServerRepository.py b/direct/src/distributed/ServerRepository.py index 40b856fe59..9f9a646cfb 100644 --- a/direct/src/distributed/ServerRepository.py +++ b/direct/src/distributed/ServerRepository.py @@ -340,7 +340,7 @@ class ServerRepository: if self.notify.getDebug(): self.notify.debug( "ServerRepository received datagram from %s:" % (client.doIdBase)) - datagram.dumpHex(ostream) + #datagram.dumpHex(ostream) if not client: # This shouldn't be possible. @@ -689,7 +689,7 @@ class ServerRepository: if self.notify.getDebug(): self.notify.debug( "ServerRepository sending to all in zone %s except %s:" % (zoneId, map(lambda c: c.doIdBase, exceptionList))) - datagram.dumpHex(ostream) + #datagram.dumpHex(ostream) for client in self.zonesToClients.get(zoneId, []): if client not in exceptionList: @@ -706,7 +706,7 @@ class ServerRepository: if self.notify.getDebug(): self.notify.debug( "ServerRepository sending to all except %s:" % (map(lambda c: c.doIdBase, exceptionList),)) - datagram.dumpHex(ostream) + #datagram.dumpHex(ostream) for client in self.clientsByConnection.values(): if client not in exceptionList: diff --git a/direct/src/plugin/p3dInstance.cxx b/direct/src/plugin/p3dInstance.cxx index c53c0fba8d..409778291b 100644 --- a/direct/src/plugin/p3dInstance.cxx +++ b/direct/src/plugin/p3dInstance.cxx @@ -1315,6 +1315,27 @@ auth_finished_main_thread() { check_p3d_signature(); } +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::uninstall +// Access: Public +// Description: Stops the instance (if it is running) and deletes any +// packages referenced by the instance. This is +// normally called by JavaScript, via +// P3DMainObject::call_uninstall(). +//////////////////////////////////////////////////////////////////// +void P3DInstance:: +uninstall() { + if (_session != NULL) { + _session->shutdown(); + } + + Packages::const_iterator pi; + for (pi = _packages.begin(); pi != _packages.end(); ++pi) { + P3DPackage *package = (*pi); + package->uninstall(); + } +} + //////////////////////////////////////////////////////////////////// // Function: P3DInstance::priv_set_p3d_filename // Access: Private diff --git a/direct/src/plugin/p3dInstance.h b/direct/src/plugin/p3dInstance.h index a1eae0da37..b52e295074 100644 --- a/direct/src/plugin/p3dInstance.h +++ b/direct/src/plugin/p3dInstance.h @@ -116,6 +116,8 @@ public: void auth_finished_sub_thread(); void auth_finished_main_thread(); + void uninstall(); + private: class ImageDownload : public P3DFileDownload { public: diff --git a/direct/src/plugin/p3dInstanceManager.cxx b/direct/src/plugin/p3dInstanceManager.cxx index 37ef4bd2c2..288b4e2aa6 100644 --- a/direct/src/plugin/p3dInstanceManager.cxx +++ b/direct/src/plugin/p3dInstanceManager.cxx @@ -1067,10 +1067,11 @@ scan_directory(const string &dirname, vector &contents) { //////////////////////////////////////////////////////////////////// // Function: P3DInstanceManager::scan_directory_recursively // Access: Public, Static -// Description: Fills up the indicated vector with the list of all -// files (but not directories) rooted at the indicated -// dirname and below. The filenames generated are -// relative to the root of the dirname, with slashes +// Description: Fills up filename_contents with the list of all +// files (but not directories), and dirname_contents +// with the list of all directories, rooted at the +// indicated dirname and below. The filenames generated +// are relative to the root of the dirname, with slashes // (not backslashes) as the directory separator // character. // @@ -1078,7 +1079,9 @@ scan_directory(const string &dirname, vector &contents) { // dirname wasn't a directory or something like that. //////////////////////////////////////////////////////////////////// bool P3DInstanceManager:: -scan_directory_recursively(const string &dirname, vector &contents, +scan_directory_recursively(const string &dirname, + vector &filename_contents, + vector &dirname_contents, const string &prefix) { vector dir_contents; if (!scan_directory(dirname, dir_contents)) { @@ -1093,14 +1096,16 @@ scan_directory_recursively(const string &dirname, vector &contents, // directory, or is it a regular file? string pathname = dirname + "/" + (*si); string rel_filename = prefix + (*si); - if (scan_directory_recursively(pathname, contents, rel_filename + "/")) { + if (scan_directory_recursively(pathname, filename_contents, + dirname_contents, rel_filename + "/")) { // It's a directory, and it's just added its results to the // contents. + dirname_contents.push_back(rel_filename); } else { // It's not a directory, so assume it's an ordinary file, and // add it to the contents. - contents.push_back(rel_filename); + filename_contents.push_back(rel_filename); } } diff --git a/direct/src/plugin/p3dInstanceManager.h b/direct/src/plugin/p3dInstanceManager.h index 08b2b44992..811de78fcf 100644 --- a/direct/src/plugin/p3dInstanceManager.h +++ b/direct/src/plugin/p3dInstanceManager.h @@ -131,7 +131,9 @@ public: static inline char encode_hexdigit(int c); static bool scan_directory(const string &dirname, vector &contents); - static bool scan_directory_recursively(const string &dirname, vector &contents, + static bool scan_directory_recursively(const string &dirname, + vector &filename_contents, + vector &dirname_contents, const string &prefix = ""); static bool remove_file_from_list(vector &contents, const string &filename); diff --git a/direct/src/plugin/p3dMainObject.cxx b/direct/src/plugin/p3dMainObject.cxx index aa02852ea7..4417ced798 100644 --- a/direct/src/plugin/p3dMainObject.cxx +++ b/direct/src/plugin/p3dMainObject.cxx @@ -191,6 +191,8 @@ has_method(const string &method_name) { return true; } else if (method_name == "read_system_log") { return true; + } else if (method_name == "uninstall") { + return true; } if (_pyobj == NULL) { @@ -225,6 +227,8 @@ call(const string &method_name, bool needs_response, return call_read_game_log(params, num_params); } else if (method_name == "read_system_log") { return call_read_system_log(params, num_params); + } else if (method_name == "uninstall") { + return call_uninstall(params, num_params); } if (_pyobj == NULL) { @@ -435,3 +439,24 @@ read_log(const string &log_pathname, P3D_object *params[], int num_params) { return result; } + +//////////////////////////////////////////////////////////////////// +// Function: P3DMainObject::call_uninstall +// Access: Private +// Description: Implements the uninstall() plugin method, which +// removes all Panda installed files for a particular +// host, or referenced by a particular p3d file. +//////////////////////////////////////////////////////////////////// +P3D_object *P3DMainObject:: +call_uninstall(P3D_object *params[], int num_params) { + P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); + + if (_inst != NULL) { + nout << "uninstall for " << _inst << "\n"; + _inst->uninstall(); + return inst_mgr->new_bool_object(true); + } + + nout << "couldn't uninstall; no instance.\n"; + return inst_mgr->new_bool_object(false); +} diff --git a/direct/src/plugin/p3dMainObject.h b/direct/src/plugin/p3dMainObject.h index a04af29e5a..a77e8b004e 100644 --- a/direct/src/plugin/p3dMainObject.h +++ b/direct/src/plugin/p3dMainObject.h @@ -73,6 +73,7 @@ private: P3D_object *call_read_system_log(P3D_object *params[], int num_params); P3D_object *read_log(const string &log_pathname, P3D_object *params[], int num_params); + P3D_object *call_uninstall(P3D_object *params[], int num_params); private: P3D_object *_pyobj; diff --git a/direct/src/plugin/p3dPackage.cxx b/direct/src/plugin/p3dPackage.cxx index bb02bb4de8..ba8621006e 100755 --- a/direct/src/plugin/p3dPackage.cxx +++ b/direct/src/plugin/p3dPackage.cxx @@ -206,6 +206,78 @@ remove_instance(P3DInstance *inst) { begin_info_download(); } +//////////////////////////////////////////////////////////////////// +// Function: P3DPackage::uninstall +// Access: Public +// Description: Removes the package directory and all its contents +// from the user's hard disk. +//////////////////////////////////////////////////////////////////// +void P3DPackage:: +uninstall() { + if (_package_dir.empty()) { + nout << "Cannot uninstall " << _package_name << ": package directory not yet known.\n"; + return; + } + + nout << "Uninstalling package " << _package_name << " from " << _package_dir << "\n"; + + P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); + vector contents, dirname_contents; + inst_mgr->scan_directory_recursively(_package_dir, contents, + dirname_contents); + + vector::iterator ci; + for (ci = contents.begin(); ci != contents.end(); ++ci) { + string filename = (*ci); + string pathname = _package_dir + "/" + filename; + +#ifdef _WIN32 + // Windows can't delete a file if it's read-only. + chmod(pathname.c_str(), 0644); +#endif + int result = unlink(pathname.c_str()); + if (result == 0) { + nout << " Deleted " << filename << "\n"; + } else { + nout << " Could not delete " << filename << "\n"; + } + } + + // Now delete all of the directories too. Go in reverse order so we + // remove deeper directories first. + vector::reverse_iterator rci; + for (rci = dirname_contents.rbegin(); rci != dirname_contents.rend(); ++rci) { + string filename = (*rci); + string pathname = _package_dir + "/" + filename; + +#ifdef _WIN32 + chmod(pathname.c_str(), 0755); +#endif + int result = rmdir(pathname.c_str()); + if (result == 0) { + nout << " Removed directory " << filename << "\n"; + } else { + nout << " Could not remove directory " << filename << "\n"; + } + } + + // Finally, delete the package directory itself. + string pathname = _package_dir; +#ifdef _WIN32 + chmod(pathname.c_str(), 0755); +#endif + int result = rmdir(pathname.c_str()); + if (result == 0) { + nout << "Removed directory " << _package_dir << "\n"; + } else { + nout << "Could not remove directory " << _package_dir << "\n"; + } + + _info_ready = false; + _ready = false; + _failed = false; +} + //////////////////////////////////////////////////////////////////// // Function: P3DPackage::make_xml // Access: Public @@ -442,7 +514,7 @@ contents_file_redownload_finished(bool success) { // rest of the download process. //////////////////////////////////////////////////////////////////// void P3DPackage:: -host_got_contents_file() { +host_got_contents_file(bool continue_download) { if (!_alt_host.empty()) { // If we have an alt host specification, maybe we need to change // the host now. @@ -476,10 +548,12 @@ host_got_contents_file() { _package_dir += string("/") + _package_version; } - // Ensure the package directory exists; create it if it does not. - mkdir_complete(_package_dir, nout); - - download_desc_file(); + if (continue_download) { + // Ensure the package directory exists; create it if it does not. + mkdir_complete(_package_dir, nout); + + download_desc_file(); + } } //////////////////////////////////////////////////////////////////// @@ -658,8 +732,8 @@ got_desc_file(TiXmlDocument *doc, bool freshly_downloaded) { // Get a list of all of the files in the directory, so we can remove // files that don't belong. - vector contents; - inst_mgr->scan_directory_recursively(_package_dir, contents); + vector contents, dirname_contents; + inst_mgr->scan_directory_recursively(_package_dir, contents, dirname_contents); inst_mgr->remove_file_from_list(contents, _desc_file_basename); inst_mgr->remove_file_from_list(contents, _uncompressed_archive.get_filename()); diff --git a/direct/src/plugin/p3dPackage.h b/direct/src/plugin/p3dPackage.h index c338f944f2..1343a5223e 100755 --- a/direct/src/plugin/p3dPackage.h +++ b/direct/src/plugin/p3dPackage.h @@ -69,6 +69,8 @@ public: void add_instance(P3DInstance *inst); void remove_instance(P3DInstance *inst); + void uninstall(); + TiXmlElement *make_xml(); private: @@ -192,7 +194,7 @@ private: void contents_file_download_finished(bool success); void redownload_contents_file(Download *download); void contents_file_redownload_finished(bool success); - void host_got_contents_file(); + void host_got_contents_file(bool continue_download = true); void download_desc_file(); void desc_file_download_finished(bool success); diff --git a/direct/src/plugin/p3dPythonRun.cxx b/direct/src/plugin/p3dPythonRun.cxx index ed14253d38..294560d0c5 100755 --- a/direct/src/plugin/p3dPythonRun.cxx +++ b/direct/src/plugin/p3dPythonRun.cxx @@ -1531,14 +1531,26 @@ pyobj_to_xml(PyObject *value) { } } else if (PyString_Check(value)) { - // A string value. + // A string value. Insist that it is utf-8 encoded, by decoding + // it first using the standard encoding, then re-encoding it. xvalue->SetAttribute("type", "string"); - char *buffer; - Py_ssize_t length; - if (PyString_AsStringAndSize(value, &buffer, &length) != -1) { - string str(buffer, length); - xvalue->SetAttribute("value", str); + PyObject *ustr = PyUnicode_FromEncodedObject(value, NULL, NULL); + if (ustr == NULL) { + PyErr_Print(); + return xvalue; + } else { + PyObject *as_str = PyUnicode_AsUTF8String(ustr); + if (as_str != NULL) { + char *buffer; + Py_ssize_t length; + if (PyString_AsStringAndSize(as_str, &buffer, &length) != -1) { + string str(buffer, length); + xvalue->SetAttribute("value", str); + } + Py_DECREF(as_str); + } + Py_DECREF(ustr); } } else if (PyTuple_Check(value)) { @@ -1685,7 +1697,7 @@ xml_to_pyobj(TiXmlElement *xvalue) { // don't get tripped up on embedded null characters. const string *value = xvalue->Attribute(string("value")); if (value != NULL) { - return PyString_FromStringAndSize(value->data(), value->length()); + return PyUnicode_DecodeUTF8(value->data(), value->length(), NULL); } } else if (strcmp(type, "undefined") == 0) { diff --git a/direct/src/plugin/p3d_plugin.h b/direct/src/plugin/p3d_plugin.h index 900189935f..450af1e950 100644 --- a/direct/src/plugin/p3d_plugin.h +++ b/direct/src/plugin/p3d_plugin.h @@ -470,8 +470,9 @@ P3D_object_get_float_method(P3D_object *object); return value is larger than buffer_size, the string has been truncated. If it is equal, there is no null character written to the buffer (like strncpy). You may call this method first with - buffer = NULL and buffer_size = 0 to return just the required - size of the buffer. */ + buffer = NULL and buffer_size = 0 to return just the required size + of the buffer. Note that P3D_object string data is internally + encoded using utf-8, by convention. */ typedef int P3D_object_get_string_method(P3D_object *object, char *buffer, int buffer_size); @@ -676,7 +677,8 @@ typedef P3D_object * P3D_new_float_object_func(double value); /* Returns a new-reference P3D_object of type string. The supplied - string is copied into the object and stored internally. */ + string should be already encoded in utf-8. It is copied into the + object and stored internally. */ typedef P3D_object * P3D_new_string_object_func(const char *string, int length); diff --git a/direct/src/showbase/ShowBase.py b/direct/src/showbase/ShowBase.py index 4cfa04d134..976f69c491 100644 --- a/direct/src/showbase/ShowBase.py +++ b/direct/src/showbase/ShowBase.py @@ -861,6 +861,7 @@ class ShowBase(DirectObject.DirectObject): def sleepCycleTask(self, task): Thread.sleep(self.clientSleep) + #time.sleep(self.clientSleep) return Task.cont def setFrameRateMeter(self, flag):