<commit_before>describe('test', function() {

  var ObjectiveFire, ObjectClass, Properties, $timeout, PrimitiveProperty, ObjectProperty, ObjectArrayProperty;
  var objFire;

  beforeEach(function () {
    module('objective-fire');
    inject(function (_ObjectiveFire_, _ObjectClass_, _Properties_, _$timeout_, _PrimitiveProperty_, _ObjectProperty_, _ObjectArrayProperty_) {
      ObjectiveFire = _ObjectiveFire_;
      ObjectClass = _ObjectClass_;
      Properties = _Properties_;
      $timeout = _$timeout_;
      PrimitiveProperty = _PrimitiveProperty_; ObjectProperty = _ObjectProperty_; ObjectArrayProperty = _ObjectArrayProperty_;
    });
    var dogConstructor = function(name, color) {
    this.name = name;
    this.color = color;
  };
  var dogMethods = {
    description: function() {return this.name + " is " + this.color;}
  };
  dogProperties = new Properties();
  var name = new PrimitiveProperty("name");
  var color = new PrimitiveProperty("color");
  dogProperties.addProperty(name).addProperty(color);
  var dogClass = new ObjectClass("dog", dogConstructor, dogMethods, dogProperties);

  var userConstructor = function(first, last) {
    this.first = first;
    this.last = last;
  };
  var userMethods = {
    fullName: function() {return this.first + " " + this.last;}
  };
  var userProperties = new Properties();
  var firstName = new PrimitiveProperty("first");
  var lastName = new PrimitiveProperty("last");
  var dog = new ObjectProperty("dog", "dog");
  var dog2 = new ObjectProperty("dog2", "dog");
  var dogs = new ObjectArrayProperty("dogs", "dog");
  userProperties.addProperty(firstName).addProperty(lastName).addProperty(dog).addProperty(dog2).addProperty(dogs);
  var userClass = new ObjectClass("user", userConstructor, userMethods, userProperties);

  objFire = new ObjectiveFire(new Firebase("https://objective-fire.firebaseio.com"));
  objFire.registerObjectClass(userClass);
  objFire.registerObjectClass(dogClass);
  jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
  });

  it("will obtain data from the firebase", function(done) {
    var user = objFire.getObjectClass("user");
    var myUser = user.instance("user:1");
    function setTimeout1() {
      setTimeout(function() {
	       $timeout.flush();
         setTimeout1();
      }, 1000);
    }
    setTimeout1();
    myUser.$load("dog2");
    myUser.$loaded().then(function() {
    expect(myUser.first).toEqual("Davis")
    expect(myUser.last).toEqual("Cook")
    expect(typeof myUser.dog2).toBe("object");
    expect(typeof myUser.dog).not.toBe("object");
      done()
    });
  });

  it("will do stuff", function(done) {
    var user = objFire.getObjectClass("user");
    var myUser = user.new("A", "B");
    var ref = new Firebase("https://objective-fire.firebaseio.com");
    var ref2 = ref.child("user").child(myUser.$id);
    ref2.on("value", function(snap) {
      var data = snap.val();
      expect(data.first).toEqual("A");
      expect(data.last).toEqual("B");
      done();
    });
  });

  it("will do stuff #2", function(done) {
    var user = objFire.getObjectClass("user");
    var dog = objFire.getObjectClass("dog");
    var myUser = user.new("A", "B");
    myUser.$load("dogs");
    myUser.$loaded().then(function() {
      myUser.dogs.$loaded().then(function() {
        myUser.dogs.$add(dog.new("Rover", "Black"));
        console.log("Create dog");
        myUser.dogs.$add(dog.new("Rover", "Black"));
        console.log("Create dog");
        myUser.dogs.$add(dog.new("Rover", "Black"));
        console.log("Create dog");
        myUser.dogs.$add(dog.new("Rover", "Black"));
        console.log("Create dog");
        myUser.dogs.$add(dog.new("Rover", "Black"));
        console.log("Create dog");
        myUser.dogs.$add(dog.new("Rover", "Black")); // why won't these update the local data and create the elements in the array
        console.log("Create dog");
        setTimeout(function() {
          console.log(myUser.dogs);
          myUser.$save(); // known bug - items in an array aren't created in the array right when using $add
          done();
        }, 2000)
        expect(true).toEqual(true);
      });
    });
  });

});
<commit_msg>realized the bug I had was just developer misuse<commit_after>describe('test', function() {

  var ObjectiveFire, ObjectClass, Properties, $timeout, PrimitiveProperty, ObjectProperty, ObjectArrayProperty;
  var objFire;

  beforeEach(function () {
    module('objective-fire');
    inject(function (_ObjectiveFire_, _ObjectClass_, _Properties_, _$timeout_, _PrimitiveProperty_, _ObjectProperty_, _ObjectArrayProperty_) {
      ObjectiveFire = _ObjectiveFire_;
      ObjectClass = _ObjectClass_;
      Properties = _Properties_;
      $timeout = _$timeout_;
      PrimitiveProperty = _PrimitiveProperty_; ObjectProperty = _ObjectProperty_; ObjectArrayProperty = _ObjectArrayProperty_;
    });
    var dogConstructor = function(name, color) {
    this.name = name;
    this.color = color;
  };
  var dogMethods = {
    description: function() {return this.name + " is " + this.color;}
  };
  dogProperties = new Properties();
  var name = new PrimitiveProperty("name");
  var color = new PrimitiveProperty("color");
  dogProperties.addProperty(name).addProperty(color);
  var dogClass = new ObjectClass("dog", dogConstructor, dogMethods, dogProperties);

  var userConstructor = function(first, last) {
    this.first = first;
    this.last = last;
  };
  var userMethods = {
    fullName: function() {return this.first + " " + this.last;}
  };
  var userProperties = new Properties();
  var firstName = new PrimitiveProperty("first");
  var lastName = new PrimitiveProperty("last");
  var dog = new ObjectProperty("dog", "dog");
  var dog2 = new ObjectProperty("dog2", "dog");
  var dogs = new ObjectArrayProperty("dogs", "dog");
  userProperties.addProperty(firstName).addProperty(lastName).addProperty(dog).addProperty(dog2).addProperty(dogs);
  var userClass = new ObjectClass("user", userConstructor, userMethods, userProperties);

  objFire = new ObjectiveFire(new Firebase("https://objective-fire.firebaseio.com"));
  objFire.registerObjectClass(userClass);
  objFire.registerObjectClass(dogClass);
  jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
  });

  it("will obtain data from the firebase", function(done) {
console.log("iran");
    var user = objFire.getObjectClass("user");
    var myUser = user.instance("user:1");
    function setTimeout1() {
      setTimeout(function() {
try{
	       $timeout.flush();}catch(err){}
         setTimeout1();
      }, 0);
    }
    setTimeout1();
    myUser.$load("dog2");
    myUser.$loaded().then(function() {
    expect(myUser.first).toEqual("Davis")
    expect(myUser.last).toEqual("Cook")
    expect(typeof myUser.dog2).toBe("object");
    expect(typeof myUser.dog).not.toBe("object");
      done()
    });
  });

  it("will do stuff", function(done) {
    var user = objFire.getObjectClass("user");
    var myUser = user.new("A", "B");
    var ref = new Firebase("https://objective-fire.firebaseio.com");
    var ref2 = ref.child("user").child(myUser.$id);
    ref2.on("value", function(snap) {
      var data = snap.val();
      expect(data.first).toEqual("A");
      expect(data.last).toEqual("B");
      done();
    });
  });

  it("will do stuff #2", function(done) {
    var user = objFire.getObjectClass("user");
    var dog = objFire.getObjectClass("dog");
    var myUser = user.new("A", "B");
    myUser.$load("dogs");
    myUser.$loaded().then(function() {
      myUser.dogs.$loaded().then(function() {
        myUser.dogs.$add(dog.new("Rover", "Black"));
        console.log("Create dog");
        myUser.dogs.$add(dog.new("Rover", "Black"));
        console.log("Create dog");
        myUser.dogs.$add(dog.new("Rover", "Black"));
        console.log("Create dog");
        myUser.dogs.$add(dog.new("Rover", "Black"));
        console.log("Create dog");
        myUser.dogs.$add(dog.new("Rover", "Black"));
        console.log("Create dog");
        myUser.dogs.$add(dog.new("Rover", "Black")).then(function() {
          myUser.$save(); // known bug - items in an array aren't created in the array right when using $add
          done();
          expect(true).toEqual(true);
        });
      });// why won't these update the local data and create the elements in the array
    });
  });

});
<|endoftext|>


<commit_before>/*!
 * node-gcm
 * Copyright(c) 2013 Marcus Farkas <toothlessgear@finitebox.com>
 * MIT Licensed
 */
var Constants = require('./constants');
var req = require('request');
var debug = require('debug')('node-gcm');

function Sender(key , options) {
    if (!(this instanceof Sender)) {
        return new Sender(key, options);
    }

    this.key = key;
    this.options = options;
}

