forked from mystiq/hydrogen-web
basic session loading
This commit is contained in:
parent
c115164822
commit
3f776129f5
10 changed files with 94 additions and 101 deletions
10
src/main.js
10
src/main.js
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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"]});
|
||||||
|
|
|
@ -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");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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) {
|
||||||
// or dedicated set sync_token method?
|
return this._sessionStore.put({key: 1, value: session});
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
Loading…
Reference in a new issue