From 94778f1c44b4980738dfb91a4132ae549f51c9fb Mon Sep 17 00:00:00 2001 From: Griatch Date: Thu, 12 Mar 2015 20:28:17 +0100 Subject: [PATCH] Run migrations! Made Channel model also accept ObjectDB subscriptions. --- evennia/comms/comms.py | 84 +++++++++----- evennia/comms/managers.py | 9 +- .../0006_channeldb_db_object_subscriptions.py | 21 ++++ evennia/comms/models.py | 106 ++++++++++++++++++ 4 files changed, 193 insertions(+), 27 deletions(-) create mode 100644 evennia/comms/migrations/0006_channeldb_db_object_subscriptions.py diff --git a/evennia/comms/comms.py b/evennia/comms/comms.py index 85f7d10810..622ba58feb 100644 --- a/evennia/comms/comms.py +++ b/evennia/comms/comms.py @@ -58,44 +58,78 @@ class DefaultChannel(ChannelDB): # helper methods, for easy overloading - def has_connection(self, player): + def has_connection(self, subscriber): """ Checks so this player is actually listening to this channel. - """ - if hasattr(player, "player"): - player = player.player - return player in self.db_subscriptions.all() - def connect(self, player): - "Connect the user to this channel. This checks access." - if hasattr(player, "player"): - player = player.player + Args: + subscriber (Player or Object): Entity to check. + + Returns: + has_sub (bool): Whether the subscriber is subscribing to + this channel or not. + + Notes: + This will first try Player subscribers and only try Object + if the Player fails. + + """ + has_sub = self.subscriptions.has(subscriber) + if not has_sub and hasattr(subscriber, "player"): + # it's common to send an Object when we + # by default only allow Players to subscribe. + has_sub = self.subscriptions.has(subscriber.player) + return has_sub + + + def connect(self, subscriber): + """ + Connect the user to this channel. This checks access. + + Args: + subscriber (Player or Object): the entity to subscribe + to this channel. + + Returns: + success (bool): Whether or not the addition was + successful. + + """ # check access - if not self.access(player, 'listen'): + if not self.access(subscriber, 'listen'): return False # pre-join hook - connect = self.pre_join_channel(player) + connect = self.pre_join_channel(subscriber) if not connect: return False # subscribe - self.db_subscriptions.add(player) + self.subscriptions.add(subscriber) # post-join hook - self.post_join_channel(player) + self.post_join_channel(subscriber) return True - def disconnect(self, player): - "Disconnect user from this channel." - if hasattr(player, "player"): - player = player.player + def disconnect(self, subscriber): + """ + Disconnect entity from this channel. + + Args: + subscriber (Player of Object): the + entity to disconnect. + + Returns: + success (bool): Whether or not the removal was + successful. + + """ # pre-disconnect hook - disconnect = self.pre_leave_channel(player) + disconnect = self.pre_leave_channel(subscriber) if not disconnect: return False # disconnect - self.db_subscriptions.remove(player) + self.subscriptions.remove(subscriber) # post-disconnect hook - self.post_leave_channel(player) + self.post_leave_channel(subscriber) return True def access(self, accessing_obj, access_type='listen', default=False): @@ -133,17 +167,17 @@ class DefaultChannel(ChannelDB): def distribute_message(self, msg, online=False): """ - Method for grabbing all listeners that a message should be sent to on - this channel, and sending them a message. + Method for grabbing all listeners that a message should be + sent to on this channel, and sending them a message. """ # get all players connected to this channel and send to them - for player in self.db_subscriptions.all(): + for entity in self.subscriptions.all(): try: # note our addition of the from_channel keyword here. This could be checked # by a custom player.msg() to treat channel-receives differently. - player.msg(msg.message, from_obj=msg.senders, from_channel=self.id) + entity.msg(msg.message, from_obj=msg.senders, from_channel=self.id) except AttributeError, e: - logger.log_trace("%s\nCannot send msg to player '%s'." % (e, player)) + logger.log_trace("%s\nCannot send msg to '%s'." % (e, entity)) def msg(self, msgobj, header=None, senders=None, sender_strings=None, persistent=False, online=False, emit=False, external=False): diff --git a/evennia/comms/managers.py b/evennia/comms/managers.py index 1b73c3d376..f633231fc5 100644 --- a/evennia/comms/managers.py +++ b/evennia/comms/managers.py @@ -283,11 +283,16 @@ class ChannelDBManager(TypedObjectManager): return None @returns_typeclass_list - def get_subscriptions(self, player): + def get_subscriptions(self, entity): """ Return all channels a given player is subscribed to """ - return player.subscription_set.all() + clsname = entity.__dbclass__.__name__ + if clsname == "PlayerDB": + return entity.subscription_set.all() + if clsname == "ObjectDB": + return entity.object_subscription_set.all() + return [] @returns_typeclass_list def channel_search(self, ostring, exact=True): diff --git a/evennia/comms/migrations/0006_channeldb_db_object_subscriptions.py b/evennia/comms/migrations/0006_channeldb_db_object_subscriptions.py new file mode 100644 index 0000000000..570d24b136 --- /dev/null +++ b/evennia/comms/migrations/0006_channeldb_db_object_subscriptions.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('objects', '0004_auto_20150118_1622'), + ('comms', '0005_auto_20150223_1517'), + ] + + operations = [ + migrations.AddField( + model_name='channeldb', + name='db_object_subscriptions', + field=models.ManyToManyField(related_name='object_subscription_set', null=True, verbose_name=b'subscriptions', to='objects.ObjectDB', db_index=True), + preserve_default=True, + ), + ] diff --git a/evennia/comms/models.py b/evennia/comms/models.py index 3dc6ea4b9a..a3a6869702 100644 --- a/evennia/comms/models.py +++ b/evennia/comms/models.py @@ -349,6 +349,105 @@ class TempMsg(object): # #------------------------------------------------------------ +class SubscriptionHandler(object): + """ + This handler manages subscriptions to the + channel and hides away which type of entity is + subscribing (Player or Object) + """ + def __init__(self, obj): + """ + Initialize the handler + + Attr: + obj (ChannelDB): The channel the handler sits on. + + """ + self.obj = obj + + def has(self, entity): + """ + Check if the given entity subscribe to this channel + + Args: + entity (str, Player or Object): The entity to return. If + a string, it assumed to be the key or the #dbref + of the entity. + + Returns: + subscriber (Player, Object or None): The given + subscriber. + + """ + clsname = entity.__dbclass__.__name__ + if clsname == "PlayerDB": + return entity in self.obj.db_subscriptions.all() + elif clsname == "ObjectDB": + return entity in self.obj.db_object_subscriptions.all() + + + def add(self, entity): + """ + Subscribe an entity to this channel. + + Args: + entity (Player, Object or list): The entity or + list of entities to subscribe to this channel. + + Note: + No access-checking is done here, this must have + been done before calling this method. Also + no hooks will be called. + + """ + for subscriber in make_iter(entity): + if subscriber: + clsname = subscriber.__dbclass__.__name__ + # chooses the right type + if clsname == "ObjectDB": + self.obj.db_object_subscriptions.add(subscriber) + elif clsname == "PlayerDB": + self.obj.db_subscriptions.add(subscriber) + + def remove(self, entity): + """ + Remove a subecriber from the channel. + + Args: + entity (Player, Object or list): The entity or + entities to un-subscribe from the channel. + + """ + for subscriber in make_iter(entity): + if subscriber: + clsname = subscriber.__dbclass__.__name__ + # chooses the right type + if clsname == "PlayerDB": + self.obj.db_subscriptions.remove(entity) + elif clsname == "ObjectDB": + self.obj.db_object_subscriptions.remove(entity) + + def all(self): + """ + Get all subscriptions to this channel. + + Returns: + subscribers (list): The subscribers. This + may be a mix of Players and Objects! + + """ + return list(self.obj.db_subscriptions.all()) + \ + list(self.obj.db_object_subscriptions.all()) + + def clear(self): + """ + Remove all subscribers from channel. + + """ + self.obj.db_subscriptions.clear() + self.obj.db_object_subscriptions.clear() + + class ChannelDB(TypedObject): """ This is the basis of a comm channel, only implementing @@ -364,6 +463,9 @@ class ChannelDB(TypedObject): db_subscriptions = models.ManyToManyField("players.PlayerDB", related_name="subscription_set", null=True, verbose_name='subscriptions', db_index=True) + db_object_subscriptions = models.ManyToManyField("objects.ObjectDB", + related_name="object_subscription_set", null=True, verbose_name='subscriptions', db_index=True) + # Database manager objects = managers.ChannelDBManager() @@ -377,3 +479,7 @@ class ChannelDB(TypedObject): def __str__(self): return "Channel '%s' (%s)" % (self.key, self.db.desc) + + @lazy_property + def subscriptions(self): + return SubscriptionHandler(self)