Mercurial > repos > guerler > springsuite
comparison planemo/lib/python3.7/site-packages/boto/sqs/message.py @ 0:d30785e31577 draft
"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
| author | guerler |
|---|---|
| date | Fri, 31 Jul 2020 00:18:57 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:d30785e31577 |
|---|---|
| 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 |
