comparison env/lib/python3.9/site-packages/boto/sqs/message.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 # Copyright (c) 2006,2007 Mitch Garnaat http://garnaat.org/
2 #
3 # Permission is hereby granted, free of charge, to any person obtaining a
4 # copy of this software and associated documentation files (the
5 # "Software"), to deal in the Software without restriction, including
6 # without limitation the rights to use, copy, modify, merge, publish, dis-
7 # tribute, sublicense, and/or sell copies of the Software, and to permit
8 # persons to whom the Software is furnished to do so, subject to the fol-
9 # lowing conditions:
10 #
11 # The above copyright notice and this permission notice shall be included
12 # in all copies or substantial portions of the Software.
13 #
14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
16 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
17 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 # IN THE SOFTWARE.
21
22 """
23 SQS Message
24
25 A Message represents the data stored in an SQS queue. The rules for what is allowed within an SQS
26 Message are here:
27
28 http://docs.amazonwebservices.com/AWSSimpleQueueService/2008-01-01/SQSDeveloperGuide/Query_QuerySendMessage.html
29
30 So, at it's simplest level a Message just needs to allow a developer to store bytes in it and get the bytes
31 back out. However, to allow messages to have richer semantics, the Message class must support the
32 following interfaces:
33
34 The constructor for the Message class must accept a keyword parameter "queue" which is an instance of a
35 boto Queue object and represents the queue that the message will be stored in. The default value for
36 this parameter is None.
37
38 The constructor for the Message class must accept a keyword parameter "body" which represents the
39 content or body of the message. The format of this parameter will depend on the behavior of the
40 particular Message subclass. For example, if the Message subclass provides dictionary-like behavior to the
41 user the body passed to the constructor should be a dict-like object that can be used to populate
42 the initial state of the message.
43
44 The Message class must provide an encode method that accepts a value of the same type as the body
45 parameter of the constructor and returns a string of characters that are able to be stored in an
46 SQS message body (see rules above).
47
48 The Message class must provide a decode method that accepts a string of characters that can be
49 stored (and probably were stored!) in an SQS message and return an object of a type that is consistent
50 with the "body" parameter accepted on the class constructor.
51
52 The Message class must provide a __len__ method that will return the size of the encoded message
53 that would be stored in SQS based on the current state of the Message object.
54
55 The Message class must provide a get_body method that will return the body of the message in the
56 same format accepted in the constructor of the class.
57
58 The Message class must provide a set_body method that accepts a message body in the same format
59 accepted by the constructor of the class. This method should alter to the internal state of the
60 Message object to reflect the state represented in the message body parameter.
61
62 The Message class must provide a get_body_encoded method that returns the current body of the message
63 in the format in which it would be stored in SQS.
64 """
65
66 import base64
67
68 import boto
69
70 from boto.compat import StringIO
71 from boto.compat import six
72 from boto.sqs.attributes import Attributes
73 from boto.sqs.messageattributes import MessageAttributes
74 from boto.exception import SQSDecodeError
75
76 class RawMessage(object):
77 """
78 Base class for SQS messages. RawMessage does not encode the message
79 in any way. Whatever you store in the body of the message is what
80 will be written to SQS and whatever is returned from SQS is stored
81 directly into the body of the message.
82 """
83
84 def __init__(self, queue=None, body=''):
85 self.queue = queue
86 self.set_body(body)
87 self.id = None
88 self.receipt_handle = None
89 self.md5 = None
90 self.attributes = Attributes(self)
91 self.message_attributes = MessageAttributes(self)
92 self.md5_message_attributes = None
93
94 def __len__(self):
95 return len(self.encode(self._body))
96
97 def startElement(self, name, attrs, connection):
98 if name == 'Attribute':
99 return self.attributes
100 if name == 'MessageAttribute':
101 return self.message_attributes
102 return None
103
104 def endElement(self, name, value, connection):
105 if name == 'Body':
106 self.set_body(value)
107 elif name == 'MessageId':
108 self.id = value
109 elif name == 'ReceiptHandle':
110 self.receipt_handle = value
111 elif name == 'MD5OfBody':
112 self.md5 = value
113 elif name == 'MD5OfMessageAttributes':
114 self.md5_message_attributes = value
115 else:
116 setattr(self, name, value)
117
118 def endNode(self, connection):
119 self.set_body(self.decode(self.get_body()))
120
121 def encode(self, value):
122 """Transform body object into serialized byte array format."""
123 return value
124
125 def decode(self, value):
126 """Transform seralized byte array into any object."""
127 return value
128
129 def set_body(self, body):
130 """Override the current body for this object, using decoded format."""
131 self._body = body
132
133 def get_body(self):
134 return self._body
135
136 def get_body_encoded(self):
137 """
138 This method is really a semi-private method used by the Queue.write
139 method when writing the contents of the message to SQS.
140 You probably shouldn't need to call this method in the normal course of events.
141 """
142 return self.encode(self.get_body())
143
144 def delete(self):
145 if self.queue:
146 return self.queue.delete_message(self)
147
148 def change_visibility(self, visibility_timeout):
149 if self.queue:
150 self.queue.connection.change_message_visibility(self.queue,
151 self.receipt_handle,
152 visibility_timeout)
153
154 class Message(RawMessage):
155 """
156 The default Message class used for SQS queues. This class automatically
157 encodes/decodes the message body using Base64 encoding to avoid any
158 illegal characters in the message body. See:
159
160 https://forums.aws.amazon.com/thread.jspa?threadID=13067
161
162 for details on why this is a good idea. The encode/decode is meant to
163 be transparent to the end-user.
164 """
165
166 def encode(self, value):
167 if not isinstance(value, six.binary_type):
168 value = value.encode('utf-8')
169 return base64.b64encode(value).decode('utf-8')
170
171 def decode(self, value):
172 try:
173 value = base64.b64decode(value.encode('utf-8')).decode('utf-8')
174 except:
175 boto.log.warning('Unable to decode message')
176 return value
177 return value
178
179 class MHMessage(Message):
180 """
181 The MHMessage class provides a message that provides RFC821-like
182 headers like this:
183
184 HeaderName: HeaderValue
185
186 The encoding/decoding of this is handled automatically and after
187 the message body has been read, the message instance can be treated
188 like a mapping object, i.e. m['HeaderName'] would return 'HeaderValue'.
189 """
190
191 def __init__(self, queue=None, body=None, xml_attrs=None):
192 if body is None or body == '':
193 body = {}
194 super(MHMessage, self).__init__(queue, body)
195
196 def decode(self, value):
197 try:
198 msg = {}
199 fp = StringIO(value)
200 line = fp.readline()
201 while line:
202 delim = line.find(':')
203 key = line[0:delim]
204 value = line[delim+1:].strip()
205 msg[key.strip()] = value.strip()
206 line = fp.readline()
207 except:
208 raise SQSDecodeError('Unable to decode message', self)
209 return msg
210
211 def encode(self, value):
212 s = ''
213 for item in value.items():
214 s = s + '%s: %s\n' % (item[0], item[1])
215 return s
216
217 def __contains__(self, key):
218 return key in self._body
219
220 def __getitem__(self, key):
221 if key in self._body:
222 return self._body[key]
223 else:
224 raise KeyError(key)
225
226 def __setitem__(self, key, value):
227 self._body[key] = value
228 self.set_body(self._body)
229
230 def keys(self):
231 return self._body.keys()
232
233 def values(self):
234 return self._body.values()
235
236 def items(self):
237 return self._body.items()
238
239 def has_key(self, key):
240 return key in self._body
241
242 def update(self, d):
243 self._body.update(d)
244 self.set_body(self._body)
245
246 def get(self, key, default=None):
247 return self._body.get(key, default)
248
249 class EncodedMHMessage(MHMessage):
250 """
251 The EncodedMHMessage class provides a message that provides RFC821-like
252 headers like this:
253
254 HeaderName: HeaderValue
255
256 This variation encodes/decodes the body of the message in base64 automatically.
257 The message instance can be treated like a mapping object,
258 i.e. m['HeaderName'] would return 'HeaderValue'.
259 """
260
261 def decode(self, value):
262 try:
263 value = base64.b64decode(value.encode('utf-8')).decode('utf-8')
264 except:
265 raise SQSDecodeError('Unable to decode message', self)
266 return super(EncodedMHMessage, self).decode(value)
267
268 def encode(self, value):
269 value = super(EncodedMHMessage, self).encode(value)
270 return base64.b64encode(value.encode('utf-8')).decode('utf-8')
271