add the types required for event retention

This commit is contained in:
Amber Brown (HawkOwl) 2016-11-12 23:13:54 +11:00
parent 0a5271c17d
commit 93f86b1e8d
No known key found for this signature in database
GPG Key ID: 2308B479D3924A11
4 changed files with 177 additions and 15 deletions

View File

@ -1116,7 +1116,8 @@ class Publish(Message):
eligible_authrole=None,
enc_algo=None,
enc_key=None,
enc_serializer=None):
enc_serializer=None,
retain=None):
"""
:param request: The WAMP request ID of this request.
@ -1156,6 +1157,8 @@ class Publish(Message):
:type enc_key: unicode or binary
:param enc_serializer: If using payload encryption, the encrypted payload object serializer.
:type enc_serializer: unicode
:param retain: If ``True``, request the broker retain this event.
:type retain: bool or None
"""
assert(type(request) in six.integer_types)
assert(type(topic) == six.text_type)
@ -1226,6 +1229,9 @@ class Publish(Message):
self.enc_key = enc_key
self.enc_serializer = enc_serializer
# event retention
self.retain = retain
@staticmethod
def parse(wmsg):
"""
@ -1292,6 +1298,8 @@ class Publish(Message):
eligible_authid = None
eligible_authrole = None
retain = None
if u'acknowledge' in options:
option_acknowledge = options[u'acknowledge']
@ -1380,6 +1388,11 @@ class Publish(Message):
eligible_authrole = option_eligible_authrole
if u'retain' in options:
retain = options[u'retain']
if type(retain) != bool:
raise ProtocolError("invalid type {0} for 'retain' option in PUBLISH".format(type(retain)))
obj = Publish(request,
topic,
args=args,
@ -1395,7 +1408,8 @@ class Publish(Message):
eligible_authrole=eligible_authrole,
enc_algo=enc_algo,
enc_key=enc_key,
enc_serializer=enc_serializer)
enc_serializer=enc_serializer,
retain=retain)
return obj
@ -1424,6 +1438,8 @@ class Publish(Message):
options[u'eligible_authid'] = self.eligible_authid
if self.eligible_authrole is not None:
options[u'eligible_authrole'] = self.eligible_authrole
if self.retain is not None:
options[u'retain'] = self.retain
if self.payload:
if self.enc_algo is not None:
@ -1445,7 +1461,7 @@ class Publish(Message):
"""
Returns string representation of this message.
"""
return u"Publish(request={0}, topic={1}, args={2}, kwargs={3}, acknowledge={4}, exclude_me={5}, exclude={6}, exclude_authid={7}, exclude_authrole={8}, eligible={9}, eligible_authid={10}, eligible_authrole={11}, enc_algo={12}, enc_key={13}, enc_serializer={14}, payload={15})".format(self.request, self.topic, self.args, self.kwargs, self.acknowledge, self.exclude_me, self.exclude, self.exclude_authid, self.exclude_authrole, self.eligible, self.eligible_authid, self.eligible_authrole, self.enc_algo, self.enc_key, self.enc_serializer, b2a(self.payload))
return u"Publish(request={0}, topic={1}, args={2}, kwargs={3}, acknowledge={4}, exclude_me={5}, exclude={6}, exclude_authid={7}, exclude_authrole={8}, eligible={9}, eligible_authid={10}, eligible_authrole={11}, enc_algo={12}, enc_key={13}, enc_serializer={14}, payload={15}, retain={16})".format(self.request, self.topic, self.args, self.kwargs, self.acknowledge, self.exclude_me, self.exclude, self.exclude_authid, self.exclude_authrole, self.eligible, self.eligible_authid, self.eligible_authrole, self.enc_algo, self.enc_key, self.enc_serializer, b2a(self.payload), self.retain)
class Published(Message):
@ -1530,7 +1546,7 @@ class Subscribe(Message):
MATCH_PREFIX = u'prefix'
MATCH_WILDCARD = u'wildcard'
def __init__(self, request, topic, match=None):
def __init__(self, request, topic, match=None, get_retained=None):
"""
:param request: The WAMP request ID of this request.
@ -1539,16 +1555,20 @@ class Subscribe(Message):
:type topic: unicode
:param match: The topic matching method to be used for the subscription.
:type match: unicode
:param get_retained: Whether the client wants the retained message we may have along with the subscription.
:type get_retained: bool or None
"""
assert(type(request) in six.integer_types)
assert(type(topic) == six.text_type)
assert(match is None or type(match) == six.text_type)
assert(match is None or match in [Subscribe.MATCH_EXACT, Subscribe.MATCH_PREFIX, Subscribe.MATCH_WILDCARD])
assert(get_retained is None or type(get_retained) is bool)
Message.__init__(self)
self.request = request
self.topic = topic
self.match = match or Subscribe.MATCH_EXACT
self.get_retained = get_retained
@staticmethod
def parse(wmsg):
@ -1572,6 +1592,7 @@ class Subscribe(Message):
topic = check_or_raise_uri(wmsg[3], u"'topic' in SUBSCRIBE", allow_empty_components=True)
match = Subscribe.MATCH_EXACT
get_retained = None
if u'match' in options:
@ -1584,7 +1605,13 @@ class Subscribe(Message):
match = option_match
obj = Subscribe(request, topic, match=match)
if u'get_retained' in options:
get_retained = options[u'get_retained']
if type(get_retained) != bool:
raise ProtocolError("invalid type {0} for 'get_retained' option in SUBSCRIBE".format(type(get_retained)))
obj = Subscribe(request, topic, match=match, get_retained=get_retained)
return obj
@ -1599,13 +1626,16 @@ class Subscribe(Message):
if self.match and self.match != Subscribe.MATCH_EXACT:
options[u'match'] = self.match
if self.get_retained is not None:
options[u'get_retained'] = self.get_retained
return [Subscribe.MESSAGE_TYPE, self.request, options, self.topic]
def __str__(self):
"""
Returns string representation of this message.
"""
return u"Subscribe(request={0}, topic={1}, match={2})".format(self.request, self.topic, self.match)
return u"Subscribe(request={0}, topic={1}, match={2}, get_retained={3})".format(self.request, self.topic, self.match, self.get_retained)
class Subscribed(Message):
@ -1858,7 +1888,7 @@ class Event(Message):
def __init__(self, subscription, publication, args=None, kwargs=None, payload=None,
publisher=None, publisher_authid=None, publisher_authrole=None, topic=None,
enc_algo=None, enc_key=None, enc_serializer=None):
enc_algo=None, enc_key=None, enc_serializer=None, retained=None):
"""
:param subscription: The subscription ID this event is dispatched under.
@ -1887,6 +1917,8 @@ class Event(Message):
:type enc_key: unicode or binary
:param enc_serializer: If using payload encryption, the encrypted payload object serializer.
:type enc_serializer: unicode
:param retained: Whether the message was retained by the broker on the topic, rather than just published.
:type retained: bool or None
"""
assert(type(subscription) in six.integer_types)
assert(type(publication) in six.integer_types)
@ -1904,6 +1936,7 @@ class Event(Message):
assert(enc_key is None or type(enc_key) in [six.text_type, six.binary_type])
assert(enc_serializer is None or enc_serializer in [u'json', u'msgpack', u'cbor', u'ubjson'])
assert((enc_algo is None and enc_key is None and enc_serializer is None) or (enc_algo is not None and payload is not None))
assert(retained is None or type(retained) == bool)
Message.__init__(self)
self.subscription = subscription
@ -1921,6 +1954,9 @@ class Event(Message):
self.enc_key = enc_key
self.enc_serializer = enc_serializer
# event retention
self.retained = retained
@staticmethod
def parse(wmsg):
"""
@ -1948,6 +1984,7 @@ class Event(Message):
enc_algo = None
enc_key = None
enc_serializer = None
retained = None
if len(wmsg) == 5 and type(wmsg[4]) in [six.text_type, six.binary_type]:
@ -2012,6 +2049,11 @@ class Event(Message):
topic = detail_topic
if u'retained' in details:
retained = details[u'retained']
if type(retained) != bool:
raise ProtocolError("invalid type {0} for 'retained' detail in EVENT".format(type(retained)))
obj = Event(subscription,
publication,
args=args,
@ -2023,7 +2065,8 @@ class Event(Message):
topic=topic,
enc_algo=enc_algo,
enc_key=enc_key,
enc_serializer=enc_serializer)
enc_serializer=enc_serializer,
retained=retained)
return obj
@ -2047,6 +2090,9 @@ class Event(Message):
if self.topic is not None:
details[u'topic'] = self.topic
if self.retained is not None:
details[u'retained'] = self.retained
if self.payload:
if self.enc_algo is not None:
details[u'enc_algo'] = self.enc_algo
@ -2067,7 +2113,7 @@ class Event(Message):
"""
Returns string representation of this message.
"""
return u"Event(subscription={0}, publication={1}, args={2}, kwargs={3}, publisher={4}, publisher_authid={5}, publisher_authrole={6}, topic={7}, enc_algo={8}, enc_key={9}, enc_serializer={9}, payload={10})".format(self.subscription, self.publication, self.args, self.kwargs, self.publisher, self.publisher_authid, self.publisher_authrole, self.topic, self.enc_algo, self.enc_key, self.enc_serializer, b2a(self.payload))
return u"Event(subscription={0}, publication={1}, args={2}, kwargs={3}, publisher={4}, publisher_authid={5}, publisher_authrole={6}, topic={7}, enc_algo={8}, enc_key={9}, enc_serializer={9}, payload={10}, retained={11})".format(self.subscription, self.publication, self.args, self.kwargs, self.publisher, self.publisher_authid, self.publisher_authrole, self.topic, self.enc_algo, self.enc_key, self.enc_serializer, b2a(self.payload), retained)
class Call(Message):

