1+ import { CACHE_DB , DB , STATE_DB } from '@/js/consts' ;
12import { API } from '@/js/msg-api' ;
3+ import { CLIENT } from '@/js/port' ;
24import { STORAGE_KEY } from '@/js/prefs' ;
35import { chromeLocal } from '@/js/storage-util' ;
46import { CHROME } from '@/js/ua' ;
5- import { deepCopy } from '@/js/util' ;
7+ import { deepMerge } from '@/js/util' ;
8+ import { bgBusy } from './common' ;
69import ChromeStorageDB from './db-chrome-storage' ;
10+ import offscreen , { offscreenCache } from './offscreen' ;
11+ import { offloadCache } from './style-manager/util' ;
712
813/*
914 Initialize a database. There are some problems using IndexedDB in Firefox:
@@ -15,7 +20,7 @@ import ChromeStorageDB from './db-chrome-storage';
1520let exec = __ . BUILD === 'chrome' || CHROME
1621 ? dbExecIndexedDB
1722 : tryUsingIndexedDB ;
18- const DB = 'stylish' ;
23+ const cachedClient = new WeakSet ( ) ;
1924const FALLBACK = 'dbInChromeStorage' ;
2025const REASON = FALLBACK + 'Reason' ;
2126const CACHING = { } ;
@@ -26,7 +31,7 @@ const dataCache = {};
2631const proxies = { } ;
2732const databases = { } ;
2833const proxyHandler = {
29- get : ( { dbName} , cmd ) => ( CACHING [ dbName ] ? cachedExec : exec ) . bind ( null , dbName , cmd ) ,
34+ get : ( { dbName} , cmd ) => ( CACHING [ dbName ] || exec ) . bind ( null , dbName , cmd ) ,
3035} ;
3136/**
3237 * @param {string } dbName
@@ -36,40 +41,85 @@ const proxyHandler = {
3641 * @param {string } [cfg.store]
3742 * @return {IDBObjectStoreMany }
3843 */
39- export const getDbProxy = ( dbName , {
44+ const getDbProxy = ( dbName , {
4045 cache,
4146 id,
4247 store = 'data' ,
4348 ver = 2 ,
4449} = { } ) => ( proxies [ dbName ] ??= (
45- ( CACHING [ dbName ] = cache ) ,
50+ ( CACHING [ dbName ] = typeof cache === 'function' ? cache : cache && cachedExec ) ,
4651 ( DATA_KEY [ dbName ] = ! id || typeof id === 'string' ? id : 'id' ) ,
4752 ( STORES [ dbName ] = store ) ,
4853 ( VERSIONS [ dbName ] = ver ) ,
4954 new Proxy ( { dbName} , proxyHandler )
5055) ) ;
5156
52- export const db = getDbProxy ( DB , { id : true , store : 'styles' } ) ;
57+ export const cacheDB = getDbProxy ( CACHE_DB , {
58+ id : 'url' ,
59+ cache : __ . MV3 && cachedExecOffscreen ,
60+ } ) ;
61+ export const db = getDbProxy ( DB , {
62+ id : true ,
63+ store : 'styles' ,
64+ cache : __ . MV3 && cachedExecOffscreen ,
65+ } ) ;
5366export const draftsDb = getDbProxy ( 'drafts' , { cache : true } ) ;
5467/** Storage for big items that may exceed 8kB limit of chrome.storage.sync.
5568 * To make an item syncable register it with uuidIndex.addCustom. */
56- export const prefsDb = getDbProxy ( STORAGE_KEY , { cache : true } ) ;
69+ export const prefsDb = getDbProxy ( STORAGE_KEY , {
70+ cache : ! __ . MV3 || cachedExecOffscreen ,
71+ } ) ;
72+ export const stateDB = __ . MV3 && getDbProxy ( STATE_DB , {
73+ store : 'kv' ,
74+ cache : cachedExecOffscreen ,
75+ } ) ;
5776
5877Object . assign ( API , /** @namespace API */ {
5978 draftsDb,
6079 prefsDb,
6180} ) ;
6281
6382async function cachedExec ( dbName , cmd , a , b ) {
64- const hub = dataCache [ dbName ] || ( dataCache [ dbName ] = { } ) ;
65- const res = cmd === 'get' && a in hub ? hub [ a ] : await exec ( ...arguments ) ;
66- if ( cmd === 'get' ) {
67- hub [ a ] = deepCopy ( res ) ;
68- } else if ( cmd === 'put' ) {
69- const key = DATA_KEY [ dbName ] ;
70- hub [ key ? a [ key ] : b ] = deepCopy ( a ) ;
71- } else if ( cmd === 'delete' ) {
72- delete hub [ a ] ;
83+ const old = dataCache [ dbName ] ;
84+ const hub = old || ( dataCache [ dbName ] = { __proto__ : null } ) ;
85+ const res = cmd === 'get' && a in hub
86+ ? hub [ a ]
87+ : old && cmd === 'getAll'
88+ ? Object . values ( old )
89+ : await exec ( ...arguments ) ;
90+ switch ( cmd ) {
91+ case 'put' :
92+ cmd = DATA_KEY [ dbName ] ;
93+ hub [ cmd ? a [ cmd ] : b ] = deepMerge ( a ) ;
94+ break ;
95+ case 'delete' :
96+ delete hub [ a ] ;
97+ break ;
98+ case 'clear' :
99+ delete dataCache [ dbName ] ;
100+ break ;
101+ }
102+ return res && typeof res === 'object' ? deepMerge ( res ) : res ;
103+ }
104+
105+ async function cachedExecOffscreen ( dbName , cmd , a ) {
106+ let res ;
107+ const isRead = cmd === 'get' || cmd === 'getAll' ;
108+ if ( isRead
109+ && offscreenCache
110+ && await offscreenCache
111+ && ( res = offscreenCache [ dbName ] ) ) {
112+ res = cmd === 'get' ? res . get ( a ) : [ ...res . values ( ) ] ;
113+ } else {
114+ if ( ( a = offscreen [ CLIENT ] ) ) {
115+ if ( ! cachedClient . has ( a ) ) {
116+ cachedClient . add ( a ) ;
117+ if ( ! bgBusy ) offloadCache ( dataCache [ STATE_DB ] || { } ) ;
118+ } else if ( ! isRead ) {
119+ offscreen . dbCache ( ...arguments ) ;
120+ }
121+ }
122+ res = ( dbName === STATE_DB || dbName === STORAGE_KEY ? cachedExec : exec ) ( ...arguments ) ;
73123 }
74124 return res ;
75125}
0 commit comments