feat(all): Various changes
- Fix unavailable presence being sent *after* connecting - Migrate more APIs to the JID class - Advertise +notify for user avatar metadata
This commit is contained in:
parent
1475cb542f
commit
9e0f38154e
@ -405,8 +405,7 @@ class XmppConnection {
|
||||
|
||||
/// Returns true if we can send data through the socket.
|
||||
Future<bool> _canSendData() async {
|
||||
return [XmppConnectionState.connected, XmppConnectionState.connecting]
|
||||
.contains(await getConnectionState());
|
||||
return await getConnectionState() == XmppConnectionState.connected;
|
||||
}
|
||||
|
||||
/// Sends a stanza described by [details] to the server. Until sent, the stanza is
|
||||
@ -424,13 +423,17 @@ class XmppConnection {
|
||||
);
|
||||
|
||||
final completer = details.awaitable ? Completer<XMLNode>() : null;
|
||||
await _stanzaQueue.enqueueStanza(
|
||||
StanzaQueueEntry(
|
||||
details,
|
||||
completer,
|
||||
),
|
||||
final entry = StanzaQueueEntry(
|
||||
details,
|
||||
completer,
|
||||
);
|
||||
|
||||
if (details.bypassQueue) {
|
||||
await _sendStanzaImpl(entry);
|
||||
} else {
|
||||
await _stanzaQueue.enqueueStanza(entry);
|
||||
}
|
||||
|
||||
return completer?.future;
|
||||
}
|
||||
|
||||
@ -523,7 +526,7 @@ class XmppConnection {
|
||||
if (await _canSendData()) {
|
||||
_socket.write(data.stanza.toXml());
|
||||
} else {
|
||||
_log.fine('Not sending dat as _canSendData() returned false.');
|
||||
_log.fine('Not sending data as _canSendData() returned false.');
|
||||
}
|
||||
|
||||
// Run post-send handlers
|
||||
@ -535,6 +538,7 @@ class XmppConnection {
|
||||
false,
|
||||
null,
|
||||
newStanza,
|
||||
excludeFromStreamManagement: details.excludeFromStreamManagement,
|
||||
),
|
||||
);
|
||||
_log.fine('Done');
|
||||
@ -835,7 +839,7 @@ class XmppConnection {
|
||||
await _reconnectionPolicy.setShouldReconnect(false);
|
||||
|
||||
if (triggeredByUser) {
|
||||
getPresenceManager()?.sendUnavailablePresence();
|
||||
await getPresenceManager()?.sendUnavailablePresence();
|
||||
}
|
||||
|
||||
_socket.prepareDisconnect();
|
||||
|
@ -7,6 +7,7 @@ import 'package:moxxmpp/src/stanza.dart';
|
||||
import 'package:moxxmpp/src/xeps/xep_0030/types.dart';
|
||||
import 'package:moxxmpp/src/xeps/xep_0060/xep_0060.dart';
|
||||
import 'package:moxxmpp/src/xeps/xep_0066.dart';
|
||||
import 'package:moxxmpp/src/xeps/xep_0084.dart';
|
||||
import 'package:moxxmpp/src/xeps/xep_0085.dart';
|
||||
import 'package:moxxmpp/src/xeps/xep_0334.dart';
|
||||
import 'package:moxxmpp/src/xeps/xep_0359.dart';
|
||||
@ -192,15 +193,35 @@ class SubscriptionRequestReceivedEvent extends XmppEvent {
|
||||
final JID from;
|
||||
}
|
||||
|
||||
/// Triggered when we receive a new or updated avatar
|
||||
class AvatarUpdatedEvent extends XmppEvent {
|
||||
AvatarUpdatedEvent({
|
||||
required this.jid,
|
||||
required this.base64,
|
||||
required this.hash,
|
||||
});
|
||||
final String jid;
|
||||
/// Triggered when we receive a new or updated avatar via XEP-0084
|
||||
class UserAvatarUpdatedEvent extends XmppEvent {
|
||||
UserAvatarUpdatedEvent(
|
||||
this.jid,
|
||||
this.metadata,
|
||||
);
|
||||
|
||||
/// The JID of the user updating their avatar.
|
||||
final JID jid;
|
||||
|
||||
/// The metadata of the avatar.
|
||||
final List<UserAvatarMetadata> metadata;
|
||||
}
|
||||
|
||||
/// Triggered when we receive a new or updated avatar via XEP-0054
|
||||
class VCardAvatarUpdatedEvent extends XmppEvent {
|
||||
VCardAvatarUpdatedEvent(
|
||||
this.jid,
|
||||
this.base64,
|
||||
this.hash,
|
||||
);
|
||||
|
||||
/// The JID of the entity that updated their avatar.
|
||||
final JID jid;
|
||||
|
||||
/// The base64-encoded avatar data.
|
||||
final String base64;
|
||||
|
||||
/// The SHA-1 hash of the avatar.
|
||||
final String hash;
|
||||
}
|
||||
|
||||
|
@ -75,5 +75,8 @@ class StanzaHandlerData with _$StanzaHandlerData {
|
||||
MessageReactions? messageReactions,
|
||||
// The Id of the sticker pack this sticker belongs to
|
||||
String? stickerPackId,
|
||||
// Flag indicating whether the stanza should be excluded from stream management's
|
||||
// resending behaviour
|
||||
@Default(false) bool excludeFromStreamManagement,
|
||||
}) = _StanzaHandlerData;
|
||||
}
|
||||
|
@ -71,7 +71,10 @@ mixin _$StanzaHandlerData {
|
||||
throw _privateConstructorUsedError; // Reactions data
|
||||
MessageReactions? get messageReactions =>
|
||||
throw _privateConstructorUsedError; // The Id of the sticker pack this sticker belongs to
|
||||
String? get stickerPackId => throw _privateConstructorUsedError;
|
||||
String? get stickerPackId =>
|
||||
throw _privateConstructorUsedError; // Flag indicating whether the stanza should be excluded from stream management's
|
||||
// resending behaviour
|
||||
bool get excludeFromStreamManagement => throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
$StanzaHandlerDataCopyWith<StanzaHandlerData> get copyWith =>
|
||||
@ -111,7 +114,8 @@ abstract class $StanzaHandlerDataCopyWith<$Res> {
|
||||
MessageRetractionData? messageRetraction,
|
||||
String? lastMessageCorrectionSid,
|
||||
MessageReactions? messageReactions,
|
||||
String? stickerPackId});
|
||||
String? stickerPackId,
|
||||
bool excludeFromStreamManagement});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@ -154,6 +158,7 @@ class _$StanzaHandlerDataCopyWithImpl<$Res, $Val extends StanzaHandlerData>
|
||||
Object? lastMessageCorrectionSid = freezed,
|
||||
Object? messageReactions = freezed,
|
||||
Object? stickerPackId = freezed,
|
||||
Object? excludeFromStreamManagement = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
done: null == done
|
||||
@ -264,6 +269,10 @@ class _$StanzaHandlerDataCopyWithImpl<$Res, $Val extends StanzaHandlerData>
|
||||
? _value.stickerPackId
|
||||
: stickerPackId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
excludeFromStreamManagement: null == excludeFromStreamManagement
|
||||
? _value.excludeFromStreamManagement
|
||||
: excludeFromStreamManagement // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
@ -303,7 +312,8 @@ abstract class _$$_StanzaHandlerDataCopyWith<$Res>
|
||||
MessageRetractionData? messageRetraction,
|
||||
String? lastMessageCorrectionSid,
|
||||
MessageReactions? messageReactions,
|
||||
String? stickerPackId});
|
||||
String? stickerPackId,
|
||||
bool excludeFromStreamManagement});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@ -344,6 +354,7 @@ class __$$_StanzaHandlerDataCopyWithImpl<$Res>
|
||||
Object? lastMessageCorrectionSid = freezed,
|
||||
Object? messageReactions = freezed,
|
||||
Object? stickerPackId = freezed,
|
||||
Object? excludeFromStreamManagement = null,
|
||||
}) {
|
||||
return _then(_$_StanzaHandlerData(
|
||||
null == done
|
||||
@ -454,6 +465,10 @@ class __$$_StanzaHandlerDataCopyWithImpl<$Res>
|
||||
? _value.stickerPackId
|
||||
: stickerPackId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
excludeFromStreamManagement: null == excludeFromStreamManagement
|
||||
? _value.excludeFromStreamManagement
|
||||
: excludeFromStreamManagement // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -484,7 +499,8 @@ class _$_StanzaHandlerData implements _StanzaHandlerData {
|
||||
this.messageRetraction,
|
||||
this.lastMessageCorrectionSid,
|
||||
this.messageReactions,
|
||||
this.stickerPackId})
|
||||
this.stickerPackId,
|
||||
this.excludeFromStreamManagement = false})
|
||||
: _stanzaIds = stanzaIds,
|
||||
_other = other;
|
||||
|
||||
@ -595,10 +611,15 @@ class _$_StanzaHandlerData implements _StanzaHandlerData {
|
||||
// The Id of the sticker pack this sticker belongs to
|
||||
@override
|
||||
final String? stickerPackId;
|
||||
// Flag indicating whether the stanza should be excluded from stream management's
|
||||
// resending behaviour
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool excludeFromStreamManagement;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'StanzaHandlerData(done: $done, cancel: $cancel, cancelReason: $cancelReason, stanza: $stanza, retransmitted: $retransmitted, sims: $sims, sfs: $sfs, oob: $oob, originId: $originId, stanzaIds: $stanzaIds, reply: $reply, chatState: $chatState, isCarbon: $isCarbon, deliveryReceiptRequested: $deliveryReceiptRequested, isMarkable: $isMarkable, fun: $fun, funReplacement: $funReplacement, funCancellation: $funCancellation, encrypted: $encrypted, forceEncryption: $forceEncryption, encryptionType: $encryptionType, delayedDelivery: $delayedDelivery, other: $other, messageRetraction: $messageRetraction, lastMessageCorrectionSid: $lastMessageCorrectionSid, messageReactions: $messageReactions, stickerPackId: $stickerPackId)';
|
||||
return 'StanzaHandlerData(done: $done, cancel: $cancel, cancelReason: $cancelReason, stanza: $stanza, retransmitted: $retransmitted, sims: $sims, sfs: $sfs, oob: $oob, originId: $originId, stanzaIds: $stanzaIds, reply: $reply, chatState: $chatState, isCarbon: $isCarbon, deliveryReceiptRequested: $deliveryReceiptRequested, isMarkable: $isMarkable, fun: $fun, funReplacement: $funReplacement, funCancellation: $funCancellation, encrypted: $encrypted, forceEncryption: $forceEncryption, encryptionType: $encryptionType, delayedDelivery: $delayedDelivery, other: $other, messageRetraction: $messageRetraction, lastMessageCorrectionSid: $lastMessageCorrectionSid, messageReactions: $messageReactions, stickerPackId: $stickerPackId, excludeFromStreamManagement: $excludeFromStreamManagement)';
|
||||
}
|
||||
|
||||
@override
|
||||
@ -652,7 +673,11 @@ class _$_StanzaHandlerData implements _StanzaHandlerData {
|
||||
(identical(other.messageReactions, messageReactions) ||
|
||||
other.messageReactions == messageReactions) &&
|
||||
(identical(other.stickerPackId, stickerPackId) ||
|
||||
other.stickerPackId == stickerPackId));
|
||||
other.stickerPackId == stickerPackId) &&
|
||||
(identical(other.excludeFromStreamManagement,
|
||||
excludeFromStreamManagement) ||
|
||||
other.excludeFromStreamManagement ==
|
||||
excludeFromStreamManagement));
|
||||
}
|
||||
|
||||
@override
|
||||
@ -684,7 +709,8 @@ class _$_StanzaHandlerData implements _StanzaHandlerData {
|
||||
messageRetraction,
|
||||
lastMessageCorrectionSid,
|
||||
messageReactions,
|
||||
stickerPackId
|
||||
stickerPackId,
|
||||
excludeFromStreamManagement
|
||||
]);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@ -720,7 +746,8 @@ abstract class _StanzaHandlerData implements StanzaHandlerData {
|
||||
final MessageRetractionData? messageRetraction,
|
||||
final String? lastMessageCorrectionSid,
|
||||
final MessageReactions? messageReactions,
|
||||
final String? stickerPackId}) = _$_StanzaHandlerData;
|
||||
final String? stickerPackId,
|
||||
final bool excludeFromStreamManagement}) = _$_StanzaHandlerData;
|
||||
|
||||
@override // Indicates to the runner that processing is now done. This means that all
|
||||
// pre-processing is done and no other handlers should be consulted.
|
||||
@ -786,6 +813,9 @@ abstract class _StanzaHandlerData implements StanzaHandlerData {
|
||||
MessageReactions? get messageReactions;
|
||||
@override // The Id of the sticker pack this sticker belongs to
|
||||
String? get stickerPackId;
|
||||
@override // Flag indicating whether the stanza should be excluded from stream management's
|
||||
// resending behaviour
|
||||
bool get excludeFromStreamManagement;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$_StanzaHandlerDataCopyWith<_$_StanzaHandlerData> get copyWith =>
|
||||
|
@ -112,24 +112,48 @@ class PresenceManager extends XmppManagerBase {
|
||||
}
|
||||
|
||||
/// Send an unavailable presence with no 'to' attribute.
|
||||
void sendUnavailablePresence() {
|
||||
getAttributes().sendStanza(
|
||||
Future<void> sendUnavailablePresence() async {
|
||||
// Bypass the queue so that this get's sent immediately.
|
||||
// If we do it like this, we can also block the disconnection
|
||||
// until we're actually ready.
|
||||
await getAttributes().sendStanza(
|
||||
StanzaDetails(
|
||||
Stanza.presence(
|
||||
type: 'unavailable',
|
||||
),
|
||||
awaitable: false,
|
||||
bypassQueue: true,
|
||||
excludeFromStreamManagement: true,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Sends a subscription request to [to].
|
||||
// TODO(PapaTutuWawa): Check if we're allowed to pre-approve
|
||||
Future<void> requestSubscription(JID to, {bool preApprove = false}) async {
|
||||
await getAttributes().sendStanza(
|
||||
StanzaDetails(
|
||||
Stanza.presence(
|
||||
type: preApprove ? 'subscribed' : 'subscribe',
|
||||
to: to.toString(),
|
||||
),
|
||||
awaitable: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Sends a subscription request to [to].
|
||||
void sendSubscriptionRequest(String to) {
|
||||
getAttributes().sendStanza(
|
||||
/// Accept a subscription request from [to].
|
||||
Future<void> acceptSubscriptionRequest(JID to) async {
|
||||
await requestSubscription(to, preApprove: true);
|
||||
}
|
||||
|
||||
/// Send a subscription request rejection to [to].
|
||||
Future<void> rejectSubscriptionRequest(JID to) async {
|
||||
await getAttributes().sendStanza(
|
||||
StanzaDetails(
|
||||
Stanza.presence(
|
||||
type: 'subscribe',
|
||||
to: to,
|
||||
type: 'unsubscribed',
|
||||
to: to.toString(),
|
||||
),
|
||||
awaitable: false,
|
||||
),
|
||||
@ -137,38 +161,12 @@ class PresenceManager extends XmppManagerBase {
|
||||
}
|
||||
|
||||
/// Sends an unsubscription request to [to].
|
||||
void sendUnsubscriptionRequest(String to) {
|
||||
getAttributes().sendStanza(
|
||||
Future<void> unsubscribe(JID to) async {
|
||||
await getAttributes().sendStanza(
|
||||
StanzaDetails(
|
||||
Stanza.presence(
|
||||
type: 'unsubscribe',
|
||||
to: to,
|
||||
),
|
||||
awaitable: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Accept a presence subscription request for [to].
|
||||
void sendSubscriptionRequestApproval(String to) {
|
||||
getAttributes().sendStanza(
|
||||
StanzaDetails(
|
||||
Stanza.presence(
|
||||
type: 'subscribed',
|
||||
to: to,
|
||||
),
|
||||
awaitable: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Reject a presence subscription request for [to].
|
||||
void sendSubscriptionRequestRejection(String to) {
|
||||
getAttributes().sendStanza(
|
||||
StanzaDetails(
|
||||
Stanza.presence(
|
||||
type: 'unsubscribed',
|
||||
to: to,
|
||||
to: to.toString(),
|
||||
),
|
||||
awaitable: false,
|
||||
),
|
||||
|
@ -223,15 +223,21 @@ class RosterManager extends XmppManagerBase {
|
||||
return Result(result);
|
||||
}
|
||||
|
||||
/// Requests the roster following RFC 6121.
|
||||
Future<Result<RosterRequestResult, RosterError>> requestRoster() async {
|
||||
/// Requests the roster following RFC 6121. If [useRosterVersion] is set to false, then
|
||||
/// roster versioning will not be used, even if the server supports it and we have a last
|
||||
/// known roster version.
|
||||
Future<Result<RosterRequestResult, RosterError>> requestRoster({
|
||||
bool useRosterVersion = true,
|
||||
}) async {
|
||||
final attrs = getAttributes();
|
||||
final query = XMLNode.xmlns(
|
||||
tag: 'query',
|
||||
xmlns: rosterXmlns,
|
||||
);
|
||||
final rosterVersion = await _stateManager.getRosterVersion();
|
||||
if (rosterVersion != null && rosterVersioningAvailable()) {
|
||||
if (rosterVersion != null &&
|
||||
rosterVersioningAvailable() &&
|
||||
useRosterVersion) {
|
||||
query.attributes['ver'] = rosterVersion;
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,8 @@ class StanzaDetails {
|
||||
this.awaitable = true,
|
||||
this.encrypted = false,
|
||||
this.forceEncryption = false,
|
||||
this.bypassQueue = false,
|
||||
this.excludeFromStreamManagement = false,
|
||||
});
|
||||
|
||||
/// The stanza to send.
|
||||
@ -23,6 +25,16 @@ class StanzaDetails {
|
||||
final bool encrypted;
|
||||
|
||||
final bool forceEncryption;
|
||||
|
||||
/// Bypasses being put into the queue. Useful for sending stanzas that must go out
|
||||
/// now, where it's okay if it does not get sent.
|
||||
/// This should never have to be set to true.
|
||||
final bool bypassQueue;
|
||||
|
||||
/// This makes the Stream Management implementation, when available, ignore the stanza,
|
||||
/// meaning that it gets counted but excluded from resending.
|
||||
/// This should never have to be set to true.
|
||||
final bool excludeFromStreamManagement;
|
||||
}
|
||||
|
||||
/// A simple description of the <error /> element that may be inside a stanza
|
||||
|
@ -66,11 +66,7 @@ class VCardManager extends XmppManagerBase {
|
||||
final binval = vcardResult.get<VCard>().photo?.binval;
|
||||
if (binval != null) {
|
||||
getAttributes().sendEvent(
|
||||
AvatarUpdatedEvent(
|
||||
jid: from,
|
||||
base64: binval,
|
||||
hash: hash,
|
||||
),
|
||||
VCardAvatarUpdatedEvent(JID.fromString(from), binval, hash),
|
||||
);
|
||||
} else {
|
||||
logger.warning('No avatar data found');
|
||||
|
@ -179,13 +179,13 @@ class PubSubManager extends XmppManagerBase {
|
||||
return options;
|
||||
}
|
||||
|
||||
Future<Result<PubSubError, bool>> subscribe(String jid, String node) async {
|
||||
Future<Result<PubSubError, bool>> subscribe(JID jid, String node) async {
|
||||
final attrs = getAttributes();
|
||||
final result = (await attrs.sendStanza(
|
||||
StanzaDetails(
|
||||
Stanza.iq(
|
||||
type: 'set',
|
||||
to: jid,
|
||||
to: jid.toString(),
|
||||
children: [
|
||||
XMLNode.xmlns(
|
||||
tag: 'pubsub',
|
||||
@ -222,13 +222,13 @@ class PubSubManager extends XmppManagerBase {
|
||||
return Result(subscription.attributes['subscription'] == 'subscribed');
|
||||
}
|
||||
|
||||
Future<Result<PubSubError, bool>> unsubscribe(String jid, String node) async {
|
||||
Future<Result<PubSubError, bool>> unsubscribe(JID jid, String node) async {
|
||||
final attrs = getAttributes();
|
||||
final result = (await attrs.sendStanza(
|
||||
StanzaDetails(
|
||||
Stanza.iq(
|
||||
type: 'set',
|
||||
to: jid,
|
||||
to: jid.toString(),
|
||||
children: [
|
||||
XMLNode.xmlns(
|
||||
tag: 'pubsub',
|
||||
@ -398,14 +398,14 @@ class PubSubManager extends XmppManagerBase {
|
||||
}
|
||||
|
||||
Future<Result<PubSubError, List<PubSubItem>>> getItems(
|
||||
String jid,
|
||||
JID jid,
|
||||
String node,
|
||||
) async {
|
||||
final result = (await getAttributes().sendStanza(
|
||||
StanzaDetails(
|
||||
Stanza.iq(
|
||||
type: 'get',
|
||||
to: jid,
|
||||
to: jid.toString(),
|
||||
children: [
|
||||
XMLNode.xmlns(
|
||||
tag: 'pubsub',
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'dart:convert';
|
||||
import 'package:moxxmpp/src/events.dart';
|
||||
import 'package:moxxmpp/src/jid.dart';
|
||||
import 'package:moxxmpp/src/managers/base.dart';
|
||||
@ -15,10 +16,17 @@ abstract class AvatarError {}
|
||||
|
||||
class UnknownAvatarError extends AvatarError {}
|
||||
|
||||
class UserAvatar {
|
||||
const UserAvatar({required this.base64, required this.hash});
|
||||
class UserAvatarData {
|
||||
const UserAvatarData(this.base64, this.hash);
|
||||
|
||||
/// The base64-encoded avatar data.
|
||||
final String base64;
|
||||
|
||||
/// The SHA-1 hash of the raw avatar data.
|
||||
final String hash;
|
||||
|
||||
/// The raw avatar data.
|
||||
List<int> get data => base64Decode(base64);
|
||||
}
|
||||
|
||||
class UserAvatarMetadata {
|
||||
@ -27,21 +35,44 @@ class UserAvatarMetadata {
|
||||
this.length,
|
||||
this.width,
|
||||
this.height,
|
||||
this.mime,
|
||||
this.type,
|
||||
this.url,
|
||||
);
|
||||
|
||||
/// The amount of bytes in the file
|
||||
factory UserAvatarMetadata.fromXML(XMLNode node) {
|
||||
assert(
|
||||
node.tag == 'metadata' &&
|
||||
node.attributes['xmlns'] == userAvatarMetadataXmlns,
|
||||
'<metadata /> element required',
|
||||
);
|
||||
|
||||
final width = node.attributes['width'] as String?;
|
||||
final height = node.attributes['height'] as String?;
|
||||
return UserAvatarMetadata(
|
||||
node.attributes['id']! as String,
|
||||
int.parse(node.attributes['bytes']! as String),
|
||||
width != null ? int.parse(width) : null,
|
||||
height != null ? int.parse(height) : null,
|
||||
node.attributes['type']! as String,
|
||||
node.attributes['url'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
/// The amount of bytes in the file.
|
||||
final int length;
|
||||
|
||||
/// The identifier of the avatar
|
||||
/// The identifier of the avatar.
|
||||
final String id;
|
||||
|
||||
/// Image proportions
|
||||
final int width;
|
||||
final int height;
|
||||
/// Image proportions.
|
||||
final int? width;
|
||||
final int? height;
|
||||
|
||||
/// The MIME type of the avatar
|
||||
final String mime;
|
||||
/// The URL where the avatar can be found.
|
||||
final String? url;
|
||||
|
||||
/// The MIME type of the avatar.
|
||||
final String type;
|
||||
}
|
||||
|
||||
/// NOTE: This class requires a PubSubManager
|
||||
@ -51,13 +82,18 @@ class UserAvatarManager extends XmppManagerBase {
|
||||
PubSubManager _getPubSubManager() =>
|
||||
getAttributes().getManagerById(pubsubManager)! as PubSubManager;
|
||||
|
||||
@override
|
||||
List<String> getDiscoFeatures() => [
|
||||
'$userAvatarMetadataXmlns+notify',
|
||||
];
|
||||
|
||||
@override
|
||||
Future<void> onXmppEvent(XmppEvent event) async {
|
||||
if (event is PubSubNotificationEvent) {
|
||||
if (event.item.node != userAvatarDataXmlns) return;
|
||||
if (event.item.node != userAvatarMetadataXmlns) return;
|
||||
|
||||
if (event.item.payload.tag != 'data' ||
|
||||
event.item.payload.attributes['xmlns'] != userAvatarDataXmlns) {
|
||||
if (event.item.payload.tag != 'metadata' ||
|
||||
event.item.payload.attributes['xmlns'] != userAvatarMetadataXmlns) {
|
||||
logger.warning(
|
||||
'Received avatar update from ${event.from} but the payload is invalid. Ignoring...',
|
||||
);
|
||||
@ -65,10 +101,12 @@ class UserAvatarManager extends XmppManagerBase {
|
||||
}
|
||||
|
||||
getAttributes().sendEvent(
|
||||
AvatarUpdatedEvent(
|
||||
jid: event.from,
|
||||
base64: event.item.payload.innerText(),
|
||||
hash: event.item.id,
|
||||
UserAvatarUpdatedEvent(
|
||||
JID.fromString(event.from),
|
||||
event.item.payload
|
||||
.findTags('metadata', xmlns: userAvatarMetadataXmlns)
|
||||
.map(UserAvatarMetadata.fromXML)
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -80,7 +118,7 @@ class UserAvatarManager extends XmppManagerBase {
|
||||
|
||||
/// Requests the avatar from [jid]. Returns the avatar data if the request was
|
||||
/// successful. Null otherwise
|
||||
Future<Result<AvatarError, UserAvatar>> getUserAvatar(String jid) async {
|
||||
Future<Result<AvatarError, UserAvatarData>> getUserAvatar(JID jid) async {
|
||||
final pubsub = _getPubSubManager();
|
||||
final resultsRaw = await pubsub.getItems(jid, userAvatarDataXmlns);
|
||||
if (resultsRaw.isType<PubSubError>()) return Result(UnknownAvatarError());
|
||||
@ -90,9 +128,9 @@ class UserAvatarManager extends XmppManagerBase {
|
||||
|
||||
final item = results[0];
|
||||
return Result(
|
||||
UserAvatar(
|
||||
base64: item.payload.innerText(),
|
||||
hash: item.id,
|
||||
UserAvatarData(
|
||||
item.payload.innerText(),
|
||||
item.id,
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -146,7 +184,7 @@ class UserAvatarManager extends XmppManagerBase {
|
||||
'bytes': metadata.length.toString(),
|
||||
'height': metadata.height.toString(),
|
||||
'width': metadata.width.toString(),
|
||||
'type': metadata.mime,
|
||||
'type': metadata.type,
|
||||
'id': metadata.id,
|
||||
},
|
||||
),
|
||||
@ -163,14 +201,14 @@ class UserAvatarManager extends XmppManagerBase {
|
||||
}
|
||||
|
||||
/// Subscribe the data and metadata node of [jid].
|
||||
Future<Result<AvatarError, bool>> subscribe(String jid) async {
|
||||
Future<Result<AvatarError, bool>> subscribe(JID jid) async {
|
||||
await _getPubSubManager().subscribe(jid, userAvatarMetadataXmlns);
|
||||
|
||||
return const Result(true);
|
||||
}
|
||||
|
||||
/// Unsubscribe the data and metadata node of [jid].
|
||||
Future<Result<AvatarError, bool>> unsubscribe(String jid) async {
|
||||
Future<Result<AvatarError, bool>> unsubscribe(JID jid) async {
|
||||
await _getPubSubManager().subscribe(jid, userAvatarMetadataXmlns);
|
||||
|
||||
return const Result(true);
|
||||
|
@ -399,10 +399,12 @@ class StreamManagementManager extends XmppManagerBase {
|
||||
Stanza stanza,
|
||||
StanzaHandlerData state,
|
||||
) async {
|
||||
await _incrementC2S();
|
||||
_unackedStanzas[_state.c2s] = stanza;
|
||||
|
||||
if (isStreamManagementEnabled()) {
|
||||
await _incrementC2S();
|
||||
|
||||
if (state.excludeFromStreamManagement) return state;
|
||||
|
||||
_unackedStanzas[_state.c2s] = stanza;
|
||||
await _sendAckRequest();
|
||||
}
|
||||
|
||||
@ -414,6 +416,8 @@ class StreamManagementManager extends XmppManagerBase {
|
||||
_unackedStanzas.clear();
|
||||
|
||||
for (final stanza in stanzas) {
|
||||
logger
|
||||
.finest('Resending ${stanza.tag} with id ${stanza.attributes["id"]}');
|
||||
await getAttributes().sendStanza(
|
||||
StanzaDetails(
|
||||
stanza,
|
||||
|
@ -516,8 +516,7 @@ abstract class BaseOmemoManager extends XmppManagerBase {
|
||||
JID jid,
|
||||
) async {
|
||||
final pm = getAttributes().getManagerById<PubSubManager>(pubsubManager)!;
|
||||
final result =
|
||||
await pm.getItems(jid.toBare().toString(), omemoDevicesXmlns);
|
||||
final result = await pm.getItems(jid.toBare(), omemoDevicesXmlns);
|
||||
if (result.isType<PubSubError>()) return Result(UnknownOmemoError());
|
||||
return Result(result.get<List<PubSubItem>>().first.payload);
|
||||
}
|
||||
@ -543,7 +542,7 @@ abstract class BaseOmemoManager extends XmppManagerBase {
|
||||
) async {
|
||||
// TODO(Unknown): Should we query the device list first?
|
||||
final pm = getAttributes().getManagerById<PubSubManager>(pubsubManager)!;
|
||||
final bundlesRaw = await pm.getItems(jid.toString(), omemoBundlesXmlns);
|
||||
final bundlesRaw = await pm.getItems(jid, omemoBundlesXmlns);
|
||||
if (bundlesRaw.isType<PubSubError>()) return Result(UnknownOmemoError());
|
||||
|
||||
final bundles = bundlesRaw
|
||||
@ -639,7 +638,7 @@ abstract class BaseOmemoManager extends XmppManagerBase {
|
||||
/// Subscribes to the device list PubSub node of [jid].
|
||||
Future<void> subscribeToDeviceListImpl(String jid) async {
|
||||
final pm = getAttributes().getManagerById<PubSubManager>(pubsubManager)!;
|
||||
await pm.subscribe(jid, omemoDevicesXmlns);
|
||||
await pm.subscribe(JID.fromString(jid), omemoDevicesXmlns);
|
||||
}
|
||||
|
||||
/// Attempts to find out if [jid] supports omemo:2.
|
||||
|
Loading…
Reference in New Issue
Block a user