From e6c792a8ac26119cec6f75833c8957aab385ce2a Mon Sep 17 00:00:00 2001 From: "Alexander \"PapaTutuWawa" Date: Fri, 16 Jun 2023 20:13:30 +0200 Subject: [PATCH] feat: DeviceListModifiedEvent now contains a delta --- lib/src/helpers.dart | 24 ++++++++++++++++++++++++ lib/src/omemo/events.dart | 9 ++++++--- lib/src/omemo/omemo.dart | 30 ++++++++++++++++++++++-------- test/helpers_test.dart | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 11 deletions(-) create mode 100644 test/helpers_test.dart diff --git a/lib/src/helpers.dart b/lib/src/helpers.dart index 8c4ac98..fc4e4a6 100644 --- a/lib/src/helpers.dart +++ b/lib/src/helpers.dart @@ -59,3 +59,27 @@ OmemoPublicKey? decodeKeyIfNotNull( int getTimestamp() { return DateTime.now().millisecondsSinceEpoch; } + +/// Describes the differences between two lists in terms of its items. +class ListDiff { + ListDiff(this.added, this.removed); + + /// The items that were added. + final List added; + + /// The items that were removed. + final List removed; +} + +extension BeforeAfterListDiff on List { + /// Compute the set-based changes between this list and [newList]. + ListDiff diff(List newList) { + final oldSet = Set.from(this); + final newSet = Set.from(newList); + + return ListDiff( + newSet.difference(oldSet).toList(), + oldSet.difference(newSet).toList(), + ); + } +} diff --git a/lib/src/omemo/events.dart b/lib/src/omemo/events.dart index 01c770e..12dad1c 100644 --- a/lib/src/omemo/events.dart +++ b/lib/src/omemo/events.dart @@ -39,13 +39,16 @@ class RatchetRemovedEvent extends OmemoEvent { /// Triggered when the device map has been modified class DeviceListModifiedEvent extends OmemoEvent { - DeviceListModifiedEvent(this.jid, this.devices); + DeviceListModifiedEvent(this.jid, this.added, this.removed); /// The JID of the user. final String jid; - /// The list of devices for [jid]. - final List devices; + /// The list of added devices for [jid]. + final List added; + + /// The list of removed devices for [jid]. + final List removed; } /// Triggered by the OmemoSessionManager when our own device bundle was modified diff --git a/lib/src/omemo/omemo.dart b/lib/src/omemo/omemo.dart index 7e76f98..92cdc04 100644 --- a/lib/src/omemo/omemo.dart +++ b/lib/src/omemo/omemo.dart @@ -154,7 +154,7 @@ class OmemoManager { _deviceListRequested[jid] = true; _eventStreamController.add( - DeviceListModifiedEvent(jid, newDeviceList), + DeviceListModifiedEvent(jid, newDeviceList, []), ); } } @@ -709,9 +709,10 @@ class OmemoManager { } // Clear the device list + _eventStreamController + .add(DeviceListModifiedEvent(jid, [], _deviceList[jid]!)); _deviceList.remove(jid); _deviceListRequested.remove(jid); - _eventStreamController.add(DeviceListModifiedEvent(jid, [])); }, ); } @@ -719,13 +720,26 @@ class OmemoManager { /// To be called when a update to the device list of [jid] is returned. /// [devices] is the list of device identifiers contained in the update. Future onDeviceListUpdate(String jid, List devices) async { - // Update our state - _deviceList[jid] = devices; - _deviceListRequested[jid] = true; + await _ratchetQueue.synchronized( + [jid], + () async { + // Compute the delta + ListDiff delta; + if (_deviceList.containsKey(jid)) { + delta = _deviceList[jid]!.diff(devices); + } else { + delta = ListDiff(devices, []); + } - // Commit the device list - _eventStreamController.add( - DeviceListModifiedEvent(jid, devices), + // Update our state + _deviceList[jid] = devices; + _deviceListRequested[jid] = true; + + // Commit the device list + _eventStreamController.add( + DeviceListModifiedEvent(jid, delta.added, delta.removed), + ); + }, ); } diff --git a/test/helpers_test.dart b/test/helpers_test.dart new file mode 100644 index 0000000..0b718d2 --- /dev/null +++ b/test/helpers_test.dart @@ -0,0 +1,33 @@ +import 'package:omemo_dart/src/helpers.dart'; +import 'package:omemo_dart/src/omemo/queue.dart'; +import 'package:test/test.dart'; + +void main() { + group('List diff', () { + test('Empty list to full list', () { + final result = [].diff([1, 2, 3, 4]); + expect(result.removed, isEmpty); + expect( + result.added.containsAll([1, 2, 3, 4]), + isTrue, + ); + expect(result.added.length, 4); + }); + + test('Full list to empty list', () { + final result = [1, 2, 3, 4].diff([]); + expect(result.added, isEmpty); + expect( + result.removed.containsAll([1, 2, 3, 4]), + isTrue, + ); + expect(result.removed.length, 4); + }); + + test('Full list to full list', () { + final result = [1, 2, 3, 4].diff([1, 2, 4, 5]); + expect(result.added, [5]); + expect(result.removed, [3]); + }); + }); +}