import { UUIDType, uuidTypes } from "./types"; import { BaseHandler } from "./base-handler"; // 웹 URI에서 UUID를 제외하고 IndexedDB에서 UUID를 관리하는 클래스 export default class IndexedDBHandler extends BaseHandler { static instance: IndexedDBHandler | null = null; dbName = "eviq_csms"; dbVersion = 1; storeName = "detail_id"; // 상세페이지를 식별하는 ID; db: IDBDatabase | null = null; dbInitRetryMaxCount = 3; tempStorage: Record = { // set 실패 시에도 get, delete 요청을 처리하기 위한 임시 저장소 evStationId: "", evChargerId: "", chargingHistoryId: "", customerServiceId: "", noticeId: "", onlineUserId: "", }; /** * IndexedDBHandler 인스턴스 생성후 return * * @public * @return instance */ static getInstance(): IndexedDBHandler { if (!this.instance) { this.instance = new IndexedDBHandler(); } return this.instance; } /** * indexed db에 값 저장 * * @public * @param uuidType "evStationId, evChargerId, chargingHistoryId, onlineUserId, customerServiceId, noticeId" * @param uuidValue uuid * @return 값 저장후 결과 return */ async set(uuidType: UUIDType, uuidValue: string): Promise { try { const transaction = await this.createTransaction("readwrite"); return this.checkRequestSuccess(transaction.put(uuidValue, uuidType)); } catch (error) { console.error(error); this.tempStorage[uuidType] = uuidValue; return uuidValue; } } /** * indexed db에 값 꺼내오기 * * @public * @param uuidType "evStationId, evChargerId, chargingHistoryId, onlineUserId, customerServiceId, noticeId" * @return indexed db에 uuidType으로 key로 저장되어있는 value return */ async get(uuidType: UUIDType): Promise { try { const transaction = await this.createTransaction("readonly"); return this.checkRequestSuccess(transaction.get(uuidType)); } catch (error) { return await this.useTempStorage(uuidType); } } /** * indexed db에 값 삭제하기 * * @public * @param uuidType "evStationId, evChargerId, chargingHistoryId, onlineUserId, customerServiceId, noticeId" * @return indexed db에 uuidType으로 key로 저장되어있는 value 삭제 후 결과 return */ async delete(uuidType: UUIDType): Promise { try { const transaction = await this.createTransaction("readonly"); return this.checkRequestSuccess(transaction.get(uuidType)); } catch (error) { return await this.useTempStorage(uuidType); } } /** * indexed db에 값 모두 삭제하기 * * @public */ async clear(): Promise { const transaction = await this.createTransaction("readwrite"); await Promise.all( uuidTypes.map((uuidType) => { this.checkRequestSuccess(transaction.delete(uuidType)); this.tempStorage[uuidType] = ""; }) ); this.cleanUp(); } /** * indexed db 생성 및 열기 * * @public */ init(): Promise { return new Promise((resolve, reject) => { const request = indexedDB.open(this.dbName, this.dbVersion); request.onsuccess = (event) => { this.db = (event.target as IDBOpenDBRequest).result; resolve(); }; request.onerror = () => { reject(request.error); }; request.onupgradeneeded = (event) => { this.db = (event.target as IDBOpenDBRequest).result; // 객체 저장소 생성 if (event.oldVersion < this.dbVersion) { this.db.createObjectStore(this.storeName); } }; }); } /** * indexedDB에 store가 있으면 transaction 생성 후 store return 없으면 store create * * @public */ async createTransaction( mode: IDBTransactionMode, retryCount = this.dbInitRetryMaxCount ): Promise { if (this.db) { return this.db .transaction(this.storeName, mode) .objectStore(this.storeName); } try { await this.init(); // 새로고침 등으로 DB를 다시 열어야 할 때 } catch (error) { if (retryCount > 0) { return await this.createTransaction(mode, retryCount - 1); // 재시도 } else { throw error; } } return await this.createTransaction(mode); } /** * indexed db와 관련된 method들을 호출 했을 때 처리가 정상적으로 되었는지 확인. * * @public * @return 정상적으로 잘 되었으면 결과 return, 안되었으면 error return */ checkRequestSuccess(request: IDBRequest): Promise { return new Promise((resolve, reject) => { request.onsuccess = (event) => { resolve((event.target as IDBRequest).result); }; request.onerror = (event) => { reject(new Error((event.target as IDBRequest).error?.message)); }; }); } /** * indexed db에 delete, get할 때 오류가 날 경우 임시로 tempStorage에 넣어 둔 값을 return * * @public * @param uuidType * @return tempStorage에 key가 uuidType이었던 값 return */ async useTempStorage(uuidType: UUIDType): Promise { const uuidValue = this.tempStorage[uuidType]; if (uuidValue) { await this.set(uuidType, uuidValue); this.tempStorage[uuidType] = ""; return uuidValue; } else { throw new Error("IndexedDB retrieval failed"); } } /** * indexed db transaction 종료 및 db 연결 disconnect, 이벤트 리스너 제거, 객체 참조 해제 * * @public */ cleanUp(): void { if (!this.db) return; // 트랜잭션 종료 if (this.db.transaction) { const transaction = this.db.transaction(this.storeName); transaction.abort(); } // DB 연결 닫기 this.db.close(); // 이벤트 리스너 제거 this.db.onclose = null; this.db.onabort = null; // 객체 참조 해제 this.db = null; } }