reasoncodes.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. """
  2. *******************************************************************
  3. Copyright (c) 2017, 2019 IBM Corp.
  4. All rights reserved. This program and the accompanying materials
  5. are made available under the terms of the Eclipse Public License v1.0
  6. and Eclipse Distribution License v1.0 which accompany this distribution.
  7. The Eclipse Public License is available at
  8. http://www.eclipse.org/legal/epl-v10.html
  9. and the Eclipse Distribution License is available at
  10. http://www.eclipse.org/org/documents/edl-v10.php.
  11. Contributors:
  12. Ian Craggs - initial implementation and/or documentation
  13. *******************************************************************
  14. """
  15. import sys
  16. from .packettypes import PacketTypes
  17. class ReasonCodes:
  18. """MQTT version 5.0 reason codes class.
  19. See ReasonCodes.names for a list of possible numeric values along with their
  20. names and the packets to which they apply.
  21. """
  22. def __init__(self, packetType, aName="Success", identifier=-1):
  23. """
  24. packetType: the type of the packet, such as PacketTypes.CONNECT that
  25. this reason code will be used with. Some reason codes have different
  26. names for the same identifier when used a different packet type.
  27. aName: the String name of the reason code to be created. Ignored
  28. if the identifier is set.
  29. identifier: an integer value of the reason code to be created.
  30. """
  31. self.packetType = packetType
  32. self.names = {
  33. 0: {"Success": [PacketTypes.CONNACK, PacketTypes.PUBACK,
  34. PacketTypes.PUBREC, PacketTypes.PUBREL, PacketTypes.PUBCOMP,
  35. PacketTypes.UNSUBACK, PacketTypes.AUTH],
  36. "Normal disconnection": [PacketTypes.DISCONNECT],
  37. "Granted QoS 0": [PacketTypes.SUBACK]},
  38. 1: {"Granted QoS 1": [PacketTypes.SUBACK]},
  39. 2: {"Granted QoS 2": [PacketTypes.SUBACK]},
  40. 4: {"Disconnect with will message": [PacketTypes.DISCONNECT]},
  41. 16: {"No matching subscribers":
  42. [PacketTypes.PUBACK, PacketTypes.PUBREC]},
  43. 17: {"No subscription found": [PacketTypes.UNSUBACK]},
  44. 24: {"Continue authentication": [PacketTypes.AUTH]},
  45. 25: {"Re-authenticate": [PacketTypes.AUTH]},
  46. 128: {"Unspecified error": [PacketTypes.CONNACK, PacketTypes.PUBACK,
  47. PacketTypes.PUBREC, PacketTypes.SUBACK, PacketTypes.UNSUBACK,
  48. PacketTypes.DISCONNECT], },
  49. 129: {"Malformed packet":
  50. [PacketTypes.CONNACK, PacketTypes.DISCONNECT]},
  51. 130: {"Protocol error":
  52. [PacketTypes.CONNACK, PacketTypes.DISCONNECT]},
  53. 131: {"Implementation specific error": [PacketTypes.CONNACK,
  54. PacketTypes.PUBACK, PacketTypes.PUBREC, PacketTypes.SUBACK,
  55. PacketTypes.UNSUBACK, PacketTypes.DISCONNECT], },
  56. 132: {"Unsupported protocol version": [PacketTypes.CONNACK]},
  57. 133: {"Client identifier not valid": [PacketTypes.CONNACK]},
  58. 134: {"Bad user name or password": [PacketTypes.CONNACK]},
  59. 135: {"Not authorized": [PacketTypes.CONNACK, PacketTypes.PUBACK,
  60. PacketTypes.PUBREC, PacketTypes.SUBACK, PacketTypes.UNSUBACK,
  61. PacketTypes.DISCONNECT], },
  62. 136: {"Server unavailable": [PacketTypes.CONNACK]},
  63. 137: {"Server busy": [PacketTypes.CONNACK, PacketTypes.DISCONNECT]},
  64. 138: {"Banned": [PacketTypes.CONNACK]},
  65. 139: {"Server shutting down": [PacketTypes.DISCONNECT]},
  66. 140: {"Bad authentication method":
  67. [PacketTypes.CONNACK, PacketTypes.DISCONNECT]},
  68. 141: {"Keep alive timeout": [PacketTypes.DISCONNECT]},
  69. 142: {"Session taken over": [PacketTypes.DISCONNECT]},
  70. 143: {"Topic filter invalid":
  71. [PacketTypes.SUBACK, PacketTypes.UNSUBACK, PacketTypes.DISCONNECT]},
  72. 144: {"Topic name invalid":
  73. [PacketTypes.CONNACK, PacketTypes.PUBACK,
  74. PacketTypes.PUBREC, PacketTypes.DISCONNECT]},
  75. 145: {"Packet identifier in use":
  76. [PacketTypes.PUBACK, PacketTypes.PUBREC,
  77. PacketTypes.SUBACK, PacketTypes.UNSUBACK]},
  78. 146: {"Packet identifier not found":
  79. [PacketTypes.PUBREL, PacketTypes.PUBCOMP]},
  80. 147: {"Receive maximum exceeded": [PacketTypes.DISCONNECT]},
  81. 148: {"Topic alias invalid": [PacketTypes.DISCONNECT]},
  82. 149: {"Packet too large": [PacketTypes.CONNACK, PacketTypes.DISCONNECT]},
  83. 150: {"Message rate too high": [PacketTypes.DISCONNECT]},
  84. 151: {"Quota exceeded": [PacketTypes.CONNACK, PacketTypes.PUBACK,
  85. PacketTypes.PUBREC, PacketTypes.SUBACK, PacketTypes.DISCONNECT], },
  86. 152: {"Administrative action": [PacketTypes.DISCONNECT]},
  87. 153: {"Payload format invalid":
  88. [PacketTypes.PUBACK, PacketTypes.PUBREC, PacketTypes.DISCONNECT]},
  89. 154: {"Retain not supported":
  90. [PacketTypes.CONNACK, PacketTypes.DISCONNECT]},
  91. 155: {"QoS not supported":
  92. [PacketTypes.CONNACK, PacketTypes.DISCONNECT]},
  93. 156: {"Use another server":
  94. [PacketTypes.CONNACK, PacketTypes.DISCONNECT]},
  95. 157: {"Server moved":
  96. [PacketTypes.CONNACK, PacketTypes.DISCONNECT]},
  97. 158: {"Shared subscription not supported":
  98. [PacketTypes.SUBACK, PacketTypes.DISCONNECT]},
  99. 159: {"Connection rate exceeded":
  100. [PacketTypes.CONNACK, PacketTypes.DISCONNECT]},
  101. 160: {"Maximum connect time":
  102. [PacketTypes.DISCONNECT]},
  103. 161: {"Subscription identifiers not supported":
  104. [PacketTypes.SUBACK, PacketTypes.DISCONNECT]},
  105. 162: {"Wildcard subscription not supported":
  106. [PacketTypes.SUBACK, PacketTypes.DISCONNECT]},
  107. }
  108. if identifier == -1:
  109. if packetType == PacketTypes.DISCONNECT and aName == "Success":
  110. aName = "Normal disconnection"
  111. self.set(aName)
  112. else:
  113. self.value = identifier
  114. self.getName() # check it's good
  115. def __getName__(self, packetType, identifier):
  116. """
  117. Get the reason code string name for a specific identifier.
  118. The name can vary by packet type for the same identifier, which
  119. is why the packet type is also required.
  120. Used when displaying the reason code.
  121. """
  122. assert identifier in self.names.keys(), identifier
  123. names = self.names[identifier]
  124. namelist = [name for name in names.keys() if packetType in names[name]]
  125. assert len(namelist) == 1
  126. return namelist[0]
  127. def getId(self, name):
  128. """
  129. Get the numeric id corresponding to a reason code name.
  130. Used when setting the reason code for a packetType
  131. check that only valid codes for the packet are set.
  132. """
  133. identifier = None
  134. for code in self.names.keys():
  135. if name in self.names[code].keys():
  136. if self.packetType in self.names[code][name]:
  137. identifier = code
  138. break
  139. assert identifier != None, name
  140. return identifier
  141. def set(self, name):
  142. self.value = self.getId(name)
  143. def unpack(self, buffer):
  144. c = buffer[0]
  145. if sys.version_info[0] < 3:
  146. c = ord(c)
  147. name = self.__getName__(self.packetType, c)
  148. self.value = self.getId(name)
  149. return 1
  150. def getName(self):
  151. """Returns the reason code name corresponding to the numeric value which is set.
  152. """
  153. return self.__getName__(self.packetType, self.value)
  154. def __eq__(self, other):
  155. if isinstance(other, int):
  156. return self.value == other
  157. if isinstance(other, str):
  158. return self.value == str(self)
  159. if isinstance(other, ReasonCodes):
  160. return self.value == other.value
  161. return False
  162. def __str__(self):
  163. return self.getName()
  164. def json(self):
  165. return self.getName()
  166. def pack(self):
  167. return bytearray([self.value])