diff --git a/project.godot b/project.godot index f0a51a1..72ace35 100644 --- a/project.godot +++ b/project.godot @@ -50,7 +50,7 @@ _global_script_class_icons={ [application] -config/name="tochie" +config/name="tochie-facade" run/main_scene="res://scenes/App.tscn" run/low_processor_mode=true config/icon="res://icon.png" diff --git a/scenes/App.gd b/scenes/App.gd index 2558bb3..43fa419 100644 --- a/scenes/App.gd +++ b/scenes/App.gd @@ -31,3 +31,7 @@ func _ready(): for room in rooms_request.value: var me = service.muc.join_room(room, "tochie-facade") + if not me.is_done: + yield(me, "done") + + print("Chat joined") diff --git a/scenes/Connections.gd b/scenes/Connections.gd index e12a4d1..22000cf 100644 --- a/scenes/Connections.gd +++ b/scenes/Connections.gd @@ -12,7 +12,7 @@ class Connection extends Reference: var _id_counter: int = 0 var _pending_iqs: Dictionary # of id to GDScriptFunctionState - var _presence_sinks: Dictionary # of Jid to [[WeakRef, String]] + var _presence_sinks: Dictionary # of Jid to [[WeakRef, String, String]] var _xml_parser := Xml.Parser.new() # todo: Route signals to particular receivers, based on 'from' or 'to' @@ -59,9 +59,9 @@ class Connection extends Reference: return Sums.Result.make_value(null) - func presence_sink(p_base_jid: String, p_sink: Object, p_signal: String) -> void: + func presence_sink(p_base_jid: String, p_sink: Object, p_type: String, p_signal: String) -> void: self._presence_sinks[p_base_jid] = \ - self._presence_sinks.get(p_base_jid, []) + [[weakref(p_sink), p_signal]] + self._presence_sinks.get(p_base_jid, []) + [[weakref(p_sink), p_type, p_signal]] ## Registry of connections used for poking of pending iqs. var _connections: Array # of WeakRef to Connection @@ -91,7 +91,6 @@ func _process_connections() -> void: response = null var stanza := connection._xml_parser.take_root() - print(stanza.as_string()) if stanza.name == "iq": if "to" in stanza.attributes and stanza.attributes["to"] != connection.jid: @@ -118,8 +117,17 @@ func _process_connections() -> void: if not stanza.attributes["from"].begins_with(base_jid): continue - for to_emit in connection._presence_sinks[base_jid]: - to_emit[0].emit_signal(to_emit[1], stanza) + var sink = connection._presence_sinks[base_jid] + var sink_idx := 0 + while sink_idx < sink.size(): + var ref = sink[sink_idx][0].get_ref() + if ref == null: + sink.remove(sink_idx) + else: + if sink[sink_idx][1] == "signal": + ref.emit_signal(sink[sink_idx][2], stanza) + else: ref.call(sink[sink_idx][2], stanza) + sink_idx += 1 ## Collect dropped connections. for idx in range(to_remove.size() - 1, 0, -1): diff --git a/scenes/MucService.gd b/scenes/MucService.gd index ab6bf66..95120bd 100644 --- a/scenes/MucService.gd +++ b/scenes/MucService.gd @@ -8,27 +8,31 @@ class MucRoom extends Reference: var name: String var members: Dictionary # nick to MucMember - signal presence_received(presence) + signal message_received(message) + signal member_presence(member) - func _init() -> void: - if self.connect("presence_received", self, "_presence_received") != OK: - assert(false) + signal _presence_received(presence) - func _presence_received(presence) -> void: - if presence.children.size() == 0: - return - var x = presence.get_named_child_element("x") - if x.name != "x" and x.attributes["xmlns"] != "http://jabber.org/protocol/muc#user": - ## Member information came. - var item = x.get_named_child_element("item") - var nick = presence.attributes["from"].rsplit("/").pop_front() - var member = MucMember.new() - member.jid = presence.attributes["from"] - member.nick = nick - member.role = item.attributes["role"] - member.affiliation = item.attributes["affiliation"] - # member.room = self - members[nick] = member + func _receive_internal_presence(presence) -> void: + ## First do internal book keeping ... + if presence.children.size() > 0: + var x = presence.get_named_child_element("x") + if x.name == "x" and x.attributes["xmlns"] == "http://jabber.org/protocol/muc#user": + ## Member information came. + var item = x.get_named_child_element("item") + var nick = Stanza.extract_resource_part(presence.attributes["from"]) + var member = MucMember.new() + member.jid = presence.attributes["from"] + member.nick = nick + member.role = item.attributes["role"] + member.affiliation = item.attributes["affiliation"] + # member.room = self + members[nick] = member + + emit_signal("member_presence", member) + + ## ... then propagate outside. + emit_signal("_presence_received", presence) func as_string() -> String: return "MucRoom \"%s\", Jid: \"%s\"" % [name, jid] @@ -84,7 +88,7 @@ func _iq_rooms() -> Sums.Result: for item in query.value.children: if item.is_element() and item.name == "item": var muc_room := MucRoom.new() - _connection.presence_sink(muc_room.jid, muc_room, "presence_received") + _connection.presence_sink(muc_room.jid, muc_room, "method", "_receive_internal_presence") muc_room.jid = item.attributes["jid"] muc_room.name = item.attributes["name"] rooms.push_back(muc_room) @@ -103,12 +107,12 @@ func _join_room(room: MucRoom, nick: String) -> Sums.Result: if not result.is_ok: return result - var response = Stanza.presence_result(yield(room, "presence_received")) + var response = Stanza.presence_result(yield(room, "_presence_received")) if not response.is_ok: return response while true: - response = Stanza.presence_result(yield(room, "presence_received")) + response = Stanza.presence_result(yield(room, "_presence_received")) if not response.is_ok: return response @@ -119,7 +123,7 @@ func _join_room(room: MucRoom, nick: String) -> Sums.Result: if x.name != "x" and x.attributes["xmlns"] != "http://jabber.org/protocol/muc#user": continue for child in x.children: - if child.is_element() and child.name == "status" and child.attrbiutes["code"] == "110": + if child.is_element() and child.name == "status" and child.attributes["code"] == "110": return Sums.Result.make_value(room.members[nick]) return Sums.Result.make_error(null) diff --git a/scenes/PolyServiceBuilder.gd b/scenes/PolyServiceBuilder.gd index 54bc7d8..968f289 100644 --- a/scenes/PolyServiceBuilder.gd +++ b/scenes/PolyServiceBuilder.gd @@ -19,6 +19,7 @@ func _service_discovery(connection: Connections.Connection) -> Sums.Result: var poly_services := Array() for item in query.value.children: + # todo: Do this at the same time, in separate coroutines. if not item.is_element() or item.name != "item": continue diff --git a/scenes/Stanza.gd b/scenes/Stanza.gd index 7be1857..7437f15 100644 --- a/scenes/Stanza.gd +++ b/scenes/Stanza.gd @@ -43,3 +43,8 @@ static func presence_result(stanza: Xml.XmlElement) -> Sums.Result: return Sums.Result.make_error(stanza) else: return Sums.Result.make_value(stanza) + +static func extract_resource_part(jid: String) -> String: + var parts = jid.rsplit("/") + assert(parts.size() > 0) + return parts[parts.size() - 1]