feat(xep): Improve the ergonomics of Bind2 negotiators

This commit is contained in:
PapaTutuWawa 2023-04-02 13:39:43 +02:00
parent ec6b5ab753
commit b354ca8d0a
6 changed files with 77 additions and 54 deletions

View File

@ -28,7 +28,7 @@ enum _StreamManagementNegotiatorState {
/// StreamManagementManager at least once before connecting, if stream resumption /// StreamManagementManager at least once before connecting, if stream resumption
/// is wanted. /// is wanted.
class StreamManagementNegotiator extends Sasl2FeatureNegotiator class StreamManagementNegotiator extends Sasl2FeatureNegotiator
implements Bind2FeatureNegotiator { implements Bind2FeatureNegotiatorInterface {
StreamManagementNegotiator() StreamManagementNegotiator()
: super(10, false, smXmlns, streamManagementNegotiator); : super(10, false, smXmlns, streamManagementNegotiator);
@ -256,6 +256,9 @@ class StreamManagementNegotiator extends Sasl2FeatureNegotiator
]; ];
} }
@override
Future<void> onBind2Success(XMLNode response) async {}
@override @override
Future<List<XMLNode>> onSasl2FeaturesReceived(XMLNode sasl2Features) async { Future<List<XMLNode>> onSasl2FeaturesReceived(XMLNode sasl2Features) async {
final inline = sasl2Features.firstTag('inline')!; final inline = sasl2Features.firstTag('inline')!;

View File

@ -9,11 +9,8 @@ import 'package:moxxmpp/src/managers/handlers.dart';
import 'package:moxxmpp/src/managers/namespaces.dart'; import 'package:moxxmpp/src/managers/namespaces.dart';
import 'package:moxxmpp/src/namespaces.dart'; import 'package:moxxmpp/src/namespaces.dart';
import 'package:moxxmpp/src/negotiators/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/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/xeps/xep_0030/xep_0030.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_0297.dart';
import 'package:moxxmpp/src/xeps/xep_0386.dart'; import 'package:moxxmpp/src/xeps/xep_0386.dart';
@ -202,9 +199,8 @@ class CarbonsManager extends XmppManagerBase {
} }
} }
class CarbonsNegotiator extends Sasl2FeatureNegotiator class CarbonsNegotiator extends Bind2FeatureNegotiator {
implements Bind2FeatureNegotiator { CarbonsNegotiator() : super(0, carbonsXmlns, carbonsNegotiator);
CarbonsNegotiator() : super(0, false, carbonsXmlns, carbonsNegotiator);
/// Flag indicating whether we requested to enable carbons inline (true) or not /// Flag indicating whether we requested to enable carbons inline (true) or not
/// (false). /// (false).
@ -214,19 +210,12 @@ class CarbonsNegotiator extends Sasl2FeatureNegotiator
final Logger _log = Logger('CarbonsNegotiator'); final Logger _log = Logger('CarbonsNegotiator');
@override @override
bool canInlineFeature(List<XMLNode> features) => true; Future<void> onBind2Success(XMLNode response) async {
if (!_requestedEnablement) {
@override return;
Future<List<XMLNode>> onSasl2FeaturesReceived(XMLNode sasl2Features) async {
return [];
} }
@override final enabled = response.firstTag('enabled', xmlns: carbonsXmlns);
Future<Result<bool, NegotiatorError>> onSasl2Success(XMLNode response) async {
if (_requestedEnablement) {
final enabled = response
.firstTag('bound', xmlns: bind2Xmlns)
?.firstTag('enabled', xmlns: carbonsXmlns);
final cm = attributes.getManagerById<CarbonsManager>(carbonsManager)!; final cm = attributes.getManagerById<CarbonsManager>(carbonsManager)!;
if (enabled != null) { if (enabled != null) {
_log.finest('Successfully enabled Message Carbons inline'); _log.finest('Successfully enabled Message Carbons inline');
@ -237,19 +226,10 @@ class CarbonsNegotiator extends Sasl2FeatureNegotiator
} }
} }
return const Result(true);
}
@override
Future<Result<NegotiatorState, NegotiatorError>> negotiate(
XMLNode nonza,
) async {
return const Result(NegotiatorState.done);
}
@override @override
Future<List<XMLNode>> onBind2FeaturesReceived( Future<List<XMLNode>> onBind2FeaturesReceived(
List<String> bind2Features) async { List<String> bind2Features,
) async {
if (!bind2Features.contains(carbonsXmlns)) { if (!bind2Features.contains(carbonsXmlns)) {
return []; return [];
} }
@ -263,16 +243,6 @@ class CarbonsNegotiator extends Sasl2FeatureNegotiator
]; ];
} }
@override
Future<void> postRegisterCallback() async {
attributes
.getNegotiatorById<Sasl2Negotiator>(sasl2Negotiator)
?.registerNegotiator(this);
attributes
.getNegotiatorById<Bind2Negotiator>(bind2Negotiator)
?.registerNegotiator(this);
}
@override @override
void reset() { void reset() {
_requestedEnablement = false; _requestedEnablement = false;

View File

@ -25,7 +25,7 @@ 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
implements Bind2FeatureNegotiator { implements Bind2FeatureNegotiatorInterface {
CSINegotiator() : 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.
@ -50,12 +50,16 @@ class CSINegotiator extends XmppFeatureNegotiatorBase
return []; return [];
} }
_supported = true;
final active = attributes.getManagerById<CSIManager>(csiManager)!.isActive; final active = attributes.getManagerById<CSIManager>(csiManager)!.isActive;
return [ return [
if (active) CSIActiveNonza() else CSIInactiveNonza(), if (active) CSIActiveNonza() else CSIInactiveNonza(),
]; ];
} }
@override
Future<void> onBind2Success(XMLNode response) async {}
@override @override
void reset() { void reset() {
_supported = false; _supported = false;

View File

@ -1,4 +1,5 @@
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:meta/meta.dart';
import 'package:moxxmpp/src/namespaces.dart'; import 'package:moxxmpp/src/namespaces.dart';
import 'package:moxxmpp/src/negotiators/namespaces.dart'; import 'package:moxxmpp/src/negotiators/namespaces.dart';
import 'package:moxxmpp/src/negotiators/negotiator.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 /// An interface that allows registering against Bind2's feature list in order to
/// negotiate features inline with Bind2. /// negotiate features inline with Bind2.
// ignore: one_member_abstracts // ignore: one_member_abstracts
abstract class Bind2FeatureNegotiator { abstract class Bind2FeatureNegotiatorInterface {
/// Called by the Bind2 negotiator when Bind2 features are received. The returned /// Called by the Bind2 negotiator when Bind2 features are received. The returned
/// [XMLNode]s are added to Bind2's bind request. /// [XMLNode]s are added to Bind2's bind request.
Future<List<XMLNode>> onBind2FeaturesReceived(List<String> bind2Features); Future<List<XMLNode>> onBind2FeaturesReceived(List<String> bind2Features);
/// Called by the Bind2 negotiator when Bind2 results are received.
Future<void> 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<XMLNode> features) => false;
@override
Future<Result<NegotiatorState, NegotiatorError>> negotiate(
XMLNode nonza,
) async {
return const Result(NegotiatorState.done);
}
@mustCallSuper
@override
Future<void> postRegisterCallback() async {
attributes
.getNegotiatorById<Bind2Negotiator>(bind2Negotiator)!
.registerNegotiator(this);
}
} }
/// A negotiator implementing XEP-0386. This negotiator is useless on its own /// 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); Bind2Negotiator() : super(0, false, bind2Xmlns, bind2Negotiator);
/// A list of negotiators that can work with Bind2. /// A list of negotiators that can work with Bind2.
final List<Bind2FeatureNegotiator> _negotiators = final List<Bind2FeatureNegotiatorInterface> _negotiators =
List<Bind2FeatureNegotiator>.empty(growable: true); List<Bind2FeatureNegotiatorInterface>.empty(growable: true);
/// A tag to sent to the server when requesting Bind2. /// A tag to sent to the server when requesting Bind2.
String? tag; String? tag;
/// Register [negotiator] against the Bind2 negotiator to append data to the Bind2 /// Register [negotiator] against the Bind2 negotiator to append data to the Bind2
/// negotiation. /// negotiation.
void registerNegotiator(Bind2FeatureNegotiator negotiator) { void registerNegotiator(Bind2FeatureNegotiatorInterface negotiator) {
_negotiators.add(negotiator); _negotiators.add(negotiator);
} }
@ -87,8 +121,14 @@ class Bind2Negotiator extends Sasl2FeatureNegotiator {
@override @override
Future<Result<bool, NegotiatorError>> onSasl2Success(XMLNode response) async { Future<Result<bool, NegotiatorError>> 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); return const Result(true);
} }

View File

@ -141,6 +141,8 @@ void main() {
expect(result.isType<NegotiatorError>(), false); expect(result.isType<NegotiatorError>(), false);
expect(conn.resource, 'test-resource'); expect(conn.resource, 'test-resource');
expect( expect(
conn.getManagerById<CarbonsManager>(carbonsManager)!.isEnabled, true); conn.getManagerById<CarbonsManager>(carbonsManager)!.isEnabled,
true,
);
}); });
} }

View File

@ -204,5 +204,9 @@ void main() {
); );
expect(result.isType<NegotiatorError>(), false); expect(result.isType<NegotiatorError>(), false);
expect(fakeSocket.getState(), 2); expect(fakeSocket.getState(), 2);
expect(
conn.getNegotiatorById<CSINegotiator>(csiNegotiator)!.isSupported,
true,
);
}); });
} }