diff --git a/packages/moxxmpp/lib/src/connection.dart b/packages/moxxmpp/lib/src/connection.dart index 6c92e9f..52d7cf7 100644 --- a/packages/moxxmpp/lib/src/connection.dart +++ b/packages/moxxmpp/lib/src/connection.dart @@ -84,6 +84,10 @@ class XmppConnection { () => _isAuthenticated, sendRawXML, () => connectionSettings, + () { + _log.finest('Resetting stream parser'); + _streamParser.reset(); + }, ); _socketStream = _socket.getDataStream(); @@ -699,7 +703,7 @@ class XmppConnection { // Process nonzas separately if (!['message', 'iq', 'presence'].contains(nonza.tag)) { _log.finest('<== ${nonza.toXml()}'); - + var nonzaHandled = false; await Future.forEach(_xmppManagers.values, (XmppManagerBase manager) async { @@ -746,7 +750,7 @@ class XmppConnection { ), ); if (!incomingHandlers.done) { - _log.warning('Returning error for unhandled stanza'); + _log.warning('Returning error for unhandled stanza ${incomingPreHandlers.stanza.tag}'); await handleUnhandledStanza(this, incomingPreHandlers); } } @@ -809,8 +813,6 @@ class XmppConnection { /// Sends an event to the connection's event stream. Future _sendEvent(XmppEvent event) async { - _log.finest('Event: ${event.toString()}'); - for (final manager in _xmppManagers.values) { await manager.onXmppEvent(event); } diff --git a/packages/moxxmpp/lib/src/handlers/base.dart b/packages/moxxmpp/lib/src/handlers/base.dart index eaf06db..5bec690 100644 --- a/packages/moxxmpp/lib/src/handlers/base.dart +++ b/packages/moxxmpp/lib/src/handlers/base.dart @@ -22,6 +22,9 @@ typedef SendNonzaFunction = void Function(XMLNode); /// Returns the connection settings. typedef GetConnectionSettingsFunction = ConnectionSettings Function(); +/// Resets the stream parser's state. +typedef ResetStreamParserFunction = void Function(); + /// This class implements the stream feature negotiation for XmppConnection. abstract class NegotiationsHandler { @protected @@ -51,6 +54,9 @@ abstract class NegotiationsHandler { @protected late final GetConnectionSettingsFunction getConnectionSettings; + @protected + late final ResetStreamParserFunction resetStreamParser; + /// The id included in the last stream header. @protected String? streamId; @@ -72,12 +78,14 @@ abstract class NegotiationsHandler { IsAuthenticatedFunction isAuthenticated, SendNonzaFunction sendNonza, GetConnectionSettingsFunction getConnectionSettings, + ResetStreamParserFunction resetStreamParser, ) { this.onNegotiationsDone = onNegotiationsDone; this.handleError = handleError; this.isAuthenticated = isAuthenticated; this.sendNonza = sendNonza; this.getConnectionSettings = getConnectionSettings; + this.resetStreamParser = resetStreamParser; log = Logger(toString()); } diff --git a/packages/moxxmpp/lib/src/handlers/client.dart b/packages/moxxmpp/lib/src/handlers/client.dart index 91ab099..a9b2f5f 100644 --- a/packages/moxxmpp/lib/src/handlers/client.dart +++ b/packages/moxxmpp/lib/src/handlers/client.dart @@ -60,6 +60,7 @@ class ClientToServerNegotiator extends NegotiationsHandler { @override void sendStreamHeader() { + resetStreamParser(); sendNonza( XMLNode( tag: 'xml', diff --git a/packages/moxxmpp/lib/src/handlers/component.dart b/packages/moxxmpp/lib/src/handlers/component.dart index 33360dc..d3c47d0 100644 --- a/packages/moxxmpp/lib/src/handlers/component.dart +++ b/packages/moxxmpp/lib/src/handlers/component.dart @@ -49,6 +49,7 @@ class ComponentToServerNegotiator extends NegotiationsHandler { @override void sendStreamHeader() { + resetStreamParser(); sendNonza( XMLNode( tag: 'xml', diff --git a/packages/moxxmpp/lib/src/managers/handlers.dart b/packages/moxxmpp/lib/src/managers/handlers.dart index ca7dea3..618ecb4 100644 --- a/packages/moxxmpp/lib/src/managers/handlers.dart +++ b/packages/moxxmpp/lib/src/managers/handlers.dart @@ -1,6 +1,5 @@ import 'package:moxlib/moxlib.dart'; import 'package:moxxmpp/src/managers/data.dart'; -import 'package:moxxmpp/src/namespaces.dart'; import 'package:moxxmpp/src/stanza.dart'; import 'package:moxxmpp/src/stringxml.dart'; @@ -56,9 +55,8 @@ class StanzaHandler extends Handler { this.tagName, this.priority = 0, this.stanzaTag, - this.xmlns = stanzaXmlns, }); - + /// If specified, then the stanza must contain a direct child with a tag equal to /// [tagName]. final String? tagName; @@ -71,11 +69,6 @@ class StanzaHandler extends Handler { /// If specified, the matching stanza must have a tag equal to [stanzaTag]. final String? stanzaTag; - /// If specified, then the stanza must have a xmlns attribute equal to [xmlns]. - /// This defaults to [stanzaXmlns], but can be set to any other value or null. This - /// is useful, for example, for components. - final String? xmlns; - /// The priority after which [StanzaHandler]s are sorted. final int priority; @@ -88,9 +81,11 @@ class StanzaHandler extends Handler { if (stanzaTag != null) { matches &= node.tag == stanzaTag; } - if (xmlns != null) { - matches &= node.xmlns == xmlns; - } + // if (xmlns != null) { + // matches &= node.xmlns == xmlns; + // if (flag != null) + // print('${node.xmlns} == $xmlns'); + // } if (tagName != null) { final firstTag = node.firstTag(tagName!, xmlns: tagXmlns); diff --git a/packages/moxxmpp/lib/src/parser.dart b/packages/moxxmpp/lib/src/parser.dart index 9292493..c5738cd 100644 --- a/packages/moxxmpp/lib/src/parser.dart +++ b/packages/moxxmpp/lib/src/parser.dart @@ -69,6 +69,12 @@ class XMPPStreamParser extends StreamTransformerBase { _ChunkedConversionBuffer, XmlNode> _childBuffer = _ChunkedConversionBuffer, XmlNode>(const XmlNodeDecoder()); + /// The selectors. + _ChunkedConversionBuffer, XmlEvent> _childSelector = + _ChunkedConversionBuffer, XmlEvent>(XmlSubtreeSelector((event) => event.qualifiedName != 'stream:stream')); + _ChunkedConversionBuffer, XmlEvent> _streamHeaderSelector = + _ChunkedConversionBuffer, XmlEvent>(XmlSubtreeSelector((event) => event.qualifiedName == 'stream:stream')); + void reset() { try { _eventBuffer.close(); @@ -81,6 +87,16 @@ class XMPPStreamParser extends StreamTransformerBase { } catch (_) { // Do nothing. } + try { + _childSelector.close(); + } catch (_) { + // Do nothing. + } + try { + _streamHeaderSelector.close(); + } catch (_) { + // Do nothing. + } // Recreate the buffers. _eventBuffer = @@ -88,6 +104,9 @@ class XMPPStreamParser extends StreamTransformerBase { _childBuffer = _ChunkedConversionBuffer, XmlNode>( const XmlNodeDecoder(), ); + _childSelector = _ChunkedConversionBuffer, XmlEvent>(XmlSubtreeSelector((event) => event.qualifiedName != 'stream:stream')); + _streamHeaderSelector = + _ChunkedConversionBuffer, XmlEvent>(XmlSubtreeSelector((event) => event.qualifiedName == 'stream:stream')); } @override @@ -95,14 +114,9 @@ class XMPPStreamParser extends StreamTransformerBase { // We do not want to use xml's toXmlEvents and toSubtreeEvents methods as they // create streams we cannot close. We need to be able to destroy and recreate an // XML parser whenever we start a new connection. - final childSelector = - XmlSubtreeSelector((event) => event.qualifiedName != 'stream:stream'); - final streamHeaderSelector = - XmlSubtreeSelector((event) => event.qualifiedName == 'stream:stream'); - stream.listen((input) { final events = _eventBuffer.convert(input); - final streamHeaderEvents = streamHeaderSelector.convert(events); + final streamHeaderEvents = _streamHeaderSelector.convert(events); // Process the stream header separately. for (final event in streamHeaderEvents) { @@ -126,7 +140,7 @@ class XMPPStreamParser extends StreamTransformerBase { } // Process the children of the element. - final childEvents = childSelector.convert(events); + final childEvents = _childSelector.convert(events); final children = _childBuffer.convert(childEvents); for (final node in children) { if (node.nodeType == XmlNodeType.ELEMENT) { diff --git a/packages/moxxmpp/lib/src/xeps/xep_0198/xep_0198.dart b/packages/moxxmpp/lib/src/xeps/xep_0198/xep_0198.dart index 55d2c06..6595833 100644 --- a/packages/moxxmpp/lib/src/xeps/xep_0198/xep_0198.dart +++ b/packages/moxxmpp/lib/src/xeps/xep_0198/xep_0198.dart @@ -255,7 +255,7 @@ class StreamManagementManager extends XmppManagerBase { _pendingAcks++; _startAckTimer(); - logger.fine('_pendingAcks is now at $_pendingAcks'); + logger.fine('_pendingAcks is now at $_pendingAcks (caused by )'); getAttributes().sendNonza(StreamManagementRequestNonza()); @@ -294,6 +294,7 @@ class StreamManagementManager extends XmppManagerBase { /// Called when we receive an nonza from the server. /// This is a response to the question "How many of my stanzas have you handled". Future _handleAckResponse(XMLNode nonza) async { + logger.finest('Received ack'); final h = int.parse(nonza.attributes['h']! as String); _lastAckTimestamp = DateTime.now().millisecondsSinceEpoch; @@ -306,6 +307,7 @@ class StreamManagementManager extends XmppManagerBase { // Reset the timer if (_pendingAcks > 0) { + _stopAckTimer(); _startAckTimer(); } } @@ -314,7 +316,7 @@ class StreamManagementManager extends XmppManagerBase { _stopAckTimer(); } - logger.fine('_pendingAcks is now at $_pendingAcks'); + logger.fine('_pendingAcks is now at $_pendingAcks (caused by )'); }); }); diff --git a/packages/moxxmpp/test/negotiator_test.dart b/packages/moxxmpp/test/negotiator_test.dart index 4323a1b..15de453 100644 --- a/packages/moxxmpp/test/negotiator_test.dart +++ b/packages/moxxmpp/test/negotiator_test.dart @@ -59,6 +59,7 @@ void main() { jid: JID.fromString('test'), password: 'abc123', ), + () {}, ) ..registerNegotiator(StubNegotiator1()) ..registerNegotiator(StubNegotiator2()); @@ -77,6 +78,7 @@ void main() { jid: JID.fromString('test'), password: 'abc123', ), + () {}, ) ..registerNegotiator(StubNegotiator1()) ..registerNegotiator(StubNegotiator2()); diff --git a/packages/moxxmpp/test/stanzahandler_test.dart b/packages/moxxmpp/test/stanzahandler_test.dart index 3c3bae8..61f4413 100644 --- a/packages/moxxmpp/test/stanzahandler_test.dart +++ b/packages/moxxmpp/test/stanzahandler_test.dart @@ -122,24 +122,23 @@ void main() { expect(handler.matches(stanza2), false); }); - test('Test matching stanzas with a different xmlns', () { - final handler = StanzaHandler( - callback: (stanza, _) async => StanzaHandlerData( - true, - false, - null, - stanza, - ), - xmlns: componentAcceptXmlns, - ); + // test('Test matching stanzas with a different xmlns', () { + // final handler = StanzaHandler( + // callback: (stanza, _) async => StanzaHandlerData( + // true, + // false, + // null, + // stanza, + // ), + // ); - expect(handler.matches(Stanza.iq(xmlns: stanzaXmlns)), false); - expect(handler.matches(Stanza.message(xmlns: stanzaXmlns)), false); - expect(handler.matches(Stanza.presence(xmlns: stanzaXmlns)), false); - expect(handler.matches(Stanza.iq(xmlns: componentAcceptXmlns)), true); - expect(handler.matches(stanza1), false); - expect(handler.matches(stanza2), false); - }); + // expect(handler.matches(Stanza.iq(xmlns: stanzaXmlns)), false); + // expect(handler.matches(Stanza.message(xmlns: stanzaXmlns)), false); + // expect(handler.matches(Stanza.presence(xmlns: stanzaXmlns)), false); + // expect(handler.matches(Stanza.iq(xmlns: componentAcceptXmlns)), true); + // expect(handler.matches(stanza1), false); + // expect(handler.matches(stanza2), false); + // }); test('sorting', () { final handlerList = [