fix(xep): Fix resend behaviour leading to period disconnects
It seems that we were expecting acks "in the future" for old stanzas. Also, this commit should prevent E2EE implementations from re-encrypting resent stanzas. Fixes #38.
This commit is contained in:
		
							parent
							
								
									4f9a0605c7
								
							
						
					
					
						commit
						2db44e2f51
					
				@ -28,7 +28,6 @@ import 'package:moxxmpp/src/stringxml.dart';
 | 
				
			|||||||
import 'package:moxxmpp/src/util/queue.dart';
 | 
					import 'package:moxxmpp/src/util/queue.dart';
 | 
				
			||||||
import 'package:moxxmpp/src/util/typed_map.dart';
 | 
					import 'package:moxxmpp/src/util/typed_map.dart';
 | 
				
			||||||
import 'package:moxxmpp/src/xeps/xep_0030/xep_0030.dart';
 | 
					import 'package:moxxmpp/src/xeps/xep_0030/xep_0030.dart';
 | 
				
			||||||
import 'package:moxxmpp/src/xeps/xep_0198/types.dart';
 | 
					 | 
				
			||||||
import 'package:moxxmpp/src/xeps/xep_0198/xep_0198.dart';
 | 
					import 'package:moxxmpp/src/xeps/xep_0198/xep_0198.dart';
 | 
				
			||||||
import 'package:moxxmpp/src/xeps/xep_0352.dart';
 | 
					import 'package:moxxmpp/src/xeps/xep_0352.dart';
 | 
				
			||||||
import 'package:synchronized/synchronized.dart';
 | 
					import 'package:synchronized/synchronized.dart';
 | 
				
			||||||
