xmpp: Implement stream resumption

This commit is contained in:
PapaTutuWawa 2021-12-31 21:58:16 +01:00
parent c56aefab06
commit 86ff5350de
4 changed files with 34 additions and 21 deletions

View File

@ -222,6 +222,7 @@ class XmppConnection {
return true; return true;
} }
// Sends the initial presence to enable receiving messages
void _sendInitialPresence() { void _sendInitialPresence() {
this.sendStanza(Stanza.presence( this.sendStanza(Stanza.presence(
from: this.settings.jid.withResource(this._resource).toString(), from: this.settings.jid.withResource(this._resource).toString(),
@ -242,6 +243,7 @@ class XmppConnection {
return; return;
} }
// TODO: Otherwise they will be bounced
if (stanzaRaw.tag == "presence") return; if (stanzaRaw.tag == "presence") return;
final stanza = Stanza.fromXMLNode(stanzaRaw); final stanza = Stanza.fromXMLNode(stanzaRaw);
@ -262,17 +264,6 @@ class XmppConnection {
handleUnhandledStanza(this, stanza); handleUnhandledStanza(this, stanza);
} }
void handleSaslResult(AuthenticationResult result) {
switch (result) {
case AuthenticationResult.SUCCESS: this._routingState = RoutingState.CHECK_STREAM_MANAGEMENT;
break;
case AuthenticationResult.FAILURE: this._routingState = RoutingState.ERROR;
break;
case AuthenticationResult.NOT_DONE:
break;
}
}
void handleXmlStream(XMLNode node) async { void handleXmlStream(XMLNode node) async {
print("(xml) <== " + node.toXml()); print("(xml) <== " + node.toXml());
@ -317,6 +308,9 @@ class XmppConnection {
if (result == AuthenticationResult.SUCCESS) { if (result == AuthenticationResult.SUCCESS) {
this._routingState = RoutingState.CHECK_STREAM_MANAGEMENT; this._routingState = RoutingState.CHECK_STREAM_MANAGEMENT;
this._sendStreamHeader(); this._sendStreamHeader();
} else if (result == AuthenticationResult.FAILURE) {
print("SASL failed");
this._routingState = RoutingState.ERROR;
} }
} }
break; break;
@ -326,6 +320,9 @@ class XmppConnection {
if (result == AuthenticationResult.SUCCESS) { if (result == AuthenticationResult.SUCCESS) {
this._routingState = RoutingState.CHECK_STREAM_MANAGEMENT; this._routingState = RoutingState.CHECK_STREAM_MANAGEMENT;
this._sendStreamHeader(); this._sendStreamHeader();
} else if (result == AuthenticationResult.FAILURE) {
print("SASL failed");
this._routingState = RoutingState.ERROR;
} }
} }
break; break;
@ -343,9 +340,11 @@ class XmppConnection {
if (this.streamFeatureSupported(SM_XMLNS)) { if (this.streamFeatureSupported(SM_XMLNS)) {
// Try to work with SM first // Try to work with SM first
if (/*this.settings.streamResumptionId != null*/ false) { if (this.settings.streamResumptionId != null) {
// Try to resume the last stream // Try to resume the last stream
// TODO // TODO
this._routingState = RoutingState.PERFORM_STREAM_RESUMPTION;
this.sendRawXML(StreamManagementResumeNonza(this.settings.streamResumptionId!, 0 /*TODO*/));
} else { } else {
// Try to enable SM // Try to enable SM
this._routingState = RoutingState.BIND_RESOURCE_PRE_SM; this._routingState = RoutingState.BIND_RESOURCE_PRE_SM;
@ -365,6 +364,20 @@ class XmppConnection {
} }
} }
break; break;
case RoutingState.PERFORM_STREAM_RESUMPTION: {
// TODO: Synchronize the h values
if (node.tag == "resumed") {
print("Stream Resumption successful!");
this._resource = this.settings.resource!;
this._routingState = RoutingState.HANDLE_STANZAS;
this._setConnectionState(ConnectionState.CONNECTED);
} else if (node.tag == "failed") {
print("Stream resumption failed. Proceeding with new stream...");
this._routingState = RoutingState.BIND_RESOURCE_PRE_SM;
this._performResourceBinding();
}
}
break;
case RoutingState.ENABLE_SM: { case RoutingState.ENABLE_SM: {
if (node.tag == "failed") { if (node.tag == "failed") {
// Not critical // Not critical
@ -374,11 +387,10 @@ class XmppConnection {
} else if (node.tag == "enabled") { } else if (node.tag == "enabled") {
print("SM enabled!"); print("SM enabled!");
// TODO: Assuming that having the ID implies that we can resume
final id = node.attributes["id"]; final id = node.attributes["id"];
if (id != null) { if (id != null && [ "true", "1" ].indexOf(node.attributes["resume"]) != -1) {
print("Stream resumption possible!"); print("Stream resumption possible!");
this.sendEvent(StreamResumptionEvent(id: id)); this.sendEvent(StreamResumptionEvent(id: id, resource: this._resource));
} }
this.streamManager = StreamManager(connection: this, streamResumptionId: id); this.streamManager = StreamManager(connection: this, streamResumptionId: id);

View File

@ -32,7 +32,8 @@ class ChatMarkerEvent extends XmppEvent {
// Triggered when we received a Stream resumption ID // Triggered when we received a Stream resumption ID
class StreamResumptionEvent extends XmppEvent { class StreamResumptionEvent extends XmppEvent {
final String resource;
final String id; final String id;
StreamResumptionEvent({ required this.id }); StreamResumptionEvent({ required this.id, required this.resource });
} }

View File

@ -6,6 +6,7 @@ class ConnectionSettings {
final bool useDirectTLS; final bool useDirectTLS;
final bool allowPlainAuth; final bool allowPlainAuth;
final String? streamResumptionId; final String? streamResumptionId;
final String? resource;
ConnectionSettings({ required this.jid, required this.password, required this.useDirectTLS, required this.allowPlainAuth, this.streamResumptionId }); ConnectionSettings({ required this.jid, required this.password, required this.useDirectTLS, required this.allowPlainAuth, this.streamResumptionId, this.resource });
} }

View File

@ -28,8 +28,7 @@
<implements> <implements>
<xmpp:SupportedXep> <xmpp:SupportedXep>
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0198.html" /> <xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0198.html" />
<xmpp:status>partial</xmpp:status> <xmpp:status>complete</xmpp:status>
<xmpp:note xml:lang="en">Stream-resumption not working</xmpp:note>
<xmpp:version>1.6</xmpp:version> <xmpp:version>1.6</xmpp:version>
</xmpp:SupportedXep> </xmpp:SupportedXep>
</implements> </implements>