<commit_before>var fdom = fdom || {};

/**
 * Defines fdom.Hub, the core message hub between freedom modules.
 * Incomming messages from apps are sent to hub.onMessage()
 * Use fdom.Hub.get() for the singleton instance.
 * @private
 * @constructor
 */
fdom.Hub = function() {
  this.config = {};
  this.apps = {};
  this.pipes = {};
  this.unbound = [];
  handleEvents(this);
};

/**
 * Singleton accessor for fdom.Hub.
 * @returns {fdom.Hub} The singleton freedom hub interconnecting freedom modules.
 */
fdom.Hub.get = function() {
  if (!fdom.Hub._hub) {
    fdom.Hub._hub = new fdom.Hub();
  }
  window.hub = fdom.Hub._hub;
  return fdom.Hub._hub;
};

/**
 * Handle an incoming message from a freedom app.
 * @param {fdom.app} app The app sending the message.
 * @param {Object} message The sent message.
 */
fdom.Hub.prototype.onMessage = function(app, message) {
  if (!this.apps[app.id]) {
    console.warn("Message dropped from unregistered app " + app.id);
    return;
  }
  var flows = this.pipes[app.id];
  var flow = message.sourceFlow;
  var destChannel = flows[flow];

  if (flow == 'control') {
    if (this.config['debug'] && message.request != 'debug') {
      console.log(app.id + " -C " + message.request);
    } else if (this.config['debug']) {
      console.log(app.id + " -D " + message.msg);
    }
    // Signaling Channel.
    if (message.request == 'dep') {
      this.createPipe(app, message.dep);
    } else if (message.request == 'create') {
      var config = {
        "debug": this.config['debug']
      };

      app.postMessage({
        sourceFlow: 'control',
        msg: {
          id: app.id,
          manifest: app.manifest,
          config: config
        }
      });
      this.permitAccess(app.id);
    } else if (message.request == 'ready') {
      app.ready();
    } else if (message.request == 'channel') {
      // Register new unprivileged message channel.
      var flow = 'custom' + Math.random();

      // Binding a channel.
      if (message.to) {
        var aid = message.to[0];
        var dep = this.apps[aid];
        var endpoint = false;
        for (var i = 0; i < this.unbound.length; i++) {
          if (this.unbound[i][0] == dep) {
            endpoint = this.unbound[i];
            this.unbound.splice(i, 1);
            break;
          }
        }
        if (endpoint) {
          var other = endpoint[0];
          if (this.pipes[app.id][flow] || this.pipes[other.id][endpoint[1]]) {
            console.warn("unwilling to redefine existing pipes.");
          } else {
            this.pipes[app.id][flow] = other.getChannel(endpoint[1]);
            this.pipes[other.id][endpoint[1]] = app.getChannel(flow);
          }
        }
      } else {
        // TODO: make sure apps can't make infinite unbound pipes.
        this.unbound.push([app, flow]);
      }

      app.postMessage({
        sourceFlow: 'control',
        msg: {
          flow: flow
        }
      });
    }
  } else if (destChannel) {
    if (this.debug("channels")) {
      console.log(app.id + " -> " + flow + " " + message.msg.action + " " + message.msg.type);
    }

    // Deliver Message
    if (destChannel == app.getChannel(flow)) {
      destChannel.onMessage(message.msg);
    } else {
      destChannel.postMessage(message.msg);
    }
  } else {
    var af = []
    for(var i in flows) {
      af.push(i);
    }
    console.warn("Message dropped from unregistered flow " + app.id + " -> " + flow);
    console.log(message.msg);
  }
};

/**
 * Ensure than an application is enstantiated. and registered.
 * @param {String} id The URL identifying the app.
 */
fdom.Hub.prototype.ensureApp = function(id) {
  var canonicalId = makeAbsolute(id);
  if (!this.apps[canonicalId]) {
    var newApp = new fdom.app.External();
    newApp.configure(this.config);
    newApp.configure({
      manifest: canonicalId
    });
    this.apps[canonicalId] = newApp;
  }
  return canonicalId;
}

/**
 * Establish a communication channel between an application and one of its dependencies.
 * @param {fdom.app} app The application establishing communication.
 * @param {String} dep The identifier of the dependency.
 */
fdom.Hub.prototype.createPipe = function(app, dep) {
  // 1. Make sure source has permissions to create the pipe.
  if (!app.manifest['dependencies'].hasOwnProperty(dep)) {
    console.warn("Dependency requested that was undeclared in app manifest");
    return false;
  }

  // 2. Make sure the dependency exists.
  var depId = this.ensureApp(app.manifest['dependencies'][dep]);
  var depApp = this.apps[depId];

  // 3. Register the link
  this.pipes[app.id][dep] = depApp.getChannel('default');
  this.pipes[depId] = {'default': app.getChannel(dep)};
}

/**
 * Register an application with the hub.
 * @param {fdom.app} app The application to register.
 */
fdom.Hub.prototype.register = function(app) {
  if (!this.apps[app.id]) {
    this.apps[app.id] = app;
    this.pipes[app.id] = {'default' : app.channels['default']};
  }
  this['emit']('register', app);
}

/**
 * Register permissions of a freedom application.
 * @param String id The application for whom to register permissions.
 * @private
 */
fdom.Hub.prototype.permitAccess = function(id) {
  if (!this.apps[id]) {
    console.warn("Registration requested for unknown App " + id);
    return;
  }
  if (!this.apps[id].manifest['permissions']) {
    return;
  }
  for (var i = 0; i < this.apps[id].manifest['permissions'].length; i++) {
    var permission = this.apps[id].manifest['permissions'][i];
    if (permission.indexOf("core.") === 0) {
      this.pipes[id][permission] = fdom.apis.getCore(permission, this.apps[id].getChannel(permission));
    }
  }
}

/**
 * Bind an unbound app channel to a service implementing 'postMessage'.
 */
fdom.Hub.prototype.bindChannel = function(id, flow, service) {
  var dep = this.apps[id];
  var endpoint = false;
  for (var i = 0; i < this.unbound.length; i++) {
    if (this.unbound[i][0] == dep) {
      endpoint = this.unbound[i];
      this.unbound.splice(i, 1);
      break;
    }
  }
  if (endpoint) {
    if (this.pipes[endpoint[0].id][endpoint[1]]) {
      console.warn("unwilling to redefine existing pipes.");
    } else {
      if (this.debug("pipes")) {
        console.log("Custom channel bound: " + endpoint[1]);
      }
      this.pipes[endpoint[0].id][endpoint[1]] = service;
      return true;
    }
  }
  return false;
};

/**
 * Decide which messages to debug, if debugging enabled.
 */
fdom.Hub.prototype.debug = function(feature) {
  return this.config['debug'] === true || (this.config['debug'] !== false &&
      this.config['debug'].indexOf(feature) > -1);
}
<commit_msg>better debugging<commit_after>var fdom = fdom || {};

/**
 * Defines fdom.Hub, the core message hub between freedom modules.
 * Incomming messages from apps are sent to hub.onMessage()
 * Use fdom.Hub.get() for the singleton instance.
 * @private
 * @constructor
 */
fdom.Hub = function() {
  this.config = {};
  this.apps = {};
  this.pipes = {};
  this.unbound = [];
  handleEvents(this);
};

/**
 * Singleton accessor for fdom.Hub.
 * @returns {fdom.Hub} The singleton freedom hub interconnecting freedom modules.
 */
fdom.Hub.get = function() {
  if (!fdom.Hub._hub) {
    fdom.Hub._hub = new fdom.Hub();
  }
  window.hub = fdom.Hub._hub;
  return fdom.Hub._hub;
};

/**
 * Handle an incoming message from a freedom app.
 * @param {fdom.app} app The app sending the message.
 * @param {Object} message The sent message.
 */
fdom.Hub.prototype.onMessage = function(app, message) {
  if (!this.apps[app.id]) {
    console.warn("Message dropped from unregistered app " + app.id);
    return;
  }
  var flows = this.pipes[app.id];
  var flow = message.sourceFlow;
  var destChannel = flows[flow];

  if (flow == 'control') {
    if (this.debug("control") && message.request != 'debug') {
      console.log(app.id + " -C " + message.request);
    } else if (this.config['debug'] && message.request == 'debug') {
      console.log(app.id + " -D " + message.msg);
    }
    // Signaling Channel.
    if (message.request == 'dep') {
      this.createPipe(app, message.dep);
    } else if (message.request == 'create') {
      var config = {
        "debug": this.config['debug']
      };

      app.postMessage({
        sourceFlow: 'control',
        msg: {
          id: app.id,
          manifest: app.manifest,
          config: config
        }
      });
      this.permitAccess(app.id);
    } else if (message.request == 'ready') {
      app.ready();
    } else if (message.request == 'channel') {
      // Register new unprivileged message channel.
      var flow = 'custom' + Math.random();

      // Binding a channel.
      if (message.to) {
        var aid = message.to[0];
        var dep = this.apps[aid];
        var endpoint = false;
        for (var i = 0; i < this.unbound.length; i++) {
          if (this.unbound[i][0] == dep) {
            endpoint = this.unbound[i];
            this.unbound.splice(i, 1);
            break;
          }
        }
        if (endpoint) {
          var other = endpoint[0];
          if (this.pipes[app.id][flow] || this.pipes[other.id][endpoint[1]]) {
            console.warn("unwilling to redefine existing pipes.");
          } else {
            this.pipes[app.id][flow] = other.getChannel(endpoint[1]);
            this.pipes[other.id][endpoint[1]] = app.getChannel(flow);
          }
        }
      } else {
        // TODO: make sure apps can't make infinite unbound pipes.
        this.unbound.push([app, flow]);
      }

      app.postMessage({
        sourceFlow: 'control',
        msg: {
          flow: flow
        }
      });
    }
  } else if (destChannel) {
    if (this.debug("channels")) {
      console.log(app.id + " -> " + flow + " " + message.msg.action + " " + message.msg.type);
    }

    // Deliver Message
    if (destChannel == app.getChannel(flow)) {
      destChannel.onMessage(message.msg);
    } else {
      destChannel.postMessage(message.msg);
    }
  } else {
    var af = []
    for(var i in flows) {
      af.push(i);
    }
    console.warn("Message dropped from unregistered flow " + app.id + " -> " + flow);
    console.log(message.msg);
  }
};

/**
 * Ensure than an application is enstantiated. and registered.
 * @param {String} id The URL identifying the app.
 */
