git » sdk » commit 2738faf

logout / remove account

author Stephen Paul Weber
2024-10-06 19:40:25 UTC
committer Stephen Paul Weber
2024-10-06 19:40:25 UTC
parent be7f78bb5f933115af421c35ab9a2ede8fe3f756

logout / remove account

snikket/Client.hx +12 -0
snikket/GenericStream.hx +1 -0
snikket/Persistence.hx +1 -0
snikket/persistence/Custom.hx +5 -0
snikket/persistence/Dummy.hx +3 -0
snikket/persistence/Sqlite.hx +26 -0
snikket/persistence/browser.js +48 -0
snikket/streams/XmppJsStream.hx +6 -0
snikket/streams/XmppStropheStream.hx +7 -0

diff --git a/snikket/Client.hx b/snikket/Client.hx
index a967bb3..7285c6f 100644
--- a/snikket/Client.hx
+++ b/snikket/Client.hx
@@ -522,6 +522,18 @@ class Client extends EventEmitter {
 		});
 	}
 
+	/**
+		Destroy local data for this account
+
+		@param completely if true chats, messages, etc will be deleted as well
+	**/
+	public function logout(completely: Bool) {
+		// TODO: unregister from all push notifications
+		stream.disconnect();
+		// TODO: FAST invalidate https://xmpp.org/extensions/xep-0484.html#invalidation
+		persistence.removeAccount(accountId(), completely);
+	}
+
 	/**
 		Sets the password to be used in response to the password needed event
 
diff --git a/snikket/GenericStream.hx b/snikket/GenericStream.hx
index 5fe7b63..cb11984 100644
--- a/snikket/GenericStream.hx
+++ b/snikket/GenericStream.hx
@@ -21,6 +21,7 @@ abstract class GenericStream extends EventEmitter {
 	/* Connections and streams */
 
 	abstract public function connect(jid:String, sm:Null<BytesData>):Void;