@ -533,15 +532,14 @@ class XmppConnection {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Run post-send handlers
 | 
					    // Run post-send handlers
 | 
				
			||||||
    _log.fine('Running post stanza handlers..');
 | 
					    _log.fine('Running post stanza handlers..');
 | 
				
			||||||
    final extensions = TypedMap<StanzaHandlerExtension>()
 | 
					 | 
				
			||||||
      ..set(StreamManagementData(details.excludeFromStreamManagement));
 | 
					 | 
				
			||||||
    await _runOutgoingPostStanzaHandlers(
 | 
					    await _runOutgoingPostStanzaHandlers(
 | 
				
			||||||
      newStanza,
 | 
					      newStanza,
 | 
				
			||||||
      initial: StanzaHandlerData(
 | 
					      initial: StanzaHandlerData(
 | 
				
			||||||
        false,
 | 
					        false,
 | 
				
			||||||
        false,
 | 
					        false,
 | 
				
			||||||
        newStanza,
 | 
					        newStanza,
 | 
				
			||||||
        extensions,
 | 
					        details.postSendExtensions ?? TypedMap<StanzaHandlerExtension>(),
 | 
				
			||||||
 | 
					        encrypted: data.encrypted,
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    _log.fine('Done');
 | 
					    _log.fine('Done');
 | 
				
			||||||
 | 
				
			|||||||
@ -11,6 +11,8 @@ import 'package:moxxmpp/src/negotiators/namespaces.dart';
 | 
				
			|||||||
import 'package:moxxmpp/src/negotiators/negotiator.dart';
 | 
					import 'package:moxxmpp/src/negotiators/negotiator.dart';
 | 
				
			||||||
import 'package:moxxmpp/src/stanza.dart';
 | 
					import 'package:moxxmpp/src/stanza.dart';
 | 
				
			||||||
import 'package:moxxmpp/src/stringxml.dart';
 | 
					import 'package:moxxmpp/src/stringxml.dart';
 | 
				
			||||||
 | 
					import 'package:moxxmpp/src/util/typed_map.dart';
 | 
				
			||||||
 | 
					import 'package:moxxmpp/src/xeps/xep_0198/types.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// A function that will be called when presence, outside of subscription request
 | 
					/// A function that will be called when presence, outside of subscription request
 | 
				
			||||||
/// management, will be sent. Useful for managers that want to add [XMLNode]s to said
 | 
					/// management, will be sent. Useful for managers that want to add [XMLNode]s to said
 | 
				
			||||||
@ -156,7 +158,9 @@ class PresenceManager extends XmppManagerBase {
 | 
				
			|||||||
        ),
 | 
					        ),
 | 
				
			||||||
        awaitable: false,
 | 
					        awaitable: false,
 | 
				
			||||||
        bypassQueue: true,
 | 
					        bypassQueue: true,
 | 
				
			||||||
        excludeFromStreamManagement: true,
 | 
					        postSendExtensions: TypedMap<StanzaHandlerExtension>.fromList([
 | 
				
			||||||
 | 
					          const StreamManagementData(true, null),
 | 
				
			||||||
 | 
					        ]),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,7 @@
 | 
				
			|||||||
 | 
					import 'package:moxxmpp/src/managers/data.dart';
 | 
				
			||||||
import 'package:moxxmpp/src/namespaces.dart';
 | 
					import 'package:moxxmpp/src/namespaces.dart';
 | 
				
			||||||
import 'package:moxxmpp/src/stringxml.dart';
 | 
					import 'package:moxxmpp/src/stringxml.dart';
 | 
				
			||||||
 | 
					import 'package:moxxmpp/src/util/typed_map.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// A description of a stanza to send.
 | 
					/// A description of a stanza to send.
 | 
				
			||||||
class StanzaDetails {
 | 
					class StanzaDetails {
 | 
				
			||||||
@ -11,7 +13,7 @@ class StanzaDetails {
 | 
				
			|||||||
    this.encrypted = false,
 | 
					    this.encrypted = false,
 | 
				
			||||||
    this.forceEncryption = false,
 | 
					    this.forceEncryption = false,
 | 
				
			||||||
    this.bypassQueue = false,
 | 
					    this.bypassQueue = false,
 | 
				
			||||||
    this.excludeFromStreamManagement = false,
 | 
					    this.postSendExtensions,
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// The stanza to send.
 | 
					  /// The stanza to send.
 | 
				
			||||||
@ -42,7 +44,7 @@ class StanzaDetails {
 | 
				
			|||||||
  /// This makes the Stream Management implementation, when available, ignore the stanza,
 | 
					  /// This makes the Stream Management implementation, when available, ignore the stanza,
 | 
				
			||||||
  /// meaning that it gets counted but excluded from resending.
 | 
					  /// meaning that it gets counted but excluded from resending.
 | 
				
			||||||
  /// This should never have to be set to true.
 | 
					  /// This should never have to be set to true.
 | 
				
			||||||
  final bool excludeFromStreamManagement;
 | 
					  final TypedMap<StanzaHandlerExtension>? postSendExtensions;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// A simple description of the <error /> element that may be inside a stanza
 | 
					/// A simple description of the <error /> element that may be inside a stanza
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,39 @@
 | 
				
			|||||||
 | 
					import 'package:meta/meta.dart';
 | 
				
			||||||
import 'package:moxxmpp/src/managers/data.dart';
 | 
					import 'package:moxxmpp/src/managers/data.dart';
 | 
				
			||||||
 | 
					import 'package:moxxmpp/src/stanza.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class StreamManagementData implements StanzaHandlerExtension {
 | 
					class StreamManagementData implements StanzaHandlerExtension {
 | 
				
			||||||
  const StreamManagementData(this.exclude);
 | 
					  const StreamManagementData(this.exclude, this.queueId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Whether the stanza should be exluded from the StreamManagement's resend queue.
 | 
					  /// Whether the stanza should be exluded from the StreamManagement's resend queue.
 | 
				
			||||||
  final bool exclude;
 | 
					  final bool exclude;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// The ID to use when queuing the stanza.
 | 
				
			||||||
 | 
					  final int? queueId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// If we resend a stanza, then we will have [queueId] set, so we should skip
 | 
				
			||||||
 | 
					  /// incrementing the C2S counter.
 | 
				
			||||||
 | 
					  bool get shouldCountStanza => queueId == null;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// A queue element for keeping track of stanzas to (potentially) resend.
 | 
				
			||||||
 | 
					@immutable
 | 
				
			||||||
 | 
					class SMQueueEntry {
 | 
				
			||||||
 | 
					  const SMQueueEntry(this.stanza, this.encrypted);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// The actual stanza.
 | 
				
			||||||
 | 
					  final Stanza stanza;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// Flag indicating whether the stanza was encrypted before sending.
 | 
				
			||||||
 | 
					  final bool encrypted;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  bool operator ==(Object other) {
 | 
				
			||||||
 | 
					    return other is SMQueueEntry &&
 | 
				
			||||||
 | 
					        other.stanza == stanza &&
 | 
				
			||||||
 | 
					        other.encrypted == encrypted;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  int get hashCode => stanza.hashCode ^ encrypted.hashCode;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -11,6 +11,7 @@ import 'package:moxxmpp/src/namespaces.dart';
 | 
				
			|||||||
import 'package:moxxmpp/src/negotiators/namespaces.dart';
 | 
					import 'package:moxxmpp/src/negotiators/namespaces.dart';
 | 
				
			||||||
import 'package:moxxmpp/src/stanza.dart';
 | 
					import 'package:moxxmpp/src/stanza.dart';
 | 
				
			||||||
import 'package:moxxmpp/src/stringxml.dart';
 | 
					import 'package:moxxmpp/src/stringxml.dart';
 | 
				
			||||||
 | 
					import 'package:moxxmpp/src/util/typed_map.dart';
 | 
				
			||||||
import 'package:moxxmpp/src/xeps/xep_0198/errors.dart';
 | 
					import 'package:moxxmpp/src/xeps/xep_0198/errors.dart';
 | 
				
			||||||
import 'package:moxxmpp/src/xeps/xep_0198/negotiator.dart';
 | 
					import 'package:moxxmpp/src/xeps/xep_0198/negotiator.dart';
 | 
				
			||||||
import 'package:moxxmpp/src/xeps/xep_0198/nonzas.dart';
 | 
					import 'package:moxxmpp/src/xeps/xep_0198/nonzas.dart';
 | 
				
			||||||
@ -28,7 +29,7 @@ class StreamManagementManager extends XmppManagerBase {
 | 
				
			|||||||
  }) : super(smManager);
 | 
					  }) : super(smManager);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// The queue of stanzas that are not (yet) acked
 | 
					  /// The queue of stanzas that are not (yet) acked
 | 
				
			||||||
  final Map<int, Stanza> _unackedStanzas = {};
 | 
					  final Map<int, SMQueueEntry> _unackedStanzas = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Commitable state of the StreamManagementManager
 | 
					  /// Commitable state of the StreamManagementManager
 | 
				
			||||||
  StreamManagementState _state = StreamManagementState(0, 0);
 | 
					  StreamManagementState _state = StreamManagementState(0, 0);
 | 
				
			||||||
@ -60,8 +61,8 @@ class StreamManagementManager extends XmppManagerBase {
 | 
				
			|||||||
  final Lock _ackLock = Lock();
 | 
					  final Lock _ackLock = Lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Functions for testing
 | 
					  /// Functions for testing
 | 
				
			||||||
  @visibleForTesting
 | 
					  /// @visibleForTesting
 | 
				
			||||||
  Map<int, Stanza> getUnackedStanzas() => _unackedStanzas;
 | 
					  Map<int, SMQueueEntry> getUnackedStanzas() => _unackedStanzas;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @visibleForTesting
 | 
					  @visibleForTesting
 | 
				
			||||||
  Future<int> getPendingAcks() async {
 | 
					  Future<int> getPendingAcks() async {
 | 
				
			||||||
@ -306,6 +307,10 @@ class StreamManagementManager extends XmppManagerBase {
 | 
				
			|||||||
        if (_pendingAcks > 0) {
 | 
					        if (_pendingAcks > 0) {
 | 
				
			||||||
          // Prevent diff from becoming negative
 | 
					          // Prevent diff from becoming negative
 | 
				
			||||||
          final diff = max(_state.c2s - h, 0);
 | 
					          final diff = max(_state.c2s - h, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          logger.finest(
 | 
				
			||||||
 | 
					            'Setting _pendingAcks to $diff (was $_pendingAcks before): max(${_state.c2s} - $h, 0)',
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
          _pendingAcks = diff;
 | 
					          _pendingAcks = diff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          // Reset the timer
 | 
					          // Reset the timer
 | 
				
			||||||
@ -336,15 +341,18 @@ class StreamManagementManager extends XmppManagerBase {
 | 
				
			|||||||
      final attrs = getAttributes();
 | 
					      final attrs = getAttributes();
 | 
				
			||||||
      final sequences = _unackedStanzas.keys.toList()..sort();
 | 
					      final sequences = _unackedStanzas.keys.toList()..sort();
 | 
				
			||||||
      for (final height in sequences) {
 | 
					      for (final height in sequences) {
 | 
				
			||||||
 | 
					        logger.finest('Unacked stanza: height $height, h $h');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Do nothing if the ack does not concern this stanza
 | 
					        // Do nothing if the ack does not concern this stanza
 | 
				
			||||||
        if (height > h) continue;
 | 
					        if (height > h) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        final stanza = _unackedStanzas[height]!;
 | 
					        logger.finest('Removing stanza with height $height');
 | 
				
			||||||
 | 
					        final entry = _unackedStanzas[height]!;
 | 
				
			||||||
        _unackedStanzas.remove(height);
 | 
					        _unackedStanzas.remove(height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Create a StanzaAckedEvent if the stanza is correct
 | 
					        // Create a StanzaAckedEvent if the stanza is correct
 | 
				
			||||||
        if (shouldTriggerAckedEvent(stanza)) {
 | 
					        if (shouldTriggerAckedEvent(entry.stanza)) {
 | 
				
			||||||
          attrs.sendEvent(StanzaAckedEvent(stanza));
 | 
					          attrs.sendEvent(StanzaAckedEvent(entry.stanza));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -401,13 +409,29 @@ class StreamManagementManager extends XmppManagerBase {
 | 
				
			|||||||
    StanzaHandlerData state,
 | 
					    StanzaHandlerData state,
 | 
				
			||||||
  ) async {
 | 
					  ) async {
 | 
				
			||||||
    if (isStreamManagementEnabled()) {
 | 
					    if (isStreamManagementEnabled()) {
 | 
				
			||||||
      await _incrementC2S();
 | 
					      final smData = state.extensions.get<StreamManagementData>();
 | 
				
			||||||
 | 
					      logger.finest('Should count stanza: ${smData?.shouldCountStanza}');
 | 
				
			||||||
 | 
					      if (smData?.shouldCountStanza ?? true) {
 | 
				
			||||||
 | 
					        await _incrementC2S();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (state.extensions.get<StreamManagementData>()?.exclude ?? false) {
 | 
					      if (smData?.exclude ?? false) {
 | 
				
			||||||
        return state;
 | 
					        return state;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      _unackedStanzas[_state.c2s] = stanza;
 | 
					      int queueId;
 | 
				
			||||||
 | 
					      if (smData?.queueId != null) {
 | 
				
			||||||
 | 
					        logger.finest('Reusing queue id ${smData!.queueId}');
 | 
				
			||||||
 | 
					        queueId = smData.queueId!;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        queueId = await _stateLock.synchronized(() => _state.c2s);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      _unackedStanzas[queueId] = SMQueueEntry(
 | 
				
			||||||
 | 
					        stanza,
 | 
				
			||||||
 | 
					        // Prevent an E2EE message being encrypted again
 | 
				
			||||||
 | 
					        state.encrypted,
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
      await _sendAckRequest();
 | 
					      await _sendAckRequest();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -415,16 +439,23 @@ class StreamManagementManager extends XmppManagerBase {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<void> _resendStanzas() async {
 | 
					  Future<void> _resendStanzas() async {
 | 
				
			||||||
    final stanzas = _unackedStanzas.values.toList();
 | 
					    final queueCopy = _unackedStanzas.entries.toList();
 | 
				
			||||||
    _unackedStanzas.clear();
 | 
					    for (final entry in queueCopy) {
 | 
				
			||||||
 | 
					      logger.finest(
 | 
				
			||||||
    for (final stanza in stanzas) {
 | 
					        'Resending ${entry.value.stanza.tag} with id ${entry.value.stanza.attributes["id"]}',
 | 
				
			||||||
      logger
 | 
					      );
 | 
				
			||||||
          .finest('Resending ${stanza.tag} with id ${stanza.attributes["id"]}');
 | 
					 | 
				
			||||||
      await getAttributes().sendStanza(
 | 
					      await getAttributes().sendStanza(
 | 
				
			||||||
        StanzaDetails(
 | 
					        StanzaDetails(
 | 
				
			||||||
          stanza,
 | 
					          entry.value.stanza,
 | 
				
			||||||
 | 
					          postSendExtensions: TypedMap<StanzaHandlerExtension>.fromList([
 | 
				
			||||||
 | 
					            StreamManagementData(
 | 
				
			||||||
 | 
					              false,
 | 
				
			||||||
 | 
					              entry.key,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          ]),
 | 
				
			||||||
          awaitable: false,
 | 
					          awaitable: false,
 | 
				
			||||||
 | 
					          // Prevent an E2EE message being encrypted again
 | 
				
			||||||
 | 
					          encrypted: entry.value.encrypted,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
import 'dart:async';
 | 
					import 'dart:async';
 | 
				
			||||||
import 'package:moxxmpp/moxxmpp.dart';
 | 
					import 'package:moxxmpp/moxxmpp.dart';
 | 
				
			||||||
 | 
					import 'package:moxxmpp/src/xeps/xep_0198/types.dart';
 | 
				
			||||||
import 'package:test/test.dart';
 | 
					import 'package:test/test.dart';
 | 
				
			||||||
import '../helpers/logging.dart';
 | 
					import '../helpers/logging.dart';
 | 
				
			||||||
import '../helpers/xmpp.dart';
 | 
					import '../helpers/xmpp.dart';
 | 
				
			||||||
@ -42,10 +43,10 @@ Future<void> runOutgoingStanzaHandlers(
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
XmppManagerAttributes mkAttributes(void Function(Stanza) callback) {
 | 
					XmppManagerAttributes mkAttributes(void Function(StanzaDetails) callback) {
 | 
				
			||||||
  return XmppManagerAttributes(
 | 
					  return XmppManagerAttributes(
 | 
				
			||||||
    sendStanza: (StanzaDetails details) async {
 | 
					    sendStanza: (StanzaDetails details) async {
 | 
				
			||||||
      callback(details.stanza);
 | 
					      callback(details);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return Stanza.message();
 | 
					      return Stanza.message();
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
@ -1069,4 +1070,49 @@ void main() {
 | 
				
			|||||||
    expect(smn.streamEnablementFailed, true);
 | 
					    expect(smn.streamEnablementFailed, true);
 | 
				
			||||||
    expect(conn.resource, 'test-resource');
 | 
					    expect(conn.resource, 'test-resource');
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  test('Test resending state changes', () async {
 | 
				
			||||||
 | 
					    final manager = StreamManagementManager();
 | 
				
			||||||
 | 
					    final attributes = mkAttributes((details) async {
 | 
				
			||||||
 | 
					      for (final handler in manager.getOutgoingPostStanzaHandlers()) {
 | 
				
			||||||
 | 
					        await handler.callback(
 | 
				
			||||||
 | 
					          details.stanza,
 | 
				
			||||||
 | 
					          StanzaHandlerData(
 | 
				
			||||||
 | 
					            false,
 | 
				
			||||||
 | 
					            false,
 | 
				
			||||||
 | 
					            stanza,
 | 
				
			||||||
 | 
					            details.postSendExtensions ?? TypedMap(),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    manager.register(attributes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await manager.onXmppEvent(
 | 
				
			||||||
 | 
					      StreamManagementEnabledEvent(resource: 'hallo'),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Send a stanza 5 times
 | 
				
			||||||
 | 
					    for (var i = 0; i < 5; i++) {
 | 
				
			||||||
 | 
					      await runOutgoingStanzaHandlers(manager, stanza);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // <a h='3'/>
 | 
				
			||||||
 | 
					    await manager.runNonzaHandlers(mkAck(3));
 | 
				
			||||||
 | 
					    //expect(manager.getUnackedStanzas().length, 2);
 | 
				
			||||||
 | 
					    final oldC2s = manager.state.c2s;
 | 
				
			||||||
 | 
					    final oldQueue = Map<int, SMQueueEntry>.from(manager.getUnackedStanzas());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Disconnect and reconnect
 | 
				
			||||||
 | 
					    await manager.onXmppEvent(ConnectingEvent());
 | 
				
			||||||
 | 
					    await manager.onXmppEvent(StreamResumedEvent(h: 3));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(manager.state.c2s, oldC2s);
 | 
				
			||||||
 | 
					    expect(manager.getUnackedStanzas(), oldQueue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Now they get acked
 | 
				
			||||||
 | 
					    await manager.runNonzaHandlers(mkAck(5));
 | 
				
			||||||
 | 
					    expect(manager.getUnackedStanzas().length, 0);
 | 
				
			||||||
 | 
					    expect(manager.state.c2s, 5);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user