ethereum/mist

View on GitHub
modules/dbSync.js

Summary

Maintainability
B
5 hrs
Test Coverage
/**
@module dbSync
*/
const { ipcMain, ipcRenderer } = require('electron');

/**
 * Sync IPC calls received from given window into given db table.
 * @param  {Object} coll Db collection to save to.
 */
exports.initializeListeners = function() {
  let log = require('./utils/logger').create('dbSync'),
    db = require('./db'),
    ipc = ipcMain;

  ipc.on('dbSync-add', (event, args) => {
    let collName = args.collName,
      coll = db.getCollection(`UI_${collName}`);

    log.trace('dbSync-add', collName, args._id);

    const _id = args._id;

    if (!coll.by('_id', _id)) {
      args.fields._id = _id;
      coll.insert(args.fields);
    }
  });

  ipc.on('dbSync-changed', (event, args) => {
    let collName = args.collName,
      coll = db.getCollection(`UI_${collName}`);

    log.trace('dbSync-changed', collName, args._id);

    const _id = args._id;
    const item = coll.by('_id', _id);

    if (item) {
      for (const k in args.fields) {
        if ({}.hasOwnProperty.call(args.fields, k)) {
          item[k] = args.fields[k];
        }
      }

      coll.update(item);
    } else {
      log.error('Item not found in db', _id);
    }
  });

  ipc.on('dbSync-removed', (event, args) => {
    let collName = args.collName,
      coll = db.getCollection(`UI_${collName}`);

    log.trace('dbSync-removed', collName, args._id);

    const _id = args._id;
    const item = coll.by('_id', _id);

    if (item) {
      coll.remove(item);
    } else {
      log.error('Item not found in db', _id);
    }
  });

  // Get all data (synchronous)
  ipc.on('dbSync-reloadSync', (event, args) => {
    let collName = args.collName,
      coll = db.getCollection(`UI_${collName}`),
      docs = coll.find();

    log.debug('dbSync-reloadSync, no. of docs:', collName, docs.length);

    docs = docs.map(doc => {
      const ret = {};

      for (const k in doc) {
        if (k !== 'meta' && k !== '$loki') {
          ret[k] = doc[k];
        }
      }

      return ret;
    });

    event.returnValue = docs;
  });
};

const syncDataFromBackend = function(coll) {
  const ipc = ipcRenderer;

  const collName = coll._name;

  console.debug('Load collection data from backend: ', collName);

  return new Promise((resolve, reject) => {
    const dataJson = ipc.sendSync('dbSync-reloadSync', {
      collName
    });

    try {
      let done = 0;

      coll.remove({});

      if (!dataJson.length) {
        resolve();
      }

      // we do inserts slowly, to avoid race conditions when it comes
      // to updating the UI
      dataJson.forEach(record => {
        Tracker.afterFlush(() => {
          try {
            // On Meteor startup if a record contains a redirect to about:blank
            // page, the application process crashes.
            if (
              _.isString(record.redirect) &&
              record.redirect.indexOf('//about:blank') > -1
            ) {
              record.redirect = null;
            }

            if (record._id) {
              coll.upsert(record._id, record);
            } else {
              coll.insert(record);
            }
          } catch (err) {
            console.error(err.toString());
          }

          done++;

          if (done >= dataJson.length) {
            resolve();
          }
        });
      });
    } catch (err) {
      reject(err);
    }
  });
};
exports.syncDataFromBackend = syncDataFromBackend;

exports.frontendSyncInit = function(coll) {
  let ipc = ipcRenderer,
    syncDoneResolver;

  const collName = coll._name;

  coll.onceSynced = new Promise((resolve, reject) => {
    syncDoneResolver = resolve;
  });

  syncDataFromBackend(coll)
    .catch(err => {
      console.error(err.toString());
    })
    .then(() => {
      // start watching for changes
      coll.find().observeChanges({
        added(id, fields) {
          ipc.send('dbSync-add', {
            collName,
            _id: id,
            fields
          });
        },
        changed(id, fields) {
          ipc.send('dbSync-changed', {
            collName,
            _id: id,
            fields
          });
        },
        removed(id) {
          ipc.send('dbSync-removed', {
            collName,
            _id: id
          });
        }
      });

      console.debug('Sync collection data to backend started: ', collName);

      syncDoneResolver();
    });

  return coll;
};