Sender.prototype.sendNoRetry = function(message, registrationIds, callback) {
    if(!callback) {
        callback = function() {};
    }

    var body = {},
        requestBody,
        post_options,
        post_req,
        timeout;

    body[Constants.JSON_REGISTRATION_IDS] = registrationIds;

    if (message.delayWhileIdle !== undefined) {
        body[Constants.PARAM_DELAY_WHILE_IDLE] = message.delayWhileIdle;
    }
    if (message.collapseKey !== undefined) {
        body[Constants.PARAM_COLLAPSE_KEY] = message.collapseKey;
    }
    if (message.timeToLive !== undefined) {
        body[Constants.PARAM_TIME_TO_LIVE] = message.timeToLive;
    }
    if (message.dryRun !== undefined) {
        body[Constants.PARAM_DRY_RUN] = message.dryRun;
    }
    if (Object.keys(message.data)) {
        body[Constants.PARAM_PAYLOAD_KEY] = message.data;
    }

    requestBody = JSON.stringify(body);

    post_options = {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Content-length': Buffer.byteLength(requestBody, 'utf8'),
            'Authorization': 'key=' + this.key
        },
        uri: Constants.GCM_SEND_URI,
        body: requestBody
    };

    if (this.options && this.options.proxy) {
        post_options.proxy = this.options.proxy;
    }

    if (this.options && this.options.maxSockets) {
        post_options.maxSockets = this.options.maxSockets;
    }

    timeout = Constants.SOCKET_TIMEOUT;

    if (this.options && this.options.timeout) {
        timeout =  this.options.timeout;
    }

    post_options.timeout = timeout;

    post_req = req(post_options, function (err, res, resBody) {

        if (err) {
            return callback(err, null);

        }
        if (!res) {
            return callback('response is null', null);

        }
        if (res.statusCode >= 500) {
            debug('GCM service is unavailable (500)');
            return callback(res.statusCode, null);
        } else if (res.statusCode === 401) {
            debug('Unauthorized (401). Check that your API token is correct.');
            return callback(res.statusCode, null);
        } else if (res.statusCode !== 200) {
            debug('Invalid request (' + res.statusCode + '): ' + resBody);
            return callback(res.statusCode, null);
        }

        try {
            callback(null, JSON.parse(resBody));
        } catch (e) {
            debug("Error handling GCM response " + e);
            callback("error", null);
        }
    });
};

Sender.prototype.send = function(message, registrationIds, retries, backoff, callback) {
    if(typeof backoff == "undefined" || typeof backoff == "function") {
        callback = backoff;
        backoff = Constants.BACKOFF_INITIAL_DELAY;
    }
    if(typeof retries == "undefined" || typeof retries == "function") {
        callback = retries;
        retries = 5;
    }
    if(!callback) {
        callback = function() {};
    }

    var attempt = 0,
        self = this;

    if (registrationIds.length) {
        this.sendNoRetry(message, registrationIds, function lambda(err, result) {

            if (attempt < retries) {
                var sleepTime, unsentRegIds = [], i;

                // if we err'd resend them all
                if (err) {
                    unsentRegIds = registrationIds;
                }
                // success but check for bad ids
                else {
                    for (i = 0; i < registrationIds.length; i += 1) {
                        if (result.results[i].error === 'Unavailable') {
                            unsentRegIds.push(registrationIds[i]);
                        }
                    }
                }

                if (unsentRegIds.length) {
                    if (result) {
                        debug("Results received but not all successful", result);
                    }
                    sleepTime = Math.pow (2, attempt) * backoff;
                    if (sleepTime > Constants.MAX_BACKOFF_DELAY) {
                        sleepTime = Constants.MAX_BACKOFF_DELAY;
                    }

                    setTimeout(function () {
                        self.sendNoRetry(message, unsentRegIds, lambda);
                    }, sleepTime);
                    attempt += 1;
                } else {
                    // No more registration ids to send
                    callback(err, result);
                }

            } else {
                // attempts has exceeded retries
                callback(err, result);
            }
        });
    } else {
        debug('No RegistrationIds given!');
        callback('No RegistrationIds given!', null);
    }
};

module.exports = Sender;<commit_msg>Flipped if-statement to reduce nesting<commit_after>/*!
 * node-gcm
 * Copyright(c) 2013 Marcus Farkas <toothlessgear@finitebox.com>
 * MIT Licensed
 */
var Constants = require('./constants');
var req = require('request');
var debug = require('debug')('node-gcm');

function Sender(key , options) {
    if (!(this instanceof Sender)) {
        return new Sender(key, options);
    }

    this.key = key;
    this.options = options;
}

Sender.prototype.sendNoRetry = function(message, registrationIds, callback) {
    if(!callback) {
        callback = function() {};
    }

    var body = {},
        requestBody,
        post_options,
        post_req,
        timeout;

    body[Constants.JSON_REGISTRATION_IDS] = registrationIds;

    if (message.delayWhileIdle !== undefined) {
        body[Constants.PARAM_DELAY_WHILE_IDLE] = message.delayWhileIdle;
    }
    if (message.collapseKey !== undefined) {
        body[Constants.PARAM_COLLAPSE_KEY] = message.collapseKey;
    }
    if (message.timeToLive !== undefined) {
        body[Constants.PARAM_TIME_TO_LIVE] = message.timeToLive;
    }
    if (message.dryRun !== undefined) {
        body[Constants.PARAM_DRY_RUN] = message.dryRun;
    }
    if (Object.keys(message.data)) {
        body[Constants.PARAM_PAYLOAD_KEY] = message.data;
    }

    requestBody = JSON.stringify(body);

    post_options = {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Content-length': Buffer.byteLength(requestBody, 'utf8'),
            'Authorization': 'key=' + this.key
        },
        uri: Constants.GCM_SEND_URI,
        body: requestBody
    };

    if (this.options && this.options.proxy) {
        post_options.proxy = this.options.proxy;
    }

    if (this.options && this.options.maxSockets) {
        post_options.maxSockets = this.options.maxSockets;
    }

    timeout = Constants.SOCKET_TIMEOUT;

    if (this.options && this.options.timeout) {
        timeout =  this.options.timeout;
    }

    post_options.timeout = timeout;

    post_req = req(post_options, function (err, res, resBody) {

        if (err) {
            return callback(err, null);

        }
        if (!res) {
            return callback('response is null', null);

        }
        if (res.statusCode >= 500) {
            debug('GCM service is unavailable (500)');
            return callback(res.statusCode, null);
        } else if (res.statusCode === 401) {
            debug('Unauthorized (401). Check that your API token is correct.');
            return callback(res.statusCode, null);
        } else if (res.statusCode !== 200) {
            debug('Invalid request (' + res.statusCode + '): ' + resBody);
            return callback(res.statusCode, null);
        }

        try {
            callback(null, JSON.parse(resBody));
        } catch (e) {
            debug("Error handling GCM response " + e);
            callback("error", null);
        }
    });
};

Sender.prototype.send = function(message, registrationIds, retries, backoff, callback) {
    if(typeof backoff == "undefined" || typeof backoff == "function") {
        callback = backoff;
        backoff = Constants.BACKOFF_INITIAL_DELAY;
    }
    if(typeof retries == "undefined" || typeof retries == "function") {
        callback = retries;
        retries = 5;
    }
    if(!callback) {
        callback = function() {};
    }

    var attempt = 0,
        self = this;

    if (!registrationIds.length) {
        debug('No RegistrationIds given!');
        callback('No RegistrationIds given!', null);
        return;
    }
    this.sendNoRetry(message, registrationIds, function lambda(err, result) {

        if (attempt < retries) {
            var sleepTime, unsentRegIds = [], i;

            // if we err'd resend them all
            if (err) {
                unsentRegIds = registrationIds;
            }
            // success but check for bad ids
            else {
                for (i = 0; i < registrationIds.length; i += 1) {
                    if (result.results[i].error === 'Unavailable') {
                        unsentRegIds.push(registrationIds[i]);
                    }
                }
            }

            if (unsentRegIds.length) {
                if (result) {
                    debug("Results received but not all successful", result);
                }
                sleepTime = Math.pow (2, attempt) * backoff;
                if (sleepTime > Constants.MAX_BACKOFF_DELAY) {
                    sleepTime = Constants.MAX_BACKOFF_DELAY;
                }

                setTimeout(function () {
                    self.sendNoRetry(message, unsentRegIds, lambda);
                }, sleepTime);
                attempt += 1;
            } else {
                // No more registration ids to send
                callback(err, result);
            }

        } else {
            // attempts has exceeded retries
            callback(err, result);
        }
    });
};

module.exports = Sender;<|endoftext|>


<commit_before>module.exports = {
  entry: './src/wildcard-regex.js',
  output: {
    path: './dist',
    filename: 'wildcard-regex.js',
    library: 'wildcardRegex',
    libraryTarget: 'umd'
  }
};
<commit_msg>Update webpack.config.js to reflect new entry point in src/index.js<commit_after>module.exports = {
  entry: './src/index.js',
  output: {
    path: './dist',
    filename: 'wildcard-regex.js',
    library: 'wildcardRegex',
    libraryTarget: 'umd'
  }
};
<|endoftext|>


<commit_before>var tls             = require("tls"),
    fs              = require("fs"),
    http            = require("http"),
    https           = require("https"),
    Connect         = require("connect"),
    EventPublisher  = require("./event-publisher"),
    FSM             = require("./fsm"),
    Semaphore       = require("./semaphore"),
    indexer         = require("./file-indexer"),
    parser          = require("./parser"),
    fileWatcher     = require("./filewatcher"),
    middleware      = require("./middleware"),
    cache           = require("./simple-cache"),
    _               = require("underscore")._,
    restProxy       = require("./restProxy"),
    connectRouter   = require("./router_connect");