fdom.Hub.prototype.ensureApp = function(id) {
  var canonicalId = makeAbsolute(id);
  if (!this.apps[canonicalId]) {
    var newApp = new fdom.app.External();
    newApp.configure(this.config);
    newApp.configure({
      manifest: canonicalId
    });
    this.apps[canonicalId] = newApp;
  }
  return canonicalId;
}

/**
 * Establish a communication channel between an application and one of its dependencies.
 * @param {fdom.app} app The application establishing communication.
 * @param {String} dep The identifier of the dependency.
 */
fdom.Hub.prototype.createPipe = function(app, dep) {
  // 1. Make sure source has permissions to create the pipe.
  if (!app.manifest['dependencies'].hasOwnProperty(dep)) {
    console.warn("Dependency requested that was undeclared in app manifest");
    return false;
  }

  // 2. Make sure the dependency exists.
  var depId = this.ensureApp(app.manifest['dependencies'][dep]);
  var depApp = this.apps[depId];

  // 3. Register the link
  this.pipes[app.id][dep] = depApp.getChannel('default');
  this.pipes[depId] = {'default': app.getChannel(dep)};
}

/**
 * Register an application with the hub.
 * @param {fdom.app} app The application to register.
 */
fdom.Hub.prototype.register = function(app) {
  if (!this.apps[app.id]) {
    this.apps[app.id] = app;
    this.pipes[app.id] = {'default' : app.channels['default']};
  }
  this['emit']('register', app);
}

/**
 * Register permissions of a freedom application.
 * @param String id The application for whom to register permissions.
 * @private
 */
fdom.Hub.prototype.permitAccess = function(id) {
  if (!this.apps[id]) {
    console.warn("Registration requested for unknown App " + id);
    return;
  }
  if (!this.apps[id].manifest['permissions']) {
    return;
  }
  for (var i = 0; i < this.apps[id].manifest['permissions'].length; i++) {
    var permission = this.apps[id].manifest['permissions'][i];
    if (permission.indexOf("core.") === 0) {
      this.pipes[id][permission] = fdom.apis.getCore(permission, this.apps[id].getChannel(permission));
    }
  }
}

/**
 * Bind an unbound app channel to a service implementing 'postMessage'.
 */
fdom.Hub.prototype.bindChannel = function(id, flow, service) {
  var dep = this.apps[id];
  var endpoint = false;
  for (var i = 0; i < this.unbound.length; i++) {
    if (this.unbound[i][0] == dep) {
      endpoint = this.unbound[i];
      this.unbound.splice(i, 1);
      break;
    }
  }
  if (endpoint) {
    if (this.pipes[endpoint[0].id][endpoint[1]]) {
      console.warn("unwilling to redefine existing pipes.");
    } else {
      if (this.debug("pipes")) {
        console.log("Custom channel bound: " + endpoint[1]);
      }
      this.pipes[endpoint[0].id][endpoint[1]] = service;
      return true;
    }
  }
  return false;
};

/**
 * Decide which messages to debug, if debugging enabled.
 */
fdom.Hub.prototype.debug = function(feature) {
  return this.config['debug'] === true || (this.config['debug'] !== false &&
      this.config['debug'].indexOf(feature) > -1);
}
<|endoftext|>


<commit_before>import { c, set, create, struct } from 'brisky-struct'
import * as client from './client'
import * as server from './server'
import * as context from './context'

if (typeof window === 'undefined') {
  // dont do this gets added to client...
  require('source-map-support').install()
}

const types = struct.props.types

const hub = create({
  type: 'hub',
  instances: false,
  define: { isHub: true },
  props: {
    default: 'self',
    clients: (t, val, key, stamp) => {
      if (!t.clients) {
        t.clients = c(clients, val, stamp, t, key)
      } else {
        set(t.clients, val, stamp)
      }
    },
    types: types.bind(), // to not interfere with struct type
    type: struct.props.type.bind(),
    client: true
  }
})

hub.props.types.struct = c(hub, {
  props: { default: types.struct.props.default.bind() }
})

hub.props.types.struct.props.default.struct = hub.props.type.struct = hub

hub.set({ types: { hub: 'self' }, inject: [ server, context, client ] }, false)

hub.types._ks = void 0

const clients = create({
  props: {
    default: c(hub, {
      props: {
        cache: true,
        upstreamSubscriptions: true,
        resolve: true,
        socket: true,
        context: true
      }
    })
  }
}, false)

export default hub
<commit_msg>added _uid_<commit_after>import { c, set, create, struct } from 'brisky-struct'
import * as client from './client'
import * as server from './server'
import * as context from './context'

if (typeof window === 'undefined') {
  // dont do this gets added to client...
  require('source-map-support').install()
}

const types = struct.props.types

const hub = create({
  type: 'hub',
  instances: false,
  define: { isHub: true },
  props: {
    default: 'self',
    _uid_: (t, val) => { t.set({ define: { _uid_: val } }) },
    clients: (t, val, key, stamp) => {
      if (!t.clients) {
        t.clients = c(clients, val, stamp, t, key)
      } else {
        set(t.clients, val, stamp)
      }
    },
    types: types.bind(), // to not interfere with struct type
    type: struct.props.type.bind(),
    client: true
  }
})

hub.props.types.struct = c(hub, {
  props: { default: types.struct.props.default.bind() }
})

hub.props.types.struct.props.default.struct = hub.props.type.struct = hub

hub.set({ types: { hub: 'self' }, inject: [ server, context, client ] }, false)

hub.types._ks = void 0

const clients = create({
  props: {
    default: c(hub, {
      props: {
        cache: true,
        upstreamSubscriptions: true,
        resolve: true,
        socket: true,
        context: true
      }
    })
  }
}, false)

export default hub
<|endoftext|>


<commit_before>'use strict';

var bcrypt = require('bcrypt-nodejs'),
    Server = require('socket.io'),
    express = require('express'),
    http = require('http'),
    path = require('path'),
    mongo = require('mongojs');

var util = require('util');
var session = require('./session');
var _ = require('lodash');
var cors = require('cors');
var shortid = require('shortid');

var _validTokens = {};

function getDateForLog() {
    return new Date();
}

function throwErr (func) {
    return function(err, data) {
        if (err) {
            throw err;
        } else {
            func.call(null, data);
        }
    };
}

function validateScene (sceneData) {
    // convert _id so mongo recognizes it
    if (sceneData.hasOwnProperty('_id')) {
        sceneData._id = mongo.ObjectId(sceneData._id);
    }

    // add _ids to all mediaObjects
    if (sceneData.hasOwnProperty('scene')) {
        if (! Array.isArray(sceneData.scene) ) {
            throw new Error('"scene" property must be an array of objects');
        } else {
            sceneData.scene.forEach(function(mediaObject) {
                if (! mediaObject.hasOwnProperty('_id')) {
                    mediaObject._id = mongo.ObjectId();
                }
            });
        }
    }

    return sceneData;
}

function validateSceneGraph (sceneGraphData) {
    //convert _id so mongo recognizes it
    if (sceneGraphData.hasOwnProperty('_id')) {
        sceneGraphData._id = mongo.ObjectId(sceneGraphData._id);
    }

    //TODO most likely more detailed validation can occur

    return sceneGraphData;
}

function addApiCalls (hub, io, socket) {
    function idSearch (id) {
        return {_id: mongo.ObjectId(id)};
    }

    function _findScene (sceneId, cb) {

        console.log(getDateForLog() + " - hub.js - _findScene");

        return hub.db.mediaScenes.findOne(idSearch(sceneId), cb);
    }

    function _findSceneGraph(sceneGraphId, cb) {

        console.log(getDateForLog() + " - hub.js - _findSceneGraph");

        return hub.db.mediaSceneGraphs.findOne(idSearch(sceneGraphId), cb);
    }

    socket.on('listScenes', function(callback) {

        console.log(getDateForLog() + " - hub.js - listScenes groupID: " + socket.groupID);

        //AJF: if the groupID is 0 (admin) then list all scenes
        if(socket.groupID == 0)
            hub.db.mediaScenes.find({'$query': {}, '$orderby': {name: 1}}, {name: 1, _groupID: 2}, callback);
        else
        {
            hub.db.mediaScenes.find({'$query': {_groupID: socket.groupID}, '$orderby': {name: 1}}, {name: 1, _groupID: 2}, callback);
        }

    });

    socket.on('listSceneGraphs', function(callback) {
        console.log(getDateForLog() + " - hub.js - listSceneGraphs");
        hub.db.mediaSceneGraphs.find({'$query': {}}, callback);

    });

    socket.on('saveScene', function(sceneData, callback) {
        console.log(getDateForLog() + " - hub.js - listSceneGraphs");

        try {
            var data = validateScene(sceneData);

            console.log(getDateForLog() + " - hub.js - saveScene after validation: ", data);

			//AJF: sanity check to stop client side CTRL+Z bug blank scene reaching the db
			if(data.hasOwnProperty('themes') || data.hasOwnProperty('style') || data.hasOwnProperty('scene'))
			{
				console.log("Valid");

            //AJF: save the groupID acquired from the socket if the groupID isn't already set
            console.log(getDateForLog() + " - hub.js - saveScene data._groupID: " + data._groupID);

            if(!data._groupID) {
                console.log(getDateForLog() + " - hub.js - saveScene data._groupID not set so setting to: " + socket.groupID);
                data._groupID = socket.groupID;
            }

            hub.db.mediaScenes.save(data, function(err, scene) {
                io.to(scene._id.toString()).emit('sceneUpdate', scene);

                if (callback) {
                    callback(err, scene);
                }
            });
			}
        } catch(err) {
            if (callback) {
                callback(err.message);
            }
        }
    });

    socket.on('saveSceneGraph', function(sceneGraphData, callback) {
        try {
            console.log(getDateForLog() + " - hub.js - saveSceneGraph");

            var data = validateSceneGraph(sceneGraphData);

            hub.db.mediaSceneGraphs.save(data, function(err, sceneGraph) {
                io.to(sceneGraph._id.toString()).emit('sceneGraphUpdate', sceneGraph);

                if (callback) {
                    callback(err, sceneGraph);
                }
            });

        } catch(err) {
            if(callback) {
                callback(err.message);
            }
        }
    });

    socket.on('loadScene', _findScene);

    socket.on('loadSceneGraph', _findSceneGraph);

    socket.on('loadSceneByName', function(name, callback) {

        console.log(getDateForLog() + " - hub.js - loadSceneByName");

        hub.db.mediaScenes.findOne({name: name}, callback);
    });

    socket.on('deleteScene', function(sceneId, callback) {

        console.log(getDateForLog() + " - hub.js - deleteScene");

        hub.db.mediaScenes.remove(idSearch(sceneId), function(err) {
            if (callback) {
                callback(err);
            }
        });
    });

    socket.on('deleteSceneGraph', function(sceneGraphId, callback){

        console.log(getDateForLog() + " - hub.js - deleteSceneGraph");

        hub.db.mediaSceneGraphs.remove(idSearch(sceneGraphId), function(err){
            if(callback) {
                callback(err);
            }
        });
    });

    socket.on('subScene', function(sceneId, callback) {

        console.log(getDateForLog() + " - hub.js - subScene");

        _findScene(sceneId, function(err, scene) {
            socket.join(sceneId);

            if (callback) {
                callback(err, scene);
            }
        });
    });

    socket.on('unsubScene', function(sceneId, callback) {

        console.log(getDateForLog() + " - hub.js - unsubScene");

        _findScene(sceneId, function(err, scene) {
            socket.leave(sceneId);
            if (callback) {
                callback(err);
            }
        });
    });

    socket.on('sendCommand', function(roomId, commandName, commandValue) {

        console.log(getDateForLog() + " - hub.js - sendCommand: ", {
            roomId: roomId,
            commandName: commandName,
            commandValue: commandValue
        });

        io.to(roomId).emit('command', {name: commandName, value: commandValue});
    });

    socket.on('register', function(roomId) {

        roomId = roomId.replace("/#", "");

        console.log(getDateForLog() + " - hub.js - REGISTER TO ROOM: ", roomId);

        socket.join(roomId);
    });
}

