import * as d from "../localData"; import * as util from "../core/util"; const AccountTokenObjectStoreName = "AccountToken"; const imageObjectStoreName = "image"; const AccountTokenKeyName = "lastLogInUser"; /** * ブラウザでindexDBがサポートされているかどうか調べる */ const checkIndexDBSupport = (): boolean => "indexedDB" in window; /** * 1度 indexedDBにアクセスしたら, データベースへの参照を維持しておくための変数 */ let databaseCache: IDBDatabase | null = null; /** * データベースにアクセスする. * ブラウザがindexedDBがサポートされていない場合,nullが返る * Databaseにアクセスできなかったとき,rejectされる */ export const getDatabase = (): Promise => new Promise((resolve, reject) => { if (databaseCache !== null) { resolve(databaseCache); return; } if (!checkIndexDBSupport()) { resolve(null); } const dbRequest: IDBOpenDBRequest = indexedDB.open("main", 1); dbRequest.onupgradeneeded = (): void => { console.log("Databaseのversionが上がった"); databaseCache = dbRequest.result; databaseCache.createObjectStore(AccountTokenObjectStoreName, {}); databaseCache.createObjectStore(imageObjectStoreName, {}); }; dbRequest.onsuccess = (): void => { resolve(dbRequest.result); }; dbRequest.onerror = (): void => { console.log("Databaseに接続できなかった"); reject(new Error("indexed connection error")); }; }); /** * データをindexedDBから読む */ const get = ( objectStoreName: string, id: id ): Promise => new Promise((resolve, reject) => { getDatabase().then((database) => { if (database === null) { resolve(undefined); return; } const transaction = database.transaction([objectStoreName], "readonly"); transaction.oncomplete = (): void => { resolve(getRequest.result); }; transaction.onerror = (): void => { reject(new Error("read " + objectStoreName + " failed")); }; const getRequest: IDBRequest = transaction .objectStore(objectStoreName) .get(id); }); }); /** * データをindexedDBに書く */ const set = ( objectStoreName: string, id: id, data: data ): Promise => new Promise((resolve, reject) => { getDatabase().then((database) => { if (database === null) { resolve(); return; } const transaction = database.transaction([objectStoreName], "readwrite"); transaction.oncomplete = (): void => { resolve(); }; transaction.onerror = (): void => { reject( new Error( "write " + objectStoreName + " error: write transaction failed" ) ); }; transaction.objectStore(objectStoreName).put(data, id); }); }); const deleteValue = ( objectStoreName: string, id: id ): Promise => new Promise((resolve, reject) => { getDatabase().then((database) => { if (database === null) { resolve(); return; } const transaction = database.transaction([objectStoreName], "readwrite"); transaction.oncomplete = (): void => { resolve(); }; transaction.onerror = (): void => { reject( new Error( "delete " + objectStoreName + " error: delete transaction failed" ) ); }; transaction.objectStore(objectStoreName).delete(id); }); }); /** * リソースデータをindexedDBに書く * * 指定したIDのデータがなかった場合, 指定したデータをindexedDBに書く * 指定したデータのgetTimeが 前にあったデータのgetTimeより新しかった場合, 指定したデータをindexedDBに書く * そうでなければ何もしない */ const setResource = ( objectStoreName: string, id: id, resource: d.WithTime ): Promise => new Promise((resolve, reject) => { getDatabase().then((database) => { if (database === null) { resolve(); return; } const transaction = database.transaction([objectStoreName], "readonly"); transaction.oncomplete = (): void => { if (getRequest.result === undefined) { set(objectStoreName, id, resource).then(resolve); return; } if ( util.timeToDate(getRequest.result.getTime).getTime() < util.timeToDate(resource.getTime).getTime() ) { set(objectStoreName, id, resource).then(resolve); return; } resolve(); }; transaction.onerror = (): void => { reject( new Error("set before get getTime " + objectStoreName + " failed") ); }; const getRequest: IDBRequest> = transaction .objectStore(objectStoreName) .get(id); }); }); /** * indexDBからアクセストークンを取得する */ export const getAccountToken = (): Promise => get( AccountTokenObjectStoreName, AccountTokenKeyName ); /** * indexDBにアクセストークンを書き込む * @param AccountToken アクセストークン */ export const setAccountToken = (AccountToken: d.AccountToken): Promise => set( AccountTokenObjectStoreName, AccountTokenKeyName, AccountToken ); /** * indexedDBからアクセストークンを削除する */ export const deleteAccountToken = (): Promise => deleteValue( AccountTokenObjectStoreName, AccountTokenKeyName ); /** * indexedDBに画像データのキャッシュを書き込む * @param imageToken 画像のハッシュ値 * @param imagePngBinary PNGの画像バイナリのデータ */ export const setImage = ( imageToken: d.ImageHash, imagePngBinary: Uint8Array ): Promise => set( imageObjectStoreName, imageToken, imagePngBinary ); /** * indexedDBから画像データを読み込む * @param imageToken 画像のハッシュ値 */ export const getImage = ( imageToken: d.ImageHash ): Promise => get(imageObjectStoreName, imageToken);