77 lines
2.4 KiB
Swift
77 lines
2.4 KiB
Swift
import Foundation
|
|
|
|
// TODO: add versioning (XEP-0237) if needed
|
|
final class RosterModule: XmppModule {
|
|
let id = "Roseter module"
|
|
|
|
private weak var storage: (any XMPPStorage)?
|
|
|
|
init(_ storage: any XMPPStorage) {
|
|
self.storage = storage
|
|
}
|
|
|
|
func reduce(oldState: ClientState, with _: Event) -> ClientState {
|
|
oldState
|
|
}
|
|
|
|
func process(state: ClientState, with event: Event) async -> Event? {
|
|
switch event {
|
|
case .streamReady:
|
|
return .requestRoster
|
|
|
|
case .requestRoster:
|
|
let req = Stanza.iqGet(
|
|
from: state.jid.full,
|
|
payload: XMLElement(name: "query", xmlns: "jabber:iq:roster", attributes: [:], content: nil, nodes: [])
|
|
)
|
|
if let req {
|
|
return .stanzaOutbound(req)
|
|
} else {
|
|
return nil
|
|
}
|
|
|
|
case .stanzaInbound(let stanza):
|
|
if stanza.type == .iq(.result) {
|
|
if let query = stanza.wrapped.nodes.first(where: { $0.name == "query" }), query.xmlns == "jabber:iq:roster" {
|
|
return await processRoster(state: state, xml: query)
|
|
}
|
|
}
|
|
return nil
|
|
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
|
|
private extension RosterModule {
|
|
func processRoster(state: ClientState, xml: XMLElement) async -> Event? {
|
|
// get exists roster items
|
|
var existItems: [Roster] = []
|
|
if let data = await storage?.getRoster(jid: state.jid), let decoded = try? JSONDecoder().decode([XMLElement].self, from: data) {
|
|
existItems = decoded.compactMap { Roster(wrap: $0, owner: state.jid) }
|
|
}
|
|
|
|
// extract items from incoming xml
|
|
var newItems = xml.nodes
|
|
.compactMap { Roster(wrap: $0, owner: state.jid) }
|
|
|
|
// manage it ?????
|
|
var roster: [XMLElement] = newItems.map { $0.wrapped }
|
|
|
|
// save updated roster
|
|
if let data = try? JSONEncoder().encode(roster) {
|
|
await storage?.setRoster(jid: state.jid, roster: data)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// <iq to='testmon3@test.anal.company/TwtWkVOZ3liz' type='result' id='7l899q9r'>
|
|
// <query ver='27' xmlns='jabber:iq:roster'>
|
|
// <item jid='fmodf@conversations.im' subscription='both' xmlns='jabber:iq:roster'/>
|
|
// <item subscription='to' jid='testmon4@test.anal.company' xmlns='jabber:iq:roster'/>
|
|
// </query>
|
|
// </iq>
|