@@ -5,17 +5,21 @@ use matrix_sdk::{
5
5
config:: SyncSettings ,
6
6
media:: { MediaFormat , MediaRequest } ,
7
7
ruma:: {
8
- api:: client:: {
9
- account:: whoami,
10
- filter:: { FilterDefinition , LazyLoadOptions , RoomEventFilter , RoomFilter } ,
11
- session:: get_login_types,
12
- sync:: sync_events:: v3:: Filter ,
8
+ api:: {
9
+ client:: {
10
+ account:: whoami,
11
+ error:: ErrorKind ,
12
+ filter:: { FilterDefinition , LazyLoadOptions , RoomEventFilter , RoomFilter } ,
13
+ session:: get_login_types,
14
+ sync:: sync_events:: v3:: Filter ,
15
+ } ,
16
+ error:: { FromHttpResponseError , ServerError } ,
13
17
} ,
14
18
events:: room:: MediaSource ,
15
19
serde:: Raw ,
16
20
TransactionId ,
17
21
} ,
18
- Client as MatrixClient , LoopCtrl , Session ,
22
+ Client as MatrixClient , Error , HttpError , LoopCtrl , RumaApiError , Session ,
19
23
} ;
20
24
21
25
use super :: {
@@ -32,6 +36,8 @@ impl std::ops::Deref for Client {
32
36
33
37
pub trait ClientDelegate : Sync + Send {
34
38
fn did_receive_sync_update ( & self ) ;
39
+ fn did_receive_auth_error ( & self , is_soft_logout : bool ) ;
40
+ fn did_update_restore_token ( & self ) ;
35
41
}
36
42
37
43
#[ derive( Clone ) ]
@@ -54,18 +60,34 @@ impl Client {
54
60
}
55
61
56
62
/// Login using a username and password.
57
- pub fn login ( & self , username : String , password : String ) -> anyhow:: Result < ( ) > {
63
+ pub fn login (
64
+ & self ,
65
+ username : String ,
66
+ password : String ,
67
+ initial_device_name : Option < String > ,
68
+ device_id : Option < String > ,
69
+ ) -> anyhow:: Result < ( ) > {
58
70
RUNTIME . block_on ( async move {
59
- self . client . login_username ( & username, & password) . send ( ) . await ?;
71
+ let mut builder = self . client . login_username ( & username, & password) ;
72
+ if let Some ( initial_device_name) = initial_device_name. as_ref ( ) {
73
+ builder = builder. initial_device_display_name ( initial_device_name) ;
74
+ }
75
+ if let Some ( device_id) = device_id. as_ref ( ) {
76
+ builder = builder. device_id ( device_id) ;
77
+ }
78
+ builder. send ( ) . await ?;
60
79
Ok ( ( ) )
61
80
} )
62
81
}
63
82
64
83
/// Restores the client from a `RestoreToken`.
65
84
pub fn restore_login ( & self , restore_token : String ) -> anyhow:: Result < ( ) > {
66
- let RestoreToken { session, homeurl : _, is_guest : _ } =
85
+ let RestoreToken { session, homeurl : _, is_guest : _, is_soft_logout } =
67
86
serde_json:: from_str ( & restore_token) ?;
68
87
88
+ // update soft logout state
89
+ self . state . write ( ) . unwrap ( ) . is_soft_logout = is_soft_logout;
90
+
69
91
self . restore_session ( session)
70
92
}
71
93
@@ -112,6 +134,7 @@ impl Client {
112
134
let state = self . state . clone ( ) ;
113
135
let delegate = self . delegate . clone ( ) ;
114
136
let session_verification_controller = self . session_verification_controller . clone ( ) ;
137
+ let local_self = self . clone ( ) ;
115
138
RUNTIME . spawn ( async move {
116
139
let mut filter = FilterDefinition :: default ( ) ;
117
140
let mut room_filter = RoomFilter :: default ( ) ;
@@ -131,31 +154,35 @@ impl Client {
131
154
let sync_settings = SyncSettings :: new ( ) . filter ( Filter :: FilterId ( & filter_id) ) ;
132
155
133
156
client
134
- . sync_with_callback ( sync_settings, |sync_response| async {
135
- if !state. read ( ) . unwrap ( ) . has_first_synced {
136
- state. write ( ) . unwrap ( ) . has_first_synced = true ;
137
- }
138
-
139
- if state. read ( ) . unwrap ( ) . should_stop_syncing {
140
- state. write ( ) . unwrap ( ) . is_syncing = false ;
141
- return LoopCtrl :: Break ;
142
- } else if !state. read ( ) . unwrap ( ) . is_syncing {
143
- state. write ( ) . unwrap ( ) . is_syncing = true ;
157
+ . sync_with_result_callback ( sync_settings, |result| async {
158
+ if let Ok ( sync_response) = result {
159
+ if !state. read ( ) . unwrap ( ) . has_first_synced {
160
+ state. write ( ) . unwrap ( ) . has_first_synced = true ;
161
+ }
162
+
163
+ if state. read ( ) . unwrap ( ) . should_stop_syncing {
164
+ state. write ( ) . unwrap ( ) . is_syncing = false ;
165
+ return LoopCtrl :: Break ;
166
+ } else if !state. read ( ) . unwrap ( ) . is_syncing {
167
+ state. write ( ) . unwrap ( ) . is_syncing = true ;
168
+ }
169
+
170
+ if let Some ( delegate) = & * delegate. read ( ) . unwrap ( ) {
171
+ delegate. did_receive_sync_update ( )
172
+ }
173
+
174
+ if let Some ( session_verification_controller) =
175
+ & * session_verification_controller. read ( ) . await
176
+ {
177
+ session_verification_controller
178
+ . process_to_device_messages ( sync_response. to_device )
179
+ . await ;
180
+ }
181
+
182
+ LoopCtrl :: Continue
183
+ } else {
184
+ local_self. process_sync_error ( result. err ( ) . unwrap ( ) )
144
185
}
145
-
146
- if let Some ( delegate) = & * delegate. read ( ) . unwrap ( ) {
147
- delegate. did_receive_sync_update ( )
148
- }
149
-
150
- if let Some ( session_verification_controller) =
151
- & * session_verification_controller. read ( ) . await
152
- {
153
- session_verification_controller
154
- . process_to_device_messages ( sync_response. to_device )
155
- . await ;
156
- }
157
-
158
- LoopCtrl :: Continue
159
186
} )
160
187
. await ;
161
188
} ) ;
@@ -169,6 +196,7 @@ impl Client {
169
196
session,
170
197
homeurl,
171
198
is_guest : self . state . read ( ) . unwrap ( ) . is_guest ,
199
+ is_soft_logout : self . state . read ( ) . unwrap ( ) . is_soft_logout ,
172
200
} ) ?)
173
201
} )
174
202
}
@@ -258,6 +286,35 @@ impl Client {
258
286
Ok ( Arc :: new ( session_verification_controller) )
259
287
} )
260
288
}
289
+
290
+ /// Log out the current user
291
+ pub fn logout ( & self ) -> anyhow:: Result < ( ) > {
292
+ RUNTIME . block_on ( async move {
293
+ match self . client . logout ( ) . await {
294
+ Ok ( _) => Ok ( ( ) ) ,
295
+ Err ( error) => Err ( anyhow ! ( error. to_string( ) ) ) ,
296
+ }
297
+ } )
298
+ }
299
+
300
+ /// Process a sync error and return loop control accordingly
301
+ fn process_sync_error ( & self , sync_error : Error ) -> LoopCtrl {
302
+ let mut control = LoopCtrl :: Continue ;
303
+ if let Error :: Http ( HttpError :: Api ( FromHttpResponseError :: Server ( ServerError :: Known (
304
+ RumaApiError :: ClientApi ( error) ,
305
+ ) ) ) ) = sync_error
306
+ {
307
+ if let ErrorKind :: UnknownToken { soft_logout } = error. kind {
308
+ self . state . write ( ) . unwrap ( ) . is_soft_logout = soft_logout;
309
+ if let Some ( delegate) = & * self . delegate . read ( ) . unwrap ( ) {
310
+ delegate. did_update_restore_token ( ) ;
311
+ delegate. did_receive_auth_error ( soft_logout) ;
312
+ }
313
+ control = LoopCtrl :: Break
314
+ }
315
+ }
316
+ control
317
+ }
261
318
}
262
319
263
320
#[ uniffi:: export]
@@ -283,6 +340,11 @@ impl Client {
283
340
self . state . read ( ) . unwrap ( ) . is_guest
284
341
}
285
342
343
+ /// Flag indicating whether the session is in soft logout mode
344
+ pub fn is_soft_logout ( & self ) -> bool {
345
+ self . state . read ( ) . unwrap ( ) . is_soft_logout
346
+ }
347
+
286
348
pub fn rooms ( & self ) -> Vec < Arc < Room > > {
287
349
self . client . rooms ( ) . into_iter ( ) . map ( |room| Arc :: new ( Room :: new ( room) ) ) . collect ( )
288
350
}
0 commit comments