git » sdk » commit e6518cc

Fixes for MUC sync status

author Stephen Paul Weber
2024-11-19 18:13:20 UTC
committer Stephen Paul Weber
2024-11-19 18:13:20 UTC
parent 0a826dd3d05b3242ce90b9c552a298251ee00868

Fixes for MUC sync status

snikket/Chat.hx +38 -17
snikket/Client.hx +7 -7
snikket/Persistence.hx +1 -1
snikket/Stanza.hx +1 -1
snikket/persistence/Dummy.hx +1 -1
snikket/persistence/Sqlite.hx +1 -1

diff --git a/snikket/Chat.hx b/snikket/Chat.hx
index d2d479e..79d692c 100644
--- a/snikket/Chat.hx
+++ b/snikket/Chat.hx
@@ -892,6 +892,8 @@ class Channel extends Chat {
 	@:allow(snikket)
 	private var disco: Caps = new Caps("", [], ["http://jabber.org/protocol/muc"]);
 	private var inSync = true;
+	private var sync = null;
+	private var forceLive = false;
 
 	@:allow(snikket)
 	private function new(client:Client, stream:GenericStream, persistence:Persistence, chatId:String, uiState = Open, isBlocked = false, extensions = null, readUpToId = null, readUpToBy = null, ?disco: Caps) {
@@ -912,16 +914,21 @@ class Channel extends Chat {
 			return;
 		}
 
-		stream.sendIq(
-			new Stanza("iq", { type: "get", to: getFullJid().asString() })
-				.tag("ping", { xmlns: "urn:xmpp:ping" }).up(),
-			(response) -> {
-				if (response.attr.get("type") == "error") {
-					final err = response.getChild("error")?.getChild(null, "urn:ietf:params:xml:ns:xmpp-stanzas");
-					if (err.name == "service-unavailable" || err.name == "feature-not-implemented") return checkRename(); // Error, success!
-					if (err.name == "remote-server-not-found" || err.name == "remote-server-timeout") return checkRename(); // Timeout, retry later
-					if (err.name == "item-not-found") return checkRename(); // Nick was changed?
-					(shouldRefreshDisco ? refreshDisco : (cb)->cb())(() -> {
+		(refresh ? refreshDisco : (cb)->cb())(() -> {
+			if (!disco.features.contains("http://jabber.org/protocol/muc")) {
+				// Not a MUC, owhat kind of channel is this?
+				forceLive = true;
+				return;
+			}
+			stream.sendIq(
+				new Stanza("iq", { type: "get", to: getFullJid().asString() })
+					.tag("ping", { xmlns: "urn:xmpp:ping" }).up(),
+				(response) -> {
+					if (response.attr.get("type") == "error") {
+						final err = response.getChild("error")?.getChild(null, "urn:ietf:params:xml:ns:xmpp-stanzas");
+						if (err.name == "service-unavailable" || err.name == "feature-not-implemented") return checkRename(); // Error, success!
+						if (err.name == "remote-server-not-found" || err.name == "remote-server-timeout") return checkRename(); // Timeout, retry later
+						if (err.name == "item-not-found") return checkRename(); // Nick was changed?
 						presence = []; // About to ask for a fresh set
 						inSync = false;
 						client.trigger("chats/update", [this]);
@@ -936,12 +943,14 @@ class Channel extends Chat {
 								return stanza;
 							}
 						);
-					});
-				} else {
-					checkRename();
+					} else {
+						inSync = false;
+						persistence.lastId(client.accountId(), chatId, doSync);
+						checkRename();
+					}
 				}
-			}
-		);
+			);
+		});
 	}
 
 	private function checkRename() {
@@ -967,15 +976,21 @@ class Channel extends Chat {
 			persistence.lastId(client.accountId(), chatId, doSync);
 		}
 		if (oneTen != null && tripleThree != null) {
-			selfPing();
+			selfPing(true);
 		}
 	}
 
 	private function doSync(lastId: Null<String>) {
+		if (!disco.features.contains("urn:xmpp:mam:2")) {
+			inSync = true;
+			return;
+		}
+		if (sync != null) return;
+
 		var threeDaysAgo = Date.format(
 			DateTools.delta(std.Date.now(), DateTools.days(-3))
 		);
-		var sync = new MessageSync(
+		sync = new MessageSync(
 			client,
 			stream,
 			lastId == null ? { startTime: threeDaysAgo } : { page: { after: lastId } },
@@ -1008,6 +1023,7 @@ class Channel extends Chat {
 					sync.fetchNext();
 				} else {
 					inSync = true;
+					sync = null;
 					final lastFromSync = chatMessages[chatMessages.length - 1];
 					if (lastFromSync != null && (lastMessageTimestamp() == null || Reflect.compare(lastFromSync.timestamp, lastMessageTimestamp()) > 0)) {
 						setLastMessage(lastFromSync);
@@ -1024,9 +1040,12 @@ class Channel extends Chat {
 			});
 		});
 		sync.onError((stanza) -> {
+			sync = null;
 			if (lastId != null) {
 				// Gap in sync, out newest message has expired from server
 				doSync(null);
+			} else {
+				trace("SYNC failed", chatId, stanza);
 			}
 		});
 		sync.fetchNext();
@@ -1054,6 +1073,8 @@ class Channel extends Chat {
 
 	@:allow(snikket)
 	override private function livePresence() {
+		if (forceLive) return true;
+
 		for (nick => p in presence) {
 			for (status in p?.mucUser?.allTags("status") ?? []) {
 				if (status.attr.get("code") == "110") {
diff --git a/snikket/Client.hx b/snikket/Client.hx
index 80af3c8..ff25060 100644
--- a/snikket/Client.hx
+++ b/snikket/Client.hx
@@ -109,7 +109,7 @@ class Client extends EventEmitter {
 		});
 
 		stream.on("sm/update", (data) -> {
-			final anySyncHappening = chats.exists(chat -> chat.syncing());
+			final anySyncHappening = chats.exists(chat -> chat.uiState != Closed && chat.syncing());
 			persistence.storeStreamManagement(accountId(), anySyncHappening ? null : data.sm);
 			return EventHandled;
 		});
@@ -147,7 +147,7 @@ class Client extends EventEmitter {
 			if (stanza.attr.get("type") == "error" && from != null) {
 				final chat = getChat(from.asBare().asString());
 				final channel = Std.downcast(chat, Channel);
-				if (channel != null) channel.selfPing();
+				if (channel != null) channel.selfPing(true);
 			}
 
 			var fwd = null;
@@ -650,7 +650,7 @@ class Client extends EventEmitter {
 		if (fn == null || fn == "" || fn == displayName()) return false;
 		_displayName = fn;
 		persistence.storeLogin(jid.asBare().asString(), stream.clientId ?? jid.resource, fn, null);
-		pingAllChannels();
+		pingAllChannels(false);
 		return true;
 	}
 
@@ -706,7 +706,7 @@ class Client extends EventEmitter {
 					// Set self to online
 					if (sendAvailable) {
 						sendPresence();
-						pingAllChannels();
+						pingAllChannels(true);
 					}
 					this.trigger("status/online", {});
 					trace("SYNC: done");
@@ -854,7 +854,7 @@ class Client extends EventEmitter {
 				chats = chats.filter((chat) -> chat.chatId != availableChat.chatId);
 			} else {
 				if (existingChat.uiState == Closed) existingChat.uiState = Open;
-				channel?.selfPing();
+				channel?.selfPing(true);
 				this.trigger("chats/update", [existingChat]);
 				return existingChat;
 			}
@@ -1410,10 +1410,10 @@ class Client extends EventEmitter {
 		sync.fetchNext();
 	}
 
-	private function pingAllChannels() {
+	private function pingAllChannels(refresh: Bool) {
 		for (chat in getChats()) {
 			final channel = Std.downcast(chat, Channel);
-			channel?.selfPing(channel?.disco == null);
+			channel?.selfPing(refresh || channel?.disco == null);
 		}
 	}
 }
diff --git a/snikket/Persistence.hx b/snikket/Persistence.hx
index 7340f3c..bd07317 100644
--- a/snikket/Persistence.hx
+++ b/snikket/Persistence.hx
@@ -27,7 +27,7 @@ interface Persistence {
 	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 storeStreamManagement(accountId:String, data:Null<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;
 	@HaxeCBridge.noemit
diff --git a/snikket/Stanza.hx b/snikket/Stanza.hx
index e7c33ae..92afaeb 100644
--- a/snikket/Stanza.hx
+++ b/snikket/Stanza.hx
@@ -246,7 +246,7 @@ class Stanza implements NodeInterface {
 		return allText().join("");
 	}
 
-	public function find(path:String):Node {
+	public function find(path:String): Null<Node> {
 		var pos = 0;
 		var len = path.length;
 		var cursor = this;
diff --git a/snikket/persistence/Dummy.hx b/snikket/persistence/Dummy.hx
index c343703..bfb178b 100644
--- a/snikket/persistence/Dummy.hx
+++ b/snikket/persistence/Dummy.hx
@@ -106,7 +106,7 @@ class Dummy implements Persistence {
 	public function removeAccount(accountId:String, completely:Bool) { }
 
 	@HaxeCBridge.noemit
-	public function storeStreamManagement(accountId:String, sm:BytesData) { }
+	public function storeStreamManagement(accountId:String, sm:Null<BytesData>) { }
 
 	@HaxeCBridge.noemit
 	public function getStreamManagement(accountId:String, callback: (Null<BytesData>)->Void) {
diff --git a/snikket/persistence/Sqlite.hx b/snikket/persistence/Sqlite.hx
index 0869cbe..ad8d5c9 100644
--- a/snikket/persistence/Sqlite.hx
+++ b/snikket/persistence/Sqlite.hx
@@ -447,7 +447,7 @@ class Sqlite implements Persistence {
 	}
 
 	@HaxeCBridge.noemit
-	public function storeStreamManagement(accountId:String, sm:BytesData) {
+	public function storeStreamManagement(accountId:String, sm:Null<BytesData>) {
 		// TODO
 	}