Add Sync3ObservableList
This commit is contained in:
parent
104d98d4a4
commit
32c62641fd
3 changed files with 189 additions and 0 deletions
|
@ -58,6 +58,7 @@
|
|||
"@rollup/plugin-commonjs": "^15.0.0",
|
||||
"@rollup/plugin-json": "^4.1.0",
|
||||
"@rollup/plugin-node-resolve": "^9.0.0",
|
||||
"@types/assert": "^1.5.6",
|
||||
"aes-js": "^3.1.2",
|
||||
"another-json": "^0.2.0",
|
||||
"base64-arraybuffer": "^0.2.0",
|
||||
|
|
183
src/matrix/Sync3ObservableList.ts
Normal file
183
src/matrix/Sync3ObservableList.ts
Normal file
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import * as assert from "assert";
|
||||
import { BaseObservableList } from "../observable/list/BaseObservableList";
|
||||
import { ObservableMap } from "../observable/map/ObservableMap.js";
|
||||
import { Room } from "./room/Room.js";
|
||||
|
||||
// subset of Sync3 functions used in this list; interfaced out for testing
|
||||
interface ISync {
|
||||
count(): number;
|
||||
roomAtIndex(i: number): string
|
||||
}
|
||||
|
||||
/**
|
||||
* An observable list that produces a subset of rooms based on Sync3 responses.
|
||||
*/
|
||||
export class Sync3ObservableList extends BaseObservableList<Room | null> {
|
||||
sync: ISync;
|
||||
rooms: ObservableMap;
|
||||
|
||||
/**
|
||||
* Construct an observable list that produces Rooms within the sliding window of Sync3 responses
|
||||
* or `null` to indicate that a placeholder room should be used.
|
||||
* @param sync3 The Sync3 class, which tracks up-to-date information on the sliding window / room counts.
|
||||
* @param rooms The entire set of rooms known to the client (e.g from Session.rooms).
|
||||
*/
|
||||
constructor(sync3: ISync, rooms: ObservableMap) {
|
||||
super();
|
||||
this.sync = sync3;
|
||||
this.rooms = rooms;
|
||||
}
|
||||
|
||||
get length(): number {
|
||||
return this.sync.count();
|
||||
}
|
||||
|
||||
[Symbol.iterator](): Iterator<Room | null, any, undefined> {
|
||||
let i = 0;
|
||||
return {
|
||||
next: (): any => {
|
||||
// base case
|
||||
if (i >= this.length) {
|
||||
return {
|
||||
done: true,
|
||||
};
|
||||
}
|
||||
let roomId = this.sync.roomAtIndex(i);
|
||||
i += 1;
|
||||
if (!roomId) {
|
||||
return {
|
||||
value: null
|
||||
}
|
||||
}
|
||||
return {
|
||||
value: this.rooms.get(roomId) || null,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function tests() {
|
||||
const makeRooms = function (len) {
|
||||
let rooms: any[] = [];
|
||||
for (let i = 0; i < len; i++) {
|
||||
const roomId = "!room-" + i;
|
||||
rooms.push({
|
||||
id: roomId,
|
||||
data: {
|
||||
some_key: i,
|
||||
},
|
||||
});
|
||||
}
|
||||
return rooms;
|
||||
}
|
||||
|
||||
const assertList = function (assert, rooms, gotList, wantListRoomIds) {
|
||||
if (wantListRoomIds.length === 0) {
|
||||
assert.equal(gotList.length, 0);
|
||||
for (const room of gotList) {
|
||||
assert.equal(0, 1); // fail
|
||||
}
|
||||
return;
|
||||
}
|
||||
let i = 0;
|
||||
for (const room of gotList) {
|
||||
const wantRoomId = wantListRoomIds[i];
|
||||
const gotRoomId = room ? room.id : null;
|
||||
assert.equal(wantRoomId, gotRoomId);
|
||||
if (wantRoomId !== null && gotRoomId !== null) {
|
||||
assert.deepEqual(room, rooms.get(wantRoomId));
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
"iterator": (assert) => {
|
||||
const rooms = new ObservableMap();
|
||||
let indexToRoomId = {};
|
||||
let roomCount = 0;
|
||||
const sync3 = {
|
||||
count: (): number => {
|
||||
return roomCount;
|
||||
},
|
||||
roomAtIndex: (i: number): string => {
|
||||
return indexToRoomId[i];
|
||||
},
|
||||
};
|
||||
|
||||
makeRooms(100).forEach((r) => {
|
||||
rooms.add(r.id, r);
|
||||
});
|
||||
const list = new Sync3ObservableList(sync3, rooms);
|
||||
|
||||
// iterate over the list (0 items) as sync3 has no indexes for the rooms
|
||||
assertList(assert, rooms, list, []);
|
||||
|
||||
|
||||
// 'load' 5 rooms from sync v3 and set the total count to 5 so we load the entire room list in one go!
|
||||
// [R,R,R,R,R]
|
||||
let slidingWindow: any[] = [
|
||||
"!room-50", "!room-53", "!room-1", "!room-52", "!room-97"
|
||||
]
|
||||
roomCount = 5;
|
||||
for (let i = 0; i < slidingWindow.length; i++) {
|
||||
indexToRoomId[i] = slidingWindow[i];
|
||||
}
|
||||
assertList(assert, rooms, list, slidingWindow);
|
||||
|
||||
// now add 5 more rooms which we don't know about, we should iterate through them with `null` entries
|
||||
// [R,R,R,R,R,P,P,P,P,P] (R=room, P=placeholder)
|
||||
roomCount = 10;
|
||||
assertList(assert, rooms, list, slidingWindow.concat([null, null, null, null, null]));
|
||||
|
||||
|
||||
// now track a window in the middle of the list (5-10)
|
||||
indexToRoomId = {};
|
||||
for (let i = 0; i < slidingWindow.length; i++) {
|
||||
indexToRoomId[i + 5] = slidingWindow[i];
|
||||
}
|
||||
roomCount = 15;
|
||||
// [P,P,P,P,P,R,R,R,R,R,P,P,P,P,P]
|
||||
assertList(assert, rooms, list, [null, null, null, null, null].concat(slidingWindow.concat([null, null, null, null, null])));
|
||||
|
||||
|
||||
// now track multiple ranges
|
||||
const anotherSlidingWindow: any[] = [
|
||||
"!room-30", "!room-33", "!room-36", "!room-29", "!room-21"
|
||||
]
|
||||
for (let i = 0; i < anotherSlidingWindow.length; i++) {
|
||||
indexToRoomId[i + 15] = anotherSlidingWindow[i];
|
||||
}
|
||||
roomCount = 20;
|
||||
// [P,P,P,P,P,R,R,R,R,R,P,P,P,P,P,R,R,R,R,R]
|
||||
assertList(
|
||||
assert, rooms, list,
|
||||
[null, null, null, null, null].concat(
|
||||
slidingWindow.concat(
|
||||
[null, null, null, null, null].concat(
|
||||
anotherSlidingWindow
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
},
|
||||
};
|
||||
};
|
|
@ -1164,6 +1164,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
|
||||
integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
|
||||
|
||||
"@types/assert@^1.5.6":
|
||||
version "1.5.6"
|
||||
resolved "https://registry.yarnpkg.com/@types/assert/-/assert-1.5.6.tgz#a8b5a94ce5fb8f4ba65fdc37fc9507609114189e"
|
||||
integrity sha512-Y7gDJiIqb9qKUHfBQYOWGngUpLORtirAVPuj/CWJrU2C6ZM4/y3XLwuwfGMF8s7QzW746LQZx23m0+1FSgjfug==
|
||||
|
||||
"@types/cacheable-request@^6.0.1":
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.2.tgz#c324da0197de0a98a2312156536ae262429ff6b9"
|
||||
|
|
Reference in a new issue