diff --git a/packages/moxxmpp/CHANGELOG.md b/packages/moxxmpp/CHANGELOG.md index b05f0c2..8dc1b96 100644 --- a/packages/moxxmpp/CHANGELOG.md +++ b/packages/moxxmpp/CHANGELOG.md @@ -14,6 +14,7 @@ - **BREAKING**: `MessageManager.sendMessage` does not use `MessageDetails` anymore. Instead, use `TypedMap`. - `MessageManager` now allows registering callbacks for adding data whenever a message is sent. - **BREAKING**: `MessageEvent` now makes use of `TypedMap`. +- **BREAKING**: Removed `PresenceReceivedEvent`. Use a manager registering handlers with priority greater than `[PresenceManager.presenceHandlerPriority]` instead. ## 0.3.1 diff --git a/packages/moxxmpp/lib/src/events.dart b/packages/moxxmpp/lib/src/events.dart index 5a6c735..7b0e6c7 100644 --- a/packages/moxxmpp/lib/src/events.dart +++ b/packages/moxxmpp/lib/src/events.dart @@ -138,13 +138,6 @@ class ResourceBoundEvent extends XmppEvent { final String resource; } -/// Triggered when we receive presence -class PresenceReceivedEvent extends XmppEvent { - PresenceReceivedEvent(this.jid, this.presence); - final JID jid; - final Stanza presence; -} - /// Triggered when we are starting an connection attempt class ConnectingEvent extends XmppEvent {} diff --git a/packages/moxxmpp/lib/src/message.dart b/packages/moxxmpp/lib/src/message.dart index c528cd0..2e36b5c 100644 --- a/packages/moxxmpp/lib/src/message.dart +++ b/packages/moxxmpp/lib/src/message.dart @@ -46,6 +46,11 @@ class MessageIdData { class MessageManager extends XmppManagerBase { MessageManager() : super(messageManager); + /// The priority of the message handler. If a handler should run before this one, + /// which emits the [MessageEvent] event and terminates processing, make sure it + /// has a priority greater than [messageHandlerPriority]. + static int messageHandlerPriority = -100; + /// A list of callbacks that are called when a message is sent in order to add /// appropriate child elements. final List _messageSendingCallbacks = @@ -60,7 +65,7 @@ class MessageManager extends XmppManagerBase { StanzaHandler( stanzaTag: 'message', callback: _onMessage, - priority: -100, + priority: messageHandlerPriority, ) ]; diff --git a/packages/moxxmpp/lib/src/presence.dart b/packages/moxxmpp/lib/src/presence.dart index 41e1013..e8fb407 100644 --- a/packages/moxxmpp/lib/src/presence.dart +++ b/packages/moxxmpp/lib/src/presence.dart @@ -23,11 +23,17 @@ class PresenceManager extends XmppManagerBase { final List _presenceCallbacks = List.empty(growable: true); + /// The priority of the presence handler. If a handler should run before this one, + /// which terminates processing, make sure the handler has a priority greater than + /// [presenceHandlerPriority]. + static int presenceHandlerPriority = -100; + @override List getIncomingStanzaHandlers() => [ StanzaHandler( stanzaTag: 'presence', callback: _onPresence, + priority: presenceHandlerPriority, ) ]; @@ -75,9 +81,6 @@ class PresenceManager extends XmppManagerBase { if (presence.from != null) { logger.finest("Received presence from '${presence.from}'"); - getAttributes().sendEvent( - PresenceReceivedEvent(JID.fromString(presence.from!), presence), - ); return state..done = true; } diff --git a/packages/moxxmpp/lib/src/xeps/xep_0115.dart b/packages/moxxmpp/lib/src/xeps/xep_0115.dart index 75fefb3..ab6f2ea 100644 --- a/packages/moxxmpp/lib/src/xeps/xep_0115.dart +++ b/packages/moxxmpp/lib/src/xeps/xep_0115.dart @@ -4,10 +4,13 @@ import 'package:meta/meta.dart'; import 'package:moxxmpp/src/events.dart'; import 'package:moxxmpp/src/jid.dart'; import 'package:moxxmpp/src/managers/base.dart'; +import 'package:moxxmpp/src/managers/data.dart'; +import 'package:moxxmpp/src/managers/handlers.dart'; import 'package:moxxmpp/src/managers/namespaces.dart'; import 'package:moxxmpp/src/namespaces.dart'; import 'package:moxxmpp/src/presence.dart'; import 'package:moxxmpp/src/rfcs/rfc_4790.dart'; +import 'package:moxxmpp/src/stanza.dart'; import 'package:moxxmpp/src/stringxml.dart'; import 'package:moxxmpp/src/util/list.dart'; import 'package:moxxmpp/src/xeps/xep_0004.dart'; @@ -105,7 +108,20 @@ class EntityCapabilitiesManager extends XmppManagerBase { Future isSupported() async => true; @override - List getDiscoFeatures() => [capsXmlns]; + List getDiscoFeatures() => [ + capsXmlns, + ]; + + @override + List getIncomingStanzaHandlers() => [ + StanzaHandler( + stanzaTag: 'presence', + tagName: 'c', + tagXmlns: capsXmlns, + callback: onPresence, + priority: PresenceManager.presenceHandlerPriority + 1, + ), + ]; /// Computes, if required, the capability hash of the data provided by /// the DiscoManager. @@ -159,33 +175,38 @@ class EntityCapabilitiesManager extends XmppManagerBase { } @visibleForTesting - Future onPresence(PresenceReceivedEvent event) async { - final c = event.presence.firstTag('c', xmlns: capsXmlns); - if (c == null) { - return; + Future onPresence( + Stanza stanza, + StanzaHandlerData state, + ) async { + if (stanza.from == null) { + return state; } + final from = JID.fromString(stanza.from!); + final c = stanza.firstTag('c', xmlns: capsXmlns)!; + final hashFunctionName = c.attributes['hash'] as String?; final capabilityNode = c.attributes['node'] as String?; final ver = c.attributes['ver'] as String?; if (hashFunctionName == null || capabilityNode == null || ver == null) { - return; + return state; } // Check if we know of the hash final isCached = await _cacheLock.synchronized(() => _capHashCache.containsKey(ver)); if (isCached) { - return; + return state; } final dm = getAttributes().getManagerById(discoManager)!; final discoRequest = await dm.discoInfoQuery( - event.jid, + from, node: capabilityNode, ); if (discoRequest.isType()) { - return; + return state; } final discoInfo = discoRequest.get(); @@ -194,13 +215,13 @@ class EntityCapabilitiesManager extends XmppManagerBase { await dm.addCachedDiscoInfo( MapEntry( DiscoCacheKey( - event.jid, + from, null, ), discoInfo, ), ); - return; + return state; } // Validate the disco#info result according to XEP-0115 ยง 5.4 @@ -214,7 +235,7 @@ class EntityCapabilitiesManager extends XmppManagerBase { logger.warning( 'Malformed disco#info response: More than one equal identity', ); - return; + return state; } } @@ -225,7 +246,7 @@ class EntityCapabilitiesManager extends XmppManagerBase { logger.warning( 'Malformed disco#info response: More than one equal feature', ); - return; + return state; } } @@ -253,7 +274,7 @@ class EntityCapabilitiesManager extends XmppManagerBase { logger.warning( 'Malformed disco#info response: Extended Info FORM_TYPE contains more than one value(s) of different value.', ); - return; + return state; } } @@ -268,7 +289,7 @@ class EntityCapabilitiesManager extends XmppManagerBase { logger.warning( 'Malformed disco#info response: More than one Extended Disco Info forms with the same FORM_TYPE value', ); - return; + return state; } // Check if the field type is hidden @@ -297,14 +318,16 @@ class EntityCapabilitiesManager extends XmppManagerBase { if (computedCapabilityHash == ver) { await _cacheLock.synchronized(() { - _jidToCapHashCache[event.jid.toString()] = ver; + _jidToCapHashCache[from.toString()] = ver; _capHashCache[ver] = newDiscoInfo; }); } else { logger.warning( - 'Capability hash mismatch from ${event.jid}: Received "$ver", expected "$computedCapabilityHash".', + 'Capability hash mismatch from $from: Received "$ver", expected "$computedCapabilityHash".', ); } + + return state; } @visibleForTesting @@ -315,9 +338,7 @@ class EntityCapabilitiesManager extends XmppManagerBase { @override Future onXmppEvent(XmppEvent event) async { - if (event is PresenceReceivedEvent) { - unawaited(onPresence(event)); - } else if (event is StreamNegotiationsDoneEvent) { + if (event is StreamNegotiationsDoneEvent) { // Clear the JID to cap. hash mapping. await _cacheLock.synchronized(_jidToCapHashCache.clear); } diff --git a/packages/moxxmpp/test/xeps/xep_0115_test.dart b/packages/moxxmpp/test/xeps/xep_0115_test.dart index 3daf321..f4c45ae 100644 --- a/packages/moxxmpp/test/xeps/xep_0115_test.dart +++ b/packages/moxxmpp/test/xeps/xep_0115_test.dart @@ -1,4 +1,5 @@ import 'package:moxxmpp/moxxmpp.dart'; +import 'package:moxxmpp/src/util/typed_map.dart'; import 'package:test/test.dart'; import '../helpers/logging.dart'; @@ -324,24 +325,23 @@ void main() { manager, ]); - await manager.onPresence( - PresenceReceivedEvent( - aliceJid, - Stanza.presence( - from: aliceJid.toString(), - children: [ - XMLNode.xmlns( - tag: 'c', - xmlns: capsXmlns, - attributes: { - 'hash': 'sha-1', - 'node': 'http://example.org/client', - 'ver': 'QgayPKawpkPSDYmwT/WM94uAlu0=', - }, - ), - ], + final stanza = Stanza.presence( + from: aliceJid.toString(), + children: [ + XMLNode.xmlns( + tag: 'c', + xmlns: capsXmlns, + attributes: { + 'hash': 'sha-1', + 'node': 'http://example.org/client', + 'ver': 'QgayPKawpkPSDYmwT/WM94uAlu0=', + }, ), - ), + ], + ); + await manager.onPresence( + stanza, + StanzaHandlerData(false, false, stanza, TypedMap()), ); expect( @@ -359,24 +359,23 @@ void main() { manager, ]); - await manager.onPresence( - PresenceReceivedEvent( - aliceJid, - Stanza.presence( - from: aliceJid.toString(), - children: [ - XMLNode.xmlns( - tag: 'c', - xmlns: capsXmlns, - attributes: { - 'hash': 'sha-1', - 'node': 'http://example.org/client', - 'ver': 'QgayPKawpkPSDYmwT/WM94AAAAA=', - }, - ), - ], + final stanza = Stanza.presence( + from: aliceJid.toString(), + children: [ + XMLNode.xmlns( + tag: 'c', + xmlns: capsXmlns, + attributes: { + 'hash': 'sha-1', + 'node': 'http://example.org/client', + 'ver': 'QgayPKawpkPSDYmwT/WM94AAAAA=', + }, ), - ), + ], + ); + await manager.onPresence( + stanza, + StanzaHandlerData(false, false, stanza, TypedMap()), ); expect( @@ -394,24 +393,23 @@ void main() { manager, ]); - await manager.onPresence( - PresenceReceivedEvent( - aliceJid, - Stanza.presence( - from: aliceJid.toString(), - children: [ - XMLNode.xmlns( - tag: 'c', - xmlns: capsXmlns, - attributes: { - 'hash': 'sha-1', - 'node': 'http://example.org/client', - 'ver': 'QgayPKawpkPSDYmwT/WM94uAlu0=', - }, - ), - ], + final stanza = Stanza.presence( + from: aliceJid.toString(), + children: [ + XMLNode.xmlns( + tag: 'c', + xmlns: capsXmlns, + attributes: { + 'hash': 'sha-1', + 'node': 'http://example.org/client', + 'ver': 'QgayPKawpkPSDYmwT/WM94uAlu0=', + }, ), - ), + ], + ); + await manager.onPresence( + stanza, + StanzaHandlerData(false, false, stanza, TypedMap()), ); expect( @@ -429,24 +427,23 @@ void main() { manager, ]); - await manager.onPresence( - PresenceReceivedEvent( - aliceJid, - Stanza.presence( - from: aliceJid.toString(), - children: [ - XMLNode.xmlns( - tag: 'c', - xmlns: capsXmlns, - attributes: { - 'hash': 'sha-1', - 'node': 'http://example.org/client', - 'ver': 'QgayPKawpkPSDYmwT/WM94uAlu0=', - }, - ), - ], + final stanza = Stanza.presence( + from: aliceJid.toString(), + children: [ + XMLNode.xmlns( + tag: 'c', + xmlns: capsXmlns, + attributes: { + 'hash': 'sha-1', + 'node': 'http://example.org/client', + 'ver': 'QgayPKawpkPSDYmwT/WM94uAlu0=', + }, ), - ), + ], + ); + await manager.onPresence( + stanza, + StanzaHandlerData(false, false, stanza, TypedMap()), ); expect( @@ -464,24 +461,23 @@ void main() { manager, ]); - await manager.onPresence( - PresenceReceivedEvent( - aliceJid, - Stanza.presence( - from: aliceJid.toString(), - children: [ - XMLNode.xmlns( - tag: 'c', - xmlns: capsXmlns, - attributes: { - 'hash': 'sha-1', - 'node': 'http://example.org/client', - 'ver': 'QgayPKawpkPSDYmwT/WM94uAlu0=', - }, - ), - ], + final stanza = Stanza.presence( + from: aliceJid.toString(), + children: [ + XMLNode.xmlns( + tag: 'c', + xmlns: capsXmlns, + attributes: { + 'hash': 'sha-1', + 'node': 'http://example.org/client', + 'ver': 'QgayPKawpkPSDYmwT/WM94uAlu0=', + }, ), - ), + ], + ); + await manager.onPresence( + stanza, + StanzaHandlerData(false, false, stanza, TypedMap()), ); expect( @@ -499,24 +495,23 @@ void main() { manager, ]); - await manager.onPresence( - PresenceReceivedEvent( - aliceJid, - Stanza.presence( - from: aliceJid.toString(), - children: [ - XMLNode.xmlns( - tag: 'c', - xmlns: capsXmlns, - attributes: { - 'hash': 'sha-1', - 'node': 'http://example.org/client', - 'ver': 'QgayPKawpkPSDYmwT/WM94uAlu0=', - }, - ), - ], + final stanza = Stanza.presence( + from: aliceJid.toString(), + children: [ + XMLNode.xmlns( + tag: 'c', + xmlns: capsXmlns, + attributes: { + 'hash': 'sha-1', + 'node': 'http://example.org/client', + 'ver': 'QgayPKawpkPSDYmwT/WM94uAlu0=', + }, ), - ), + ], + ); + await manager.onPresence( + stanza, + StanzaHandlerData(false, false, stanza, TypedMap()), ); final cachedItem = await manager.getCachedDiscoInfoFromJid(aliceJid); @@ -536,24 +531,23 @@ void main() { manager, ]); - await manager.onPresence( - PresenceReceivedEvent( - aliceJid, - Stanza.presence( - from: aliceJid.toString(), - children: [ - XMLNode.xmlns( - tag: 'c', - xmlns: capsXmlns, - attributes: { - 'hash': 'sha-1', - 'node': 'http://example.org/client', - 'ver': 'QgayPKawpkPSDYmwT/WM94uAlu0=', - }, - ), - ], + final stanza = Stanza.presence( + from: aliceJid.toString(), + children: [ + XMLNode.xmlns( + tag: 'c', + xmlns: capsXmlns, + attributes: { + 'hash': 'sha-1', + 'node': 'http://example.org/client', + 'ver': 'QgayPKawpkPSDYmwT/WM94uAlu0=', + }, ), - ), + ], + ); + await manager.onPresence( + stanza, + StanzaHandlerData(false, false, stanza, TypedMap()), ); final cachedItem = await manager.getCachedDiscoInfoFromJid(aliceJid); @@ -573,24 +567,23 @@ void main() { manager, ]); - await manager.onPresence( - PresenceReceivedEvent( - aliceJid, - Stanza.presence( - from: aliceJid.toString(), - children: [ - XMLNode.xmlns( - tag: 'c', - xmlns: capsXmlns, - attributes: { - 'hash': 'sha-1', - 'node': 'http://example.org/client', - 'ver': 'QgayPKawpkPSDYmwT/WM94uAlu0=', - }, - ), - ], + final stanza = Stanza.presence( + from: aliceJid.toString(), + children: [ + XMLNode.xmlns( + tag: 'c', + xmlns: capsXmlns, + attributes: { + 'hash': 'sha-1', + 'node': 'http://example.org/client', + 'ver': 'QgayPKawpkPSDYmwT/WM94uAlu0=', + }, ), - ), + ], + ); + await manager.onPresence( + stanza, + StanzaHandlerData(false, false, stanza, TypedMap()), ); expect(