View File

@ -262,6 +262,38 @@ class TestSubscribeMessage(unittest.TestCase):
self.assertEqual(msg.match, message.Subscribe.MATCH_PREFIX)
self.assertEqual(msg.marshal(), wmsg)
def test_get_retained_default_false(self):
wmsg = [message.Subscribe.MESSAGE_TYPE, 123456, {u'match': u'prefix'}, u'com.myapp.topic1']
msg = message.Subscribe.parse(wmsg)
self.assertIsInstance(msg, message.Subscribe)
self.assertEqual(msg.request, 123456)
self.assertEqual(msg.topic, u'com.myapp.topic1')
self.assertEqual(msg.get_retained, None)
self.assertNotEqual(msg.get_retained, True)
self.assertEqual(msg.match, message.Subscribe.MATCH_PREFIX)
self.assertEqual(msg.marshal(), wmsg)
def test_get_retained_explicit_false(self):
wmsg = [message.Subscribe.MESSAGE_TYPE, 123456, {u'match': u'prefix', u'get_retained': False}, u'com.myapp.topic1']
msg = message.Subscribe.parse(wmsg)
self.assertIsInstance(msg, message.Subscribe)
self.assertEqual(msg.request, 123456)
self.assertEqual(msg.topic, u'com.myapp.topic1')
self.assertEqual(msg.get_retained, False)
self.assertNotEqual(msg.get_retained, True)
self.assertEqual(msg.match, message.Subscribe.MATCH_PREFIX)
self.assertEqual(msg.marshal(), wmsg)
def test_get_retained_explicit_true(self):
wmsg = [message.Subscribe.MESSAGE_TYPE, 123456, {u'match': u'prefix', u'get_retained': True}, u'com.myapp.topic1']
msg = message.Subscribe.parse(wmsg)
self.assertIsInstance(msg, message.Subscribe)
self.assertEqual(msg.request, 123456)
self.assertEqual(msg.topic, u'com.myapp.topic1')
self.assertEqual(msg.get_retained, True)
self.assertEqual(msg.match, message.Subscribe.MATCH_PREFIX)
self.assertEqual(msg.marshal(), wmsg)
class TestSubscribedMessage(unittest.TestCase):
@ -416,6 +448,39 @@ class TestPublishMessage(unittest.TestCase):
self.assertEqual(msg.eligible, [100, 200, 300])
self.assertEqual(msg.marshal(), wmsg)
def test_retain_default_false(self):
"""
Retain, when not specified, is False-y by default.
"""
wmsg = [message.Publish.MESSAGE_TYPE, 123456, {u'exclude_me': False, u'exclude': [300], u'eligible': [100, 200, 300]}, u'com.myapp.topic1']
msg = message.Publish.parse(wmsg)
self.assertIsInstance(msg, message.Publish)
self.assertEqual(msg.retain, None)
self.assertIsNot(msg.retain, True)
self.assertEqual(msg.marshal(), wmsg)
def test_retain_explicit_false(self):
"""
Retain, when specified as False, shows up in the message.
"""
wmsg = [message.Publish.MESSAGE_TYPE, 123456, {u'exclude_me': False, u'retain': False, u'exclude': [300], u'eligible': [100, 200, 300]}, u'com.myapp.topic1']
msg = message.Publish.parse(wmsg)
self.assertIsInstance(msg, message.Publish)
self.assertEqual(msg.retain, False)
self.assertIsNot(msg.retain, True)
self.assertEqual(msg.marshal(), wmsg)
def test_retain_explicit_true(self):
"""
Retain, when specified as True, shows up in the message.
"""
wmsg = [message.Publish.MESSAGE_TYPE, 123456, {u'exclude_me': False, u'retain': True, u'exclude': [300], u'eligible': [100, 200, 300]}, u'com.myapp.topic1']
msg = message.Publish.parse(wmsg)
self.assertIsInstance(msg, message.Publish)
self.assertEqual(msg.retain, True)
self.assertIs(msg.retain, True)
self.assertEqual(msg.marshal(), wmsg)
class TestPublishedMessage(unittest.TestCase):
@ -496,6 +561,29 @@ class TestEventMessage(unittest.TestCase):
self.assertEqual(msg.publisher, 300)
self.assertEqual(msg.marshal(), wmsg)
def test_retained_default_false(self):
wmsg = [message.Event.MESSAGE_TYPE, 123456, 789123, {}]
msg = message.Event.parse(wmsg)
self.assertIsInstance(msg, message.Event)
self.assertEqual(msg.retained, None)
self.assertNotEqual(msg.retained, True)
self.assertEqual(msg.marshal(), wmsg)
def test_retained_explicit_false(self):
wmsg = [message.Event.MESSAGE_TYPE, 123456, 789123, {u'retained': False}]
msg = message.Event.parse(wmsg)
self.assertIsInstance(msg, message.Event)
self.assertEqual(msg.retained, False)
self.assertNotEqual(msg.retained, True)
self.assertEqual(msg.marshal(), wmsg)
def test_retained_explicit_false(self):
wmsg = [message.Event.MESSAGE_TYPE, 123456, 789123, {u'retained': True}]
msg = message.Event.parse(wmsg)
self.assertIsInstance(msg, message.Event)
self.assertEqual(msg.retained, True)
self.assertEqual(msg.marshal(), wmsg)
class TestRegisterMessage(unittest.TestCase):

