From a928c5c877cec46e19a074e8afe46bbfb9a925a1 Mon Sep 17 00:00:00 2001 From: "Alexander \"PapaTutuWawa" Date: Thu, 29 Jun 2023 21:12:30 +0200 Subject: [PATCH] feat(xep): Also potentially return "generic" stanza errors --- packages/moxxmpp/CHANGELOG.md | 1 + packages/moxxmpp/lib/src/stanza.dart | 63 ++++++++++++++----- .../moxxmpp/lib/src/xeps/xep_0030/errors.dart | 9 ++- .../lib/src/xeps/xep_0030/xep_0030.dart | 43 ++++++------- 4 files changed, 75 insertions(+), 41 deletions(-) diff --git a/packages/moxxmpp/CHANGELOG.md b/packages/moxxmpp/CHANGELOG.md index 3960a67..f653e13 100644 --- a/packages/moxxmpp/CHANGELOG.md +++ b/packages/moxxmpp/CHANGELOG.md @@ -17,6 +17,7 @@ - **BREAKING**: Removed `PresenceReceivedEvent`. Use a manager registering handlers with priority greater than `[PresenceManager.presenceHandlerPriority]` instead. - **BREAKING**: `ChatState.toString()` is now `ChatState.toName()` - **BREAKING**: Overriding `BaseOmemoManager` is no longer required. `OmemoManager` now takes callback methods instead. +- Removed `ErrorResponseDiscoError` from the possible XEP-0030 errors. ## 0.3.1 diff --git a/packages/moxxmpp/lib/src/stanza.dart b/packages/moxxmpp/lib/src/stanza.dart index b7424b3..2e5804b 100644 --- a/packages/moxxmpp/lib/src/stanza.dart +++ b/packages/moxxmpp/lib/src/stanza.dart @@ -47,28 +47,57 @@ class StanzaDetails { final TypedMap? postSendExtensions; } -/// A simple description of the element that may be inside a stanza -class StanzaError { - StanzaError(this.type, this.error); - String type; - String error; +/// A general error type for errors. +abstract class StanzaError { + static StanzaError? fromXMLNode(XMLNode node) { + final error = node.firstTag('error'); + if (error == null) { + return null; + } + + final specificError = error.firstTagByXmlns(fullStanzaXmlns); + if (specificError == null) { + return UnknownStanzaError(); + } + + switch (specificError.tag) { + case RemoteServerNotFoundError.tag: + return RemoteServerNotFoundError(); + case RemoteServerTimeoutError.tag: + return RemoteServerTimeoutError(); + case ServiceUnavailableError.tag: + return ServiceUnavailableError(); + } + + return UnknownStanzaError(); + } - /// Returns a StanzaError if [stanza] contains a element. If not, returns - /// null. static StanzaError? fromStanza(Stanza stanza) { - final error = stanza.firstTag('error'); - if (error == null) return null; - - final stanzaError = error.firstTagByXmlns(fullStanzaXmlns); - if (stanzaError == null) return null; - - return StanzaError( - error.attributes['type']! as String, - stanzaError.tag, - ); + return fromXMLNode(stanza); } } +/// Recipient does not provide a given service. +/// https://xmpp.org/rfcs/rfc6120.html#stanzas-error-conditions-service-unavailable +class ServiceUnavailableError extends StanzaError { + static const tag = 'service-unavailable'; +} + +/// Could not connect to the remote server. +/// https://xmpp.org/rfcs/rfc6120.html#stanzas-error-conditions-remote-server-not-found +class RemoteServerNotFoundError extends StanzaError { + static const tag = 'remote-server-not-found'; +} + +/// The connection to the remote server timed out. +/// https://xmpp.org/rfcs/rfc6120.html#stanzas-error-conditions-remote-server-timeout +class RemoteServerTimeoutError extends StanzaError { + static const tag = 'remote-server-timeout'; +} + +/// An unknown error. +class UnknownStanzaError extends StanzaError {} + class Stanza extends XMLNode { // ignore: use_super_parameters Stanza({ diff --git a/packages/moxxmpp/lib/src/xeps/xep_0030/errors.dart b/packages/moxxmpp/lib/src/xeps/xep_0030/errors.dart index f11717d..bab7e09 100644 --- a/packages/moxxmpp/lib/src/xeps/xep_0030/errors.dart +++ b/packages/moxxmpp/lib/src/xeps/xep_0030/errors.dart @@ -1,7 +1,10 @@ -abstract class DiscoError {} +import 'package:moxxmpp/src/stanza.dart'; +/// Base type for disco-related errors. +abstract class DiscoError extends StanzaError {} + +/// An unspecified error that is not covered by another [DiscoError]. class UnknownDiscoError extends DiscoError {} +/// The received disco response is invalid in some shape or form. class InvalidResponseDiscoError extends DiscoError {} - -class ErrorResponseDiscoError extends DiscoError {} diff --git a/packages/moxxmpp/lib/src/xeps/xep_0030/xep_0030.dart b/packages/moxxmpp/lib/src/xeps/xep_0030/xep_0030.dart index 09443d2..96a854e 100644 --- a/packages/moxxmpp/lib/src/xeps/xep_0030/xep_0030.dart +++ b/packages/moxxmpp/lib/src/xeps/xep_0030/xep_0030.dart @@ -44,11 +44,11 @@ class DiscoManager extends XmppManagerBase { final Map _discoInfoCache = {}; /// The tracker for tracking disco#info queries that are in flight. - final WaitForTracker> + final WaitForTracker> _discoInfoTracker = WaitForTracker(); /// The tracker for tracking disco#info queries that are in flight. - final WaitForTracker>> + final WaitForTracker>> _discoItemsTracker = WaitForTracker(); /// Cache lock @@ -67,7 +67,7 @@ class DiscoManager extends XmppManagerBase { List get features => _features; @visibleForTesting - WaitForTracker> + WaitForTracker> get infoTracker => _discoInfoTracker; @override @@ -231,7 +231,7 @@ class DiscoManager extends XmppManagerBase { Future _exitDiscoInfoCriticalSection( DiscoCacheKey key, - Result result, + Result result, bool shouldCache, ) async { await _cacheLock.synchronized(() async { @@ -252,7 +252,7 @@ class DiscoManager extends XmppManagerBase { /// /// [shouldCache] indicates whether the successful result of the disco#info query /// should be cached (true) or not(false). - Future> discoInfoQuery( + Future> discoInfoQuery( JID entity, { String? node, bool shouldEncrypt = false, @@ -263,7 +263,7 @@ class DiscoManager extends XmppManagerBase { final ecm = getAttributes() .getManagerById(entityCapabilitiesManager); final ffuture = await _cacheLock - .synchronized>?>?>( + .synchronized>?>?>( () async { // Check if we already know what the JID supports if (_discoInfoCache.containsKey(cacheKey)) { @@ -297,16 +297,18 @@ class DiscoManager extends XmppManagerBase { shouldEncrypt: shouldEncrypt, ), ))!; - final query = stanza.firstTag('query'); - if (query == null) { - final result = Result(InvalidResponseDiscoError()); + + // Error handling + if (stanza.attributes['type'] == 'error') { + final result = + Result(StanzaError.fromXMLNode(stanza)); await _exitDiscoInfoCriticalSection(cacheKey, result, shouldCache); return result; } - if (stanza.attributes['type'] == 'error') { - //final error = stanza.firstTag('error'); - final result = Result(ErrorResponseDiscoError()); + final query = stanza.firstTag('query'); + if (query == null) { + final result = Result(InvalidResponseDiscoError()); await _exitDiscoInfoCriticalSection(cacheKey, result, shouldCache); return result; } @@ -322,7 +324,7 @@ class DiscoManager extends XmppManagerBase { } /// Sends a disco items query to the (full) jid [entity], optionally with node=[node]. - Future>> discoItemsQuery( + Future>> discoItemsQuery( JID entity, { String? node, bool shouldEncrypt = false, @@ -340,19 +342,18 @@ class DiscoManager extends XmppManagerBase { ), ))!; - final query = stanza.firstTag('query'); - if (query == null) { + // Error handling + if (stanza.attributes['type'] == 'error') { final result = - Result>(InvalidResponseDiscoError()); + Result>(StanzaError.fromXMLNode(stanza)); await _discoItemsTracker.resolve(key, result); return result; } - if (stanza.attributes['type'] == 'error') { - //final error = stanza.firstTag('error'); - //print("Disco Items error: " + error.toXml()); + final query = stanza.firstTag('query'); + if (query == null) { final result = - Result>(ErrorResponseDiscoError()); + Result>(InvalidResponseDiscoError()); await _discoItemsTracker.resolve(key, result); return result; } @@ -419,7 +420,7 @@ class DiscoManager extends XmppManagerBase { /// [entity] supports the disco feature [feature]. If not, returns false. Future supportsFeature(JID entity, String feature) async { final info = await discoInfoQuery(entity); - if (info.isType()) return false; + if (info.isType()) return false; return info.get().features.contains(feature); }