git » sdk » commit ab77cf7

Keep resource across connections

author Stephen Paul Weber
2023-09-25 17:05:54 UTC
committer Stephen Paul Weber
2023-09-25 17:10:23 UTC
parent 4b165cb856c5236eec193d49e302934e837d91c2

Keep resource across connections

xmpp/Client.hx +12 -2
xmpp/JID.hx +4 -0
xmpp/Persistence.hx +2 -0
xmpp/persistence/browser.js +32 -1
xmpp/streams/XmppJsStream.hx +6 -2

diff --git a/xmpp/Client.hx b/xmpp/Client.hx
index a271840..cd4eeca 100644
--- a/xmpp/Client.hx
+++ b/xmpp/Client.hx
@@ -31,11 +31,17 @@ class Client extends xmpp.EventEmitter {
 		this.persistence = persistence;
 		stream = new Stream();
 		stream.on("status/online", this.onConnected);
-		stream.on("auth/password-needed", (data)->this.trigger("auth/password-needed", { jid: this.jid }));
 	}
 
 	public function start() {
-		stream.connect(jid);
+		persistence.getLogin(jid, (login) -> {
+			if (login.token == null) {
+				stream.on("auth/password-needed", (data)->this.trigger("auth/password-needed", { jid: this.jid }));
+			} else {
+				stream.on("auth/password-needed", (data)->this.stream.trigger("auth/password", { password: login.token }));
+			}
+			stream.connect(login.clientId == null ? jid : jid + "/" + login.clientId);
+		});
 	}
 
 	public function addChatMessageListener(handler:ChatMessage->Void):Void {
@@ -43,6 +49,10 @@ class Client extends xmpp.EventEmitter {
 	}
 
 	private function onConnected(data) {
+		if (data != null && data.jid != null) {
+			final jidp = JID.parse(data.jid);
+			if (!jidp.isBare()) persistence.storeLogin(jidp.asBare().asString(), jidp.resource, null);
+		}
 		this.stream.on("message", function(event) {
 			final stanza:Stanza = event.stanza;
 			final chatMessage = ChatMessage.fromStanza(stanza, jid);
diff --git a/xmpp/JID.hx b/xmpp/JID.hx
index a4bd3a5..cedb018 100644
--- a/xmpp/JID.hx
+++ b/xmpp/JID.hx
@@ -62,6 +62,10 @@ class JID {
 		return node == null;
 	}
 
+	public function isBare():Bool {
+		return resource == null;
+	}
+
 	public function equals(rhs:JID):Bool {
 		return (
 			this.node == rhs.node &&
diff --git a/xmpp/Persistence.hx b/xmpp/Persistence.hx
index 39b2cbe..80bc318 100644
--- a/xmpp/Persistence.hx
+++ b/xmpp/Persistence.hx
@@ -11,4 +11,6 @@ abstract class Persistence {
 	abstract public function storeMedia(mime:String, bytes:BytesData, callback: ()->Void):Void;
 	abstract public function storeCaps(caps:Caps):Void;
 	abstract public function getCaps(ver:String, callback: (Caps)->Void):Void;
+	abstract public function storeLogin(login:String, clientId:String, token:Null<String>):Void;
+	abstract public function getLogin(login:String, callback:({ ?clientId: String, ?token: String })->Void):Void;
 }
diff --git a/xmpp/persistence/browser.js b/xmpp/persistence/browser.js
index 9a32d34..8522fe9 100644
--- a/xmpp/persistence/browser.js
+++ b/xmpp/persistence/browser.js
@@ -4,13 +4,14 @@
 exports.xmpp.persistence = {
 	browser: (dbname) => {
 		var db = null;
-		var dbOpenReq = indexedDB.open(dbname, 1);
+		var dbOpenReq = indexedDB.open(dbname);
 		dbOpenReq.onerror = console.error;
 		dbOpenReq.onupgradeneeded = (event) => {
 			const upgradeDb = event.target.result;
 			const store = upgradeDb.createObjectStore("messages", { keyPath: "serverId" });
 			store.createIndex("account", ["account", "timestamp"]);
 			store.createIndex("conversation", ["account", "conversation", "timestamp"]);
+			upgradeDb.createObjectStore("keyvaluepairs");
 		};
 		dbOpenReq.onsuccess = (event) => {
 			db = event.target.result;
@@ -24,6 +25,13 @@ exports.xmpp.persistence = {
 			return "/.well-known/ni/" + hashAlgorithm + "/" + b64url;
 		}
 
+		function promisifyRequest(request) {
+			return new Promise((resolve, reject) => {
+				request.oncomplete = request.onsuccess = () => resolve(request.result);
+				request.onabort = request.onerror = () => reject(request.error);
+			});
+		}
+
 		return {
 			lastId: function(account, jid, callback) {
 				const tx = db.transaction(["messages"], "readonly");
@@ -146,6 +154,29 @@ exports.xmpp.persistence = {
 				} else {
 					callback(null);
 				}
+			},
+
+			storeLogin: function(login, clientId, token) {
+				const tx = db.transaction(["keyvaluepairs"], "readwrite");
+				const store = tx.objectStore("keyvaluepairs");
+				store.put(clientId, "login:clientId:" + login).onerror = console.error;
+				if (token != null) store.put(token, "login:token:" + login).onerror = console.error;
+			},
+
+			getLogin: function(login, callback) {
+				const tx = db.transaction(["keyvaluepairs"], "readonly");
+				const store = tx.objectStore("keyvaluepairs");
+				Promise.all([
+					promisifyRequest(store.get("login:clientId:" + login)),
+					promisifyRequest(store.get("login:token:" + login))
+				]).then((result) => {
+					callback({
+						clientId: result[0],
+						token: result[1]
+					});
+				}).catch((e) => {
+					callback({});
+				});
 			}
 		}
 	}
diff --git a/xmpp/streams/XmppJsStream.hx b/xmpp/streams/XmppJsStream.hx
index 570afdb..1eb5a76 100644
--- a/xmpp/streams/XmppJsStream.hx
+++ b/xmpp/streams/XmppJsStream.hx
@@ -19,6 +19,7 @@ extern class XmppJsClient {
 @:jsRequire("@xmpp/jid", "JID")
 extern class XmppJsJID {
 	function new(jid:String);
+	function toString():String;
 
 	var local(default, set):String;
 	var domain(default, set):String;
@@ -49,6 +50,7 @@ extern class XmppJsLtx {
 	static function isNode(el:Dynamic):Bool;
 	static function isElement(el:Dynamic):Bool;
 	static function isText(el:Dynamic):Bool;
+	static function parse(input:String):XmppJsXml;
 }
 
 @:jsRequire("@xmpp/id")
@@ -124,6 +126,7 @@ class XmppJsStream extends GenericStream {
 				service: connectionURI,
 				domain: jid.domain,
 				username: jid.local,
+				resource: jid.resource,
 				password: event.password,
 			});
 
@@ -133,7 +136,8 @@ class XmppJsStream extends GenericStream {
 
 			this.client = xmpp;
 
-			xmpp.on("online", function (data) {
+			xmpp.on("online", function (jid) {
+				this.jid = jid;
 				this.state.event("connection-success");
 			});
 
@@ -196,7 +200,7 @@ class XmppJsStream extends GenericStream {
 	/* State handlers */
 
 	private function onOnline(event) {
-		trigger("status/online", {});
+		trigger("status/online", { jid: jid.toString() });
 	}
 
 	private function onOffline(event) {