From b354ca8d0a9773d8a16f49d50df84b61e8af18e8 Mon Sep 17 00:00:00 2001 From: "Alexander \"PapaTutuWawa" Date: Sun, 2 Apr 2023 13:39:43 +0200 Subject: [PATCH] feat(xep): Improve the ergonomics of Bind2 negotiators --- .../lib/src/xeps/xep_0198/negotiator.dart | 5 +- packages/moxxmpp/lib/src/xeps/xep_0280.dart | 62 +++++-------------- packages/moxxmpp/lib/src/xeps/xep_0352.dart | 6 +- packages/moxxmpp/lib/src/xeps/xep_0386.dart | 50 +++++++++++++-- packages/moxxmpp/test/xeps/xep_0280_test.dart | 4 +- packages/moxxmpp/test/xeps/xep_0352_test.dart | 4 ++ 6 files changed, 77 insertions(+), 54 deletions(-) diff --git a/packages/moxxmpp/lib/src/xeps/xep_0198/negotiator.dart b/packages/moxxmpp/lib/src/xeps/xep_0198/negotiator.dart index 48497f3..daa00b3 100644 --- a/packages/moxxmpp/lib/src/xeps/xep_0198/negotiator.dart +++ b/packages/moxxmpp/lib/src/xeps/xep_0198/negotiator.dart @@ -28,7 +28,7 @@ enum _StreamManagementNegotiatorState { /// StreamManagementManager at least once before connecting, if stream resumption /// is wanted. class StreamManagementNegotiator extends Sasl2FeatureNegotiator - implements Bind2FeatureNegotiator { + implements Bind2FeatureNegotiatorInterface { StreamManagementNegotiator() : super(10, false, smXmlns, streamManagementNegotiator); @@ -256,6 +256,9 @@ class StreamManagementNegotiator extends Sasl2FeatureNegotiator ]; } + @override + Future onBind2Success(XMLNode response) async {} + @override Future> onSasl2FeaturesReceived(XMLNode sasl2Features) async { final inline = sasl2Features.firstTag('inline')!; diff --git a/packages/moxxmpp/lib/src/xeps/xep_0280.dart b/packages/moxxmpp/lib/src/xeps/xep_0280.dart index f3efc24..3153dd1 100644 --- a/packages/moxxmpp/lib/src/xeps/xep_0280.dart +++ b/packages/moxxmpp/lib/src/xeps/xep_0280.dart @@ -9,11 +9,8 @@ import 'package:moxxmpp/src/managers/handlers.dart'; import 'package:moxxmpp/src/managers/namespaces.dart'; import 'package:moxxmpp/src/namespaces.dart'; import 'package:moxxmpp/src/negotiators/namespaces.dart'; -import 'package:moxxmpp/src/negotiators/negotiator.dart'; -import 'package:moxxmpp/src/negotiators/sasl2.dart'; import 'package:moxxmpp/src/stanza.dart'; import 'package:moxxmpp/src/stringxml.dart'; -import 'package:moxxmpp/src/types/result.dart'; import 'package:moxxmpp/src/xeps/xep_0030/xep_0030.dart'; import 'package:moxxmpp/src/xeps/xep_0297.dart'; import 'package:moxxmpp/src/xeps/xep_0386.dart'; @@ -202,9 +199,8 @@ class CarbonsManager extends XmppManagerBase { } } -class CarbonsNegotiator extends Sasl2FeatureNegotiator - implements Bind2FeatureNegotiator { - CarbonsNegotiator() : super(0, false, carbonsXmlns, carbonsNegotiator); +class CarbonsNegotiator extends Bind2FeatureNegotiator { + CarbonsNegotiator() : super(0, carbonsXmlns, carbonsNegotiator); /// Flag indicating whether we requested to enable carbons inline (true) or not /// (false). @@ -214,42 +210,26 @@ class CarbonsNegotiator extends Sasl2FeatureNegotiator final Logger _log = Logger('CarbonsNegotiator'); @override - bool canInlineFeature(List features) => true; - - @override - Future> onSasl2FeaturesReceived(XMLNode sasl2Features) async { - return []; - } - - @override - Future> onSasl2Success(XMLNode response) async { - if (_requestedEnablement) { - final enabled = response - .firstTag('bound', xmlns: bind2Xmlns) - ?.firstTag('enabled', xmlns: carbonsXmlns); - final cm = attributes.getManagerById(carbonsManager)!; - if (enabled != null) { - _log.finest('Successfully enabled Message Carbons inline'); - cm.setEnabled(); - } else { - _log.warning('Failed to enable Message Carbons inline'); - cm.setDisabled(); - } + Future onBind2Success(XMLNode response) async { + if (!_requestedEnablement) { + return; } - return const Result(true); - } - - @override - Future> negotiate( - XMLNode nonza, - ) async { - return const Result(NegotiatorState.done); + final enabled = response.firstTag('enabled', xmlns: carbonsXmlns); + final cm = attributes.getManagerById(carbonsManager)!; + if (enabled != null) { + _log.finest('Successfully enabled Message Carbons inline'); + cm.setEnabled(); + } else { + _log.warning('Failed to enable Message Carbons inline'); + cm.setDisabled(); + } } @override Future> onBind2FeaturesReceived( - List bind2Features) async { + List bind2Features, + ) async { if (!bind2Features.contains(carbonsXmlns)) { return []; } @@ -263,16 +243,6 @@ class CarbonsNegotiator extends Sasl2FeatureNegotiator ]; } - @override - Future postRegisterCallback() async { - attributes - .getNegotiatorById(sasl2Negotiator) - ?.registerNegotiator(this); - attributes - .getNegotiatorById(bind2Negotiator) - ?.registerNegotiator(this); - } - @override void reset() { _requestedEnablement = false; diff --git a/packages/moxxmpp/lib/src/xeps/xep_0352.dart b/packages/moxxmpp/lib/src/xeps/xep_0352.dart index 1c339df..718d805 100644 --- a/packages/moxxmpp/lib/src/xeps/xep_0352.dart +++ b/packages/moxxmpp/lib/src/xeps/xep_0352.dart @@ -25,7 +25,7 @@ class CSIInactiveNonza extends XMLNode { /// A Stub negotiator that is just for "intercepting" the stream feature. class CSINegotiator extends XmppFeatureNegotiatorBase - implements Bind2FeatureNegotiator { + implements Bind2FeatureNegotiatorInterface { CSINegotiator() : super(11, false, csiXmlns, csiNegotiator); /// True if CSI is supported. False otherwise. @@ -50,12 +50,16 @@ class CSINegotiator extends XmppFeatureNegotiatorBase return []; } + _supported = true; final active = attributes.getManagerById(csiManager)!.isActive; return [ if (active) CSIActiveNonza() else CSIInactiveNonza(), ]; } + @override + Future onBind2Success(XMLNode response) async {} + @override void reset() { _supported = false; diff --git a/packages/moxxmpp/lib/src/xeps/xep_0386.dart b/packages/moxxmpp/lib/src/xeps/xep_0386.dart index 60691b3..09550d9 100644 --- a/packages/moxxmpp/lib/src/xeps/xep_0386.dart +++ b/packages/moxxmpp/lib/src/xeps/xep_0386.dart @@ -1,4 +1,5 @@ import 'package:collection/collection.dart'; +import 'package:meta/meta.dart'; import 'package:moxxmpp/src/namespaces.dart'; import 'package:moxxmpp/src/negotiators/namespaces.dart'; import 'package:moxxmpp/src/negotiators/negotiator.dart'; @@ -9,10 +10,43 @@ import 'package:moxxmpp/src/types/result.dart'; /// An interface that allows registering against Bind2's feature list in order to /// negotiate features inline with Bind2. // ignore: one_member_abstracts -abstract class Bind2FeatureNegotiator { +abstract class Bind2FeatureNegotiatorInterface { /// Called by the Bind2 negotiator when Bind2 features are received. The returned /// [XMLNode]s are added to Bind2's bind request. Future> onBind2FeaturesReceived(List bind2Features); + + /// Called by the Bind2 negotiator when Bind2 results are received. + Future onBind2Success(XMLNode result); +} + +/// A class that allows for simple negotiators that only registers itself against +/// the Bind2 negotiator. You only have to implement the functions required by +/// [Bind2FeatureNegotiatorInterface]. +abstract class Bind2FeatureNegotiator extends XmppFeatureNegotiatorBase + implements Bind2FeatureNegotiatorInterface { + Bind2FeatureNegotiator( + int priority, + String negotiatingXmlns, + String id, + ) : super(priority, false, negotiatingXmlns, id); + + @override + bool matchesFeature(List features) => false; + + @override + Future> negotiate( + XMLNode nonza, + ) async { + return const Result(NegotiatorState.done); + } + + @mustCallSuper + @override + Future postRegisterCallback() async { + attributes + .getNegotiatorById(bind2Negotiator)! + .registerNegotiator(this); + } } /// A negotiator implementing XEP-0386. This negotiator is useless on its own @@ -21,15 +55,15 @@ class Bind2Negotiator extends Sasl2FeatureNegotiator { Bind2Negotiator() : super(0, false, bind2Xmlns, bind2Negotiator); /// A list of negotiators that can work with Bind2. - final List _negotiators = - List.empty(growable: true); + final List _negotiators = + List.empty(growable: true); /// A tag to sent to the server when requesting Bind2. String? tag; /// Register [negotiator] against the Bind2 negotiator to append data to the Bind2 /// negotiation. - void registerNegotiator(Bind2FeatureNegotiator negotiator) { + void registerNegotiator(Bind2FeatureNegotiatorInterface negotiator) { _negotiators.add(negotiator); } @@ -87,8 +121,14 @@ class Bind2Negotiator extends Sasl2FeatureNegotiator { @override Future> onSasl2Success(XMLNode response) async { - attributes.removeNegotiatingFeature(bindXmlns); + final bound = response.firstTag('bound', xmlns: bind2Xmlns); + if (bound != null) { + for (final negotiator in _negotiators) { + await negotiator.onBind2Success(bound); + } + } + attributes.removeNegotiatingFeature(bindXmlns); return const Result(true); } diff --git a/packages/moxxmpp/test/xeps/xep_0280_test.dart b/packages/moxxmpp/test/xeps/xep_0280_test.dart index c29c751..1f9bf6d 100644 --- a/packages/moxxmpp/test/xeps/xep_0280_test.dart +++ b/packages/moxxmpp/test/xeps/xep_0280_test.dart @@ -141,6 +141,8 @@ void main() { expect(result.isType(), false); expect(conn.resource, 'test-resource'); expect( - conn.getManagerById(carbonsManager)!.isEnabled, true); + conn.getManagerById(carbonsManager)!.isEnabled, + true, + ); }); } diff --git a/packages/moxxmpp/test/xeps/xep_0352_test.dart b/packages/moxxmpp/test/xeps/xep_0352_test.dart index 15192b1..67b2fbe 100644 --- a/packages/moxxmpp/test/xeps/xep_0352_test.dart +++ b/packages/moxxmpp/test/xeps/xep_0352_test.dart @@ -204,5 +204,9 @@ void main() { ); expect(result.isType(), false); expect(fakeSocket.getState(), 2); + expect( + conn.getNegotiatorById(csiNegotiator)!.isSupported, + true, + ); }); }