Skip to content

Commit

Permalink
feat(room_key_stream): Add support for lagging stream error
Browse files Browse the repository at this point in the history
  • Loading branch information
BillCarsonFr committed Dec 20, 2024
1 parent 23b22c6 commit a85752d
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 13 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
`DehydratedDevices.keysForUpload` and `DehydratedDevices.rehydrate` now use the `DehydratedDeviceKey` as parameter
instead of a raw UInt8Array.Use `DehydratedDeviceKey::createKeyFromArray` to migrate.

**Other changes**

- Add `OlmMachine.registerRoomKeysWithheldCallbacks` that supports now a success and error callback.
An error will occur when the stream missed some updates; in that case decryption could be retried
for all current failures.

# matrix-sdk-crypto-wasm v12.1.0

- Update matrix-rusk-sdk to `37c17cf854a70f` for the fix for
Expand Down
73 changes: 60 additions & 13 deletions src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1320,22 +1320,69 @@ impl OlmMachine {
/// of {@link RoomKeyInfo}) and returns a Promise.
#[wasm_bindgen(js_name = "registerRoomKeyUpdatedCallback")]
pub async fn register_room_key_updated_callback(&self, callback: Function) {
self.register_room_key_updated_callbacks(callback, None).await
}

/// Register a success and an error callback which will be called whenever
/// there is an update to room keys.
///
/// `success_callback` should be a function that takes a single argument (an
/// array of {@link RoomKeyInfo}) and returns a Promise.
///
/// `error_callback` should be a function that takes a single argument (the
/// error) and returns a Promise. When such an error happens that means
/// that update stream lost track and that all current decryption failures
/// can be retried as the key might as been imported without notice.
#[wasm_bindgen(js_name = "registerRoomKeyUpdatedCallbacks")]
pub async fn register_room_key_updated_callbacks(
&self,
success_callback: Function,
error_callback: Option<Function>,
) {
let stream = self.inner.store().room_keys_received_stream();

copy_stream_to_callback(
stream,
|input| match input {
Ok(keys) => iter::once(
keys.into_iter().map(RoomKeyInfo::from).map(JsValue::from).collect::<Array>(),
),
Err(e) => {
warn!("Error reading room_keys_received_stream {:?}", e);
iter::once(Array::new())
spawn_local(async move {
pin_mut!(stream);

while let Some(item) = stream.next().await {
match item {
Ok(input) => {
let js_array = input
.into_iter()
.map(RoomKeyInfo::from)
.map(JsValue::from)
.collect::<Array>();
match promise_result_to_future(
success_callback.call1(&JsValue::NULL, &js_array.into()),
)
.await
{
Ok(_) => (),
Err(e) => {
warn!("Error calling registerRoomKeyUpdatedCallback success callback: {:?}", e);
}
}
}
Err(e) => {
if let Some(ref error_callback) = error_callback {
let js_error = JsError::new(&e.to_string());
match promise_result_to_future(
error_callback.call1(&JsValue::NULL, &js_error.into()),
)
.await
{
Ok(_) => (),
Err(e) => {
warn!("Error calling registerRoomKeyUpdatedCallback error callback: {:?}", e);
}
}
} else {
warn!("Error reading room_keys_received_stream {:?}, no callback specified", e);
}
}
}
},
callback,
"room-key-received",
);
}
})
}

/// Register a callback which will be called whenever we receive a
Expand Down
16 changes: 16 additions & 0 deletions tests/machine.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -929,6 +929,22 @@ describe(OlmMachine.name, () => {
expect(keyInfoList.length).toEqual(1);
expect(keyInfoList[0].roomId.toString()).toStrictEqual(room.toString());
});

test("importing room keys calls RoomKeyUpdatedCallbacks", async () => {
const success = jest.fn();
success.mockImplementation(() => Promise.resolve(undefined));
const error = jest.fn();
error.mockImplementation(() => Promise.resolve(undefined));
let m = await machine();
m.registerRoomKeyUpdatedCallbacks(success, error);
await m.importExportedRoomKeys(exportedRoomKeys, () => undefined);
expect(success).toHaveBeenCalledTimes(1);
let keyInfoList = success.mock.calls[0][0];
expect(keyInfoList.length).toEqual(1);
expect(keyInfoList[0].roomId.toString()).toStrictEqual(room.toString());

expect(error).toHaveBeenCalledTimes(0);
});
});

describe("can do in-room verification", () => {
Expand Down

0 comments on commit a85752d

Please sign in to comment.