LCOV - code coverage report
Current view: top level - src/messages - mqtt_client_mqtt_header.dart (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 49 51 96.1 %
Date: 2017-10-09 Functions: 0 0 -

          Line data    Source code
       1             : /*
       2             :  * Package : mqtt_client
       3             :  * Author : S. Hamblett <steve.hamblett@linux.com>
       4             :  * Date   : 31/05/2017
       5             :  * Copyright :  S.Hamblett
       6             :  */
       7             : 
       8             : part of mqtt_client;
       9             : 
      10             : /// Represents the Fixed Header of an MQTT message.
      11             : class MqttHeader {
      12             :   /// Initializes a new instance of the MqttHeader class.
      13           6 :   MqttHeader();
      14             : 
      15             :   /// Initializes a new instance of MqttHeader" based on data contained within the supplied stream.
      16           4 :   MqttHeader.fromByteBuffer(MqttByteBuffer headerStream) {
      17           4 :     readFrom(headerStream);
      18             :   }
      19             : 
      20             :   /// Backing storage for the payload size.
      21             :   int _messageSize = 0;
      22             : 
      23             :   /// Gets or sets the type of the MQTT message.
      24             :   MqttMessageType messageType;
      25             : 
      26             :   /// Gets or sets a value indicating whether this MQTT Message is duplicate of a previous message.
      27             :   /// True if duplicate; otherwise, false.
      28             :   bool duplicate = false;
      29             : 
      30             :   /// Gets or sets the Quality of Service indicator for the message.
      31             :   MqttQos qos = MqttQos.atMostOnce;
      32             : 
      33             :   /// Gets or sets a value indicating whether this MQTT message should be retained by the message broker for transmission to new subscribers.
      34             :   /// True if message should be retained by the message broker; otherwise, false.
      35             :   /// </value>
      36             :   bool retain = false;
      37             : 
      38             :   ///     Gets or sets the size of the variable header + payload section of the message.
      39             :   /// <value>The size of the variable header + payload.</value>
      40             :   /// <exception cref="Nmqtt.InvalidPayloadSizeException">The size of the variable header + payload exceeds the maximum allowed size.</exception>
      41           2 :   int get messageSize => _messageSize;
      42             : 
      43             :   set messageSize(int value) {
      44           2 :     if (value < 0 || value > Constants.maxMessageSize) {
      45           1 :       throw new InvalidPayloadSizeException(value, Constants.maxMessageSize);
      46             :     }
      47           1 :     _messageSize = value;
      48             :   }
      49             : 
      50             :   /// Writes the header to a supplied stream.
      51             :   void writeTo(int messageSize, MqttByteBuffer messageStream) {
      52           4 :     _messageSize = messageSize;
      53           4 :     final typed.Uint8Buffer headerBuff = headerBytes();
      54           4 :     messageStream.write(headerBuff);
      55             :   }
      56             : 
      57             :   /// Creates a new MqttHeader based on a list of bytes.
      58             :   void readFrom(MqttByteBuffer headerStream) {
      59           8 :     if (headerStream.length < 2) {
      60           1 :       throw new InvalidHeaderException(
      61             :           "The supplied header is invalid. Header must be at least 2 bytes long.");
      62             :     }
      63           4 :     final int firstHeaderByte = headerStream.readByte();
      64             :     // Pull out the first byte
      65          12 :     retain = ((firstHeaderByte & 1) == 1 ? true : false);
      66          16 :     qos = MqttQos.values[((firstHeaderByte & 6) >> 1)];
      67          16 :     duplicate = (((firstHeaderByte & 8) >> 3) == 1 ? true : false);
      68          16 :     messageType = MqttMessageType.values[((firstHeaderByte & 240) >> 4)];
      69             : 
      70             :     // Decode the remaining bytes as the remaining/payload size, input param is the 2nd to last byte of the header byte list
      71             :     try {
      72           8 :       _messageSize = readRemainingLength(headerStream);
      73             :     } catch (InvalidPayloadSizeException) {
      74           0 :       throw new InvalidHeaderException(
      75           0 :           "The header being processed contained an invalid size byte pattern." +
      76             :               "Message size must take a most 4 bytes, and the last byte must have bit 8 set to 0.");
      77             :     }
      78             :   }
      79             : 
      80             :   /// Gets the value of the Mqtt header as a byte array
      81             :   typed.Uint8Buffer headerBytes() {
      82           4 :     final typed.Uint8Buffer headerBytes = new typed.Uint8Buffer();
      83             : 
      84             :     // Build the bytes that make up the header. The first byte is a combination of message type, dup,
      85             :     // qos and retain, and the follow bytes (up to 4 of them) are the size of the payload + variable header.
      86          12 :     final int messageTypeLength = messageType.index << 4;
      87           8 :     final int duplicateLength = (duplicate ? 1 : 0) << 3;
      88          12 :     final int qosLength = qos.index << 1;
      89           4 :     final int retainLength = retain ? 1 : 0;
      90           8 :     final int firstByte = messageTypeLength + duplicateLength +
      91           4 :         qosLength + retainLength;
      92           4 :     headerBytes.add(firstByte);
      93           8 :     headerBytes.addAll(getRemainingLengthBytes());
      94             :     return headerBytes;
      95             :   }
      96             : 
      97             :   static int readRemainingLength(MqttByteBuffer headerStream) {
      98           4 :     final typed.Uint8Buffer lengthBytes = readLengthBytes(headerStream);
      99           4 :     return calculateLength(lengthBytes);
     100             :   }
     101             : 
     102             :   /// Reads the length bytes of an MqttHeader from the supplied stream.
     103             :   static typed.Uint8Buffer readLengthBytes(MqttByteBuffer headerStream) {
     104           4 :     final typed.Uint8Buffer lengthBytes = new typed.Uint8Buffer();
     105             :     // Read until we've got the entire size, or the 4 byte limit is reached
     106             :     int sizeByte;
     107             :     int byteCount = 0;
     108             :     do {
     109           4 :       sizeByte = headerStream.readByte();
     110           4 :       lengthBytes.add(sizeByte);
     111          16 :     } while (++byteCount <= 4 && (sizeByte & 0x80) == 0x80);
     112             :     return lengthBytes;
     113             :   }
     114             : 
     115             :   /// Calculates and return the bytes that represent the remaining length of the message.
     116             :   typed.Uint8Buffer getRemainingLengthBytes() {
     117           4 :     final typed.Uint8Buffer lengthBytes = new typed.Uint8Buffer();
     118           4 :     int payloadCalc = _messageSize;
     119             : 
     120             :     // Generate a byte array based on the message size, splitting it up into
     121             :     // 7 bit chunks, with the 8th bit being used to indicate "one more to come"
     122             :     do {
     123           4 :       int nextByteValue = payloadCalc % 128;
     124           4 :       payloadCalc = (payloadCalc ~/ 128);
     125           4 :       if (payloadCalc > 0) {
     126           1 :         nextByteValue = nextByteValue | 0x80;
     127             :       }
     128           4 :       lengthBytes.add(nextByteValue);
     129           4 :     } while (payloadCalc > 0);
     130             : 
     131             :     return lengthBytes;
     132             :   }
     133             : 
     134             :   /// Calculates the remaining length of an MqttMessage from the bytes that make up the length
     135             :   static int calculateLength(typed.Uint8Buffer lengthBytes) {
     136             :     var remainingLength = 0;
     137             :     var multiplier = 1;
     138             : 
     139           8 :     for (int currentByte in lengthBytes) {
     140          12 :       remainingLength += (currentByte & 0x7f) * multiplier;
     141           4 :       multiplier *= 0x80;
     142             :     }
     143             :     return remainingLength;
     144             :   }
     145             : 
     146             :   /// Sets the IsDuplicate flag of the header.
     147             :   MqttHeader isDuplicate() {
     148           1 :     this.duplicate = true;
     149             :     return this;
     150             :   }
     151             : 
     152             :   /// Sets the Qos of the message header.
     153             :   MqttHeader withQos(MqttQos qos) {
     154           4 :     this.qos = qos;
     155             :     return this;
     156             :   }
     157             : 
     158             :   /// Sets the type of the message identified in the header.
     159             :   MqttHeader asType(MqttMessageType messageType) {
     160           6 :     this.messageType = messageType;
     161             :     return this;
     162             :   }
     163             : 
     164             :   /// Defines that the message should be retained.
     165             :   MqttHeader shouldBeRetained() {
     166           1 :     this.retain = true;
     167             :     return this;
     168             :   }
     169             : 
     170             :   String toString() {
     171          36 :     return "Header: MessageType = $messageType, Duplicate = $duplicate, Retain = $retain, Qos = $qos, Size = $_messageSize";
     172             :   }
     173             : }

Generated by: LCOV version 1.10