Skip to content

Commit 81e79ad

Browse files
authored
Merge pull request #145 from tinode/next
Cleanup of PromisedReplies, credentials work now
2 parents fe6b7fc + 527f97c commit 81e79ad

32 files changed

+989
-742
lines changed

TinodeSDK.xcodeproj/project.pbxproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,17 +159,17 @@
159159
isa = PBXGroup;
160160
children = (
161161
0A431BE72244A14B00A837F7 /* JSONValue.swift */,
162-
0A81B316236FA896009AF14B /* Types.swift */,
163162
0A431BE82244A14B00A837F7 /* Acs.swift */,
164163
0A431BE92244A14B00A837F7 /* AcsHelper.swift */,
165164
0A431BEA2244A14B00A837F7 /* ClientMessages.swift */,
166165
0A431BEB2244A14B00A837F7 /* Defacs.swift */,
167166
0A431BEC2244A14B00A837F7 /* Description.swift */,
168167
0A431BED2244A14B00A837F7 /* Drafty.swift */,
168+
0AAF8BEB23B70E2A00C9CFBB /* MsgRange.swift */,
169169
0A431BEE2244A14B00A837F7 /* ServerMessages.swift */,
170170
0A431BEF2244A14B00A837F7 /* Subscription.swift */,
171+
0A81B316236FA896009AF14B /* Types.swift */,
171172
0A431BF02244A14B00A837F7 /* VCard.swift */,
172-
0AAF8BEB23B70E2A00C9CFBB /* MsgRange.swift */,
173173
);
174174
path = model;
175175
sourceTree = "<group>";

TinodeSDK/FndTopic.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public class FndTopic<SP: Codable>: Topic<String, String, SP, Array<String>> {
1414
}
1515

