wip
This commit is contained in:
parent
d733394196
commit
6d669f924d
|
@ -1,12 +1,13 @@
|
||||||
|
// RFC 6121
|
||||||
|
// XEP-0237
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
// TODO: add versioning (XEP-0237)
|
|
||||||
// TODO: implement error catching
|
|
||||||
final class RosterModule: XmppModule {
|
final class RosterModule: XmppModule {
|
||||||
let id = "Roseter module"
|
let id = "Roseter module"
|
||||||
|
|
||||||
private weak var storage: (any XMPPStorage)?
|
private weak var storage: (any XMPPStorage)?
|
||||||
private var fullReqId = ""
|
private var fullReqId = ""
|
||||||
|
private var isVerSupported = false
|
||||||
|
|
||||||
init(_ storage: any XMPPStorage) {
|
init(_ storage: any XMPPStorage) {
|
||||||
self.storage = storage
|
self.storage = storage
|
||||||
|
@ -21,10 +22,29 @@ final class RosterModule: XmppModule {
|
||||||
case .streamReady:
|
case .streamReady:
|
||||||
return .requestRoster
|
return .requestRoster
|
||||||
|
|
||||||
|
case .xmlInbound(let xml):
|
||||||
|
if xml.name == "stream:features" {
|
||||||
|
if let ver = xml.nodes.first(where: { $0.name == "ver" }), ver.xmlns == "urn:xmpp:features:rosterver" {
|
||||||
|
isVerSupported = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
case .requestRoster:
|
case .requestRoster:
|
||||||
|
var attributes: [String: String] = [:]
|
||||||
|
if isVerSupported {
|
||||||
|
let ver = await storage?.getRosterVer(jid: state.jid)
|
||||||
|
attributes["ver"] = ver ?? ""
|
||||||
|
}
|
||||||
let req = Stanza.iqGet(
|
let req = Stanza.iqGet(
|
||||||
from: state.jid.full,
|
from: state.jid.full,
|
||||||
payload: XMLElement(name: "query", xmlns: "jabber:iq:roster", attributes: [:], content: nil, nodes: [])
|
payload: XMLElement(
|
||||||
|
name: "query",
|
||||||
|
xmlns: "jabber:iq:roster",
|
||||||
|
attributes: attributes,
|
||||||
|
content: nil,
|
||||||
|
nodes: []
|
||||||
|
)
|
||||||
)
|
)
|
||||||
if let req {
|
if let req {
|
||||||
fullReqId = req.id ?? "???"
|
fullReqId = req.id ?? "???"
|
||||||
|
@ -46,13 +66,16 @@ final class RosterModule: XmppModule {
|
||||||
if let query = stanza.wrapped.nodes.first(where: { $0.name == "query" }), query.xmlns == "jabber:iq:roster" {
|
if let query = stanza.wrapped.nodes.first(where: { $0.name == "query" }), query.xmlns == "jabber:iq:roster" {
|
||||||
switch stanza.type {
|
switch stanza.type {
|
||||||
case .iq(.set):
|
case .iq(.set):
|
||||||
return await processSet(state: state, stanza: stanza)
|
return nil
|
||||||
|
// return await processSet(state: state, stanza: stanza)
|
||||||
|
|
||||||
case .iq(.result):
|
case .iq(.result):
|
||||||
return await processResult(state: state, stanza: stanza)
|
return nil
|
||||||
|
// return await processResult(state: state, stanza: stanza)
|
||||||
|
|
||||||
case .iq(.error):
|
case .iq(.error):
|
||||||
// handle errors here
|
// handle errors here
|
||||||
|
// TODO: implement error catching
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -68,88 +91,88 @@ final class RosterModule: XmppModule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension RosterModule {
|
// private extension RosterModule {
|
||||||
private func update(state: ClientState, jidStr: String, args: [String: String]) async -> Event? {
|
// private func update(state: ClientState, jidStr: String, args: [String: String]) async -> Event? {
|
||||||
print(state, jidStr, args)
|
// print(state, jidStr, args)
|
||||||
return nil
|
// return nil
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private func delete(state: ClientState, jidStr: String) async -> Event? {
|
// private func delete(state: ClientState, jidStr: String) async -> Event? {
|
||||||
var existItems: [RosterItem] = []
|
// var existItems: [RosterItem] = []
|
||||||
guard
|
// guard
|
||||||
let data = await storage?.getRoster(jid: state.jid),
|
// let data = await storage?.getRoster(jid: state.jid),
|
||||||
let decoded = try? JSONDecoder().decode([XMLElement].self, from: data),
|
// let decoded = try? JSONDecoder().decode([XMLElement].self, from: data),
|
||||||
let jid = try? JID(jidStr)
|
// let jid = try? JID(jidStr)
|
||||||
else {
|
// else {
|
||||||
return nil
|
// return nil
|
||||||
}
|
// }
|
||||||
existItems = decoded.compactMap { RosterItem(wrap: $0, owner: state.jid) }
|
// existItems = decoded.compactMap { RosterItem(wrap: $0, owner: state.jid) }
|
||||||
existItems = existItems.filter { $0.jid != jid }
|
// existItems = existItems.filter { $0.jid != jid }
|
||||||
return .rosterUpdated
|
// return .rosterUpdated
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private func processSet(state: ClientState, stanza: Stanza) async -> Event? {
|
// private func processSet(state: ClientState, stanza: Stanza) async -> Event? {
|
||||||
// sanity check
|
// // sanity check
|
||||||
if stanza.wrapped.attributes["from"] != state.jid.bare {
|
// if stanza.wrapped.attributes["from"] != state.jid.bare {
|
||||||
return nil
|
// return nil
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// get exists roster items
|
// // get exists roster items
|
||||||
var existItems: [RosterItem] = []
|
// var existItems: [RosterItem] = []
|
||||||
if let data = await storage?.getRoster(jid: state.jid), let decoded = try? JSONDecoder().decode([XMLElement].self, from: data) {
|
// if let data = await storage?.getRoster(jid: state.jid), let decoded = try? JSONDecoder().decode([XMLElement].self, from: data) {
|
||||||
existItems = decoded.compactMap { RosterItem(wrap: $0, owner: state.jid) }
|
// existItems = decoded.compactMap { RosterItem(wrap: $0, owner: state.jid) }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// process
|
// // process
|
||||||
let items = stanza.wrapped
|
// let items = stanza.wrapped
|
||||||
.nodes
|
// .nodes
|
||||||
.first(where: { $0.name == "query" })?
|
// .first(where: { $0.name == "query" })?
|
||||||
.nodes
|
// .nodes
|
||||||
.filter { $0.name == "item" } ?? []
|
// .filter { $0.name == "item" } ?? []
|
||||||
for item in items {
|
// for item in items {
|
||||||
guard let itemJidStr = item.attributes["jid"], let itemJid = try? JID(itemJidStr) else { continue }
|
// guard let itemJidStr = item.attributes["jid"], let itemJid = try? JID(itemJidStr) else { continue }
|
||||||
let subscription = item.attributes["subscription"]
|
// let subscription = item.attributes["subscription"]
|
||||||
switch subscription {
|
// switch subscription {
|
||||||
// TODO: scheck subscription type for removed contacts
|
// // TODO: scheck subscription type for removed contacts
|
||||||
// on different servers
|
// // on different servers
|
||||||
case "remove":
|
// case "remove":
|
||||||
existItems = existItems.filter { $0.jid == itemJid }
|
// existItems = existItems.filter { $0.jid == itemJid }
|
||||||
|
//
|
||||||
// by default just update roster (or add it if its new)
|
// // by default just update roster (or add it if its new)
|
||||||
default:
|
// default:
|
||||||
if let rosterItem = RosterItem(wrap: item, owner: state.jid) {
|
// if let rosterItem = RosterItem(wrap: item, owner: state.jid) {
|
||||||
existItems = existItems.filter { $0.jid == itemJid }
|
// existItems = existItems.filter { $0.jid == itemJid }
|
||||||
existItems.append(rosterItem)
|
// existItems.append(rosterItem)
|
||||||
} else {
|
// } else {
|
||||||
continue
|
// continue
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// save roster
|
// // save roster
|
||||||
guard let data = try? JSONEncoder().encode(existItems.map { $0.wrapped }) else { return nil }
|
// guard let data = try? JSONEncoder().encode(existItems.map { $0.wrapped }) else { return nil }
|
||||||
await storage?.setRoster(jid: state.jid, roster: data)
|
// await storage?.setRoster(jid: state.jid, roster: data)
|
||||||
|
//
|
||||||
// according to RFC-6121 a set from server (push)
|
// // according to RFC-6121 a set from server (push)
|
||||||
// shouyld be answered with result
|
// // shouyld be answered with result
|
||||||
guard
|
// guard
|
||||||
let res = Stanza(wrap: XMLElement(
|
// let res = Stanza(wrap: XMLElement(
|
||||||
name: "iq",
|
// name: "iq",
|
||||||
xmlns: nil,
|
// xmlns: nil,
|
||||||
attributes: [
|
// attributes: [
|
||||||
"from": state.jid.full,
|
// "from": state.jid.full,
|
||||||
"id": stanza.id ?? "???",
|
// "id": stanza.id ?? "???",
|
||||||
"type": "result"
|
// "type": "result"
|
||||||
],
|
// ],
|
||||||
content: nil,
|
// content: nil,
|
||||||
nodes: []
|
// nodes: []
|
||||||
)) else { return nil }
|
// )) else { return nil }
|
||||||
return .stanzaOutbound(res)
|
// return .stanzaOutbound(res)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private func processResult(state _: ClientState, stanza: Stanza) async -> Event? {
|
// private func processResult(state _: ClientState, stanza: Stanza) async -> Event? {
|
||||||
print("--WE HERE 2!")
|
// print("--WE HERE 2!")
|
||||||
print(stanza)
|
// print(stanza)
|
||||||
return nil
|
// return nil
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
|
@ -81,6 +81,7 @@ targets:
|
||||||
- path: AnotherIM
|
- path: AnotherIM
|
||||||
excludes:
|
excludes:
|
||||||
- .nvim
|
- .nvim
|
||||||
|
- xmls
|
||||||
settings:
|
settings:
|
||||||
TARGETED_DEVICE_FAMILY: 1
|
TARGETED_DEVICE_FAMILY: 1
|
||||||
DEBUG_INFORMATION_FORMAT: dwarf-with-dsym
|
DEBUG_INFORMATION_FORMAT: dwarf-with-dsym
|
||||||
|
|
Loading…
Reference in a new issue