var Hub = function(config) {
    this.config = config;
    this.db = mongo.connect(config.mongo, ['mediaScenes', 'sessions', 'mediaSceneGraphs']);
    session.setClient(this.db);
};

Hub.prototype.listen = function(callback) {
    var self = this,
        app = express(),
        server = http.Server(app),
        io = new Server(server);

    this.server = server;

    app.use(cors());

    // require a valid session token for all api calls
    var validateSession =  function(req, res, next) {
        session.find(req.query.token, function(err, data) {
            if (err || ! data) {
                res.sendStatus(401);
            } else {
                next();
            }
        });
    };

    // allow cross origin requests
    io.set('origins', '*:*');
    io.sockets.on('connection', function (socket) {
        var disconnectTimer = setTimeout(function() {
            socket.disconnect();
        }, 10000);

        socket.on('auth', function (creds, callback) {

            function succeed (record) {

                //AJF: set the groupID on the socket to be used in further local calls

                //AJF: set the groupID on the socket to be used in further calls

                socket.groupID = record._groupID;
                addApiCalls(self, io, socket);
                clearTimeout(disconnectTimer);
                var roomId = shortid.generate(); // APEP: generate a user friendly shortid for roomID for graph and player to communicate

                console.log("auth - suceed - callback:", callback);
                // APEP logging and test if callback exists - used due to error in android platform
                if(callback)
                    callback(null, record._id.toString(), roomId, record._groupID.toString());//AJF: try to return the groupID...
            }

            function fail (msg) {
                callback(msg);
                socket.disconnect();
            }

            if (creds.hasOwnProperty('password') && creds.password && creds.password !== '') {
                //AJF: Compares the passwords and determines what group the user logging into belongs to
                if ( bcrypt.compareSync(creds.password, self.config.secret) ) {
                    session.create(0, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_1)) {
                    session.create(1, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_2)) {
                    session.create(2, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_101)) {
                    session.create(101, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_102)) {
                    session.create(102, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_103)) {
                    session.create(103, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_104)) {
                    session.create(104, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_105)) {
                    session.create(105, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_106)) {
                    session.create(106, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_107)) {
                    session.create(107, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_108)) {
                    session.create(108, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_109)) {
                    session.create(109, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_110)) {
                    session.create(110, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_111)) {
                    session.create(111, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_112)) {
                    session.create(112, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_113)) {
                    session.create(113, throwErr(succeed));
                } else {
                    fail('Invalid Password');
                }

            } else if (creds.hasOwnProperty('token') && creds.token && creds.token !== '') {
                console.log("Finding session via token");
                session.find(creds.token, function(err, data) {
                        if (data) {
                            succeed(data);
                        } else {
                            fail('Invalid Token');
                        }
                    });
            } else {
                fail('Password must be provided');
            }
        });

    });

    server.listen(self.config.port, callback);
};

Hub.prototype.close = function(cb) {
    this.server.close(cb);
};

module.exports = {
    createHub: function(mongoUrl) {
        return new Hub(mongoUrl);
    }
};
<commit_msg>Testing of android specific web socket<commit_after>'use strict';

var bcrypt = require('bcrypt-nodejs'),
    Server = require('socket.io'),
    express = require('express'),
    http = require('http'),
    path = require('path'),
    mongo = require('mongojs');

var util = require('util');
var session = require('./session');
var _ = require('lodash');
var cors = require('cors');
var shortid = require('shortid');

var _validTokens = {};

function getDateForLog() {
    return new Date();
}

function throwErr (func) {
    return function(err, data) {
        if (err) {
            throw err;
        } else {
            func.call(null, data);
        }
    };
}

function validateScene (sceneData) {
    // convert _id so mongo recognizes it
    if (sceneData.hasOwnProperty('_id')) {
        sceneData._id = mongo.ObjectId(sceneData._id);
    }

    // add _ids to all mediaObjects
    if (sceneData.hasOwnProperty('scene')) {
        if (! Array.isArray(sceneData.scene) ) {
            throw new Error('"scene" property must be an array of objects');
        } else {
            sceneData.scene.forEach(function(mediaObject) {
                if (! mediaObject.hasOwnProperty('_id')) {
                    mediaObject._id = mongo.ObjectId();
                }
            });
        }
    }

    return sceneData;
}

function validateSceneGraph (sceneGraphData) {
    //convert _id so mongo recognizes it
    if (sceneGraphData.hasOwnProperty('_id')) {
        sceneGraphData._id = mongo.ObjectId(sceneGraphData._id);
    }

    //TODO most likely more detailed validation can occur

    return sceneGraphData;
}

function addApiCalls (hub, io, socket) {
    function idSearch (id) {
        return {_id: mongo.ObjectId(id)};
    }

    function _findScene (sceneId, cb) {

        console.log(getDateForLog() + " - hub.js - _findScene");

        return hub.db.mediaScenes.findOne(idSearch(sceneId), cb);
    }

    function _findSceneGraph(sceneGraphId, cb) {

        console.log(getDateForLog() + " - hub.js - _findSceneGraph");

        return hub.db.mediaSceneGraphs.findOne(idSearch(sceneGraphId), cb);
    }

    socket.on('listScenes', function(callback) {

        console.log(getDateForLog() + " - hub.js - listScenes groupID: " + socket.groupID);

        //AJF: if the groupID is 0 (admin) then list all scenes
        if(socket.groupID == 0)
            hub.db.mediaScenes.find({'$query': {}, '$orderby': {name: 1}}, {name: 1, _groupID: 2}, callback);
        else
        {
            hub.db.mediaScenes.find({'$query': {_groupID: socket.groupID}, '$orderby': {name: 1}}, {name: 1, _groupID: 2}, callback);
        }

    });

    socket.on('listSceneGraphs', function(callback) {
        console.log(getDateForLog() + " - hub.js - listSceneGraphs");
        hub.db.mediaSceneGraphs.find({'$query': {}}, callback);

    });

    socket.on('saveScene', function(sceneData, callback) {
        console.log(getDateForLog() + " - hub.js - listSceneGraphs");

        try {
            var data = validateScene(sceneData);

            console.log(getDateForLog() + " - hub.js - saveScene after validation: ", data);

			//AJF: sanity check to stop client side CTRL+Z bug blank scene reaching the db
			if(data.hasOwnProperty('themes') || data.hasOwnProperty('style') || data.hasOwnProperty('scene'))
			{
				console.log("Valid");

            //AJF: save the groupID acquired from the socket if the groupID isn't already set
            console.log(getDateForLog() + " - hub.js - saveScene data._groupID: " + data._groupID);

            if(!data._groupID) {
                console.log(getDateForLog() + " - hub.js - saveScene data._groupID not set so setting to: " + socket.groupID);
                data._groupID = socket.groupID;
            }

            hub.db.mediaScenes.save(data, function(err, scene) {
                io.to(scene._id.toString()).emit('sceneUpdate', scene);

                if (callback) {
                    callback(err, scene);
                }
            });
			}
        } catch(err) {
            if (callback) {
                callback(err.message);
            }
        }
    });

    socket.on('saveSceneGraph', function(sceneGraphData, callback) {
        try {
            console.log(getDateForLog() + " - hub.js - saveSceneGraph");

            var data = validateSceneGraph(sceneGraphData);

            hub.db.mediaSceneGraphs.save(data, function(err, sceneGraph) {
                io.to(sceneGraph._id.toString()).emit('sceneGraphUpdate', sceneGraph);

                if (callback) {
                    callback(err, sceneGraph);
                }
            });

        } catch(err) {
            if(callback) {
                callback(err.message);
            }
        }
    });

    socket.on('loadScene', _findScene);

    socket.on('loadSceneGraph', _findSceneGraph);

    socket.on('loadSceneByName', function(name, callback) {

        console.log(getDateForLog() + " - hub.js - loadSceneByName");

        hub.db.mediaScenes.findOne({name: name}, callback);
    });

    socket.on('deleteScene', function(sceneId, callback) {

        console.log(getDateForLog() + " - hub.js - deleteScene");

        hub.db.mediaScenes.remove(idSearch(sceneId), function(err) {
            if (callback) {
                callback(err);
            }
        });
    });

    socket.on('deleteSceneGraph', function(sceneGraphId, callback){

        console.log(getDateForLog() + " - hub.js - deleteSceneGraph");

        hub.db.mediaSceneGraphs.remove(idSearch(sceneGraphId), function(err){
            if(callback) {
                callback(err);
            }
        });
    });

    socket.on('subScene', function(sceneId, callback) {

        console.log(getDateForLog() + " - hub.js - subScene");

        _findScene(sceneId, function(err, scene) {
            socket.join(sceneId);

            if (callback) {
                callback(err, scene);
            }
        });
    });

    socket.on('unsubScene', function(sceneId, callback) {

        console.log(getDateForLog() + " - hub.js - unsubScene");

        _findScene(sceneId, function(err, scene) {
            socket.leave(sceneId);
            if (callback) {
                callback(err);
            }
        });
    });

    socket.on('sendCommand', function(roomId, commandName, commandValue) {

        console.log(getDateForLog() + " - hub.js - sendCommand: ", {
            roomId: roomId,
            commandName: commandName,
            commandValue: commandValue
        });

        io.to(roomId).emit('command', {name: commandName, value: commandValue});
    });

    socket.on('register', function(roomId) {

        roomId = roomId.replace("/#", "");

        console.log(getDateForLog() + " - hub.js - REGISTER TO ROOM: ", roomId);

        socket.join(roomId);
    });
}

