@@ -105,7 +105,8 @@ impl IdentityManager {
105105 ///
106106 /// # Arguments
107107 ///
108- /// * `request_id` - The request_id returned by users_for_key_query
108+ /// * `request_id` - The request_id returned by `users_for_key_query` or
109+ /// `build_key_query_for_users`
109110 /// * `response` - The keys query response of the request that the client
110111 /// performed.
111112 pub async fn receive_keys_query_response (
@@ -619,6 +620,38 @@ impl IdentityManager {
619620 Ok ( ( changes, changed_identity) )
620621 }
621622
623+ /// Generate an "out-of-band" key query request for the given set of users.
624+ ///
625+ /// Unlike the regular key query requests returned by `users_for_key_query`,
626+ /// there can be several of these in flight at once. This can be useful
627+ /// if we need results to be as up-to-date as possible.
628+ ///
629+ /// Once the request has been made, the response can be fed back into the
630+ /// IdentityManager and store by calling `receive_keys_query_response`.
631+ ///
632+ /// # Arguments
633+ ///
634+ /// * `users` - list of users whose keys should be queried
635+ ///
636+ /// # Returns
637+ ///
638+ /// A tuple containing the request ID for the request, and the request
639+ /// itself.
640+ pub ( crate ) fn build_key_query_for_users < ' a > (
641+ & self ,
642+ users : impl IntoIterator < Item = & ' a UserId > ,
643+ ) -> ( OwnedTransactionId , KeysQueryRequest ) {
644+ // Since this is an "out-of-band" request, we just make up a transaction ID and
645+ // do not store the details in `self.keys_query_request_details`.
646+ //
647+ // `receive_keys_query_response` will process the response as normal, except
648+ // that it will not mark the users as "up-to-date".
649+
650+ // We assume that there aren't too many users here; if we find a usecase that
651+ // requires lots of users to be up-to-date we may need to rethink this.
652+ ( TransactionId :: new ( ) , KeysQueryRequest :: new ( users. into_iter ( ) . map ( |u| u. to_owned ( ) ) ) )
653+ }
654+
622655 /// Get a list of key query requests needed.
623656 ///
624657 /// # Returns
@@ -969,6 +1002,7 @@ pub(crate) mod tests {
9691002 use serde_json:: json;
9701003
9711004 use super :: testing:: { device_id, key_query, manager, other_key_query, other_user_id, user_id} ;
1005+ use crate :: identities:: manager:: testing:: own_key_query;
9721006
9731007 fn key_query_with_failures ( ) -> KeysQueryResponse {
9741008 let response = json ! ( {
@@ -1161,4 +1195,24 @@ pub(crate) mod tests {
11611195 . iter( )
11621196 . any( |( _, r) | r. device_keys. contains_key( alice) ) ) ;
11631197 }
1198+
1199+ #[ async_test]
1200+ async fn test_out_of_band_key_query ( ) {
1201+ // build the request
1202+ let manager = manager ( ) . await ;
1203+ let ( reqid, req) = manager. build_key_query_for_users ( vec ! [ user_id( ) ] ) ;
1204+ assert ! ( req. device_keys. contains_key( user_id( ) ) ) ;
1205+
1206+ // make up a response and check it is processed
1207+ let ( device_changes, identity_changes) =
1208+ manager. receive_keys_query_response ( & reqid, & own_key_query ( ) ) . await . unwrap ( ) ;
1209+ assert_eq ! ( device_changes. new. len( ) , 1 ) ;
1210+ assert_eq ! ( device_changes. new[ 0 ] . device_id( ) , "LVWOVGOXME" ) ;
1211+ assert_eq ! ( identity_changes. new. len( ) , 1 ) ;
1212+ assert_eq ! ( identity_changes. new[ 0 ] . user_id( ) , user_id( ) ) ;
1213+
1214+ let devices = manager. store . get_user_devices ( user_id ( ) ) . await . unwrap ( ) ;
1215+ assert_eq ! ( devices. devices( ) . count( ) , 1 ) ;
1216+ assert_eq ! ( devices. devices( ) . next( ) . unwrap( ) . device_id( ) , "LVWOVGOXME" ) ;
1217+ }
11641218}
0 commit comments