basic session loading

This commit is contained in:
Bruno Windels 2019-02-07 00:20:27 +00:00
parent c115164822
commit 3f776129f5
10 changed files with 94 additions and 101 deletions

View file

@ -30,12 +30,18 @@ async function main() {
let sessionId = getSessionId("@bruno1:localhost"); let sessionId = getSessionId("@bruno1:localhost");
let loginData; let loginData;
if (!sessionId) { if (!sessionId) {
({sessionId, loginData} = await login("bruno1", "testtest", "http://localhost:8008")); ({sessionId, loginData} = await login("bruno1", "testtest", HOMESERVER));
} }
const storage = await createIdbStorage(`morpheus_session_${sessionId}`); const storage = await createIdbStorage(`morpheus_session_${sessionId}`);
console.log("database created", storage); console.log("database created", storage);
const session = new Session(loginData, storage); const session = new Session(storage);
if (loginData) {
await session.setLoginData(loginData);
}
await session.load(); await session.load();
console.log("session loaded", session);
return;
const network = new Network(HOMESERVER, session.accessToken);
const sync = new Sync(network, session, storage); const sync = new Sync(network, session, storage);
await sync.start(); await sync.start();

View file

@ -1,14 +1,25 @@
export default class Session { export default class Session {
// sessionData has device_id, user_id, home_server (not access_token, that is for network) // loginData has device_id, user_id, home_server, access_token
constructor(sessionData, storage) { constructor(storage) {
this._sessionData = sessionData;
this._storage = storage; this._storage = storage;
this._rooms = {}; this._session = null;
this._syncToken = null; this._rooms = null;
}
// should be called before load
async setLoginData(loginData) {
const txn = this._storage.readWriteTxn([this._storage.storeNames.session]);
const session = {loginData};
txn.session.set(session);
await txn.complete();
} }
load() { async load() {
// what is the PK for a session [user_id, device_id], a uuid? const txn = this._storage.readTxn([this._storage.storeNames.session]);
this._session = await txn.session.get();
if (!this._session) {
throw new Error("session store is empty");
}
// load rooms
} }
getRoom(roomId) { getRoom(roomId) {
@ -22,7 +33,15 @@ export default class Session {
} }
applySync(syncToken, accountData, txn) { applySync(syncToken, accountData, txn) {
this._syncToken = syncToken; this._session.syncToken = syncToken;
txn.session.setSyncToken(syncToken); txn.session.setSession(this._session);
}
get syncToken() {
return this._session.syncToken;
}
get accessToken() {
return this._session.loginData.access_token;
} }
} }

View file

@ -7,7 +7,7 @@ export default async function createIdbStorage(databaseName) {
} }
function createStores(db) { function createStores(db) {
db.createObjectStore("sync"); //sync token db.createObjectStore("session", {keyPath: "key"});
// any way to make keys unique here? // any way to make keys unique here?
db.createObjectStore("roomSummary", {keyPath: "room_id"}); db.createObjectStore("roomSummary", {keyPath: "room_id"});
const timeline = db.createObjectStore("roomTimeline", {keyPath: ["room_id", "sort_key"]}); const timeline = db.createObjectStore("roomTimeline", {keyPath: ["room_id", "sort_key"]});

View file

@ -1,6 +1,10 @@
import {iterateCursor} from "./utils"; import {iterateCursor} from "./utils.js";
export default class QueryTarget { export default class QueryTarget {
constructor(target) {
this._target = target;
}
reduce(range, reducer, initialValue) { reduce(range, reducer, initialValue) {
return this._reduce(range, reducer, initialValue, "next"); return this._reduce(range, reducer, initialValue, "next");
} }
@ -26,7 +30,7 @@ export default class QueryTarget {
} }
selectAll(range) { selectAll(range) {
const cursor = this._queryTarget().openCursor(range, direction); const cursor = this._target.openCursor(range, direction);
const results = []; const results = [];
return iterateCursor(cursor, (value) => { return iterateCursor(cursor, (value) => {
results.push(value); results.push(value);
@ -52,7 +56,7 @@ export default class QueryTarget {
_reduce(range, reducer, initialValue, direction) { _reduce(range, reducer, initialValue, direction) {
let reducedValue = initialValue; let reducedValue = initialValue;
const cursor = this._queryTarget().openCursor(range, direction); const cursor = this._target.openCursor(range, direction);
return iterateCursor(cursor, (value) => { return iterateCursor(cursor, (value) => {
reducedValue = reducer(reducedValue, value); reducedValue = reducer(reducedValue, value);
return true; return true;
@ -66,7 +70,7 @@ export default class QueryTarget {
} }
_selectWhile(range, predicate, direction) { _selectWhile(range, predicate, direction) {
const cursor = this._queryTarget().openCursor(range, direction); const cursor = this._target.openCursor(range, direction);
const results = []; const results = [];
return iterateCursor(cursor, (value) => { return iterateCursor(cursor, (value) => {
results.push(value); results.push(value);
@ -75,20 +79,17 @@ export default class QueryTarget {
} }
async _find(range, predicate, direction) { async _find(range, predicate, direction) {
const cursor = this._queryTarget().openCursor(range, direction); const cursor = this._target.openCursor(range, direction);
let result; let result;
const found = await iterateCursor(cursor, (value) => { const found = await iterateCursor(cursor, (value) => {
if (predicate(value)) { const found = predicate(value);
if (found) {
result = value; result = value;
} }
return found;
}); });
if (!found) { if (found) {
throw new Error("not found"); return result;
} }
return result;
}
_queryTarget() {
throw new Error("override this");
} }
} }

View file

@ -1,3 +1,5 @@
import Transaction from "./transaction.js";
export const STORE_NAMES = ["session", "roomState", "roomSummary", "roomTimeline"]; export const STORE_NAMES = ["session", "roomState", "roomSummary", "roomTimeline"];
export default class Storage { export default class Storage {
@ -17,13 +19,13 @@ export default class Storage {
} }
} }
startReadOnlyTxn(storeNames) { readTxn(storeNames) {
this._validateStoreNames(storeNames); this._validateStoreNames(storeNames);
const txn = this._db.transaction(storeNames, "readonly"); const txn = this._db.transaction(storeNames, "readonly");
return new Transaction(txn, storeNames); return new Transaction(txn, storeNames);
} }
startReadWriteTxn(storeNames) { readWriteTxn(storeNames) {
this._validateStoreNames(storeNames); this._validateStoreNames(storeNames);
const txn = this._db.transaction(storeNames, "readwrite"); const txn = this._db.transaction(storeNames, "readwrite");
return new Transaction(txn, storeNames); return new Transaction(txn, storeNames);

View file

@ -1,11 +0,0 @@
import QueryTarget from "./query-target.js";
export default class StoreIndex extends QueryTarget {
constructor(index) {
this._index = index;
}
_queryTarget() {
return this._index;
}
}

View file

@ -1,16 +1,24 @@
import QueryTarget from "./query-target.js"; import QueryTarget from "./query-target.js";
import StoreIndex from "./store-index.js"; import { reqAsPromise } from "./utils.js";
export default class Store extends QueryTarget { export default class Store extends QueryTarget {
constructor(store) { constructor(store) {
this._store = store; super(store);
} }
_queryTarget() { get _store() {
return this._store; return this._target;
} }
index(indexName) { index(indexName) {
return new StoreIndex(this._store.index(indexName)); return new QueryTarget(this._store.index(indexName));
}
put(value) {
return reqAsPromise(this._store.put(value));
}
add(value) {
return reqAsPromise(this._store.add(value));
} }
} }

View file

@ -14,59 +14,19 @@ store contains:
avatarUrl avatarUrl
lastSynced lastSynced
*/ */
class SessionStore { export default class SessionStore {
constructor(sessionStore) { constructor(sessionStore) {
this._sessionStore = sessionStore; this._sessionStore = sessionStore;
} }
readSession() { async get() {
return this._session; const session = await this._sessionStore.selectFirst(IDBKeyRange.only(1));
if (session) {
return session.value;
}
} }
writeSession(session) { set(session) {
return this._sessionStore.put({key: 1, value: session});
}
// or dedicated set sync_token method?
async setAvatar(avatar) {
}
async setDisplayName(displayName) {
}
getSyncStatus() {
return this._db.store("sync").selectFirst();
}
setSyncStatus(syncToken, lastSynced) {
return this._db.store("sync").updateFirst({sync_token: syncToken, last_synced: lastSynced});
// return updateSingletonStore(this._db, "sync", {sync_token: syncToken, last_synced: lastSynced});
}
setAccessToken(accessToken) {
}
async addRoom(room) {
}
async removeRoom(roomId) {
}
async getRoomStores() {
}
async getRoomStore(roomId) {
}
async startSyncTransaction() {
return this._db.startSyncTxn();
} }
} }

View file

@ -1,5 +1,4 @@
import GapSortKey from "./gapsortkey"; import SortKey from "../../sortkey.js";
import {select} from "./utils";
class TimelineStore { class TimelineStore {
constructor(timelineStore) { constructor(timelineStore) {

View file

@ -1,6 +1,7 @@
import {txnAsPromise} from "./utils"; import {txnAsPromise} from "./utils.js";
import Store from "./store.js"; import Store from "./store.js";
import TimelineStore from "./stores/timeline.js"; // import TimelineStore from "./stores/timeline.js";
import SessionStore from "./stores/session.js";
export default class Transaction { export default class Transaction {
constructor(txn, allowedStoreNames) { constructor(txn, allowedStoreNames) {
@ -19,15 +20,23 @@ export default class Transaction {
// more specific error? this is a bug, so maybe not ... // more specific error? this is a bug, so maybe not ...
throw new Error(`Invalid store for transaction: ${name}, only ${this._allowedStoreNames.join(", ")} are allowed.`); throw new Error(`Invalid store for transaction: ${name}, only ${this._allowedStoreNames.join(", ")} are allowed.`);
} }
return new Store(this._txn.getObjectStore(name)); return new Store(this._txn.objectStore(name));
} }
get roomTimeline() { _store(name, mapStore) {
if (!this._stores.roomTimeline) { if (!this._stores[name]) {
const idbStore = this._idbStore("roomTimeline"); const idbStore = this._idbStore(name);
this._stores.roomTimeline = new TimelineStore(idbStore); this._stores[name] = mapStore(idbStore);
} }
return this._stores.roomTimeline; return this._stores[name];
}
// get roomTimeline() {
// return this._store("roomTimeline", idbStore => new TimelineStore(idbStore));
// }
get session() {
return this._store("session", idbStore => new SessionStore(idbStore));
} }
complete() { complete() {