var Hub = function(config) {
    this.config = config;
    this.db = mongo.connect(config.mongo, ['mediaScenes', 'sessions', 'mediaSceneGraphs']);
    session.setClient(this.db);
};

Hub.prototype.listen = function(callback) {
    var self = this,
        app = express(),
        server = http.Server(app),
        io = new Server(server);

    this.server = server;

    app.use(cors());

    // require a valid session token for all api calls
    var validateSession =  function(req, res, next) {
        session.find(req.query.token, function(err, data) {
            if (err || ! data) {
                res.sendStatus(401);
            } else {
                next();
            }
        });
    };

    // allow cross origin requests
    io.set('origins', '*:*');
    io.sockets.on('connection', function (socket) {
        var disconnectTimer = setTimeout(function() {
            socket.disconnect();
        }, 10000);

        socket.on('a-auth', function (creds, args, callback) {

            console.log("a-auth - args: ", args);
            console.log("a-auth - callback: ", callback);

            function succeed (record) {

                //AJF: set the groupID on the socket to be used in further local calls

                //AJF: set the groupID on the socket to be used in further calls

                socket.groupID = record._groupID;
                addApiCalls(self, io, socket);
                clearTimeout(disconnectTimer);
                var roomId = shortid.generate(); // APEP: generate a user friendly shortid for roomID for graph and player to communicate

                console.log("auth - suceed - callback:", callback);
                // APEP logging and test if callback exists - used due to error in android platform
                if(callback)
                    callback(null, record._id.toString(), roomId, record._groupID.toString());//AJF: try to return the groupID...
            }

            function fail (msg) {
                callback(msg);
                socket.disconnect();
            }

            if (creds.hasOwnProperty('password') && creds.password && creds.password !== '') {
                //AJF: Compares the passwords and determines what group the user logging into belongs to
                if ( bcrypt.compareSync(creds.password, self.config.secret) ) {
                    session.create(0, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_1)) {
                    session.create(1, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_2)) {
                    session.create(2, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_101)) {
                    session.create(101, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_102)) {
                    session.create(102, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_103)) {
                    session.create(103, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_104)) {
                    session.create(104, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_105)) {
                    session.create(105, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_106)) {
                    session.create(106, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_107)) {
                    session.create(107, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_108)) {
                    session.create(108, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_109)) {
                    session.create(109, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_110)) {
                    session.create(110, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_111)) {
                    session.create(111, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_112)) {
                    session.create(112, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_113)) {
                    session.create(113, throwErr(succeed));
                } else {
                    fail('Invalid Password');
                }

            } else if (creds.hasOwnProperty('token') && creds.token && creds.token !== '') {
                console.log("Finding session via token");
                session.find(creds.token, function(err, data) {
                        if (data) {
                            succeed(data);
                        } else {
                            fail('Invalid Token');
                        }
                    });
            } else {
                fail('Password must be provided');
            }
        });

    })

        socket.on('auth', function (creds, callback) {

            function succeed (record) {

                //AJF: set the groupID on the socket to be used in further local calls

                //AJF: set the groupID on the socket to be used in further calls

                socket.groupID = record._groupID;
                addApiCalls(self, io, socket);
                clearTimeout(disconnectTimer);
                var roomId = shortid.generate(); // APEP: generate a user friendly shortid for roomID for graph and player to communicate

                console.log("auth - suceed - callback:", callback);
                // APEP logging and test if callback exists - used due to error in android platform
                if(callback)
                    callback(null, record._id.toString(), roomId, record._groupID.toString());//AJF: try to return the groupID...
            }

            function fail (msg) {
                callback(msg);
                socket.disconnect();
            }

            if (creds.hasOwnProperty('password') && creds.password && creds.password !== '') {
                //AJF: Compares the passwords and determines what group the user logging into belongs to
                if ( bcrypt.compareSync(creds.password, self.config.secret) ) {
                    session.create(0, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_1)) {
                    session.create(1, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_2)) {
                    session.create(2, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_101)) {
                    session.create(101, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_102)) {
                    session.create(102, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_103)) {
                    session.create(103, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_104)) {
                    session.create(104, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_105)) {
                    session.create(105, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_106)) {
                    session.create(106, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_107)) {
                    session.create(107, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_108)) {
                    session.create(108, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_109)) {
                    session.create(109, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_110)) {
                    session.create(110, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_111)) {
                    session.create(111, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_112)) {
                    session.create(112, throwErr(succeed));
                } else if (bcrypt.compareSync(creds.password, self.config.secret_113)) {
                    session.create(113, throwErr(succeed));
                } else {
                    fail('Invalid Password');
                }

            } else if (creds.hasOwnProperty('token') && creds.token && creds.token !== '') {
                console.log("Finding session via token");
                session.find(creds.token, function(err, data) {
                        if (data) {
                            succeed(data);
                        } else {
                            fail('Invalid Token');
                        }
                    });
            } else {
                fail('Password must be provided');
            }
        });

    });

    server.listen(self.config.port, callback);
};

Hub.prototype.close = function(cb) {
    this.server.close(cb);
};

module.exports = {
    createHub: function(mongoUrl) {
        return new Hub(mongoUrl);
    }
};
<|endoftext|>


<commit_before>/*jslint node: true, nomen: true, white: true, forin: true*/
'use strict';

var async = require('async')
  , common = require('./common')
  ;

var unwriteable = common.unwriteable
  , unseeable = common.unseeable
  , hidden = common.hidden
  , makeNano = common.makeNano
  ;

module.exports.forInstance = function(instance) {
  return function(dest) {
    var db
      , to = {}
      ;

    to.save = function(cb) {
      var state = {}
        , p
        , schema = instance.$schema
        , hasCreatedOn = schema.properties.hasOwnProperty('createdOn')
        , createdOnIsUndefined = instance.createdOn === undefined
        , refProperties = schema.refProperties
        , childProperties = schema.childProperties
        ;

      for (p in instance) {
        if (refProperties.indexOf(p) > -1) {
          state['$' + p + 'Id'] = instance[p]._id;
        } else if (childProperties.indexOf(p) === -1 && typeof instance[p] !== 'function') {
          state[p] = instance[p];
        }
      }
      state = JSON.parse(JSON.stringify(state));
      if (instance._rev) {
        state._rev = instance._rev;
      }
      if (instance._id) {
        state._id = instance._id;
      }
      if (hasCreatedOn && createdOnIsUndefined) {
        instance.createdOn = new Date();
      }
      if (instance.$schema.properties.hasOwnProperty('updatedOn')) {
        instance.updatedOn = new Date();
      }
      db.insert(state, function(err, result) {
        var childUpdates
          ;

        if (err) {
          return cb(err);
        }
        unwriteable(instance, '_id', result.id);
        hidden(instance, '_rev', result.rev);

        if (childProperties.length > 0) {
          childUpdates = [];
          childProperties.forEach(function(property) {
            var children = instance[property] || []
              , childProperty = '$' + instance.kind + '_' + property + '_id'
              ;
            children.forEach(function(child) {
              var childTo = child.to(db)
                ;
              if (child[childProperty] !== result.id) {
                child[childProperty] = result.id;
                childUpdates.push(childTo.save.bind(childTo));
              }
            });
          });
          async.parallel(childUpdates, function(err) {
            cb(err, instance);
          });
        } else {
          cb(err, instance);
        }
      });
    };

    db = makeNano(dest, 'instance#to must be a couchdb url or nano db');
    unseeable(to, 'db', db);
    return to;
  };
};
<commit_msg>Destroy an instance.<commit_after>/*jslint node: true, nomen: true, white: true, forin: true*/
'use strict';

var async = require('async')
  , common = require('./common')
  ;

var unwriteable = common.unwriteable
  , unseeable = common.unseeable
  , hidden = common.hidden
  , makeNano = common.makeNano
  ;

module.exports.forInstance = function(instance) {
  return function(dest) {
    var db
      , to = {}
      ;

    to.destroy = function (cb) {
    	db.destroy(instance._id, instance._rev, cb);
    };

    to.save = function(cb) {
      var state = {}
        , p
        , schema = instance.$schema
        , hasCreatedOn = schema.properties.hasOwnProperty('createdOn')
        , createdOnIsUndefined = instance.createdOn === undefined
        , refProperties = schema.refProperties
        , childProperties = schema.childProperties
        ;

      for (p in instance) {
        if (refProperties.indexOf(p) > -1) {
          state['$' + p + 'Id'] = instance[p]._id;
        } else if (childProperties.indexOf(p) === -1 && typeof instance[p] !== 'function') {
          state[p] = instance[p];
        }
      }
      state = JSON.parse(JSON.stringify(state));
      if (instance._rev) {
        state._rev = instance._rev;
      }
      if (instance._id) {
        state._id = instance._id;
      }
      if (hasCreatedOn && createdOnIsUndefined) {
        instance.createdOn = new Date();
      }
      if (instance.$schema.properties.hasOwnProperty('updatedOn')) {
        instance.updatedOn = new Date();
      }
      db.insert(state, function(err, result) {
        var childUpdates
          ;

        if (err) {
          return cb(err);
        }
        unwriteable(instance, '_id', result.id);
        hidden(instance, '_rev', result.rev);

        if (childProperties.length > 0) {
          childUpdates = [];
          childProperties.forEach(function(property) {
            var children = instance[property] || []
              , childProperty = '$' + instance.kind + '_' + property + '_id'
              ;
            children.forEach(function(child) {
              var childTo = child.to(db)
                ;
              if (child[childProperty] !== result.id) {
                child[childProperty] = result.id;
                childUpdates.push(childTo.save.bind(childTo));
              }
            });
          });
          async.parallel(childUpdates, function(err) {
            cb(err, instance);
          });
        } else {
          cb(err, instance);
        }
      });
    };

    db = makeNano(dest, 'instance#to must be a couchdb url or nano db');
    unseeable(to, 'db', db);
    return to;
  };
};
<|endoftext|>


