@@ -124,35 +124,115 @@ export default class OutgoingRoomKeyRequestManager {
124
124
*
125
125
* @param {module:crypto~RoomKeyRequestBody } requestBody
126
126
* @param {Array<{userId: string, deviceId: string}> } recipients
127
+ * @param {boolean } resend whether to resend the key request if there is
128
+ * already one
127
129
*
128
130
* @returns {Promise } resolves when the request has been added to the
129
131
* pending list (or we have established that a similar request already
130
132
* exists)
131
133
*/
132
- sendRoomKeyRequest ( requestBody , recipients ) {
133
- return this . _cryptoStore . getOrAddOutgoingRoomKeyRequest ( {
134
- requestBody : requestBody ,
135
- recipients : recipients ,
136
- requestId : this . _baseApis . makeTxnId ( ) ,
137
- state : ROOM_KEY_REQUEST_STATES . UNSENT ,
138
- } ) . then ( ( req ) => {
139
- if ( req . state === ROOM_KEY_REQUEST_STATES . UNSENT ) {
140
- this . _startTimer ( ) ;
134
+ async sendRoomKeyRequest ( requestBody , recipients , resend = false ) {
135
+ const req = await this . _cryptoStore . getOutgoingRoomKeyRequest (
136
+ requestBody ,
137
+ ) ;
138
+ if ( ! req ) {
139
+ await this . _cryptoStore . getOrAddOutgoingRoomKeyRequest ( {
140
+ requestBody : requestBody ,
141
+ recipients : recipients ,
142
+ requestId : this . _baseApis . makeTxnId ( ) ,
143
+ state : ROOM_KEY_REQUEST_STATES . UNSENT ,
144
+ } ) ;
145
+ } else {
146
+ switch ( req . state ) {
147
+ case ROOM_KEY_REQUEST_STATES . CANCELLATION_PENDING_AND_WILL_RESEND :
148
+ case ROOM_KEY_REQUEST_STATES . UNSENT :
149
+ // nothing to do here, since we're going to send a request anyways
150
+ return ;
151
+
152
+ case ROOM_KEY_REQUEST_STATES . CANCELLATION_PENDING : {
153
+ // existing request is about to be cancelled. If we want to
154
+ // resend, then change the state so that it resends after
155
+ // cancelling. Otherwise, just cancel the cancellation.
156
+ const state = resend ?
157
+ ROOM_KEY_REQUEST_STATES . CANCELLATION_PENDING_AND_WILL_RESEND :
158
+ ROOM_KEY_REQUEST_STATES . SENT ;
159
+ await this . _cryptoStore . updateOutgoingRoomKeyRequest (
160
+ req . requestId , ROOM_KEY_REQUEST_STATES . CANCELLATION_PENDING , {
161
+ state,
162
+ cancellationTxnId : this . _baseApis . makeTxnId ( ) ,
163
+ } ,
164
+ ) ;
165
+ break ;
141
166
}
142
- } ) ;
167
+ case ROOM_KEY_REQUEST_STATES . SENT : {
168
+ // a request has already been sent. If we don't want to
169
+ // resend, then do nothing. If we do want to, then cancel the
170
+ // existing request and send a new one.
171
+ if ( resend ) {
172
+ const state =
173
+ ROOM_KEY_REQUEST_STATES . CANCELLATION_PENDING_AND_WILLRESEND ;
174
+ const updatedReq =
175
+ await this . _cryptoStore . updateOutgoingRoomKeyRequest (
176
+ req . requestId , ROOM_KEY_REQUEST_STATES . SENT , {
177
+ state,
178
+ cancellationTxnId : this . _baseApis . makeTxnId ( ) ,
179
+ } ,
180
+ ) ;
181
+ if ( ! updatedReq ) {
182
+ // updateOutgoingRoomKeyRequest couldn't find the request
183
+ // in state ROOM_KEY_REQUEST_STATES.SENT, so we must have
184
+ // raced with another tab to mark the request cancelled.
185
+ // Try again, to make sure the request is resent.
186
+ return await this . sendRoomKeyRequest (
187
+ requestBody , recipients , resend ,
188
+ ) ;
189
+ }
190
+
191
+ // We don't want to wait for the timer, so we send it
192
+ // immediately. (We might actually end up racing with the timer,
193
+ // but that's ok: even if we make the request twice, we'll do it
194
+ // with the same transaction_id, so only one message will get
195
+ // sent).
196
+ //
197
+ // (We also don't want to wait for the response from the server
198
+ // here, as it will slow down processing of received keys if we
199
+ // do.)
200
+ try {
201
+ await this . _sendOutgoingRoomKeyRequestCancellation (
202
+ updatedReq ,
203
+ true ,
204
+ ) ;
205
+ } catch ( e ) {
206
+ logger . error (
207
+ "Error sending room key request cancellation;"
208
+ + " will retry later." , e ,
209
+ ) ;
210
+ }
211
+ // The request has transitioned from
212
+ // CANCELLATION_PENDING_AND_WILL_RESEND to UNSENT. We
213
+ // still need to resend the request which is now UNSENT, so
214
+ // start the timer if it isn't already started.
215
+ }
216
+ break ;
217
+ }
218
+ default :
219
+ throw new Error ( 'unhandled state: ' + req . state ) ;
220
+ }
221
+ }
222
+ // some of the branches require the timer to be started. Just start it
223
+ // all the time, because it doesn't hurt to start it.
224
+ this . _startTimer ( ) ;
143
225
}
144
226
145
227
/**
146
228
* Cancel room key requests, if any match the given requestBody
147
229
*
148
230
* @param {module:crypto~RoomKeyRequestBody } requestBody
149
- * @param {boolean } andResend if true, transition to UNSENT instead of
150
- * deleting after sending cancellation.
151
231
*
152
232
* @returns {Promise } resolves when the request has been updated in our
153
233
* pending list.
154
234
*/
155
- cancelRoomKeyRequest ( requestBody , andResend = false ) {
235
+ cancelRoomKeyRequest ( requestBody ) {
156
236
return this . _cryptoStore . getOutgoingRoomKeyRequest (
157
237
requestBody ,
158
238
) . then ( ( req ) => {
@@ -183,15 +263,10 @@ export default class OutgoingRoomKeyRequestManager {
183
263
) ;
184
264
185
265
case ROOM_KEY_REQUEST_STATES . SENT : {
186
- // If `andResend` is set, transition to UNSENT once the
187
- // cancellation has successfully been sent.
188
- const state = andResend ?
189
- ROOM_KEY_REQUEST_STATES . CANCELLATION_PENDING_AND_WILL_RESEND :
190
- ROOM_KEY_REQUEST_STATES . CANCELLATION_PENDING ;
191
266
// send a cancellation.
192
267
return this . _cryptoStore . updateOutgoingRoomKeyRequest (
193
268
req . requestId , ROOM_KEY_REQUEST_STATES . SENT , {
194
- state,
269
+ state : ROOM_KEY_REQUEST_STATES . CANCELLATION_PENDING ,
195
270
cancellationTxnId : this . _baseApis . makeTxnId ( ) ,
196
271
} ,
197
272
) . then ( ( updatedReq ) => {
@@ -221,20 +296,12 @@ export default class OutgoingRoomKeyRequestManager {
221
296
// do.)
222
297
this . _sendOutgoingRoomKeyRequestCancellation (
223
298
updatedReq ,
224
- andResend ,
225
299
) . catch ( ( e ) => {
226
300
logger . error (
227
301
"Error sending room key request cancellation;"
228
302
+ " will retry later." , e ,
229
303
) ;
230
304
this . _startTimer ( ) ;
231
- } ) . then ( ( ) => {
232
- if ( ! andResend ) return ;
233
- // The request has transitioned from
234
- // CANCELLATION_PENDING_AND_WILL_RESEND to UNSENT. We
235
- // still need to resend the request which is now UNSENT, so
236
- // start the timer if it isn't already started.
237
- this . _startTimer ( ) ;
238
305
} ) ;
239
306
} ) ;
240
307
}
0 commit comments