X-Git-Url: https://mudpy.org/gitweb?p=mudpy.git;a=blobdiff_plain;f=lib%2Fmudpy%2Fmisc.py;h=1f3909b2af0897e60f39737c4ae45dd3d1d0c26f;hp=96957bc7ec28deb9a9c03c328b9d12c8de24386f;hb=2a2a4dd5265401038795a81815141e277998c33f;hpb=bca875d67e9f4fad50bf47a6c9695687a6e95778 diff --git a/lib/mudpy/misc.py b/lib/mudpy/misc.py index 96957bc..1f3909b 100644 --- a/lib/mudpy/misc.py +++ b/lib/mudpy/misc.py @@ -6,8 +6,6 @@ # terms provided in the LICENSE file distributed with this software. import codecs -import ctypes -import ctypes.util import os import random import re @@ -76,8 +74,13 @@ class Element: self.origin = self.universe.files[filename] # add a data section to the origin if necessary - if not self.origin.data.has_section(self.key): - self.origin.data.add_section(self.key) + # TODO(fungi): remove this indirection after the YAML transition + if self.origin._format == "yaml": + if self.key not in self.origin.data: + self.origin.data[self.key] = {} + else: + if not self.origin.data.has_section(self.key): + self.origin.data.add_section(self.key) # add or replace this element in the universe self.universe.contents[self.key] = self @@ -97,10 +100,17 @@ class Element: def facets(self): """Return a list of non-inherited facets for this element.""" - if self.key in self.origin.data.sections(): - return self.origin.data.options(self.key) + # TODO(fungi): remove this indirection after the YAML transition + if self.origin._format == "yaml": + try: + return self.origin.data[self.key].keys() + except KeyError: + return [] else: - return [] + if self.key in self.origin.data.sections(): + return self.origin.data.options(self.key) + else: + return [] def has_facet(self, facet): """Return whether the non-inherited facet exists.""" @@ -129,31 +139,58 @@ class Element: """Retrieve values.""" if default is None: default = "" - if self.origin.data.has_option(self.key, facet): - raw_data = self.origin.data.get(self.key, facet) - if raw_data.startswith("u\"") or raw_data.startswith("u'"): - raw_data = raw_data[1:] - raw_data.strip("\"'") - return raw_data - elif self.has_facet("inherit"): - for ancestor in self.ancestry(): - if self.universe.contents[ancestor].has_facet(facet): - return self.universe.contents[ancestor].get(facet) + # TODO(fungi): remove this indirection after the YAML transition + if self.origin._format == "yaml": + try: + return self.origin.data[self.key][facet] + except KeyError: + pass + if self.has_facet("inherit"): + for ancestor in self.ancestry(): + if self.universe.contents[ancestor].has_facet(facet): + return self.universe.contents[ancestor].get(facet) + else: + return default else: - return default + if self.origin.data.has_option(self.key, facet): + raw_data = self.origin.data.get(self.key, facet) + if raw_data.startswith("u\"") or raw_data.startswith("u'"): + raw_data = raw_data[1:] + raw_data.strip("\"'") + return raw_data + elif self.has_facet("inherit"): + for ancestor in self.ancestry(): + if self.universe.contents[ancestor].has_facet(facet): + return self.universe.contents[ancestor].get(facet) + else: + return default def getboolean(self, facet, default=None): """Retrieve values as boolean type.""" if default is None: default = False - if self.origin.data.has_option(self.key, facet): - return self.origin.data.getboolean(self.key, facet) - elif self.has_facet("inherit"): + # TODO(fungi): remove this indirection after the YAML transition + if self.origin._format == "yaml": + try: + return bool(self.origin.data[self.key][facet]) + except KeyError: + pass for ancestor in self.ancestry(): - if self.universe.contents[ancestor].has_facet(facet): + try: return self.universe.contents[ancestor].getboolean(facet) - else: + except KeyError: + pass return default + else: + if self.origin.data.has_option(self.key, facet): + return self.origin.data.getboolean(self.key, facet) + elif self.has_facet("inherit"): + for ancestor in self.ancestry(): + if self.universe.contents[ancestor].has_facet(facet): + return self.universe.contents[ancestor].getboolean( + facet) + else: + return default def getint(self, facet, default=None): """Return values as int type.""" @@ -265,9 +302,9 @@ class Element: def update_location(self): """Make sure the location's contents contain this element.""" - location = self.get("location") - if location in self.universe.contents: - self.universe.contents[location].contents[self.key] = self + area = self.get("location") + if area in self.universe.contents: + self.universe.contents[area].contents[self.key] = self def clean_contents(self): """Make sure the element's contents aren't bogus.""" @@ -275,15 +312,15 @@ class Element: if element.get("location") != self.key: del self.contents[element.key] - def go_to(self, location): - """Relocate the element to a specific location.""" + def go_to(self, area): + """Relocate the element to a specific area.""" current = self.get("location") if current and self.key in self.universe.contents[current].contents: del universe.contents[current].contents[self.key] - if location in self.universe.contents: - self.set("location", location) - self.universe.contents[location].contents[self.key] = self - self.look_at(location) + if area in self.universe.contents: + self.set("location", area) + self.universe.contents[area].contents[self.key] = self + self.look_at(area) def go_home(self): """Relocate the element to its default location.""" @@ -368,9 +405,9 @@ class Element: self.send(message) def portals(self): - """Map the portal directions for a room to neighbors.""" + """Map the portal directions for an area to neighbors.""" portals = {} - if re.match("""^location:-?\d+,-?\d+,-?\d+$""", self.key): + if re.match("""^area:-?\d+,-?\d+,-?\d+$""", self.key): coordinates = [(int(x)) for x in self.key.split(":")[1].split(",")] directions = self.universe.categories["internal"]["directions"] @@ -384,7 +421,7 @@ class Element: for portal in self.getlist("gridlinks"): adjacent = map(lambda c, o: c + o, coordinates, offsets[portal]) - neighbor = "location:" + ",".join( + neighbor = "area:" + ",".join( [(str(x)) for x in adjacent] ) if neighbor in self.universe.contents: @@ -481,13 +518,13 @@ class Universe: # go through all elements to clear out inactive avatar locations for element in self.contents.values(): - location = element.get("location") - if element in inactive_avatars and location: - if location in self.contents and element.key in self.contents[ - location + area = element.get("location") + if element in inactive_avatars and area: + if area in self.contents and element.key in self.contents[ + area ].contents: - del self.contents[location].contents[element.key] - element.set("default_location", location) + del self.contents[area].contents[element.key] + element.set("default_location", area) element.remove_facet("location") # another pass to straighten out all the element contents @@ -895,14 +932,13 @@ class User: try: self.connection.send(self.output_queue[0]) del self.output_queue[0] - except: + except BrokenPipeError: if self.account and self.account.get("name"): account = self.account.get("name") else: account = "an unknown user" - log("Sending to %s raised an exception (broken pipe?)." - % account, 7) - pass + log("Broken pipe sending to %s." % account, 7) + self.state = "disconnecting" def enqueue_input(self): """Process and enqueue any new input.""" @@ -910,7 +946,7 @@ class User: # check for some input try: raw_input = self.connection.recv(1024) - except: + except (BlockingIOError, OSError): raw_input = b"" # we got something @@ -1492,7 +1528,7 @@ def check_for_connection(listening_socket): # try to accept a new connection try: connection, address = listening_socket.accept() - except: + except BlockingIOError: return None # note that we got one @@ -2068,7 +2104,7 @@ def command_look(actor, parameters): def command_say(actor, parameters): - """Speak to others in the same room.""" + """Speak to others in the same area.""" # check for replacement macros and escape them parameters = escape_macros(parameters) @@ -2132,7 +2168,7 @@ def command_say(actor, parameters): # capitalize the first letter message = message[0].upper() + message[1:] - # tell the room + # tell the area if message: actor.echo_to_location( actor.get("name") + " " + action + "s, \"" + message + "\"" @@ -2233,8 +2269,9 @@ def command_show(actor, parameters): else: try: message = repr(eval(" ".join(arguments[1:]))) - except: - message = "Your expression raised an exception!" + except Exception as e: + message = ("$(red)Your expression raised an exception...$(eol)" + "$(eol)$(bld)%s$(nrm)" % e) elif arguments[0] == "log": if len(arguments) == 4: if re.match("^\d+$", arguments[3]) and int(arguments[3]) >= 0: @@ -2399,48 +2436,6 @@ def daemonize(universe): # only if this is what we're configured to do if universe.contents["internal:process"].getboolean("daemon"): - # if possible, we want to rename the process to the same as the script - new_argv = b"\x00".join(x.encode("utf-8") for x in sys.argv) + b"\x00" - short_argv0 = os.path.basename(sys.argv[0]).encode("utf-8") + b"\x00" - - # attempt the linux way first - try: - argv_array = ctypes.POINTER(ctypes.c_char_p) - ctypes.pythonapi.Py_GetArgcArgv.argtypes = ( - ctypes.POINTER(ctypes.c_int), - ctypes.POINTER(argv_array) - ) - argc = argv_array() - ctypes.pythonapi.Py_GetArgcArgv( - ctypes.c_int(0), - ctypes.pointer(argc) - ) - old_argv0_size = len(argc.contents.value) - ctypes.memset(argc.contents, 0, len(new_argv) + old_argv0_size) - ctypes.memmove(argc.contents, new_argv, len(new_argv)) - ctypes.CDLL(ctypes.util.find_library("c")).prctl( - 15, - short_argv0, - 0, - 0, - 0 - ) - - except: - - # since that failed, maybe it's bsd? - try: - - # much simpler, since bsd has a libc function call for this - ctypes.CDLL(ctypes.util.find_library("c")).setproctitle( - new_argv - ) - - except: - - # that didn't work either, so just log that we couldn't - log("Failed to rename the interpreter process (cosmetic).") - # log before we start forking around, so the terminal gets the message log("Disassociating from the controlling terminal.") @@ -2507,14 +2502,9 @@ def excepthook(excepttype, value, tracebackdata): # try to log it, if possible try: log(message, 9) - except: - pass - - # try to write it to stderr, if possible - try: - sys.stderr.write(message) - except: - pass + except Exception as e: + # try to write it to stderr, if possible + sys.stderr.write(message + "\nException while logging...\n%s" % e) def sighook(what, where):