<commit_before>/* jslint node: true, esnext: true */
"use strict";

const Interceptor = require('kronos-interceptor').Interceptor;
const parserFactory = require('./line-parser');

/**
 * This interceptor cares about the handling of the messages.
 * It will add the hops and copies the messages
 */
class LineParserInterceptor extends Interceptor {

	constructor(endpoint, config) {
		super(endpoint, config);

		this.streamFilter = parserFactory(config, true);
	}

	static get type() {
		return "line-parser";
	}

	get type() {
		return LineParserInterceptor.type;
	}

	receive(request, oldRequest) {
		if (request.payload) {
			const stream = request.payload;
			request.payload = stream.pipe(this.streamFilter);
		}
		return this.connected.receive(request, oldRequest);
	}
}

exports.Interceptor = LineParserInterceptor;
<commit_msg>fix(process): The stream filter needs to be created per request.<commit_after>/* jslint node: true, esnext: true */
"use strict";

const Interceptor = require('kronos-interceptor').Interceptor;
const parserFactory = require('./line-parser');

/**
 * This interceptor cares about the handling of the messages.
 * It will add the hops and copies the messages
 */
class LineParserInterceptor extends Interceptor {

	constructor(endpoint, config) {
		super(endpoint, config);
	}

	static get type() {
		return "line-parser";
	}

	get type() {
		return LineParserInterceptor.type;
	}

	receive(request, oldRequest) {
		if (request.payload) {
			const streamFilter = parserFactory(this.config, true);
			const stream = request.payload;
			request.payload = stream.pipe(streamFilter);
		}
		return this.connected.receive(request, oldRequest);
	}
}

exports.Interceptor = LineParserInterceptor;
<|endoftext|>


<commit_before>/* jslint node: true, esnext: true */
"use strict";

// The mixin contains the base methods for endpoints and mixins
const connectorMixin = require('./connector-mixin').connectorMixin;

class _DummyInterceptor {}

/**
 * Base interceptor. The base class for all the interceptors
 */
class Interceptor extends connectorMixin(_DummyInterceptor) {

  /**
   * The type under which the interceptor will be registered.
   */
  static get name() {
    return "none";
  }

  /**
   * The instance method returning the type
   */
  get type() {
    return Interceptor.name;
  }

  /**
   * Creates a new interceptor
   * @param endpoint {object} the endpoint object this interceptor will be attached to.
   * @param config {object} The interceptor configuration object.
   */
  constructor(config, endpoint) {
    super();

    const props = {
      endpoint: {
        value: endpoint
      },
      logger: {
        value: endpoint.step
      },
      config: {
        value: config
      }
    };

    Object.defineProperties(this, props);
  }

  toString() {
    return `${this.endpoint}[${this.type}]`;
  }

  toJSON() {
    return {
      type: this.type
    };
  }

  /**
   * forget all accumulated information
   */
  reset() {}

  /**
   * The receive method. This method receives the request from the leading interceptor and calls the
   * trailing interceptor
   * @param request {object} the request from the leading interceptor
   * @param oldRequest {object} the oldRequest from the leading interceptor.
   *        This is a special case. As some interceptors are in charge of copying and creating the
   *        request objects, the step will call the interceptor chain with the both requests.
   *        At some point of the interceptor chain only the request itself will survive.
   *        But all intercptors designed to be inserted early in the interceptor chain of a sending
   *        endpoint should pass both requests to the next interceptor.
   */
  receive(request, oldRequest) {
    // This is a dummy implementation. Must be overwritten by the derived object.
    return this.connected.receive(request, oldRequest);
  }
}

module.exports.Interceptor = Interceptor;
<commit_msg>feat: trigger<commit_after>/* jslint node: true, esnext: true */
"use strict";

// The mixin contains the base methods for endpoints and mixins
const connectorMixin = require('./connector-mixin').connectorMixin;

class _DummyInterceptor {}

/**
 * Base interceptor. The base class for all the interceptors
 */
class Interceptor extends connectorMixin(_DummyInterceptor) {

  /**
   * The type under which the interceptor will be registered.
   */
  static get name() {
    return "none";
  }

  /**
   * The instance method returning the type
   */
  get type() {
    return Interceptor.name;
  }

  /**
   * Creates a new interceptor
   * @param endpoint {object} the endpoint object this interceptor will be attached to.
   * @param config {object} The interceptor configuration object.
   */
  constructor(config, endpoint) {
    super();

    const props = {
      endpoint: {
        value: endpoint
      },
      logger: {
        value: endpoint.step
      },
      config: {
        value: config
      }
    };

    Object.defineProperties(this, props);
  }

  toString() {
    return `${this.endpoint}[${this.type}]`;
  }

  /**
   * Deliver the json representation
   * @return {Object} json representation
   */
  toJSON() {
    return {
      type: this.type
    };
  }

  /**
   * forget all accumulated information
   */
  reset() {}

  /**
   * The receive method. This method receives the request from the leading interceptor and calls the
   * trailing interceptor
   * @param request {object} the request from the leading interceptor
   * @param oldRequest {object} the oldRequest from the leading interceptor.
   *        This is a special case. As some interceptors are in charge of copying and creating the
   *        request objects, the step will call the interceptor chain with the both requests.
   *        At some point of the interceptor chain only the request itself will survive.
   *        But all intercptors designed to be inserted early in the interceptor chain of a sending
   *        endpoint should pass both requests to the next interceptor.
   */
  receive(request, oldRequest) {
    // This is a dummy implementation. Must be overwritten by the derived object.
    return this.connected.receive(request, oldRequest);
  }
}

module.exports.Interceptor = Interceptor;
<|endoftext|>


<commit_before>const _ = require('lodash');
const program = require('commander');
const Avrgirl = require('avrgirl-arduino');
const Serialport = require('serialport');
const child_process = require('child_process');
const colors = require('colors');
const Download= require('download');
const fs      = require('fs');
const fsextra = require('fs-extra');
const http    = require('http');
const path    = require('path');
const tmp     = require('tmp');

const creators = require('./firmwares.json').creators;
const firmwares = require('./firmwares.json').firmwares;
const interchange_client = require('./interchange_client');
const Downloader = require('./downloader');
const ic_client = new interchange_client.Client();
const version = require('../package.json').version;

let fw = null; // used to hold details of the firmware we want in it.

const Interchange = function() {
  this.firmwares = firmwares;
};

Interchange.prototype.clean_temp_dir = function(tmpdir) {
  // takes a temporary directory and cleans up any files within it and
  // then calls the callback to remove itself.
  if (tmpdir != undefined && tmpdir !== null && tmpdir !== '') {
    fsextra.removeSync(tmpdir.name);
    tmpdir.removeCallback();
  }
};

Interchange.prototype.list_devices = function() {
  // this method returns the list of available firmwares as a JSON object

  const fws = [];
  firmwares.forEach((firmware) => {
    fws.push({
      name: firmware.name,
      firmata: (firmware.firmata ? true : false),
      description: firmware.description
    });
  });

  return (fws);
};

Interchange.prototype.get_ports = function(cb) {
  return new Promise((resolve, reject) => {
    Serialport.list()
      .then((ports) => {
        resolve(ports);
      })
      .catch((err) => {
        reject(err);
      });
  });
};

Interchange.prototype.list_ports = function() {
  // this function lists out all the ports available to flash firmware
  // this function  is now deprecated
  console.warn('list_ports method deprecated - use get_ports instead');
  return this.get_ports();
};

Interchange.prototype.get_firmware_info = function(port) {
  // attempts to connect to an interchange firmware and get the
  // installed details.

  if (!port) {
    console.error('Please provide a device path'.red);
    return;
  }

  ic_client.port = port;

  ic_client.on('error', function(err) {
    console.error(err);
    return err;
  });
  ic_client.on('ready', function() {
    this.get_info(function(err, data) {
      // json is returned
      if (err) {
        this.close();
        throw err;
      }

      // look up the details from the various resources
      fw_details = _.find(firmwares, function(f) {
        return ((parseInt(f.creatorID, 16) == data.creatorID) &&
                        (parseInt(f.firmwareID, 16) == data.firmwareID));
      });
      const creator = _.find(creators, {id: fw_details.creatorID});

      // print everything out.
      console.info((fw_details.name + ' backpack firmware').bold);
      console.info('Version %s Built %s', data.fw_version, data.compile_date);
      console.info('Creator ID: %s (%s @%s)', fw_details.creatorID, creator.name, creator.gh);
      console.info('Device ID: %s (%s)', fw_details.firmwareID, fw_details.name);
      console.info('I2C Address: 0x%s (%s)', data.i2c_address.toString(16),
        data.use_custom_addr ? 'Using custom' : 'Using default');
      console.info(fw_details.description);

      // close it up.
      this.close();
    }.bind(this));
  })
};

Interchange.prototype.install_firmware = function(firmware, opts = {}) {
  if (!firmware) {
    throw new Error('Please supply a firmware to install');
  }

  const settings = {
    board: opts.board || process.env.INTERCHANGE_BOARD || 'nano',
    port: opts.port || process.env.INTERCHANGE_PORT,
    firmata: opts.firmata,
    i2c_address: opts.address
  };

  // check firmware
  // download firmware
  // flash firmware to device
  // optionally do interchange client things if needed

  try {
    this.check_firmware(firmware, settings, function(hex_path, tmp_dir, options) {
      this.flash_firmware(hex_path, tmp_dir, options, function() {
        // once complete destory the tmp_dir.
        console.log('flash completed', tmp_dir);
        if (tmp_dir) {
          console.log('about to clean up');
          this.clean_temp_dir(tmp_dir);
        }
      }.bind(this));
    }.bind(this));
  } catch (e) {
    console.error(e);
    return;
  }
};

Interchange.prototype.set_firmware_details = function(port, opts, cb) {
  // sets the firmware details for the specifics

  ic_client.port = port;

  ic_client.on('error', function(err) {
    console.error("Can't configure device. Did you remember to set your backpack into config mode?".red);
    this.close();
    if (cb) {
      cb();
    }
  });
  ic_client.on('ready', function() {
    // use defaults and then check if we need otherwise
    let address = parseInt(fw.address, 16);
    let use_custom = 0;
    if (opts.i2c_address != undefined && opts.i2c_address != 0) {
      // override with the custom one.
      address = opts.i2c_address;
      use_custom = 1;
    }

    this.set_details({
      firmwareID: parseInt(fw.firmwareID, 16),
      creatorID: parseInt(fw.creatorID, 16),
      i2c_address: address,
      use_custom_address: use_custom
    }, function() {
      this.close();
      if (cb) {
        console.info('Cleaning up. Installation complete.'.green);
        cb();
      }
    }.bind(this))
  });
};

