@@ -1540,10 +1540,10 @@ vAPI.cloud = (( ) => {
15401540 // good thing given chrome.storage.sync.MAX_WRITE_OPERATIONS_PER_MINUTE
15411541 // and chrome.storage.sync.MAX_WRITE_OPERATIONS_PER_HOUR.
15421542
1543- const getCoarseChunkCount = async function ( dataKey ) {
1543+ const getCoarseChunkCount = async function ( datakey ) {
15441544 const keys = { } ;
15451545 for ( let i = 0 ; i < maxChunkCountPerItem ; i += 16 ) {
1546- keys [ dataKey + i . toString ( ) ] = '' ;
1546+ keys [ datakey + i . toString ( ) ] = '' ;
15471547 }
15481548 let bin ;
15491549 try {
@@ -1553,13 +1553,13 @@ vAPI.cloud = (( ) => {
15531553 }
15541554 let chunkCount = 0 ;
15551555 for ( let i = 0 ; i < maxChunkCountPerItem ; i += 16 ) {
1556- if ( bin [ dataKey + i . toString ( ) ] === '' ) { break ; }
1556+ if ( bin [ datakey + i . toString ( ) ] === '' ) { break ; }
15571557 chunkCount = i + 16 ;
15581558 }
15591559 return chunkCount ;
15601560 } ;
15611561
1562- const deleteChunks = function ( dataKey , start ) {
1562+ const deleteChunks = async function ( datakey , start ) {
15631563 const keys = [ ] ;
15641564
15651565 // No point in deleting more than:
@@ -1570,54 +1570,70 @@ vAPI.cloud = (( ) => {
15701570 Math . ceil ( maxStorageSize / maxChunkSize )
15711571 ) ;
15721572 for ( let i = start ; i < n ; i ++ ) {
1573- keys . push ( dataKey + i . toString ( ) ) ;
1573+ keys . push ( datakey + i . toString ( ) ) ;
15741574 }
15751575 if ( keys . length !== 0 ) {
15761576 webext . storage . sync . remove ( keys ) ;
15771577 }
15781578 } ;
15791579
1580- const push = async function ( dataKey , data ) {
1581- let bin = {
1582- 'source' : options . deviceName || options . defaultDeviceName ,
1583- 'tstamp' : Date . now ( ) ,
1584- 'data' : data ,
1585- 'size' : 0
1580+ const push = async function ( details ) {
1581+ const { datakey, data, encode } = details ;
1582+ if (
1583+ data === undefined ||
1584+ typeof data === 'string' && data === ''
1585+ ) {
1586+ return deleteChunks ( datakey , 0 ) ;
1587+ }
1588+ const item = {
1589+ source : options . deviceName || options . defaultDeviceName ,
1590+ tstamp : Date . now ( ) ,
1591+ data,
15861592 } ;
1587- bin . size = JSON . stringify ( bin ) . length ;
1588- const item = JSON . stringify ( bin ) ;
1593+ const json = JSON . stringify ( item ) ;
1594+ const encoded = encode instanceof Function
1595+ ? await encode ( json )
1596+ : json ;
15891597
15901598 // Chunkify taking into account QUOTA_BYTES_PER_ITEM:
15911599 // https://developer.chrome.com/extensions/storage#property-sync
15921600 // "The maximum size (in bytes) of each individual item in sync
15931601 // "storage, as measured by the JSON stringification of its value
15941602 // "plus its key length."
1595- bin = { } ;
1596- let chunkCount = Math . ceil ( item . length / maxChunkSize ) ;
1603+ const bin = { } ;
1604+ const chunkCount = Math . ceil ( encoded . length / maxChunkSize ) ;
15971605 for ( let i = 0 ; i < chunkCount ; i ++ ) {
1598- bin [ dataKey + i . toString ( ) ] = item . substr ( i * maxChunkSize , maxChunkSize ) ;
1606+ bin [ datakey + i . toString ( ) ]
1607+ = encoded . substr ( i * maxChunkSize , maxChunkSize ) ;
15991608 }
1600- bin [ dataKey + chunkCount . toString ( ) ] = '' ; // Sentinel
1609+ bin [ datakey + chunkCount . toString ( ) ] = '' ; // Sentinel
16011610
1611+ // Remove potentially unused trailing chunks before storing the data,
1612+ // this will free storage space which could otherwise cause the push
1613+ // operation to fail.
1614+ try {
1615+ await deleteChunks ( datakey , chunkCount ) ;
1616+ } catch ( reason ) {
1617+ }
1618+
1619+ // Push the data to browser-provided cloud storage.
16021620 try {
16031621 await webext . storage . sync . set ( bin ) ;
16041622 } catch ( reason ) {
16051623 return String ( reason ) ;
16061624 }
1607-
1608- // Remove potentially unused trailing chunks
1609- deleteChunks ( dataKey , chunkCount ) ;
16101625 } ;
16111626
1612- const pull = async function ( dataKey ) {
1627+ const pull = async function ( details ) {
1628+ const { datakey, decode } = details ;
16131629
1614- const result = await getCoarseChunkCount ( dataKey ) ;
1630+ const result = await getCoarseChunkCount ( datakey ) ;
16151631 if ( typeof result !== 'number' ) {
16161632 return result ;
16171633 }
16181634 const chunkKeys = { } ;
16191635 for ( let i = 0 ; i < result ; i ++ ) {
1620- chunkKeys [ dataKey + i . toString ( ) ] = '' ;
1636+ chunkKeys [ datakey + i . toString ( ) ] = '' ;
16211637 }
16221638
16231639 let bin ;
@@ -1633,22 +1649,48 @@ vAPI.cloud = (( ) => {
16331649 // happen when the number of chunks is a multiple of
16341650 // chunkCountPerFetch. Hence why we must also test against
16351651 // undefined.
1636- let json = [ ] , jsonSlice ;
1652+ let encoded = [ ] ;
16371653 let i = 0 ;
16381654 for ( ; ; ) {
1639- jsonSlice = bin [ dataKey + i . toString ( ) ] ;
1640- if ( jsonSlice === '' || jsonSlice === undefined ) { break ; }
1641- json . push ( jsonSlice ) ;
1655+ const slice = bin [ datakey + i . toString ( ) ] ;
1656+ if ( slice === '' || slice === undefined ) { break ; }
1657+ encoded . push ( slice ) ;
16421658 i += 1 ;
16431659 }
1660+ encoded = encoded . join ( '' ) ;
1661+ const json = decode instanceof Function
1662+ ? await decode ( encoded )
1663+ : encoded ;
16441664 let entry = null ;
16451665 try {
1646- entry = JSON . parse ( json . join ( '' ) ) ;
1666+ entry = JSON . parse ( json ) ;
16471667 } catch ( ex ) {
16481668 }
16491669 return entry ;
16501670 } ;
16511671
1672+ const used = async function ( datakey ) {
1673+ if ( webext . storage . sync . getBytesInUse instanceof Function === false ) {
1674+ return ;
1675+ }
1676+ const coarseCount = await getCoarseChunkCount ( datakey ) ;
1677+ if ( typeof coarseCount !== 'number' ) { return ; }
1678+ const keys = [ ] ;
1679+ for ( let i = 0 ; i < coarseCount ; i ++ ) {
1680+ keys . push ( `${ datakey } ${ i } ` ) ;
1681+ }
1682+ let results ;
1683+ try {
1684+ results = await Promise . all ( [
1685+ webext . storage . sync . getBytesInUse ( keys ) ,
1686+ webext . storage . sync . getBytesInUse ( null ) ,
1687+ ] ) ;
1688+ } catch ( ex ) {
1689+ }
1690+ if ( Array . isArray ( results ) === false ) { return ; }
1691+ return { used : results [ 0 ] , total : results [ 1 ] , max : QUOTA_BYTES } ;
1692+ } ;
1693+
16521694 const getOptions = function ( callback ) {
16531695 if ( typeof callback !== 'function' ) { return ; }
16541696 callback ( options ) ;
@@ -1665,7 +1707,7 @@ vAPI.cloud = (( ) => {
16651707 getOptions ( callback ) ;
16661708 } ;
16671709
1668- return { push, pull, getOptions, setOptions } ;
1710+ return { push, pull, used , getOptions, setOptions } ;
16691711} ) ( ) ;
16701712
16711713/******************************************************************************/
0 commit comments