1616
@discardableResult
17-
override public func setMeta(meta: MsgSetMeta<String, String>) -> PromisedReply<ServerMessage>? {
17+
override public func setMeta(meta: MsgSetMeta<String, String>) -> PromisedReply<ServerMessage> {
1818
if self.subs != nil {
1919
self.subs!.removeAll()
2020
self.subs = nil

TinodeSDK/MeTopic.swift

Lines changed: 150 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,43 @@
77

88
import Foundation
99

10+
public protocol MeTopicProto: TopicProto {
11+
var creds: [Credential]? { get set }
12+
func serializeCreds() -> String?
13+
@discardableResult
14+
func deserializeCreds(from data: String?) -> Bool
15+
}
16+
17+
open class MeTopic<DP: Codable & Mergeable>: Topic<DP, PrivateType, DP, PrivateType>, MeTopicProto {
18+
open class Listener: Topic<DP, PrivateType, DP, PrivateType>.Listener {
19+
// Called when user credentials are updated.
20+
open func onCredUpdated(cred: [Credential]?) {}
21+
}
22+
23+
private var credentials: [Credential]? = nil
1024

11-
open class MeTopic<DP: Codable & Mergeable>: Topic<DP, PrivateType, DP, PrivateType> {
25+
public init(tinode: Tinode?) {
26+
super.init(tinode: tinode, name: Tinode.kTopicMe, l: nil)
27+
}
1228
public init(tinode: Tinode?, l: MeTopic<DP>.Listener?) {
1329
super.init(tinode: tinode, name: Tinode.kTopicMe, l: l)
1430
}
1531
public init(tinode: Tinode?, desc: Description<DP, PrivateType>) {
1632
super.init(tinode: tinode, name: Tinode.kTopicMe, desc: desc)
1733
}
1834

35+
public func serializeCreds() -> String? {
36+
guard let c = self.creds else { return nil }
37+
return Tinode.serializeObject(c)
38+
}
39+
public func deserializeCreds(from data: String?) -> Bool {
40+
if let c: [Credential]? = Tinode.deserializeObject(from: data) {
41+
self.creds = c
42+
return true
43+
}
44+
return false
45+
}
46+
1947
override public var subsUpdated: Date? {
2048
get { return tinode?.topicsUpdated }
2149
}
@@ -25,6 +53,51 @@ open class MeTopic<DP: Codable & Mergeable>: Topic<DP, PrivateType, DP, PrivateT
2553
return 0
2654
}
2755

56+
public var creds: [Credential]? {
57+
get { return credentials }
58+
set {
59+
if let c = newValue {
60+
credentials = c.sorted(by: <)
61+
} else {
62+
credentials = nil
63+
}
64+
}
65+
}
66+
67+
public func delCredential(meth: String, val: String) -> PromisedReply<ServerMessage> {
68+
return delCredential(Credential(meth: meth, val: val))
69+
}
70+
71+
public func delCredential(_ cred: Credential) -> PromisedReply<ServerMessage> {
72+
let tnd = tinode!
73+
74+
return tnd.delCredential(cred: cred)
75+
.thenApply { [weak self] msg in
76+
guard let idx = self?.findCredIndex(cred: cred, anyUnconfirmed: false) else { return nil }
77+
78+
if idx >= 0 {
79+
self?.credentials?.remove(at: idx)
80+
// No need to sort.
81+
}
82+
83+
// Notify listeners
84+
(self?.listener as! Listener).onCredUpdated(cred: self?.creds)
85+
return nil
86+
}
87+
}
88+
89+
public func confirmCred(meth: String, response: String) ->PromisedReply<ServerMessage> {
90+
let cred = Credential(meth: meth, val: nil, resp: response, params: nil)
91+
return setMeta(meta: MsgSetMeta(desc: nil, sub: nil, tags: nil, cred: cred));
92+
}
93+
94+
private func findCredIndex(cred other: Credential, anyUnconfirmed: Bool) -> Int {
95+
guard let creds = creds else { return -1 }
96+
return creds.firstIndex {
97+
$0.meth == other.meth && ((anyUnconfirmed && !$0.isDone) || $0.val == other.val)
98+
} ?? -1
99+
}
100+
28101
override public func topicLeft(unsub: Bool?, code: Int?, reason: String?) {
29102
super.topicLeft(unsub: unsub, code: code, reason: reason)
30103
if let topics = tinode?.getTopics() {
@@ -34,7 +107,7 @@ open class MeTopic<DP: Codable & Mergeable>: Topic<DP, PrivateType, DP, PrivateT
34107
}
35108
}
36109

37-
override public func updateMode(update: String) -> PromisedReply<ServerMessage>? {
110+
override public func updateMode(update: String) -> PromisedReply<ServerMessage> {
38111
var acs = accessMode
39112
if acs == nil {
40113
acs = Acs()
@@ -73,6 +146,22 @@ open class MeTopic<DP: Codable & Mergeable>: Topic<DP, PrivateType, DP, PrivateT
73146
}
74147
}
75148

149+
override internal func update(ctrl: MsgServerCtrl, meta: MsgSetMeta<DP, PrivateType>) {
150+
super.update(ctrl: ctrl, meta: meta)
151+
if let cred = meta.cred {
152+
routeMetaCred(cred: cred)
153+
154+
(listener as? MeTopic.Listener)?.onCredUpdated(cred: [cred])
155+
}
156+
}
157+
158+
override public func routeMeta(meta: MsgServerMeta) {
159+
if let cred = meta.cred {
160+
routeMetaCred(cred: cred)
161+
}
162+
super.routeMeta(meta: meta)
163+
}
164+
76165
override public func routePres(pres: MsgServerPres) {
77166
let what = MsgServerPres.parseWhat(what: pres.what)
78167
if what == .kTerm {
@@ -193,4 +282,63 @@ open class MeTopic<DP: Codable & Mergeable>: Topic<DP, PrivateType, DP, PrivateT
193282
}
194283
listener?.onSubsUpdated()
195284
}
285+
286+
private func processOneCred(_ cred: Credential) {
287+
guard cred.meth != nil else { return }
288+
289+
if cred.val != nil {
290+
if creds == nil {
291+
// Empty list. Create list with one new element.
292+
credentials = [cred]
293+
} else {
294+
// Try finding this credential among confirmed or not.
295+
var idx = findCredIndex(cred: cred, anyUnconfirmed: false)
296+
if idx < 0 {
297+
// Not found.
298+
if !cred.isDone {
299+
// Unconfirmed credential replaces previous unconfirmed credential of the same method.
300+
idx = findCredIndex(cred: cred, anyUnconfirmed: true)
301+
if idx >= 0 {
302+
// Remove previous unconfirmed credential.
303+
credentials!.remove(at: idx)
304+
}
305+
}
306+
credentials!.append(cred)
307+
} else {
308+
// Found. Maybe change 'done' status.
309+
credentials?[idx].done = cred.isDone
310+
}
311+
}
312+
} else if cred.resp != nil && credentials != nil {
313+
// Handle credential confirmation.
314+
let idx = findCredIndex(cred: cred, anyUnconfirmed: true)
315+
if idx >= 0 {
316+
credentials?[idx].done = true
317+
}
318+
}
319+
// Ensure predictable order.
320+
credentials?.sort(by: <)
321+
}
322+
323+
internal func routeMetaCred(cred: Credential) {
324+
processOneCred(cred)
325+
326+
(listener as! Listener).onCredUpdated(cred: creds)
327+
}
328+
329+
internal func routeMetaCred(cred: [Credential]) {
330+
var newCreds: [Credential] = []
331+
for c in cred {
332+
if c.meth != nil && c.val != nil {
333+
newCreds.append(c)
334+
}
335+
}
336+
337+
// Ensure predictable order of credentials.
338+
newCreds.sort(by: <)
339+
credentials = newCreds
340+
341+
// Notify listeners
342+
(listener as! Listener).onCredUpdated(cred: creds)
343+
}
196344
}

TinodeSDK/PromisedReply.swift

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,11 @@ public class PromisedReply<Value> {
133133
}
134134
}
135135
@discardableResult
136-
public func then(onSuccess successHandler: SuccessHandler,
137-
onFailure failureHandler: FailureHandler = nil) throws -> PromisedReply<Value>? {
138-
return try queue.sync {
136+
public func then(onSuccess successHandler: SuccessHandler, onFailure failureHandler: FailureHandler = nil) -> PromisedReply<Value> {
137+
return queue.sync {
139138
// start critical section
140139
guard nextPromise == nil else {
141-
throw PromisedReplyError.illegalStateError("Multiple calls to then are not supported")
140+
fatalError("Multiple calls to then are not supported")
142141
}
143142
self.successHandler = successHandler
144143
self.failureHandler = failureHandler
@@ -152,24 +151,22 @@ public class PromisedReply<Value> {
152151
case .waiting: break
153152
}
154153
} catch {
155-
nextPromise = PromisedReply<Value>(error: error)
154+
self.nextPromise = PromisedReply<Value>(error: error)
156155
}
157-
return nextPromise
156+
return self.nextPromise!
158157
}
159158
}
160159
@discardableResult
161-
public func thenApply(onSuccess successHandler: SuccessHandler)
162-
throws -> PromisedReply<Value>? {
163-
return try then(onSuccess: successHandler, onFailure: nil)
160+
public func thenApply(_ successHandler: SuccessHandler) -> PromisedReply<Value> {
161+
return then(onSuccess: successHandler, onFailure: nil)
164162
}
165163
@discardableResult
166-
public func thenCatch(onFailure failureHandler: FailureHandler)
167-
throws -> PromisedReply<Value>? {
168-
return try then(onSuccess: nil, onFailure: failureHandler)
164+
public func thenCatch(_ failureHandler: FailureHandler) -> PromisedReply<Value> {
165+
return then(onSuccess: nil, onFailure: failureHandler)
169166
}
170167

171-
public func thenFinally(finally: @escaping FinallyHandler) throws {
172-
try then(
168+
public func thenFinally(_ finally: @escaping FinallyHandler) {
169+
then(
173170
onSuccess: {
174171
msg in try finally()
175172
return nil

0 commit comments

Comments
 (0)