Interchange.prototype.flash_firmware = function(firmware, tmp_dir, opts, cb) {
  // flashes the board with the options provided.

  const board = opts.board || 'nano'; // assumes nano if none provided
  let port = opts.port || ''; // will leave empty and sees what happens.
  const usingFirmata = opts.useFirmata || false; // Assumes not unless explicit

  const avrgirl = new Avrgirl({
    board,
    port,
    debug: true
  });

  avrgirl.flash(firmware, function(err) {
    if (err) {
      console.error(err);
      process.exit(1);
    }

    if (port == '') {
      port = avrgirl.options.port;
    }

    if (!usingFirmata) {
      this.set_firmware_details(port, opts, cb);
    }
  }.bind(this));
};

/**
Interchange.prototype.download_from_npm = function(firmware, options, cb) {
  // downloads the firmware from the npm package

  console.info(colors.magenta('Installing ' + firmware.name + ' from npm'));
  // first try to install the npm package
  let command = 'npm install --no-save ';

  // test to see if installing from a gh repo as an npm package.
  if (firmware.npm.repo !== undefined) {
    command = command + firmware.npm.repo;
  } else {
    if (typeof(firmware.npm.version) == 'undefined') {
      // just use "latest" from npm
      command = command + firmware.npm.package;
    } else {
      command = command + firmware.npm.package + '@' + firmware.npm.version;
    }
  }

  try {
    // simply call the command on the command line.
    child_process.execSync(command, {stdio: [0,1,2]});
  } catch (e) {
    console.error('npm could not complete');
    throw e;
  }

  // as we have installed get the manifest file.
  const base_path = path.join('.', 'node_modules', firmware.npm.package)
  const manifest_file = path.join(base_path, 'manifest.json');
  let manifest = null;

  try {
    manifest = JSON.parse(fs.readFileSync(manifest_file));
  } catch (e) {
    console.error('Manifest file incorrect');
    throw e;
  }

  let manifest_objects = (options.useFirmata ? manifest.firmata : manifest.backpack);
  // this deals with a firmata object supplied that isn't the default
  // one in order to grab the right hex file.
  if (options.useFirmata && options.firmataName != '') {
    manifest_objects = manifest.firmata[options.firmataName];
  } else if (options.useFirmata && options.firmataName == '' && manifest.firmata.multi != undefined) {
    // we have multiple firmatas and none have been supplied.
    throw new Error('Multiple firmatas are available, please supply a name');
  }

  if (manifest_objects.hexPath.indexOf('/') != 0) {
    manifest_objects.hexPath = '/' + manifest_objects.hexPath;
  }

  const hex_path = path.join(base_path, manifest_objects.bins, options.board, manifest_objects.hexPath);

  cb(hex_path, null,  options);
};
**/
/**
Interchange.prototype.download_from_github = function(firmware, options, cb) {
  // downloads the firmware from the GH repo

  const self = this;
  let manifest_uri = null;
  let base_uri = null;
  let branch = 'master';
  let repo = '';

  console.info('Retrieving manifest data from GitHub'.magenta);

  if (firmware.repo.indexOf('git+https') == 0) {
    if (firmware.repo.indexOf('#') > 0 ) {
      // we want a branch so get that detail.
      branch = '/' + firmware.repo.substring(firmware.repo.indexOf('#') + 1);
      repo = firmware.repo.substring(22, firmware.repo.indexOf('#'));
    } else {
      repo = firmware.repo.substring(22);
      branch = '/master';
    }

    base_uri = 'https://raw.githubusercontent.com' + repo + branch;
    manifest_uri = base_uri + '/manifest.json?' + (new Date().getTime());
  }

  if (manifest_uri == null) {
    throw new Error('Cannot find manifest of ' + firmware);
  }
  // download the manifest file and then hand it over to then
  // download the hex file ready to be written to the board
  const tmp_dir = tmp.dirSync();
  const manifest_file_path = tmp_dir.name + '/manifest.json';

  Download(manifest_uri).then(data => {
    let manifest = null;
    try {
      manifest = JSON.parse(data);
    } catch (e) {
      console.error('Manifest file incorrect');
      self.clean_temp_dir(tmp_dir);
      throw new Error('Manifest file error');
    }

    // now we need to download the hex file.
    let manifest_objects = (options.useFirmata ? manifest.firmata : manifest.backpack);

    if (manifest_objects == undefined) {
      console.error("An appropriate bin can't be found to flash in the manifest file.".red);
      console.error("This is likely because either the maintainer hasn't provided the right " +
                "path to the hex file or because you've passed in an innapropriate selector " +
                'on the --firmata= switch');
      console.log('Firmware types available from this manifest file:');
      if (manifest.firmata) {
        console.log('FIRMATA:'.blue);
        if (manifest.firmata.multi) {
          Object.keys(manifest.firmata).forEach(function(key) {
            if (key != 'multi') {
              console.log('\t "' + key + '" use --firmata=' + key);
            }
          });
        } else {
          console.log('\t default use --firmata');
        }
      }
      if (manifest.backpack) {
        console.log('I2C BACKPACK'.blue);
      }
      throw new Error("Can't find binary to flash");
    }

    // this deals with a firmata object supplied that isn't the default
    // one in order to grab the right hex file.
    if (options.useFirmata && options.firmataName != '') {
      manifest_objects = manifest.firmata[options.firmataName];
    } else if (options.useFirmata && options.firmataName == '' && manifest.firmata.multi != undefined) {
      // we have multiple firmatas and none have been supplied.
      throw new Error('Multiple firmatas are available, please supply a name');
    }

    if (manifest_objects.hexPath == undefined) {
      console.error(manifest_objects);
      self.clean_tmp_dir(tmp_dir);
      throw new Error('Hex path cannot be found');
    }

    if (manifest_objects.hexPath.indexOf('/') != 0) {
      manifest_objects.hexPath = '/' + manifest_objects.hexPath;
    }
    const hex_uri = base_uri + manifest_objects.bins + options.board +
                        manifest_objects.hexPath + '?' + (new Date().getTime());

    console.info('Downloading hex file')

    Download(hex_uri).then(hex_data => {
      const hex_path = tmp_dir.name + '/bin.hex';
      try {
        fs.writeFileSync(hex_path, hex_data);
      } catch (e) {
        console.error("Can't write hex file to file system".red);
        self.clean_tmp_dir(tmp_dir);
        throw new Error('HexWriteError');
      }

      // about to call the writer.
      cb(hex_path, tmp_dir, options);
    }).catch(function() {
      console.error("Can't download the hex file (%s)".red, hex_uri);
      self.clean_tmp_dir(tmp_dir);
      throw new Error('HexDownloadError');
    });
  }).catch(function(err) {
    console.error('There was an error downloading or processing the the manifest file.'.red);
    console.log(err);
  });
};
**/

Interchange.prototype.check_firmware = (firmware, options = {}, cb) => {
  // checks if the firmware makes sense and downloads the hex file
  // to a temporary location

  if (firmware == undefined || firmware == null) {
    throw new Error('Must define a firmware to flash');
  }

  const board = options.board || 'nano'; // assumes nano if none provided
  const useFirmata = (firmware.indexOf('Firmata') > 0) || options.firmata || false;
  let firmataName = options.firmata || '';
  // check for default where no firmata name is supplied or default is implied.
  if (firmataName === true) {
    // set it to empty string
    firmataName = '';
  }

  // see if the firmware is in the directory
  fw = _.find(firmwares, function(f) {
    return f.name == firmware;
  });

  if (fw == undefined) {
    if (firmware.indexOf('git+https') >= 0) {
      // command has been passed with a git repo so make a temp object for
      // fw with appropriate stuff in it.
      fw = {
        'name': firmware,
        'deviceID': 0x01,
        'creatorID': 0x00,
        'repo': firmware,
        'firmata': useFirmata
      };
    } else {
      throw new Error('No firmware found: ' + firmware);
    }
  }

  // we have a firmware - check if we need firmata
  if (useFirmata) {
    if (! fw.firmata) {
      throw new Error(`Firmware ${fw.name} does not support custom firmata`);
    }
  }

  const opts = options || {};

  opts['useFirmata'] = useFirmata;
  opts['firmataName'] = firmataName;

  // now check if the firmware is in npm or github.
  if (fw.npm == undefined) {
    // use git repo
    const dl = new Downloader({fw});
    dl.download(fw, opts)
      .then(({hexpath, tmpdir}) => {
        console.log(hexpath, 'made it to flasing stuff');
        cb(hexpath, tmpdir, opts);
      })
      .catch((err) => console.log(err));
    // this.download_from_github(fw, opts, cb);
  } else {
    // get from npm now
    const dl = new Downloader({fw});
    // about to try to download from npm
    dl.download(fw, opts)
      .then(({hexpath, tmpdir}) => {
        // calling back to write firmware
        cb(hexpath, null, opts);
      })
      .catch((err) => console.log(err));
  }
};

module.exports = Interchange;
<commit_msg>refactor: let downloader determine how to get the hex file<commit_after>const _ = require('lodash');
const program = require('commander');
const Avrgirl = require('avrgirl-arduino');
const Serialport = require('serialport');
const child_process = require('child_process');
const colors = require('colors');
// const Download= require('download');
const fs      = require('fs');
const fsextra = require('fs-extra');
// const http    = require('http');
// const path    = require('path');
// const tmp     = require('tmp');

const creators = require('./firmwares.json').creators;
const firmwares = require('./firmwares.json').firmwares;
const interchange_client = require('./interchange_client');
const Downloader = require('./downloader');
const ic_client = new interchange_client.Client();
const version = require('../package.json').version;

let fw = null; // used to hold details of the firmware we want in it.

const Interchange = function() {
  this.firmwares = firmwares;
};

Interchange.prototype.clean_temp_dir = function(tmpdir) {
  // takes a temporary directory and cleans up any files within it and
  // then calls the callback to remove itself.
  if (tmpdir != undefined && tmpdir !== null && tmpdir !== '') {
    fsextra.removeSync(tmpdir.name);
    tmpdir.removeCallback();
  }
};

Interchange.prototype.list_devices = function() {
  // this method returns the list of available firmwares as a JSON object

  const fws = [];
  firmwares.forEach((firmware) => {
    fws.push({
      name: firmware.name,
      firmata: (firmware.firmata ? true : false),
      description: firmware.description
    });
  });

  return (fws);
};

