git » sdk » commit 54cf537

Use iqCallee pattern rather than trigger for "iq"

author Stephen Paul Weber
2023-10-14 23:53:58 UTC
committer Stephen Paul Weber
2023-10-14 23:53:58 UTC
parent c887f7d7f632fe1d13eba19f2c637db26c42be7e

Use iqCallee pattern rather than trigger for "iq"

xmpp/Caps.hx +3 -9
xmpp/Client.hx +46 -51
xmpp/GenericStream.hx +8 -11
xmpp/Stanza.hx +5 -0
xmpp/streams/XmppJsStream.hx +22 -1

diff --git a/xmpp/Caps.hx b/xmpp/Caps.hx
index cc57ba8..b3fe1c1 100644
--- a/xmpp/Caps.hx
+++ b/xmpp/Caps.hx
@@ -41,21 +41,15 @@ class Caps {
 		this.features = features;
 	}
 
-	public function discoReply(stanza: Stanza):Stanza {
-		final reply = new Stanza("iq", {
-			type: "result",
-			id: stanza.attr.get("id"),
-			to: stanza.attr.get("from")
-		});
-		final query = reply.tag("query", { xmlns: "http://jabber.org/protocol/disco#info" });
+	public function discoReply():Stanza {
+		final query = new Stanza("query", { xmlns: "http://jabber.org/protocol/disco#info" });
 		for (identity in identities) {
 			identity.addToDisco(query);
 		}
 		for (feature in features) {
 			query.tag("feature", { "var": feature }).up();
 		}
-		query.up();
-		return reply;
+		return query;
 	}
 
 	public function addC(stanza: Stanza): Stanza {
diff --git a/xmpp/Client.hx b/xmpp/Client.hx
index d0b90d6..157409d 100644
--- a/xmpp/Client.hx
+++ b/xmpp/Client.hx
@@ -53,6 +53,10 @@ class Client extends xmpp.EventEmitter {
 		stream.on("status/online", this.onConnected);
 	}
 
+	public function accountId() {
+		return JID.parse(jid).asBare().asString();
+	}
+
 	public function start() {
 		persistence.getChats(jid, (protoChats) -> {
 			for (protoChat in protoChats) {
@@ -175,75 +179,73 @@ class Client extends xmpp.EventEmitter {
 			return EventUnhandled; // Allow others to get this event as well
 		});
 
-		this.stream.on("iq", function(event) {
-			final stanza:Stanza = event.stanza;
+		this.stream.onIq(Set, "jingle", "urn:xmpp:jingle:1", (stanza) -> {
 			final from = stanza.attr.get("from") == null ? null : JID.parse(stanza.attr.get("from"));
-
 			final jingle = stanza.getChild("jingle", "urn:xmpp:jingle:1");
-			if (stanza.attr.get("type") == "set" && jingle != null) {
-				// First, jingle requires useless replies to every iq
-				sendStanza(new Stanza("iq", { type: "result", to: stanza.attr.get("from"), id: stanza.attr.get("id") }));
-				final chat = getDirectChat(from.asBare().asString());
-				final session = chat.jingleSessions.get(jingle.attr.get("sid"));
-
-				if (jingle.attr.get("action") == "session-initiate") {
-					if (session != null) {
-						try {
-							chat.jingleSessions.set(session.sid, session.initiate(stanza));
-						} catch (e) {
-							chat.jingleSessions.remove(session.sid);
-						}
-					} else {
-						final newSession = xmpp.jingle.InitiatedSession.fromSessionInitiate(this, stanza);
-						chat.jingleSessions.set(newSession.sid, newSession);
-						chatActivity(chat);
-						newSession.ring();
-					}
-				}
+			final chat = getDirectChat(from.asBare().asString());
+			final session = chat.jingleSessions.get(jingle.attr.get("sid"));
 
-				if (session != null && jingle.attr.get("action") == "session-accept") {
+			if (jingle.attr.get("action") == "session-initiate") {
+				if (session != null) {
 					try {
 						chat.jingleSessions.set(session.sid, session.initiate(stanza));
 					} catch (e) {
-						trace("session-accept failed", e);
+						chat.jingleSessions.remove(session.sid);
 					}
+				} else {
+					final newSession = xmpp.jingle.InitiatedSession.fromSessionInitiate(this, stanza);
+					chat.jingleSessions.set(newSession.sid, newSession);
+					chatActivity(chat);
+					newSession.ring();
 				}
+			}
 
-				if (session != null && jingle.attr.get("action") == "session-terminate") {
-					session.terminate();
-					chat.jingleSessions.remove(jingle.attr.get("sid"));
+			if (session != null && jingle.attr.get("action") == "session-accept") {
+				try {
+					chat.jingleSessions.set(session.sid, session.initiate(stanza));
+				} catch (e) {
+					trace("session-accept failed", e);
 				}
+			}
 
-				if (session != null && jingle.attr.get("action") == "content-add") {
-					session.contentAdd(stanza);
-				}
+			if (session != null && jingle.attr.get("action") == "session-terminate") {
+				session.terminate();
+				chat.jingleSessions.remove(jingle.attr.get("sid"));
+			}
 
-				if (session != null && jingle.attr.get("action") == "content-accept") {
-					session.contentAccept(stanza);
-				}
+			if (session != null && jingle.attr.get("action") == "content-add") {
+				session.contentAdd(stanza);
+			}
 
-				if (session != null && jingle.attr.get("action") == "transport-info") {
-					session.transportInfo(stanza);
-				}
-				return EventHandled;
+			if (session != null && jingle.attr.get("action") == "content-accept") {
+				session.contentAccept(stanza);
 			}
 
-			if (stanza.attr.get("type") == "get" && stanza.getChild("query", "http://jabber.org/protocol/disco#info") != null) {
-				stream.sendStanza(caps.discoReply(stanza));
-				return EventHandled;
+			if (session != null && jingle.attr.get("action") == "transport-info") {
+				session.transportInfo(stanza);
 			}
 
+			// jingle requires useless replies to every iq
+			return IqResult;
+		});
+
+
+		this.stream.onIq(Get, "query", "http://jabber.org/protocol/disco#info", (stanza) -> {
+			return IqResultElement(caps.discoReply());
+		});
+
+		this.stream.onIq(Set, "query", "jabber:iq:roster", (stanza) -> {
 			if (
 				stanza.attr.get("from") != null &&
 				stanza.attr.get("from") != JID.parse(jid).domain
 			) {
-				return EventUnhandled;
+				return IqNoResult;
 			}
 
 			var roster = new RosterGet();
 			roster.handleResponse(stanza);
 			var items = roster.getResult();
-			if (items.length == 0) return EventUnhandled;
+			if (items.length == 0) return IqNoResult;
 
 			for (item in items) {
 				if (item.subscription != "remove") {
@@ -253,14 +255,7 @@ class Client extends xmpp.EventEmitter {
 			}
 			this.trigger("chats/update", chats);
 
-			var reply = new Stanza("iq", {
-				type: "result",
-				id: stanza.attr.get("id"),
-				to: stanza.attr.get("from")
-			});
-			sendStanza(reply);
-
-			return EventHandled;
+			return IqResult;
 		});
 
 		this.stream.on("presence", function(event) {
diff --git a/xmpp/GenericStream.hx b/xmpp/GenericStream.hx
index a1e8aea..f025879 100644
--- a/xmpp/GenericStream.hx
+++ b/xmpp/GenericStream.hx
@@ -3,6 +3,12 @@ package xmpp;
 import xmpp.Stanza;
 import xmpp.EventEmitter;
 
+enum IqResult {
+	IqResultElement(element:Stanza);
+	IqResult;
+	IqNoResult;
+}
+
 abstract class GenericStream extends EventEmitter {
 
 	public function new() {
@@ -14,6 +20,7 @@ abstract class GenericStream extends EventEmitter {
 	abstract public function connect(jid:String):Void;
 	abstract public function sendStanza(stanza:Stanza):Void;
 	abstract public function newId():String;
+	abstract public function onIq(type:IqRequestType, tag:String, xmlns:String, handler:(Stanza)->IqResult):Void;
 
 	public function sendIq(stanza:Stanza, callback:(stanza:Stanza)->Void):Void {
 		var id = newId();
@@ -37,17 +44,7 @@ abstract class GenericStream extends EventEmitter {
 					var id = stanza.attr.get("id");
 					trigger('iq-response/$id', { stanza: stanza });
 				} else {
-					if (trigger('iq', { stanza: stanza }) == EventUnhandled) {
-						var reply = new Stanza("iq", {
-							type: "error",
-							id: stanza.attr.get("id"),
-							to: stanza.attr.get("from")
-						})
-							.tag("error", { type: "cancel" })
-							.tag("service-unavailable", { xmlns: "urn:ietf:params:xml:ns:xmpp-stanzas" })
-							.up().up();
-						sendStanza(reply);
-					}
+					// These are handled by onIq instead
 				}
 			} else if (name == "message" || name == "presence") {
 				trigger(name, { stanza: stanza });
diff --git a/xmpp/Stanza.hx b/xmpp/Stanza.hx
index 7e10bb0..8916de4 100644
--- a/xmpp/Stanza.hx
+++ b/xmpp/Stanza.hx
@@ -278,3 +278,8 @@ class Stanza implements NodeInterface {
 		};
 	}
 }
+
+enum IqRequestType {
+	Get;
+	Set;
+}
diff --git a/xmpp/streams/XmppJsStream.hx b/xmpp/streams/XmppJsStream.hx
index 201e78c..1d85252 100644
--- a/xmpp/streams/XmppJsStream.hx
+++ b/xmpp/streams/XmppJsStream.hx
@@ -14,9 +14,13 @@ extern class XmppJsClient {
 	function start():Promise<Dynamic>;
 	function on(eventName:String, callback:(Dynamic)->Void):Void;
 	function send(stanza:XmppJsXml):Void;
+	var iqCallee:{
+		get: (String, String, ({stanza: XmppJsXml})->Any)->Void,
+		set: (String, String, ({stanza: XmppJsXml})->Any)->Void,
+	};
 }
 
-@:jsRequire("@xmpp/jid", "JID")
+@:jsRequire("@xmpp/jid", "jid")
 extern class XmppJsJID {
 	function new(jid:String);
 	function toString():String;
@@ -201,6 +205,23 @@ class XmppJsStream extends GenericStream {
 		return XmppJsId.id();
 	}
 
+	private function fromIqResult(result: IqResult): Any {
+		switch (result) {
+		case IqResultElement(el): return convertFromStanza(el);
+		case IqResult: return true;
+		case IqNoResult: return false;
+		}
+	}
+
+	public function onIq(type:IqRequestType, tag:String, xmlns:String, handler:(Stanza)->IqResult) {
+		switch (type) {
+		case Get:
+			client.iqCallee.get(xmlns, tag, (el) -> fromIqResult(handler(convertToStanza(el.stanza))));
+		case Set:
+			client.iqCallee.set(xmlns, tag, (el) -> fromIqResult(handler(convertToStanza(el.stanza))));
+		}
+	}
+
 	/* State handlers */
 
 	private function onOnline(event) {