+	abstract public function disconnect():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;
diff --git a/snikket/Persistence.hx b/snikket/Persistence.hx
index e8ab6ad..03eaddb 100644
--- a/snikket/Persistence.hx
+++ b/snikket/Persistence.hx
@@ -26,6 +26,7 @@ interface Persistence {
 	public function getCaps(ver:String, callback: (Null<Caps>)->Void):Void;
 	public function storeLogin(login:String, clientId:String, displayName:String, token:Null<String>):Void;
 	public function getLogin(login:String, callback:(clientId:Null<String>, token:Null<String>, fastCount: Int, displayName:Null<String>)->Void):Void;
+	public function removeAccount(accountId: String, completely:Bool):Void;
 	public function storeStreamManagement(accountId:String, data:BytesData):Void;
 	public function getStreamManagement(accountId:String, callback: (Null<BytesData>)->Void):Void;
 	public function storeService(accountId:String, serviceId:String, name:Null<String>, node:Null<String>, caps:Caps):Void;
diff --git a/snikket/persistence/Custom.hx b/snikket/persistence/Custom.hx
index 469e490..df489d3 100644
--- a/snikket/persistence/Custom.hx
+++ b/snikket/persistence/Custom.hx
@@ -123,6 +123,11 @@ class Custom implements Persistence {
 		backing.storeStreamManagement(accountId, sm);
 	}
 
+	@HaxeCBridge.noemit
+	public function removeAccount(accountId:String, completely:Bool) {
+		backing.removeAccount(accountId, completely);
+	}
+
 	@HaxeCBridge.noemit
 	public function getStreamManagement(accountId:String, callback: (BytesData)->Void) {
 		backing.getStreamManagement(accountId, callback);
diff --git a/snikket/persistence/Dummy.hx b/snikket/persistence/Dummy.hx
index eddfd9f..28e5641 100644
--- a/snikket/persistence/Dummy.hx
+++ b/snikket/persistence/Dummy.hx
@@ -97,6 +97,9 @@ class Dummy implements Persistence {
 		callback(null, null, 0, null);
 	}
 
+	@HaxeCBridge.noemit
+	public function removeAccount(accountId:String, completely:Bool) { }
+
 	@HaxeCBridge.noemit
 	public function storeStreamManagement(accountId:String, sm:BytesData) { }
 
diff --git a/snikket/persistence/Sqlite.hx b/snikket/persistence/Sqlite.hx
index 66b5f95..1312424 100644
--- a/snikket/persistence/Sqlite.hx
+++ b/snikket/persistence/Sqlite.hx
@@ -412,6 +412,32 @@ class Sqlite implements Persistence {
 		callback(null, null, 0, null);
 	}
 
+	@HaxeCBridge.noemit
+	public function removeAccount(accountId:String, completely:Bool) {
+		var q = new StringBuf();
+		q.add("DELETE FROM logins WHERE login=");
+		db.addValue(q, accountId);
+		db.request(q.toString());
+		// TODO stream managemento
+
+		if (!completely) return;
+
+		var q = new StringBuf();
+		q.add("DELETE FROM messages WHERE account_id=");
+		db.addValue(q, accountId);
+		db.request(q.toString());
+
+		var q = new StringBuf();
+		q.add("DELETE FROM chats WHERE account_id=");
+		db.addValue(q, accountId);
+		db.request(q.toString());
+
+		var q = new StringBuf();
+		q.add("DELETE FROM services WHERE account_id=");
+		db.addValue(q, accountId);
+		db.request(q.toString());
+	}
+
 	@HaxeCBridge.noemit
 	public function storeStreamManagement(accountId:String, sm:BytesData) {
 		// TODO
diff --git a/snikket/persistence/browser.js b/snikket/persistence/browser.js
index 0e81fd8..e33a03d 100644
--- a/snikket/persistence/browser.js
+++ b/snikket/persistence/browser.js
@@ -592,6 +592,54 @@ const browser = (dbname, tokenize, stemmer) => {
 			});
 		},
 
+		removeAccount(account, completely) {
+			const tx = db.transaction(["keyvaluepairs", "services", "messages", "chats", "reactions"], "readwrite");
+			const store = tx.objectStore("keyvaluepairs");
+			store.delete("login:clientId:" + account);
+			store.delete("login:token:" + account);
+			store.delete("login:fastCount:" + account);
+			store.delete("fn:" + account);
+			store.delete("sm:" + account);
+
+			if (!completely) return;
+
+			const servicesStore = tx.objectStore("services");
+			const servicesCursor = servicesStore.openCursor(IDBKeyRange.bound([account], [account, []]));
+			servicesCursor.onsuccess = (event) => {
+				if (event.target.result) {
+					event.target.result.delete();
+					event.target.result.continue();
+				}
+			};
+
+			const messagesStore = tx.objectStore("messages");
+			const messagesCursor = messagesStore.openCursor(IDBKeyRange.bound([account], [account, []]));
+			messagesCursor.onsuccess = (event) => {
+				if (event.target.result) {
+					event.target.result.delete();
+					event.target.result.continue();
+				}
+			};
+
+			const chatsStore = tx.objectStore("chats");
+			const chatsCursor = chatsStore.openCursor(IDBKeyRange.bound([account], [account, []]));
+			chatsCursor.onsuccess = (event) => {
+				if (event.target.result) {
+					event.target.result.delete();
+					event.target.result.continue();
+				}
+			};
+
+			const reactionsStore = tx.objectStore("reactions");
+			const reactionsCursor = reactionsStore.openCursor(IDBKeyRange.bound([account], [account, []]));
+			reactionsCursor.onsuccess = (event) => {
+				if (event.target.result) {
+					event.target.result.delete();
+					event.target.result.continue();
+				}
+			};
+		},
+
 		storeService(account, serviceId, name, node, caps) {
 			this.storeCaps(caps);
 
diff --git a/snikket/streams/XmppJsStream.hx b/snikket/streams/XmppJsStream.hx
index 7b3fc21..102ddca 100644
--- a/snikket/streams/XmppJsStream.hx
+++ b/snikket/streams/XmppJsStream.hx
@@ -21,6 +21,7 @@ extern class XmppJsScramSha1 {
 extern class XmppJsClient {
 	function new(options:Dynamic);
 	function start():Promise<Dynamic>;
+	function stop():Promise<Dynamic>;
 	function on(eventName:String, callback:(Dynamic)->Void):Void;
 	function send(stanza:XmppJsXml):Void;
 	var jid:XmppJsJID;
@@ -277,6 +278,11 @@ class XmppJsStream extends GenericStream {
 		resolveConnectionURI(this.jid.domain, this.connectWithURI);
 	}
 
+	public function disconnect() {
+		if (client == null) return;
+		client.stop();
+	}
+
 	private function convertFromStanza(el:Stanza):XmppJsXml {
 		var xml = new XmppJsXml(el.name, el.attr);
 		if(el.children.length > 0) {
diff --git a/snikket/streams/XmppStropheStream.hx b/snikket/streams/XmppStropheStream.hx
index 0c9fe85..9223023 100644
--- a/snikket/streams/XmppStropheStream.hx
+++ b/snikket/streams/XmppStropheStream.hx
@@ -76,6 +76,9 @@ extern class StropheConn {
 		userdata:RawPointer<Void>
 	):cpp.Int32;
 
+	@:native("xmpp_disconnect")
+	static function disconnect(conn:StropheConn):Void;
+
 	@:native("xmpp_handler_add")
 	static function handler_add(
 		conn:StropheConn,
@@ -268,6 +271,10 @@ class XmppStropheStream extends GenericStream {
 		poll();
 	}
 
+	public function disconnect() {
+		StropheConn.disconnect(conn);
+	}
+
 	private function poll() {
 		sys.thread.Thread.current().events.run(() -> {
 			StropheCtx.run_once(ctx, 1);