Interchange.prototype.get_ports = function(cb) {
  return new Promise((resolve, reject) => {
    Serialport.list()
      .then((ports) => {
        resolve(ports);
      })
      .catch((err) => {
        reject(err);
      });
  });
};

Interchange.prototype.list_ports = function() {
  // this function lists out all the ports available to flash firmware
  // this function  is now deprecated
  console.warn('list_ports method deprecated - use get_ports instead');
  return this.get_ports();
};

Interchange.prototype.get_firmware_info = function(port) {
  // attempts to connect to an interchange firmware and get the
  // installed details.

  if (!port) {
    console.error('Please provide a device path'.red);
    return;
  }

  ic_client.port = port;

  ic_client.on('error', function(err) {
    console.error(err);
    return err;
  });
  ic_client.on('ready', function() {
    this.get_info(function(err, data) {
      // json is returned
      if (err) {
        this.close();
        throw err;
      }

      // look up the details from the various resources
      fw_details = _.find(firmwares, function(f) {
        return ((parseInt(f.creatorID, 16) == data.creatorID) &&
                        (parseInt(f.firmwareID, 16) == data.firmwareID));
      });
      const creator = _.find(creators, {id: fw_details.creatorID});

      // print everything out.
      console.info((fw_details.name + ' backpack firmware').bold);
      console.info('Version %s Built %s', data.fw_version, data.compile_date);
      console.info('Creator ID: %s (%s @%s)', fw_details.creatorID, creator.name, creator.gh);
      console.info('Device ID: %s (%s)', fw_details.firmwareID, fw_details.name);
      console.info('I2C Address: 0x%s (%s)', data.i2c_address.toString(16),
        data.use_custom_addr ? 'Using custom' : 'Using default');
      console.info(fw_details.description);

      // close it up.
      this.close();
    }.bind(this));
  })
};

Interchange.prototype.install_firmware = function(firmware, opts = {}) {
  if (!firmware) {
    throw new Error('Please supply a firmware to install');
  }

  const settings = {
    board: opts.board || process.env.INTERCHANGE_BOARD || 'nano',
    port: opts.port || process.env.INTERCHANGE_PORT,
    firmata: opts.firmata,
    i2c_address: opts.address
  };

  // check firmware
  // download firmware
  // flash firmware to device
  // optionally do interchange client things if needed

  try {
    this.check_firmware(firmware, settings, function(hex_path, tmp_dir, options) {
      this.flash_firmware(hex_path, tmp_dir, options, function() {
        // once complete destory the tmp_dir.
        console.log('flash completed', tmp_dir);
        if (tmp_dir) {
          console.log('about to clean up');
          this.clean_temp_dir(tmp_dir);
        }
      }.bind(this));
    }.bind(this));
  } catch (e) {
    console.error(e);
    return;
  }
};

Interchange.prototype.set_firmware_details = function(port, opts, cb) {
  // sets the firmware details for the specifics

  ic_client.port = port;

  ic_client.on('error', function(err) {
    console.error("Can't configure device. Did you remember to set your backpack into config mode?".red);
    this.close();
    if (cb) {
      cb();
    }
  });
  ic_client.on('ready', function() {
    // use defaults and then check if we need otherwise
    let address = parseInt(fw.address, 16);
    let use_custom = 0;
    if (opts.i2c_address != undefined && opts.i2c_address != 0) {
      // override with the custom one.
      address = opts.i2c_address;
      use_custom = 1;
    }

    this.set_details({
      firmwareID: parseInt(fw.firmwareID, 16),
      creatorID: parseInt(fw.creatorID, 16),
      i2c_address: address,
      use_custom_address: use_custom
    }, function() {
      this.close();
      if (cb) {
        console.info('Cleaning up. Installation complete.'.green);
        cb();
      }
    }.bind(this))
  });
};

Interchange.prototype.flash_firmware = function(firmware, tmp_dir, opts, cb) {
  // flashes the board with the options provided.

  const board = opts.board || 'nano'; // assumes nano if none provided
  let port = opts.port || ''; // will leave empty and sees what happens.
  const usingFirmata = opts.useFirmata || false; // Assumes not unless explicit

  const avrgirl = new Avrgirl({
    board,
    port,
    debug: true
  });

  avrgirl.flash(firmware, function(err) {
    if (err) {
      console.error(err);
      process.exit(1);
    }

    if (port == '') {
      port = avrgirl.options.port;
    }

    if (!usingFirmata) {
      this.set_firmware_details(port, opts, cb);
    }
  }.bind(this));
};

/**
Interchange.prototype.download_from_npm = function(firmware, options, cb) {
  // downloads the firmware from the npm package

  console.info(colors.magenta('Installing ' + firmware.name + ' from npm'));
  // first try to install the npm package
  let command = 'npm install --no-save ';

  // test to see if installing from a gh repo as an npm package.
  if (firmware.npm.repo !== undefined) {
    command = command + firmware.npm.repo;
  } else {
    if (typeof(firmware.npm.version) == 'undefined') {
      // just use "latest" from npm
      command = command + firmware.npm.package;
    } else {
      command = command + firmware.npm.package + '@' + firmware.npm.version;
    }
  }

  try {
    // simply call the command on the command line.
    child_process.execSync(command, {stdio: [0,1,2]});
  } catch (e) {
    console.error('npm could not complete');
    throw e;
  }

  // as we have installed get the manifest file.
  const base_path = path.join('.', 'node_modules', firmware.npm.package)
  const manifest_file = path.join(base_path, 'manifest.json');
  let manifest = null;

  try {
    manifest = JSON.parse(fs.readFileSync(manifest_file));
  } catch (e) {
    console.error('Manifest file incorrect');
    throw e;
  }

  let manifest_objects = (options.useFirmata ? manifest.firmata : manifest.backpack);
  // this deals with a firmata object supplied that isn't the default
  // one in order to grab the right hex file.
  if (options.useFirmata && options.firmataName != '') {
    manifest_objects = manifest.firmata[options.firmataName];
  } else if (options.useFirmata && options.firmataName == '' && manifest.firmata.multi != undefined) {
    // we have multiple firmatas and none have been supplied.
    throw new Error('Multiple firmatas are available, please supply a name');
  }

  if (manifest_objects.hexPath.indexOf('/') != 0) {
    manifest_objects.hexPath = '/' + manifest_objects.hexPath;
  }

  const hex_path = path.join(base_path, manifest_objects.bins, options.board, manifest_objects.hexPath);

  cb(hex_path, null,  options);
};
**/
/**
Interchange.prototype.download_from_github = function(firmware, options, cb) {
  // downloads the firmware from the GH repo

  const self = this;
  let manifest_uri = null;
  let base_uri = null;
  let branch = 'master';
  let repo = '';

  console.info('Retrieving manifest data from GitHub'.magenta);

  if (firmware.repo.indexOf('git+https') == 0) {
    if (firmware.repo.indexOf('#') > 0 ) {
      // we want a branch so get that detail.
      branch = '/' + firmware.repo.substring(firmware.repo.indexOf('#') + 1);
      repo = firmware.repo.substring(22, firmware.repo.indexOf('#'));
    } else {
      repo = firmware.repo.substring(22);
      branch = '/master';
    }

    base_uri = 'https://raw.githubusercontent.com' + repo + branch;
    manifest_uri = base_uri + '/manifest.json?' + (new Date().getTime());
  }

  if (manifest_uri == null) {
    throw new Error('Cannot find manifest of ' + firmware);
  }
  // download the manifest file and then hand it over to then
  // download the hex file ready to be written to the board
  const tmp_dir = tmp.dirSync();
  const manifest_file_path = tmp_dir.name + '/manifest.json';

  Download(manifest_uri).then(data => {
    let manifest = null;
    try {
      manifest = JSON.parse(data);
    } catch (e) {
      console.error('Manifest file incorrect');
      self.clean_temp_dir(tmp_dir);
      throw new Error('Manifest file error');
    }

    // now we need to download the hex file.
    let manifest_objects = (options.useFirmata ? manifest.firmata : manifest.backpack);

    if (manifest_objects == undefined) {
      console.error("An appropriate bin can't be found to flash in the manifest file.".red);
      console.error("This is likely because either the maintainer hasn't provided the right " +
                "path to the hex file or because you've passed in an innapropriate selector " +
                'on the --firmata= switch');
      console.log('Firmware types available from this manifest file:');
      if (manifest.firmata) {
        console.log('FIRMATA:'.blue);
        if (manifest.firmata.multi) {
          Object.keys(manifest.firmata).forEach(function(key) {
            if (key != 'multi') {
              console.log('\t "' + key + '" use --firmata=' + key);
            }
          });
        } else {
          console.log('\t default use --firmata');
        }
      }
      if (manifest.backpack) {
        console.log('I2C BACKPACK'.blue);
      }
      throw new Error("Can't find binary to flash");
    }

    // this deals with a firmata object supplied that isn't the default
    // one in order to grab the right hex file.
    if (options.useFirmata && options.firmataName != '') {
      manifest_objects = manifest.firmata[options.firmataName];
    } else if (options.useFirmata && options.firmataName == '' && manifest.firmata.multi != undefined) {
      // we have multiple firmatas and none have been supplied.
      throw new Error('Multiple firmatas are available, please supply a name');
    }

    if (manifest_objects.hexPath == undefined) {
      console.error(manifest_objects);
      self.clean_tmp_dir(tmp_dir);
      throw new Error('Hex path cannot be found');
    }

    if (manifest_objects.hexPath.indexOf('/') != 0) {
      manifest_objects.hexPath = '/' + manifest_objects.hexPath;
    }
    const hex_uri = base_uri + manifest_objects.bins + options.board +
                        manifest_objects.hexPath + '?' + (new Date().getTime());

    console.info('Downloading hex file')

    Download(hex_uri).then(hex_data => {
      const hex_path = tmp_dir.name + '/bin.hex';
      try {
        fs.writeFileSync(hex_path, hex_data);
      } catch (e) {
        console.error("Can't write hex file to file system".red);
        self.clean_tmp_dir(tmp_dir);
        throw new Error('HexWriteError');
      }

      // about to call the writer.
      cb(hex_path, tmp_dir, options);
    }).catch(function() {
      console.error("Can't download the hex file (%s)".red, hex_uri);
      self.clean_tmp_dir(tmp_dir);
      throw new Error('HexDownloadError');
    });
  }).catch(function(err) {
    console.error('There was an error downloading or processing the the manifest file.'.red);
    console.log(err);
  });
};
**/

