This commit is contained in:
fmodf 2024-12-16 13:51:12 +01:00
parent ff6f3f3ee2
commit ab01430aae
5 changed files with 54 additions and 7 deletions

View file

@ -38,7 +38,12 @@ enum Event {
case bindStream
case bindStreamDone(String)
case bindStreamError
// stream established, RFC-6120 procedure done
case streamReady
case requestRoster
// case gotRoster // by request or by server push
}
// MARK: State
@ -83,6 +88,7 @@ struct ClientState: Codable & Equatable {
}
}
// MARK: Client
final class XMPPClient {
private var state = ClientState.initial
private let logger = ClientLogger()
@ -94,7 +100,8 @@ final class XMPPClient {
SessionModule(),
AuthorizationModule(self.storage),
StanzaModule(self.storage),
DiscoveryModule()
DiscoveryModule(),
RosterModule()
]
init(storage: any XMPPClientStorageProtocol, userAgent: UserAgent) {
@ -103,7 +110,7 @@ final class XMPPClient {
}
func tryLogin(jid: JID, credentialsId: UUID) {
logger.update(jid.description)
logger.update(jid.full)
Task {
await fire(.startClientLogin(jid: jid, credsId: credentialsId))
}

View file

@ -10,7 +10,7 @@ struct JID: Hashable, CustomStringConvertible, Codable, Equatable {
resourcePart = parts.2
}
var description: String {
var full: String {
var str = "\(localPart)@\(domainPart)"
if let resource = resourcePart {
str += "/\(resource)"
@ -18,6 +18,10 @@ struct JID: Hashable, CustomStringConvertible, Codable, Equatable {
return str
}
var description: String {
full
}
var hash: Int {
if let resourcePart {
return "\(localPart)@\(domainPart)/\(resourcePart)".hashValue

View file

@ -75,18 +75,26 @@ struct Stanza {
// MARK: Init
extension Stanza {
static func iqGet(payload: XMLElement) -> Stanza? {
static func iqGet(jid: String? = nil, payload: XMLElement) -> Stanza? {
var attributes = ["id": XMLElement.randomId, "type": "get"]
if let jid {
attributes["from"] = jid
}
let req = XMLElement(
name: "iq",
xmlns: nil,
attributes: ["type": "get", "id": XMLElement.randomId],
attributes: attributes,
content: nil,
nodes: [payload]
)
return Stanza(wrap: req)
}
static func iqSet(payload: XMLElement) -> Stanza? {
static func iqSet(jid: String? = nil, payload: XMLElement) -> Stanza? {
var attributes = ["id": XMLElement.randomId, "type": "get"]
if let jid {
attributes["from"] = jid
}
let req = XMLElement(
name: "iq",
xmlns: nil,

View file

@ -0,0 +1,28 @@
import Foundation
final class RosterModule: XmppModule {
let id = "Roseter module"
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:
// TODO: check version!
let req = Stanza.iqGet(jid: state.jid.full, payload: XMLElement(name: "query", xmlns: "jabber:iq:roster", attributes: [:], content: nil, nodes: []))
if let req {
return .stanzaOutbound(req)
} else {
return nil
}
default:
return nil
}
}
}

View file

@ -92,7 +92,7 @@ final class SessionModule: XmppModule {
name: "stream:stream",
xmlns: nil,
attributes: [
"from": state.jid.description,
"from": state.jid.bare,
"to": state.jid.domainPart,
"xml:lang": "en",
"version": "1.0",