TypeScript zipファイルとIndexedDBを使ったインストール(ファイルキャッシュ)システムの作成
ブラウザで動作するゲームなどが利用するデータ(画像、ポリゴンデータなど)をIndexedDBに保存する(インストール)することで、読み込み処理の高速化、サーバー負荷軽減が行えます。
使い方
zipファイル内のファイルをIndexedDBに保存、fetchなどサーバーにアクセスする前にDBを検索、あればそのデータを使いなければサーバーから取得
zipが更新されていればDBの再構築
const nameDB = "ZipFileCacheSample";
// db削除
// IdxDBFileCache.deleteDatabase(nameDB)
// DBオープン なければ作成
// zipファイルが更新されていたら再構築
let fileCache = await IdxDBFileCache.openDB(nameDB, "./test.zip");
// キャッシュにあればIndexedBDから取得
// なければfetchで取得
let blob = await fileCache.loadFile("./test/test.dat");
console.log(blob);
IndexedDB?
ブラウザが管理するオブジェクト指向データベース
ローカルな記憶領域(装置)にデータが保存されます。
詳しくは検索で
ソースコード(有料)
サイズが大きく更新頻度が低いデータ(画像、ポリゴンデータとか)を利用するゲームでの利用が効果的です
ただし
実際に使用するには、エラー処理やデータの整合性チェックなどが必要になります。基本的な機能のみの実装です。
利用API
IndexedDB
DecompressionStream
TextDecoder
動作確認
Windows10 Edge (2023/11/9)
ソースコードの一部
実装部分を除いたソースコードです
export class IdxDBFileCache{
iddb : IDBDatabase;
readonly nameStore : string;
topURL : string;
private constructor(iddb : IDBDatabase, topURL : string, nameStore : string){
this.topURL = topURL;
this.iddb = iddb;
this.nameStore = nameStore;
}
// DBオープン なければ作成
// zipファイルが更新されていたら再構築
static async openDB(nameDB : string, zipURL : string){
// remove ".zip"
let topURL = zipURL.slice(0,-4);
// zipファイルの更新日時
let resp = await fetch(zipURL,{method:"HEAD"});
let dateStr = resp.headers.get("Last-Modified");
if(!dateStr){
throw "IdxDBFileCache zipURL " + zipURL;
}
// 更新日時(ms)をバージョンとして使用
let date = new Date(dateStr);
const version = date.getTime();
const nameStore = "FileCache";
let rebuild = false;
let open = indexedDB.open(nameDB, version);
let iddb = await new Promise<IDBDatabase>((rs,rj)=>{
open.onupgradeneeded = (event : IDBVersionChangeEvent)=>{
let db = open.result;
if(event.oldVersion != 0 && event.oldVersion != event.newVersion){
// 削除
// 効率化:更新があったファイルだけ更新とか
db.deleteObjectStore(nameStore);
}
console.log("db build");
db.createObjectStore(nameStore);
rebuild = true;
};
open.onsuccess = ()=>{
console.log("db open success " + nameDB);
rs(open.result);
};
open.onerror = (event)=>{
rj(event);
};
});
// ファイルキャッシュDB構築
if(rebuild){
// zipファイルをメモリに
// 大きい場合は分割、ファイルの部分アクセスなどで省メモリ化
let blobZip = await (await fetch(zipURL)).blob();
// ファイル情報取得
let files = await parsePkZip(blobZip);
// ファイルの登録
// DB容量節約 : 圧縮した状態で保存、読み込み時に展開
for(let file of files){
let key = topURL+"/"+file.fileName;
let buff = blobZip.slice(file.filePtr, file.filePtr+file.compSize);
//console.log(key)
IdxDBFileCache.putObj(iddb, nameStore, key, {header:file, data : buff});
}
}
return new IdxDBFileCache(iddb, topURL, nameStore);
}
// ファイル読み込み
// キャッシュにあればIndexedBDから取得
// なければfetchで取得
async loadFile(url : string){
let obj = await IdxDBFileCache.getObj(this.iddb, this.nameStore, url);
if(obj){
if(obj.header.compType == COMP_DEFLATE){
let blob = await decompressPkZipDeflate(obj.data);
let crc32 = new CRC32().crc32( new Uint8Array( await blob.arrayBuffer()));
if(crc32 != obj.header.crc32){
throw "IdxDBFileCache loadFile crc";
}
return blob;
}else{
return obj.data;
}
}else{
//console.log("fetch " + url)
let resp = await fetch(url);
if(!resp.ok || resp.status != 200){
return undefined;
}
return resp.blob();
}
}
}
ソースコード(フル)
ここから先は
12,748字
¥ 300
この記事が役に立ったという方は、サポートお願いします。今後の製作の励みになります。