Interchange.prototype.check_firmware = (firmware, options = {}, cb) => {
  // checks if the firmware makes sense and downloads the hex file
  // to a temporary location

  if (firmware == undefined || firmware == null) {
    throw new Error('Must define a firmware to flash');
  }

  const board = options.board || 'nano'; // assumes nano if none provided
  const useFirmata = (firmware.indexOf('Firmata') > 0) || options.firmata || false;
  let firmataName = options.firmata || '';
  // check for default where no firmata name is supplied or default is implied.
  if (firmataName === true) {
    // set it to empty string
    firmataName = '';
  }

  // see if the firmware is in the directory
  fw = _.find(firmwares, function(f) {
    return f.name == firmware;
  });

  if (fw == undefined) {
    if (firmware.indexOf('git+https') >= 0) {
      // command has been passed with a git repo so make a temp object for
      // fw with appropriate stuff in it.
      fw = {
        'name': firmware,
        'deviceID': 0x01,
        'creatorID': 0x00,
        'repo': firmware,
        'firmata': useFirmata
      };
    } else {
      throw new Error('No firmware found: ' + firmware);
    }
  }

  // we have a firmware - check if we need firmata
  if (useFirmata) {
    if (! fw.firmata) {
      throw new Error(`Firmware ${fw.name} does not support custom firmata`);
    }
  }

  const opts = options || {};

  opts['useFirmata'] = useFirmata;
  opts['firmataName'] = firmataName;

  // now check if the firmware is in npm or github.
  const dl = new Downloader({fw});
  dl.download(fw, opts)
    .then(({hexpath, tmpdir}) => {
      console.log(hexpath, 'made it to flasing stuff');
      cb(hexpath, tmpdir, opts);
    })
    .catch((err) => console.log(err));
};

module.exports = Interchange;
<|endoftext|>


<commit_before>
function isObject(val) {
    return val != null && typeof val === 'object' && Array.isArray(val) === false;
}

function isComponentSpec(val) {
    return (typeof val === "function" || (typeof val === "string" && val[0] === ":"));
}

function classListsProxy(args) {
    if (!Array.isArray(args))
        return args;

    // flatten
    return  ReactHut.classLists.apply(null, args);
}

ReactHut.createHut = function (React, config) {
    config = (config || {});

    if (!React || !React.createElement || !React.isValidElement)
        throw new Error("first arg must be React!");

    var transformProps = config.propsTransform || {};
    var transformPropNames = Object.keys(transformProps);

    var componentTransform = (config.componentTransform || null);

    var factory = React.createElement;
    var isResolved = React.isValidElement;

    if (ReactHut.classLists && !transformProps.className) {
        transformProps.className = classListsProxy;
        transformPropNames.push("className");

    }

    var resolve = function (fragment) {
        var spec = [null, null];
        var i, propName, componentSpec, propsSpec;

        if (!Array.isArray(fragment))
            return fragment;

        // unroll nested arrays -> [[[[[[:div]]]]]] -> [:div]
        while (fragment.length === 1 && Array.isArray(fragment[0]))
            fragment = fragment[0];

        // empty ?
        if (fragment.length === 0 || fragment[0] === null)
            return null;

        // resolved ?
        if (fragment.length === 1 && isResolved(fragment[0]))
            return fragment[0];

        // an array of children ?
        if (!isComponentSpec(fragment[0]))
            return fragment.map(resolve);

        // we use a different array, and copy, because it's faster & simpler..
        spec[0] = fragment[0];

        // props or children?
        if (fragment.length > 1) {
            i = 0;

            if (isObject(fragment[1])) {
                spec[1] =  fragment[1];
                i = 1;
            }

            while(++i < fragment.length)
                spec.push(fragment[i]);
        }

        // prop transform
        if (spec[1])
            for (i = 0; i < transformPropNames.length; i++) {
                propName = transformPropNames[i];

                if (spec[1].hasOwnProperty(propName))
                    spec[1][propName] = transformProps[propName](spec[1][propName]);
            }

        // component transform
        if (componentTransform) {
            spec = (componentTransform(spec) || spec);

            if (isResolved(spec))
                return spec;

            if (!Array.isArray(spec))
                throw new Error("component transform should return an array or nothing, got: " + typeof spec);
        }

        // resolve children
        for (i = 2; i < spec.length; i++)
            spec[i] = resolve(spec[i]);

        // remove ":" from primitive components and inline class names
        if (typeof spec[0] === "string") {
            componentSpec = spec[0].slice(1);

            componentSpec = componentSpec.split(".");
            spec[0] = componentSpec.shift();

            if (componentSpec.length) {
                propsSpec = (spec[1] || {});

                if (propsSpec.className)
                    propsSpec.className =  (propsSpec.className + " " + componentSpec.join(" "));
                else
                    propsSpec.className = componentSpec.join(" ");

                spec[1] = propsSpec;
            }
        }

        return factory.apply(React, spec);
    };

    return function () {
        var args = Array.prototype.slice.call(arguments);

        while (args.length === 1 && Array.isArray(args[0]))
            args = args[0];

        if(!args.length)
            return null;

        if (!Array.isArray(args[0]))
            return resolve(args);

        for (var i = 0; i < args.length; i++)
            args[i] = resolve(args[i]);

        return args;
    };
};

<commit_msg>minor whitespace fix<commit_after>
function isObject(val) {
    return val != null && typeof val === 'object' && Array.isArray(val) === false;
}

function isComponentSpec(val) {
    return (typeof val === "function" || (typeof val === "string" && val[0] === ":"));
}

function classListsProxy(args) {
    if (!Array.isArray(args))
        return args;

    // flatten
    return  ReactHut.classLists.apply(null, args);
}

ReactHut.createHut = function (React, config) {
    config = (config || {});

    if (!React || !React.createElement || !React.isValidElement)
        throw new Error("first arg must be React!");

    var transformProps = config.propsTransform || {};
    var transformPropNames = Object.keys(transformProps);

    var componentTransform = (config.componentTransform || null);

    var factory = React.createElement;
    var isResolved = React.isValidElement;

    if (ReactHut.classLists && !transformProps.className) {
        transformProps.className = classListsProxy;
        transformPropNames.push("className");
    }

    var resolve = function (fragment) {
        var spec = [null, null];
        var i, propName, componentSpec, propsSpec;

        if (!Array.isArray(fragment))
            return fragment;

        // unroll nested arrays -> [[[[[[:div]]]]]] -> [:div]
        while (fragment.length === 1 && Array.isArray(fragment[0]))
            fragment = fragment[0];

        // empty ?
        if (fragment.length === 0 || fragment[0] === null)
            return null;

        // resolved ?
        if (fragment.length === 1 && isResolved(fragment[0]))
            return fragment[0];

        // an array of children ?
        if (!isComponentSpec(fragment[0]))
            return fragment.map(resolve);

        // we use a different array, and copy, because it's faster & simpler..
        spec[0] = fragment[0];

        // props or children?
        if (fragment.length > 1) {
            i = 0;

            if (isObject(fragment[1])) {
                spec[1] =  fragment[1];
                i = 1;
            }

            while(++i < fragment.length)
                spec.push(fragment[i]);
        }

        // prop transform
        if (spec[1])
            for (i = 0; i < transformPropNames.length; i++) {
                propName = transformPropNames[i];

                if (spec[1].hasOwnProperty(propName))
                    spec[1][propName] = transformProps[propName](spec[1][propName]);
            }

        // component transform
        if (componentTransform) {
            spec = (componentTransform(spec) || spec);

            if (isResolved(spec))
                return spec;

            if (!Array.isArray(spec))
                throw new Error("component transform should return an array or nothing, got: " + typeof spec);
        }

        // resolve children
        for (i = 2; i < spec.length; i++)
            spec[i] = resolve(spec[i]);

        // remove ":" from primitive components and inline class names
        if (typeof spec[0] === "string") {
            componentSpec = spec[0].slice(1);

            componentSpec = componentSpec.split(".");
            spec[0] = componentSpec.shift();

            if (componentSpec.length) {
                propsSpec = (spec[1] || {});

                if (propsSpec.className)
                    propsSpec.className =  (propsSpec.className + " " + componentSpec.join(" "));
                else
                    propsSpec.className = componentSpec.join(" ");

                spec[1] = propsSpec;
            }
        }

        return factory.apply(React, spec);
    };

    return function () {
        var args = Array.prototype.slice.call(arguments);

        while (args.length === 1 && Array.isArray(args[0]))
            args = args[0];

        if(!args.length)
            return null;

        if (!Array.isArray(args[0]))
            return resolve(args);

        for (var i = 0; i < args.length; i++)
            args[i] = resolve(args[i]);

        return args;
    };
};

<|endoftext|>


<commit_before>/*
    This is a series of javascript functions that the UI uses to communicate with the Master contract
    Coded by Austen Goddu
*/

function TAG_IS_REAL(searchTerm) {

    if(getTagAddressFromName(searchTerm) == 0) {
        return false;

    } else {
        return true;

    }

}

function SEARCH_ENGINE (searchTerm) {

    searchTerm = string(searchTerm);

    if(TAG_IS_REAL(searchTerm)) {
        return searchTerm;

    } else {
        return "Sorry, we did not find the specified tag, check mispelling grammar, punctuation, etc.";
    }

}

function ADD_TAG(tagName) {

    // will be finished at a later date, need to figure out how to pass arrays as arguments

}
<commit_msg>General update, added in function to get the description with a tag<commit_after>/*
    This is a series of javascript functions that the UI uses to communicate with the Master contract
    Coded by Austen Goddu
*/

function TAG_IS_REAL(searchTerm) {

    if(getTagAddressFromName(searchTerm) == 0) {
        return false;

    } else {
        return true;

    }

}

function SEARCH_ENGINE (searchTerm) {

    searchTerm = string(searchTerm);

    if(TAG_IS_REAL(searchTerm)) {
        return searchTerm;

    } else {
        return "Sorry, we did not find the specified tag, check mispelling grammar, punctuation, etc.";

    }

}

function ADD_TAG(tagName) {

    // will be finished at a later date, need to figure out how to pass arrays as arguments

}

function GET_TAG_DESCRIPTION (searchTerm) {

    if (TAG_IS_REAL(searchTerm)) {
          return master.getTagDescription(searchTerm);

    } else {
          return "Sorry, we did not find the specified tag, check mispelling grammar, punctuation, etc.";

    }

}
<|endoftext|>