View File

@ -187,6 +187,9 @@ if os.environ.get('USE_TWISTED', False):
publication = yield handler.publish(u'com.myapp.topic1', 1, 2, 3, foo=23, bar='hello', options=types.PublishOptions(exclude_me=False, exclude=[100, 200, 300]))
self.assertEqual(publication, None)
publication = yield handler.publish(u'com.myapp.topic1', 1, 2, 3, foo=23, bar='hello', options=types.PublishOptions(exclude_me=False, exclude=[100, 200, 300], retain=True))
self.assertEqual(publication, None)
@inlineCallbacks
def test_publish_acknowledged(self):
handler = ApplicationSession()
@ -279,6 +282,9 @@ if os.environ.get('USE_TWISTED', False):
subscription = yield handler.subscribe(on_event, u'com.myapp.topic1', options=types.SubscribeOptions(match=u'wildcard'))
self.assertTrue(type(subscription.id) in (int, long))
subscription = yield handler.subscribe(on_event, u'com.myapp.topic1', options=types.SubscribeOptions(match=u'wildcard', get_retained=True))
self.assertTrue(type(subscription.id) in (int, long))
@inlineCallbacks
def test_double_subscribe(self):
handler = ApplicationSession()

View File

@ -344,9 +344,10 @@ class SubscribeOptions(object):
__slots__ = (
'match',
'details_arg',
'get_retained',
)
def __init__(self, match=None, details_arg=None):
def __init__(self, match=None, details_arg=None, get_retained=None):
"""
:param match: The topic matching method to be used for the subscription.
@ -354,12 +355,16 @@ class SubscribeOptions(object):
:param details_arg: When invoking the handler, provide event details
in this keyword argument to the callable.
:type details_arg: str
:param get_retained: Whether the client wants the retained message we may have along with the subscription.
:type get_retained: bool or None
"""
assert(match is None or (type(match) == six.text_type and match in [u'exact', u'prefix', u'wildcard']))
assert(details_arg is None or type(details_arg) == str)
assert(get_retained is None or type(get_retained) is bool)
self.match = match
self.details_arg = details_arg
self.get_retained = get_retained
def message_attr(self):
"""
@ -370,10 +375,13 @@ class SubscribeOptions(object):
if self.match is not None:
options[u'match'] = self.match
if self.get_retained is not None:
options[u'get_retained'] = self.get_retained
return options
def __str__(self):
return "SubscribeOptions(match={0}, details_arg={1})".format(self.match, self.details_arg)
return "SubscribeOptions(match={0}, details_arg={1}, get_retained={2})".format(self.match, self.details_arg, self.get_retained)
class EventDetails(object):
@ -389,9 +397,10 @@ class EventDetails(object):
'publisher_authrole',
'topic',
'enc_algo',
'retained',
)
def __init__(self, publication, publisher=None, publisher_authid=None, publisher_authrole=None, topic=None, enc_algo=None):
def __init__(self, publication, publisher=None, publisher_authid=None, publisher_authrole=None, topic=None, enc_algo=None, retained=None):
"""
:param publication: The publication ID of the event (always present).
@ -411,6 +420,8 @@ class EventDetails(object):
:param enc_algo: Payload encryption algorithm that
was in use (currently, either `None` or `"cryptobox"`).
:type enc_algo: None or unicode
:param retained: Whether the message was retained by the broker on the topic, rather than just published.
:type retained: bool or None
"""
assert(type(publication) in six.integer_types)
assert(publisher is None or type(publisher) in six.integer_types)
@ -418,6 +429,7 @@ class EventDetails(object):
assert(publisher_authrole is None or type(publisher_authrole) == six.text_type)
assert(topic is None or type(topic) == six.text_type)
assert(enc_algo is None or (type(enc_algo) == six.text_type and enc_algo in [u'cryptobox']))
assert(retained is None or type(retained) is bool)
self.publication = publication
self.publisher = publisher
@ -425,9 +437,10 @@ class EventDetails(object):
self.publisher_authrole = publisher_authrole
self.topic = topic
self.enc_algo = enc_algo
self.retained = retained
def __str__(self):
return "EventDetails(publication={0}, publisher={1}, publisher_authid={2}, publisher_authrole={3}, topic=<{4}>, enc_algo={5})".format(self.publication, self.publisher, self.publisher_authid, self.publisher_authrole, self.topic, self.enc_algo)
return "EventDetails(publication={0}, publisher={1}, publisher_authid={2}, publisher_authrole={3}, topic=<{4}>, enc_algo={5}, retained={6})".format(self.publication, self.publisher, self.publisher_authid, self.publisher_authrole, self.topic, self.enc_algo, self.retained)
class PublishOptions(object):
@ -445,6 +458,7 @@ class PublishOptions(object):
'eligible',
'eligible_authid',
'eligible_authrole',
'retain',
)
def __init__(self,
@ -455,7 +469,8 @@ class PublishOptions(object):
exclude_authrole=None,
eligible=None,
eligible_authid=None,
eligible_authrole=None):
eligible_authrole=None,
retain=None):
"""
:param acknowledge: If ``True``, acknowledge the publication with a success or
@ -476,6 +491,8 @@ class PublishOptions(object):
:type eligible_authid: unicode or list of unicode or None
:param eligible_authrole: A single WAMP authrole or a list thereof eligible to receive this event.
:type eligible_authrole: unicode or list of unicode or None
:param retain: If ``True``, request the broker retain this event.
:type retain: bool or None
"""
assert(acknowledge is None or type(acknowledge) == bool)
assert(exclude_me is None or type(exclude_me) == bool)
@ -485,6 +502,7 @@ class PublishOptions(object):
assert(eligible is None or type(eligible) in six.integer_types or (type(eligible) == list and all(type(x) in six.integer_types for x in eligible)))
assert(eligible_authid is None or type(eligible_authid) == six.text_type or (type(eligible_authid) == list and all(type(x) == six.text_type for x in eligible_authid)))
assert(eligible_authrole is None or type(eligible_authrole) == six.text_type or (type(eligible_authrole) == list and all(type(x) == six.text_type for x in eligible_authrole)))
assert(retain is None or type(retain) == bool)
self.acknowledge = acknowledge
self.exclude_me = exclude_me
@ -494,6 +512,7 @@ class PublishOptions(object):
self.eligible = eligible
self.eligible_authid = eligible_authid
self.eligible_authrole = eligible_authrole
self.retain = retain
def message_attr(self):
"""
@ -525,10 +544,13 @@ class PublishOptions(object):
if self.eligible_authrole is not None:
options[u'eligible_authrole'] = self.eligible_authrole if type(self.eligible_authrole) == list else [self.eligible_authrole]
if self.retain is not None:
options[u'retain'] = self.retain
return options
def __str__(self):
return "PublishOptions(acknowledge={0}, exclude_me={1}, exclude={2}, exclude_authid={3}, exclude_authrole={4}, eligible={5}, eligible_authid={6}, eligible_authrole={7})".format(self.acknowledge, self.exclude_me, self.exclude, self.exclude_authid, self.exclude_authrole, self.eligible, self.eligible_authid, self.eligible_authrole)
return "PublishOptions(acknowledge={0}, exclude_me={1}, exclude={2}, exclude_authid={3}, exclude_authrole={4}, eligible={5}, eligible_authid={6}, eligible_authrole={7}, retain={8})".format(self.acknowledge, self.exclude_me, self.exclude, self.exclude_authid, self.exclude_authrole, self.eligible, self.eligible_authid, self.eligible_authrole, self.retain)
class RegisterOptions(object):