started reworking WAMPv2 messages

This commit is contained in:
Tobias Oberstein
2014-01-12 20:08:29 +01:00
parent 4470d77aa9
commit af602f9d2c
3 changed files with 360 additions and 147 deletions

View File

@@ -25,7 +25,8 @@ publish: clean
test:
# trial.py autobahn.wamp2.tests
trial.py autobahn.wamp2.tests.test_uri_pattern
trial.py autobahn.wamp2.tests.test_message
# trial.py autobahn.wamp2.tests.test_uri_pattern
testp:
python autobahn/wamp2/tests/test_uri_pattern.py

View File

@@ -58,7 +58,7 @@ def parse_wamp_callid(string):
class WampMessage:
class Message:
"""
WAMP message base class.
"""
@@ -73,10 +73,10 @@ class WampMessage:
def serialize(self, serializer):
if not self._serialized.has_key(serializer):
#print "WampMessage.serialize [new]", serializer
#print "Message.serialize [new]", serializer
self._serialized[serializer] = serializer.serialize(self.marshal())
else:
#print "WampMessage.serialize [cached]", serializer
#print "Message.serialize [cached]", serializer
pass
return self._serialized[serializer]
@@ -89,29 +89,36 @@ class WampMessage:
class WampMessageError(WampMessage):
class Error(Message):
"""
A WAMP Error message base class.
A WAMP Error message.
"""
def __init__(self, requestid, error, message = None, value = None):
MESSAGE_TYPE = 17
"""
The WAMP message code for this type of message.
"""
def __init__(self, request, error, args = None, kwargs = None):
"""
Message constructor.
:param requestid: The WAMP request ID (callid, subscribeid, ..) of the original request (call, subscribe, ..) this error is for.
:type requestid: str
:param request: The WAMP request ID of the original request (`Call`, `Subscribe`, ...) this error occured for.
:type request: int
:param error: The WAMP or application error URI for the error that occured.
:type error: str
:param message: Human readable error message.
:type message: str
:param value: Arbitrary error value to transport error detail data for programatic consumption (must be serializable using the serializer in use).
:type value: any
:param args: Exception positional values.
:type args: list
:param kwargs: Exception keyword values.
:type kwargs: dict
"""
WampMessage.__init__(self)
self.requestid = requestid
assert(not (kwargs and not args))
Message.__init__(self)
self.request = request
self.error = error
self.message = message
self.value = value
self.args = args
self.kwargs = kwargs
@classmethod
@@ -127,17 +134,14 @@ class WampMessageError(WampMessage):
##
assert(len(wmsg) > 0 and wmsg[0] == Klass.MESSAGE_TYPE)
if len(wmsg) not in (3, 4):
if len(wmsg) not in (4, 5, 6):
raise WampProtocolError("invalid message length %d for WAMP Error message" % len(wmsg))
## callid
## request
##
if type(wmsg[1]) not in (str, unicode):
raise WampProtocolError("invalid type %s for 'requestid' in WAMP Error message" % type(wmsg[1]))
requestid = parse_wamp_callid(wmsg[1])
if requestid is None:
raise WampProtocolError("invalid value '%s' for 'requestid' in WAMP Error message" % wmsg[1])
request = wmsg[1]
if request != int:
raise WampProtocolError("invalid type %s for 'request' in WAMP Error message" % type(request))
## error
##
@@ -150,34 +154,32 @@ class WampMessageError(WampMessage):
## details
##
message = None
value = None
details = wmsg[3]
if len(wmsg) == 4:
details = wmsg[3]
if type(details) != dict:
raise WampProtocolError("invalid type %s for 'details' in WAMP Error message" % type(details))
if type(details) != dict:
raise WampProtocolError("invalid type %s for 'details' in WAMP Error message" % type(details))
for k in details.keys():
if type(k) not in (str, unicode):
raise WampProtocolError("invalid type %s for key '%s' in 'details' in WAMP Error message" % (k, type(k)))
for k in details.keys():
if type(k) not in (str, unicode):
raise WampProtocolError("invalid type %s for key '%s' in 'details' in WAMP Error message" % (k, type(k)))
## exception
##
args = None
if len(wmsg) > 4:
args = wmsg[4]
if type(args) != list:
raise WampProtocolError("invalid type %s for 'args' in WAMP Error message" % type(args))
## error message (should be human readable)
##
if details.has_key('message'):
## exceptionkw
##
kwargs = None
if len(wmsg) > 5:
kwargs = wmsg[5]
if type(kwargs) != dict:
raise WampProtocolError("invalid type %s for 'kwargs' in WAMP Error message" % type(kwargs))
option_message = options['message']
if type(option_message) not in (str, unicode):
raise WampProtocolError("invalid type %s for 'message' option in WAMP Error message" % type(option_message))
message = option_message
## arbitrary application error value
##
value = details['value']
obj = Klass(requestid, error, message = message, value = value)
obj = Klass(request, error, args = args, kwargs = kwargs)
return obj
@@ -188,16 +190,12 @@ class WampMessageError(WampMessage):
"""
details = {}
if self.message is not None:
details['message'] = self.message
if self.value is not None:
details['value'] = self.value
if len(details):
return [self.MESSAGE_TYPE, self.requestid, self.error, details]
if self.kwargs:
return [self.MESSAGE_TYPE, self.request, self.error, details, self.args, self.kwargs]
elif self.args:
return [self.MESSAGE_TYPE, self.request, self.error, details, self.args]
else:
return [self.MESSAGE_TYPE, self.requestid, self.error]
return [self.MESSAGE_TYPE, self.request, self.error, details]
def __str__(self):
@@ -206,11 +204,11 @@ class WampMessageError(WampMessage):
:returns str -- Human readable representation (eg for logging or debugging purposes).
"""
return "WAMP Error Message (requestid = '%s', error = '%s', message = '%s', value = %s)" % (self.requestid, self.error, self.message, self.value)
return "WAMP Error Message (request = {}, error = {}, exception = {}, exceptionkw = {})".format(self.request, self.error, self.exception, self.exceptionkw)
class WampMessageHello(WampMessage):
class Hello(Message):
"""
A WAMP Hello message.
"""
@@ -228,7 +226,7 @@ class WampMessageHello(WampMessage):
:param sessionid: The WAMP session ID the other peer is assigned.
:type sessionid: str
"""
WampMessage.__init__(self)
Message.__init__(self)
self.sessionid = sessionid
@@ -243,7 +241,7 @@ class WampMessageHello(WampMessage):
"""
## this should already be verified by WampSerializer.unserialize
##
assert(len(wmsg) > 0 and wmsg[0] == WampMessageHello.MESSAGE_TYPE)
assert(len(wmsg) > 0 and wmsg[0] == Hello.MESSAGE_TYPE)
if len(wmsg) != 2:
raise WampProtocolError("invalid message length %d for WAMP Hello message" % len(wmsg))
@@ -266,7 +264,7 @@ class WampMessageHello(WampMessage):
"""
Marshal this object into a raw message for subsequent serialization to bytes.
"""
return [WampMessageHello.MESSAGE_TYPE, self.sessionid]
return [Hello.MESSAGE_TYPE, self.sessionid]
def __str__(self):
@@ -279,7 +277,7 @@ class WampMessageHello(WampMessage):
class WampMessageRoleChange(WampMessage):
class RoleChange(Message):
"""
A WAMP Role-Change message.
"""
@@ -310,7 +308,7 @@ class WampMessageRoleChange(WampMessage):
:param role: Role to be added or removed.
:type role: str
"""
WampMessage.__init__(self)
Message.__init__(self)
self.op = op
self.role = role
@@ -326,7 +324,7 @@ class WampMessageRoleChange(WampMessage):
"""
## this should already be verified by WampSerializer.unserialize
##
assert(len(wmsg) > 0 and wmsg[0] == WampMessageRoleChange.MESSAGE_TYPE)
assert(len(wmsg) > 0 and wmsg[0] == RoleChange.MESSAGE_TYPE)
if len(wmsg) != 3:
raise WampProtocolError("invalid message length %d for WAMP Role-Change message" % len(wmsg))
@@ -336,7 +334,7 @@ class WampMessageRoleChange(WampMessage):
op = wmsg[1]
if type(op) != int:
raise WampProtocolError("invalid type %s for 'op' in WAMP Role-Change message" % type(op))
if op not in [WampMessageRoleChange.ROLE_CHANGE_OP_ADD, WampMessageRoleChange.ROLE_CHANGE_OP_REMOVE]:
if op not in [RoleChange.ROLE_CHANGE_OP_ADD, RoleChange.ROLE_CHANGE_OP_REMOVE]:
raise WampProtocolError("invalid value '%s' for 'op' in WAMP Role-Change message" % op)
## role
@@ -344,7 +342,7 @@ class WampMessageRoleChange(WampMessage):
role = wmsg[2]
if type(role) not in (str, unicode):
raise WampProtocolError("invalid type %s for 'role' in WAMP Role-Change message" % type(role))
if role not in [WampMessageRoleChange.ROLE_CHANGE_ROLE_BROKER, WampMessageRoleChange.ROLE_CHANGE_ROLE_DEALER]:
if role not in [RoleChange.ROLE_CHANGE_ROLE_BROKER, RoleChange.ROLE_CHANGE_ROLE_DEALER]:
raise WampProtocolError("invalid value '%s' for 'role' in WAMP Role-Change message" % role)
obj = Klass(op, role)
@@ -356,7 +354,7 @@ class WampMessageRoleChange(WampMessage):
"""
Marshal this object into a raw message for subsequent serialization to bytes.
"""
return [WampMessageRoleChange.MESSAGE_TYPE, self.op, self.role]
return [RoleChange.MESSAGE_TYPE, self.op, self.role]
def __str__(self):
@@ -365,11 +363,11 @@ class WampMessageRoleChange(WampMessage):
:returns str -- Human readable representation (eg for logging or debugging purposes).
"""
return "WAMP Role-Change Message (op = '%s', role = '%s')" % (WampMessageRoleChange.ROLE_CHANGE_OP_DESC.get(self.op), self.role)
return "WAMP Role-Change Message (op = '%s', role = '%s')" % (RoleChange.ROLE_CHANGE_OP_DESC.get(self.op), self.role)
class WampMessageHeartbeat(WampMessage):
class Heartbeat(Message):
"""
A WAMP Hearbeat message.
"""
@@ -389,7 +387,7 @@ class WampMessageHeartbeat(WampMessage):
:param outgoing: Outgoing heartbeat.
:type outgoing: int
"""
WampMessage.__init__(self)
Message.__init__(self)
self.incoming = incoming
self.outgoing = outgoing
@@ -405,7 +403,7 @@ class WampMessageHeartbeat(WampMessage):
"""
## this should already be verified by WampSerializer.unserialize
##
assert(len(wmsg) > 0 and wmsg[0] == WampMessageHeartbeat.MESSAGE_TYPE)
assert(len(wmsg) > 0 and wmsg[0] == Heartbeat.MESSAGE_TYPE)
if len(wmsg) != 3:
raise WampProtocolError("invalid message length %d for WAMP Heartbeat message" % len(wmsg))
@@ -439,7 +437,7 @@ class WampMessageHeartbeat(WampMessage):
"""
Marshal this object into a raw message for subsequent serialization to bytes.
"""
return [WampMessageHeartbeat.MESSAGE_TYPE, self.incoming, self.outgoing]
return [Heartbeat.MESSAGE_TYPE, self.incoming, self.outgoing]
def __str__(self):
@@ -452,7 +450,7 @@ class WampMessageHeartbeat(WampMessage):
class WampMessageSubscribe(WampMessage):
class Subscribe(Message):
"""
A WAMP Subscribe message.
"""
@@ -478,7 +476,7 @@ class WampMessageSubscribe(WampMessage):
:param match: The topic matching method to be used for the subscription.
:type match: int
"""
WampMessage.__init__(self)
Message.__init__(self)
self.subscribeid = subscribeid
self.topic = topic
self.match = match
@@ -495,7 +493,7 @@ class WampMessageSubscribe(WampMessage):
"""
## this should already be verified by WampSerializer.unserialize
##
assert(len(wmsg) > 0 and wmsg[0] == WampMessageSubscribe.MESSAGE_TYPE)
assert(len(wmsg) > 0 and wmsg[0] == Subscribe.MESSAGE_TYPE)
if len(wmsg) not in (3, 4):
raise WampProtocolError("invalid message length %d for WAMP Subscribe message" % len(wmsg))
@@ -520,7 +518,7 @@ class WampMessageSubscribe(WampMessage):
## options
##
match = WampMessageSubscribe.MATCH_EXACT
match = Subscribe.MATCH_EXACT
if len(wmsg) == 4:
options = wmsg[3]
@@ -538,7 +536,7 @@ class WampMessageSubscribe(WampMessage):
if type(option_match) != int:
raise WampProtocolError("invalid type %s for 'match' option in WAMP Subscribe message" % type(option_match))
if option_match not in [WampMessageSubscribe.MATCH_EXACT, WampMessageSubscribe.MATCH_PREFIX, WampMessageSubscribe.MATCH_WILDCARD]:
if option_match not in [Subscribe.MATCH_EXACT, Subscribe.MATCH_PREFIX, Subscribe.MATCH_WILDCARD]:
raise WampProtocolError("invalid value %d for 'match' option in WAMP Subscribe message" % option_match)
match = option_match
@@ -554,13 +552,13 @@ class WampMessageSubscribe(WampMessage):
"""
options = {}
if self.match != WampMessageSubscribe.MATCH_EXACT:
if self.match != Subscribe.MATCH_EXACT:
options['match'] = self.match
if len(options):
return [WampMessageSubscribe.MESSAGE_TYPE, self.subscribeid, self.topic, options]
return [Subscribe.MESSAGE_TYPE, self.subscribeid, self.topic, options]
else:
return [WampMessageSubscribe.MESSAGE_TYPE, self.subscribeid, self.topic]
return [Subscribe.MESSAGE_TYPE, self.subscribeid, self.topic]
def __str__(self):
@@ -569,11 +567,11 @@ class WampMessageSubscribe(WampMessage):
:returns str -- Human readable representation (eg for logging or debugging purposes).
"""
return "WAMP Subscribe Message (subscribeid = '%s', topic = '%s', match = %s)" % (self.subscribeid, self.topic, WampMessageSubscribe.MATCH_DESC.get(self.match))
return "WAMP Subscribe Message (subscribeid = '%s', topic = '%s', match = %s)" % (self.subscribeid, self.topic, Subscribe.MATCH_DESC.get(self.match))
class WampMessageSubscription(WampMessage):
class Subscription(Message):
"""
A WAMP Subscription message.
"""
@@ -592,7 +590,7 @@ class WampMessageSubscription(WampMessage):
:param match: The topic matching method to be used for the subscription.
:type match: int
"""
WampMessage.__init__(self)
Message.__init__(self)
self.subscribeid = subscribeid
self.subscriptionid = subscriptionid
@@ -608,7 +606,7 @@ class WampMessageSubscription(WampMessage):
"""
## this should already be verified by WampSerializer.unserialize
##
assert(len(wmsg) > 0 and wmsg[0] == WampMessageSubscription.MESSAGE_TYPE)
assert(len(wmsg) > 0 and wmsg[0] == Subscription.MESSAGE_TYPE)
if len(wmsg) != 3:
raise WampProtocolError("invalid message length %d for WAMP Subscribe message" % len(wmsg))
@@ -640,7 +638,7 @@ class WampMessageSubscription(WampMessage):
"""
Marshal this object into a raw message for subsequent serialization to bytes.
"""
return [WampMessageSubscription.MESSAGE_TYPE, self.subscribeid, self.subscriptionid]
return [Subscription.MESSAGE_TYPE, self.subscribeid, self.subscriptionid]
def __str__(self):
@@ -653,7 +651,7 @@ class WampMessageSubscription(WampMessage):
class WampMessageSubscribeError(WampMessageError):
class SubscribeError(Error):
"""
A WAMP Subscribe-Error message.
"""
@@ -665,7 +663,7 @@ class WampMessageSubscribeError(WampMessageError):
class WampMessageUnsubscribe(WampMessage):
class Unsubscribe(Message):
"""
A WAMP Unsubscribe message.
"""
@@ -676,7 +674,7 @@ class WampMessageUnsubscribe(WampMessage):
"""
def __init__(self, topic, match = WampMessageSubscribe.MATCH_EXACT):
def __init__(self, topic, match = Subscribe.MATCH_EXACT):
"""
Message constructor.
@@ -685,7 +683,7 @@ class WampMessageUnsubscribe(WampMessage):
:param match: The topic matching method effective for the subscription to unsubscribe from.
:type match: int
"""
WampMessage.__init__(self)
Message.__init__(self)
self.topic = topic
self.match = match
@@ -701,7 +699,7 @@ class WampMessageUnsubscribe(WampMessage):
"""
## this should already be verified by WampSerializer.unserialize
##
assert(len(wmsg) > 0 and wmsg[0] == WampMessageUnsubscribe.MESSAGE_TYPE)
assert(len(wmsg) > 0 and wmsg[0] == Unsubscribe.MESSAGE_TYPE)
if len(wmsg) not in (2, 3):
raise WampProtocolError("invalid message length %d for WAMP Unsubscribe message" % len(wmsg))
@@ -717,7 +715,7 @@ class WampMessageUnsubscribe(WampMessage):
## options
##
match = WampMessageSubscribe.MATCH_EXACT
match = Subscribe.MATCH_EXACT
if len(wmsg) == 3:
options = wmsg[2]
@@ -735,7 +733,7 @@ class WampMessageUnsubscribe(WampMessage):
if type(option_match) != int:
raise WampProtocolError("invalid type %s for 'match' option in WAMP Unsubscribe message" % type(option_match))
if option_match not in [WampMessageSubscribe.MATCH_EXACT, WampMessageSubscribe.MATCH_PREFIX, WampMessageSubscribe.MATCH_WILDCARD]:
if option_match not in [Subscribe.MATCH_EXACT, Subscribe.MATCH_PREFIX, Subscribe.MATCH_WILDCARD]:
raise WampProtocolError("invalid value %d for 'match' option in WAMP Unsubscribe message" % option_match)
match = option_match
@@ -751,13 +749,13 @@ class WampMessageUnsubscribe(WampMessage):
"""
options = {}
if self.match != WampMessageSubscribe.MATCH_EXACT:
if self.match != Subscribe.MATCH_EXACT:
options['match'] = self.match
if len(options):
return [WampMessageUnsubscribe.MESSAGE_TYPE, self.topic, options]
return [Unsubscribe.MESSAGE_TYPE, self.topic, options]
else:
return [WampMessageUnsubscribe.MESSAGE_TYPE, self.topic]
return [Unsubscribe.MESSAGE_TYPE, self.topic]
def __str__(self):
@@ -766,11 +764,11 @@ class WampMessageUnsubscribe(WampMessage):
:returns str -- Human readable representation (eg for logging or debugging purposes).
"""
return "WAMP Unsubscribe Message (topic = '%s', match = %s)" % (self.topic, WampMessageSubscribe.MATCH_DESC.get(self.match))
return "WAMP Unsubscribe Message (topic = '%s', match = %s)" % (self.topic, Subscribe.MATCH_DESC.get(self.match))
class WampMessagePublish(WampMessage):
class Publish(Message):
"""
A WAMP Publish message.
"""
@@ -798,7 +796,7 @@ class WampMessagePublish(WampMessage):
:param discloseMe: If True, request to disclose the publisher of this event to subscribers.
:type discloseMe: bool
"""
WampMessage.__init__(self)
Message.__init__(self)
self.topic = topic
self.event = event
self.excludeMe = excludeMe
@@ -818,7 +816,7 @@ class WampMessagePublish(WampMessage):
"""
## this should already be verified by WampSerializer.unserialize
##
assert(len(wmsg) > 0 and wmsg[0] == WampMessagePublish.MESSAGE_TYPE)
assert(len(wmsg) > 0 and wmsg[0] == Publish.MESSAGE_TYPE)
if len(wmsg) not in (3, 4):
raise WampProtocolError("invalid message length %d for WAMP Publish message" % len(wmsg))
@@ -914,9 +912,9 @@ class WampMessagePublish(WampMessage):
options['discloseme'] = self.discloseMe
if len(options):
return [WampMessagePublish.MESSAGE_TYPE, self.topic, self.event, options]
return [Publish.MESSAGE_TYPE, self.topic, self.event, options]
else:
return [WampMessagePublish.MESSAGE_TYPE, self.topic, self.event]
return [Publish.MESSAGE_TYPE, self.topic, self.event]
def __str__(self):
@@ -929,7 +927,7 @@ class WampMessagePublish(WampMessage):
class WampMessageEvent(WampMessage):
class Event(Message):
"""
A WAMP Event message.
"""
@@ -951,7 +949,7 @@ class WampMessageEvent(WampMessage):
:param publisher: If present, the WAMP session ID of the publisher of this event.
:type publisher: str
"""
WampMessage.__init__(self)
Message.__init__(self)
self.subscriptionid = subscriptionid
self.topic = topic
self.event = event
@@ -969,7 +967,7 @@ class WampMessageEvent(WampMessage):
"""
## this should already be verified by WampSerializer.unserialize
##
assert(len(wmsg) > 0 and wmsg[0] == WampMessageEvent.MESSAGE_TYPE)
assert(len(wmsg) > 0 and wmsg[0] == Event.MESSAGE_TYPE)
if len(wmsg) not in (3, 4, 5):
raise WampProtocolError("invalid message length %d for WAMP Event message" % len(wmsg))
@@ -1035,12 +1033,12 @@ class WampMessageEvent(WampMessage):
details['publisher'] = self.publisher
if len(details):
return [WampMessageEvent.MESSAGE_TYPE, self.topic, self.event, details]
return [Event.MESSAGE_TYPE, self.topic, self.event, details]
else:
if self.event is not None:
return [WampMessageEvent.MESSAGE_TYPE, self.subscriptionid, self.topic, self.event]
return [Event.MESSAGE_TYPE, self.subscriptionid, self.topic, self.event]
else:
return [WampMessageEvent.MESSAGE_TYPE, self.subscriptionid, self.topic]
return [Event.MESSAGE_TYPE, self.subscriptionid, self.topic]
def __str__(self):
@@ -1053,7 +1051,7 @@ class WampMessageEvent(WampMessage):
class WampMessageMetaEvent(WampMessage):
class MetaEvent(Message):
"""
A WAMP Meta-Event message.
"""
@@ -1075,7 +1073,7 @@ class WampMessageMetaEvent(WampMessage):
:param metaevent: WAMP metaevent payload.
:type metaevent: any
"""
WampMessage.__init__(self)
Message.__init__(self)
self.topic = topic
self.metatopic = metatopic
self.metaevent = metaevent
@@ -1092,7 +1090,7 @@ class WampMessageMetaEvent(WampMessage):
"""
## this should already be verified by WampSerializer.unserialize
##
assert(len(wmsg) > 0 and wmsg[0] == WampMessageMetaEvent.MESSAGE_TYPE)
assert(len(wmsg) > 0 and wmsg[0] == MetaEvent.MESSAGE_TYPE)
if len(wmsg) not in (3, 4):
raise WampProtocolError("invalid message length %d for WAMP Meta-Event message" % len(wmsg))
@@ -1131,9 +1129,9 @@ class WampMessageMetaEvent(WampMessage):
Marshal this object into a raw message for subsequent serialization to bytes.
"""
if self.metaevent is not None:
return [WampMessageMetaEvent.MESSAGE_TYPE, self.topic, self.metatopic, self.metaevent]
return [MetaEvent.MESSAGE_TYPE, self.topic, self.metatopic, self.metaevent]
else:
return [WampMessageMetaEvent.MESSAGE_TYPE, self.topic, self.metatopic]
return [MetaEvent.MESSAGE_TYPE, self.topic, self.metatopic]
def __str__(self):
@@ -1146,7 +1144,7 @@ class WampMessageMetaEvent(WampMessage):
class WampMessageProvide(WampMessage):
class Provide(Message):
"""
A WAMP Provide message.
"""
@@ -1165,7 +1163,7 @@ class WampMessageProvide(WampMessage):
:param pkeys: The endpoint can work for this list of application partition keys.
:type pkeys: list
"""
WampMessage.__init__(self)
Message.__init__(self)
self.endpoint = endpoint
self.pkeys = pkeys
@@ -1181,7 +1179,7 @@ class WampMessageProvide(WampMessage):
"""
## this should already be verified by WampSerializer.unserialize
##
assert(len(wmsg) > 0 and wmsg[0] == WampMessageProvide.MESSAGE_TYPE)
assert(len(wmsg) > 0 and wmsg[0] == Provide.MESSAGE_TYPE)
if len(wmsg) not in (2, 3):
raise WampProtocolError("invalid message length %d for WAMP Provide message" % len(wmsg))
@@ -1236,9 +1234,9 @@ class WampMessageProvide(WampMessage):
options['pkeys'] = self.pkeys
if len(options):
return [WampMessageProvide.MESSAGE_TYPE, self.endpoint, options]
return [Provide.MESSAGE_TYPE, self.endpoint, options]
else:
return [WampMessageProvide.MESSAGE_TYPE, self.endpoint]
return [Provide.MESSAGE_TYPE, self.endpoint]
def __str__(self):
@@ -1251,7 +1249,7 @@ class WampMessageProvide(WampMessage):
class WampMessageUnprovide(WampMessage):
class Unprovide(Message):
"""
A WAMP Unprovide message.
"""
@@ -1271,7 +1269,7 @@ class WampMessageUnprovide(WampMessage):
:param pkeys: The endpoint is unprovided to work for this list of application partition keys.
:type pkeys: list
"""
WampMessage.__init__(self)
Message.__init__(self)
self.endpoint = endpoint
self.pkeys = pkeys
@@ -1287,7 +1285,7 @@ class WampMessageUnprovide(WampMessage):
"""
## this should already be verified by WampSerializer.unserialize
##
assert(len(wmsg) > 0 and wmsg[0] == WampMessageUnprovide.MESSAGE_TYPE)
assert(len(wmsg) > 0 and wmsg[0] == Unprovide.MESSAGE_TYPE)
if len(wmsg) not in (2, 3):
raise WampProtocolError("invalid message length %d for WAMP Unprovide message" % len(wmsg))
@@ -1342,9 +1340,9 @@ class WampMessageUnprovide(WampMessage):
options['pkeys'] = self.pkeys
if len(options):
return [WampMessageUnprovide.MESSAGE_TYPE, self.endpoint, options]
return [Unprovide.MESSAGE_TYPE, self.endpoint, options]
else:
return [WampMessageUnprovide.MESSAGE_TYPE, self.endpoint]
return [Unprovide.MESSAGE_TYPE, self.endpoint]
def __str__(self):
@@ -1357,7 +1355,7 @@ class WampMessageUnprovide(WampMessage):
class WampMessageCall(WampMessage):
class Call(Message):
"""
A WAMP Call message.
"""
@@ -1383,7 +1381,7 @@ class WampMessageCall(WampMessage):
:param timeout: If present, let the callee automatically cancel the call after this ms.
:type timeout: int
"""
WampMessage.__init__(self)
Message.__init__(self)
self.callid = callid
self.endpoint = endpoint
self.args = args
@@ -1402,7 +1400,7 @@ class WampMessageCall(WampMessage):
"""
## this should already be verified by WampSerializer.unserialize
##
assert(len(wmsg) > 0 and wmsg[0] == WampMessageCall.MESSAGE_TYPE)
assert(len(wmsg) > 0 and wmsg[0] == Call.MESSAGE_TYPE)
if len(wmsg) not in (3, 4, 5):
raise WampProtocolError("invalid message length %d for WAMP Call message" % len(wmsg))
@@ -1489,12 +1487,12 @@ class WampMessageCall(WampMessage):
options['session'] = self.sessionid
if len(options):
return [WampMessageCall.MESSAGE_TYPE, self.callid, self.endpoint, self.args, options]
return [Call.MESSAGE_TYPE, self.callid, self.endpoint, self.args, options]
else:
if len(self.args) > 0:
return [WampMessageCall.MESSAGE_TYPE, self.callid, self.endpoint, self.args]
return [Call.MESSAGE_TYPE, self.callid, self.endpoint, self.args]
else:
return [WampMessageCall.MESSAGE_TYPE, self.callid, self.endpoint]
return [Call.MESSAGE_TYPE, self.callid, self.endpoint]
def __str__(self):
@@ -1507,7 +1505,7 @@ class WampMessageCall(WampMessage):
class WampMessageCancelCall(WampMessage):
class CancelCall(Message):
"""
A WAMP Cancel-Call message.
"""
@@ -1537,7 +1535,7 @@ class WampMessageCancelCall(WampMessage):
:param mode: Specifies how to cancel the call (skip, abort or kill).
:type mode: int
"""
WampMessage.__init__(self)
Message.__init__(self)
self.callid = callid
self.mode = mode
@@ -1553,7 +1551,7 @@ class WampMessageCancelCall(WampMessage):
"""
## this should already be verified by WampSerializer.unserialize
##
assert(len(wmsg) > 0 and wmsg[0] == WampMessageCancelCall.MESSAGE_TYPE)
assert(len(wmsg) > 0 and wmsg[0] == CancelCall.MESSAGE_TYPE)
if len(wmsg) not in (2, 3):
raise WampProtocolError("invalid message length %d for WAMP Cancel-Call message" % len(wmsg))
@@ -1587,7 +1585,7 @@ class WampMessageCancelCall(WampMessage):
if type(option_mode) != int:
raise WampProtocolError("invalid type %s for 'mode' option in WAMP Cancel-Call message" % type(option_mode))
if option_moption_modeatch not in [WampMessageCancelCall.CANCEL_SKIP, WampMessageCancelCall.CANCEL_ABORT, WampMessageCancelCall.CANCEL_KILL]:
if option_moption_modeatch not in [CancelCall.CANCEL_SKIP, CancelCall.CANCEL_ABORT, CancelCall.CANCEL_KILL]:
raise WampProtocolError("invalid value %d for 'mode' option in WAMP Cancel-Call message" % option_mode)
mode = option_mode
@@ -1607,9 +1605,9 @@ class WampMessageCancelCall(WampMessage):
options['mode'] = self.mode
if len(options):
return [WampMessageCancelCall.MESSAGE_TYPE, self.callid, options]
return [CancelCall.MESSAGE_TYPE, self.callid, options]
else:
return [WampMessageCancelCall.MESSAGE_TYPE, self.callid]
return [CancelCall.MESSAGE_TYPE, self.callid]
def __str__(self):
@@ -1618,11 +1616,11 @@ class WampMessageCancelCall(WampMessage):
:returns str -- Human readable representation (eg for logging or debugging purposes).
"""
return "WAMP Cancel-Call Message (callid = '%s', mode = %s)" % (self.callid, WampMessageCancelCall.CANCEL_DESC.get(self.mode))
return "WAMP Cancel-Call Message (callid = '%s', mode = %s)" % (self.callid, CancelCall.CANCEL_DESC.get(self.mode))
class WampMessageCallProgress(WampMessage):
class CallProgress(Message):
"""
A WAMP Call-Progress message.
"""
@@ -1642,7 +1640,7 @@ class WampMessageCallProgress(WampMessage):
:param progress: Arbitrary application progress (must be serializable using the serializer in use).
:type progress: any
"""
WampMessage.__init__(self)
Message.__init__(self)
self.callid = callid
self.progress = progress
@@ -1658,7 +1656,7 @@ class WampMessageCallProgress(WampMessage):
"""
## this should already be verified by WampSerializer.unserialize
##
assert(len(wmsg) > 0 and wmsg[0] == WampMessageCallProgress.MESSAGE_TYPE)
assert(len(wmsg) > 0 and wmsg[0] == CallProgress.MESSAGE_TYPE)
if len(wmsg) not in (2, 3):
raise WampProtocolError("invalid message length %d for WAMP Call-Progress message" % len(wmsg))
@@ -1688,9 +1686,9 @@ class WampMessageCallProgress(WampMessage):
Marshal this object into a raw message for subsequent serialization to bytes.
"""
if self.progress is not None:
return [WampMessageCallProgress.MESSAGE_TYPE, self.callid, self.progress]
return [CallProgress.MESSAGE_TYPE, self.callid, self.progress]
else:
return [WampMessageCallProgress.MESSAGE_TYPE, self.callid]
return [CallProgress.MESSAGE_TYPE, self.callid]
def __str__(self):
@@ -1703,7 +1701,7 @@ class WampMessageCallProgress(WampMessage):
class WampMessageCallResult(WampMessage):
class CallResult(Message):
"""
A WAMP Call-Result message.
"""
@@ -1723,7 +1721,7 @@ class WampMessageCallResult(WampMessage):
:param result: Arbitrary application result (must be serializable using the serializer in use).
:type result: any
"""
WampMessage.__init__(self)
Message.__init__(self)
self.callid = callid
self.result = result
@@ -1739,7 +1737,7 @@ class WampMessageCallResult(WampMessage):
"""
## this should already be verified by WampSerializer.unserialize
##
assert(len(wmsg) > 0 and wmsg[0] == WampMessageCallResult.MESSAGE_TYPE)
assert(len(wmsg) > 0 and wmsg[0] == CallResult.MESSAGE_TYPE)
if len(wmsg) not in (2, 3):
raise WampProtocolError("invalid message length %d for WAMP Call-Result message" % len(wmsg))
@@ -1769,9 +1767,9 @@ class WampMessageCallResult(WampMessage):
Marshal this object into a raw message for subsequent serialization to bytes.
"""
if self.result is not None:
return [WampMessageCallResult.MESSAGE_TYPE, self.callid, self.result]
return [CallResult.MESSAGE_TYPE, self.callid, self.result]
else:
return [WampMessageCallResult.MESSAGE_TYPE, self.callid]
return [CallResult.MESSAGE_TYPE, self.callid]
def __str__(self):
@@ -1784,7 +1782,7 @@ class WampMessageCallResult(WampMessage):
class WampMessageCallError(WampMessageError):
class CallError(Error):
"""
A WAMP Call-Error message.
"""

View File

@@ -0,0 +1,214 @@
###############################################################################
##
## Copyright (C) 2014 Tavendo GmbH
##
## Licensed under the Apache License, Version 2.0 (the "License");
## you may not use this file except in compliance with the License.
## You may obtain a copy of the License at
##
## http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.
##
###############################################################################
from __future__ import absolute_import
from twisted.trial import unittest
#import unittest
from autobahn import wamp2 as wamp
from autobahn.wamp2.uri import Pattern
from autobahn.wamp2 import message
class KwException(Exception):
def __init__(self, *args, **kwargs):
Exception.__init__(self, *args)
self.kwargs = kwargs
class MockSession:
def __init__(self):
self._ecls_to_uri_pat = {}
self._uri_to_ecls = {}
def define(self, exception, error = None):
"""
Defines an exception for a WAMP error in the context of this WAMP session.
"""
if error is None:
assert(hasattr(exception, '_wampuris'))
self._ecls_to_uri_pat[exception] = exception._wampuris
self._uri_to_ecls[exception._wampuris[0].uri()] = exception
else:
assert(not hasattr(exception, '_wampuris'))
self._ecls_to_uri_pat[exception] = [Pattern(error, Pattern.URI_TARGET_HANDLER)]
self._uri_to_ecls[error] = exception
def message_from_exception(self, request, exc):
"""
Create a WAMP error message from an exception.
:param request: The request ID this WAMP error message is for.
:type request: int
:param exc: The exception.
:type exc: Instance of :class:`Exception` or subclass thereof.
"""
if isinstance(exc, KwException):
msg = message.Error(request, exc.args[0], args = exc.args[1:], kwargs = exc.kwargs)
else:
if self._ecls_to_uri_pat.has_key(exc.__class__):
error = self._ecls_to_uri_pat[exc.__class__][0]._uri
else:
error = "wamp.error.runtime_error"
if hasattr(exc, 'args'):
if hasattr(exc, 'kwargs'):
msg = message.Error(request, error, args = exc.args, kwargs = exc.kwargs)
else:
msg = message.Error(request, error, args = exc.args)
else:
msg = message.Error(request, error)
return msg
def exception_from_message(self, msg):
"""
Create a user (or generic) exception from a WAMP error message.
:param msg: A WAMP error message.
:type msg: Instance of :class:`autobahn.wamp.message.Error`
"""
# FIXME:
# 1. map to ecls based on error URI wildcard/prefix
# 2. extract additional args/kwargs from error URI
exc = None
if self._uri_to_ecls.has_key(msg.error):
ecls = self._uri_to_ecls[msg.error]
try:
## the following might fail, eg. TypeError when
## signature of exception constructor is incompatible
## with args/kwargs or when the exception constructor raises
if msg.kwargs:
if msg.args:
exc = ecls(*msg.args, **msg.kwargs)
else:
exc = ecls(**msg.kwargs)
else:
if msg.args:
exc = ecls(*msg.args)
else:
exc = ecls()
except Exception as e:
## FIXME: log e
pass
if not exc:
## the following ctor never fails ..
if msg.kwargs:
if msg.args:
exc = KwException(msg.error, *msg.args, **msg.kwargs)
else:
exc = KwException(msg.error, **msg.kwargs)
else:
if msg.args:
exc = KwException(msg.error, *msg.args)
else:
exc = KwException(msg.error)
return exc
class TestUris(unittest.TestCase):
def test_exception_message_ctor(self):
e = message.Error(123456, 'com.myapp.error1')
msg = e.marshal()
self.assertEqual(msg[0], message.Error.MESSAGE_TYPE)
self.assertEqual(msg[1], 123456)
self.assertEqual(msg[2], 'com.myapp.error1')
self.assertEqual(msg[3], {})
def test_exception_from_message(self):
session = MockSession()
@wamp.error("com.myapp.error1")
class AppError1(Exception):
pass
@wamp.error("com.myapp.error2")
class AppError2(Exception):
pass
session.define(AppError1)
session.define(AppError2)
## map defined errors to user exceptions
##
emsg = message.Error(123456, 'com.myapp.error1')
exc = session.exception_from_message(emsg)
self.assertIsInstance(exc, AppError1)
self.assertEqual(exc.args, ())
emsg = message.Error(123456, 'com.myapp.error2')
exc = session.exception_from_message(emsg)
self.assertIsInstance(exc, AppError2)
self.assertEqual(exc.args, ())
## map undefined error to (generic) exception
##
emsg = message.Error(123456, 'com.myapp.error3')
exc = session.exception_from_message(emsg)
self.assertIsInstance(exc, KwException)
self.assertEqual(exc.args, ('com.myapp.error3',))
self.assertEqual(exc.kwargs, {})
emsg = message.Error(123456, 'com.myapp.error3', args = [1, 2, 'hello'])
exc = session.exception_from_message(emsg)
self.assertIsInstance(exc, KwException)
self.assertEqual(exc.args, ('com.myapp.error3', 1, 2, 'hello'))
self.assertEqual(exc.kwargs, {})
emsg = message.Error(123456, 'com.myapp.error3', args = [1, 2, 'hello'], kwargs = {'foo': 23, 'bar': 'baz'})
exc = session.exception_from_message(emsg)
self.assertIsInstance(exc, KwException)
self.assertEqual(exc.args, ('com.myapp.error3', 1, 2, 'hello'))
self.assertEqual(exc.kwargs, {'foo': 23, 'bar': 'baz'})
def test_message_from_exception(self):
session = MockSession()
@wamp.error("com.myapp.error1")
class AppError1(Exception):
pass
@wamp.error("com.myapp.error2")
class AppError2(Exception):
pass
session.define(AppError1)
session.define(AppError2)
exc = AppError1()
msg = session.message_from_exception(123456, exc)
self.assertEqual(msg.marshal(), [message.Error.MESSAGE_TYPE, 123456, "com.myapp.error1", {}])
if __name__ == '__main__':
unittest.main()