tochie-facade/scenes/MucService.gd
2023-09-02 16:18:36 +05:00

126 lines
4.1 KiB
GDScript

extends Reference
class_name MucService
## https://xmpp.org/extensions/xep-0045.html
class MucRoom extends Reference:
var jid: String
var name: String
var members: Dictionary # nick to MucMember
signal presence_received(presence)
func _init() -> void:
if self.connect("presence_received", self, "_presence_received") != OK:
assert(false)
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 as_string() -> String:
return "MucRoom \"%s\", Jid: \"%s\"" % [name, jid]
class MucMember extends Reference:
var jid: String
var nick: String
var role: String
# var room: MucRoom
var affiliation: String
var jid: String
var _connection: Connections.Connection
var _rooms_promise: Sums.Promise = null
func try_init(connection: Connections.Connection, p_jid: String, disco_info: Xml.XmlElement):
var is_muc := false
for item in disco_info.children:
if item.is_element() and item.name == "feature":
if item.attributes["var"] == "http://jabber.org/protocol/muc":
is_muc = true
break
if not is_muc:
return null
self.jid = p_jid
self._connection = connection
return self
func request_rooms() -> Sums.Promise:
if self._rooms_promise != null:
return self._rooms_promise
self._rooms_promise = _connection.promise_iq(
jid, "get",
Stanza.disco_items_queury,
_iq_rooms())
return self._rooms_promise
func _iq_rooms() -> Sums.Result:
var response = yield()
if not response.is_ok:
return response
var query := Stanza.unwrap_query_result(response.value)
if not query.is_ok:
return query
var rooms := Array()
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")
muc_room.jid = item.attributes["jid"]
muc_room.name = item.attributes["name"]
rooms.push_back(muc_room)
return Sums.Result.make_value(rooms)
## Returns MucMemeber that is registered on behalf on user.
func join_room(room: MucRoom, nick: String) -> Sums.Promise:
# todo: https://xmpp.org/extensions/xep-0045.html#reservednick
return Sums.Promise.from(_join_room(room, nick))
func _join_room(room: MucRoom, nick: String) -> Sums.Result:
var member_jid = room.jid + '/' + nick
var result = _connection.push_presence(member_jid, null,
"<x xmlns='http://jabber.org/protocol/muc'/>")
if not result.is_ok:
return result
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"))
if not response.is_ok:
return response
if response.value.attributes["from"] == member_jid:
if response.value.children.size() == 0:
continue
var x = response.value.children[0]
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":
return Sums.Result.make_value(room.members[nick])
return Sums.Result.make_error(null)