exports.init = function(options, cb) {

  //use a state machine to package/parse required application resources
  var fsm = new FSM({
    states: {
      initial: {
        stateStartup: function() {
          // - index the application's files and directories
          indexer.index(options, function(err, indexedFiles) {
            if (err) fsm.fire("error", err); else {
              cache.setItem("feather-files", indexedFiles);

              if (indexedFiles.restFiles && options.rest && options.rest.autoGenerateProxy) {
                fsm.fire("generateRestProxy", indexedFiles);
              } else {
                fsm.fire("parseFeatherFiles", indexedFiles, null);
              }
            }
          });
        },
        generateRestProxy: function(indexedFiles) {
          restProxy.generateProxy({
            appOptions: options,
            files: indexedFiles.restFiles
          }, function(err, restProxyInfo) {
            if (err) cb(err); else {
              fsm.fire("parseFeatherFiles", indexedFiles, restProxyInfo);
            }
          });
        },
        parseFeatherFiles: function(indexedFiles, restProxyInfo) {
          // - pre-parse all feather.html files
          // - move the stateMachine to the next state
          var sem = new Semaphore(function() {
            fsm.fire("parsingComplete");
          });
          //parse the .feather.html files in the app
          _.each(_.keys(indexedFiles.featherFiles), function(_path) {
            sem.increment();
            //guarantee all files get counted in semaphore
            process.nextTick(function() {
              parser.parseFile({
                restProxyInfo: restProxyInfo,
                path: _path,
                request: {page: _path.replace(/.*\/public\/(.*)$/, "$1")} //need a dummy request object for parser since there is no real request at this point
              }, function(err, render) {
                  if (err) throw new Error(JSON.stringify(err)); else {
                    indexedFiles.featherFiles[_path].render = render;
                    //now, if this file changes on disk, invalidate and remove the compiled renderer until the next request
                    if (!indexedFiles.featherFiles[_path].watchingFile) { //only wire the watcher once
                      fileWatcher.watchFileMtime(_path, function(args) {
                        indexedFiles.featherFiles[_path].render = null;
                      });
                      indexedFiles.featherFiles[_path].watchingFile = true;
                    }
                    sem.execute();
                  }
              });
            });
          });
        },
        parsingComplete: function() {
          return fsm.states.createServer;
        }
      },
      createServer: {
        stateStartup: function() {
          middleware.getMiddleware(options, function(err, _middleware, _rest) {
            if (err) fsm.fire("error", err); else {
              var mirror = null,
                sem = 0,
                tlsOptions;

              //stash the rest interface
              cache.setItem("feather-rest", _rest);

              //defer final server setup until SSL/mirroring is sorted out below
              var completeServerSetup = function() {
                //create the underlying Connect server instance
                var server = Connect();
                _.each(_middleware, function(ware) {
                  server.use(ware);
                });

                // configure session path ignores
                if (options.session.ignorePaths && server.session) {
                  var si = options.session.ignorePaths.length-1;
                  while (si >= 0) {
                    server.session.ignore.push(options.session.ignorePaths[si]);
                    si -= 1;
                  }
                }

                //start listening
                var port = options.port;
                if (options.ssl && options.ssl.enabled && options.ssl.port) port = options.ssl.port;

                if (options.ssl) {
                  server.httpServer = https.createServer(tlsOptions, server).listen(port);
                } else {
                  server.httpServer = server.listen(port);
                }

                if (options.daemon.runAsDaemon == true && options.daemon.runAsUser) {
                  console.log("Setting uid to " + options.daemon.runAsUser);
                  process.setuid(options.daemon.runAsUser);
                  console.log("Server uid is now " + process.getuid());

                  if (options.daemon.runAsDaemon == true && options.daemon.runAsGroup) {
                    console.log("Setting gid to " + options.daemon.runAsGroup);
                    process.setgid(options.daemon.runAsGroup);
                    console.log("Server gid is now " + process.getgid());
                  }
                }

                fsm.fire("complete", server, mirror);
              };

              //use ssl?
              if (options.ssl && options.ssl.enabled) {
                if (options.ssl.routes && (!options.ssl.port || options.ssl.port == options.port)) throw new Error("When explicit SSL routes are defined, you must also specify a value for ssl.port which must be different from the non-SSL port.");

                tlsOptions = {
                  key: fs.readFileSync(options.ssl.key),
                  cert: fs.readFileSync(options.ssl.cert)
                };
                if (options.ssl.ca) {
                  tlsOptions.ca = [];
                  _.each(options.ssl.ca, function(ca) {
                    var certs = fs.readFileSync(ca);
                    tlsOptions.ca.push(certs);
                  });
                }
                _middleware.unshift(tlsOptions);

                if (options.ssl.useRedirectServer && !options.ssl.routes) {
                  //ssl is configured as "strict, always on" - i.e. no explicit ssl routes are defined,
                  //therefore, the 'mirror' server on the redirect port need only be a 'throw-away' shim that redirects all requests to SSL
                  var redirectServer = Connect(
                    function(req, res, next) {
                      //do the redirect
                      res.statusCode = 302;
                      var host = options.host;
                      //if ssl port is non-standard (443), make sure it gets included in the redirect url
                      host += options.ssl.port === 443 ? "" : ":" + options.ssl.port;
                      res.setHeader("Location", "https://" + host + req.url);
                      res.end();
                    }
                  );
                  redirectServer.listen(options.ssl.redirectServerPort);
                } else if (options.ssl.routes) {
                  //ssl is defined as only _enforced_ for a subset of routes (all routes MAY still use https, but these routes MUST use it),
                  //therefore we must create a full mirror server that has logic to force-redirect to ssl for specific routes

                  sem++; //indicate final server setup needs to be deferred

                  //get another copy of the middleware stack for the mirror
                  middleware.getMiddleware(options, function(err, __middleware, __rest) {
                    //stash the mirror's rest interface
                    cache.setItem("feather-rest-mirror", __rest);

                    //add the SSL route enforcement middleware module at the top of the new stack
                    __middleware.unshift(connectRouter(function(app) {
                      _.each(options.ssl.routes, function(route) {
                        _.each(connectRouter.methods, function(verb) {
                          (app[verb])(new RegExp(route), function(req, res, next) {
                            //do the redirect
                            res.statusCode = 302;
                            var host = options.host;
                            //if ssl port is non-standard (443), make sure it gets included in the redirect url
                            host += options.ssl.port === 443 ? "" : ":" + options.ssl.port;
                            res.setHeader("Location", "https://" + host + req.url);
                            res.end();
                          });
                        });
                      });
                    }));

                    //spin up mirror and complete server setup
                    mirror = Connect();
                    _.each(__middleware, function(ware) {
                      mirror.use(ware);
                    });
                    mirror.listen(options.port);
                    completeServerSetup();
                  });
                }
              }

              if (sem === 0) completeServerSetup();
            }
          });
        },
        complete: function() {
          return this.states.complete;
        }
      }, //end createServer state
      complete: {
        stateStartup: function(server, mirror) {
          cb(null, server, mirror);
          fsm.dispose();
        }
      },
      error: {
        stateStartup: function(err) {
          console.log(err);
          cb(err);
          fsm.dispose();
        }
      }
    }
  });
};<commit_msg>bah, missed obvious check<commit_after>var tls             = require("tls"),
    fs              = require("fs"),
    http            = require("http"),
    https           = require("https"),
    Connect         = require("connect"),
    EventPublisher  = require("./event-publisher"),
    FSM             = require("./fsm"),
    Semaphore       = require("./semaphore"),
    indexer         = require("./file-indexer"),
    parser          = require("./parser"),
    fileWatcher     = require("./filewatcher"),
    middleware      = require("./middleware"),
    cache           = require("./simple-cache"),
    _               = require("underscore")._,
    restProxy       = require("./restProxy"),
    connectRouter   = require("./router_connect");

exports.init = function(options, cb) {

  //use a state machine to package/parse required application resources
  var fsm = new FSM({
    states: {
      initial: {
        stateStartup: function() {
          // - index the application's files and directories
          indexer.index(options, function(err, indexedFiles) {
            if (err) fsm.fire("error", err); else {
              cache.setItem("feather-files", indexedFiles);

              if (indexedFiles.restFiles && options.rest && options.rest.autoGenerateProxy) {
                fsm.fire("generateRestProxy", indexedFiles);
              } else {
                fsm.fire("parseFeatherFiles", indexedFiles, null);
              }
            }
          });
        },
        generateRestProxy: function(indexedFiles) {
          restProxy.generateProxy({
            appOptions: options,
            files: indexedFiles.restFiles
          }, function(err, restProxyInfo) {
            if (err) cb(err); else {
              fsm.fire("parseFeatherFiles", indexedFiles, restProxyInfo);
            }
          });
        },
        parseFeatherFiles: function(indexedFiles, restProxyInfo) {
          // - pre-parse all feather.html files
          // - move the stateMachine to the next state
          var sem = new Semaphore(function() {
            fsm.fire("parsingComplete");
          });
          //parse the .feather.html files in the app
          _.each(_.keys(indexedFiles.featherFiles), function(_path) {
            sem.increment();
            //guarantee all files get counted in semaphore
            process.nextTick(function() {
              parser.parseFile({
                restProxyInfo: restProxyInfo,
                path: _path,
                request: {page: _path.replace(/.*\/public\/(.*)$/, "$1")} //need a dummy request object for parser since there is no real request at this point
              }, function(err, render) {
                  if (err) throw new Error(JSON.stringify(err)); else {
                    indexedFiles.featherFiles[_path].render = render;
                    //now, if this file changes on disk, invalidate and remove the compiled renderer until the next request
                    if (!indexedFiles.featherFiles[_path].watchingFile) { //only wire the watcher once
                      fileWatcher.watchFileMtime(_path, function(args) {
                        indexedFiles.featherFiles[_path].render = null;
                      });
                      indexedFiles.featherFiles[_path].watchingFile = true;
                    }
                    sem.execute();
                  }
              });
            });
          });
        },
        parsingComplete: function() {
          return fsm.states.createServer;
        }
      },
      createServer: {
        stateStartup: function() {
          middleware.getMiddleware(options, function(err, _middleware, _rest) {
            if (err) fsm.fire("error", err); else {
              var mirror = null,
                sem = 0,
                tlsOptions;

              //stash the rest interface
              cache.setItem("feather-rest", _rest);

              //defer final server setup until SSL/mirroring is sorted out below
              var completeServerSetup = function() {
                //create the underlying Connect server instance
                var server = Connect();
                _.each(_middleware, function(ware) {
                  server.use(ware);
                });

                // configure session path ignores
                if (options.session.ignorePaths && server.session) {
                  var si = options.session.ignorePaths.length-1;
                  while (si >= 0) {
                    server.session.ignore.push(options.session.ignorePaths[si]);
                    si -= 1;
                  }
                }

                //start listening
                var port = options.port;
                if (options.ssl && options.ssl.enabled && options.ssl.port) port = options.ssl.port;

                if (options.ssl && options.ssl.enabled) {
                  server.httpServer = https.createServer(tlsOptions, server).listen(port);
                } else {
                  server.httpServer = server.listen(port);
                }

                if (options.daemon.runAsDaemon == true && options.daemon.runAsUser) {
                  console.log("Setting uid to " + options.daemon.runAsUser);
                  process.setuid(options.daemon.runAsUser);
                  console.log("Server uid is now " + process.getuid());

                  if (options.daemon.runAsDaemon == true && options.daemon.runAsGroup) {
                    console.log("Setting gid to " + options.daemon.runAsGroup);
                    process.setgid(options.daemon.runAsGroup);
                    console.log("Server gid is now " + process.getgid());
                  }
                }

                fsm.fire("complete", server, mirror);
              };

              //use ssl?
              if (options.ssl && options.ssl.enabled) {
                if (options.ssl.routes && (!options.ssl.port || options.ssl.port == options.port)) throw new Error("When explicit SSL routes are defined, you must also specify a value for ssl.port which must be different from the non-SSL port.");

                tlsOptions = {
                  key: fs.readFileSync(options.ssl.key),
                  cert: fs.readFileSync(options.ssl.cert)
                };
                if (options.ssl.ca) {
                  tlsOptions.ca = [];
                  _.each(options.ssl.ca, function(ca) {
                    var certs = fs.readFileSync(ca);
                    tlsOptions.ca.push(certs);
                  });
                }
                _middleware.unshift(tlsOptions);

                if (options.ssl.useRedirectServer && !options.ssl.routes) {
                  //ssl is configured as "strict, always on" - i.e. no explicit ssl routes are defined,
                  //therefore, the 'mirror' server on the redirect port need only be a 'throw-away' shim that redirects all requests to SSL
                  var redirectServer = Connect(
                    function(req, res, next) {
                      //do the redirect
                      res.statusCode = 302;
                      var host = options.host;
                      //if ssl port is non-standard (443), make sure it gets included in the redirect url
                      host += options.ssl.port === 443 ? "" : ":" + options.ssl.port;
                      res.setHeader("Location", "https://" + host + req.url);
                      res.end();
                    }
                  );
                  redirectServer.listen(options.ssl.redirectServerPort);
                } else if (options.ssl.routes) {
                  //ssl is defined as only _enforced_ for a subset of routes (all routes MAY still use https, but these routes MUST use it),
                  //therefore we must create a full mirror server that has logic to force-redirect to ssl for specific routes

                  sem++; //indicate final server setup needs to be deferred

                  //get another copy of the middleware stack for the mirror
                  middleware.getMiddleware(options, function(err, __middleware, __rest) {
                    //stash the mirror's rest interface
                    cache.setItem("feather-rest-mirror", __rest);

                    //add the SSL route enforcement middleware module at the top of the new stack
                    __middleware.unshift(connectRouter(function(app) {
                      _.each(options.ssl.routes, function(route) {
                        _.each(connectRouter.methods, function(verb) {
                          (app[verb])(new RegExp(route), function(req, res, next) {
                            //do the redirect
                            res.statusCode = 302;
                            var host = options.host;
                            //if ssl port is non-standard (443), make sure it gets included in the redirect url
                            host += options.ssl.port === 443 ? "" : ":" + options.ssl.port;
                            res.setHeader("Location", "https://" + host + req.url);
                            res.end();
                          });
                        });
                      });
                    }));

                    //spin up mirror and complete server setup
                    mirror = Connect();
                    _.each(__middleware, function(ware) {
                      mirror.use(ware);
                    });
                    mirror.listen(options.port);
                    completeServerSetup();
                  });
                }
              }

              if (sem === 0) completeServerSetup();
            }
          });
        },
        complete: function() {
          return this.states.complete;
        }
      }, //end createServer state
      complete: {
        stateStartup: function(server, mirror) {
          cb(null, server, mirror);
          fsm.dispose();
        }
      },
      error: {
        stateStartup: function(err) {
          console.log(err);
          cb(err);
          fsm.dispose();
        }
      }
    }
  });
};<|endoftext|>


