wip
This commit is contained in:
parent
0be3f68710
commit
7a722e200c
|
@ -66,6 +66,7 @@ final class TestStorage: XMPPStorage {
|
|||
|
||||
func setRoster(jid: JID, roster: Data) async {
|
||||
self.roster[jid.bare] = roster
|
||||
print("updated")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,9 @@ enum Event {
|
|||
case streamReady
|
||||
|
||||
case requestRoster
|
||||
// case gotRoster // by request or by server push
|
||||
case rosterUpdated
|
||||
case addRosterItem(jidStr: String)
|
||||
case deleteRosterItem(jidStr: String)
|
||||
}
|
||||
|
||||
// MARK: State
|
||||
|
@ -118,6 +120,18 @@ extension XMPPClient {
|
|||
await fire(.startClientLogin(jid: jid, credsId: credentialsId))
|
||||
}
|
||||
}
|
||||
|
||||
func addContact(jidStr: String) {
|
||||
Task {
|
||||
await fire(.addRosterItem(jidStr: jidStr))
|
||||
}
|
||||
}
|
||||
|
||||
func deleteRosterItem(jidStr: String) {
|
||||
Task {
|
||||
await fire(.deleteRosterItem(jidStr: jidStr))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Private part
|
||||
|
|
|
@ -30,7 +30,7 @@ enum RosterSubsriptionType: String {
|
|||
|
||||
// Roster is a "transparent" structure
|
||||
// which is just wrap xml item around
|
||||
struct Roster: Identifiable, Equatable {
|
||||
struct RosterItem: Identifiable, Equatable {
|
||||
let owner: String
|
||||
let wrapped: XMLElement
|
||||
|
||||
|
@ -62,8 +62,8 @@ struct Roster: Identifiable, Equatable {
|
|||
return RosterSubsriptionType(rawValue: str) ?? .none
|
||||
}
|
||||
|
||||
static func == (_ rhs: Roster, _ lhs: Roster) -> Bool {
|
||||
rhs.id == lhs.id
|
||||
static func == (_ rhs: RosterItem, _ lhs: RosterItem) -> Bool {
|
||||
rhs.id == lhs.id && rhs.wrapped == lhs.wrapped
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import Foundation
|
||||
|
||||
struct XMLElement: Codable, CustomStringConvertible {
|
||||
struct XMLElement: Codable, Equatable, CustomStringConvertible {
|
||||
let name: String
|
||||
let xmlns: String?
|
||||
let attributes: [String: String]
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import Foundation
|
||||
|
||||
// TODO: add versioning (XEP-0237) if needed
|
||||
// TODO: implement error catching
|
||||
final class RosterModule: XmppModule {
|
||||
let id = "Roseter module"
|
||||
|
||||
|
@ -31,12 +32,11 @@ final class RosterModule: XmppModule {
|
|||
}
|
||||
|
||||
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 await processRoster(state: state, stanza: stanza)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
default:
|
||||
return nil
|
||||
|
@ -45,28 +45,40 @@ final class RosterModule: XmppModule {
|
|||
}
|
||||
|
||||
private extension RosterModule {
|
||||
func processRoster(state: ClientState, xml: XMLElement) async -> Event? {
|
||||
func processRoster(state: ClientState, stanza: Stanza) async -> Event? {
|
||||
// get inner query
|
||||
guard let query = stanza.wrapped.nodes.first(where: { $0.name == "query" })
|
||||
else { return nil }
|
||||
|
||||
// get exists roster items
|
||||
var existItems: [Roster] = []
|
||||
var existItems: [RosterItem] = []
|
||||
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) }
|
||||
existItems = decoded.compactMap { RosterItem(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) {
|
||||
// process push (.set from server)
|
||||
if stanza.type == .iq(.set) {
|
||||
guard
|
||||
let item = query.nodes.first(where: { $0.name == "item" }),
|
||||
let new = RosterItem(wrap: item, owner: state.jid)
|
||||
else { return nil }
|
||||
existItems = existItems.filter { $0.jid != new.jid }
|
||||
existItems.append(new)
|
||||
guard let data = try? JSONEncoder().encode(existItems.map { $0.wrapped }) else { return nil }
|
||||
await storage?.setRoster(jid: state.jid, roster: data)
|
||||
}
|
||||
return .rosterUpdated
|
||||
|
||||
// process get response (.result from server)
|
||||
} else if stanza.type == .iq(.get) {
|
||||
let items = query.nodes.filter { $0.name == "item" }
|
||||
guard let data = try? JSONEncoder().encode(items) else { return nil }
|
||||
await storage?.setRoster(jid: state.jid, roster: data)
|
||||
return .rosterUpdated
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// <iq to='testmon3@test.anal.company/TwtWkVOZ3liz' type='result' id='7l899q9r'>
|
||||
// <query ver='27' xmlns='jabber:iq:roster'>
|
||||
|
|
Loading…
Reference in a new issue