feat(xep): Also potentially return "generic" stanza errors
This commit is contained in:
parent
77a1acb0e7
commit
a928c5c877
@ -17,6 +17,7 @@
|
|||||||
- **BREAKING**: Removed `PresenceReceivedEvent`. Use a manager registering handlers with priority greater than `[PresenceManager.presenceHandlerPriority]` instead.
|
- **BREAKING**: Removed `PresenceReceivedEvent`. Use a manager registering handlers with priority greater than `[PresenceManager.presenceHandlerPriority]` instead.
|
||||||
- **BREAKING**: `ChatState.toString()` is now `ChatState.toName()`
|
- **BREAKING**: `ChatState.toString()` is now `ChatState.toName()`
|
||||||
- **BREAKING**: Overriding `BaseOmemoManager` is no longer required. `OmemoManager` now takes callback methods instead.
|
- **BREAKING**: Overriding `BaseOmemoManager` is no longer required. `OmemoManager` now takes callback methods instead.
|
||||||
|
- Removed `ErrorResponseDiscoError` from the possible XEP-0030 errors.
|
||||||
|
|
||||||
## 0.3.1
|
## 0.3.1
|
||||||
|
|
||||||
|
@ -47,28 +47,57 @@ class StanzaDetails {
|
|||||||
final TypedMap<StanzaHandlerExtension>? postSendExtensions;
|
final TypedMap<StanzaHandlerExtension>? postSendExtensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A simple description of the <error /> element that may be inside a stanza
|
/// A general error type for errors.
|
||||||
class StanzaError {
|
abstract class StanzaError {
|
||||||
StanzaError(this.type, this.error);
|
static StanzaError? fromXMLNode(XMLNode node) {
|
||||||
String type;
|
final error = node.firstTag('error');
|
||||||
String 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 <error /> element. If not, returns
|
|
||||||
/// null.
|
|
||||||
static StanzaError? fromStanza(Stanza stanza) {
|
static StanzaError? fromStanza(Stanza stanza) {
|
||||||
final error = stanza.firstTag('error');
|
return fromXMLNode(stanza);
|
||||||
if (error == null) return null;
|
|
||||||
|
|
||||||
final stanzaError = error.firstTagByXmlns(fullStanzaXmlns);
|
|
||||||
if (stanzaError == null) return null;
|
|
||||||
|
|
||||||
return StanzaError(
|
|
||||||
error.attributes['type']! as String,
|
|
||||||
stanzaError.tag,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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 {
|
class Stanza extends XMLNode {
|
||||||
// ignore: use_super_parameters
|
// ignore: use_super_parameters
|
||||||
Stanza({
|
Stanza({
|
||||||
|
@ -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 {}
|
class UnknownDiscoError extends DiscoError {}
|
||||||
|
|
||||||
|
/// The received disco response is invalid in some shape or form.
|
||||||
class InvalidResponseDiscoError extends DiscoError {}
|
class InvalidResponseDiscoError extends DiscoError {}
|
||||||
|
|
||||||
class ErrorResponseDiscoError extends DiscoError {}
|
|
||||||
|
@ -44,11 +44,11 @@ class DiscoManager extends XmppManagerBase {
|
|||||||
final Map<DiscoCacheKey, DiscoInfo> _discoInfoCache = {};
|
final Map<DiscoCacheKey, DiscoInfo> _discoInfoCache = {};
|
||||||
|
|
||||||
/// The tracker for tracking disco#info queries that are in flight.
|
/// The tracker for tracking disco#info queries that are in flight.
|
||||||
final WaitForTracker<DiscoCacheKey, Result<DiscoError, DiscoInfo>>
|
final WaitForTracker<DiscoCacheKey, Result<StanzaError, DiscoInfo>>
|
||||||
_discoInfoTracker = WaitForTracker();
|
_discoInfoTracker = WaitForTracker();
|
||||||
|
|
||||||
/// The tracker for tracking disco#info queries that are in flight.
|
/// The tracker for tracking disco#info queries that are in flight.
|
||||||
final WaitForTracker<DiscoCacheKey, Result<DiscoError, List<DiscoItem>>>
|
final WaitForTracker<DiscoCacheKey, Result<StanzaError, List<DiscoItem>>>
|
||||||
_discoItemsTracker = WaitForTracker();
|
_discoItemsTracker = WaitForTracker();
|
||||||
|
|
||||||
/// Cache lock
|
/// Cache lock
|
||||||
@ -67,7 +67,7 @@ class DiscoManager extends XmppManagerBase {
|
|||||||
List<String> get features => _features;
|
List<String> get features => _features;
|
||||||
|
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
WaitForTracker<DiscoCacheKey, Result<DiscoError, DiscoInfo>>
|
WaitForTracker<DiscoCacheKey, Result<StanzaError, DiscoInfo>>
|
||||||
get infoTracker => _discoInfoTracker;
|
get infoTracker => _discoInfoTracker;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -231,7 +231,7 @@ class DiscoManager extends XmppManagerBase {
|
|||||||
|
|
||||||
Future<void> _exitDiscoInfoCriticalSection(
|
Future<void> _exitDiscoInfoCriticalSection(
|
||||||
DiscoCacheKey key,
|
DiscoCacheKey key,
|
||||||
Result<DiscoError, DiscoInfo> result,
|
Result<StanzaError, DiscoInfo> result,
|
||||||
bool shouldCache,
|
bool shouldCache,
|
||||||
) async {
|
) async {
|
||||||
await _cacheLock.synchronized(() async {
|
await _cacheLock.synchronized(() async {
|
||||||
@ -252,7 +252,7 @@ class DiscoManager extends XmppManagerBase {
|
|||||||
///
|
///
|
||||||
/// [shouldCache] indicates whether the successful result of the disco#info query
|
/// [shouldCache] indicates whether the successful result of the disco#info query
|
||||||
/// should be cached (true) or not(false).
|
/// should be cached (true) or not(false).
|
||||||
Future<Result<DiscoError, DiscoInfo>> discoInfoQuery(
|
Future<Result<StanzaError, DiscoInfo>> discoInfoQuery(
|
||||||
JID entity, {
|
JID entity, {
|
||||||
String? node,
|
String? node,
|
||||||
bool shouldEncrypt = false,
|
bool shouldEncrypt = false,
|
||||||
@ -263,7 +263,7 @@ class DiscoManager extends XmppManagerBase {
|
|||||||
final ecm = getAttributes()
|
final ecm = getAttributes()
|
||||||
.getManagerById<EntityCapabilitiesManager>(entityCapabilitiesManager);
|
.getManagerById<EntityCapabilitiesManager>(entityCapabilitiesManager);
|
||||||
final ffuture = await _cacheLock
|
final ffuture = await _cacheLock
|
||||||
.synchronized<Future<Future<Result<DiscoError, DiscoInfo>>?>?>(
|
.synchronized<Future<Future<Result<StanzaError, DiscoInfo>>?>?>(
|
||||||
() async {
|
() async {
|
||||||
// Check if we already know what the JID supports
|
// Check if we already know what the JID supports
|
||||||
if (_discoInfoCache.containsKey(cacheKey)) {
|
if (_discoInfoCache.containsKey(cacheKey)) {
|
||||||
@ -297,16 +297,18 @@ class DiscoManager extends XmppManagerBase {
|
|||||||
shouldEncrypt: shouldEncrypt,
|
shouldEncrypt: shouldEncrypt,
|
||||||
),
|
),
|
||||||
))!;
|
))!;
|
||||||
final query = stanza.firstTag('query');
|
|
||||||
if (query == null) {
|
// Error handling
|
||||||
final result = Result<DiscoError, DiscoInfo>(InvalidResponseDiscoError());
|
if (stanza.attributes['type'] == 'error') {
|
||||||
|
final result =
|
||||||
|
Result<StanzaError, DiscoInfo>(StanzaError.fromXMLNode(stanza));
|
||||||
await _exitDiscoInfoCriticalSection(cacheKey, result, shouldCache);
|
await _exitDiscoInfoCriticalSection(cacheKey, result, shouldCache);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stanza.attributes['type'] == 'error') {
|
final query = stanza.firstTag('query');
|
||||||
//final error = stanza.firstTag('error');
|
if (query == null) {
|
||||||
final result = Result<DiscoError, DiscoInfo>(ErrorResponseDiscoError());
|
final result = Result<DiscoError, DiscoInfo>(InvalidResponseDiscoError());
|
||||||
await _exitDiscoInfoCriticalSection(cacheKey, result, shouldCache);
|
await _exitDiscoInfoCriticalSection(cacheKey, result, shouldCache);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -322,7 +324,7 @@ class DiscoManager extends XmppManagerBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sends a disco items query to the (full) jid [entity], optionally with node=[node].
|
/// Sends a disco items query to the (full) jid [entity], optionally with node=[node].
|
||||||
Future<Result<DiscoError, List<DiscoItem>>> discoItemsQuery(
|
Future<Result<StanzaError, List<DiscoItem>>> discoItemsQuery(
|
||||||
JID entity, {
|
JID entity, {
|
||||||
String? node,
|
String? node,
|
||||||
bool shouldEncrypt = false,
|
bool shouldEncrypt = false,
|
||||||
@ -340,19 +342,18 @@ class DiscoManager extends XmppManagerBase {
|
|||||||
),
|
),
|
||||||
))!;
|
))!;
|
||||||
|
|
||||||
final query = stanza.firstTag('query');
|
// Error handling
|
||||||
if (query == null) {
|
if (stanza.attributes['type'] == 'error') {
|
||||||
final result =
|
final result =
|
||||||
Result<DiscoError, List<DiscoItem>>(InvalidResponseDiscoError());
|
Result<StanzaError, List<DiscoItem>>(StanzaError.fromXMLNode(stanza));
|
||||||
await _discoItemsTracker.resolve(key, result);
|
await _discoItemsTracker.resolve(key, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stanza.attributes['type'] == 'error') {
|
final query = stanza.firstTag('query');
|
||||||
//final error = stanza.firstTag('error');
|
if (query == null) {
|
||||||
//print("Disco Items error: " + error.toXml());
|
|
||||||
final result =
|
final result =
|
||||||
Result<DiscoError, List<DiscoItem>>(ErrorResponseDiscoError());
|
Result<DiscoError, List<DiscoItem>>(InvalidResponseDiscoError());
|
||||||
await _discoItemsTracker.resolve(key, result);
|
await _discoItemsTracker.resolve(key, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -419,7 +420,7 @@ class DiscoManager extends XmppManagerBase {
|
|||||||
/// [entity] supports the disco feature [feature]. If not, returns false.
|
/// [entity] supports the disco feature [feature]. If not, returns false.
|
||||||
Future<bool> supportsFeature(JID entity, String feature) async {
|
Future<bool> supportsFeature(JID entity, String feature) async {
|
||||||
final info = await discoInfoQuery(entity);
|
final info = await discoInfoQuery(entity);
|
||||||
if (info.isType<DiscoError>()) return false;
|
if (info.isType<StanzaError>()) return false;
|
||||||
|
|
||||||
return info.get<DiscoInfo>().features.contains(feature);
|
return info.get<DiscoInfo>().features.contains(feature);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user