<commit_before>'use strict';

var webpack = require('webpack');
var path = require('path');
var extractTextPlugin = require('extract-text-webpack-plugin');

var commonsPlugin = new webpack.optimize.CommonsChunkPlugin('common.js');
var noErrorsPlugin = new webpack.NoErrorsPlugin();
var extractCss = new extractTextPlugin('../styles/style.css');

var NODE_ENV = process.env.NODE_ENV || 'production'; // eslint-disable-line no-process-env

var entries = {
  frontpage: './src/client/components/FrontPage/index.js',
  header: './src/client/components/Header/index.js',
  footer: './src/client/components/Footer/index.js',
  login: './src/client/components/Login/index.js',
  order: './src/client/components/Order/index.js',
  profile: './src/client/components/Profile/index.js',
  querysearch: './src/client/components/searchpage/index.js',
  receipt: './src/client/components/Receipt/index.js',
  work: './src/client/components/Work/Work.client',
  news: './src/client/components/News/NewsPage.index',
  libraries: './src/client/components/LibraryAffiliateList/index.js',
  event: './src/client/components/Calendar/EventPage.index',
  styles: './src/client/styles/ddb.scss'
};

if (NODE_ENV === 'development') {
  entries.terminal = './src/utils/Terminal';
}

module.exports = [{
  name: 'browser',

  entry: entries,

  output: {
    path: path.join(__dirname, 'public/js'),
    filename: '[name].js'
  },

  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader'
      },
      {
        test: /\.scss$/,
        loader: extractTextPlugin.extract(
          // activate source maps via loader query
          'css?sourceMap!' +
          'sass?sourceMap'
        )
      }
    ]
  },

  externals: {
    react: 'React',
    'react-dom': 'ReactDOM',
    lodash: '_',
    newrelic: 'newrelic'
  },

  plugins: [
    commonsPlugin,
    extractCss,
    noErrorsPlugin
  ],

  watchOptions: {
    poll: true
  },

  node: {
    fs: 'empty',
    tls: 'empty'
  }
}];
<commit_msg>Removed unused ddb.scss<commit_after>'use strict';

var webpack = require('webpack');
var path = require('path');
var extractTextPlugin = require('extract-text-webpack-plugin');

var commonsPlugin = new webpack.optimize.CommonsChunkPlugin('common.js');
var noErrorsPlugin = new webpack.NoErrorsPlugin();
var extractCss = new extractTextPlugin('../styles/style.css');

var NODE_ENV = process.env.NODE_ENV || 'production'; // eslint-disable-line no-process-env

var entries = {
  frontpage: './src/client/components/FrontPage/index.js',
  header: './src/client/components/Header/index.js',
  footer: './src/client/components/Footer/index.js',
  login: './src/client/components/Login/index.js',
  order: './src/client/components/Order/index.js',
  profile: './src/client/components/Profile/index.js',
  querysearch: './src/client/components/searchpage/index.js',
  receipt: './src/client/components/Receipt/index.js',
  work: './src/client/components/Work/Work.client',
  news: './src/client/components/News/NewsPage.index',
  libraries: './src/client/components/LibraryAffiliateList/index.js',
  event: './src/client/components/Calendar/EventPage.index',
};

if (NODE_ENV === 'development') {
  entries.terminal = './src/utils/Terminal';
}

module.exports = [{
  name: 'browser',

  entry: entries,

  output: {
    path: path.join(__dirname, 'public/js'),
    filename: '[name].js'
  },

  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader'
      },
      {
        test: /\.scss$/,
        loader: extractTextPlugin.extract(
          // activate source maps via loader query
          'css?sourceMap!' +
          'sass?sourceMap'
        )
      }
    ]
  },

  externals: {
    react: 'React',
    'react-dom': 'ReactDOM',
    lodash: '_',
    newrelic: 'newrelic'
  },

  plugins: [
    commonsPlugin,
    extractCss,
    noErrorsPlugin
  ],

  watchOptions: {
    poll: true
  },

  node: {
    fs: 'empty',
    tls: 'empty'
  }
}];
<|endoftext|>


<commit_before>import http from 'http';
import cluster from 'cluster';
import Logger from 'werelogs';
import bunyanLogstash from 'bunyan-logstash';

import Config from './Config';
import routes from './routes';

const _config = new Config();

const logger = new Logger('S3', {
    level: _config.log.logLevel,
    dump: _config.log.dumpLevel,
    streams: [
        { stream: process.stdout },
        {
            type: 'raw',
            stream: bunyanLogstash.createStream({
                host: _config.log.logstash.host,
                port: _config.log.logstash.port,
            }),
        },
    ],
});

class S3Server {
    /**
     * This represents our S3 connector.
     * @constructor
     * @param {Worker} [worker=null] - Track the worker when using cluster
     */
    constructor(worker) {
        this.worker = worker;
        http.globalAgent.keepAlive = true;

        process.on('SIGINT', this.cleanUp.bind(this));
        process.on('SIGHUP', this.cleanUp.bind(this));
        process.on('SIGQUIT', this.cleanUp.bind(this));
        process.on('SIGTERM', this.cleanUp.bind(this));
        process.on('SIGPIPE', () => {});
    }

    /*
     * This starts the http server.
     */
    startup() {
        // Todo: http.globalAgent.maxSockets, http.globalAgent.maxFreeSockets

        this.server = http.createServer((req, res) => {
            // This will pick up exceptions up the stack
            process.on('uncaughtException', err => {
                // If just send the error object results in empty
                // object on server log.
                logger.fatal('caught error', { error: err.message,
                    stack: err.stack });
                this.caughtExceptionShutdown();
                res.statusCode = 500;
                res.end();
            });
            routes(req, res, logger);
        });
        this.server.on('listening', () => {
            const addr = this.server.address() || {
                address: '0.0.0.0',
                port: _config.port,
            };
            logger.info('server started', { address: addr.address,
                port: addr.port, pid: process.pid });
        });
        this.server.listen(_config.port);
    }

    /*
     * This exits the running process properly.
     */
    cleanUp() {
        logger.info('server shutting down');
        this.server.close();
        process.exit(0);
    }

    caughtExceptionShutdown() {
        logger.error('shutdown of worker due to exception');
        // Will close all servers, cause disconnect event on master and kill
        // worker process with 'SIGTERM'.
        this.worker.kill();
        const killTimer = setTimeout(() => {
            if (!this.worker.isDead()) {
                this.worker.kill('SIGKILL');
            }
        }, 2000);
        killTimer.unref();
    }
}

