Run migrations! Made Channel model also accept ObjectDB subscriptions.

This commit is contained in:
Griatch 2015-03-12 20:28:17 +01:00
parent d63db77eb4
commit 94778f1c44
4 changed files with 193 additions and 27 deletions

View file

@ -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):

View file

@ -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):

View file

@ -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,
),
]

View file

@ -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)