From fd9acd6bf9fbc384989ecbbea0c20e16cbbf4142 Mon Sep 17 00:00:00 2001 From: Griatch Date: Mon, 23 Sep 2013 22:08:14 +0200 Subject: [PATCH] Fixed website. Fixing references to db_references, not sure how to add the m2m field access to the admin. Fixed wrapper for db_home. --- src/commands/default/tests.py | 2 +- src/objects/admin.py | 40 +++-- src/objects/models.py | 197 +++++++++++----------- src/players/admin.py | 17 +- src/players/models.py | 28 ++- src/server/caches.py | 139 +++------------ src/server/portal/portalsessionhandler.py | 4 +- src/server/portal/webclient.py | 4 +- src/server/server.py | 6 + src/typeclasses/models.py | 5 +- src/utils/create.py | 6 +- 11 files changed, 187 insertions(+), 261 deletions(-) diff --git a/src/commands/default/tests.py b/src/commands/default/tests.py index 615c577d65..7e4c108b20 100644 --- a/src/commands/default/tests.py +++ b/src/commands/default/tests.py @@ -72,7 +72,7 @@ class CommandTest(TestCase): "sets up testing environment" self.player = create.create_player("TestPlayer%i" % self.CID, "test@test.com", "testpassword", typeclass=TestPlayerClass) self.player2 = create.create_player("TestPlayer%ib" % self.CID, "test@test.com", "testpassword", typeclass=TestPlayerClass) - self.room1 = create.create_object("src.objects.objects.Room", key="Room%i"%self.CID) + self.room1 = create.create_object("src.objects.objects.Room", key="Room%i"%self.CID, testmode=True) self.room1.db.desc = "room_desc" self.room2 = create.create_object("src.objects.objects.Room", key="Room%ib" % self.CID) self.obj1 = create.create_object(TestObjectClass, key="Obj%i" % self.CID, location=self.room1, home=self.room1) diff --git a/src/objects/admin.py b/src/objects/admin.py index ffb62af803..4cf2a661a3 100644 --- a/src/objects/admin.py +++ b/src/objects/admin.py @@ -6,10 +6,8 @@ from django import forms from django.conf import settings from django.contrib import admin -from src.typeclasses.models import Attribute +from src.typeclasses.models import Attribute, Tag from src.objects.models import ObjectDB -from src.typeclasses.models import Tag, LiteAttribute - class AttributeInline(admin.TabularInline): # This class is currently not used, because PickleField objects are not editable. @@ -23,11 +21,6 @@ class TagInline(admin.TabularInline): raw_id_fields = ('tag',) extra = 0 -class LiteAttributeInline(admin.TabularInline): - model = LiteAttribute - fields = ('db_key', 'db_category', 'db_data') - extra = 0 - class TagAdmin(admin.ModelAdmin): fields = ('db_key', 'db_category', 'db_data') @@ -41,11 +34,11 @@ class ObjectCreateForm(forms.ModelForm): db_typeclass_path = forms.CharField(label="Typeclass",initial="Change to (for example) %s or %s." % (settings.BASE_OBJECT_TYPECLASS, settings.BASE_CHARACTER_TYPECLASS), widget=forms.TextInput(attrs={'size':'78'}), help_text="This defines what 'type' of entity this is. This variable holds a Python path to a module with a valid Evennia Typeclass. If you are creating a Character you should use the typeclass defined by settings.BASE_CHARACTER_TYPECLASS or one derived from that.") - db_permissions = forms.CharField(label="Permissions", - initial=settings.PERMISSION_PLAYER_DEFAULT, - required=False, - widget=forms.TextInput(attrs={'size':'78'}), - help_text="a comma-separated list of text strings checked by certain locks. They are mainly of use for Character objects. Character permissions overload permissions defined on a controlling Player. Most objects normally don't have any permissions defined.") + #db_permissions = forms.CharField(label="Permissions", + # initial=settings.PERMISSION_PLAYER_DEFAULT, + # required=False, + # widget=forms.TextInput(attrs={'size':'78'}), + # help_text="a comma-separated list of text strings checked by certain locks. They are mainly of use for Character objects. Character permissions overload permissions defined on a controlling Player. Most objects normally don't have any permissions defined.") db_cmdset_storage = forms.CharField(label="CmdSet", initial=settings.CMDSET_CHARACTER, required=False, @@ -75,17 +68,24 @@ class ObjectDBAdmin(admin.ModelAdmin): save_as = True save_on_top = True list_select_related = True - list_filter = ('db_permissions', 'db_typeclass_path') + list_filter = ('db_typeclass_path',) + #list_filter = ('db_permissions', 'db_typeclass_path') # editing fields setup form = ObjectEditForm fieldsets = ( (None, { - 'fields': (('db_key','db_typeclass_path'), ('db_permissions', 'db_lock_storage'), + 'fields': (('db_key','db_typeclass_path'), ('db_lock_storage', ), ('db_location', 'db_home'), 'db_destination','db_cmdset_storage' )}), ) + #fieldsets = ( + # (None, { + # 'fields': (('db_key','db_typeclass_path'), ('db_permissions', 'db_lock_storage'), + # ('db_location', 'db_home'), 'db_destination','db_cmdset_storage' + # )}), + # ) #deactivated temporarily, they cause empty objects to be created in admin inlines = [TagInline] @@ -96,10 +96,16 @@ class ObjectDBAdmin(admin.ModelAdmin): add_form = ObjectCreateForm add_fieldsets = ( (None, { - 'fields': (('db_key','db_typeclass_path'), 'db_permissions', + 'fields': (('db_key','db_typeclass_path'), ('db_location', 'db_home'), 'db_destination', 'db_cmdset_storage' )}), ) + #add_fieldsets = ( + # (None, { + # 'fields': (('db_key','db_typeclass_path'), 'db_permissions', + # ('db_location', 'db_home'), 'db_destination', 'db_cmdset_storage' + # )}), + # ) def get_fieldsets(self, request, obj=None): if not obj: return self.add_fieldsets @@ -130,4 +136,4 @@ class ObjectDBAdmin(admin.ModelAdmin): admin.site.register(ObjectDB, ObjectDBAdmin) -admin.site.register(Tag, TagAdmin) \ No newline at end of file +admin.site.register(Tag, TagAdmin) diff --git a/src/objects/models.py b/src/objects/models.py index 14960d22a1..12e054c57f 100644 --- a/src/objects/models.py +++ b/src/objects/models.py @@ -19,7 +19,6 @@ from django.db import models from django.conf import settings from src.typeclasses.models import TypedObject, TagHandler, NickHandler, AliasHandler, AttributeHandler -from src.server.caches import get_field_cache, set_field_cache, del_field_cache from src.server.caches import get_prop_cache, set_prop_cache from src.typeclasses.typeclass import TypeClass @@ -165,7 +164,8 @@ class ObjectDB(TypedObject): We have to be careful here since Player is also a TypedObject, so as to not create a loop. """ - player = get_field_cache(self, "player") + player = _GA(self, "db_player") + #player = get_field_cache(self, "player") if player: try: return player.typeclass @@ -178,7 +178,9 @@ class ObjectDB(TypedObject): "Setter. Allows for self.player = value" if inherits_from(player, TypeClass): player = player.dbobj - set_field_cache(self, "player", player) + _SA(self, "db_player", player) + _GA(self, "save")() + #set_field_cache(self, "player", player) # we must set this here or superusers won't be able to # bypass lockchecks unless they start the game connected # to the character in question. @@ -187,30 +189,37 @@ class ObjectDB(TypedObject): #@player.deleter def __player_del(self): "Deleter. Allows for del self.player" - del_field_cache(self, "player") + _SA(self, "db_player", None) + _GA(self, "save")() + #del_field_cache(self, "player") player = property(__player_get, __player_set, __player_del) - # sessid property (wraps db_sessid) + #sessid property (wraps db_sessid) #@property - #def __sessid_get(self): - # """ - # Getter. Allows for value = self.sessid. Since sessid - # is directly related to self.player, we cannot have - # a sessid without a player being connected (but the - # opposite could be true). - # """ - # if not get_field_cache(self, "sessid"): - # del_field_cache(self, "sessid") - # return get_field_cache(self, "sessid") - ##@sessid.setter - #def __sessid_set(self, sessid): - # "Setter. Allows for self.player = value" - # set_field_cache(self, "sessid", sessid) - ##@sessid.deleter - #def __sessid_del(self): - # "Deleter. Allows for del self.player" - # del_field_cache(self, "sessid") - #sessid = property(__sessid_get, __sessid_set, __sessid_del) + def __sessid_get(self): + """ + Getter. Allows for value = self.sessid. Since sessid + is directly related to self.player, we cannot have + a sessid without a player being connected (but the + opposite could be true). + """ + return _GA(self, "db_sessid") + #if not get_field_cache(self, "sessid"): + # del_field_cache(self, "sessid") + #return get_field_cache(self, "sessid") + #@sessid.setter + def __sessid_set(self, sessid): + "Setter. Allows for self.player = value" + _SA(self, "db_sessid", sessid) + _GA(self, "save")() + #set_field_cache(self, "sessid", sessid) + #@sessid.deleter + def __sessid_del(self): + "Deleter. Allows for del self.player" + _SA(self, "db_sessid", None) + _GA(self, "save")() + #del_field_cache(self, "sessid") + sessid = property(__sessid_get, __sessid_set, __sessid_del) def _at_db_location_save(self, new_value, old_value=None): "This is called automatically just before a new location is saved." @@ -311,79 +320,79 @@ class ObjectDB(TypedObject): # home property (wraps db_home) #@property - def __home_get(self): - "Getter. Allows for value = self.home" - home = get_field_cache(self, "home") - if home: - return _GA(home, "typeclass") - return None - #@home.setter - def __home_set(self, home): - "Setter. Allows for self.home = value" - try: - if home == None or type(home) == ObjectDB: - hom = home - elif ObjectDB.objects.dbref(home): - hom = ObjectDB.objects.dbref_search(home) - if hom and hasattr(hom,'dbobj'): - hom = _GA(hom, "dbobj") - else: - hom = _GA(home, "dbobj") - else: - hom = _GA(home, "dbobj") - set_field_cache(self, "home", hom) - except Exception: - string = "Cannot set home: " - string += "%s is not a valid home." - _GA(self, "msg")(_(string) % home) - logger.log_trace(string) - #raise - #@home.deleter - def __home_del(self): - "Deleter. Allows for del self.home." - _SA(self, "db_home", None) - _GA(self, "save")() - del_field_cache(self, "home") - home = property(__home_get, __home_set, __home_del) + #def __home_get(self): + # "Getter. Allows for value = self.home" + # home = get_field_cache(self, "home") + # if home: + # return _GA(home, "typeclass") + # return None + ##@home.setter + #def __home_set(self, home): + # "Setter. Allows for self.home = value" + # try: + # if home == None or type(home) == ObjectDB: + # hom = home + # elif ObjectDB.objects.dbref(home): + # hom = ObjectDB.objects.dbref_search(home) + # if hom and hasattr(hom,'dbobj'): + # hom = _GA(hom, "dbobj") + # else: + # hom = _GA(home, "dbobj") + # else: + # hom = _GA(home, "dbobj") + # set_field_cache(self, "home", hom) + # except Exception: + # string = "Cannot set home: " + # string += "%s is not a valid home." + # _GA(self, "msg")(_(string) % home) + # logger.log_trace(string) + # #raise + ##@home.deleter + #def __home_del(self): + # "Deleter. Allows for del self.home." + # _SA(self, "db_home", None) + # _GA(self, "save")() + # del_field_cache(self, "home") + #home = property(__home_get, __home_set, __home_del) # destination property (wraps db_destination) #@property - def __destination_get(self): - "Getter. Allows for value = self.destination." - dest = get_field_cache(self, "destination") - if dest: - return _GA(dest, "typeclass") - return None - #@destination.setter - def __destination_set(self, destination): - "Setter. Allows for self.destination = destination" - try: - if destination == None or type(destination) == ObjectDB: - # destination is None or a valid object - dest = destination - elif ObjectDB.objects.dbref(destination): - # destination is a dbref; search - dest = ObjectDB.objects.dbref_search(destination) - if dest and _GA(self, "_hasattr")(dest,'dbobj'): - dest = _GA(dest, "dbobj") - else: - dest = _GA(destination, "dbobj") - else: - dest = destination.dbobj - set_field_cache(self, "destination", dest) - except Exception: - string = "Cannot set destination: " - string += "%s is not a valid destination." % destination - _GA(self, "msg")(string) - logger.log_trace(string) - raise - #@destination.deleter - def __destination_del(self): - "Deleter. Allows for del self.destination" - _SA(self, "db_destination", None) - _GA(self, "save")() - del_field_cache(self, "destination") - destination = property(__destination_get, __destination_set, __destination_del) + #def __destination_get(self): + # "Getter. Allows for value = self.destination." + # dest = get_field_cache(self, "destination") + # if dest: + # return _GA(dest, "typeclass") + # return None + ##@destination.setter + #def __destination_set(self, destination): + # "Setter. Allows for self.destination = destination" + # try: + # if destination == None or type(destination) == ObjectDB: + # # destination is None or a valid object + # dest = destination + # elif ObjectDB.objects.dbref(destination): + # # destination is a dbref; search + # dest = ObjectDB.objects.dbref_search(destination) + # if dest and _GA(self, "_hasattr")(dest,'dbobj'): + # dest = _GA(dest, "dbobj") + # else: + # dest = _GA(destination, "dbobj") + # else: + # dest = destination.dbobj + # set_field_cache(self, "destination", dest) + # except Exception: + # string = "Cannot set destination: " + # string += "%s is not a valid destination." % destination + # _GA(self, "msg")(string) + # logger.log_trace(string) + # raise + ##@destination.deleter + #def __destination_del(self): + # "Deleter. Allows for del self.destination" + # _SA(self, "db_destination", None) + # _GA(self, "save")() + # del_field_cache(self, "destination") + #destination = property(__destination_get, __destination_set, __destination_del) # cmdset_storage property. # This seems very sensitive to caching, so leaving it be for now. /Griatch diff --git a/src/players/admin.py b/src/players/admin.py index 52db397665..3e5de18090 100644 --- a/src/players/admin.py +++ b/src/players/admin.py @@ -94,11 +94,11 @@ class PlayerForm(forms.ModelForm): initial=settings.BASE_PLAYER_TYPECLASS, widget=forms.TextInput(attrs={'size':'78'}), help_text="Required. Defines what 'type' of entity this is. This variable holds a Python path to a module with a valid Evennia Typeclass. Defaults to settings.BASE_PLAYER_TYPECLASS.") - db_permissions = forms.CharField(label="Permissions", - initial=settings.PERMISSION_PLAYER_DEFAULT, - required=False, - widget=forms.TextInput(attrs={'size':'78'}), - help_text="In-game permissions. A comma-separated list of text strings checked by certain locks. They are often used for hierarchies, such as letting a Player have permission 'Wizards', 'Builders' etc. A Player permission can be overloaded by the permissions of a controlled Character. Normal players use 'Players' by default.") + #db_permissions = forms.CharField(label="Permissions", + # initial=settings.PERMISSION_PLAYER_DEFAULT, + # required=False, + # widget=forms.TextInput(attrs={'size':'78'}), + # help_text="In-game permissions. A comma-separated list of text strings checked by certain locks. They are often used for hierarchies, such as letting a Player have permission 'Wizards', 'Builders' etc. A Player permission can be overloaded by the permissions of a controlled Character. Normal players use 'Players' by default.") db_lock_storage = forms.CharField(label="Locks", widget=forms.Textarea(attrs={'cols':'100', 'rows':'2'}), required=False, @@ -116,7 +116,8 @@ class PlayerInline(admin.StackedInline): form = PlayerForm fieldsets = ( ("In-game Permissions and Locks", - {'fields': ('db_permissions', 'db_lock_storage'), + {'fields': ('db_lock_storage',), + #{'fields': ('db_permissions', 'db_lock_storage'), 'description':"These are permissions/locks for in-game use. They are unrelated to website access rights."}), ("In-game Player data", {'fields':('db_typeclass_path', 'db_cmdset_storage'), @@ -140,8 +141,10 @@ class PlayerDBAdmin(BaseUserAdmin): 'description':'Relevant only to the website.'}), ('Website Permissions', {'fields': ('is_active', 'is_staff', 'is_superuser', 'user_permissions','groups'), 'description': "These are permissions/permission groups for accessing the admin site. They are unrelated to in-game access rights."}), - ('Game Options', {'fields': ('db_typeclass_path', 'db_cmdset_storage', 'db_permissions', 'db_lock_storage'), + ('Game Options', {'fields': ('db_typeclass_path', 'db_cmdset_storage', 'db_lock_storage'), 'description': 'These are attributes that are more relevant to gameplay.'})) + #('Game Options', {'fields': ('db_typeclass_path', 'db_cmdset_storage', 'db_permissions', 'db_lock_storage'), + # 'description': 'These are attributes that are more relevant to gameplay.'})) add_fieldsets = ( diff --git a/src/players/models.py b/src/players/models.py index 3647b33b55..0a56082d68 100644 --- a/src/players/models.py +++ b/src/players/models.py @@ -21,8 +21,6 @@ from django.db import models from django.contrib.auth.models import AbstractUser from django.utils.encoding import smart_str -from src.server.caches import get_field_cache, set_field_cache - from src.players import manager from src.scripts.models import ScriptDB from src.typeclasses.models import TypedObject, TagHandler, NickHandler, AliasHandler, AttributeHandler @@ -165,19 +163,19 @@ class PlayerDB(TypedObject, AbstractUser): _GA(self, "save")() cmdset_storage = property(cmdset_storage_get, cmdset_storage_set, cmdset_storage_del) - #@property - def is_connected_get(self): - "Getter. Allows for value = self.is_connected" - return get_field_cache(self, "is_connected") - #@is_connected.setter - def is_connected_set(self, value): - "Setter. Allows for self.is_connected = value" - set_field_cache(self, "is_connected", value) - #@is_connected.deleter - def is_connected_del(self): - "Deleter. Allows for del is_connected" - set_field_cache(self, "is_connected", False) - is_connected = property(is_connected_get, is_connected_set, is_connected_del) + ##@property + #def is_connected_get(self): + # "Getter. Allows for value = self.is_connected" + # return get_field_cache(self, "is_connected") + ##@is_connected.setter + #def is_connected_set(self, value): + # "Setter. Allows for self.is_connected = value" + # set_field_cache(self, "is_connected", value) + ##@is_connected.deleter + #def is_connected_del(self): + # "Deleter. Allows for del is_connected" + # set_field_cache(self, "is_connected", False) + #is_connected = property(is_connected_get, is_connected_set, is_connected_del) class Meta: "Define Django meta options" diff --git a/src/server/caches.py b/src/server/caches.py index 884697cf4b..b74db1068d 100644 --- a/src/server/caches.py +++ b/src/server/caches.py @@ -3,6 +3,7 @@ Central caching module. """ +from sys import getsizeof import os, threading from collections import defaultdict @@ -21,16 +22,9 @@ _IS_MAIN_THREAD = threading.currentThread().getName() == "MainThread" # Set up the cache stores # -_FIELD_CACHE = {} _ATTR_CACHE = {} _PROP_CACHE = defaultdict(dict) -# OOB trackers -_TRACKED_FIELDS = {} -_TRACKED_ATTRS = {} -_TRACKED_CACHE = {} - - #------------------------------------------------------------ # Cache key hash generation #------------------------------------------------------------ @@ -110,7 +104,7 @@ def field_pre_save(sender, instance=None, update_fields=None, raw=False, **kwarg if callable(handler): #hid = hashid(instance, "-%s" % fieldname) try: - old_value = _GA(instance, _GA(field, "get_cache_name")())#_FIELD_CACHE.get(hid) if hid else None + old_value = _GA(instance, _GA(field, "get_cache_name")()) except AttributeError: old_value=None # the handler may modify the stored value in various ways @@ -127,21 +121,6 @@ def field_pre_save(sender, instance=None, update_fields=None, raw=False, **kwarg def get_cache_sizes(): return (0, 0), (0, 0), (0, 0) -def get_field_cache(obj, name): - return _GA(obj, "db_%s" % name) -def set_field_cache(obj, name, val): - _SA(obj, "db_%s" % name, val) - _GA(obj, "save")() - #hid = hashid(obj) - #if _OOB_FIELD_UPDATE_HOOKS[hid].get(name): - # _OOB_HANDLER.update(hid, name, val) -def del_field_cache(obj, name): - _SA(obj, "db_%s" % name, None) - _GA(obj, "save")() - #hid = hashid(obj) - #if _OOB_FIELD_UPDATE_HOOKS[hid].get(name): - # _OOB_HANDLER.update(hid, name, None) - #------------------------------------------------------------ # Attr cache - caching the attribute objects related to a given object to @@ -151,11 +130,10 @@ def del_field_cache(obj, name): # connected to m2m_changed signal in respective model class def post_attr_update(sender, **kwargs): - "Called when the many2many relation changes some way" + "Called when the many2many relation changes (NOT when updating the value of an Attribute!)" obj = kwargs['instance'] model = kwargs['model'] action = kwargs['action'] - #print "update_attr_cache:", obj, model, action if kwargs['reverse']: # the reverse relation changed (the Attribute itself was acted on) pass @@ -183,7 +161,7 @@ def post_attr_update(sender, **kwargs): def get_attr_cache(obj, attrname): "Called by getting attribute" hid = hashid(obj, "-%s" % attrname) - return hid and _ATTR_CACHE.get(hid, None) or None + return _ATTR_CACHE.get(hid, None) def set_attr_cache(obj, attrname, attrobj): "Set the attr cache manually; this can be used to update" @@ -217,28 +195,20 @@ def clear_obj_attr_cache(obj): def get_prop_cache(obj, propname): "retrieve data from cache" hid = hashid(obj, "-%s" % propname) - if hid: - #print "get_prop_cache", hid, propname, _PROP_CACHE.get(hid, None) - return _PROP_CACHE[hid].get(propname, None) + return _PROP_CACHE[hid].get(propname, None) if hid else None def set_prop_cache(obj, propname, propvalue): "Set property cache" hid = hashid(obj, "-%s" % propname) - if obj and hasattr(obj, "oobhandler"): - obj.oobhandler.update(propname, _GA(obj, propname), propvalue, type="property", action="set") if hid: - #print "set_prop_cache", propname, propvalue _PROP_CACHE[hid][propname] = propvalue - #_PROP_CACHE.set(hid, propvalue) def del_prop_cache(obj, propname): "Delete element from property cache" hid = hashid(obj, "-%s" % propname) - if obj and hasattr(obj, "oobhandler"): - obj.oobhandler.update(propname, _GA(obj, propname), None, type="property", action="delete") - if hid and propname in _PROP_CACHE[hid]: - del _PROP_CACHE[hid][propname] - #_PROP_CACHE.delete(hid) + if hid: + if propname in _PROP_CACHE[hid]: + del _PROP_CACHE[hid][propname] def flush_prop_cache(): "Clear property cache" @@ -246,84 +216,17 @@ def flush_prop_cache(): _PROP_CACHE = defaultdict(dict) #_PROP_CACHE.clear() +def get_cache_sizes(): + """ + Get cache sizes, expressed in number of objects and memory size in MB + """ + global _ATTR_CACHE, _PROP_CACHE + attr_n = len(_ATTR_CACHE) + attr_mb = sum(getsizeof(obj) for obj in _ATTR_CACHE) / 1024.0 + field_n = 0 #sum(len(dic) for dic in _FIELD_CACHE.values()) + field_mb = 0 # sum(sum([getsizeof(obj) for obj in dic.values()]) for dic in _FIELD_CACHE.values()) / 1024.0 + prop_n = sum(len(dic) for dic in _PROP_CACHE.values()) + prop_mb = sum(sum([getsizeof(obj) for obj in dic.values()]) for dic in _PROP_CACHE.values()) / 1024.0 + return (attr_n, attr_mb), (field_n, field_mb), (prop_n, prop_mb) + -#_ENABLE_LOCAL_CACHES = settings.GAME_CACHE_TYPE -## oob helper functions -# OOB hooks (OOB not yet functional, don't use yet) -#_OOB_FIELD_UPDATE_HOOKS = defaultdict(dict) -#_OOB_PROP_UPDATE_HOOKS = defaultdict(dict) -#_OOB_ATTR_UPDATE_HOOKS = defaultdict(dict) -#_OOB_NDB_UPDATE_HOOKS = defaultdict(dict) -#_OOB_CUSTOM_UPDATE_HOOKS = defaultdict(dict) -# -#_OOB_HANDLER = None # set by oob handler when it initializes -#def register_oob_update_hook(obj,name, entity="field"): -# """ -# Register hook function to be called when field/property/db/ndb is updated. -# Given function will be called with function(obj, entityname, newvalue, *args, **kwargs) -# entity - one of "field", "property", "db", "ndb" or "custom" -# """ -# hid = hashid(obj) -# if hid: -# if entity == "field": -# global _OOB_FIELD_UPDATE_HOOKS -# _OOB_FIELD_UPDATE_HOOKS[hid][name] = True -# return -# elif entity == "property": -# global _OOB_PROP_UPDATE_HOOKS -# _OOB_PROP_UPDATE_HOOKS[hid][name] = True -# elif entity == "db": -# global _OOB_ATTR_UPDATE_HOOKS -# _OOB_ATTR_UPDATE_HOOKS[hid][name] = True -# elif entity == "ndb": -# global _OOB_NDB_UPDATE_HOOKS -# _OOB_NDB_UPDATE_HOOKS[hid][name] = True -# elif entity == "custom": -# global _OOB_CUSTOM_UPDATE_HOOKS -# _OOB_CUSTOM_UPDATE_HOOKS[hid][name] = True -# else: -# return None -# -#def unregister_oob_update_hook(obj, name, entity="property"): -# """ -# Un-register a report hook -# """ -# hid = hashid(obj) -# if hid: -# global _OOB_FIELD_UPDATE_HOOKS,_OOB_PROP_UPDATE_HOOKS, _OOB_ATTR_UPDATE_HOOKS -# global _OOB_CUSTOM_UPDATE_HOOKS, _OOB_NDB_UPDATE_HOOKS -# if entity == "field" and name in _OOB_FIELD_UPDATE_HOOKS: -# del _OOB_FIELD_UPDATE_HOOKS[hid][name] -# elif entity == "property" and name in _OOB_PROP_UPDATE_HOOKS: -# del _OOB_PROP_UPDATE_HOOKS[hid][name] -# elif entity == "db" and name in _OOB_ATTR_UPDATE_HOOKS: -# del _OOB_ATTR_UPDATE_HOOKS[hid][name] -# elif entity == "ndb" and name in _OOB_NDB_UPDATE_HOOKS: -# del _OOB_NDB_UPDATE_HOOKS[hid][name] -# elif entity == "custom" and name in _OOB_CUSTOM_UPDATE_HOOKS: -# del _OOB_CUSTOM_UPDATE_HOOKS[hid][name] -# else: -# return None -# -#def call_ndb_hooks(obj, attrname, value): -# """ -# No caching is done of ndb here, but -# we use this as a way to call OOB hooks. -# """ -# hid = hashid(obj) -# if hid: -# oob_hook = _OOB_NDB_UPDATE_HOOKS[hid].get(attrname) -# if oob_hook: -# oob_hook[0](obj.typeclass, attrname, value, *oob_hook[1], **oob_hook[2]) -# -#def call_custom_hooks(obj, attrname, value): -# """ -# Custom handler for developers adding their own oob hooks, e.g. to -# custom typeclass properties. -# """ -# hid = hashid(obj) -# if hid: -# oob_hook = _OOB_CUSTOM_UPDATE_HOOKS[hid].get(attrname) -# if oob_hook: -# oob_hook[0](obj.typeclass, attrname, value, *oob_hook[1], **oob_hook[2]) -# diff --git a/src/server/portal/portalsessionhandler.py b/src/server/portal/portalsessionhandler.py index 2424e14641..f0dbb40dac 100644 --- a/src/server/portal/portalsessionhandler.py +++ b/src/server/portal/portalsessionhandler.py @@ -121,7 +121,7 @@ class PortalSessionHandler(SessionHandler): return [sess for sess in self.get_sessions(include_unloggedin=True) if hasattr(sess, 'suid') and sess.suid == suid] - def data_in(self, session, string="", **kwargs): + def data_in(self, session, text="", **kwargs): """ Called by portal sessions for relaying data coming in from the protocol to the server. data is @@ -129,7 +129,7 @@ class PortalSessionHandler(SessionHandler): """ #print "portal_data_in:", string self.portal.amp_protocol.call_remote_MsgPortal2Server(session.sessid, - msg=string, + msg=text, data=kwargs) def announce_all(self, message): """ diff --git a/src/server/portal/webclient.py b/src/server/portal/webclient.py index 3737efb633..14d87d8c42 100644 --- a/src/server/portal/webclient.py +++ b/src/server/portal/webclient.py @@ -137,9 +137,9 @@ class WebClient(resource.Resource): sess = self.sessionhandler.session_from_suid(suid) if sess: sess = sess[0] - string = request.args.get('msg', [''])[0] + text = request.args.get('msg', [''])[0] data = request.args.get('data', [None])[0] - sess.sessionhandler.data_in(sess, string, data) + sess.sessionhandler.data_in(sess, text, data=data) return '' def mode_receive(self, request): diff --git a/src/server/server.py b/src/server/server.py index b7e8f6a281..21429e4b53 100644 --- a/src/server/server.py +++ b/src/server/server.py @@ -36,6 +36,12 @@ from django.db.models.signals import pre_save from src.server.caches import field_pre_save pre_save.connect(field_pre_save, dispatch_uid="fieldcache") +from django.db.models.signals import m2m_changed +from src.typeclasses.models import TypedObject +from src.server.caches import post_attr_update +# connect to attribute cache signal +m2m_changed.connect(post_attr_update, sender=TypedObject.db_attributes.through) + _SA = object.__setattr__ if os.name == 'nt': diff --git a/src/typeclasses/models.py b/src/typeclasses/models.py index 2106ac4049..eb6b9b0109 100644 --- a/src/typeclasses/models.py +++ b/src/typeclasses/models.py @@ -42,7 +42,6 @@ from django.db.models import Q from django.db.models.signals import m2m_changed from src.utils.idmapper.models import SharedMemoryModel -from src.server.caches import get_field_cache, set_field_cache, del_field_cache from src.server.caches import get_attr_cache, del_attr_cache, set_attr_cache from src.server.caches import get_prop_cache, set_prop_cache, flush_attr_cache from src.server.caches import post_attr_update @@ -363,7 +362,7 @@ class AttributeHandler(object): if attr_obj.count(): # re-use old attribute object attr_obj = attr_obj[0] - set_attr_cache(self.obj, key, attr_obj) # renew cache + #set_attr_cache(self.obj, key, attr_obj) # renew cache else: # no old attr available; create new (caches automatically) attr_obj = Attribute(db_key=key, db_category=category) @@ -1423,5 +1422,3 @@ class TypedObject(SharedMemoryModel): -# connect to attribute cache signal -m2m_changed.connect(post_attr_update, sender=TypedObject.db_attributes.through) diff --git a/src/utils/create.py b/src/utils/create.py index c734540633..5cd4c52c3f 100644 --- a/src/utils/create.py +++ b/src/utils/create.py @@ -53,7 +53,7 @@ _GA = object.__getattribute__ def create_object(typeclass, key=None, location=None, home=None, permissions=None, locks=None, - aliases=None, destination=None, report_to=None): + aliases=None, destination=None, report_to=None, testmode=False): """ Create a new in-game object. Any game object is a combination of a database object that stores data persistently to @@ -69,6 +69,7 @@ def create_object(typeclass, key=None, location=None, If report_to is not set, errors will be raised as en Exception containing the error message. If set, this method will return None upon errors. + testmode is only intended for Evennia unittest system """ global _Object, _ObjectDB if not _Object: @@ -134,6 +135,9 @@ def create_object(typeclass, key=None, location=None, # perform a move_to in order to display eventual messages. if home: new_object.home = home + elif testmode: + # this is required by unittest + pass else: new_object.home = settings.CHARACTER_DEFAULT_HOME