| author | Stephen Paul Weber
<singpolyma@singpolyma.net> 2023-11-01 15:54:20 UTC |
| committer | Stephen Paul Weber
<singpolyma@singpolyma.net> 2023-11-08 21:16:35 UTC |
| parent | 31282d48fbb20b877e1a8feb0a1e8d7907555083 |
| xmpp/Chat.hx | +33 | -16 |
| xmpp/Client.hx | +1 | -1 |
| xmpp/Presence.hx | +10 | -0 |
| xmpp/persistence/browser.js | +2 | -2 |
diff --git a/xmpp/Chat.hx b/xmpp/Chat.hx index 2267c0b..c14ffe1 100644 --- a/xmpp/Chat.hx +++ b/xmpp/Chat.hx @@ -24,7 +24,7 @@ abstract class Chat { private var stream:GenericStream; private var persistence:Persistence; private var avatarSha1:Null<BytesData> = null; - private var caps:haxe.DynamicAccess<Null<Caps>> = {}; + private var presence:haxe.DynamicAccess<Presence> = {}; private var trusted:Bool = false; public var chatId(default, null):String; public var jingleSessions: Map<String, xmpp.jingle.Session> = []; @@ -76,20 +76,36 @@ abstract class Chat { return this.displayName; } + public function setPresence(resource:String, presence:Presence) { + this.presence.set(resource, presence); + } + public function setCaps(resource:String, caps:Caps) { - this.caps.set(resource, caps); + final presence = presence.get(resource); + if (presence != null) { + presence.caps = caps; + } else { + this.presence.set(resource, new Presence(caps)); + } } - public function removeCaps(resource:String) { - this.caps.remove(resource); + public function removePresence(resource:String) { + presence.remove(resource); } public function getCaps():KeyValueIterator<String, Caps> { - return caps.keyValueIterator(); + final iter = presence.keyValueIterator(); + return { + hasNext: iter.hasNext, + next: () -> { + final n = iter.next(); + return { key: n.key, value: n.value.caps }; + } + }; } public function getResourceCaps(resource:String):Caps { - return caps[resource]; + return presence[resource].caps; } public function setAvatarSha1(sha1: BytesData) { @@ -105,16 +121,16 @@ abstract class Chat { } public function canAudioCall():Bool { - for (resource => cap in caps) { - if (cap?.features?.contains("urn:xmpp:jingle:apps:rtp:audio") ?? false) return true; + for (resource => p in presence) { + if (p.caps?.features?.contains("urn:xmpp:jingle:apps:rtp:audio") ?? false) return true; } return false; } public function canVideoCall():Bool { - for (resource => cap in caps) { - if (cap?.features?.contains("urn:xmpp:jingle:apps:rtp:video") ?? false) return true; + for (resource => p in presence) { + if (p.caps?.features?.contains("urn:xmpp:jingle:apps:rtp:video") ?? false) return true; } return false; @@ -296,6 +312,7 @@ class Channel extends Chat { if (err.name == "remote-server-not-found" || err.name == "remote-server-timeout") return; // Timeout, retry later if (err.name == "item-not-found") return; // Nick was changed? (shouldRefreshDisco ? refreshDisco : (cb)->cb())(() -> { + presence = {}; // About to ask for a fresh set client.sendPresence( getFullJid().asString(), (stanza) -> { @@ -332,7 +349,7 @@ class Channel extends Chat { public function getParticipants() { final jid = JID.parse(chatId); - return caps.keys().map((resource) -> new JID(jid.node, jid.domain, resource).asString()); + return presence.keys().map((resource) -> new JID(jid.node, jid.domain, resource).asString()); } public function getParticipantDetails(participantId:String, callback:({photoUri:String, displayName:String})->Void) { @@ -454,18 +471,18 @@ class SerializedChat { public final chatId:String; public final trusted:Bool; public final avatarSha1:Null<BytesData>; - public final caps:haxe.DynamicAccess<Caps>; + public final presence:haxe.DynamicAccess<Presence>; public final displayName:Null<String>; public final uiState:String; public final extensions:String; public final disco:Null<Caps>; public final klass:String; - public function new(chatId: String, trusted: Bool, avatarSha1: Null<BytesData>, caps: haxe.DynamicAccess<Caps>, displayName: Null<String>, uiState: Null<String>, extensions: Null<String>, disco: Null<Caps>, klass: String) { + public function new(chatId: String, trusted: Bool, avatarSha1: Null<BytesData>, presence: haxe.DynamicAccess<Presence>, displayName: Null<String>, uiState: Null<String>, extensions: Null<String>, disco: Null<Caps>, klass: String) { this.chatId = chatId; this.trusted = trusted; this.avatarSha1 = avatarSha1; - this.caps = caps; + this.presence = presence; this.displayName = displayName; this.uiState = uiState ?? "Open"; this.extensions = extensions ?? "<extensions xmlns='urn:app:bookmarks:1' />"; @@ -494,8 +511,8 @@ class SerializedChat { if (displayName != null) chat.setDisplayName(displayName); if (avatarSha1 != null) chat.setAvatarSha1(avatarSha1); chat.setTrusted(trusted); - for (resource => c in caps) { - chat.setCaps(resource, c); + for (resource => p in presence) { + chat.setPresence(resource, p); } return chat; } diff --git a/xmpp/Client.hx b/xmpp/Client.hx index 4d42ce2..c16a852 100644 --- a/xmpp/Client.hx +++ b/xmpp/Client.hx @@ -306,7 +306,7 @@ class Client extends xmpp.EventEmitter { return EventUnhandled; } // Maybe in the future record it as offine rather than removing it - chat.removeCaps(JID.parse(stanza.attr.get("from")).resource); + chat.removePresence(JID.parse(stanza.attr.get("from")).resource); persistence.storeChat(jid, chat); this.trigger("chats/update", [chat]); } diff --git a/xmpp/Presence.hx b/xmpp/Presence.hx new file mode 100644 index 0000000..fe25e63 --- /dev/null +++ b/xmpp/Presence.hx @@ -0,0 +1,10 @@ +package xmpp; + +@:expose +class Presence { + public var caps:Null<Caps>; + + public function new(caps: Null<Caps>) { + this.caps = caps; + } +} diff --git a/xmpp/persistence/browser.js b/xmpp/persistence/browser.js index 7bd9498..90bd6e9 100644 --- a/xmpp/persistence/browser.js +++ b/xmpp/persistence/browser.js @@ -103,7 +103,7 @@ exports.xmpp.persistence = { chatId: chat.chatId, trusted: chat.trusted, avatarSha1: chat.avatarSha1, - caps: chat.caps, + presence: chat.presence, displayName: chat.displayName, uiState: chat.uiState?.toString(), extensions: chat.extensions?.toString(), @@ -120,7 +120,7 @@ exports.xmpp.persistence = { r.chatId, r.trusted, r.avatarSha1, - r.caps, + r.presence, r.displayName, r.uiState, r.extensions,