1/* 2 * Copyright (C) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15import { info } from '../../log/Log'; 16 17/** 18 * 数据缓存期限 19 */ 20const file_cache_due = 24 * 60 * 60 * 1000; 21const db_version = 6; 22/** 23 * 初始化indexed db 24 */ 25export function initIndexedDB(): Promise<IDBDatabase> { 26 return new Promise((resolve, reject) => { 27 let request = indexedDB.open('smart_perf', db_version); 28 request.onerror = function (event): void {}; 29 request.onsuccess = function (event): void { 30 let db = request.result; 31 resolve(db); 32 }; 33 request.onupgradeneeded = function (event): void { 34 // @ts-ignore 35 let db = event!.target!.result; 36 if (db.objectStoreNames.contains('trace_file')) { 37 info('delete trace_file table'); 38 db.deleteObjectStore('trace_file'); 39 } 40 info('create trace_file table'); 41 let objectStore = db.createObjectStore('trace_file', { keyPath: 'file_index' }); 42 objectStore.createIndex('file_no', 'file_no'); 43 objectStore.createIndex('file_id', 'file_id'); 44 objectStore.createIndex('file_time', 'file_time'); 45 objectStore.createIndex('file_buffer', 'file_buffer'); 46 }; 47 }); 48} 49 50/** 51 * 删除过期数据 52 * @param db 53 */ 54export function deleteExpireData(db: IDBDatabase): void { 55 if (db?.objectStoreNames.contains('trace_file')) { 56 let objectStore = db.transaction(['trace_file'], 'readwrite').objectStore('trace_file'); 57 let request = objectStore.getAll(); 58 request.onsuccess = function (event): void { 59 let now = new Date().getTime(); 60 for (let re of request.result) { 61 if (now - re.file_time > file_cache_due) { 62 objectStore.delete(re.file_index); 63 } 64 } 65 db.close(); 66 }; 67 request.onerror = function (): void { 68 info('delete expire data failed'); 69 }; 70 } 71} 72 73/** 74 * 缓存数据 75 * @param db 数据库链接对象 76 * @param oldFileId 上次打开的文件id 77 * @param fileId 当前打开的文件id 78 * @param buffer 二进制数据 79 */ 80export function cacheTraceFileBuffer(db: IDBDatabase, oldFileId: string, fileId: string, buffer: ArrayBuffer): void { 81 if (db?.objectStoreNames.contains('trace_file')) { 82 let objectStore = db.transaction(['trace_file'], 'readwrite').objectStore('trace_file'); 83 let request = objectStore.index('file_id').getAll(oldFileId); 84 request.onsuccess = function (event): void { 85 for (let re of request.result) { 86 objectStore.delete(re.file_index); 87 } 88 info('delete file success'); 89 let size = buffer.byteLength; 90 let index = 0; 91 let no = 0; 92 let time = new Date().getTime(); 93 while (index < size) { 94 let sliceLen = Math.min(size - index, 4 * 1024 * 1024); 95 objectStore.add({ 96 file_index: randomUUID(), 97 file_no: no, 98 file_id: fileId, 99 file_time: time, 100 file_buffer: buffer.slice(index, index + sliceLen), 101 }); 102 no++; 103 index += sliceLen; 104 } 105 info('cache file success', fileId, buffer.byteLength); 106 db.close(); 107 }; 108 request.onerror = function (ev): void { 109 info('delete error', fileId); 110 }; 111 } 112} 113 114function randomUUID(): string { 115 // @ts-ignore 116 return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c: unknown) => 117 //@ts-ignore 118 (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16) 119 ); 120} 121 122/** 123 * 获取当前文件的 二进制数据 124 * @param fileId 125 */ 126export function getTraceFileBuffer(fileId: string): Promise<ArrayBuffer | null> { 127 return new Promise((resolve) => { 128 if (fileId === null || fileId === undefined || fileId === '') { 129 resolve(new Uint8Array(0).buffer); 130 } else { 131 initIndexedDB().then((db) => { 132 if (db?.objectStoreNames.contains('trace_file')) { 133 let request = db 134 .transaction(['trace_file'], 'readwrite') 135 .objectStore('trace_file') 136 .index('file_id') 137 .getAll(fileId); 138 request.onsuccess = function (ev): void { 139 let totalLen = 0; 140 let arr = request.result.sort((a, b) => a.file_no - b.file_no); 141 for (let re of arr) { 142 totalLen += re.file_buffer.byteLength; 143 } 144 let buffer = new Uint8Array(totalLen); 145 let offset = 0; 146 for (let re of arr) { 147 let ua = new Uint8Array(re.file_buffer); 148 buffer.set(ua, offset); 149 offset += re.file_buffer.byteLength; 150 } 151 arr.length = 0; 152 request.result.length = 0; 153 resolve(buffer.buffer); 154 }; 155 } else { 156 resolve(new Uint8Array(0).buffer); 157 } 158 }); 159 } 160 }); 161} 162