import LRU from 'lru-cache' ; import { createPersistStore } from 'background/utils' ; import { CHAINS_ENUM , INTERNAL_REQUEST_ORIGIN } from 'consts' ; import { max } from 'lodash' ; export interface ConnectedSite { origin : string ; icon : string ; name : string ; chain : CHAINS_ENUM ; e ? : number ; isSigned : boolean ; isTop : boolean ; order ? : number ; } export type PermissionStore = { dumpCache : ReadonlyArray < LRU . Entry < string , ConnectedSite > > ; } ; class PermissionService { store : PermissionStore = { dumpCache : [ ] , } ; lruCache : LRU < string , ConnectedSite > | undefined ; init = async ( ) => { const storage = await createPersistStore < PermissionStore > ( { name : 'permission' , } ) ; this . store = storage || this . store ; this . lruCache = new LRU ( ) ; const cache = ( this . store . dumpCache || [ ] ) . map ( ( item ) => ( { k : item . k , v : item . v , e : 0 , } ) ) ; this . lruCache . load ( cache ) ; } ; sync = ( ) => { if ( ! this . lruCache ) return ; this . store . dumpCache = this . lruCache . dump ( ) ; } ; getWithoutUpdate = ( key ) => { if ( ! this . lruCache ) return ; return this . lruCache . peek ( key ) ; } ; addConnectedSite = ( origin , name , icon , defaultChain , isSigned = false ) => { if ( ! this . lruCache ) return ; this . lruCache . set ( origin , { origin , name , icon , chain : defaultChain , isSigned , isTop : false , } ) ; this . sync ( ) ; } ; touchConnectedSite = ( origin ) => { if ( ! this . lruCache ) return ; if ( origin === INTERNAL_REQUEST_ORIGIN ) return ; this . lruCache . get ( origin ) ; this . sync ( ) ; } ; updateConnectSite = ( origin , value , partialUpdate ? ) => { if ( ! this . lruCache || ! this . lruCache . has ( origin ) ) return ; if ( origin === INTERNAL_REQUEST_ORIGIN ) return ; if ( partialUpdate ) { const _value = this . lruCache . get ( origin ) ; this . lruCache . set ( origin , { ... _value , ... value } as ConnectedSite ) ; } else { this . lruCache . set ( origin , value as ConnectedSite ) ; } this . sync ( ) ; } ; hasPerssmion = ( origin ) => { if ( ! this . lruCache ) return ; if ( origin === INTERNAL_REQUEST_ORIGIN ) return true ; return this . lruCache . has ( origin ) ; } ; setRecentConnectedSites = ( sites ) => { this . lruCache ?. load ( sites . map ( ( item ) => ( { e : 0 , k : item . origin , v : item , } ) ) ) ; this . sync ( ) ; } ; getRecentConnectedSites = ( ) => { const sites = this . lruCache ?. values ( ) || [ ] ; const pinnedSites = sites . filter ( ( item ) => item ?. isTop ) . sort ( ( a , b ) => ( a . order || 0 ) - ( b . order || 0 ) ) ; const recentSites = sites . filter ( ( item ) => ! item . isTop ) ; return [ ... pinnedSites , ... recentSites ] ; } ; getConnectedSites = ( ) => { return this . lruCache ?. values ( ) || [ ] ; } ; getConnectedSite = ( key ) => { return this . lruCache ?. get ( key ) ; } ; topConnectedSite = ( origin , order ? ) => { const site = this . getConnectedSite ( origin ) ; if ( ! site || ! this . lruCache ) return ; order = order ?? ( max ( this . getRecentConnectedSites ( ) . map ( ( item ) => item . order ) ) || 0 ) + 1 ; this . updateConnectSite ( origin , { ... site , order , isTop : true , } ) ; } ; unpinConnectedSite = ( origin ) => { const site = this . getConnectedSite ( origin ) ; if ( ! site || ! this . lruCache ) return ; this . updateConnectSite ( origin , { ... site , isTop : false , } ) ; } ; removeConnectedSite = ( origin ) => { if ( ! this . lruCache ) return ; this . lruCache . del ( origin ) ; this . sync ( ) ; } ; getSitesByDefaultChain = ( chain ) => { if ( ! this . lruCache ) return [ ] ; return this . lruCache . values ( ) . filter ( ( item ) => item . chain === chain ) ; } ; isInternalOrigin = ( origin ) => { return origin === INTERNAL_REQUEST_ORIGIN ; } ; } export default new PermissionService ( ) ;