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: any) => 117 (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16) 118 ); 119} 120 121/** 122 * 获取当前文件的 二进制数据 123 * @param fileId 124 */ 125export function getTraceFileBuffer(fileId: string): Promise<ArrayBuffer | null> { 126 return new Promise((resolve) => { 127 if (fileId === null || fileId === undefined || fileId === '') { 128 resolve(new Uint8Array(0).buffer); 129 } else { 130 initIndexedDB().then((db) => { 131 if (db?.objectStoreNames.contains('trace_file')) { 132 let request = db 133 .transaction(['trace_file'], 'readwrite') 134 .objectStore('trace_file') 135 .index('file_id') 136 .getAll(fileId); 137 request.onsuccess = function (ev): void { 138 let totalLen = 0; 139 let arr = request.result.sort((a, b) => a.file_no - b.file_no); 140 for (let re of arr) { 141 totalLen += re.file_buffer.byteLength; 142 } 143 let buffer = new Uint8Array(totalLen); 144 let offset = 0; 145 for (let re of arr) { 146 let ua = new Uint8Array(re.file_buffer); 147 buffer.set(ua, offset); 148 offset += re.file_buffer.byteLength; 149 } 150 arr.length = 0; 151 request.result.length = 0; 152 resolve(buffer.buffer); 153 }; 154 } else { 155 resolve(new Uint8Array(0).buffer); 156 } 157 }); 158 } 159 }); 160} 161