Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

message.py 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. """
  2. kombu.transport.message
  3. =======================
  4. Message class.
  5. """
  6. from __future__ import absolute_import
  7. import sys
  8. from .compression import decompress
  9. from .exceptions import MessageStateError
  10. from .five import reraise, text_t
  11. from .serialization import loads
  12. ACK_STATES = frozenset(['ACK', 'REJECTED', 'REQUEUED'])
  13. class Message(object):
  14. """Base class for received messages."""
  15. __slots__ = ('_state', 'channel', 'delivery_tag',
  16. 'content_type', 'content_encoding',
  17. 'delivery_info', 'headers', 'properties',
  18. 'body', '_decoded_cache', 'accept', '__dict__')
  19. MessageStateError = MessageStateError
  20. errors = None
  21. def __init__(self, channel, body=None, delivery_tag=None,
  22. content_type=None, content_encoding=None, delivery_info={},
  23. properties=None, headers=None, postencode=None,
  24. accept=None, **kwargs):
  25. self.errors = [] if self.errors is None else self.errors
  26. self.channel = channel
  27. self.delivery_tag = delivery_tag
  28. self.content_type = content_type
  29. self.content_encoding = content_encoding
  30. self.delivery_info = delivery_info
  31. self.headers = headers or {}
  32. self.properties = properties or {}
  33. self._decoded_cache = None
  34. self._state = 'RECEIVED'
  35. self.accept = accept
  36. compression = self.headers.get('compression')
  37. if not self.errors and compression:
  38. try:
  39. body = decompress(body, compression)
  40. except Exception:
  41. self.errors.append(sys.exc_info())
  42. if not self.errors and postencode and isinstance(body, text_t):
  43. try:
  44. body = body.encode(postencode)
  45. except Exception:
  46. self.errors.append(sys.exc_info())
  47. self.body = body
  48. def _reraise_error(self, callback=None):
  49. try:
  50. reraise(*self.errors[0])
  51. except Exception as exc:
  52. if not callback:
  53. raise
  54. callback(self, exc)
  55. def ack(self):
  56. """Acknowledge this message as being processed.,
  57. This will remove the message from the queue.
  58. :raises MessageStateError: If the message has already been
  59. acknowledged/requeued/rejected.
  60. """
  61. if self.channel.no_ack_consumers is not None:
  62. try:
  63. consumer_tag = self.delivery_info['consumer_tag']
  64. except KeyError:
  65. pass
  66. else:
  67. if consumer_tag in self.channel.no_ack_consumers:
  68. return
  69. if self.acknowledged:
  70. raise self.MessageStateError(
  71. 'Message already acknowledged with state: {0._state}'.format(
  72. self))
  73. self.channel.basic_ack(self.delivery_tag)
  74. self._state = 'ACK'
  75. def ack_log_error(self, logger, errors):
  76. try:
  77. self.ack()
  78. except errors as exc:
  79. logger.critical("Couldn't ack %r, reason:%r",
  80. self.delivery_tag, exc, exc_info=True)
  81. def reject_log_error(self, logger, errors, requeue=False):
  82. try:
  83. self.reject(requeue=requeue)
  84. except errors as exc:
  85. logger.critical("Couldn't reject %r, reason: %r",
  86. self.delivery_tag, exc, exc_info=True)
  87. def reject(self, requeue=False):
  88. """Reject this message.
  89. The message will be discarded by the server.
  90. :raises MessageStateError: If the message has already been
  91. acknowledged/requeued/rejected.
  92. """
  93. if self.acknowledged:
  94. raise self.MessageStateError(
  95. 'Message already acknowledged with state: {0._state}'.format(
  96. self))
  97. self.channel.basic_reject(self.delivery_tag, requeue=requeue)
  98. self._state = 'REJECTED'
  99. def requeue(self):
  100. """Reject this message and put it back on the queue.
  101. You must not use this method as a means of selecting messages
  102. to process.
  103. :raises MessageStateError: If the message has already been
  104. acknowledged/requeued/rejected.
  105. """
  106. if self.acknowledged:
  107. raise self.MessageStateError(
  108. 'Message already acknowledged with state: {0._state}'.format(
  109. self))
  110. self.channel.basic_reject(self.delivery_tag, requeue=True)
  111. self._state = 'REQUEUED'
  112. def decode(self):
  113. """Deserialize the message body, returning the original
  114. python structure sent by the publisher."""
  115. return loads(self.body, self.content_type,
  116. self.content_encoding, accept=self.accept)
  117. @property
  118. def acknowledged(self):
  119. """Set to true if the message has been acknowledged."""
  120. return self._state in ACK_STATES
  121. @property
  122. def payload(self):
  123. """The decoded message body."""
  124. if not self._decoded_cache:
  125. self._decoded_cache = self.decode()
  126. return self._decoded_cache