Merge pull request #474 from vector-im/snowpack-ts-storage-3

Snowpack + Typescript conversion (Part 3)
This commit is contained in:
Bruno Windels 2021-09-06 12:55:46 +02:00 committed by GitHub
commit 360b4db17a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 274 additions and 134 deletions

View file

@ -22,18 +22,18 @@ import {RoomSummaryStore} from "./stores/RoomSummaryStore";
import {InviteStore} from "./stores/InviteStore";
import {TimelineEventStore} from "./stores/TimelineEventStore";
import {TimelineRelationStore} from "./stores/TimelineRelationStore";
import {RoomStateStore} from "./stores/RoomStateStore.js";
import {RoomStateStore} from "./stores/RoomStateStore";
import {RoomMemberStore} from "./stores/RoomMemberStore";
import {TimelineFragmentStore} from "./stores/TimelineFragmentStore.js";
import {PendingEventStore} from "./stores/PendingEventStore.js";
import {UserIdentityStore} from "./stores/UserIdentityStore.js";
import {DeviceIdentityStore} from "./stores/DeviceIdentityStore.js";
import {OlmSessionStore} from "./stores/OlmSessionStore.js";
import {InboundGroupSessionStore} from "./stores/InboundGroupSessionStore.js";
import {OutboundGroupSessionStore} from "./stores/OutboundGroupSessionStore.js";
import {GroupSessionDecryptionStore} from "./stores/GroupSessionDecryptionStore.js";
import {OperationStore} from "./stores/OperationStore.js";
import {AccountDataStore} from "./stores/AccountDataStore.js";
import {TimelineFragmentStore} from "./stores/TimelineFragmentStore";
import {PendingEventStore} from "./stores/PendingEventStore";
import {UserIdentityStore} from "./stores/UserIdentityStore";
import {DeviceIdentityStore} from "./stores/DeviceIdentityStore";
import {OlmSessionStore} from "./stores/OlmSessionStore";
import {InboundGroupSessionStore} from "./stores/InboundGroupSessionStore";
import {OutboundGroupSessionStore} from "./stores/OutboundGroupSessionStore";
import {GroupSessionDecryptionStore} from "./stores/GroupSessionDecryptionStore";
import {OperationStore} from "./stores/OperationStore";
import {AccountDataStore} from "./stores/AccountDataStore";
export class Transaction {
constructor(txn, allowedStoreNames, IDBKeyRange) {

View file

@ -3,7 +3,7 @@ import {RoomMember, EVENT_TYPE as MEMBER_EVENT_TYPE} from "../../room/members/Ro
import {addRoomToIdentity} from "../../e2ee/DeviceTracker.js";
import {RoomMemberStore} from "./stores/RoomMemberStore";
import {SessionStore} from "./stores/SessionStore";
import {encodeScopeTypeKey} from "./stores/OperationStore.js";
import {encodeScopeTypeKey} from "./stores/OperationStore";
import {MAX_UNICODE} from "./stores/common";
// FUNCTIONS SHOULD ONLY BE APPENDED!!

View file

@ -13,17 +13,26 @@ 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 {Store} from "../Store";
import {Content} from "../../types";
interface AccountDataEntry {
type: string;
content: Content;
}
export class AccountDataStore {
constructor(store) {
this._store = store;
}
private _store: Store<AccountDataEntry>;
async get(type) {
return await this._store.get(type);
}
constructor(store: Store<AccountDataEntry>) {
this._store = store;
}
set(event) {
return this._store.put(event);
}
async get(type: string): Promise<AccountDataEntry | null> {
return await this._store.get(type);
}
set(event: AccountDataEntry): void {
this._store.put(event);
}
}

View file

@ -15,33 +15,46 @@ limitations under the License.
*/
import {MAX_UNICODE, MIN_UNICODE} from "./common";
import {Store} from "../Store";
function encodeKey(userId, deviceId) {
interface DeviceIdentity {
userId: string;
deviceId: string;
ed25519Key: string;
curve25519Key: string;
algorithms: string[];
displayName: string;
key: string;
}
function encodeKey(userId: string, deviceId: string): string {
return `${userId}|${deviceId}`;
}
function decodeKey(key) {
function decodeKey(key: string): { userId: string, deviceId: string } {
const [userId, deviceId] = key.split("|");
return {userId, deviceId};
}
export class DeviceIdentityStore {
constructor(store) {
private _store: Store<DeviceIdentity>;
constructor(store: Store<DeviceIdentity>) {
this._store = store;
}
getAllForUserId(userId) {
getAllForUserId(userId: string): Promise<DeviceIdentity[]> {
const range = this._store.IDBKeyRange.lowerBound(encodeKey(userId, ""));
return this._store.selectWhile(range, device => {
return device.userId === userId;
});
}
async getAllDeviceIds(userId) {
const deviceIds = [];
async getAllDeviceIds(userId: string): Promise<string[]> {
const deviceIds: string[] = [];
const range = this._store.IDBKeyRange.lowerBound(encodeKey(userId, ""));
await this._store.iterateKeys(range, key => {
const decodedKey = decodeKey(key);
const decodedKey = decodeKey(key as string);
// prevent running into the next room
if (decodedKey.userId === userId) {
deviceIds.push(decodedKey.deviceId);
@ -52,27 +65,27 @@ export class DeviceIdentityStore {
return deviceIds;
}
get(userId, deviceId) {
get(userId: string, deviceId: string): Promise<DeviceIdentity | null> {
return this._store.get(encodeKey(userId, deviceId));
}
set(deviceIdentity) {
set(deviceIdentity: DeviceIdentity): void {
deviceIdentity.key = encodeKey(deviceIdentity.userId, deviceIdentity.deviceId);
this._store.put(deviceIdentity);
}
getByCurve25519Key(curve25519Key) {
getByCurve25519Key(curve25519Key: string): Promise<DeviceIdentity | null> {
return this._store.index("byCurve25519Key").get(curve25519Key);
}
remove(userId, deviceId) {
this._store.delete(encodeKey(userId, deviceId));
remove(userId: string, deviceId: string): Promise<undefined> {
return this._store.delete(encodeKey(userId, deviceId));
}
removeAllForUser(userId) {
removeAllForUser(userId: string): Promise<undefined> {
// exclude both keys as they are theoretical min and max,
// but we should't have a match for just the room id, or room id with max
const range = this._store.IDBKeyRange.bound(encodeKey(userId, MIN_UNICODE), encodeKey(userId, MAX_UNICODE), true, true);
this._store.delete(range);
return this._store.delete(range);
}
}

View file

@ -15,30 +15,40 @@ limitations under the License.
*/
import {MIN_UNICODE, MAX_UNICODE} from "./common";
import {Store} from "../Store";
function encodeKey(roomId, sessionId, messageIndex) {
function encodeKey(roomId: string, sessionId: string, messageIndex: number | string): string {
return `${roomId}|${sessionId}|${messageIndex}`;
}
interface GroupSessionDecryption {
eventId: string;
timestamp: number;
}
type GroupSessionEntry = GroupSessionDecryption & { key: string }
export class GroupSessionDecryptionStore {
constructor(store) {
private _store: Store<GroupSessionEntry>;
constructor(store: Store<GroupSessionEntry>) {
this._store = store;
}
get(roomId, sessionId, messageIndex) {
get(roomId: string, sessionId: string, messageIndex: number): Promise<GroupSessionDecryption | null> {
return this._store.get(encodeKey(roomId, sessionId, messageIndex));
}
set(roomId, sessionId, messageIndex, decryption) {
decryption.key = encodeKey(roomId, sessionId, messageIndex);
this._store.put(decryption);
set(roomId: string, sessionId: string, messageIndex: number, decryption: GroupSessionDecryption): void {
(decryption as GroupSessionEntry).key = encodeKey(roomId, sessionId, messageIndex);
this._store.put(decryption as GroupSessionEntry);
}
removeAllForRoom(roomId) {
removeAllForRoom(roomId: string): Promise<undefined> {
const range = this._store.IDBKeyRange.bound(
encodeKey(roomId, MIN_UNICODE, MIN_UNICODE),
encodeKey(roomId, MAX_UNICODE, MAX_UNICODE)
);
this._store.delete(range);
return this._store.delete(range);
}
}

View file

@ -15,36 +15,49 @@ limitations under the License.
*/
import {MIN_UNICODE, MAX_UNICODE} from "./common";
import {Store} from "../Store";
function encodeKey(roomId, senderKey, sessionId) {
interface InboundGroupSession {
roomId: string;
senderKey: string;
sessionId: string;
session?: string;
claimedKeys?: { [algorithm : string] : string };
eventIds?: string[];
key: string;
}
function encodeKey(roomId: string, senderKey: string, sessionId: string): string {
return `${roomId}|${senderKey}|${sessionId}`;
}
export class InboundGroupSessionStore {
constructor(store) {
private _store: Store<InboundGroupSession>;
constructor(store: Store<InboundGroupSession>) {
this._store = store;
}
async has(roomId, senderKey, sessionId) {
async has(roomId: string, senderKey: string, sessionId: string): Promise<boolean> {
const key = encodeKey(roomId, senderKey, sessionId);
const fetchedKey = await this._store.getKey(key);
return key === fetchedKey;
}
get(roomId, senderKey, sessionId) {
get(roomId: string, senderKey: string, sessionId: string): Promise<InboundGroupSession | null> {
return this._store.get(encodeKey(roomId, senderKey, sessionId));
}
set(session) {
set(session: InboundGroupSession): void {
session.key = encodeKey(session.roomId, session.senderKey, session.sessionId);
this._store.put(session);
}
removeAllForRoom(roomId) {
removeAllForRoom(roomId: string): Promise<undefined> {
const range = this._store.IDBKeyRange.bound(
encodeKey(roomId, MIN_UNICODE, MIN_UNICODE),
encodeKey(roomId, MAX_UNICODE, MAX_UNICODE)
);
this._store.delete(range);
return this._store.delete(range);
}
}

View file

@ -13,26 +13,38 @@ 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 {Store} from "../Store";
function encodeKey(senderKey, sessionId) {
function encodeKey(senderKey: string, sessionId: string): string {
return `${senderKey}|${sessionId}`;
}
function decodeKey(key) {
function decodeKey(key: string): { senderKey: string, sessionId: string } {
const [senderKey, sessionId] = key.split("|");
return {senderKey, sessionId};
}
interface OlmSession {
session: string;
sessionId: string;
senderKey: string;
lastUsed: number;
}
type OlmSessionEntry = OlmSession & { key: string };
export class OlmSessionStore {
constructor(store) {
private _store: Store<OlmSessionEntry>;
constructor(store: Store<OlmSessionEntry>) {
this._store = store;
}
async getSessionIds(senderKey) {
const sessionIds = [];
async getSessionIds(senderKey: string): Promise<string[]> {
const sessionIds: string[] = [];
const range = this._store.IDBKeyRange.lowerBound(encodeKey(senderKey, ""));
await this._store.iterateKeys(range, key => {
const decodedKey = decodeKey(key);
const decodedKey = decodeKey(key as string);
// prevent running into the next room
if (decodedKey.senderKey === senderKey) {
sessionIds.push(decodedKey.sessionId);
@ -43,23 +55,23 @@ export class OlmSessionStore {
return sessionIds;
}
getAll(senderKey) {
getAll(senderKey: string): Promise<OlmSession[]> {
const range = this._store.IDBKeyRange.lowerBound(encodeKey(senderKey, ""));
return this._store.selectWhile(range, session => {
return session.senderKey === senderKey;
});
}
get(senderKey, sessionId) {
get(senderKey: string, sessionId: string): Promise<OlmSession | null> {
return this._store.get(encodeKey(senderKey, sessionId));
}
set(session) {
session.key = encodeKey(session.senderKey, session.sessionId);
return this._store.put(session);
set(session: OlmSession): void {
(session as OlmSessionEntry).key = encodeKey(session.senderKey, session.sessionId);
this._store.put(session as OlmSessionEntry);
}
remove(senderKey, sessionId) {
remove(senderKey: string, sessionId: string): Promise<undefined> {
return this._store.delete(encodeKey(senderKey, sessionId));
}
}

View file

@ -14,23 +14,46 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {MIN_UNICODE, MAX_UNICODE} from "./common";
import {Store} from "../Store";
export function encodeScopeTypeKey(scope, type) {
export function encodeScopeTypeKey(scope: string, type: string): string {
return `${scope}|${type}`;
}
interface BaseOperation {
id: string;
scope: string;
userIds: string[];
}
type OperationType = { type: "share_room_key"; roomKeyMessage: RoomKeyMessage; }
type Operation = BaseOperation & OperationType
type OperationEntry = Operation & { scopeTypeKey: string; }
interface RoomKeyMessage {
room_id: string;
session_id: string;
session_key: string;
algorithm: string;
chain_index: number;
}
export class OperationStore {
constructor(store) {
private _store: Store<OperationEntry>;
constructor(store: Store<OperationEntry>) {
this._store = store;
}
getAll() {
getAll(): Promise<Operation[]> {
return this._store.selectAll();
}
async getAllByTypeAndScope(type, scope) {
async getAllByTypeAndScope(type: string, scope: string): Promise<Operation[]> {
const key = encodeScopeTypeKey(scope, type);
const results = [];
const results: Operation[] = [];
await this._store.index("byScopeAndType").iterateWhile(key, value => {
if (value.scopeTypeKey !== key) {
return false;
@ -41,20 +64,20 @@ export class OperationStore {
return results;
}
add(operation) {
operation.scopeTypeKey = encodeScopeTypeKey(operation.scope, operation.type);
this._store.add(operation);
add(operation: Operation): void {
(operation as OperationEntry).scopeTypeKey = encodeScopeTypeKey(operation.scope, operation.type);
this._store.add(operation as OperationEntry);
}
update(operation) {
this._store.put(operation);
update(operation: Operation): void {
this._store.put(operation as OperationEntry);
}
remove(id) {
this._store.delete(id);
remove(id: string): Promise<undefined> {
return this._store.delete(id);
}
async removeAllForScope(scope) {
async removeAllForScope(scope: string): Promise<undefined> {
const range = this._store.IDBKeyRange.bound(
encodeScopeTypeKey(scope, MIN_UNICODE),
encodeScopeTypeKey(scope, MAX_UNICODE)
@ -64,5 +87,6 @@ export class OperationStore {
cur.delete();
return true;
});
return;
}
}

View file

@ -13,21 +13,30 @@ 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 {Store} from "../Store";
interface OutboundSession {
roomId: string;
session: string;
createdAt: number;
}
export class OutboundGroupSessionStore {
constructor(store) {
private _store: Store<OutboundSession>;
constructor(store: Store<OutboundSession>) {
this._store = store;
}
remove(roomId) {
this._store.delete(roomId);
remove(roomId: string): Promise<undefined> {
return this._store.delete(roomId);
}
get(roomId) {
get(roomId: string): Promise<OutboundSession | null> {
return this._store.get(roomId);
}
set(session) {
set(session: OutboundSession): void {
this._store.put(session);
}
}

View file

@ -16,23 +16,40 @@ limitations under the License.
import { encodeUint32, decodeUint32 } from "../utils";
import {KeyLimits} from "../../common";
import {Store} from "../Store";
import {Content} from "../../types";
function encodeKey(roomId, queueIndex) {
interface PendingEntry {
roomId: string;
queueIndex: number;
eventType: string;
content: Content;
relatexTxnId: string | null;
relatedEventId: string | null;
txnId?: string;
needsEncryption: boolean;
needsUpload: boolean;
key: string;
}
function encodeKey(roomId: string, queueIndex: number): string {
return `${roomId}|${encodeUint32(queueIndex)}`;
}
function decodeKey(key) {
function decodeKey(key: string): { roomId: string, queueIndex: number } {
const [roomId, encodedQueueIndex] = key.split("|");
const queueIndex = decodeUint32(encodedQueueIndex);
return {roomId, queueIndex};
}
export class PendingEventStore {
constructor(eventStore) {
private _eventStore: Store<PendingEntry>;
constructor(eventStore: Store<PendingEntry>) {
this._eventStore = eventStore;
}
async getMaxQueueIndex(roomId) {
async getMaxQueueIndex(roomId: string): Promise<number | undefined> {
const range = this._eventStore.IDBKeyRange.bound(
encodeKey(roomId, KeyLimits.minStorageKey),
encodeKey(roomId, KeyLimits.maxStorageKey),
@ -41,38 +58,38 @@ export class PendingEventStore {
);
const maxKey = await this._eventStore.findMaxKey(range);
if (maxKey) {
return decodeKey(maxKey).queueIndex;
return decodeKey(maxKey as string).queueIndex;
}
}
remove(roomId, queueIndex) {
remove(roomId: string, queueIndex: number): Promise<undefined> {
const keyRange = this._eventStore.IDBKeyRange.only(encodeKey(roomId, queueIndex));
this._eventStore.delete(keyRange);
return this._eventStore.delete(keyRange);
}
async exists(roomId, queueIndex) {
async exists(roomId: string, queueIndex: number): Promise<boolean> {
const keyRange = this._eventStore.IDBKeyRange.only(encodeKey(roomId, queueIndex));
const key = await this._eventStore.getKey(keyRange);
return !!key;
}
add(pendingEvent) {
add(pendingEvent: PendingEntry): void {
pendingEvent.key = encodeKey(pendingEvent.roomId, pendingEvent.queueIndex);
this._eventStore.add(pendingEvent);
}
update(pendingEvent) {
update(pendingEvent: PendingEntry): void {
this._eventStore.put(pendingEvent);
}
getAll() {
getAll(): Promise<PendingEntry[]> {
return this._eventStore.selectAll();
}
removeAllForRoom(roomId) {
removeAllForRoom(roomId: string): Promise<undefined> {
const minKey = encodeKey(roomId, KeyLimits.minStorageKey);
const maxKey = encodeKey(roomId, KeyLimits.maxStorageKey);
const range = this._eventStore.IDBKeyRange.bound(minKey, maxKey);
this._eventStore.delete(range);
return this._eventStore.delete(range);
}
}

View file

@ -52,7 +52,7 @@ export class RoomMemberStore {
set(member: MemberData): void {
// Object.assign would be more typesafe, but small objects
(member as any).key = encodeKey(member.roomId, member.userId);
(member as MemberStorageEntry).key = encodeKey(member.roomId, member.userId);
this._roomMembersStore.put(member as MemberStorageEntry);
}

View file

@ -16,31 +16,41 @@ limitations under the License.
*/
import {MAX_UNICODE} from "./common";
import {Store} from "../Store";
import {StateEvent} from "../../types";
function encodeKey(roomId, eventType, stateKey) {
function encodeKey(roomId: string, eventType: string, stateKey: string) {
return `${roomId}|${eventType}|${stateKey}`;
}
export interface RoomStateEntry {
roomId: string;
event: StateEvent;
key: string;
}
export class RoomStateStore {
constructor(idbStore) {
private _roomStateStore: Store<RoomStateEntry>;
constructor(idbStore: Store<RoomStateEntry>) {
this._roomStateStore = idbStore;
}
get(roomId, type, stateKey) {
get(roomId: string, type: string, stateKey: string): Promise<RoomStateEntry | null> {
const key = encodeKey(roomId, type, stateKey);
return this._roomStateStore.get(key);
}
set(roomId, event) {
set(roomId: string, event: StateEvent): void {
const key = encodeKey(roomId, event.type, event.state_key);
const entry = {roomId, event, key};
return this._roomStateStore.put(entry);
this._roomStateStore.put(entry);
}
removeAllForRoom(roomId) {
removeAllForRoom(roomId: string): Promise<undefined> {
// exclude both keys as they are theoretical min and max,
// but we should't have a match for just the room id, or room id with max
const range = this._roomStateStore.IDBKeyRange.bound(roomId, `${roomId}|${MAX_UNICODE}`, true, true);
this._roomStateStore.delete(range);
return this._roomStateStore.delete(range);
}
}

View file

@ -27,7 +27,7 @@ interface Annotation {
firstTimestamp: number;
}
interface StorageEntry {
interface TimelineEventEntry {
roomId: string;
fragmentId: number;
eventIndex: number;
@ -35,10 +35,10 @@ interface StorageEntry {
displayName?: string;
avatarUrl?: string;
annotations?: { [key : string]: Annotation };
key: string;
eventIdKey: string;
}
type TimelineEventStorageEntry = TimelineEventEntry & { key: string, eventIdKey: string };
function encodeKey(roomId: string, fragmentId: number, eventIndex: number): string {
return `${roomId}|${encodeUint32(fragmentId)}|${encodeUint32(eventIndex)}`;
}
@ -126,9 +126,9 @@ class Range {
* @property {?Gap} gap if a gap entry, the gap
*/
export class TimelineEventStore {
private _timelineStore: Store<StorageEntry>;
private _timelineStore: Store<TimelineEventStorageEntry>;
constructor(timelineStore: Store<StorageEntry>) {
constructor(timelineStore: Store<TimelineEventStorageEntry>) {
this._timelineStore = timelineStore;
}
@ -175,7 +175,7 @@ export class TimelineEventStore {
* @param amount
* @return a promise resolving to an array with 0 or more entries, in ascending order.
*/
async lastEvents(roomId: string, fragmentId: number, amount: number): Promise<StorageEntry[]> {
async lastEvents(roomId: string, fragmentId: number, amount: number): Promise<TimelineEventEntry[]> {
const eventKey = EventKey.maxKey;
eventKey.fragmentId = fragmentId;
return this.eventsBefore(roomId, eventKey, amount);
@ -187,7 +187,7 @@ export class TimelineEventStore {
* @param amount
* @return a promise resolving to an array with 0 or more entries, in ascending order.
*/
async firstEvents(roomId: string, fragmentId: number, amount: number): Promise<StorageEntry[]> {
async firstEvents(roomId: string, fragmentId: number, amount: number): Promise<TimelineEventEntry[]> {
const eventKey = EventKey.minKey;
eventKey.fragmentId = fragmentId;
return this.eventsAfter(roomId, eventKey, amount);
@ -200,7 +200,7 @@ export class TimelineEventStore {
* @param amount
* @return a promise resolving to an array with 0 or more entries, in ascending order.
*/
eventsAfter(roomId: string, eventKey: EventKey, amount: number): Promise<StorageEntry[]> {
eventsAfter(roomId: string, eventKey: EventKey, amount: number): Promise<TimelineEventEntry[]> {
const idbRange = this.lowerBoundRange(eventKey, true).asIDBKeyRange(roomId);
return this._timelineStore.selectLimit(idbRange, amount);
}
@ -212,7 +212,7 @@ export class TimelineEventStore {
* @param amount
* @return a promise resolving to an array with 0 or more entries, in ascending order.
*/
async eventsBefore(roomId: string, eventKey: EventKey, amount: number): Promise<StorageEntry[]> {
async eventsBefore(roomId: string, eventKey: EventKey, amount: number): Promise<TimelineEventEntry[]> {
const range = this.upperBoundRange(eventKey, true).asIDBKeyRange(roomId);
const events = await this._timelineStore.selectLimitReverse(range, amount);
events.reverse(); // because we fetched them backwards
@ -265,11 +265,11 @@ export class TimelineEventStore {
* @return nothing. To wait for the operation to finish, await the transaction it's part of.
* @throws {StorageError} ...
*/
insert(entry: StorageEntry): void {
entry.key = encodeKey(entry.roomId, entry.fragmentId, entry.eventIndex);
entry.eventIdKey = encodeEventIdKey(entry.roomId, entry.event.event_id);
insert(entry: TimelineEventEntry): void {
(entry as TimelineEventStorageEntry).key = encodeKey(entry.roomId, entry.fragmentId, entry.eventIndex);
(entry as TimelineEventStorageEntry).eventIdKey = encodeEventIdKey(entry.roomId, entry.event.event_id);
// TODO: map error? or in idb/store?
this._timelineStore.add(entry);
this._timelineStore.add(entry as TimelineEventStorageEntry);
}
/** Updates the entry into the store with the given [roomId, eventKey] combination.
@ -277,15 +277,15 @@ export class TimelineEventStore {
* @param entry the entry to update.
* @return nothing. To wait for the operation to finish, await the transaction it's part of.
*/
update(entry: StorageEntry): void {
this._timelineStore.put(entry);
update(entry: TimelineEventEntry): void {
this._timelineStore.put(entry as TimelineEventStorageEntry);
}
get(roomId: string, eventKey: EventKey): Promise<StorageEntry | null> {
get(roomId: string, eventKey: EventKey): Promise<TimelineEventEntry | null> {
return this._timelineStore.get(encodeKey(roomId, eventKey.fragmentId, eventKey.eventIndex));
}
getByEventId(roomId: string, eventId: string): Promise<StorageEntry | null> {
getByEventId(roomId: string, eventId: string): Promise<TimelineEventEntry | null> {
return this._timelineStore.index("byEventId").get(encodeEventIdKey(roomId, eventId));
}

View file

@ -17,17 +17,31 @@ limitations under the License.
import { StorageError } from "../../common";
import {KeyLimits} from "../../common";
import { encodeUint32 } from "../utils";
import {Store} from "../Store";
function encodeKey(roomId, fragmentId) {
interface Fragment {
roomId: string;
id: number;
previousId: number | null;
nextId: number | null;
previousToken: string | null;
nextToken: string | null;
}
type FragmentEntry = Fragment & { key: string }
function encodeKey(roomId: string, fragmentId: number): string {
return `${roomId}|${encodeUint32(fragmentId)}`;
}
export class TimelineFragmentStore {
constructor(store) {
private _store: Store<FragmentEntry>;
constructor(store: Store<FragmentEntry>) {
this._store = store;
}
_allRange(roomId) {
_allRange(roomId: string): IDBKeyRange {
try {
return this._store.IDBKeyRange.bound(
encodeKey(roomId, KeyLimits.minStorageKey),
@ -38,13 +52,13 @@ export class TimelineFragmentStore {
}
}
all(roomId) {
all(roomId: string): Promise<FragmentEntry[]> {
return this._store.selectAll(this._allRange(roomId));
}
/** Returns the fragment without a nextToken and without nextId,
if any, with the largest id if there are multiple (which should not happen) */
liveFragment(roomId) {
liveFragment(roomId: string): Promise<FragmentEntry | undefined> {
// why do we need this?
// Ok, take the case where you've got a /context fragment and a /sync fragment
// They are not connected. So, upon loading the persister, which one do we take? We can't sort them ...
@ -60,20 +74,20 @@ export class TimelineFragmentStore {
// should generate an id an return it?
// depends if we want to do anything smart with fragment ids,
// like give them meaning depending on range. not for now probably ...
add(fragment) {
fragment.key = encodeKey(fragment.roomId, fragment.id);
this._store.add(fragment);
add(fragment: Fragment): void {
(fragment as FragmentEntry).key = encodeKey(fragment.roomId, fragment.id);
this._store.add(fragment as FragmentEntry);
}
update(fragment) {
update(fragment: FragmentEntry): void {
this._store.put(fragment);
}
get(roomId, fragmentId) {
get(roomId: string, fragmentId: number): Promise<FragmentEntry | null> {
return this._store.get(encodeKey(roomId, fragmentId));
}
removeAllForRoom(roomId) {
this._store.delete(this._allRange(roomId));
removeAllForRoom(roomId: string): Promise<undefined> {
return this._store.delete(this._allRange(roomId));
}
}

View file

@ -13,21 +13,30 @@ 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 {Store} from "../Store";
interface UserIdentity {
userId: string;
roomIds: string[];
deviceTrackingStatus: number;
}
export class UserIdentityStore {
constructor(store) {
private _store: Store<UserIdentity>;
constructor(store: Store<UserIdentity>) {
this._store = store;
}
get(userId) {
get(userId: string): Promise<UserIdentity | null> {
return this._store.get(userId);
}
set(userIdentity) {
set(userIdentity: UserIdentity): void {
this._store.put(userIdentity);
}
remove(userId) {
remove(userId: string): Promise<undefined> {
return this._store.delete(userId);
}
}