export default function main() {
    if (_config.clustering && cluster.isMaster && !process.env.S3BACKEND) {
        for (let n = 0; n < _config.clusters; n++) {
            cluster.fork();
        }
        setInterval(() => {
            const len = Object.keys(cluster.workers).length;
            if (len < _config.clusters) {
                for (let i = len; i < _config.clusters; i++) {
                    const newWorker = cluster.fork();
                    logger.error('new worker forked',
                    { workerId: newWorker.id });
                }
            }
        }, 1000);
        cluster.on('disconnect', worker => {
            logger.error('worker disconnected. making sure exits',
                { workerId: worker.id });
            setTimeout(() => {
                if (!worker.isDead()) {
                    logger.error('worker not exiting. killing it');
                    worker.process.kill('SIGKILL');
                }
            }, 2000);
        });
        cluster.on('exit', worker => {
            logger.error('worker exited.',
                { workerId: worker.id });
        });
    } else if (cluster.isWorker) {
        const server = new S3Server(cluster.worker);
        server.startup();
    } else {
        const server = new S3Server;
        server.startup();
    }
}
<commit_msg>Move event listener out of server callback.<commit_after>import http from 'http';
import cluster from 'cluster';
import Logger from 'werelogs';
import bunyanLogstash from 'bunyan-logstash';

import Config from './Config';
import routes from './routes';

const _config = new Config();

const logger = new Logger('S3', {
    level: _config.log.logLevel,
    dump: _config.log.dumpLevel,
    streams: [
        { stream: process.stdout },
        {
            type: 'raw',
            stream: bunyanLogstash.createStream({
                host: _config.log.logstash.host,
                port: _config.log.logstash.port,
            }),
        },
    ],
});

class S3Server {
    /**
     * This represents our S3 connector.
     * @constructor
     * @param {Worker} [worker=null] - Track the worker when using cluster
     */
    constructor(worker) {
        this.worker = worker;
        http.globalAgent.keepAlive = true;

        process.on('SIGINT', this.cleanUp.bind(this));
        process.on('SIGHUP', this.cleanUp.bind(this));
        process.on('SIGQUIT', this.cleanUp.bind(this));
        process.on('SIGTERM', this.cleanUp.bind(this));
        process.on('SIGPIPE', () => {});
        // This will pick up exceptions up the stack
        process.on('uncaughtException', err => {
            // If just send the error object results in empty
            // object on server log.
            logger.fatal('caught error', { error: err.message,
                stack: err.stack });
            this.caughtExceptionShutdown();
        });
    }

    /*
     * This starts the http server.
     */
    startup() {
        // Todo: http.globalAgent.maxSockets, http.globalAgent.maxFreeSockets

        this.server = http.createServer((req, res) => {
            routes(req, res, logger);
        });
        this.server.on('listening', () => {
            const addr = this.server.address() || {
                address: '0.0.0.0',
                port: _config.port,
            };
            logger.info('server started', { address: addr.address,
                port: addr.port, pid: process.pid });
        });
        this.server.listen(_config.port);
    }

    /*
     * This exits the running process properly.
     */
    cleanUp() {
        logger.info('server shutting down');
        this.server.close();
        process.exit(0);
    }

    caughtExceptionShutdown() {
        logger.error('shutdown of worker due to exception');
        // Will close all servers, cause disconnect event on master and kill
        // worker process with 'SIGTERM'.
        this.worker.kill();
        const killTimer = setTimeout(() => {
            if (!this.worker.isDead()) {
                this.worker.kill('SIGKILL');
            }
        }, 2000);
        killTimer.unref();
    }
}

export default function main() {
    if (_config.clustering && cluster.isMaster && !process.env.S3BACKEND) {
        for (let n = 0; n < _config.clusters; n++) {
            cluster.fork();
        }
        setInterval(() => {
            const len = Object.keys(cluster.workers).length;
            if (len < _config.clusters) {
                for (let i = len; i < _config.clusters; i++) {
                    const newWorker = cluster.fork();
                    logger.error('new worker forked',
                    { workerId: newWorker.id });
                }
            }
        }, 1000);
        cluster.on('disconnect', worker => {
            logger.error('worker disconnected. making sure exits',
                { workerId: worker.id });
            setTimeout(() => {
                if (!worker.isDead()) {
                    logger.error('worker not exiting. killing it');
                    worker.process.kill('SIGKILL');
                }
            }, 2000);
        });
        cluster.on('exit', worker => {
            logger.error('worker exited.',
                { workerId: worker.id });
        });
    } else if (cluster.isWorker) {
        const server = new S3Server(cluster.worker);
        server.startup();
    } else {
        const server = new S3Server;
        server.startup();
    }
}
<|endoftext|>


<commit_before>const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const NpmInstallPlugin = require('npm-install-webpack-plugin');
const BellOnBundlerErrorPlugin = require('bell-on-bundler-error-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');

module.exports = {

  entry: './index.js',

  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[hash].bundle.js',
    publicPath: '/',
    library: 'eq3',
    libraryTarget: 'var'
  },

  module: {
    rules: [
      {
        test: /\.js?$/,
        exclude: /(node_modules)/,
        loader: 'babel-loader',
        options: {
          presets: [ 'react', 'es2015', 'stage-0', 'stage-1' ],
          plugins: [ 'transform-decorators-legacy', 'transform-object-assign', 'transform-class-properties' ]
        }
      },
      {
        test: /\.html?$/,
        loader: 'html-loader'
      }
    ]
  },

  resolve: {
    modules: [
      path.resolve( __dirname, 'node_modules'),
      path.resolve( __dirname, 'src')
    ],
    extensions: ['.js', '.json', '.jsx', '.css']
  },

  performance: {
    hints: 'warning', // enum
    maxAssetSize: 200000, // int (in bytes),
    maxEntrypointSize: 400000, // int (in bytes)
    assetFilter: function(assetFilename) {
      // Function predicate that provides asset filenames
      return assetFilename.endsWith('.css') || assetFilename.endsWith('.js');
    }
  },

  devtool: 'source-map', // enum
  // enhance debugging by adding meta info for the browser devtools
  // source-map most detailed at the expense of build speed.

  context: path.resolve( __dirname ), // string (absolute path!)
  // the home directory for webpack
  // the entry and module.rules.loader option
  //   is resolved relative to this directory

  target: 'web', // enum
  // the environment in which the bundle should run
  // changes chunk loading behavior and available modules

  // externals: [ 'react', /^@angular\// ],
  // Don't follow/bundle these modules, but request them at runtime from the environment

  stats: {
    colors: true,
    reasons: true
  },
  // 'errors-only',
  // lets you precisely control what bundle information gets displayed

  devServer: {
    outputPath: path.join(__dirname, 'dist'), // old version of dev server
    contentBase: [path.join(__dirname, 'dist'),path.join(__dirname)], // boolean | string | array, static file location
    compress: true, // enable gzip compression
    historyApiFallback: true, // true for index.html upon 404, object for multiple paths
    hot: true, // hot module replacement. Depends on HotModuleReplacementPlugin
    https: false, // true for self-signed, object for cert authority
    noInfo: true, // only errors & warns on hot reload
    port: 8080,
    colors: true,
    inline: true,
    progress: true,
    //   // contentBase:  [outPath,cssOutPath,jsOutPath],
    host: '0.0.0.0',
    //   historyApiFallback: true,
    clientLogLevel: 'info'
  },

  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify(process.env.NODE_ENV),
      },
    }),
    // new webpack.ProvidePlugin({
    //   'Promise': 'promise'
    // }),
    new CopyWebpackPlugin(
      [{
        from: path.join(__dirname, 'css'),
        to: path.join(__dirname, 'dist', 'css')
      },
        {
          from: path.join(__dirname, 'fonts'),
          to: path.join(__dirname, 'dist', 'fonts')
        },
        {
          from: path.join(__dirname, 'scripts'),
          to: path.join(__dirname, 'dist', 'scripts ')
        },
        {
          from: path.join(__dirname, 'js'),
          to: path.join(__dirname, 'dist', 'js')
        }
      ],
      {
        copyUnmodified: true
      }),

    new BellOnBundlerErrorPlugin(),
    // new webpack.ProvidePlugin({
    //   // polyfill for Promise
    //   'Promise': 'exports?global.Promise!es6-promise',
    //   // polyfill for fetch
    //   'fetch': 'imports?this=>global!exports?global.fetch!isomorphic-fetch'
    // }),
    // new NpmInstallPlugin(),
    // new webpack.SourceMapDevToolPlugin({
    //   filename: '[file].map'
    // }),
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'index.html'
    })
  ]

};
<commit_msg>update lib to rrpt<commit_after>const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const NpmInstallPlugin = require('npm-install-webpack-plugin');
const BellOnBundlerErrorPlugin = require('bell-on-bundler-error-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');

