[Archive] enhance lazyload archive

This commit is contained in:
Christian Pauly 2019-11-29 16:19:32 +00:00
parent c38f041a5a
commit 888155fbc7
5 changed files with 222 additions and 208 deletions

View file

@ -98,9 +98,6 @@ class Client {
/// A list of all rooms the user is participating or invited.
RoomList roomList;
/// A list of all rooms the user is not participating anymore.
RoomList archive;
/// Key/Value store of account data.
Map<String, AccountData> accountData = {};
@ -262,27 +259,33 @@ class Client {
/// Creates a new [RoomList] object.
RoomList getRoomList(
{bool onlyLeft = false,
onRoomListUpdateCallback onUpdate,
{onRoomListUpdateCallback onUpdate,
onRoomListInsertCallback onInsert,
onRoomListRemoveCallback onRemove}) {
List<Room> rooms = onlyLeft ? archive.rooms : roomList.rooms;
List<Room> rooms = roomList.rooms;
return RoomList(
client: this,
onlyLeft: onlyLeft,
onlyLeft: false,
onUpdate: onUpdate,
onInsert: onInsert,
onRemove: onRemove,
rooms: rooms);
}
/// Searches in the roomList and in the archive for a room with the given [id].
Room getRoomById(String id) {
Room room = roomList.getRoomById(id);
if (room == null) room = archive.getRoomById(id);
return room;
Future<RoomList> get archive async {
RoomList archiveList = RoomList(client: this, rooms: [], onlyLeft: true);
String syncFilters =
'{"room":{"include_leave":true,"timeline":{"limit":1}}}';
String action = "/client/r0/sync?filter=$syncFilters&timeout=0";
final syncResp =
await connection.jsonRequest(type: HTTPType.GET, action: action);
if (!(syncResp is ErrorResponse)) await connection.handleSync(syncResp);
return archiveList;
}
/// Searches in the roomList and in the archive for a room with the given [id].
Room getRoomById(String id) => roomList.getRoomById(id);
Future<dynamic> joinRoomById(String id) async {
return await connection.jsonRequest(
type: HTTPType.POST, action: "/client/r0/join/$id");

View file

@ -49,9 +49,6 @@ class Connection {
static String syncFilters = '{"room":{"state":{"lazy_load_members":true}}}';
static String firstSyncFilters =
'{"room":{"include_leave":true,"state":{"lazy_load_members":true}}}';
/// Handles the connection to the Matrix Homeserver. You can change this to a
/// MockClient for testing.
http.Client httpClient = http.Client();
@ -145,11 +142,9 @@ class Connection {
client.prevBatch = newPrevBatch;
List<Room> rooms = [];
List<Room> archivedRooms = [];
if (client.store != null) {
client.store.storeClient();
rooms = await client.store.getRoomList(onlyLeft: false);
archivedRooms = await client.store.getRoomList(onlyLeft: true);
client.accountData = await client.store.getAccountData();
client.presences = await client.store.getPresences();
}
@ -162,14 +157,6 @@ class Connection {
onRemove: null,
rooms: rooms);
client.archive = RoomList(
client: client,
onlyLeft: true,
onUpdate: null,
onInsert: null,
onRemove: null,
rooms: archivedRooms);
_userEventSub ??= onUserEvent.stream.listen(client.handleUserUpdate);
onLoginStateChanged.add(LoginState.logged);
@ -309,10 +296,9 @@ class Connection {
Future<void> _sync() async {
if (client.isLogged() == false) return;
String action = "/client/r0/sync?filter=$firstSyncFilters";
String action = "/client/r0/sync?filter=$syncFilters";
if (client.prevBatch != null) {
action = "/client/r0/sync?filter=$syncFilters";
action += "&timeout=30000";
action += "&since=${client.prevBatch}";
}
@ -327,12 +313,12 @@ class Connection {
try {
if (client.store != null)
await client.store.transaction(() {
_handleSync(syncResp);
handleSync(syncResp);
client.store.storePrevBatch(syncResp);
return;
});
else
await _handleSync(syncResp);
await handleSync(syncResp);
if (client.prevBatch == null) client.connection.onFirstSync.add(true);
client.prevBatch = syncResp["next_batch"];
} catch (e) {
@ -344,7 +330,7 @@ class Connection {
if (hash == _syncRequest.hashCode) _sync();
}
void _handleSync(dynamic sync) {
void handleSync(dynamic sync) {
if (sync["rooms"] is Map<String, dynamic>) {
if (sync["rooms"]["join"] is Map<String, dynamic>)
_handleRooms(sync["rooms"]["join"], Membership.join);

View file

@ -203,11 +203,25 @@ class Room {
!canonicalAlias.isEmpty &&
canonicalAlias.length > 3)
return canonicalAlias.substring(1, canonicalAlias.length).split(":")[0];
if (mHeroes != null && mHeroes.length > 0 && mHeroes.any((h) => h.isNotEmpty)) {
List<String> heroes = [];
if (mHeroes != null &&
mHeroes.length > 0 &&
mHeroes.any((h) => h.isNotEmpty)) {
heroes = mHeroes;
} else {
if (states["m.room.member"] is Map<String, dynamic>) {
for (var entry in states["m.room.member"].entries) {
RoomState state = entry.value;
if (state.type == EventTypes.RoomMember &&
state.stateKey != client?.userID) heroes.add(state.stateKey);
}
}
}
if (heroes.length > 0) {
String displayname = "";
for (int i = 0; i < mHeroes.length; i++) {
if (mHeroes[i].isEmpty) continue;
displayname += User(mHeroes[i]).calcDisplayname() + ", ";
for (int i = 0; i < heroes.length; i++) {
if (heroes[i].isEmpty) continue;
displayname += User(heroes[i]).calcDisplayname() + ", ";
}
return displayname.substring(0, displayname.length - 2);
}
@ -679,7 +693,6 @@ class Room {
List<User> getParticipants() {
List<User> userList = [];
if (states["m.room.member"] is Map<String, dynamic>) {
print('Check members: ${states["m.room.member"].length}');
for (var entry in states["m.room.member"].entries) {
RoomState state = entry.value;
if (state.type == EventTypes.RoomMember) userList.add(state.asUser);

View file

@ -27,6 +27,7 @@ import 'package:famedlysdk/src/AccountData.dart';
import 'package:famedlysdk/src/Client.dart';
import 'package:famedlysdk/src/Connection.dart';
import 'package:famedlysdk/src/Presence.dart';
import 'package:famedlysdk/src/RoomList.dart';
import 'package:famedlysdk/src/User.dart';
import 'package:famedlysdk/src/requests/SetPushersRequest.dart';
import 'package:famedlysdk/src/responses/ErrorResponse.dart';
@ -207,7 +208,7 @@ void main() {
List<RoomUpdate> roomUpdateList = await roomUpdateListFuture;
expect(roomUpdateList.length, 3);
expect(roomUpdateList.length, 2);
expect(roomUpdateList[0].id == "!726s6s6q:example.com", true);
expect(roomUpdateList[0].membership == Membership.join, true);
@ -222,13 +223,6 @@ void main() {
expect(roomUpdateList[1].limitedTimeline == false, true);
expect(roomUpdateList[1].notification_count == 0, true);
expect(roomUpdateList[1].highlight_count == 0, true);
expect(roomUpdateList[2].id == "!5345234234:example.com", true);
expect(roomUpdateList[2].membership == Membership.leave, true);
expect(roomUpdateList[2].prev_batch == "", true);
expect(roomUpdateList[2].limitedTimeline == false, true);
expect(roomUpdateList[2].notification_count == 0, true);
expect(roomUpdateList[2].highlight_count == 0, true);
});
test('Event Update Test', () async {
@ -364,6 +358,15 @@ void main() {
expect(resp["room_id"], roomID);
});
test('get archive', () async {
RoomList archive = await matrix.archive;
await new Future.delayed(new Duration(milliseconds: 50));
expect(archive.rooms.length, 1);
expect(archive.rooms[0].id, "!5345234234:example.com");
expect(archive.rooms[0].membership, Membership.leave);
});
test('Logout when token is unknown', () async {
Future<LoginState> loginStateFuture =
matrix.connection.onLoginStateChanged.stream.first;

View file

@ -62,6 +62,176 @@ class FakeMatrixApi extends MockClient {
return Response(json.encode(res), 100);
});
static Map<String, dynamic> syncResponse = {
"next_batch": Random().nextDouble().toString(),
"presence": {
"events": [
{
"sender": "@alice:example.com",
"type": "m.presence",
"content": {"presence": "online"}
}
]
},
"account_data": {
"events": [
{
"type": "org.example.custom.config",
"content": {"custom_config_key": "custom_config_value"}
},
{
"content": {
"@bob:example.com": [
"!726s6s6q:example.com",
"!hgfedcba:example.com"
]
},
"type": "m.direct"
},
]
},
"to_device": {
"events": [
{
"sender": "@alice:example.com",
"type": "m.new_device",
"content": {
"device_id": "XYZABCDE",
"rooms": ["!726s6s6q:example.com"]
}
}
]
},
"rooms": {
"join": {
"!726s6s6q:example.com": {
"unread_notifications": {
"highlight_count": 2,
"notification_count": 2,
},
"state": {
"events": [
{
"sender": "@alice:example.com",
"type": "m.room.member",
"state_key": "@alice:example.com",
"content": {"membership": "join"},
"origin_server_ts": 1417731086795,
"event_id": "66697273743031:example.com"
},
{
"sender": "@alice:example.com",
"type": "m.room.canonical_alias",
"content": {
"alias": "#famedlyContactDiscovery:fakeServer.notExisting"
},
"state_key": "",
"origin_server_ts": 1417731086796,
"event_id": "66697273743032:example.com"
}
]
},
"timeline": {
"events": [
{
"sender": "@bob:example.com",
"type": "m.room.member",
"state_key": "@bob:example.com",
"content": {"membership": "join"},
"prev_content": {"membership": "invite"},
"origin_server_ts": 1417731086795,
"event_id": "7365636s6r6432:example.com"
},
{
"sender": "@alice:example.com",
"type": "m.room.message",
"txn_id": "1234",
"content": {"body": "I am a fish", "msgtype": "m.text"},
"origin_server_ts": 1417731086797,
"event_id": "74686972643033:example.com"
}
],
"limited": true,
"prev_batch": "t34-23535_0_0"
},
"ephemeral": {
"events": [
{
"type": "m.typing",
"content": {
"user_ids": ["@alice:example.com"]
}
},
{
"content": {
"7365636s6r6432:example.com": {
"m.read": {
"@alice:example.com": {"ts": 1436451550453}
}
}
},
"room_id": "!726s6s6q:example.com",
"type": "m.receipt"
}
]
},
"account_data": {
"events": [
{
"type": "m.tag",
"content": {
"tags": {
"work": {"order": 1}
}
}
},
{
"type": "org.example.custom.room.config",
"content": {"custom_config_key": "custom_config_value"}
}
]
}
}
},
"invite": {
"!696r7674:example.com": {
"invite_state": {
"events": [
{
"sender": "@alice:example.com",
"type": "m.room.name",
"state_key": "",
"content": {"name": "My Room Name"}
},
{
"sender": "@alice:example.com",
"type": "m.room.member",
"state_key": "@bob:example.com",
"content": {"membership": "invite"}
}
]
}
}
},
}
};
static Map<String, dynamic> archiveSyncResponse = {
"next_batch": Random().nextDouble().toString(),
"presence": {"events": []},
"account_data": {"events": []},
"to_device": {"events": []},
"rooms": {
"join": {},
"invite": {},
"leave": {
"!5345234234:example.com": {
"timeline": {"events": []}
},
},
}
};
static final Map<String, Map<String, dynamic>> api = {
"GET": {
"/client/r0/rooms/!localpart:server.abc/state/m.room.member/@getme:example.com":
@ -339,171 +509,10 @@ class FakeMatrixApi extends MockClient {
]
}
},
"/client/r0/sync?filter=%7B%22room%22:%7B%22include_leave%22:true,%22state%22:%7B%22lazy_load_members%22:true%7D%7D%7D":
(var req) => {
"next_batch": Random().nextDouble().toString(),
"presence": {
"events": [
{
"sender": "@alice:example.com",
"type": "m.presence",
"content": {"presence": "online"}
}
]
},
"account_data": {
"events": [
{
"type": "org.example.custom.config",
"content": {"custom_config_key": "custom_config_value"}
},
{
"content": {
"@bob:example.com": [
"!726s6s6q:example.com",
"!hgfedcba:example.com"
]
},
"type": "m.direct"
},
]
},
"to_device": {
"events": [
{
"sender": "@alice:example.com",
"type": "m.new_device",
"content": {
"device_id": "XYZABCDE",
"rooms": ["!726s6s6q:example.com"]
}
}
]
},
"rooms": {
"join": {
"!726s6s6q:example.com": {
"unread_notifications": {
"highlight_count": 2,
"notification_count": 2,
},
"state": {
"events": [
{
"sender": "@alice:example.com",
"type": "m.room.member",
"state_key": "@alice:example.com",
"content": {"membership": "join"},
"origin_server_ts": 1417731086795,
"event_id": "66697273743031:example.com"
},
{
"sender": "@alice:example.com",
"type": "m.room.canonical_alias",
"content": {
"alias":
"#famedlyContactDiscovery:fakeServer.notExisting"
},
"state_key": "",
"origin_server_ts": 1417731086796,
"event_id": "66697273743032:example.com"
}
]
},
"timeline": {
"events": [
{
"sender": "@bob:example.com",
"type": "m.room.member",
"state_key": "@bob:example.com",
"content": {"membership": "join"},
"prev_content": {"membership": "invite"},
"origin_server_ts": 1417731086795,
"event_id": "7365636s6r6432:example.com"
},
{
"sender": "@alice:example.com",
"type": "m.room.message",
"txn_id": "1234",
"content": {
"body": "I am a fish",
"msgtype": "m.text"
},
"origin_server_ts": 1417731086797,
"event_id": "74686972643033:example.com"
}
],
"limited": true,
"prev_batch": "t34-23535_0_0"
},
"ephemeral": {
"events": [
{
"type": "m.typing",
"content": {
"user_ids": ["@alice:example.com"]
}
},
{
"content": {
"7365636s6r6432:example.com": {
"m.read": {
"@alice:example.com": {"ts": 1436451550453}
}
}
},
"room_id": "!726s6s6q:example.com",
"type": "m.receipt"
}
]
},
"account_data": {
"events": [
{
"type": "m.tag",
"content": {
"tags": {
"work": {"order": 1}
}
}
},
{
"type": "org.example.custom.room.config",
"content": {
"custom_config_key": "custom_config_value"
}
}
]
}
}
},
"invite": {
"!696r7674:example.com": {
"invite_state": {
"events": [
{
"sender": "@alice:example.com",
"type": "m.room.name",
"state_key": "",
"content": {"name": "My Room Name"}
},
{
"sender": "@alice:example.com",
"type": "m.room.member",
"state_key": "@bob:example.com",
"content": {"membership": "invite"}
}
]
}
}
},
"leave": {
"!5345234234:example.com": {
"timeline": {"events": []}
},
},
}
},
"/client/r0/sync?filter=%7B%22room%22:%7B%22include_leave%22:true,%22timeline%22:%7B%22limit%22:1%7D%7D%7D&timeout=0":
(var req) => archiveSyncResponse,
"/client/r0/sync?filter=%7B%22room%22:%7B%22state%22:%7B%22lazy_load_members%22:true%7D%7D%7D":
(var req) => syncResponse,
},
"POST": {
"/client/r0/login": (var req) => {