Statistics
| Branch: | Tag: | Revision:

chatsecureios / ChatSecure / Classes / Controllers / ServerCheck.swift @ 8d76e2e3

History | View | Annotate | Download (6.18 KB)

1
//
2
//  ServerCheck.swift
3
//  ChatSecure
4
//
5
//  Created by Chris Ballinger on 2/15/17.
6
//  Copyright © 2017 Chris Ballinger. All rights reserved.
7
//
8

    
9
import Foundation
10
import OTRAssets
11

    
12
/**
13
 * The purpose of this class is to collect and process server
14
 * and push info in one place.
15
 *
16
 * All public members must be accessed from the main queue.
17
 */
18
public class ServerCheck: NSObject, OTRServerCapabilitiesDelegate, XMPPPushDelegate {
19
    
20
    @objc public weak var xmpp: XMPPManager?
21
    @objc public let push: PushController
22
    
23
    @objc public var result = ServerCheckResult()
24
    
25
    @objc public static let UpdateNotificationName = Notification.Name(rawValue: "ServerCheckUpdateNotification")
26

    
27
    deinit {
28
        xmpp?.serverCapabilities.removeDelegate(self)
29
        xmpp?.xmppPushModule.removeDelegate(self)
30
        NotificationCenter.default.removeObserver(self)
31
    }
32
    
33
    
34
    @objc public init(xmpp: XMPPManager, push: PushController) {
35
        self.push = push
36
        self.xmpp = xmpp
37
        super.init()
38
        xmpp.serverCapabilities.addDelegate(self, delegateQueue: DispatchQueue.main)
39
        xmpp.xmppPushModule.addDelegate(self, delegateQueue: DispatchQueue.main)
40
        NotificationCenter.default.addObserver(self, selector: #selector(pushAccountChanged(_:)), name: Notification.Name(rawValue: OTRPushAccountDeviceChanged), object: push)
41
        NotificationCenter.default.addObserver(self, selector: #selector(pushAccountChanged(_:)), name: Notification.Name(rawValue: OTRPushAccountTokensChanged), object: push)
42
        fetch()
43
    }
44
    
45
    @objc public func getCombinedPushStatus() -> ServerCheckPushStatus {
46
        if let xmpp = xmpp, xmpp.connectionStatus != .connected {
47
            return .unknown
48
        }
49
        return result.getCombinedPushStatus()
50
    }
51
    
52
    
53
    
54
    /// set pushInfoReady, capabilitiesReady, pushStatusUpdate to get result
55
    @objc public func fetch() {
56
        refreshPush()
57
        refreshCapabilities()
58
        checkReady()
59
    }
60
    
61
    /// Must be called from main queue
62
    @objc public func refresh() {
63
        result.pushInfo = nil
64
        xmpp?.serverCapabilities.fetchAllCapabilities()
65
        fetch()
66
    }
67
    
68
    // This will refresh the pushStatusUpdate block
69
    private func updatePushStatus() {
70
        guard let push = result.pushInfo, let pubsubEndpoint = push.pubsubEndpoint else { return }
71
        if let jid = XMPPJID(user: nil, domain: pubsubEndpoint, resource: nil),
72
           let status = xmpp?.xmppPushModule.registrationStatus(forServerJID: jid) {
73
            result.pushStatus = status
74
            postUpdateNotification()
75
        }
76
    }
77
    
78
    @objc private func pushAccountChanged(_ notification: Notification) {
79
        DispatchQueue.main.async {
80
            self.refresh()
81
        }
82
    }
83
    
84
    private func checkReady() {
85
        if let _ = result.pushInfo {
86
            postUpdateNotification()
87
        }
88
        if let _ = result.capabilities {
89
            postUpdateNotification()
90
        }
91
        updatePushStatus()
92
    }
93
    
94
    private func postUpdateNotification() {
95
        NotificationCenter.default.post(name: type(of: self).UpdateNotificationName, object: self)
96
    }
97
    
98
    private func refreshPush() {
99
        push.gatherPushInfo(completion: { (info) in
100
            self.result.pushInfo = info
101
            self.checkReady()
102
            }, callbackQueue: DispatchQueue.main)
103
    }
104
    
105
    private func refreshCapabilities() {
106
        let caps = ServerCapabilityInfo.allCapabilities()
107
        result.capabilities = xmpp?.serverCapabilities.markAvailable(capabilities: caps)
108
        checkReady()
109
    }
110
    
111
    // MARK: - OTRServerCapabilitiesDelegate
112
    
113
    @objc public func serverCapabilities(_ sender: OTRServerCapabilities, didDiscoverCapabilities capabilities: [XMPPJID : XMLElement]) {
114
        checkReady()
115
    }
116
    
117
    // MARK: - XMPPPushDelegate
118
    
119
    public func pushModule(_ module: XMPPPushModule, didRegisterWithResponseIq responseIq: XMPPIQ, outgoingIq: XMPPIQ) {
120
        checkReady()
121
    }
122
    
123
    public func pushModule(_ module: XMPPPushModule, failedToRegisterWithErrorIq errorIq: XMPPIQ?, outgoingIq: XMPPIQ) {
124
        checkReady()
125
    }
126
    
127
    public func pushModule(_ module: XMPPPushModule, disabledPushForServerJID serverJID: XMPPJID, node: String?, responseIq: XMPPIQ, outgoingIq: XMPPIQ) {
128
        checkReady()
129
    }
130
    
131
    public func pushModule(_ module: XMPPPushModule, failedToDisablePushWithErrorIq errorIq: XMPPIQ?, serverJID: XMPPJID, node: String?, outgoingIq: XMPPIQ) {
132
        checkReady()
133
    }
134
    
135
    public func pushModule(_ module: XMPPPushModule, readyWithCapabilities caps: XMLElement, jid: XMPPJID) {
136
        // This _should_ be handled elsewhere in OTRServerCapabilities
137
        // Not sure why it's not working properly
138
        if var caps = result.capabilities {
139
            caps[.XEP0357]?.status = .Available
140
        }
141
        checkReady()
142
    }
143
}
144

    
145
@objc
146
public enum ServerCheckPushStatus: UInt {
147
    case unknown
148
    case broken
149
    case working
150
}
151

    
152
@objc(OTRServerCheckResult)
153
public class ServerCheckResult: NSObject {
154
    public var capabilities: [CapabilityCode : ServerCapabilityInfo]?
155
    public var pushInfo: PushInfo?
156
    public var pushStatus: XMPPPushStatus?
157
    
158
    /** This lets you collect all push info in one place */
159
    fileprivate func getCombinedPushStatus() -> ServerCheckPushStatus {
160
        var checkStatus: ServerCheckPushStatus = .unknown
161
        if let pushInfo = pushInfo, !pushInfo.pushMaybeWorks() {
162
            return .broken
163
        }
164
        if let pushStatus = pushStatus, pushStatus != .registered {
165
            return .broken
166
        }
167
        if let pushCap = capabilities?[.XEP0357], pushCap.status != .Available {
168
            return .broken
169
        }
170
        guard let caps = capabilities, let push = pushInfo, let status = pushStatus else {
171
            return .unknown
172
        }
173
        var xepExists = false
174
        if let pushCap = caps[.XEP0357], pushCap.status == .Available {
175
            xepExists = true
176
        }
177
        let pushAcctWorks = push.pushMaybeWorks()
178
        let xmppWorks = status == .registered
179
        if xepExists && pushAcctWorks && xmppWorks {
180
            checkStatus = .working
181
        } else {
182
            checkStatus = .broken
183
        }
184
        return checkStatus
185
    }
186
}
187