module.exports = {

  entry: './index.js',

  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[hash].bundle.js',
    publicPath: '/',
    library: 'rrpt',
    libraryTarget: 'var'
  },

  module: {
    rules: [
      {
        test: /\.js?$/,
        exclude: /(node_modules)/,
        loader: 'babel-loader',
        options: {
          presets: [ 'react', 'es2015', 'stage-0', 'stage-1' ],
          plugins: [ 'transform-decorators-legacy', 'transform-object-assign', 'transform-class-properties' ]
        }
      },
      {
        test: /\.html?$/,
        loader: 'html-loader'
      }
    ]
  },

  resolve: {
    modules: [
      path.resolve( __dirname, 'node_modules'),
      path.resolve( __dirname, 'src')
    ],
    extensions: ['.js', '.json', '.jsx', '.css']
  },

  performance: {
    hints: 'warning', // enum
    maxAssetSize: 200000, // int (in bytes),
    maxEntrypointSize: 400000, // int (in bytes)
    assetFilter: function(assetFilename) {
      // Function predicate that provides asset filenames
      return assetFilename.endsWith('.css') || assetFilename.endsWith('.js');
    }
  },

  devtool: 'source-map', // enum
  // enhance debugging by adding meta info for the browser devtools
  // source-map most detailed at the expense of build speed.

  context: path.resolve( __dirname ), // string (absolute path!)
  // the home directory for webpack
  // the entry and module.rules.loader option
  //   is resolved relative to this directory

  target: 'web', // enum
  // the environment in which the bundle should run
  // changes chunk loading behavior and available modules

  // externals: [ 'react', /^@angular\// ],
  // Don't follow/bundle these modules, but request them at runtime from the environment

  stats: {
    colors: true,
    reasons: true
  },
  // 'errors-only',
  // lets you precisely control what bundle information gets displayed

  devServer: {
    outputPath: path.join(__dirname, 'dist'), // old version of dev server
    contentBase: [path.join(__dirname, 'dist'),path.join(__dirname)], // boolean | string | array, static file location
    compress: true, // enable gzip compression
    historyApiFallback: true, // true for index.html upon 404, object for multiple paths
    hot: true, // hot module replacement. Depends on HotModuleReplacementPlugin
    https: false, // true for self-signed, object for cert authority
    noInfo: true, // only errors & warns on hot reload
    port: 8080,
    colors: true,
    inline: true,
    progress: true,
    //   // contentBase:  [outPath,cssOutPath,jsOutPath],
    host: '0.0.0.0',
    //   historyApiFallback: true,
    clientLogLevel: 'info'
  },

  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify(process.env.NODE_ENV),
      },
    }),
    // new webpack.ProvidePlugin({
    //   'Promise': 'promise'
    // }),
    new CopyWebpackPlugin(
      [{
        from: path.join(__dirname, 'css'),
        to: path.join(__dirname, 'dist', 'css')
      },
        {
          from: path.join(__dirname, 'fonts'),
          to: path.join(__dirname, 'dist', 'fonts')
        },
        {
          from: path.join(__dirname, 'scripts'),
          to: path.join(__dirname, 'dist', 'scripts ')
        },
        {
          from: path.join(__dirname, 'js'),
          to: path.join(__dirname, 'dist', 'js')
        }
      ],
      {
        copyUnmodified: true
      }),

    new BellOnBundlerErrorPlugin(),
    // new webpack.ProvidePlugin({
    //   // polyfill for Promise
    //   'Promise': 'exports?global.Promise!es6-promise',
    //   // polyfill for fetch
    //   'fetch': 'imports?this=>global!exports?global.fetch!isomorphic-fetch'
    // }),
    // new NpmInstallPlugin(),
    // new webpack.SourceMapDevToolPlugin({
    //   filename: '[file].map'
    // }),
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'index.html'
    })
  ]

};
<|endoftext|>


<commit_before>/**
 * @yag/is-array
 *
 * @copyright Copyright (c) 2017 - 2018, Yassel Avila Gil (http://yasselavila.com)
 * @license   BSD 3 Clause (see LICENSE.txt)
 * @link      https://github.com/yasselavila/js-is-array
 */

const { env } = require('process');
const path = require('path');

const { EnvironmentPlugin, LoaderOptionsPlugin } = require('webpack');
const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin');
const { CheckerPlugin } = require('awesome-typescript-loader');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

/* Env */
const nodeEnv = env.NODE_ENV || 'production';
const isProd = ('production' === nodeEnv);

/* Plugins */
const plugins = [
  /* Check and emit types in a separate process */
  new CheckerPlugin(),
  /* Make sure all dependencies are built in production mode */
  new EnvironmentPlugin({
    NODE_ENV: nodeEnv,
    DEBUG: !isProd
  }),
  /* Enable module concatenation */
  new ModuleConcatenationPlugin(),
  /* Enable minify */
  new LoaderOptionsPlugin({
    minimize: isProd,
    debug: !isProd
  })
];

/* Minify the ouput */
if (isProd) {
  plugins.push(
    new UglifyJsPlugin({
      uglifyOptions: {
        ecma: 5,
        ie8: true,
        output: {
          comments: false,
          beautify: false
        }
      }
    })
  );
}

/*
 * Export config
 */
module.exports = {
  entry: {
    'isarray': path.resolve('src/index')
  },
  output: {
    path: path.resolve('dist/bundles'),
    filename: '[name].umd.bundle.js',
    sourceMapFilename: '[name].umd.bundle.js.map',
    chunkFilename: '[name].umd.[chunk].js',
    libraryTarget: 'umd',
    pathinfo: !isProd
  },
  resolve: {
    extensions: ['.ts', '.tsx']
  },
  module: {
    loaders: [
      {
        test: /\.tsx?$/,
        loader: 'awesome-typescript-loader'
      }
    ]
  },
  plugins: plugins
};
<commit_msg>Update Webpack config<commit_after>/**
 * @yag/is-array
 *
 * @copyright Copyright (c) 2017 - 2018, Yassel Avila Gil (http://yasselavila.com)
 * @license   BSD 3 Clause (see LICENSE.txt)
 * @link      https://github.com/yasselavila/js-is-array
 */

const { env } = require('process');
const path = require('path');

const { EnvironmentPlugin, LoaderOptionsPlugin } = require('webpack');
const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin');
const { CheckerPlugin } = require('awesome-typescript-loader');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

/* Env */
const nodeEnv = env.NODE_ENV || 'production';
const isProd = ('production' === nodeEnv);

/* Plugins */
const plugins = [
  /* Check and emit types in a separate process */
  new CheckerPlugin(),
  /* Make sure all dependencies are built in production mode */
  new EnvironmentPlugin({
    NODE_ENV: nodeEnv,
    DEBUG: !isProd
  }),
  /* Enable module concatenation */
  new ModuleConcatenationPlugin(),
  /* Enable minify */
  new LoaderOptionsPlugin({
    minimize: isProd,
    debug: !isProd
  })
];

/* Minify the ouput */
if (isProd) {
  plugins.push(
    new UglifyJsPlugin({
      uglifyOptions: {
        ecma: 5,
        ie8: true,
        output: {
          comments: false,
          beautify: false
        }
      }
    })
  );
}

/*
 * Export config
 */
module.exports = {
  mode: isProd ? 'production' : 'development',
  entry: {
    'isarray': path.resolve('src/index')
  },
  output: {
    path: path.resolve(__dirname, 'dist', 'bundles'),
    filename: '[name].umd.bundle.js',
    sourceMapFilename: '[name].umd.bundle.js.map',
    chunkFilename: '[name].umd.[chunk].js',
    libraryTarget: 'umd',
    pathinfo: !isProd
  },
  resolve: {
    extensions: ['.ts', '.tsx']
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        loader: 'awesome-typescript-loader'
      }
    ]
  },
  plugins: plugins
};
<|endoftext|>


<commit_before>// -*- indent-tabs-mode: nil; js2-basic-offset: 2 -*-

var SelectQuery = require('../../select-query').SelectQuery;
var IndexField = require('../../database').IndexField;
var logger = require('../../logger');

var dummyRid = '000000000000000000000000000000000000000000000000000000000000000';

function formatFacets(data) {
  var drilldownRecords = data.slice(1);

  return drilldownRecords.map(function(drilldownRecord, index) {
    return formatFacet(drilldownRecord);
  });
}

function formatFacet(drilldownRecord) {
  var columnList = drilldownRecord[1];
  var columnNames = columnList.map(function(column) {
    return column[0];
  });

  var constraintEntries = drilldownRecord.slice(2);
  var constraints = constraintEntries.map(function(record) {
    var object = {};
    columnNames.forEach(function(columnName, index) {
      object[columnName] = record[index];
    });
    return {value: object._key, count: object._nsubrecs};
  });

  return {constraints: constraints};
}

function formatSelectResults(data, selectQuery) {
  var columnList = data[0][1];
  var columnNames = columnList.map(function(column) {
    return column[0];
  });

  var records = data[0].slice(2);
  var results = records.map(function(record) {
    var result = {};
    var data = {};

    columnNames.forEach(function(columnName, index) {
      // bind internal "_key" column to the "id"
      if (columnName == '_key') {
        result.id = record[index];
        return;
      }
      // don't expose any internal column
      if (columnName[0] == '_') return;

      var fieldName = IndexField.toFieldName(columnName);
      if (Array.isArray(record[index])) {
        // vector column
        data[fieldName] = record[index];
      } else {
        // scalar column
        data[fieldName] = [record[index]];
      }
    });

    selectQuery.emptyReturnFields.forEach(function(fieldName) {
      data[fieldName] = [];
    });

    if (selectQuery.returnFields.length)
      result.data = data;

    return result;
  });
  return results;
}

function select(context, selectQuery, callback) {
  if (selectQuery.noResult) {
    callback(null, [], 0, []);
    return;
  }
  context.command('select', selectQuery.selectOptions, function(error, data) {
    if (error) {
      callback(error);
    } else {
      var numFoundRecords = data[0][0][0];
      callback(
        null,
        formatSelectResults(data, selectQuery),
        numFoundRecords,
        formatFacets(data)
      );
    }
  });
}

function createResultBody(options) {
  var info = {
    rid:           dummyRid,
    'time-ms':     options.elapsedTime || 0,
    'cpu-time-ms': 0 // TODO
  };
  return {
    rank: options.rankExpression,
    'match-expr': options.matchExpression,
    hits: {
      found: options.found,
      start: options.start,
      hit:   options.hit
    },
    info: info
  };
}

function createErrorBody(options) {
  var messages = [];
  if (options.messages) {
    messages = options.messages;
  } else {
    messages.push({
      severity: 'fatal',
      code:     '',
      message:  options.message || ''
    });
  }
  return {
    error:         'info',
    rid:           options.rid,
    'time-ms':     options.elapsedTime || 0,
    'cpu-time-ms': 0, // TODO
    messages:      messages
  };
}

