Search code examples
javascriptalgorithmgoogle-chrome-extension

Algorithm to break down item for chrome storage sync


I am trying to save a string (correction: it is an object containing multiple strings of varying sizes) using chrome.storage.sync.set but am receiving the error: Error: QUOTA_BYTES_PER_ITEM quota exceeded

this is due to the limit being 8092 so I want to break the string down into multiple parts and then be able to reconstruct it when retrieving them.

my code that is giving the existing error is below.

 var obj = {};
  obj[workspaceName] = stringToSave;  
  chrome.storage.sync.set(obj, function() {
    if (chrome.runtime.lastError) {
      return customAlert("Error!: " + chrome.runtime.lastError.message);
    }
  });

Is there an existing function or code that would help me to do this?


Solution

  • Writing: generate an object like {foo0: chunkA, foo1: chunkB, foo2: chunkC, foo#: 3}.

    function chunkedWrite(key, value) {
      return new Promise(resolve => {
        if (typeof key !== 'string') key = `${key}`;
        const str = JSON.stringify(value); // consider using LZString's compressToUTF16
        const len = chrome.storage.sync.QUOTA_BYTES_PER_ITEM - key.length - 4;
        const num = Math.ceil(str.length / len);
        const obj = {};
        obj[key + '#'] = num;
        for (let i = 0; i < num; i++) {
          obj[key + i] = str.substr(i * len, len);
        }
        chrome.storage.sync.set(obj, resolve);
      });
    }
    

    Reading is two-part: read the number of keys first, then read all the keys at once.

    function chunkedRead(key) {
      return new Promise(resolve => {
        if (typeof key !== 'string') key = `${key}`;
        const keyNum = key + '#';
        chrome.storage.sync.get(keyNum, data => {
          const num = data[keyNum];
          const keys = [];
          for (let i = 0; i < num; i++) {
            keys[i] = key + i;
          }
          chrome.storage.sync.get(keys, data => {
            const chunks = [];
            for (let i = 0; i < num; i++) {
              chunks.push(data[key + i] || '');
            }
            const str = chunks.join('');
            resolve(str ? JSON.parse(str) : undefined);
          });
        });
      });
    }
    

    Deleting is similar to reading: read key#, then delete the array of keys.

    function chunkedDelete(key) {
      return new Promise(resolve => {
        if (typeof key !== 'string') key = `${key}`;
        const keyNum = key + '#';
        chrome.storage.sync.get(keyNum, data => {
          const num = data[keyNum];
          const keys = [keyNum];
          for (let i = 0; i < num; i++) {
            keys.push(key + i);
          }
          chrome.storage.sync.remove(keys, resolve);
        });
      });
    }