Compare commits
2 Commits
7e588f01b0
...
6da3342f22
Author | SHA1 | Date | |
---|---|---|---|
6da3342f22 | |||
47337540f5 |
@ -226,7 +226,7 @@ class XmppConnection {
|
|||||||
/// Registers a list of [XmppManagerBase] sub-classes as managers on this connection.
|
/// Registers a list of [XmppManagerBase] sub-classes as managers on this connection.
|
||||||
Future<void> registerManagers(List<XmppManagerBase> managers) async {
|
Future<void> registerManagers(List<XmppManagerBase> managers) async {
|
||||||
for (final manager in managers) {
|
for (final manager in managers) {
|
||||||
_log.finest('Registering ${manager.getId()}');
|
_log.finest('Registering ${manager.id}');
|
||||||
manager.register(
|
manager.register(
|
||||||
XmppManagerAttributes(
|
XmppManagerAttributes(
|
||||||
sendStanza: sendStanza,
|
sendStanza: sendStanza,
|
||||||
@ -242,8 +242,7 @@ class XmppConnection {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
final id = manager.getId();
|
_xmppManagers[manager.id] = manager;
|
||||||
_xmppManagers[id] = manager;
|
|
||||||
|
|
||||||
_incomingStanzaHandlers.addAll(manager.getIncomingStanzaHandlers());
|
_incomingStanzaHandlers.addAll(manager.getIncomingStanzaHandlers());
|
||||||
_incomingPreStanzaHandlers.addAll(manager.getIncomingPreStanzaHandlers());
|
_incomingPreStanzaHandlers.addAll(manager.getIncomingPreStanzaHandlers());
|
||||||
@ -260,7 +259,7 @@ class XmppConnection {
|
|||||||
// Run the post register callbacks
|
// Run the post register callbacks
|
||||||
for (final manager in _xmppManagers.values) {
|
for (final manager in _xmppManagers.values) {
|
||||||
if (!manager.initialized) {
|
if (!manager.initialized) {
|
||||||
_log.finest('Running post-registration callback for ${manager.getName()}');
|
_log.finest('Running post-registration callback for ${manager.name}');
|
||||||
await manager.postRegisterCallback();
|
await manager.postRegisterCallback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@ import 'package:moxxmpp/src/xeps/xep_0030/types.dart';
|
|||||||
import 'package:moxxmpp/src/xeps/xep_0030/xep_0030.dart';
|
import 'package:moxxmpp/src/xeps/xep_0030/xep_0030.dart';
|
||||||
|
|
||||||
abstract class XmppManagerBase {
|
abstract class XmppManagerBase {
|
||||||
|
XmppManagerBase(this.id);
|
||||||
|
|
||||||
late final XmppManagerAttributes _managerAttributes;
|
late final XmppManagerAttributes _managerAttributes;
|
||||||
late final Logger _log;
|
late final Logger _log;
|
||||||
|
|
||||||
@ -19,7 +21,7 @@ abstract class XmppManagerBase {
|
|||||||
/// Registers the callbacks from XmppConnection with the manager
|
/// Registers the callbacks from XmppConnection with the manager
|
||||||
void register(XmppManagerAttributes attributes) {
|
void register(XmppManagerAttributes attributes) {
|
||||||
_managerAttributes = attributes;
|
_managerAttributes = attributes;
|
||||||
_log = Logger(getName());
|
_log = Logger(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the attributes that are registered with the manager.
|
/// Returns the attributes that are registered with the manager.
|
||||||
@ -60,10 +62,10 @@ abstract class XmppManagerBase {
|
|||||||
List<Identity> getDiscoIdentities() => [];
|
List<Identity> getDiscoIdentities() => [];
|
||||||
|
|
||||||
/// Return the Id (akin to xmlns) of this manager.
|
/// Return the Id (akin to xmlns) of this manager.
|
||||||
String getId();
|
final String id;
|
||||||
|
|
||||||
/// Return a name that will be used for logging.
|
/// The name of the manager.
|
||||||
String getName();
|
String get name => toString();
|
||||||
|
|
||||||
/// Return the logger for this manager.
|
/// Return the logger for this manager.
|
||||||
Logger get logger => _log;
|
Logger get logger => _log;
|
||||||
|
@ -76,11 +76,7 @@ class MessageDetails {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MessageManager extends XmppManagerBase {
|
class MessageManager extends XmppManagerBase {
|
||||||
@override
|
MessageManager() : super(messageManager);
|
||||||
String getId() => messageManager;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getName() => 'MessageManager';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||||
|
@ -4,11 +4,7 @@ import 'package:moxxmpp/src/managers/namespaces.dart';
|
|||||||
import 'package:moxxmpp/src/xeps/xep_0198/xep_0198.dart';
|
import 'package:moxxmpp/src/xeps/xep_0198/xep_0198.dart';
|
||||||
|
|
||||||
class PingManager extends XmppManagerBase {
|
class PingManager extends XmppManagerBase {
|
||||||
@override
|
PingManager() : super(pingManager);
|
||||||
String getId() => pingManager;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getName() => 'PingManager';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> isSupported() async => true;
|
Future<bool> isSupported() async => true;
|
||||||
|
@ -17,17 +17,11 @@ typedef PresencePreSendCallback = Future<List<XMLNode>> Function();
|
|||||||
/// A mandatory manager that handles initial presence sending, sending of subscription
|
/// A mandatory manager that handles initial presence sending, sending of subscription
|
||||||
/// request management requests and triggers events for incoming presence stanzas.
|
/// request management requests and triggers events for incoming presence stanzas.
|
||||||
class PresenceManager extends XmppManagerBase {
|
class PresenceManager extends XmppManagerBase {
|
||||||
PresenceManager() : super();
|
PresenceManager() : super(presenceManager);
|
||||||
|
|
||||||
/// The list of pre-send callbacks.
|
/// The list of pre-send callbacks.
|
||||||
final List<PresencePreSendCallback> _presenceCallbacks = List.empty(growable: true);
|
final List<PresencePreSendCallback> _presenceCallbacks = List.empty(growable: true);
|
||||||
|
|
||||||
@override
|
|
||||||
String getId() => presenceManager;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getName() => 'PresenceManager';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||||
StanzaHandler(
|
StanzaHandler(
|
||||||
|
@ -93,7 +93,7 @@ class RosterFeatureNegotiator extends XmppFeatureNegotiatorBase {
|
|||||||
|
|
||||||
/// This manager requires a RosterFeatureNegotiator to be registered.
|
/// This manager requires a RosterFeatureNegotiator to be registered.
|
||||||
class RosterManager extends XmppManagerBase {
|
class RosterManager extends XmppManagerBase {
|
||||||
RosterManager(this._stateManager) : super();
|
RosterManager(this._stateManager) : super(rosterManager);
|
||||||
|
|
||||||
/// The class managing the entire roster state.
|
/// The class managing the entire roster state.
|
||||||
final BaseRosterStateManager _stateManager;
|
final BaseRosterStateManager _stateManager;
|
||||||
@ -104,12 +104,6 @@ class RosterManager extends XmppManagerBase {
|
|||||||
_stateManager.register(attributes.sendEvent);
|
_stateManager.register(attributes.sendEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
String getId() => rosterManager;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getName() => 'RosterManager';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||||
StanzaHandler(
|
StanzaHandler(
|
||||||
|
67
packages/moxxmpp/lib/src/util/wait.dart
Normal file
67
packages/moxxmpp/lib/src/util/wait.dart
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'package:meta/meta.dart';
|
||||||
|
import 'package:synchronized/synchronized.dart';
|
||||||
|
|
||||||
|
/// This class allows for multiple asynchronous code places to wait on the
|
||||||
|
/// same computation of type [V], indentified by a key of type [K].
|
||||||
|
class WaitForTracker<K, V> {
|
||||||
|
/// The mapping of key -> Completer for the pending tasks.
|
||||||
|
final Map<K, List<Completer<V>>> _tracker = {};
|
||||||
|
|
||||||
|
/// The lock for accessing _tracker.
|
||||||
|
final Lock _lock = Lock();
|
||||||
|
|
||||||
|
/// Wait for a task with key [key]. If there was no such task already
|
||||||
|
/// present, returns null. If one or more tasks were already present, returns
|
||||||
|
/// a future that will resolve to the result of the first task.
|
||||||
|
Future<Future<V>?> waitFor(K key) async {
|
||||||
|
final result = await _lock.synchronized(() {
|
||||||
|
if (_tracker.containsKey(key)) {
|
||||||
|
// The task already exists. Just append outselves
|
||||||
|
final completer = Completer<V>();
|
||||||
|
_tracker[key]!.add(completer);
|
||||||
|
return completer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The task does not exist yet
|
||||||
|
_tracker[key] = List<Completer<V>>.empty(growable: true);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
return result?.future;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolve a task with key [key] to [value].
|
||||||
|
Future<void> resolve(K key, V value) async {
|
||||||
|
await _lock.synchronized(() {
|
||||||
|
if (!_tracker.containsKey(key)) return;
|
||||||
|
|
||||||
|
for (final completer in _tracker[key]!) {
|
||||||
|
completer.complete(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
_tracker.remove(key);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> resolveAll(V value) async {
|
||||||
|
await _lock.synchronized(() {
|
||||||
|
for (final key in _tracker.keys) {
|
||||||
|
for (final completer in _tracker[key]!) {
|
||||||
|
completer.complete(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove all tasks from the tracker.
|
||||||
|
Future<void> clear() async {
|
||||||
|
await _lock.synchronized(_tracker.clear);
|
||||||
|
}
|
||||||
|
|
||||||
|
@visibleForTesting
|
||||||
|
bool hasTasksRunning() => _tracker.isNotEmpty;
|
||||||
|
|
||||||
|
@visibleForTesting
|
||||||
|
List<Completer<V>> getRunningTasks(K key) => _tracker[key]!;
|
||||||
|
}
|
@ -11,13 +11,7 @@ import 'package:moxxmpp/src/xeps/xep_0446.dart';
|
|||||||
const fileUploadNotificationXmlns = 'proto:urn:xmpp:fun:0';
|
const fileUploadNotificationXmlns = 'proto:urn:xmpp:fun:0';
|
||||||
|
|
||||||
class FileUploadNotificationManager extends XmppManagerBase {
|
class FileUploadNotificationManager extends XmppManagerBase {
|
||||||
FileUploadNotificationManager() : super();
|
FileUploadNotificationManager() : super(fileUploadNotificationManager);
|
||||||
|
|
||||||
@override
|
|
||||||
String getId() => fileUploadNotificationManager;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getName() => 'FileUploadNotificationManager';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||||
|
23
packages/moxxmpp/lib/src/xeps/xep_0030/cache.dart
Normal file
23
packages/moxxmpp/lib/src/xeps/xep_0030/cache.dart
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
|
@internal
|
||||||
|
@immutable
|
||||||
|
class DiscoCacheKey {
|
||||||
|
const DiscoCacheKey(this.jid, this.node);
|
||||||
|
|
||||||
|
/// The JID we're requesting disco data from.
|
||||||
|
final String jid;
|
||||||
|
|
||||||
|
/// Optionally the node we are requesting from.
|
||||||
|
final String? node;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is DiscoCacheKey &&
|
||||||
|
jid == other.jid &&
|
||||||
|
node == other.node;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => jid.hashCode ^ node.hashCode;
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
|
import 'package:moxxmpp/src/connection.dart';
|
||||||
import 'package:moxxmpp/src/events.dart';
|
import 'package:moxxmpp/src/events.dart';
|
||||||
import 'package:moxxmpp/src/jid.dart';
|
import 'package:moxxmpp/src/jid.dart';
|
||||||
import 'package:moxxmpp/src/managers/base.dart';
|
import 'package:moxxmpp/src/managers/base.dart';
|
||||||
@ -10,6 +11,8 @@ import 'package:moxxmpp/src/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/types/result.dart';
|
import 'package:moxxmpp/src/types/result.dart';
|
||||||
|
import 'package:moxxmpp/src/util/wait.dart';
|
||||||
|
import 'package:moxxmpp/src/xeps/xep_0030/cache.dart';
|
||||||
import 'package:moxxmpp/src/xeps/xep_0030/errors.dart';
|
import 'package:moxxmpp/src/xeps/xep_0030/errors.dart';
|
||||||
import 'package:moxxmpp/src/xeps/xep_0030/helpers.dart';
|
import 'package:moxxmpp/src/xeps/xep_0030/helpers.dart';
|
||||||
import 'package:moxxmpp/src/xeps/xep_0030/types.dart';
|
import 'package:moxxmpp/src/xeps/xep_0030/types.dart';
|
||||||
@ -22,21 +25,6 @@ typedef DiscoInfoRequestCallback = Future<DiscoInfo> Function();
|
|||||||
/// Callback that is called when a disco#items requests is received on a given node.
|
/// Callback that is called when a disco#items requests is received on a given node.
|
||||||
typedef DiscoItemsRequestCallback = Future<List<DiscoItem>> Function();
|
typedef DiscoItemsRequestCallback = Future<List<DiscoItem>> Function();
|
||||||
|
|
||||||
@immutable
|
|
||||||
class DiscoCacheKey {
|
|
||||||
const DiscoCacheKey(this.jid, this.node);
|
|
||||||
final String jid;
|
|
||||||
final String? node;
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return other is DiscoCacheKey && jid == other.jid && node == other.node;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => jid.hashCode ^ node.hashCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This manager implements XEP-0030 by providing a way of performing disco#info and
|
/// This manager implements XEP-0030 by providing a way of performing disco#info and
|
||||||
/// disco#items requests and answering those requests.
|
/// disco#items requests and answering those requests.
|
||||||
/// A caching mechanism is also provided.
|
/// A caching mechanism is also provided.
|
||||||
@ -45,7 +33,7 @@ class DiscoManager extends XmppManagerBase {
|
|||||||
/// to a disco#info response.
|
/// to a disco#info response.
|
||||||
DiscoManager(List<Identity> identities)
|
DiscoManager(List<Identity> identities)
|
||||||
: _identities = List<Identity>.from(identities),
|
: _identities = List<Identity>.from(identities),
|
||||||
super();
|
super(discoManager);
|
||||||
|
|
||||||
/// Our features
|
/// Our features
|
||||||
final List<String> _features = List.empty(growable: true);
|
final List<String> _features = List.empty(growable: true);
|
||||||
@ -62,8 +50,11 @@ class DiscoManager extends XmppManagerBase {
|
|||||||
/// Map full JID to Disco Info
|
/// Map full JID to Disco Info
|
||||||
final Map<DiscoCacheKey, DiscoInfo> _discoInfoCache = {};
|
final Map<DiscoCacheKey, DiscoInfo> _discoInfoCache = {};
|
||||||
|
|
||||||
/// Mapping the full JID to a list of running requests
|
/// The tracker for tracking disco#info queries that are in flight.
|
||||||
final Map<DiscoCacheKey, List<Completer<Result<DiscoError, DiscoInfo>>>> _runningInfoQueries = {};
|
final WaitForTracker<DiscoCacheKey, Result<DiscoError, DiscoInfo>> _discoInfoTracker = WaitForTracker();
|
||||||
|
|
||||||
|
/// The tracker for tracking disco#info queries that are in flight.
|
||||||
|
final WaitForTracker<DiscoCacheKey, Result<DiscoError, List<DiscoItem>>> _discoItemsTracker = WaitForTracker();
|
||||||
|
|
||||||
/// Cache lock
|
/// Cache lock
|
||||||
final Lock _cacheLock = Lock();
|
final Lock _cacheLock = Lock();
|
||||||
@ -81,10 +72,7 @@ class DiscoManager extends XmppManagerBase {
|
|||||||
List<String> get features => _features;
|
List<String> get features => _features;
|
||||||
|
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
bool hasInfoQueriesRunning() => _runningInfoQueries.isNotEmpty;
|
WaitForTracker<DiscoCacheKey, Result<DiscoError, DiscoInfo>> get infoTracker => _discoInfoTracker;
|
||||||
|
|
||||||
@visibleForTesting
|
|
||||||
List<Completer<Result<DiscoError, DiscoInfo>>> getRunningInfoQueries(DiscoCacheKey key) => _runningInfoQueries[key]!;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||||
@ -102,12 +90,6 @@ class DiscoManager extends XmppManagerBase {
|
|||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
@override
|
|
||||||
String getId() => discoManager;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getName() => 'DiscoManager';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<String> getDiscoFeatures() => [ discoInfoXmlns, discoItemsXmlns ];
|
List<String> getDiscoFeatures() => [ discoInfoXmlns, discoItemsXmlns ];
|
||||||
|
|
||||||
@ -118,7 +100,21 @@ class DiscoManager extends XmppManagerBase {
|
|||||||
Future<void> onXmppEvent(XmppEvent event) async {
|
Future<void> onXmppEvent(XmppEvent event) async {
|
||||||
if (event is PresenceReceivedEvent) {
|
if (event is PresenceReceivedEvent) {
|
||||||
await _onPresence(event.jid, event.presence);
|
await _onPresence(event.jid, event.presence);
|
||||||
} else if (event is StreamResumeFailedEvent) {
|
} else if (event is ConnectionStateChangedEvent) {
|
||||||
|
// TODO(Unknown): This handling is stupid. We should have an event that is
|
||||||
|
// triggered when we cannot guarantee that everything is as
|
||||||
|
// it was before.
|
||||||
|
if (event.state != XmppConnectionState.connected) return;
|
||||||
|
if (event.resumed) return;
|
||||||
|
|
||||||
|
// Cancel all waiting requests
|
||||||
|
await _discoInfoTracker.resolveAll(
|
||||||
|
Result<DiscoError, DiscoInfo>(UnknownDiscoError()),
|
||||||
|
);
|
||||||
|
await _discoItemsTracker.resolveAll(
|
||||||
|
Result<DiscoError, List<DiscoItem>>(UnknownDiscoError()),
|
||||||
|
);
|
||||||
|
|
||||||
await _cacheLock.synchronized(() async {
|
await _cacheLock.synchronized(() async {
|
||||||
// Clear the cache
|
// Clear the cache
|
||||||
_discoInfoCache.clear();
|
_discoInfoCache.clear();
|
||||||
@ -259,46 +255,37 @@ class DiscoManager extends XmppManagerBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _exitDiscoInfoCriticalSection(DiscoCacheKey key, Result<DiscoError, DiscoInfo> result) async {
|
Future<void> _exitDiscoInfoCriticalSection(DiscoCacheKey key, Result<DiscoError, DiscoInfo> result) async {
|
||||||
return _cacheLock.synchronized(() async {
|
await _cacheLock.synchronized(() async {
|
||||||
// Complete all futures
|
|
||||||
for (final completer in _runningInfoQueries[key]!) {
|
|
||||||
completer.complete(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add to cache if it is a result
|
// Add to cache if it is a result
|
||||||
if (result.isType<DiscoInfo>()) {
|
if (result.isType<DiscoInfo>()) {
|
||||||
_discoInfoCache[key] = result.get<DiscoInfo>();
|
_discoInfoCache[key] = result.get<DiscoInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove from the request cache
|
|
||||||
_runningInfoQueries.remove(key);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await _discoInfoTracker.resolve(key, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sends a disco info query to the (full) jid [entity], optionally with node=[node].
|
/// Sends a disco info query to the (full) jid [entity], optionally with node=[node].
|
||||||
Future<Result<DiscoError, DiscoInfo>> discoInfoQuery(String entity, { String? node, bool shouldEncrypt = true }) async {
|
Future<Result<DiscoError, DiscoInfo>> discoInfoQuery(String entity, { String? node, bool shouldEncrypt = true }) async {
|
||||||
final cacheKey = DiscoCacheKey(entity, node);
|
final cacheKey = DiscoCacheKey(entity, node);
|
||||||
DiscoInfo? info;
|
DiscoInfo? info;
|
||||||
Completer<Result<DiscoError, DiscoInfo>>? completer;
|
final ffuture = await _cacheLock.synchronized<Future<Future<Result<DiscoError, DiscoInfo>>?>?>(() async {
|
||||||
await _cacheLock.synchronized(() 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)) {
|
||||||
info = _discoInfoCache[cacheKey];
|
info = _discoInfoCache[cacheKey];
|
||||||
|
return null;
|
||||||
} else {
|
} else {
|
||||||
// Is a request running?
|
return _discoInfoTracker.waitFor(cacheKey);
|
||||||
if (_runningInfoQueries.containsKey(cacheKey)) {
|
|
||||||
completer = Completer();
|
|
||||||
_runningInfoQueries[cacheKey]!.add(completer!);
|
|
||||||
} else {
|
|
||||||
_runningInfoQueries[cacheKey] = List.from(<Completer<DiscoInfo?>>[]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (info != null) {
|
if (info != null) {
|
||||||
return Result<DiscoError, DiscoInfo>(info);
|
return Result<DiscoError, DiscoInfo>(info);
|
||||||
} else if (completer != null) {
|
} else {
|
||||||
return completer!.future;
|
final future = await ffuture;
|
||||||
|
if (future != null) {
|
||||||
|
return future;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final stanza = await getAttributes().sendStanza(
|
final stanza = await getAttributes().sendStanza(
|
||||||
@ -331,6 +318,12 @@ 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(String entity, { String? node, bool shouldEncrypt = true }) async {
|
Future<Result<DiscoError, List<DiscoItem>>> discoItemsQuery(String entity, { String? node, bool shouldEncrypt = true }) async {
|
||||||
|
final key = DiscoCacheKey(entity, node);
|
||||||
|
final future = await _discoItemsTracker.waitFor(key);
|
||||||
|
if (future != null) {
|
||||||
|
return future;
|
||||||
|
}
|
||||||
|
|
||||||
final stanza = await getAttributes()
|
final stanza = await getAttributes()
|
||||||
.sendStanza(
|
.sendStanza(
|
||||||
buildDiscoItemsQueryStanza(entity, node: node),
|
buildDiscoItemsQueryStanza(entity, node: node),
|
||||||
@ -338,12 +331,18 @@ class DiscoManager extends XmppManagerBase {
|
|||||||
) as Stanza;
|
) as Stanza;
|
||||||
|
|
||||||
final query = stanza.firstTag('query');
|
final query = stanza.firstTag('query');
|
||||||
if (query == null) return Result(InvalidResponseDiscoError());
|
if (query == null) {
|
||||||
|
final result = Result<DiscoError, List<DiscoItem>>(InvalidResponseDiscoError());
|
||||||
|
await _discoItemsTracker.resolve(key, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
if (stanza.type == 'error') {
|
if (stanza.type == 'error') {
|
||||||
//final error = stanza.firstTag('error');
|
//final error = stanza.firstTag('error');
|
||||||
//print("Disco Items error: " + error.toXml());
|
//print("Disco Items error: " + error.toXml());
|
||||||
return Result(ErrorResponseDiscoError());
|
final result = Result<DiscoError, List<DiscoItem>>(ErrorResponseDiscoError());
|
||||||
|
await _discoItemsTracker.resolve(key, result);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
final items = query.findTags('item').map((node) => DiscoItem(
|
final items = query.findTags('item').map((node) => DiscoItem(
|
||||||
@ -352,7 +351,9 @@ class DiscoManager extends XmppManagerBase {
|
|||||||
name: node.attributes['name'] as String?,
|
name: node.attributes['name'] as String?,
|
||||||
),).toList();
|
),).toList();
|
||||||
|
|
||||||
return Result(items);
|
final result = Result<DiscoError, List<DiscoItem>>(items);
|
||||||
|
await _discoItemsTracker.resolve(key, result);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Queries information about a jid based on its node and capability hash.
|
/// Queries information about a jid based on its node and capability hash.
|
||||||
|
@ -28,14 +28,8 @@ class VCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class VCardManager extends XmppManagerBase {
|
class VCardManager extends XmppManagerBase {
|
||||||
VCardManager() : _lastHash = {}, super();
|
VCardManager() : super(vcardManager);
|
||||||
final Map<String, String> _lastHash;
|
final Map<String, String> _lastHash = {};
|
||||||
|
|
||||||
@override
|
|
||||||
String getId() => vcardManager;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getName() => 'vCardManager';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||||
|
@ -69,11 +69,7 @@ class PubSubItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class PubSubManager extends XmppManagerBase {
|
class PubSubManager extends XmppManagerBase {
|
||||||
@override
|
PubSubManager() : super(pubsubManager);
|
||||||
String getId() => pubsubManager;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getName() => 'PubsubManager';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||||
|
@ -8,7 +8,6 @@ import 'package:moxxmpp/src/stringxml.dart';
|
|||||||
|
|
||||||
/// A data class representing the jabber:x:oob tag.
|
/// A data class representing the jabber:x:oob tag.
|
||||||
class OOBData {
|
class OOBData {
|
||||||
|
|
||||||
const OOBData({ this.url, this.desc });
|
const OOBData({ this.url, this.desc });
|
||||||
final String? url;
|
final String? url;
|
||||||
final String? desc;
|
final String? desc;
|
||||||
@ -32,11 +31,7 @@ XMLNode constructOOBNode(OOBData data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class OOBManager extends XmppManagerBase {
|
class OOBManager extends XmppManagerBase {
|
||||||
@override
|
OOBManager() : super(oobManager);
|
||||||
String getName() => 'OOBName';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getId() => oobManager;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<String> getDiscoFeatures() => [ oobDataXmlns ];
|
List<String> getDiscoFeatures() => [ oobDataXmlns ];
|
||||||
|
@ -28,24 +28,24 @@ class UserAvatarMetadata {
|
|||||||
this.height,
|
this.height,
|
||||||
this.mime,
|
this.mime,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// The amount of bytes in the file
|
/// The amount of bytes in the file
|
||||||
final int length;
|
final int length;
|
||||||
|
|
||||||
/// The identifier of the avatar
|
/// The identifier of the avatar
|
||||||
final String id;
|
final String id;
|
||||||
|
|
||||||
/// Image proportions
|
/// Image proportions
|
||||||
final int width;
|
final int width;
|
||||||
final int height;
|
final int height;
|
||||||
|
|
||||||
/// The MIME type of the avatar
|
/// The MIME type of the avatar
|
||||||
final String mime;
|
final String mime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// NOTE: This class requires a PubSubManager
|
/// NOTE: This class requires a PubSubManager
|
||||||
class UserAvatarManager extends XmppManagerBase {
|
class UserAvatarManager extends XmppManagerBase {
|
||||||
@override
|
UserAvatarManager() : super(userAvatarManager);
|
||||||
String getId() => userAvatarManager;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getName() => 'UserAvatarManager';
|
|
||||||
|
|
||||||
PubSubManager _getPubSubManager() => getAttributes().getManagerById(pubsubManager)! as PubSubManager;
|
PubSubManager _getPubSubManager() => getAttributes().getManagerById(pubsubManager)! as PubSubManager;
|
||||||
|
|
||||||
|
@ -39,15 +39,11 @@ ChatState chatStateFromString(String raw) {
|
|||||||
String chatStateToString(ChatState state) => state.toString().split('.').last;
|
String chatStateToString(ChatState state) => state.toString().split('.').last;
|
||||||
|
|
||||||
class ChatStateManager extends XmppManagerBase {
|
class ChatStateManager extends XmppManagerBase {
|
||||||
|
ChatStateManager() : super(chatStateManager);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<String> getDiscoFeatures() => [ chatStateXmlns ];
|
List<String> getDiscoFeatures() => [ chatStateXmlns ];
|
||||||
|
|
||||||
@override
|
|
||||||
String getName() => 'ChatStateManager';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getId() => chatStateManager;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||||
StanzaHandler(
|
StanzaHandler(
|
||||||
|
@ -71,7 +71,7 @@ Future<String> calculateCapabilityHash(DiscoInfo info, HashAlgorithm algorithm)
|
|||||||
/// the DiscoManager.
|
/// the DiscoManager.
|
||||||
/// NOTE: This manager requires that the DiscoManager is also registered.
|
/// NOTE: This manager requires that the DiscoManager is also registered.
|
||||||
class EntityCapabilitiesManager extends XmppManagerBase {
|
class EntityCapabilitiesManager extends XmppManagerBase {
|
||||||
EntityCapabilitiesManager(this._capabilityHashBase) : super();
|
EntityCapabilitiesManager(this._capabilityHashBase) : super(entityCapabilitiesManager);
|
||||||
|
|
||||||
/// The string that is both the node under which we advertise the disco info
|
/// The string that is both the node under which we advertise the disco info
|
||||||
/// and the base for the actual node on which we respond to disco#info requests.
|
/// and the base for the actual node on which we respond to disco#info requests.
|
||||||
@ -80,19 +80,11 @@ class EntityCapabilitiesManager extends XmppManagerBase {
|
|||||||
/// The cached capability hash.
|
/// The cached capability hash.
|
||||||
String? _capabilityHash;
|
String? _capabilityHash;
|
||||||
|
|
||||||
@override
|
|
||||||
String getName() => 'EntityCapabilitiesManager';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getId() => entityCapabilitiesManager;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> isSupported() async => true;
|
Future<bool> isSupported() async => true;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<String> getDiscoFeatures() => [
|
List<String> getDiscoFeatures() => [ capsXmlns ];
|
||||||
capsXmlns,
|
|
||||||
];
|
|
||||||
|
|
||||||
/// Computes, if required, the capability hash of the data provided by
|
/// Computes, if required, the capability hash of the data provided by
|
||||||
/// the DiscoManager.
|
/// the DiscoManager.
|
||||||
|
@ -24,15 +24,11 @@ XMLNode makeMessageDeliveryResponse(String id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MessageDeliveryReceiptManager extends XmppManagerBase {
|
class MessageDeliveryReceiptManager extends XmppManagerBase {
|
||||||
|
MessageDeliveryReceiptManager() : super(messageDeliveryReceiptManager);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<String> getDiscoFeatures() => [ deliveryXmlns ];
|
List<String> getDiscoFeatures() => [ deliveryXmlns ];
|
||||||
|
|
||||||
@override
|
|
||||||
String getName() => 'MessageDeliveryReceiptManager';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getId() => messageDeliveryReceiptManager;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||||
StanzaHandler(
|
StanzaHandler(
|
||||||
|
@ -9,16 +9,10 @@ import 'package:moxxmpp/src/stringxml.dart';
|
|||||||
import 'package:moxxmpp/src/xeps/xep_0030/xep_0030.dart';
|
import 'package:moxxmpp/src/xeps/xep_0030/xep_0030.dart';
|
||||||
|
|
||||||
class BlockingManager extends XmppManagerBase {
|
class BlockingManager extends XmppManagerBase {
|
||||||
BlockingManager() : _supported = false, _gotSupported = false, super();
|
BlockingManager() : super(blockingManager);
|
||||||
|
|
||||||
bool _supported;
|
bool _supported = false;
|
||||||
bool _gotSupported;
|
bool _gotSupported = false;
|
||||||
|
|
||||||
@override
|
|
||||||
String getId() => blockingManager;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getName() => 'BlockingManager';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||||
|
@ -21,40 +21,41 @@ const xmlUintMax = 4294967296; // 2**32
|
|||||||
typedef StanzaAckedCallback = bool Function(Stanza stanza);
|
typedef StanzaAckedCallback = bool Function(Stanza stanza);
|
||||||
|
|
||||||
class StreamManagementManager extends XmppManagerBase {
|
class StreamManagementManager extends XmppManagerBase {
|
||||||
|
|
||||||
StreamManagementManager({
|
StreamManagementManager({
|
||||||
this.ackTimeout = const Duration(seconds: 30),
|
this.ackTimeout = const Duration(seconds: 30),
|
||||||
})
|
}) : super(smManager);
|
||||||
: _state = StreamManagementState(0, 0),
|
|
||||||
_unackedStanzas = {},
|
|
||||||
_stateLock = Lock(),
|
|
||||||
_streamManagementEnabled = false,
|
|
||||||
_lastAckTimestamp = -1,
|
|
||||||
_pendingAcks = 0,
|
|
||||||
_streamResumed = false,
|
|
||||||
_ackLock = Lock();
|
|
||||||
/// 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, Stanza> _unackedStanzas = {};
|
||||||
|
|
||||||
/// Commitable state of the StreamManagementManager
|
/// Commitable state of the StreamManagementManager
|
||||||
StreamManagementState _state;
|
StreamManagementState _state = StreamManagementState(0, 0);
|
||||||
|
|
||||||
/// Mutex lock for _state
|
/// Mutex lock for _state
|
||||||
final Lock _stateLock;
|
final Lock _stateLock = Lock();
|
||||||
|
|
||||||
/// If the have enabled SM on the stream yet
|
/// If the have enabled SM on the stream yet
|
||||||
bool _streamManagementEnabled;
|
bool _streamManagementEnabled = false;
|
||||||
|
|
||||||
/// If the current stream has been resumed;
|
/// If the current stream has been resumed;
|
||||||
bool _streamResumed;
|
bool _streamResumed = false;
|
||||||
|
|
||||||
/// The time in which the response to an ack is still valid. Counts as a timeout
|
/// The time in which the response to an ack is still valid. Counts as a timeout
|
||||||
/// otherwise
|
/// otherwise
|
||||||
@internal
|
@internal
|
||||||
final Duration ackTimeout;
|
final Duration ackTimeout;
|
||||||
|
|
||||||
/// The time at which the last ack has been sent
|
/// The time at which the last ack has been sent
|
||||||
int _lastAckTimestamp;
|
int _lastAckTimestamp = -1;
|
||||||
|
|
||||||
/// The timer to see if we timed the connection out
|
/// The timer to see if we timed the connection out
|
||||||
Timer? _ackTimer;
|
Timer? _ackTimer;
|
||||||
|
|
||||||
/// Counts how many acks we're waiting for
|
/// Counts how many acks we're waiting for
|
||||||
int _pendingAcks;
|
int _pendingAcks = 0;
|
||||||
|
|
||||||
/// Lock for both [_lastAckTimestamp] and [_pendingAcks].
|
/// Lock for both [_lastAckTimestamp] and [_pendingAcks].
|
||||||
final Lock _ackLock;
|
final Lock _ackLock = Lock();
|
||||||
|
|
||||||
/// Functions for testing
|
/// Functions for testing
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
@ -121,12 +122,6 @@ class StreamManagementManager extends XmppManagerBase {
|
|||||||
|
|
||||||
bool get streamResumed => _streamResumed;
|
bool get streamResumed => _streamResumed;
|
||||||
|
|
||||||
@override
|
|
||||||
String getId() => smManager;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getName() => 'StreamManagementManager';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<NonzaHandler> getNonzaHandlers() => [
|
List<NonzaHandler> getNonzaHandlers() => [
|
||||||
NonzaHandler(
|
NonzaHandler(
|
||||||
|
@ -14,11 +14,7 @@ class DelayedDelivery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class DelayedDeliveryManager extends XmppManagerBase {
|
class DelayedDeliveryManager extends XmppManagerBase {
|
||||||
@override
|
DelayedDeliveryManager() : super(delayedDeliveryManager);
|
||||||
String getId() => delayedDeliveryManager;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getName() => 'DelayedDeliveryManager';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> isSupported() async => true;
|
Future<bool> isSupported() async => true;
|
||||||
|
@ -14,7 +14,7 @@ import 'package:moxxmpp/src/xeps/xep_0297.dart';
|
|||||||
|
|
||||||
/// This manager class implements support for XEP-0280.
|
/// This manager class implements support for XEP-0280.
|
||||||
class CarbonsManager extends XmppManagerBase {
|
class CarbonsManager extends XmppManagerBase {
|
||||||
CarbonsManager() : super();
|
CarbonsManager() : super(carbonsManager);
|
||||||
|
|
||||||
/// Indicates that message carbons are enabled.
|
/// Indicates that message carbons are enabled.
|
||||||
bool _isEnabled = false;
|
bool _isEnabled = false;
|
||||||
@ -25,12 +25,6 @@ class CarbonsManager extends XmppManagerBase {
|
|||||||
/// Indicates that we know that [CarbonsManager._supported] is accurate.
|
/// Indicates that we know that [CarbonsManager._supported] is accurate.
|
||||||
bool _gotSupported = false;
|
bool _gotSupported = false;
|
||||||
|
|
||||||
@override
|
|
||||||
String getId() => carbonsManager;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getName() => 'CarbonsManager';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<StanzaHandler> getIncomingPreStanzaHandlers() => [
|
List<StanzaHandler> getIncomingPreStanzaHandlers() => [
|
||||||
StanzaHandler(
|
StanzaHandler(
|
||||||
|
@ -61,11 +61,7 @@ HashFunction hashFunctionFromName(String name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class CryptographicHashManager extends XmppManagerBase {
|
class CryptographicHashManager extends XmppManagerBase {
|
||||||
@override
|
CryptographicHashManager() : super(cryptographicHashManager);
|
||||||
String getId() => cryptographicHashManager;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getName() => 'CryptographicHashManager';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> isSupported() async => true;
|
Future<bool> isSupported() async => true;
|
||||||
@ -81,7 +77,7 @@ class CryptographicHashManager extends XmppManagerBase {
|
|||||||
];
|
];
|
||||||
|
|
||||||
static Future<List<int>> hashFromData(List<int> data, HashFunction function) async {
|
static Future<List<int>> hashFromData(List<int> data, HashFunction function) async {
|
||||||
// TODO(PapaTutuWawa): Implemen the others as well
|
// TODO(PapaTutuWawa): Implement the others as well
|
||||||
HashAlgorithm algo;
|
HashAlgorithm algo;
|
||||||
switch (function) {
|
switch (function) {
|
||||||
case HashFunction.sha256:
|
case HashFunction.sha256:
|
||||||
|
@ -17,11 +17,7 @@ XMLNode makeLastMessageCorrectionEdit(String id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class LastMessageCorrectionManager extends XmppManagerBase {
|
class LastMessageCorrectionManager extends XmppManagerBase {
|
||||||
@override
|
LastMessageCorrectionManager() : super(lastMessageCorrectionManager);
|
||||||
String getName() => 'LastMessageCorrectionManager';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getId() => lastMessageCorrectionManager;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<String> getDiscoFeatures() => [ lmcXmlns ];
|
List<String> getDiscoFeatures() => [ lmcXmlns ];
|
||||||
|
@ -25,11 +25,7 @@ XMLNode makeChatMarker(String tag, String id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ChatMarkerManager extends XmppManagerBase {
|
class ChatMarkerManager extends XmppManagerBase {
|
||||||
@override
|
ChatMarkerManager() : super(chatMarkerManager);
|
||||||
String getName() => 'ChatMarkerManager';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getId() => chatMarkerManager;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<String> getDiscoFeatures() => [ chatMarkersXmlns ];
|
List<String> getDiscoFeatures() => [ chatMarkersXmlns ];
|
||||||
|
@ -26,10 +26,10 @@ class CSIInactiveNonza extends XMLNode {
|
|||||||
|
|
||||||
/// A Stub negotiator that is just for "intercepting" the stream feature.
|
/// A Stub negotiator that is just for "intercepting" the stream feature.
|
||||||
class CSINegotiator extends XmppFeatureNegotiatorBase {
|
class CSINegotiator extends XmppFeatureNegotiatorBase {
|
||||||
CSINegotiator() : _supported = false, super(11, false, csiXmlns, csiNegotiator);
|
CSINegotiator() : super(11, false, csiXmlns, csiNegotiator);
|
||||||
|
|
||||||
/// True if CSI is supported. False otherwise.
|
/// True if CSI is supported. False otherwise.
|
||||||
bool _supported;
|
bool _supported = false;
|
||||||
bool get isSupported => _supported;
|
bool get isSupported => _supported;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -50,15 +50,9 @@ class CSINegotiator extends XmppFeatureNegotiatorBase {
|
|||||||
|
|
||||||
/// The manager requires a CSINegotiator to be registered as a feature negotiator.
|
/// The manager requires a CSINegotiator to be registered as a feature negotiator.
|
||||||
class CSIManager extends XmppManagerBase {
|
class CSIManager extends XmppManagerBase {
|
||||||
|
CSIManager() : super(csiManager);
|
||||||
|
|
||||||
CSIManager() : _isActive = true, super();
|
bool _isActive = true;
|
||||||
bool _isActive;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getId() => csiManager;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getName() => 'CSIManager';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> isSupported() async {
|
Future<bool> isSupported() async {
|
||||||
|
@ -13,7 +13,6 @@ import 'package:moxxmpp/src/xeps/xep_0030/xep_0030.dart';
|
|||||||
/// NOTE: [StableStanzaId.stanzaId] must not be confused with the actual id attribute of
|
/// NOTE: [StableStanzaId.stanzaId] must not be confused with the actual id attribute of
|
||||||
/// the message stanza.
|
/// the message stanza.
|
||||||
class StableStanzaId {
|
class StableStanzaId {
|
||||||
|
|
||||||
const StableStanzaId({ this.originId, this.stanzaId, this.stanzaIdBy });
|
const StableStanzaId({ this.originId, this.stanzaId, this.stanzaIdBy });
|
||||||
final String? originId;
|
final String? originId;
|
||||||
final String? stanzaId;
|
final String? stanzaId;
|
||||||
@ -29,11 +28,7 @@ XMLNode makeOriginIdElement(String id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class StableIdManager extends XmppManagerBase {
|
class StableIdManager extends XmppManagerBase {
|
||||||
@override
|
StableIdManager() : super(stableIdManager);
|
||||||
String getName() => 'StableIdManager';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getId() => stableIdManager;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<String> getDiscoFeatures() => [ stableIdXmlns ];
|
List<String> getDiscoFeatures() => [ stableIdXmlns ];
|
||||||
|
@ -41,17 +41,19 @@ Map<String, String> prepareHeaders(Map<String, String> headers) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class HttpFileUploadManager extends XmppManagerBase {
|
class HttpFileUploadManager extends XmppManagerBase {
|
||||||
HttpFileUploadManager() : _gotSupported = false, _supported = false, super();
|
HttpFileUploadManager() : super(httpFileUploadManager);
|
||||||
|
|
||||||
|
/// The entity that we will request file uploads from, if discovered.
|
||||||
JID? _entityJid;
|
JID? _entityJid;
|
||||||
|
|
||||||
|
/// The maximum file upload file size, if advertised and discovered.
|
||||||
int? _maxUploadSize;
|
int? _maxUploadSize;
|
||||||
bool _gotSupported;
|
|
||||||
bool _supported;
|
|
||||||
|
|
||||||
@override
|
/// Flag, if we every tried to discover the upload entity.
|
||||||
String getId() => httpFileUploadManager;
|
bool _gotSupported = false;
|
||||||
|
|
||||||
@override
|
/// Flag, if we can use HTTP File Upload
|
||||||
String getName() => 'HttpFileUploadManager';
|
bool _supported = false;
|
||||||
|
|
||||||
/// Returns whether the entity provided an identity that tells us that we can ask it
|
/// Returns whether the entity provided an identity that tells us that we can ask it
|
||||||
/// for an HTTP upload slot.
|
/// for an HTTP upload slot.
|
||||||
|
@ -53,20 +53,12 @@ XMLNode buildEmeElement(ExplicitEncryptionType type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class EmeManager extends XmppManagerBase {
|
class EmeManager extends XmppManagerBase {
|
||||||
|
EmeManager() : super(emeManager);
|
||||||
EmeManager() : super();
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getId() => emeManager;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getName() => 'EmeManager';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> isSupported() async => true;
|
Future<bool> isSupported() async => true;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<String> getDiscoFeatures() => [emeXmlns];
|
List<String> getDiscoFeatures() => [ emeXmlns ];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||||
|
@ -42,12 +42,9 @@ const _doNotEncryptList = [
|
|||||||
DoNotEncrypt('stanza-id', stableIdXmlns),
|
DoNotEncrypt('stanza-id', stableIdXmlns),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@mustCallSuper
|
||||||
abstract class BaseOmemoManager extends XmppManagerBase {
|
abstract class BaseOmemoManager extends XmppManagerBase {
|
||||||
@override
|
BaseOmemoManager() : super(omemoManager);
|
||||||
String getId() => omemoManager;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getName() => 'OmemoManager';
|
|
||||||
|
|
||||||
// TODO(Unknown): Technically, this is not always true
|
// TODO(Unknown): Technically, this is not always true
|
||||||
@override
|
@override
|
||||||
|
@ -8,7 +8,6 @@ import 'package:moxxmpp/src/stringxml.dart';
|
|||||||
import 'package:moxxmpp/src/xeps/staging/extensible_file_thumbnails.dart';
|
import 'package:moxxmpp/src/xeps/staging/extensible_file_thumbnails.dart';
|
||||||
|
|
||||||
class StatelessMediaSharingData {
|
class StatelessMediaSharingData {
|
||||||
|
|
||||||
const StatelessMediaSharingData({ required this.mediaType, required this.size, required this.description, required this.hashes, required this.url, required this.thumbnails });
|
const StatelessMediaSharingData({ required this.mediaType, required this.size, required this.description, required this.hashes, required this.url, required this.thumbnails });
|
||||||
final String mediaType;
|
final String mediaType;
|
||||||
final int size;
|
final int size;
|
||||||
@ -63,11 +62,7 @@ StatelessMediaSharingData parseSIMSElement(XMLNode node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class SIMSManager extends XmppManagerBase {
|
class SIMSManager extends XmppManagerBase {
|
||||||
@override
|
SIMSManager() : super(simsManager);
|
||||||
String getName() => 'SIMSManager';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getId() => simsManager;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<String> getDiscoFeatures() => [ simsXmlns ];
|
List<String> getDiscoFeatures() => [ simsXmlns ];
|
||||||
|
@ -12,11 +12,7 @@ class MessageRetractionData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MessageRetractionManager extends XmppManagerBase {
|
class MessageRetractionManager extends XmppManagerBase {
|
||||||
@override
|
MessageRetractionManager() : super(messageRetractionManager);
|
||||||
String getName() => 'MessageRetractionManager';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getId() => messageRetractionManager;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<String> getDiscoFeatures() => [ messageRetractionXmlns ];
|
List<String> getDiscoFeatures() => [ messageRetractionXmlns ];
|
||||||
|
@ -29,15 +29,11 @@ class MessageReactions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MessageReactionsManager extends XmppManagerBase {
|
class MessageReactionsManager extends XmppManagerBase {
|
||||||
|
MessageReactionsManager() : super(messageReactionsManager);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<String> getDiscoFeatures() => [ messageReactionsXmlns ];
|
List<String> getDiscoFeatures() => [ messageReactionsXmlns ];
|
||||||
|
|
||||||
@override
|
|
||||||
String getName() => 'MessageReactionsManager';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getId() => messageReactionsManager;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||||
StanzaHandler(
|
StanzaHandler(
|
||||||
|
@ -105,11 +105,7 @@ class StatelessFileSharingData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class SFSManager extends XmppManagerBase {
|
class SFSManager extends XmppManagerBase {
|
||||||
@override
|
SFSManager() : super(sfsManager);
|
||||||
String getName() => 'SFSManager';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getId() => sfsManager;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||||
|
@ -225,11 +225,7 @@ class StickerPack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class StickersManager extends XmppManagerBase {
|
class StickersManager extends XmppManagerBase {
|
||||||
@override
|
StickersManager() : super(stickersManager);
|
||||||
String getId() => stickersManager;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getName() => 'StickersManager';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> isSupported() async => true;
|
Future<bool> isSupported() async => true;
|
||||||
|
@ -66,11 +66,7 @@ class QuoteData {
|
|||||||
/// A manager implementing support for parsing XEP-0461 metadata. The
|
/// A manager implementing support for parsing XEP-0461 metadata. The
|
||||||
/// MessageRepliesManager itself does not modify the body of the message.
|
/// MessageRepliesManager itself does not modify the body of the message.
|
||||||
class MessageRepliesManager extends XmppManagerBase {
|
class MessageRepliesManager extends XmppManagerBase {
|
||||||
@override
|
MessageRepliesManager() : super(messageRepliesManager);
|
||||||
String getName() => 'MessageRepliesManager';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getId() => messageRepliesManager;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<String> getDiscoFeatures() => [
|
List<String> getDiscoFeatures() => [
|
||||||
|
40
packages/moxxmpp/test/wait_test.dart
Normal file
40
packages/moxxmpp/test/wait_test.dart
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import 'package:test/test.dart';
|
||||||
|
import 'package:moxxmpp/src/util/wait.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
test('Test adding and resolving', () async {
|
||||||
|
// ID -> Milliseconds since epoch
|
||||||
|
final tracker = WaitForTracker<int, int>();
|
||||||
|
|
||||||
|
int r2 = 0;
|
||||||
|
int r3 = 0;
|
||||||
|
|
||||||
|
// Queue some jobs
|
||||||
|
final r1 = await tracker.waitFor(0);
|
||||||
|
expect(r1, null);
|
||||||
|
|
||||||
|
tracker
|
||||||
|
.waitFor(0)
|
||||||
|
.then((result) async {
|
||||||
|
expect(result != null, true);
|
||||||
|
r2 = await result!;
|
||||||
|
});
|
||||||
|
tracker
|
||||||
|
.waitFor(0)
|
||||||
|
.then((result) async {
|
||||||
|
expect(result != null, true);
|
||||||
|
r3 = await result!;
|
||||||
|
});
|
||||||
|
|
||||||
|
final c = await tracker.waitFor(1);
|
||||||
|
expect(c, null);
|
||||||
|
|
||||||
|
// Resolve jobs
|
||||||
|
await tracker.resolve(0, 42);
|
||||||
|
await tracker.resolve(1, 25);
|
||||||
|
await tracker.resolve(2, -1);
|
||||||
|
|
||||||
|
expect(r2, 42);
|
||||||
|
expect(r3, 42);
|
||||||
|
});
|
||||||
|
}
|
@ -1,9 +1,13 @@
|
|||||||
import 'package:moxxmpp/moxxmpp.dart';
|
import 'package:moxxmpp/moxxmpp.dart';
|
||||||
|
import 'package:moxxmpp/src/xeps/xep_0030/cache.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
import '../helpers/logging.dart';
|
||||||
import '../helpers/xmpp.dart';
|
import '../helpers/xmpp.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
initLogger();
|
||||||
|
|
||||||
test('Test having multiple disco requests for the same JID', () async {
|
test('Test having multiple disco requests for the same JID', () async {
|
||||||
final fakeSocket = StubTCPSocket(
|
final fakeSocket = StubTCPSocket(
|
||||||
play: [
|
play: [
|
||||||
@ -102,7 +106,7 @@ void main() {
|
|||||||
|
|
||||||
await Future.delayed(const Duration(seconds: 1));
|
await Future.delayed(const Duration(seconds: 1));
|
||||||
expect(
|
expect(
|
||||||
disco.getRunningInfoQueries(DiscoCacheKey(jid.toString(), null)).length,
|
disco.infoTracker.getRunningTasks(DiscoCacheKey(jid.toString(), null)).length,
|
||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
fakeSocket.injectRawXml("<iq type='result' id='${fakeSocket.lastId!}' from='romeo@montague.lit/orchard' to='polynomdivision@test.server/MU29eEZn' xmlns='jabber:client'><query xmlns='http://jabber.org/protocol/disco#info' /></iq>");
|
fakeSocket.injectRawXml("<iq type='result' id='${fakeSocket.lastId!}' from='romeo@montague.lit/orchard' to='polynomdivision@test.server/MU29eEZn' xmlns='jabber:client'><query xmlns='http://jabber.org/protocol/disco#info' /></iq>");
|
||||||
@ -111,6 +115,6 @@ void main() {
|
|||||||
|
|
||||||
expect(fakeSocket.getState(), 6);
|
expect(fakeSocket.getState(), 6);
|
||||||
expect(await result1, await result2);
|
expect(await result1, await result2);
|
||||||
expect(disco.hasInfoQueriesRunning(), false);
|
expect(disco.infoTracker.hasTasksRunning(), false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user