exports.createHandler = function(context, config) {
  return function(request, response) {
    var startedAt = new Date();

    var selectQuery;
    try {
      selectQuery = new SelectQuery(request, context);
    } catch(error) {
      logger.error(error);

      var errorData = { rid: dummyRid };
      if (error.message == 'validation error') {
        errorData.messages = [error.data];
      } else {
        errorData.message = 'Invalid ' + error.queryType + ' value: ' + (error.message || error) + error.stack;
      }
      var body = createErrorBody(errorData);
      return response.send(body, 400);
    }

    select(context, selectQuery,
      function(error, data, numFoundRecords, facets) {
        if (error)
          logger.error(error);

        var finishedAt = new Date();
        var elapsedTime = finishedAt.getTime() - startedAt.getTime();

        logger.query(selectQuery, elapsedTime);

        if (error) {
          var body = createErrorBody({
            rid:         dummyRid,
            message:     error.message,
            elapsedTime: elapsedTime
          });
          return response.send(body, 400); // TODO
        }
        var result = createResultBody({
          matchExpression: selectQuery.matchExpression,
          rankExpression:  selectQuery.rankExpression,
          found:           numFoundRecords,
          start:           selectQuery.start,
          hit:             data,
          elapsedTime:     elapsedTime
        });
        if (selectQuery.facets.length) {
          var facetsObject = {};
          facets.forEach(function(facet, index) {
            var fieldName = selectQuery.availableFacets[index];
            facetsObject[fieldName] = facet;
          });
          selectQuery.emptyFacets.forEach(function(fieldName) {
            facetsObject[fieldName] = {};
          });
          result.facets = facetsObject;
        }
        response.json(result);
      }
    );
  };
};
<commit_msg>Accept "results-type" parameter for search API (but it doesn't work)<commit_after>// -*- indent-tabs-mode: nil; js2-basic-offset: 2 -*-

var SelectQuery = require('../../select-query').SelectQuery;
var IndexField = require('../../database').IndexField;
var logger = require('../../logger');

var dummyRid = '000000000000000000000000000000000000000000000000000000000000000';

function formatFacets(data) {
  var drilldownRecords = data.slice(1);

  return drilldownRecords.map(function(drilldownRecord, index) {
    return formatFacet(drilldownRecord);
  });
}

function formatFacet(drilldownRecord) {
  var columnList = drilldownRecord[1];
  var columnNames = columnList.map(function(column) {
    return column[0];
  });

  var constraintEntries = drilldownRecord.slice(2);
  var constraints = constraintEntries.map(function(record) {
    var object = {};
    columnNames.forEach(function(columnName, index) {
      object[columnName] = record[index];
    });
    return {value: object._key, count: object._nsubrecs};
  });

  return {constraints: constraints};
}

function formatSelectResults(data, selectQuery) {
  var columnList = data[0][1];
  var columnNames = columnList.map(function(column) {
    return column[0];
  });

  var records = data[0].slice(2);
  var results = records.map(function(record) {
    var result = {};
    var data = {};

    columnNames.forEach(function(columnName, index) {
      // bind internal "_key" column to the "id"
      if (columnName == '_key') {
        result.id = record[index];
        return;
      }
      // don't expose any internal column
      if (columnName[0] == '_') return;

      var fieldName = IndexField.toFieldName(columnName);
      if (Array.isArray(record[index])) {
        // vector column
        data[fieldName] = record[index];
      } else {
        // scalar column
        data[fieldName] = [record[index]];
      }
    });

    selectQuery.emptyReturnFields.forEach(function(fieldName) {
      data[fieldName] = [];
    });

    if (selectQuery.returnFields.length)
      result.data = data;

    return result;
  });
  return results;
}

function select(context, selectQuery, callback) {
  if (selectQuery.noResult) {
    callback(null, [], 0, []);
    return;
  }
  context.command('select', selectQuery.selectOptions, function(error, data) {
    if (error) {
      callback(error);
    } else {
      var numFoundRecords = data[0][0][0];
      callback(
        null,
        formatSelectResults(data, selectQuery),
        numFoundRecords,
        formatFacets(data)
      );
    }
  });
}

function createResultBody(options) {
  var info = {
    rid:           dummyRid,
    'time-ms':     options.elapsedTime || 0,
    'cpu-time-ms': 0 // TODO
  };
  return {
    rank: options.rankExpression,
    'match-expr': options.matchExpression,
    hits: {
      found: options.found,
      start: options.start,
      hit:   options.hit
    },
    info: info
  };
}

function createErrorBody(options) {
  var messages = [];
  if (options.messages) {
    messages = options.messages;
  } else {
    messages.push({
      severity: 'fatal',
      code:     '',
      message:  options.message || ''
    });
  }
  return {
    error:         'info',
    rid:           options.rid,
    'time-ms':     options.elapsedTime || 0,
    'cpu-time-ms': 0, // TODO
    messages:      messages
  };
}

exports.createHandler = function(context, config) {
  return function(request, response) {
    var startedAt = new Date();
    var resultType = request.query['results-type'] || 'json';

    var selectQuery;
    try {
      selectQuery = new SelectQuery(request, context);
    } catch(error) {
      logger.error(error);

      var errorData = {
            type: resultType,
            rid:  dummyRid
          };
      if (error.message == 'validation error') {
        errorData.messages = [error.data];
      } else {
        errorData.message = 'Invalid ' + error.queryType + ' value: ' + (error.message || error) + error.stack;
      }
      var body = createErrorBody(errorData);
      return response.send(body, 400);
    }

    select(context, selectQuery,
      function(error, data, numFoundRecords, facets) {
        if (error)
          logger.error(error);

        var finishedAt = new Date();
        var elapsedTime = finishedAt.getTime() - startedAt.getTime();

        logger.query(selectQuery, elapsedTime);

        if (error) {
          var body = createErrorBody({
            type:        resultType,
            rid:         dummyRid,
            message:     error.message,
            elapsedTime: elapsedTime
          });
          return response.send(body, 400); // TODO
        }
        var result = createResultBody({
          type:            resultType,
          matchExpression: selectQuery.matchExpression,
          rankExpression:  selectQuery.rankExpression,
          found:           numFoundRecords,
          start:           selectQuery.start,
          hit:             data,
          elapsedTime:     elapsedTime
        });
        if (selectQuery.facets.length) {
          var facetsObject = {};
          facets.forEach(function(facet, index) {
            var fieldName = selectQuery.availableFacets[index];
            facetsObject[fieldName] = facet;
          });
          selectQuery.emptyFacets.forEach(function(fieldName) {
            facetsObject[fieldName] = {};
          });
          result.facets = facetsObject;
        }
        response.json(result);
      }
    );
  };
};
<|endoftext|>


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

const express = require('express');
const Http = require('http');
const debug = require('debug')('xpl-db:server');
const async = require('async');
const bodyParser = require('body-parser');
const serve_static = require('serve-static');
const compression = require('compression');

const NO_CACHE_CONTROL = "no-cache, private, no-store, must-revalidate, max-stale=0, max-age=1,post-check=0, pre-check=0";

class Server {
  constructor(configuration, store, xpl) {
    this.configuration = configuration || {};
    this.store = store;
    this.xpl = xpl;

    this.app = this.configuration.express || express();
  }

  listen(callback) {
    var app = this.app;

    app.enable('etag');
    app.use(compression());
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({
      extended: true
    }));
// app.use(noCache);

    app.get(/^\/last\/(.*)$/, this._getLast.bind(this));
    app.get(/^\/history\/(.*)$/, this._getHistory.bind(this));
    app.get(/^\/minMaxAvgSum\/(.*)$/, this._getMinMaxAvgSum.bind(this));

    if (this.xpl) {
      app.get(/^\/xplCommand\/(.*)$/, this._xplCommand.bind(this));
      app.get(/^\/proxyCommands\/(.*)$/, this._proxyCommands.bind(this));
    }

    app.post('/last', this._postLast.bind(this));
    app.post('/history', this._postHistory.bind(this));
    app.post('/minMaxAvgSum', this._postMinMaxAvgSum.bind(this));

    if (this.configuration.configPath) {

      var oneYear = 1000*60*60*24*365;

      app.use(express.static(__dirname + '/public', {  }));

      app.use("/config", serve_static(this.configuration.configPath, {
        index : false,
        maxAge: oneYear
      }));
    }

    app.use(function(req, res, next) {
      res.status(404).send('Sorry cant find that!');
    });

    var server = app.listen(this.configuration.httpPort || 8480, (error) => {
      if (error) {
        console.error("Server can not listen", error);
        return;
      }
      debug("listen", "Server is listening ", server.address());

      callback(error);
    });
  }

  _proxyCommands(request, response) {
    var hs = {
        'Content-Type': 'application/json',
        'Cache-Control': NO_CACHE_CONTROL
    };
    response.writeHead(200, hs);

    this.xpl.on("message", function(message, packet, address) {
      var infos= {
          date: (new Date()).toUTC(),
          from: address.address()+":"+address.port,
          message: message
      };

      response.write(JSON.stringify(infos));
    });
  }

  _xplCommand(request, response) {
    var key = request.params[0];

    var query = request.query;
    var command = query.c || query.cmd || query.command;
    var device = query.device;
    var target = query.target || "*";
    var bodyName = query.bodyName || "delabarre.command";
    var current = query.v || query.current;

    if (!device && !command) {
      var reg=/(.*)\/([^/]+)$/.exec(key);
      if (reg) {
        device=reg[1];
        command=reg[2];
      }
    }

    debug("xplCommand",
        "key=", key,
        "command=", command,
        "device=",device,
        "target=",target,
        "bodyName=",bodyName,
        "current=",current);

    if (!device || !command) {
      response.status(404).send("Device or command not found");
      return;
    }

    var source="http."+request.connection.remoteAddress;

    var params={
        command: command,
        device: device
    };
    if (current!==undefined) {
      params.current=current;
    }

    this.xpl.sendXplCmnd(params, bodyName, target, source, (error) => {

      if (error) {
        console.error("Command is not sent",error);
        response.status(500).send("Internal error");
        return;
      }

      console.log("Command sent !");
      response.status(200).send("Command sent");
    });
  }

  _set(name, request, response, func) {
    var keys = Object.keys(request.body);
    debug("_set", name, "set keys=", keys);

    var options = formatOptions(request);

    var results = {};
    var lastDate=null;

    async.eachLimit(keys, 8, (key, callback) => {
      var reg=/(.*)\/([^/]+)$/.exec(key);
      if (reg) {
        key=reg[1]+"@"+reg[2]; // Transform @ to /
      }

      func.call(this.store, key, options, (error, value) => {
        debug("_set", name, " set key=", key, "value=", value, "error=", error);
        if (error) {
          return callback(error);
        }

        var reg2=/(.*)\@([^@]+)$/.exec(key);
        if (reg2) {
          key=reg2[1]+"/"+reg[2]; // Transform / to @
        }

        results[key] = value;

        if (value.date) {
          if (!lastDate || lastDate<value.date) {
            lastDate=value.date;
          }
        }

        callback();
      });

    }, (error) => {
      if (error) {
        // send 500
        if (error.code === 'NOT_FOUND') {
          response.status(404).send("Key '" + error.key + "' not found");
          return;
        }

        response.status(500).send(String(error));
        return;
      }

      if (lastDate) {
        if (!response.headersSent) {
          var since=request.headers['if-modified-since'];
          console.log("Since=",since,"/",lastDate);

          if (since && (new Date(since)).getTime()===lastDate.getTime()) {
            response.status(304).send("Not modified");
            return;
          }
        }

        response.setHeader("Last-Modified", lastDate.toUTCString());
      }

      response.json(results);
    });
  }

  _get(name, request, response, func) {
    var key = request.params[0];
    debug("_get", "type=", name, "key=", key);

    var reg=/(.*)\/([^/]+)$/.exec(key);
    if (reg) {
      key=reg[1]+"@"+reg[2]; // Transform @ to /
    }

    var options = formatOptions(request);

    func.call(this.store, key, options, (error, values) => {
      debug("_get", "type=", name, "key=", key, "values=", values);
      if (error) {
        // send 500
        if (error.code === 'NOT_FOUND') {
          response.status(404).send('Key not found');
          return;
        }

        response.status(500).send(String(error));
        return;
      }

      response.json(values);
    });
  }

  _getLast(request, response) {
    this._get("getLast", request, response, this.store.getLast);
  }

  _getHistory(request, response) {
    this._get("getHistory", request, response, this.store.getHistory);
  }

  _getMinMaxAvgSum(request, response) {
    this._get("getMinMaxAvgSum", request, response, this.store.getMinMaxAvgSum);
  }

  _postLast(request, response) {
    this._set("getLastSet", request, response, this.store.getLast);
  }

  _postHistory(request, response) {
    this._set("getHistorySet", request, response, this.store.getHistory);
  }

  _postMinMaxAvgSum(request, response) {
    this._set("getMinMaxAvgSumSet", request, response, this.store.getMinMaxAvgSum);
  }
}

