deserialize method

  1. @override
AbstractMessage? deserialize(
  1. Uint8List? message
)
override

Deserialize a given message

Implementation

@override
AbstractMessage? deserialize(Uint8List? message) {
  if (message == null) {
    return null;
  }
  if (_readCborArrayHeader(message, 0) == null) {
    _validateCompleteCborValue(message);
  }
  final fastPathMessage = _deserializeFastPathMessage(message);
  if (fastPathMessage != null) {
    return fastPathMessage;
  }
  final decodedMessage = cbor.decode(message.toList());
  if (decodedMessage is CborList) {
    validateWampMessageFieldCount(decodedMessage.length);
    if (decodedMessage.isEmpty) {
      throw const FormatException('WAMP message must not be empty');
    }
    final cborMessageId = decodedMessage[0];
    if (cborMessageId is CborInt) {
      final messageId = cborMessageId.toInt();
      if (messageId != MessageTypes.codePublish ||
          decodedMessage.length < 4) {
        validateWampMessageMinimumFieldCount(
          messageId,
          decodedMessage.length,
        );
      }
      if (messageId == MessageTypes.codeAbort && decodedMessage.length == 3) {
        return Abort(
          (decodedMessage[2] as CborString).toString(),
          message:
              decodedMessage[1] is CborMap &&
                  (decodedMessage[1] as CborMap)[CborString('message')] !=
                      null
              ? ((decodedMessage[1] as CborMap)[CborString('message')]
                        as CborString)
                    .toString()
              : null,
        );
      }
      if (messageId == MessageTypes.codeChallenge &&
          decodedMessage.length == 3) {
        final extraMap = _cborMapToStringMap(decodedMessage[2] as CborMap);
        return Challenge(
          (decodedMessage[1] as CborString).toString(),
          Extra.fromMap(extraMap),
        );
      }
      if (messageId == MessageTypes.codeHello && decodedMessage.length == 3) {
        return Hello(
          (decodedMessage[1] as CborString?)?.toString(),
          _decodeDetailsMap(
            _cborMapToStringMap(decodedMessage[2] as CborMap),
          ),
        );
      }
      if (messageId == MessageTypes.codeAuthenticate &&
          decodedMessage.length == 3) {
        final extra = decodedMessage[2];
        if (extra is! CborMap ||
            extra.keys.any((key) => key is! CborString)) {
          throw const FormatException(
            'AUTHENTICATE.Extra must be a dictionary with string keys',
          );
        }
        return Authenticate(
          signature: (decodedMessage[1] as CborString?)?.toString(),
        )..extra = Map<String, Object?>.from(_cborMapToStringMap(extra));
      }
      if (messageId == MessageTypes.codeWelcome &&
          decodedMessage.length == 3) {
        return Welcome(
          (decodedMessage[1] as CborInt).toInt(),
          _decodeDetailsMap(
            _cborMapToStringMap(decodedMessage[2] as CborMap),
          ),
        );
      }
      if (messageId == MessageTypes.codeRegister &&
          decodedMessage.length == 4) {
        return Register(
          (decodedMessage[1] as CborInt).toInt(),
          (decodedMessage[3] as CborString).toString(),
          options: _decodeRegisterOptions(
            _decodeRequiredOptionsMap(decodedMessage[2], 'REGISTER'),
          ),
        );
      }
      if (messageId == MessageTypes.codeUnregister &&
          decodedMessage.length == 3) {
        return Unregister(
          (decodedMessage[1] as CborInt).toInt(),
          (decodedMessage[2] as CborInt).toInt(),
        );
      }
      if (messageId == MessageTypes.codeCall && decodedMessage.length >= 4) {
        return _addPayload(
          Call(
            (decodedMessage[1] as CborInt).toInt(),
            (decodedMessage[3] as CborString).toString(),
            options: _decodeCallOptions(
              _decodeRequiredOptionsMap(decodedMessage[2], 'CALL'),
            ),
          ),
          decodedMessage,
          4,
        );
      }
      if (messageId == MessageTypes.codeYield && decodedMessage.length >= 2) {
        return _addPayload(
          Yield(
            (decodedMessage[1] as CborInt).toInt(),
            options: _decodeYieldOptions(
              _decodeRequiredOptionsMap(decodedMessage[2], 'YIELD'),
            ),
          ),
          decodedMessage,
          3,
        );
      }
      if (messageId == MessageTypes.codePublish &&
          decodedMessage.length >= 4) {
        return _addPayload(
          Publish(
            (decodedMessage[1] as CborInt).toInt(),
            (decodedMessage[3] as CborString).toString(),
            options: _decodePublishOptions(
              _decodeRequiredOptionsMap(decodedMessage[2], 'PUBLISH'),
            ),
          ),
          decodedMessage,
          4,
        );
      }
      if (messageId == MessageTypes.codeInterrupt &&
          decodedMessage.length >= 2) {
        final optionsMap = _decodeRequiredOptionsMap(
          decodedMessage[2],
          'INTERRUPT',
        );
        final options = InterruptOptions()
          ..mode = optionsMap['mode'] as String?;
        return Interrupt(
          (decodedMessage[1] as CborInt).toInt(),
          options: options,
        );
      }
      if (messageId == MessageTypes.codeCancel &&
          decodedMessage.length >= 2) {
        final optionsMap = _decodeRequiredOptionsMap(
          decodedMessage[2],
          'CANCEL',
        );
        final options = CancelOptions()..mode = optionsMap['mode'] as String?;
        return Cancel(
          (decodedMessage[1] as CborInt).toInt(),
          options: options,
        );
      }
      if (messageId == MessageTypes.codeRegistered &&
          decodedMessage.length == 3) {
        return Registered(
          (decodedMessage[1] as CborInt).toInt(),
          (decodedMessage[2] as CborInt).toInt(),
        );
      }
      if (messageId == MessageTypes.codeUnregistered &&
          decodedMessage.length == 2) {
        return Unregistered((decodedMessage[1] as CborInt).toInt());
      }
      if (messageId == MessageTypes.codeInvocation &&
          decodedMessage.length > 3) {
        final detailsMap = _cborMapToStringMap(decodedMessage[3] as CborMap);
        final caller = decodeOptionalWampId(
          detailsMap,
          'caller',
          'INVOCATION.Details.caller',
        );
        detailsMap.remove('caller');
        decodeOptionalWampNonNegativeInteger(
          detailsMap,
          'trustlevel',
          'INVOCATION.Details.trustlevel',
        );
        final procedureValue = detailsMap.remove('procedure');
        final String? procedure = procedureValue as String?;
        final progressValue = detailsMap.remove('progress');
        final bool? progress = progressValue as bool?;
        final receiveProgressValue = detailsMap.remove('receive_progress');
        final bool? receiveProgress = receiveProgressValue as bool?;
        final timeout = decodeOptionalWampNonNegativeInteger(
          detailsMap,
          'timeout',
          'INVOCATION.Details.timeout',
        );
        detailsMap.remove('timeout');
        final pptSchemeValue = detailsMap.remove('ppt_scheme');
        final String? pptScheme = pptSchemeValue as String?;
        final pptSerializerValue = detailsMap.remove('ppt_serializer');
        final String? pptSerializer = pptSerializerValue as String?;
        final pptCipherValue = detailsMap.remove('ppt_cipher');
        final String? pptCipher = pptCipherValue as String?;
        final pptKeyIdValue = detailsMap.remove('ppt_keyid');
        final String? pptKeyId = pptKeyIdValue as String?;
        return _addPayload(
          Invocation(
            (decodedMessage[1] as CborInt).toInt(),
            (decodedMessage[2] as CborInt).toInt(),
            InvocationDetails(
                caller,
                procedure,
                receiveProgress,
                pptScheme,
                pptSerializer,
                pptCipher,
                pptKeyId,
                detailsMap,
              )
              ..progress = progress
              ..timeout = timeout,
          ),
          decodedMessage,
          4,
        );
      }
      if (messageId == MessageTypes.codeResult && decodedMessage.length > 2) {
        final detailsMap = _cborMapToStringMap(decodedMessage[2] as CborMap);
        final progressValue = detailsMap.remove('progress');
        final bool? progress = progressValue as bool?;
        final pptSchemeValue = detailsMap.remove('ppt_scheme');
        final String? pptScheme = pptSchemeValue as String?;
        final pptSerializerValue = detailsMap.remove('ppt_serializer');
        final String? pptSerializer = pptSerializerValue as String?;
        final pptCipherValue = detailsMap.remove('ppt_cipher');
        final String? pptCipher = pptCipherValue as String?;
        final pptKeyIdValue = detailsMap.remove('ppt_keyid');
        final String? pptKeyId = pptKeyIdValue as String?;
        return _addPayload(
          Result(
            (decodedMessage[1] as CborInt).toInt(),
            ResultDetails(
              progress: progress,
              pptScheme: pptScheme,
              pptSerializer: pptSerializer,
              pptCipher: pptCipher,
              pptKeyId: pptKeyId,
              custom: detailsMap,
            ),
          ),
          decodedMessage,
          3,
        );
      }
      if (messageId == MessageTypes.codePublished &&
          decodedMessage.length == 3) {
        return Published(
          (decodedMessage[1] as CborInt).toInt(),
          (decodedMessage[2] as CborInt).toInt(),
        );
      }
      if (messageId == MessageTypes.codeSubscribed &&
          decodedMessage.length == 3) {
        return Subscribed(
          (decodedMessage[1] as CborInt).toInt(),
          (decodedMessage[2] as CborInt).toInt(),
        );
      }
      if (messageId == MessageTypes.codeSubscribe &&
          decodedMessage.length == 4) {
        return Subscribe(
          (decodedMessage[1] as CborInt).toInt(),
          (decodedMessage[3] as CborString).toString(),
          options: _decodeSubscribeOptions(
            _decodeRequiredOptionsMap(decodedMessage[2], 'SUBSCRIBE'),
          ),
        );
      }
      if (messageId == MessageTypes.codeUnsubscribe &&
          decodedMessage.length == 3) {
        return Unsubscribe(
          (decodedMessage[1] as CborInt).toInt(),
          (decodedMessage[2] as CborInt).toInt(),
        );
      }
      if (messageId == MessageTypes.codeUnsubscribed &&
          decodedMessage.length > 1) {
        return Unsubscribed(
          (decodedMessage[1] as CborInt).toInt(),
          decodedMessage.length == 2
              ? null
              : UnsubscribedDetails(
                  (decodedMessage[2] as CborMap)[CborString(
                            'subscription',
                          )] ==
                          null
                      ? null
                      : ((decodedMessage[2] as CborMap)[CborString(
                                  'subscription',
                                )]
                                as CborInt)
                            .toInt(),
                  (decodedMessage[2] as CborMap)[CborString('reason')] == null
                      ? null
                      : ((decodedMessage[2] as CborMap)[CborString('reason')]
                                as CborString)
                            .toString(),
                ),
        );
      }
      if (messageId == MessageTypes.codeEvent && decodedMessage.length > 3) {
        final detailsMap = _cborMapToStringMap(decodedMessage[3] as CborMap);
        final publisher = decodeOptionalWampId(
          detailsMap,
          'publisher',
          'EVENT.Details.publisher',
        );
        detailsMap.remove('publisher');
        final trustLevel = decodeOptionalWampNonNegativeInteger(
          detailsMap,
          'trustlevel',
          'EVENT.Details.trustlevel',
        );
        detailsMap.remove('trustlevel');
        final topicValue = detailsMap.remove('topic');
        final String? topic = topicValue as String?;
        final pptSchemeValue = detailsMap.remove('ppt_scheme');
        final String? pptScheme = pptSchemeValue as String?;
        final pptSerializerValue = detailsMap.remove('ppt_serializer');
        final String? pptSerializer = pptSerializerValue as String?;
        final pptCipherValue = detailsMap.remove('ppt_cipher');
        final String? pptCipher = pptCipherValue as String?;
        final pptKeyIdValue = detailsMap.remove('ppt_keyid');
        final String? pptKeyId = pptKeyIdValue as String?;
        return _addPayload(
          Event(
            (decodedMessage[1] as CborInt).toInt(),
            (decodedMessage[2] as CborInt).toInt(),
            EventDetails(
              publisher: publisher,
              trustlevel: trustLevel,
              topic: topic,
              pptScheme: pptScheme,
              pptSerializer: pptSerializer,
              pptCipher: pptCipher,
              pptKeyid: pptKeyId,
              custom: detailsMap,
            ),
          ),
          decodedMessage,
          4,
        );
      }
      if (messageId == MessageTypes.codeError && decodedMessage.length > 4) {
        return _addPayload(
          Error(
            (decodedMessage[1] as CborInt).toInt(),
            (decodedMessage[2] as CborInt).toInt(),
            Map<String, Object>.from(
              (decodedMessage[3] as CborMap).toObject() as Map,
            ),
            (decodedMessage[4] as CborString).toString(),
          ),
          decodedMessage,
          5,
        );
      }
      if (messageId == MessageTypes.codeGoodbye) {
        return Goodbye(
          decodedMessage.length == 1
              ? null
              : GoodbyeMessage(
                  (decodedMessage[1] as CborMap)[CborString('message')] ==
                          null
                      ? null
                      : ((decodedMessage[1] as CborMap)[CborString('message')]
                                as CborString)
                            .toString(),
                ),
          (decodedMessage[2] as CborString).toString(),
        );
      }
    }
  }
  _logger.shout(
    'Could not deserialize CBOR WAMP message (${message.length} bytes)',
  );
  // TODO respond with an error
  return null;
}