7
7
8
8
import Foundation
9
9
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
10
24
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
+ }
12
28
public init ( tinode: Tinode ? , l: MeTopic < DP > . Listener ? ) {
13
29
super. init ( tinode: tinode, name: Tinode . kTopicMe, l: l)
14
30
}
15
31
public init ( tinode: Tinode ? , desc: Description < DP , PrivateType > ) {
16
32
super. init ( tinode: tinode, name: Tinode . kTopicMe, desc: desc)
17
33
}
18
34
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
+
19
47
override public var subsUpdated : Date ? {
20
48
get { return tinode? . topicsUpdated }
21
49
}
@@ -25,6 +53,51 @@ open class MeTopic<DP: Codable & Mergeable>: Topic<DP, PrivateType, DP, PrivateT
25
53
return 0
26
54
}
27
55
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
+
28
101
override public func topicLeft( unsub: Bool ? , code: Int ? , reason: String ? ) {
29
102
super. topicLeft ( unsub: unsub, code: code, reason: reason)
30
103
if let topics = tinode? . getTopics ( ) {
@@ -34,7 +107,7 @@ open class MeTopic<DP: Codable & Mergeable>: Topic<DP, PrivateType, DP, PrivateT
34
107
}
35
108
}
36
109
37
- override public func updateMode( update: String ) -> PromisedReply < ServerMessage > ? {
110
+ override public func updateMode( update: String ) -> PromisedReply < ServerMessage > {
38
111
var acs = accessMode
39
112
if acs == nil {
40
113
acs = Acs ( )
@@ -73,6 +146,22 @@ open class MeTopic<DP: Codable & Mergeable>: Topic<DP, PrivateType, DP, PrivateT
73
146
}
74
147
}
75
148
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
+
76
165
override public func routePres( pres: MsgServerPres ) {
77
166
let what = MsgServerPres . parseWhat ( what: pres. what)
78
167
if what == . kTerm {
@@ -193,4 +282,63 @@ open class MeTopic<DP: Codable & Mergeable>: Topic<DP, PrivateType, DP, PrivateT
193
282
}
194
283
listener? . onSubsUpdated ( )
195
284
}
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
+ }
196
344
}
0 commit comments