Home Manual Reference Source Test

src/lib/db/upload.js

import { utimes } from 'fs';
import through from 'through2';
import DBWorker, { Job } from 'atvise-dbworker';
import { log, colors, PluginError } from 'gulp-util';
import plur from 'plur';
import Project from '../config/ProjectConfig';
import NodeId from '../model/NodeId';

function encodedValue(value, dataType) {
  const stringValue = value.toString().trim();

  if (dataType === 'Boolean') { return stringValue === 'true'; }

  if (dataType === 'String') { return stringValue; }

  if (dataType === 'NodeId') { return NodeId.fromString(stringValue); }

  if (dataType === 'DateTime') { return new Date(value); }

  // FIXME: For ints that are not set (value = {}) this inserts a value of 0
  if (dataType.match(/^u?int/i)) { return parseInt(stringValue, 10) || 0; }

  return value;
}

function encodedContents(file) {
  const contents = file.contents;
  const dataType = file.rc.dataType;

  if (file.rc.array) {
    return JSON.parse(contents).map(v => encodedValue(v, dataType));
  }

  return encodedValue(contents, dataType);
}

function forceValidMtime(session, file, stream, cb) {
  session.read([file.nodeId], (err, nodes, results) => {
    if (!err && results.length > 0) {
      const mtime = Math.floor(results[0].serverTimestamp / 1000);

      utimes(file.path, mtime, mtime, utimesErr => {
        if (!utimesErr) {
          file.stat.mtime = new Date(mtime);
          stream.push(file);
        }
        cb(utimesErr);
      });
    } else {
      cb(err);
    }
  });
}

function uploadFile(session, file, stream, worker, cb) {
  try {
    session.writeSingleNode(file.nodeId.toString(), {
      dataType: file.rc.dataType,
      value: encodedContents(file),
    }, (err, status) => {
      if (err) {
        err.node = file.nodeId;
        cb(err);
      } else if (status > 0) {
        log(colors.red.bold('Error'), 'writing to', colors.magenta(file.nodeId.value));
        log(colors.yellow(status.description));
        log(colors.yellow('Make sure this node is not opened in atvise builder'));
        cb();
      } else {
        if (worker) {
          // Force valid mtime
          worker.addJob(new Job((...args) => forceValidMtime(...args), file, stream));
        } else {
          stream.push(file);
        }

        cb();
      }
    });
  } catch (err) {
    err.node = file.nodeId;

    cb(err);
  }
}

/**
 * Uploads {@link AtviseFile}s from a stream to atvise-server.
 * @param {Boolean} [validMtime=false] Pass `true` to force the file to have the same mtime as the
 * db node. **Use with caution: forcing mtime to be in sync doubles upload time.**
 * @return {Stream}
 */
export default function upload(validMtime) {
  let files = 0;
  const worker = new DBWorker(`opc.tcp://${Project.host}:${Project.port.opc}`);

  return through.obj(function(file, enc, cb) {
    worker.addJob(
      new Job((...args) => uploadFile(...args), file, this, validMtime ? worker : false)
    );
    files++;

    cb();
  }, function(cb) {
    if (files === 0) {
      cb();
    } else {
      worker.once('complete', () => {
        log('Uploaded', colors.cyan(files), `${plur('node', files)}.`);
        cb();
      });

      worker.on('error', err => {
        console.log('error uploading');
        // FIXME: Better error
        cb(new PluginError('upload', err));
      });

      worker.start();
    }
  });
}