git » sdk » commit 8d4cdf2

Use ES6 native maps in javascript

author Stephen Paul Weber
2023-12-11 15:45:42 UTC
committer Stephen Paul Weber
2023-12-11 15:59:52 UTC
parent c9c6ec9809bf121af7811488b7ba5bfd9ebf50b1

Use ES6 native maps in javascript

xmpp/Chat.hx +5 -5
xmpp/Map.js.hx +80 -0
xmpp/persistence/browser.js +2 -2
xmpp/queries/Push2Enable.hx +2 -2

diff --git a/xmpp/Chat.hx b/xmpp/Chat.hx
index d8c99be..d478041 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 presence:haxe.DynamicAccess<Presence> = {};
+	private var presence:Map<String, Presence> = [];
 	private var trusted:Bool = false;
 	public var chatId(default, null):String;
 	public var jingleSessions: Map<String, xmpp.jingle.Session> = [];
@@ -400,7 +400,7 @@ class Channel extends Chat {
 					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())(() -> {
-						presence = {}; // About to ask for a fresh set
+						presence = []; // About to ask for a fresh set
 						inSync = false;
 						final desiredFullJid = JID.parse(chatId).withResource(client.displayName());
 						client.sendPresence(
@@ -517,7 +517,7 @@ class Channel extends Chat {
 
 	public function getParticipants() {
 		final jid = JID.parse(chatId);
-		return presence.keys().map((resource) -> new JID(jid.node, jid.domain, resource).asString());
+		return { iterator: () -> presence.keys() }.map((resource) -> new JID(jid.node, jid.domain, resource).asString());
 	}
 
 	public function getParticipantDetails(participantId:String, callback:({photoUri:String, displayName:String})->Void) {
@@ -688,14 +688,14 @@ class SerializedChat {
 	public final chatId:String;
 	public final trusted:Bool;
 	public final avatarSha1:Null<BytesData>;
-	public final presence:haxe.DynamicAccess<Presence>;
+	public final presence:Map<String, 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>, presence: haxe.DynamicAccess<Presence>, 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: Map<String, Presence>, displayName: Null<String>, uiState: Null<String>, extensions: Null<String>, disco: Null<Caps>, klass: String) {
 		this.chatId = chatId;
 		this.trusted = trusted;
 		this.avatarSha1 = avatarSha1;
diff --git a/xmpp/Map.js.hx b/xmpp/Map.js.hx
new file mode 100644
index 0000000..1f453c7
--- /dev/null
+++ b/xmpp/Map.js.hx
@@ -0,0 +1,80 @@
+package xmpp;
+
+import haxe.Constraints.IMap;
+import js.lib.HaxeIterator;
+import js.lib.Map as NativeMap;
+using Lambda;
+
+// Use ES6 maps instead of Haxe maps
+@:forward
+abstract Map<K,V>(NativeMap<K,V>) {
+	public inline function set(k:K, v:V):Void {
+		this.set(k, v);
+	}
+
+	public inline function exists(k:K):Bool {
+		return this.has(k);
+	}
+
+	public inline function remove(k:K):Bool {
+		return this.delete(k);
+	}
+
+	public inline function keys():Iterator<K> {
+		return new HaxeIterator(this.keys());
+	}
+
+	public inline function iterator():Iterator<V> {
+		return new HaxeIterator(this.values());
+	}
+
+	public inline function keyValueIterator():KeyValueIterator<K, V> {
+		return new HaxeKVIterator(this.entries());
+	}
+
+	// This shouldn't be needed but complier wants it...
+	public inline function flatMap<B>(f:(item:V)->Iterable<B>): Array<B> {
+		return { iterator: () -> this.iterator() }.flatMap(f);
+	}
+
+	@:arrayAccess @:noCompletion public inline function arrayRead(k:K) {
+		return this.get(k);
+	}
+
+	@:arrayAccess @:noCompletion public inline function arrayWrite(k:K, v:V):V {
+		this.set(k, v);
+		return v;
+	}
+
+	@:from static function fromMap<K,V>(map:haxe.ds.Map<K,V>):Map<K, V> {
+		final result = new NativeMap();
+		for (k => v in map) {
+			result.set(k, v);
+		}
+		return cast result;
+	}
+
+	@:from static inline function fromArray<K,V>(iterable:Iterable<js.lib.KeyValue<K,V>>):Map<K, V> {
+		return cast new NativeMap(iterable);
+	}
+}
+
+class HaxeKVIterator<K,V> {
+	final jsIterator: js.lib.Iterator<js.lib.KeyValue<K,V>>;
+	var lastStep: js.lib.Iterator.IteratorStep<js.lib.KeyValue<K,V>>;
+
+	public inline function new(jsIterator: js.lib.Iterator<js.lib.KeyValue<K,V>>) {
+		this.jsIterator = jsIterator;
+		lastStep = jsIterator.next();
+	}
+
+	public inline function hasNext(): Bool {
+		return !lastStep.done;
+	}
+
+	public inline function next(): { key: K, value: V } {
+		var v = lastStep.value;
+		lastStep = jsIterator.next();
+		return { key: v.key, value: v.value };
+	}
+}
diff --git a/xmpp/persistence/browser.js b/xmpp/persistence/browser.js
index 4f6c922..fbf030c 100644
--- a/xmpp/persistence/browser.js
+++ b/xmpp/persistence/browser.js
@@ -167,7 +167,7 @@ exports.xmpp.persistence = {
 					chatId: chat.chatId,
 					trusted: chat.trusted,
 					avatarSha1: chat.avatarSha1,
-					presence: Object.fromEntries(Object.entries(chat.presence || {}).map(([k, p]) => [k, { caps: p.caps?.ver(), mucUser: p.mucUser?.toString() }])),
+					presence: new Map([...chat.presence.entries()].map(([k, p]) => [k, { caps: p.caps?.ver(), mucUser: p.mucUser?.toString() }])),
 					displayName: chat.displayName,
 					uiState: chat.uiState?.toString(),
 					extensions: chat.extensions?.toString(),
@@ -186,7 +186,7 @@ exports.xmpp.persistence = {
 						r.chatId,
 						r.trusted,
 						r.avatarSha1,
-						Object.fromEntries(await Promise.all(Object.entries(r.presence).map(
+						new Map(await Promise.all((r.presence instanceof Map ? [...r.presence.entries()] : Object.entries(r.presence)).map(
 							async ([k, p]) => [k, new xmpp.Presence(p.caps && await new Promise((resolve) => this.getCaps(p.caps, resolve)), p.mucUser && xmpp.Stanza.parse(p.mucUser))]
 						))),
 						r.displayName,
diff --git a/xmpp/queries/Push2Enable.hx b/xmpp/queries/Push2Enable.hx
index 649e423..e27c4f0 100644
--- a/xmpp/queries/Push2Enable.hx
+++ b/xmpp/queries/Push2Enable.hx
@@ -29,8 +29,8 @@ class Push2Enable extends GenericQuery {
 		if (jwt_alg != null) {
 			send.textTag("jwt-alg", jwt_alg);
 			send.textTag("jwt-key", Base64.encode(jwt_key));
-			for (claim in jwt_claims.keyValueIterator()) {
-				send.textTag("jwt-claim", claim.value, { name: claim.key });
+			for (key => value in jwt_claims) {
+				send.textTag("jwt-claim", value, { name: key });
 			}
 		}
 		enable.up().up().up();