function formatOptions(request) {
  var ret = {};

  var query = request.query;
  if (query.limit) {
    ret.limit = parseInt(query.limit, 10);
  }

  if (query.minDate) {
    ret.minDate = new Date(query.minDate);
  }

  if (query.maxDate) {
    ret.maxDate = new Date(query.maxDate);
  }

  if (query.averageMs) {
    ret.averageMs = parseInt(query.averageMs, 10);
  }

  if (query.step) {
    ret.stepMs = parseInt(query.step, 10) * 1000;
  }

  return ret;
}

module.exports = Server;
<commit_msg>Fix leaks<commit_after>/*jslint node: true, vars: true, nomen: true */
'use strict';

const express = require('express');
const Http = require('http');
const debug = require('debug')('xpl-db:server');
const async = require('async');
const bodyParser = require('body-parser');
const serve_static = require('serve-static');
const compression = require('compression');

const NO_CACHE_CONTROL = "no-cache, private, no-store, must-revalidate, max-stale=0, max-age=1,post-check=0, pre-check=0";

class Server {
  constructor(configuration, store, xpl) {
    this.configuration = configuration || {};
    this.store = store;
    this.xpl = xpl;

    this.app = this.configuration.express || express();
  }

  listen(callback) {
    var app = this.app;

    app.enable('etag');
    app.use(compression());
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({
      extended: true
    }));
// app.use(noCache);

    app.get(/^\/last\/(.*)$/, this._getLast.bind(this));
    app.get(/^\/history\/(.*)$/, this._getHistory.bind(this));
    app.get(/^\/minMaxAvgSum\/(.*)$/, this._getMinMaxAvgSum.bind(this));

    if (this.xpl) {
      app.get(/^\/xplCommand\/(.*)$/, this._xplCommand.bind(this));
      app.get(/^\/proxyCommands\/(.*)$/, this._proxyCommands.bind(this));
    }

    app.post('/last', this._postLast.bind(this));
    app.post('/history', this._postHistory.bind(this));
    app.post('/minMaxAvgSum', this._postMinMaxAvgSum.bind(this));

    if (this.configuration.configPath) {

      var oneYear = 1000*60*60*24*365;

      app.use(express.static(__dirname + '/public', {  }));

      app.use("/config", serve_static(this.configuration.configPath, {
        index : false,
        maxAge: oneYear
      }));
    }

    app.use(function(req, res, next) {
      res.status(404).send('Sorry cant find that!');
    });

    var server = app.listen(this.configuration.httpPort || 8480, (error) => {
      if (error) {
        console.error("Server can not listen", error);
        return;
      }
      debug("listen", "Server is listening ", server.address());

      callback(error);
    });
  }

  _proxyCommands(request, response) {
    var hs = {
        'Content-Type': 'application/json',
        'Cache-Control': NO_CACHE_CONTROL
    };
    response.writeHead(200, hs);

    var cb = (message, packet, address) => {
      var infos= {
          date: (new Date()).toUTC(),
          from: address.address()+":"+address.port,
          message: message
      };

      response.write(JSON.stringify(infos));
    };

    this.xpl.on("message", cb);

    response.on('error', (error) => {
      console.error("Catch error !");

      this.xpl.removeListener("message", cb);
    });

    response.on('end', () => {
      console.error("Catch end !");

      this.xpl.removeListener("message", cb);
    });
  }

  _xplCommand(request, response) {
    var key = request.params[0];

    var query = request.query;
    var command = query.c || query.cmd || query.command;
    var device = query.device;
    var target = query.target || "*";
    var bodyName = query.bodyName || "delabarre.command";
    var current = query.v || query.current;

    if (!device && !command) {
      var reg=/(.*)\/([^/]+)$/.exec(key);
      if (reg) {
        device=reg[1];
        command=reg[2];
      }
    }

    debug("xplCommand",
        "key=", key,
        "command=", command,
        "device=",device,
        "target=",target,
        "bodyName=",bodyName,
        "current=",current);

    if (!device || !command) {
      response.status(404).send("Device or command not found");
      return;
    }

    var source="http."+request.connection.remoteAddress;

    var params={
        command: command,
        device: device
    };
    if (current!==undefined) {
      params.current=current;
    }

    this.xpl.sendXplCmnd(params, bodyName, target, source, (error) => {

      if (error) {
        console.error("Command is not sent",error);
        response.status(500).send("Internal error");
        return;
      }

      console.log("Command sent !");
      response.status(200).send("Command sent");
    });
  }

  _set(name, request, response, func) {
    var keys = Object.keys(request.body);
    debug("_set", name, "set keys=", keys);

    var options = formatOptions(request);

    var results = {};
    var lastDate=null;

    async.eachLimit(keys, 8, (key, callback) => {
      var reg=/(.*)\/([^/]+)$/.exec(key);
      if (reg) {
        key=reg[1]+"@"+reg[2]; // Transform @ to /
      }

      func.call(this.store, key, options, (error, value) => {
        debug("_set", name, " set key=", key, "value=", value, "error=", error);
        if (error) {
          return callback(error);
        }

        var reg2=/(.*)\@([^@]+)$/.exec(key);
        if (reg2) {
          key=reg2[1]+"/"+reg[2]; // Transform / to @
        }

        results[key] = value;

        if (value.date) {
          if (!lastDate || lastDate<value.date) {
            lastDate=value.date;
          }
        }

        callback();
      });

    }, (error) => {
      if (error) {
        // send 500
        if (error.code === 'NOT_FOUND') {
          response.status(404).send("Key '" + error.key + "' not found");
          return;
        }

        response.status(500).send(String(error));
        return;
      }

      if (lastDate) {
        if (!response.headersSent) {
          var since=request.headers['if-modified-since'];
          console.log("Since=",since,"/",lastDate);

          if (since && (new Date(since)).getTime()===lastDate.getTime()) {
            response.status(304).send("Not modified");
            return;
          }
        }

        response.setHeader("Last-Modified", lastDate.toUTCString());
      }

      response.json(results);
    });
  }

  _get(name, request, response, func) {
    var key = request.params[0];
    debug("_get", "type=", name, "key=", key);

    var reg=/(.*)\/([^/]+)$/.exec(key);
    if (reg) {
      key=reg[1]+"@"+reg[2]; // Transform @ to /
    }

    var options = formatOptions(request);

    func.call(this.store, key, options, (error, values) => {
      debug("_get", "type=", name, "key=", key, "values=", values);
      if (error) {
        // send 500
        if (error.code === 'NOT_FOUND') {
          response.status(404).send('Key not found');
          return;
        }

        response.status(500).send(String(error));
        return;
      }

      response.json(values);
    });
  }

  _getLast(request, response) {
    this._get("getLast", request, response, this.store.getLast);
  }

  _getHistory(request, response) {
    this._get("getHistory", request, response, this.store.getHistory);
  }

  _getMinMaxAvgSum(request, response) {
    this._get("getMinMaxAvgSum", request, response, this.store.getMinMaxAvgSum);
  }

  _postLast(request, response) {
    this._set("getLastSet", request, response, this.store.getLast);
  }

  _postHistory(request, response) {
    this._set("getHistorySet", request, response, this.store.getHistory);
  }

  _postMinMaxAvgSum(request, response) {
    this._set("getMinMaxAvgSumSet", request, response, this.store.getMinMaxAvgSum);
  }
}

function formatOptions(request) {
  var ret = {};

  var query = request.query;
  if (query.limit) {
    ret.limit = parseInt(query.limit, 10);
  }

  if (query.minDate) {
    ret.minDate = new Date(query.minDate);
  }

  if (query.maxDate) {
    ret.maxDate = new Date(query.maxDate);
  }

  if (query.averageMs) {
    ret.averageMs = parseInt(query.averageMs, 10);
  }

  if (query.step) {
    ret.stepMs = parseInt(query.step, 10) * 1000;
  }

  return ret;
}

module.exports = Server;
<|endoftext|>