1
2
3
4 """
5 Flex Messaging implementation.
6
7 This module contains the message classes used with Flex Data Services.
8
9 @see: U{RemoteObject on OSFlash (external)
10 <http://osflash.org/documentation/amf3#remoteobject>}
11
12 @since: 0.1
13 """
14
15 import uuid
16
17 import pyamf.util
18 from pyamf import amf3
19
20
21 __all__ = [
22 'RemotingMessage',
23 'CommandMessage',
24 'AcknowledgeMessage',
25 'ErrorMessage'
26 ]
27
28 NAMESPACE = 'flex.messaging.messages'
29
30 SMALL_FLAG_MORE = 0x80
31
32
34 """
35 Abstract base class for all Flex messages.
36
37 Messages have two customizable sections; headers and data. The headers
38 property provides access to specialized meta information for a specific
39 message instance. The data property contains the instance specific data
40 that needs to be delivered and processed by the decoder.
41
42 @see: U{AbstractMessage on Livedocs (external)
43 <http://livedocs.adobe.com/flex/201/langref/mx/messaging/messages/AbstractMessage.html>}
44
45 @ivar body: Specific data that needs to be delivered to the remote
46 destination.
47 @type body: C{mixed}
48 @ivar clientId: Indicates which client sent the message.
49 @type clientId: C{str}
50 @ivar destination: Message destination.
51 @type destination: C{str}
52 @ivar headers: Message headers. Core header names start with DS.
53 @type headers: C{dict}
54 @ivar messageId: Unique Message ID.
55 @type messageId: C{str}
56 @ivar timeToLive: How long the message should be considered valid and
57 deliverable.
58 @type timeToLive: C{int}
59 @ivar timestamp: Timestamp when the message was generated.
60 @type timestamp: C{int}
61 """
62
64 amf3 = True
65 static = ('body', 'clientId', 'destination', 'headers', 'messageId',
66 'timestamp', 'timeToLive')
67 dynamic = False
68
69
70
71 DESTINATION_CLIENT_ID_HEADER = "DSDstClientId"
72
73
74 ENDPOINT_HEADER = "DSEndpoint"
75
76
77 REMOTE_CREDENTIALS_HEADER = "DSRemoteCredentials"
78
79
80
81
82 REQUEST_TIMEOUT_HEADER = "DSRequestTimeout"
83
84 SMALL_ATTRIBUTE_FLAGS = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40]
85 SMALL_ATTRIBUTES = dict(zip(
86 SMALL_ATTRIBUTE_FLAGS,
87 __amf__.static
88 ))
89
90 SMALL_UUID_FLAGS = [0x01, 0x02]
91 SMALL_UUIDS = dict(zip(
92 SMALL_UUID_FLAGS,
93 ['clientId', 'messageId']
94 ))
95
97 self.body = kwargs.get('body', None)
98 self.clientId = kwargs.get('clientId', None)
99 self.destination = kwargs.get('destination', None)
100 self.headers = kwargs.get('headers', {})
101 self.messageId = kwargs.get('messageId', None)
102 self.timestamp = kwargs.get('timestamp', None)
103 self.timeToLive = kwargs.get('timeToLive', None)
104
106 m = '<%s ' % self.__class__.__name__
107
108 for k in self.__dict__:
109 m += ' %s=%r' % (k, getattr(self, k))
110
111 return m + " />"
112
114 """
115 @since: 0.5
116 """
117 obj = input.readObject()
118
119 if attr in ['timestamp', 'timeToLive']:
120 return pyamf.util.get_datetime(obj / 1000.0)
121
122 return obj
123
125 """
126 @since: 0.5
127 """
128 obj = getattr(self, attr)
129
130 if not obj:
131 return obj
132
133 if attr in ['timestamp', 'timeToLive']:
134 return pyamf.util.get_timestamp(obj) * 1000.0
135 elif attr in ['clientId', 'messageId']:
136 if isinstance(obj, uuid.UUID):
137 return None
138
139 return obj
140
160
194
196 """
197 Return a ISmallMessage representation of this object. If one is not
198 available, L{NotImplementedError} will be raised.
199
200 @since: 0.5
201 """
202 raise NotImplementedError
203
204
206 """
207 I am the base class for all asynchronous Flex messages.
208
209 @see: U{AsyncMessage on Livedocs (external)
210 <http://livedocs.adobe.com/flex/201/langref/mx/messaging/messages/AsyncMessage.html>}
211
212 @ivar correlationId: Correlation id of the message.
213 @type correlationId: C{str}
214 """
215
216
217
218 SUBTOPIC_HEADER = "DSSubtopic"
219
221 static = ('correlationId',)
222
227
229 AbstractMessage.__readamf__(self, input)
230
231 flags = read_flags(input)
232
233 if len(flags) > 1:
234 raise pyamf.DecodeError('Expected <=1 (got %d) flags for the '
235 'AsyncMessage portion of the small message for %r' % (
236 len(flags), self.__class__))
237
238 byte = flags[0]
239
240 if byte & 0x01:
241 self.correlationId = input.readObject()
242
243 if byte & 0x02:
244 self.correlationId = decode_uuid(input.readObject())
245
255
257 """
258 Return a ISmallMessage representation of this async message.
259
260 @since: 0.5
261 """
262 return AsyncMessageExt(**self.__dict__)
263
264
266 """
267 I acknowledge the receipt of a message that was sent previously.
268
269 Every message sent within the messaging system must receive an
270 acknowledgement.
271
272 @see: U{AcknowledgeMessage on Livedocs (external)
273 <http://livedocs.adobe.com/flex/201/langref/mx/messaging/messages/AcknowledgeMessage.html>}
274 """
275
276
277
278 ERROR_HINT_HEADER = "DSErrorHint"
279
281 AsyncMessage.__readamf__(self, input)
282
283 flags = read_flags(input)
284
285 if len(flags) > 1:
286 raise pyamf.DecodeError('Expected <=1 (got %d) flags for the '
287 'AcknowledgeMessage portion of the small message for %r' % (
288 len(flags), self.__class__))
289
294
296 """
297 Return a ISmallMessage representation of this acknowledge message.
298
299 @since: 0.5
300 """
301 return AcknowledgeMessageExt(**self.__dict__)
302
303
400
401
403 """
404 I am the Flex error message to be returned to the client.
405
406 This class is used to report errors within the messaging system.
407
408 @see: U{ErrorMessage on Livedocs (external)
409 <http://livedocs.adobe.com/flex/201/langref/mx/messaging/messages/ErrorMessage.html>}
410 """
411
412
413
414 MESSAGE_DELIVERY_IN_DOUBT = "Client.Error.DeliveryInDoubt"
415
416
417
418
419 RETRYABLE_HINT_HEADER = "DSRetryableErrorHint"
420
422 static = ('extendedData', 'faultCode', 'faultDetail', 'faultString',
423 'rootCause')
424
426 AcknowledgeMessage.__init__(self, *args, **kwargs)
427
428
429 self.extendedData = kwargs.get('extendedData', {})
430
431 self.faultCode = kwargs.get('faultCode', None)
432
433 self.faultDetail = kwargs.get('faultDetail', None)
434
435 self.faultString = kwargs.get('faultString', None)
436
437
438 self.rootCause = kwargs.get('rootCause', {})
439
441 """
442 Return a ISmallMessage representation of this error message.
443
444 @since: 0.5
445 """
446 raise NotImplementedError
447
448
450 """
451 I am used to send RPC requests to a remote endpoint.
452
453 @see: U{RemotingMessage on Livedocs (external)
454 <http://livedocs.adobe.com/flex/201/langref/mx/messaging/messages/RemotingMessage.html>}
455 """
456
458 static = ('operation', 'source')
459
461 AbstractMessage.__init__(self, *args, **kwargs)
462
463 self.operation = kwargs.get('operation', None)
464
465
466 self.source = kwargs.get('source', None)
467
468
470 """
471 An L{AcknowledgeMessage}, but implementing C{ISmallMessage}.
472
473 @since: 0.5
474 """
475
478
479
481 """
482 A L{CommandMessage}, but implementing C{ISmallMessage}.
483
484 @since: 0.5
485 """
486
489
490
492 """
493 A L{AsyncMessage}, but implementing C{ISmallMessage}.
494
495 @since: 0.5
496 """
497
500
501
503 """
504 @since: 0.5
505 """
506 flags = []
507
508 done = False
509
510 while not done:
511 byte = input.readUnsignedByte()
512
513 if not byte & SMALL_FLAG_MORE:
514 done = True
515 else:
516 byte = byte ^ SMALL_FLAG_MORE
517
518 flags.append(byte)
519
520 return flags
521
522
524 """
525 Decode a L{ByteArray} contents to a C{uuid.UUID} instance.
526
527 @since: 0.5
528 """
529 return uuid.UUID(bytes=str(obj))
530
531
532 pyamf.register_package(globals(), package=NAMESPACE)
533 pyamf.register_class(AcknowledgeMessageExt, 'DSK')
534 pyamf.register_class(CommandMessageExt, 'DSC')
535 pyamf.register_class(AsyncMessageExt, 'DSA')
536