<commit_before>var setErrorMessage = function(statusCode, msg) {
    return {
        code: statusCode,
        message: msg
    };
};

var createIterator = function(arr) {
    currentIndex = 0;

    return {
        next: function() {
            return (currentIndex < arr.length ? {
                value: arr[currentIndex++],
                done: false
            } : { done: true });
        }
    };
};

var waterfall = function(funcs, callback) {
    callback = callback || function() {};

    if(!Array.isArray(funcs))
        throw new Error("funcs are not of type array");
    else if(funcs.length <= 0)
        throw new Error("array is empty!");

    var iterator = createIterator(funcs);

    var obj = function() {
        var nxt = iterator.next();
        var err = arguments[0];
        var args = [];

        //not so nice looking copy to keep vm optimizations
        for(var i = (nxt.done ? 0 : 1), l = arguments.length; i < l; i++)
            args.push(arguments[i]);
        args.push(obj);

        if(!nxt.done && !err)
            nxt.value.apply(nxt.value, args);
        else
            callback.apply(callback, (!err ? args : err));
    };

    obj();
};

var loginClient = function(client, tries) {
    tries = tries || 0;

    waterfall([
        client.getCSRF.bind(client),
        client.setLogin.bind(client),
        client._getAuthToken.bind(client)
    ], function _loginCredentialCheck(err) {
        if(err) {
            if(tries < 2) {
                client.log("an error occured while trying to log in", 0, "red");
                client.log("err: " + err.code, 1, "red");
                client.log("trying to reconnect...", 0);
                loginClient(client, ++tries);
            } else {
                client.log("couldn't log in.", 0, "red");
                client.emit(client.LOGIN_ERROR, "couldn't log in");
            }
        } else {
            client._loggedIn.call(client);
        }
    });
};

var decode = function(str) {
    if(typeof str !== "string")
        return str;

    return str
    .replace(/"/g, '\\\"')
    .replace(/'/g, '\'')
    .replace(/&/g, '&')
    .replace(/</g, '<')
    .replace(/>/g, '>');
};

exports.setErrorMessage = setErrorMessage;
exports.createIterator = createIterator;
exports.loginClient = loginClient;
exports.waterfall = waterfall;
exports.decode = decode;
<commit_msg>fixed bug in iterator; changed the messages for a retry a little<commit_after>var setErrorMessage = function(statusCode, msg) {
    return {
        code: statusCode,
        message: msg
    };
};

var createIterator = function(arr) {
    currentIndex = 0;

    return {
        next: function() {
            return (currentIndex < arr.length ? {
                value: arr[currentIndex++],
                done: false
            } : { done: true });
        }
    };
};

var waterfall = function(funcs, callback) {
    callback = callback || function() {};

    if(!Array.isArray(funcs))
        throw new Error("funcs are not of type array");
    else if(funcs.length <= 0)
        throw new Error("array is empty!");

    var iterator = createIterator(funcs);

    (function _obj() {
        var nxt = iterator.next();
        var err = arguments[0];
        var args = [];

        //not so nice looking copy to keep vm optimizations
        for(var i = (nxt.done ? 0 : 1), l = arguments.length; i < l; i++)
            args.push(arguments[i]);
        args.push(_obj);

        if(!nxt.done && !err)
            nxt.value.apply(nxt.value, args);
        else
            callback.apply(callback, (!err ? args : [err]));
    })();
};

var loginClient = function(client, tries) {
    tries = tries || 0;

    waterfall([
        client.getCSRF.bind(client),
        client.setLogin.bind(client),
        client._getAuthToken.bind(client)
    ], function _loginCredentialCheck(err) {
        if(err) {
            if(tries < 2 && err.code !== 401) {
                client.log("an error occured while trying to log in", 0, "red");
                client.log(err, 2, "red");
                client.log("retrying...", 0);
                loginClient(client, ++tries);
            } else {
                client.log("couldn't log in.", 0, "red");
                client.emit(client.LOGIN_ERROR, err);
            }
        } else {
            client._loggedIn.call(client);
        }
    });
};

var decode = function(str) {
    if(typeof str !== "string")
        return str;

    return str
    .replace(/"/g, '\\\"')
    .replace(/'/g, '\'')
    .replace(/&/g, '&')
    .replace(/</g, '<')
    .replace(/>/g, '>');
};

exports.setErrorMessage = setErrorMessage;
exports.createIterator = createIterator;
exports.loginClient = loginClient;
exports.waterfall = waterfall;
exports.decode = decode;
<|endoftext|>


<commit_before>module.exports = {
  /**
   * Generate a cache key unique to this query
   * @param {object} reg
   * @param {object} cProps
   */
  keygen: function(agent, req, cProps){
    var cleanParams = null;
    var cleanOptions = null;
    var params = this.getQueryParams(req);
    var options = this.getHeaderOptions(req);
    if(cProps.pruneParams || cProps.pruneOptions){
      cleanParams = (cProps.pruneParams) ? this.pruneObj(this.cloneObject(params), cProps.pruneParams) : params;
      cleanOptions = (cProps.pruneOptions) ? this.pruneObj(this.cloneObject(options), cProps.pruneOptions, true) : options;
    }
    return JSON.stringify({
      nameSpace: agent.cache.nameSpace,
      method: req.method,
      uri: req.url,
      params: cleanParams || params || null,
      options: cleanOptions || options || null
    });
  },

  /**
   * Find and extract query params
   * @param {object} reg
   */
  getQueryParams: function(req){
    if(req && req.qs && !this.isEmpty(req.qs)){
      return req.qs;
    }
    else if(req && req.qsRaw){
      return this.arrayToObj(req.qsRaw);
    }
    else if(req && req.req){
      return this.stringToObj(req.req.path);
    }
    else if(req && req._query){
      return this.stringToObj(req._query.join('&'));
    }
    return null;
  },

  /**
   * Find and extract headers
   * @param {object} reg
   */
  getHeaderOptions: function(req){
    if(req && req.req && req.req._headers){
      return req.req._headers;
    }
    else if(req && req._header){
      return req._header;
    }
    return null;
  },

  /**
   * Convert an array to an object
   * @param {array} arr
   */
  arrayToObj: function(arr){
    if(arr && arr.length){
      var obj = {};
      for(var i = 0; i < arr.length; i++){
        var str = arr[i];
        var kvArray = str.split('&');
        for(var j = 0; j < kvArray.length; j++){
          var kvString = kvArray[j].split('=');
          obj[kvString[0]] = kvString[1];
        }
      }
      return obj;
    }
    return null;
  },

  /**
   * Convert a string to an object
   * @param {string} str
   */
  stringToObj: function(str){
    if(str){
      var obj = {};
      if(~str.indexOf('?')){
        var strs = str.split('?');
        str = strs[1];
      }
      var kvArray = str.split('&');
      for(var i = 0; i < kvArray.length; i++){
        var kvString = kvArray[i].split('=');
        obj[kvString[0]] = kvString[1];
      }
      return obj;
    }
    return null;
  },

  /**
   * Remove properties from an object
   * @param {object} obj
   * @param {array} props
   * @param {boolean} isOptions
   */
  pruneObj: function(obj, props, isOptions){
    for(var i = 0; i < props.length; i++){
      var prop = props[i];
      if(isOptions){
        prop = prop.toLowerCase();
      }
      delete obj[prop]
    }
    return obj;
  },

  /**
   * Simplify superagent's http response object
   * @param {object} r
   */
  gutResponse: function(r){
    var newResponse = {};
    newResponse.body = r.body;
    newResponse.text = r.text;
    newResponse.headers = r.headers;
    newResponse.statusCode = r.statusCode;
    newResponse.status = r.status;
    newResponse.ok = r.ok;
    return newResponse;
  },

  /**
   * Determine whether a value is considered empty
   * @param {*} val
   */
  isEmpty: function(val){
    return (val === false || val === null || (typeof val == 'object' && Object.keys(val).length == 0));
  },

  /**
   * Return a cloneof an object
   * @param {object} obj
   */
  cloneObject: function(obj){
    var newObj = {};
    for(var attr in obj) {
      if (obj.hasOwnProperty(attr)){
        newObj[attr] = obj[attr];
      }
    }
    return newObj;
  },

  /**
   * Reset superagent-cache's default query properties using the options defaults object
   * @param {object} d
   */
  resetProps: function(d){
    return {
      doQuery: (typeof d.doQuery === 'boolean') ? d.doQuery : true,
      cacheWhenEmpty: (typeof d.cacheWhenEmpty === 'boolean') ? d.cacheWhenEmpty : true,
      prune: d.prune,
      pruneParams: d.pruneParams,
      pruneOptions: d.pruneOptions,
      responseProp: d.responseProp,
      expiration: d.expiration,
      backgroundRefresh: d.backgroundRefresh
    };
  },

  /**
   * Generate a background refresh query identical to the current query
   * @param {object} curProps
   */
  getBackgroundRefreshFunction: function(agent, curProps){
    return function(key, cb){
      key = JSON.parse(key);
      var method = key.method.toLowerCase();
      var request = agent[method](key.uri)
        .doQuery(curProps.doQuery)
        .pruneParams(curProps.pruneParams)
        .pruneOptions(curProps.pruneOptions)
        .prune(curProps.prune)
        .responseProp(curProps.responseProp)
        .expiration(curProps.expiration)
        .cacheWhenEmpty(curProps.cacheWhenEmpty);
      if(key.params){
        request.query(key.params)
      }
      if(key.options){
        request.set(key.options);
      }
      request.end(cb);
    }
  },

  /**
   * Handle the varying number of callback output params
   * @param {function} cb
   * @param {object} err
   * @param {object} response
   * @param {string} key
   */
  callbackExecutor: function(cb, err, response, key){
    if(cb.length === 1){
      cb(response);
    }
    else if(cb.length > 1){
      cb(err, response, key);
    }
    else{
      throw new Error('UnsupportedCallbackException: Your .end() callback must pass at least one argument.');
    }
  }
}
<commit_msg>Updating comments.<commit_after>module.exports = {
  /**
   * Generate a cache key unique to this query
   * @param {superagent} agent
   * @param {object} reg
   * @param {object} cProps
   */
  keygen: function(agent, req, cProps){
    var cleanParams = null;
    var cleanOptions = null;
    var params = this.getQueryParams(req);
    var options = this.getHeaderOptions(req);
    if(cProps.pruneParams || cProps.pruneOptions){
      cleanParams = (cProps.pruneParams) ? this.pruneObj(this.cloneObject(params), cProps.pruneParams) : params;
      cleanOptions = (cProps.pruneOptions) ? this.pruneObj(this.cloneObject(options), cProps.pruneOptions, true) : options;
    }
    return JSON.stringify({
      nameSpace: agent.cache.nameSpace,
      method: req.method,
      uri: req.url,
      params: cleanParams || params || null,
      options: cleanOptions || options || null
    });
  },

  /**
   * Find and extract query params
   * @param {object} reg
   */
  getQueryParams: function(req){
    if(req && req.qs && !this.isEmpty(req.qs)){
      return req.qs;
    }
    else if(req && req.qsRaw){
      return this.arrayToObj(req.qsRaw);
    }
    else if(req && req.req){
      return this.stringToObj(req.req.path);
    }
    else if(req && req._query){
      return this.stringToObj(req._query.join('&'));
    }
    return null;
  },

  /**
   * Find and extract headers
   * @param {object} reg
   */
  getHeaderOptions: function(req){
    if(req && req.req && req.req._headers){
      return req.req._headers;
    }
    else if(req && req._header){
      return req._header;
    }
    return null;
  },

  /**
   * Convert an array to an object
   * @param {array} arr
   */
  arrayToObj: function(arr){
    if(arr && arr.length){
      var obj = {};
      for(var i = 0; i < arr.length; i++){
        var str = arr[i];
        var kvArray = str.split('&');
        for(var j = 0; j < kvArray.length; j++){
          var kvString = kvArray[j].split('=');
          obj[kvString[0]] = kvString[1];
        }
      }
      return obj;
    }
    return null;
  },

  /**
   * Convert a string to an object
   * @param {string} str
   */
  stringToObj: function(str){
    if(str){
      var obj = {};
      if(~str.indexOf('?')){
        var strs = str.split('?');
        str = strs[1];
      }
      var kvArray = str.split('&');
      for(var i = 0; i < kvArray.length; i++){
        var kvString = kvArray[i].split('=');
        obj[kvString[0]] = kvString[1];
      }
      return obj;
    }
    return null;
  },

  /**
   * Remove properties from an object
   * @param {object} obj
   * @param {array} props
   * @param {boolean} isOptions
   */
  pruneObj: function(obj, props, isOptions){
    for(var i = 0; i < props.length; i++){
      var prop = props[i];
      if(isOptions){
        prop = prop.toLowerCase();
      }
      delete obj[prop]
    }
    return obj;
  },

  /**
   * Simplify superagent's http response object
   * @param {object} r
   */
  gutResponse: function(r){
    var newResponse = {};
    newResponse.body = r.body;
    newResponse.text = r.text;
    newResponse.headers = r.headers;
    newResponse.statusCode = r.statusCode;
    newResponse.status = r.status;
    newResponse.ok = r.ok;
    return newResponse;
  },

  /**
   * Determine whether a value is considered empty
   * @param {*} val
   */
  isEmpty: function(val){
    return (val === false || val === null || (typeof val == 'object' && Object.keys(val).length == 0));
  },

  /**
   * Return a cloneof an object
   * @param {object} obj
   */
  cloneObject: function(obj){
    var newObj = {};
    for(var attr in obj) {
      if (obj.hasOwnProperty(attr)){
        newObj[attr] = obj[attr];
      }
    }
    return newObj;
  },

  /**
   * Reset superagent-cache's default query properties using the options defaults object
   * @param {object} d
   */
  resetProps: function(d){
    return {
      doQuery: (typeof d.doQuery === 'boolean') ? d.doQuery : true,
      cacheWhenEmpty: (typeof d.cacheWhenEmpty === 'boolean') ? d.cacheWhenEmpty : true,
      prune: d.prune,
      pruneParams: d.pruneParams,
      pruneOptions: d.pruneOptions,
      responseProp: d.responseProp,
      expiration: d.expiration,
      backgroundRefresh: d.backgroundRefresh
    };
  },

  /**
   * Generate a background refresh query identical to the current query
   * @param {superagent} agent
   * @param {object} curProps
   */
  getBackgroundRefreshFunction: function(agent, curProps){
    return function(key, cb){
      key = JSON.parse(key);
      var method = key.method.toLowerCase();
      var request = agent[method](key.uri)
        .doQuery(curProps.doQuery)
        .pruneParams(curProps.pruneParams)
        .pruneOptions(curProps.pruneOptions)
        .prune(curProps.prune)
        .responseProp(curProps.responseProp)
        .expiration(curProps.expiration)
        .cacheWhenEmpty(curProps.cacheWhenEmpty);
      if(key.params){
        request.query(key.params)
      }
      if(key.options){
        request.set(key.options);
      }
      request.end(cb);
    }
  },

  /**
   * Handle the varying number of callback output params
   * @param {function} cb
   * @param {object} err
   * @param {object} response
   * @param {string} key
   */
  callbackExecutor: function(cb, err, response, key){
    if(cb.length === 1){
      cb(response);
    }
    else if(cb.length > 1){
      cb(err, response, key);
    }
    else{
      throw new Error('UnsupportedCallbackException: Your .end() callback must pass at least one argument.');
    }
  }
}
<|endoftext|>


<commit_before>import gulp from 'gulp';
import gutil from 'gulp-util';
import browserify from 'browserify';
import source from 'vinyl-source-stream';
import buffer from 'vinyl-buffer';
import async from 'async';
import once from 'once';
import gulpIf from 'gulp-if';
import uglify from 'gulp-uglify';
import replace from 'gulp-replace';
import bundleLogger from '../lib/bundle-logger';
import handleErrors from '../lib/handle-errors';
import { IS_PRODUCTION, BROWSERIFY } from '../config';

gulp.task('browserify', (next) => {

  gutil.log('NODE_ENV:', gutil.colors.yellow(process.env.NODE_ENV));
  gutil.log('IS_PRODUCTION:', gutil.colors.yellow(IS_PRODUCTION));

  async.each(BROWSERIFY.bundleConfigs, (bundleConfig, cb) => {
    cb = once(cb);
    let bundler = browserify({
      entries: bundleConfig.entries,
      insertGlobals: true,
      detectGlobals: false,
      debug: BROWSERIFY.debug
      //standalone: "Jpegasm"
    });

    let handleEnd = () => {
      bundleLogger.end(bundleConfig.outputName);
      cb();
    };

    let bundle = () => {
      bundleLogger.start(bundleConfig.outputName);
      return bundler
        .bundle()
        .on('error', handleErrors)
        .pipe(source(bundleConfig.outputName))
        .pipe(buffer())
        .pipe(replace(/&&\s*!ENVIRONMENT_IS_WEB\s*&&\s*!ENVIRONMENT_IS_WORKER/, ''))
        .pipe(gulpIf(IS_PRODUCTION, uglify())) // { mangle: false }
        .pipe(gulp.dest(bundleConfig.dest))
        .on('end', handleEnd);
    };

    bundle();

  }, next);
});
<commit_msg>fix browserify + emscripten integration<commit_after>import gulp from 'gulp';
import gutil from 'gulp-util';
import browserify from 'browserify';
import source from 'vinyl-source-stream';
import buffer from 'vinyl-buffer';
import async from 'async';
import once from 'once';
import gulpIf from 'gulp-if';
import uglify from 'gulp-uglify';
import replace from 'gulp-replace';
import bundleLogger from '../lib/bundle-logger';
import handleErrors from '../lib/handle-errors';
import { IS_PRODUCTION, BROWSERIFY } from '../config';

gulp.task('browserify', (next) => {

  gutil.log('NODE_ENV:', gutil.colors.yellow(process.env.NODE_ENV));
  gutil.log('IS_PRODUCTION:', gutil.colors.yellow(IS_PRODUCTION));

  async.each(BROWSERIFY.bundleConfigs, (bundleConfig, cb) => {
    cb = once(cb);
    let bundler = browserify({
      entries: bundleConfig.entries,
      insertGlobals: true,
      detectGlobals: true,
      debug: BROWSERIFY.debug,
      standalone: "jpegasm"
    });

    let handleEnd = () => {
      bundleLogger.end(bundleConfig.outputName);
      cb();
    };

    let bundle = () => {
      bundleLogger.start(bundleConfig.outputName);
      return bundler
        .bundle()
        .on('error', handleErrors)
        .pipe(source(bundleConfig.outputName))
        .pipe(buffer())
        .pipe(replace(/&&\s*!ENVIRONMENT_IS_WEB\s*&&\s*!ENVIRONMENT_IS_WORKER/, '')) // PATCH: cannot detect NODE in a browser.
        .pipe(replace(/NODEFS.isWindows\s*=\s*/, 'NODEFS.isWindows=false;//'))       // PATCH: process.platform is undefined
        .pipe(replace(/process\['stderr'\]\.write/, 'console.error'))                // PATCH: process.stderr is undefined
        .pipe(replace(/process\['stdout'\]\.write/, 'console.log'))                  // PATCH: process.stdout is undefined
        .pipe(gulpIf(IS_PRODUCTION, uglify())) // { mangle: false }
        .pipe(gulp.dest(bundleConfig.dest))
        .on('end', handleEnd);
    };

    bundle();

  }, next);
});
<|endoftext|>


<commit_before>import {run} from '@cycle/core';
import {makeDOMDriver, div, input} from '@cycle/dom';
import {makeAnimationDriver} from './lib/driver';
import _ from 'lodash';

const maxSpeed = 500;
const maxHeight = 100;

function nodes (timestamp, speed, height) {
  return (
    div('.nodes', _.range(1, 50).map(i =>
      div('.node', {
        style: {
          left: (i * 15) + 'px',
          top: (Math.sin(i + timestamp / (maxSpeed - speed)) * height + 150).toString() + 'px'
        }
      }, '.')
    ))
  );
}

function main ({DOM, animation}) {
  const speed$ = DOM
    .select('.speed')
    .events('input')
    .map(ev => ev.target.value)
    .startWith(maxSpeed / 2);

  const height$ = DOM
    .select('.height')
    .events('input')
    .map(ev => ev.target.value)
    .startWith(maxHeight / 2);

  return {
    DOM: animation.withLatestFrom(speed$, height$, (timestamp, speed, height) =>
      div('.time', [
        nodes(timestamp, speed, height),
        'Speed',
        input('.speed', {type: 'range', min: 1, max: maxSpeed, value: speed}),
        'Height',
        input('.height', {type: 'range', min: 1, max: maxHeight, value: height})
      ])
    )
  };
}

const drivers = {
  DOM: makeDOMDriver('.app'),
  animation: makeAnimationDriver()
};

const {sinks, sources} = run(main, drivers);

if (module.hot) {
  module.hot.accept();

  module.hot.dispose(() => {
    sinks.dispose();
  });
}
<commit_msg>Remove example from master<commit_after><|endoftext|>


<commit_before>'use strict';

var express = require('express');
var bodyParser = require('body-parser');
var request = require('request');
var app = express();

// Optional. You will see this name in eg. 'ps' or 'top' command
process.title = 'luzbot';

// Port where we'll run the websocket server
var webSocketsServerPort = 1337;

// websocket and http servers
var webSocketServer = require('websocket').server;
var http = require('http');

/**
 * Global variables
 */
// latest 100 messages
var history = [ ];
// list of currently connected clients (users)
var clients = [ ];

let Wit = null;
let log = null;
try {
  // if running from repo
  Wit = require('../').Wit;
  log = require('../').log;
} catch (e) {
  Wit = require('node-wit').Wit;
  log = require('node-wit').log;
}

// Variables are defined in Heroku
const WIT_TOKEN = process.env.WIT_TOKEN;
const FB_PAGE_ACCESS_TOKEN = process.env.PAGE_ACCESS_TOKEN;
const PORT = process.env.PORT || 3000;
//Needs feature Dyno Metadata (https://stackoverflow.com/questions/7917523/how-do-i-access-the-current-heroku-release-version-programmatically)
const VERSION = process.env.HEROKU_RELEASE_VERSION;

const { Client } = require('pg');

const pgClient = new Client({
  connectionString: process.env.DATABASE_URL,
  ssl: true,
});

/**
 * Helper function for escaping input strings
 */
function htmlEntities(str) {
    return String(str).replace(/&/g, '&').replace(/</g, '<')
                      .replace(/>/g, '>').replace(/"/g, '"');
}

// Array with some colors
var colors = [ 'green', 'blue', 'magenta', 'purple', 'plum', 'orange' ];
// ... in random order
colors.sort(function(a,b) { return Math.random() > 0.5; } );

app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());
app.listen(PORT);
console.log('Listening on :' + PORT + '...');

/**
 * HTTP server
 */
var server = http.createServer(function(request, response) {
    // Not important for us. We're writing WebSocket server, not HTTP server
});
server.listen(webSocketsServerPort, function() {
    console.log((new Date()) + " Server is listening on port " + webSocketsServerPort);
});

/**
 * WebSocket server
 */
var wsServer = new webSocketServer({
    // WebSocket server is tied to a HTTP server. WebSocket request is just
    // an enhanced HTTP request. For more info http://tools.ietf.org/html/rfc6455#page-6
    httpServer: server
});

// Server frontpage
app.get('/', function (req, res) {
    res.send('This is TestBot Server');
});

// Facebook Webhook
app.get('/webhook', function (req, res) {
    if (req.query['hub.verify_token'] === 'luzbot_hans') {
        res.send(req.query['hub.challenge']);
    } else {
        res.send('Invalid verify token');
    }
});

// handler receiving messages
app.post('/webhook', function (req, res) {
    var events = req.body.entry[0].messaging;
    for (var i = 0; i < events.length; i++) {
        var event = events[i];
        if (event.message && event.message.text) {

			// Yay! We got a new message!
			// We retrieve the Facebook user ID of the sender
			const sender = event.sender.id;

			// We retrieve the user's current session, or create one if it doesn't exist
			// This is needed for our bot to figure out the conversation history
			const sessionId = findOrCreateSession(sender);

			var question = event.message.text;

			console.log('New message detected, text: ' + question);
			console.log('New message detected, sender: ' + sender);

			sendBotAnswer(2, sender, question);

        }
    }
    res.sendStatus(200);
});

// This callback function is called every time someone tries to connect to the WebSocket server
wsServer.on('request', function(request) {
    console.log((new Date()) + ' Connection from origin ' + request.origin + '.');

    // accept connection - you should check 'request.origin' to make sure that
    // client is connecting from your website
    // (http://en.wikipedia.org/wiki/Same_origin_policy)
    var connection = request.accept(null, request.origin);
    // we need to know client index to remove them on 'close' event
    var index = clients.push(connection) - 1;
    var userName = false;
    var userColor = false;

    console.log((new Date()) + ' Connection accepted.');

    // send back chat history
    if (history.length > 0) {
        connection.sendUTF(JSON.stringify( { type: 'history', data: history} ));
    }

    // user sent some message
    connection.on('message', function(message) {
        if (message.type === 'utf8') { // accept only text
            if (userName === false) { // first message sent by user is their name
                // remember user name
                userName = htmlEntities(message.utf8Data);
                // get random color and send it back to the user
                userColor = colors.shift();
                connection.sendUTF(JSON.stringify({ type:'color', data: userColor }));
                console.log((new Date()) + ' User is known as: ' + userName
                            + ' with ' + userColor + ' color.');

            } else { // log and broadcast the message
                console.log((new Date()) + ' Received Message from '
                            + userName + ': ' + message.utf8Data);

				//Eingegeben Nachricht ausgeben...
				sendMessageNativeBot(message.utf8Data, userName, userColor);

                //Sende Bot Anwort...
				var question = message.utf8Data;
				sendBotAnswer(1, 0, question);

            }
        }
    });

    // user disconnected
    connection.on('close', function(connection) {
        if (userName !== false && userColor !== false) {
            console.log((new Date()) + " Peer "
                + connection.remoteAddress + " disconnected.");
            // remove user from the list of connected clients
            clients.splice(index, 1);
            // push back user's color to be reused by another user
            colors.push(userColor);
        }
    });

});

// ----------------------------------------------------------------------------
// Messenger API specific code

// See the Send API reference
// https://developers.facebook.com/docs/messenger-platform/send-api-reference

const fbMessage = (id, text) => {
  const body = JSON.stringify({
    recipient: { id },
    message: { text },
  });
  const qs = 'access_token=' + encodeURIComponent(FB_PAGE_ACCESS_TOKEN);
  return fetch('https://graph.facebook.com/me/messages?' + qs, {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body,
  })
  .then(rsp => rsp.json())
  .then(json => {
    if (json.error && json.error.message) {
      throw new Error(json.error.message);
    }
    return json;
  });
};

// ----------------------------------------------------------------------------
// Wit.ai bot specific code

// This will contain all user sessions.
// Each session has an entry:
// sessionId -> {fbid: facebookUserId, context: sessionState}
const sessions = {};

const findOrCreateSession = (fbid) => {
  let sessionId;
  // Let's see if we already have a session for the user fbid
  Object.keys(sessions).forEach(k => {
    if (sessions[k].fbid === fbid) {
      // Yep, got it!
      sessionId = k;
    }
  });
  if (!sessionId) {
    // No session found for user fbid, let's create a new one
    sessionId = new Date().toISOString();
    sessions[sessionId] = {fbid: fbid, context: {}};
  }
  return sessionId;
};

// Our bot actions
const actions = {
  send({sessionId}, {text}) {
	console.log('Our bot has something to say!');
    // Our bot has something to say!
    // Let's retrieve the Facebook user whose session belongs to
    const recipientId = sessions[sessionId].fbid;
	console.log('Our bot has something to say!' + recipientId);
    if (recipientId) {
		console.log('// Yay, we found our recipient!');
      // Yay, we found our recipient!
      // Let's forward our bot response to her.
      // We return a promise to let our bot know when we're done sending
      return fbMessage(recipientId, text)
      .then(() => null)
      .catch((err) => {
        console.error(
          'Oops! An error occurred while forwarding the response to',
          recipientId,
          ':',
          err.stack || err
        );
      });
    } else {
      console.error('Oops! Couldn\'t find user for session:', sessionId);
      // Giving the wheel back to our bot
      return Promise.resolve()
    }
  },

};

// Setting up our bot
const wit = new Wit({
  accessToken: WIT_TOKEN,
  actions,
  logger: new log.Logger(log.INFO)
});

//Process JSON for correct answer
function sendAnswer(botType, recipientId, nlpJson) {
	if(nlpJson.hasOwnProperty('entities') && Object.keys(nlpJson.entities).length > 0){
		console.log('property entities exists and has at least one entity');

		if (nlpJson['entities']['intent']['0']['value'] === 'temperature_get') {
			var answer = "Die aktuelle Temperatur ist...";
			sendMessage(botType, recipientId, answer);
		}
		else if (nlpJson['entities']['intent']['0']['value'] === 'temperature_set') {
			var answer = "Die neue Temperatur ist ";
			if(nlpJson.entities.hasOwnProperty('temperature')) {
				answer += nlpJson['entities']['temperature']['0']['value'] + ' ' + nlpJson['entities']['temperature']['0']['unit'];
			}
			else {
				answer = "Ich verstehe die neue Temperatur nicht!";
			}

			sendMessage(botType, recipientId, answer);
		}
		else if (nlpJson['entities']['intent']['0']['value'] === 'restaurant') {
			var answer = 'Ich zeige dir eine Liste von Restaurants...';

			pgClient.connect();

			var sql = "SELECT resultname FROM results res LEFT OUTER JOIN category cat ON res.idcategory = cat.idcategory LEFT OUTER JOIN subcategory scat ON res.idsubcategory = scat.idsubcategory WHERE category = 'Eating'";

			pgClient.query(sql, (err, res) => {
				if (err) throw err;
				for (let row of res.rows) {
					answer += row.resultname + "; ";
				}
				answer += "...Ende der Liste...";
				pgClient.end();

				sendMessage(botType, recipientId, answer);

			});

		}
	}
	else {
		var answer = "Ich verstehe deine Anfrage nicht. Sorry.";
		sendMessage(botType, recipientId, answer);
	}

}

function sendBotAnswer(botType, recipientId, question) {

	if(question.toUpperCase() == "HI") {
		var answer = "Hi. How are you?";
		sendMessage(botType, recipientId, answer);
	}
	else if(question.toUpperCase() == "VERSION") {
		var answer = "Aktuelle Version ist " + VERSION;
		sendMessage(botType, recipientId, answer);
	}
	else {
		//forward question to wit framework

		wit.message(question, {})
			.then((data) =>
			{
				var body = JSON.stringify(data);
				console.log('Wit.ai response: ' + body);
				sendAnswer(botType, recipientId, data);
			})
		.catch(console.error);
	}
}

function sendMessage(botType, recipientId, msg) {
	if(botType == 1) {
		//Native Chat
		sendMessageNativeBot(msg, 'Luzbot', 'red');
	}
	else if(botType == 2) {
		//Facebook Chat
		sendMessageFacebook(recipientId, msg);
	}
}

function sendMessageNativeBot(msg, userName, userColor) {
	// we want to keep history of all sent messages
	var obj = {
		time: (new Date()).getTime(),
		text: htmlEntities(msg),
		author: userName,
		color: userColor
	};
	history.push(obj);
	history = history.slice(-100);

	// broadcast message to all connected clients
	var json = JSON.stringify({ type:'message', data: obj });
	for (var i=0; i < clients.length; i++) {
		clients[i].sendUTF(json);
	}

}

function getAnswer(nlpJson) {
	var answer = "";
	//Process JSON for correct answer

	if (nlpJson['entities']['intent']['0']['value'] === 'temperature_get') {
		answer = "Die aktuelle Temperatur ist...";
	}
	else if (nlpJson['entities']['intent']['0']['value'] === 'temperature_set') {
		answer = "Die neue Temperatur ist " + nlpJson['entities']['temperature']['0']['value'] + ' ' + nlpJson['entities']['temperature']['0']['unit'];
	}
	else if (nlpJson['entities']['intent']['0']['value'] === 'restaurant') {
		pgClient.connect();

		answer = 'Ich zeige dir eine Liste von Restaurants...';

		var sql = "SELECT resultname FROM results res LEFT OUTER JOIN category cat ON res.idcategory = cat.idcategory LEFT OUTER JOIN subcategory scat ON res.idsubcategory = scat.idsubcategory WHERE category = 'Eating'";

		//'SELECT table_schema,table_name FROM information_schema.tables;'

		pgClient.query(sql, (err, res) => {
		if (err) throw err;
		for (let row of res.rows) {
			console.log(JSON.stringify(row));
			answer += JSON.stringify(row);
		}
		pgClient.end();
		});

		answer += "...Ende der Liste...";
	}
	else {
		answer = "Ich verstehe deine Anfrage nicht. Sorry.";
	}

    return answer;
}

// ----------------------------------------------------------------------------
// Facebook Messenger specific code

//Sends a Message in Facebook Chat
function sendMessageFacebook(recipientId, msg) {
	var message = {text: msg};
    request({
        url: 'https://graph.facebook.com/v2.10/me/messages',
        qs: {access_token: FB_PAGE_ACCESS_TOKEN},
        method: 'POST',
        json: {
            recipient: {id: recipientId},
            message: message,
        }
    }, function(error, response, body) {
        if (error) {
            console.log('Error sending message: ', error);
        } else if (response.body.error) {
            console.log('Error: ', response.body.error);
        }
    });
};
<commit_msg>Port for websocket<commit_after>'use strict';

var express = require('express');
var bodyParser = require('body-parser');
var request = require('request');
var app = express();

const PORT = process.env.PORT || 3000;

// Optional. You will see this name in eg. 'ps' or 'top' command
process.title = 'luzbot';

// Port where we'll run the websocket server
var webSocketsServerPort = PORT;

// websocket and http servers
var webSocketServer = require('websocket').server;
var http = require('http');

/**
 * Global variables
 */
// latest 100 messages
var history = [ ];
// list of currently connected clients (users)
var clients = [ ];

let Wit = null;
let log = null;
try {
  // if running from repo
  Wit = require('../').Wit;
  log = require('../').log;
} catch (e) {
  Wit = require('node-wit').Wit;
  log = require('node-wit').log;
}

// Variables are defined in Heroku
const WIT_TOKEN = process.env.WIT_TOKEN;
const FB_PAGE_ACCESS_TOKEN = process.env.PAGE_ACCESS_TOKEN;

//Needs feature Dyno Metadata (https://stackoverflow.com/questions/7917523/how-do-i-access-the-current-heroku-release-version-programmatically)
const VERSION = process.env.HEROKU_RELEASE_VERSION;

const { Client } = require('pg');

const pgClient = new Client({
  connectionString: process.env.DATABASE_URL,
  ssl: true,
});

/**
 * Helper function for escaping input strings
 */
function htmlEntities(str) {
    return String(str).replace(/&/g, '&').replace(/</g, '<')
                      .replace(/>/g, '>').replace(/"/g, '"');
}

// Array with some colors
var colors = [ 'green', 'blue', 'magenta', 'purple', 'plum', 'orange' ];
// ... in random order
colors.sort(function(a,b) { return Math.random() > 0.5; } );

/*
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());
app.listen(PORT);
*/
console.log('Listening on :' + PORT + '...');

/**
 * HTTP server
 */
/*var server = http.createServer(function(request, response) {
    // Not important for us. We're writing WebSocket server, not HTTP server
});
*/
//initialize a simple http server
var server = http.createServer(app);

server.listen(webSocketsServerPort, function() {
    console.log((new Date()) + " Server is listening on port " + webSocketsServerPort);
});

/**
 * WebSocket server
 */
var wsServer = new webSocketServer({
    // WebSocket server is tied to a HTTP server. WebSocket request is just
    // an enhanced HTTP request. For more info http://tools.ietf.org/html/rfc6455#page-6
    httpServer: server
});

// Server frontpage
app.get('/', function (req, res) {
    res.send('This is TestBot Server');
});

// Facebook Webhook
app.get('/webhook', function (req, res) {
    if (req.query['hub.verify_token'] === 'luzbot_hans') {
        res.send(req.query['hub.challenge']);
    } else {
        res.send('Invalid verify token');
    }
});

// handler receiving messages
app.post('/webhook', function (req, res) {
    var events = req.body.entry[0].messaging;
    for (var i = 0; i < events.length; i++) {
        var event = events[i];
        if (event.message && event.message.text) {

			// Yay! We got a new message!
			// We retrieve the Facebook user ID of the sender
			const sender = event.sender.id;

			// We retrieve the user's current session, or create one if it doesn't exist
			// This is needed for our bot to figure out the conversation history
			const sessionId = findOrCreateSession(sender);

			var question = event.message.text;

			console.log('New message detected, text: ' + question);
			console.log('New message detected, sender: ' + sender);

			sendBotAnswer(2, sender, question);

        }
    }
    res.sendStatus(200);
});

// This callback function is called every time someone tries to connect to the WebSocket server
wsServer.on('request', function(request) {
    console.log((new Date()) + ' Connection from origin ' + request.origin + '.');

    // accept connection - you should check 'request.origin' to make sure that
    // client is connecting from your website
    // (http://en.wikipedia.org/wiki/Same_origin_policy)
    var connection = request.accept(null, request.origin);
    // we need to know client index to remove them on 'close' event
    var index = clients.push(connection) - 1;
    var userName = false;
    var userColor = false;

    console.log((new Date()) + ' Connection accepted.');

    // send back chat history
    if (history.length > 0) {
        connection.sendUTF(JSON.stringify( { type: 'history', data: history} ));
    }

    // user sent some message
    connection.on('message', function(message) {
        if (message.type === 'utf8') { // accept only text
            if (userName === false) { // first message sent by user is their name
                // remember user name
                userName = htmlEntities(message.utf8Data);
                // get random color and send it back to the user
                userColor = colors.shift();
                connection.sendUTF(JSON.stringify({ type:'color', data: userColor }));
                console.log((new Date()) + ' User is known as: ' + userName
                            + ' with ' + userColor + ' color.');

            } else { // log and broadcast the message
                console.log((new Date()) + ' Received Message from '
                            + userName + ': ' + message.utf8Data);

				//Eingegeben Nachricht ausgeben...
				sendMessageNativeBot(message.utf8Data, userName, userColor);

                //Sende Bot Anwort...
				var question = message.utf8Data;
				sendBotAnswer(1, 0, question);

            }
        }
    });

    // user disconnected
    connection.on('close', function(connection) {
        if (userName !== false && userColor !== false) {
            console.log((new Date()) + " Peer "
                + connection.remoteAddress + " disconnected.");
            // remove user from the list of connected clients
            clients.splice(index, 1);
            // push back user's color to be reused by another user
            colors.push(userColor);
        }
    });

});

// ----------------------------------------------------------------------------
// Messenger API specific code

// See the Send API reference
// https://developers.facebook.com/docs/messenger-platform/send-api-reference

const fbMessage = (id, text) => {
  const body = JSON.stringify({
    recipient: { id },
    message: { text },
  });
  const qs = 'access_token=' + encodeURIComponent(FB_PAGE_ACCESS_TOKEN);
  return fetch('https://graph.facebook.com/me/messages?' + qs, {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body,
  })
  .then(rsp => rsp.json())
  .then(json => {
    if (json.error && json.error.message) {
      throw new Error(json.error.message);
    }
    return json;
  });
};

// ----------------------------------------------------------------------------
// Wit.ai bot specific code

// This will contain all user sessions.
// Each session has an entry:
// sessionId -> {fbid: facebookUserId, context: sessionState}
const sessions = {};

const findOrCreateSession = (fbid) => {
  let sessionId;
  // Let's see if we already have a session for the user fbid
  Object.keys(sessions).forEach(k => {
    if (sessions[k].fbid === fbid) {
      // Yep, got it!
      sessionId = k;
    }
  });
  if (!sessionId) {
    // No session found for user fbid, let's create a new one
    sessionId = new Date().toISOString();
    sessions[sessionId] = {fbid: fbid, context: {}};
  }
  return sessionId;
};

// Our bot actions
const actions = {
  send({sessionId}, {text}) {
	console.log('Our bot has something to say!');
    // Our bot has something to say!
    // Let's retrieve the Facebook user whose session belongs to
    const recipientId = sessions[sessionId].fbid;
	console.log('Our bot has something to say!' + recipientId);
    if (recipientId) {
		console.log('// Yay, we found our recipient!');
      // Yay, we found our recipient!
      // Let's forward our bot response to her.
      // We return a promise to let our bot know when we're done sending
      return fbMessage(recipientId, text)
      .then(() => null)
      .catch((err) => {
        console.error(
          'Oops! An error occurred while forwarding the response to',
          recipientId,
          ':',
          err.stack || err
        );
      });
    } else {
      console.error('Oops! Couldn\'t find user for session:', sessionId);
      // Giving the wheel back to our bot
      return Promise.resolve()
    }
  },

};

// Setting up our bot
const wit = new Wit({
  accessToken: WIT_TOKEN,
  actions,
  logger: new log.Logger(log.INFO)
});

//Process JSON for correct answer
function sendAnswer(botType, recipientId, nlpJson) {
	if(nlpJson.hasOwnProperty('entities') && Object.keys(nlpJson.entities).length > 0){
		console.log('property entities exists and has at least one entity');

		if (nlpJson['entities']['intent']['0']['value'] === 'temperature_get') {
			var answer = "Die aktuelle Temperatur ist...";
			sendMessage(botType, recipientId, answer);
		}
		else if (nlpJson['entities']['intent']['0']['value'] === 'temperature_set') {
			var answer = "Die neue Temperatur ist ";
			if(nlpJson.entities.hasOwnProperty('temperature')) {
				answer += nlpJson['entities']['temperature']['0']['value'] + ' ' + nlpJson['entities']['temperature']['0']['unit'];
			}
			else {
				answer = "Ich verstehe die neue Temperatur nicht!";
			}

			sendMessage(botType, recipientId, answer);
		}
		else if (nlpJson['entities']['intent']['0']['value'] === 'restaurant') {
			var answer = 'Ich zeige dir eine Liste von Restaurants...';

			pgClient.connect();

			var sql = "SELECT resultname FROM results res LEFT OUTER JOIN category cat ON res.idcategory = cat.idcategory LEFT OUTER JOIN subcategory scat ON res.idsubcategory = scat.idsubcategory WHERE category = 'Eating'";

			pgClient.query(sql, (err, res) => {
				if (err) throw err;
				for (let row of res.rows) {
					answer += row.resultname + "; ";
				}
				answer += "...Ende der Liste...";
				pgClient.end();

				sendMessage(botType, recipientId, answer);

			});

		}
	}
	else {
		var answer = "Ich verstehe deine Anfrage nicht. Sorry.";
		sendMessage(botType, recipientId, answer);
	}

}

function sendBotAnswer(botType, recipientId, question) {

	if(question.toUpperCase() == "HI") {
		var answer = "Hi. How are you?";
		sendMessage(botType, recipientId, answer);
	}
	else if(question.toUpperCase() == "VERSION") {
		var answer = "Aktuelle Version ist " + VERSION;
		sendMessage(botType, recipientId, answer);
	}
	else {
		//forward question to wit framework

		wit.message(question, {})
			.then((data) =>
			{
				var body = JSON.stringify(data);
				console.log('Wit.ai response: ' + body);
				sendAnswer(botType, recipientId, data);
			})
		.catch(console.error);
	}
}

function sendMessage(botType, recipientId, msg) {
	if(botType == 1) {
		//Native Chat
		sendMessageNativeBot(msg, 'Luzbot', 'red');
	}
	else if(botType == 2) {
		//Facebook Chat
		sendMessageFacebook(recipientId, msg);
	}
}

function sendMessageNativeBot(msg, userName, userColor) {
	// we want to keep history of all sent messages
	var obj = {
		time: (new Date()).getTime(),
		text: htmlEntities(msg),
		author: userName,
		color: userColor
	};
	history.push(obj);
	history = history.slice(-100);

	// broadcast message to all connected clients
	var json = JSON.stringify({ type:'message', data: obj });
	for (var i=0; i < clients.length; i++) {
		clients[i].sendUTF(json);
	}

}

function getAnswer(nlpJson) {
	var answer = "";
	//Process JSON for correct answer

	if (nlpJson['entities']['intent']['0']['value'] === 'temperature_get') {
		answer = "Die aktuelle Temperatur ist...";
	}
	else if (nlpJson['entities']['intent']['0']['value'] === 'temperature_set') {
		answer = "Die neue Temperatur ist " + nlpJson['entities']['temperature']['0']['value'] + ' ' + nlpJson['entities']['temperature']['0']['unit'];
	}
	else if (nlpJson['entities']['intent']['0']['value'] === 'restaurant') {
		pgClient.connect();

		answer = 'Ich zeige dir eine Liste von Restaurants...';

		var sql = "SELECT resultname FROM results res LEFT OUTER JOIN category cat ON res.idcategory = cat.idcategory LEFT OUTER JOIN subcategory scat ON res.idsubcategory = scat.idsubcategory WHERE category = 'Eating'";

		//'SELECT table_schema,table_name FROM information_schema.tables;'

		pgClient.query(sql, (err, res) => {
		if (err) throw err;
		for (let row of res.rows) {
			console.log(JSON.stringify(row));
			answer += JSON.stringify(row);
		}
		pgClient.end();
		});

		answer += "...Ende der Liste...";
	}
	else {
		answer = "Ich verstehe deine Anfrage nicht. Sorry.";
	}

    return answer;
}

// ----------------------------------------------------------------------------
// Facebook Messenger specific code

//Sends a Message in Facebook Chat
function sendMessageFacebook(recipientId, msg) {
	var message = {text: msg};
    request({
        url: 'https://graph.facebook.com/v2.10/me/messages',
        qs: {access_token: FB_PAGE_ACCESS_TOKEN},
        method: 'POST',
        json: {
            recipient: {id: recipientId},
            message: message,
        }
    }, function(error, response, body) {
        if (error) {
            console.log('Error sending message: ', error);
        } else if (response.body.error) {
            console.log('Error: ', response.body.error);
        }
    });
};
<|endoftext|>


<commit_before>// const cluster = require('cluster')

global.Promise = require('bluebird')
Promise.config({
  longStackTraces: true
})

// const _ = require('lodash')
const Queue = require('promise-queue')

const env = require('./lib/env')
// const dbs = require('./lib/dbs')
const statsd = require('./lib/statsd')
require('./lib/rollbar')

// if (cluster.isMaster && env.NODE_ENV !== 'development') {
//   for (let i = 0; i++ < env.WORKER_SIZE;) cluster.fork()

//   cluster.on('exit', (worker, code, signal) => {
//     console.log('worker %d died (%s). restarting...', worker.process.pid, signal || code)
//     cluster.fork()
//   })
// } else {
;(async () => {
  const amqp = require('amqplib')

  const conn = await amqp.connect(env.AMQP_URL)
  const channel = await conn.createChannel()

  // 5 different prios because order matters
  // e.g. always sync before everything else
  // or always uninstall integrations before installing
  await channel.assertQueue(env.EVENTS_QUEUE_NAME, {
    maxPriority: 5
  })

  await channel.assertExchange(`${env.JOBS_QUEUE_NAME}-exchange`, 'x-delayed-message', {
    arguments: {
      'x-delayed-type': 'direct'
    }
  })

  // one prio for free, support and paid plans each
  const jobsQueue = await channel.assertQueue(env.JOBS_QUEUE_NAME, {
    maxPriority: 3
  })

  await channel.bindQueue(jobsQueue.queue, `${env.JOBS_QUEUE_NAME}-exchange`, env.JOBS_QUEUE_NAME)

  const scheduleJob = channel.publish.bind(channel, `${env.JOBS_QUEUE_NAME}-exchange`, env.JOBS_QUEUE_NAME)
  const worker = require('./lib/worker').bind(null, scheduleJob, channel)

  // if you need a customized queue configuration, you can add it here
  // e.g. const queues = {'stripe-event': new Queue(1, 10)}
  const queues = {}
  function queueJob (queueId, job) {
    // const q = queues[queueId] = queues[queueId] || new Queue(1, Infinity)
    const q = new Queue(1, Infinity)
    return q.add(() => worker(job))
  }
  channel.consume(env.EVENTS_QUEUE_NAME, consume)
  channel.consume(env.JOBS_QUEUE_NAME, consume)

  if (env.NODE_ENV !== 'testing') {
    setInterval(function collectAccountQueueStats () {
      statsd.gauge('queues.account-jobs', Object.keys(queues).length)
    }, 5000)
  }

  const scheduleRemindersJobData = Buffer.from(JSON.stringify({name: 'schedule-stale-initial-pr-reminders'}))
  async function scheduleReminders () {
    try {
      await scheduleJob(scheduleRemindersJobData, {priority: 1})
    } catch (e) {
      console.log(e)
    }
  }

  setTimeout(scheduleReminders, 5000)
  setInterval(scheduleReminders, 24 * 60 * 60 * 1000)

  async function consume (job) {
    const data = JSON.parse(job.content.toString())
    // const jobsWithoutOwners = ['registry-change', 'stripe-event', 'schedule-stale-initial-pr-reminders', 'reset', 'cancel-stripe-subscription']
    // if (jobsWithoutOwners.includes(data.name) || data.type === 'marketplace_purchase') {
    return queueJob(data.name, job)
    // }

    // let queueId = Number(data.accountId) ||
    //   _.get(data, 'repository.owner.id') ||
    //   _.get(data, 'installation.account.id') ||
    //   _.get(data, 'organization.id')

    // if (!queueId) {
    //   const login = _.get(data, 'repository.owner.name')
    //   try {
    //     if (!login) throw new Error(`can not identify job owner of ${data.name}`)
    //
    //     const {installations} = await dbs()
    //     queueId = _.get(await installations.query('by_login', {
    //       key: login
    //     }), 'rows[0].id')
    //
    //     if (!queueId) throw new Error('totally can not identify job owner')
    //   } catch (e) {
    //     channel.nack(job, false, false)
    //     throw e
    //   }
    // }
    // queueJob(queueId, job)
  }
})()
// }
<commit_msg>Revert "fix(queue): queue all the jobs"<commit_after>// const cluster = require('cluster')

global.Promise = require('bluebird')
Promise.config({
  longStackTraces: true
})

// const _ = require('lodash')
const Queue = require('promise-queue')

const env = require('./lib/env')
// const dbs = require('./lib/dbs')
const statsd = require('./lib/statsd')
require('./lib/rollbar')

// if (cluster.isMaster && env.NODE_ENV !== 'development') {
//   for (let i = 0; i++ < env.WORKER_SIZE;) cluster.fork()

//   cluster.on('exit', (worker, code, signal) => {
//     console.log('worker %d died (%s). restarting...', worker.process.pid, signal || code)
//     cluster.fork()
//   })
// } else {
;(async () => {
  const amqp = require('amqplib')

  const conn = await amqp.connect(env.AMQP_URL)
  const channel = await conn.createChannel()

  // 5 different prios because order matters
  // e.g. always sync before everything else
  // or always uninstall integrations before installing
  await channel.assertQueue(env.EVENTS_QUEUE_NAME, {
    maxPriority: 5
  })

  await channel.assertExchange(`${env.JOBS_QUEUE_NAME}-exchange`, 'x-delayed-message', {
    arguments: {
      'x-delayed-type': 'direct'
    }
  })

  // one prio for free, support and paid plans each
  const jobsQueue = await channel.assertQueue(env.JOBS_QUEUE_NAME, {
    maxPriority: 3
  })

  await channel.bindQueue(jobsQueue.queue, `${env.JOBS_QUEUE_NAME}-exchange`, env.JOBS_QUEUE_NAME)

  const scheduleJob = channel.publish.bind(channel, `${env.JOBS_QUEUE_NAME}-exchange`, env.JOBS_QUEUE_NAME)
  const worker = require('./lib/worker').bind(null, scheduleJob, channel)

  // if you need a customized queue configuration, you can add it here
  // e.g. const queues = {'stripe-event': new Queue(1, 10)}
  const queues = {}
  function queueJob (queueId, job) {
    // const q = queues[queueId] = queues[queueId] || new Queue(1, Infinity)
    const q = new Queue(1, Infinity)
    return q.add(() => worker(job))
  }
  channel.consume(env.EVENTS_QUEUE_NAME, consume)
  channel.consume(env.JOBS_QUEUE_NAME, consume)

  if (env.NODE_ENV !== 'testing') {
    setInterval(function collectAccountQueueStats () {
      statsd.gauge('queues.account-jobs', Object.keys(queues).length)
    }, 5000)
  }

  const scheduleRemindersJobData = Buffer.from(JSON.stringify({name: 'schedule-stale-initial-pr-reminders'}))
  async function scheduleReminders () {
    try {
      await scheduleJob(scheduleRemindersJobData, {priority: 1})
    } catch (e) {
      console.log(e)
    }
  }

  setTimeout(scheduleReminders, 5000)
  setInterval(scheduleReminders, 24 * 60 * 60 * 1000)

  async function consume (job) {
    const data = JSON.parse(job.content.toString())
    const jobsWithoutOwners = ['registry-change', 'stripe-event', 'schedule-stale-initial-pr-reminders', 'reset', 'cancel-stripe-subscription']
    if (jobsWithoutOwners.includes(data.name) || data.type === 'marketplace_purchase') {
      return queueJob(data.name, job)
    }

    // let queueId = Number(data.accountId) ||
    //   _.get(data, 'repository.owner.id') ||
    //   _.get(data, 'installation.account.id') ||
    //   _.get(data, 'organization.id')

    // if (!queueId) {
    //   const login = _.get(data, 'repository.owner.name')
    //   try {
    //     if (!login) throw new Error(`can not identify job owner of ${data.name}`)
    //
    //     const {installations} = await dbs()
    //     queueId = _.get(await installations.query('by_login', {
    //       key: login
    //     }), 'rows[0].id')
    //
    //     if (!queueId) throw new Error('totally can not identify job owner')
    //   } catch (e) {
    //     channel.nack(job, false, false)
    //     throw e
    //   }
    // }
    // queueJob(queueId, job)
  }
})()
// }
<|endoftext|>


<commit_before>/* @flow strict-local */
import type { RealmState, Action, RealmEmojiById } from '../types';
import {
  REALM_INIT,
  EVENT_REALM_EMOJI_UPDATE,
  LOGOUT,
  LOGIN_SUCCESS,
  ACCOUNT_SWITCH,
  EVENT_UPDATE_DISPLAY_SETTINGS,
  EVENT_REALM_FILTERS,
} from '../actionConstants';

// Initial state
const initialState = {
  canCreateStreams: true,
  crossRealmBots: [],
  twentyFourHourTime: false,
  emoji: {},
  filters: [],
  isAdmin: false,
  nonActiveUsers: [],
};

const convertRealmEmoji = (data): RealmEmojiById => {
  const emojis = {};
  Object.keys(data).forEach(id => {
    emojis[id] = { ...data[id], code: id.toString() };
  });
  return emojis;
};

export default (state: RealmState = initialState, action: Action): RealmState => {
  switch (action.type) {
    case ACCOUNT_SWITCH:
      return initialState;

    case REALM_INIT: {
      return {
        ...state,
        canCreateStreams: action.data.can_create_streams,
        crossRealmBots: action.data.cross_realm_bots,
        emoji: convertRealmEmoji(action.data.realm_emoji),
        filters: action.data.realm_filters,
        isAdmin: action.data.is_admin,
        nonActiveUsers: action.data.realm_non_active_users,
        twentyFourHourTime: action.data.twenty_four_hour_time,
      };
    }

    case LOGOUT:
    case LOGIN_SUCCESS:
      return {
        ...state,
        emoji: {},
      };

    case EVENT_REALM_FILTERS:
      return {
        ...state,
        filters: action.realm_filters,
      };

    case EVENT_REALM_EMOJI_UPDATE:
      return {
        ...state,
        emoji: convertRealmEmoji(action.realm_emoji),
      };

    case EVENT_UPDATE_DISPLAY_SETTINGS:
      switch (action.setting_name) {
        case 'twenty_four_hour_time':
          return { ...state, twentyFourHourTime: action.setting };
        default:
          return state;
      }

    default:
      return state;
  }
};
<commit_msg>account: Clear `realm` state too on logout and login.<commit_after>/* @flow strict-local */
import type { RealmState, Action, RealmEmojiById } from '../types';
import {
  REALM_INIT,
  EVENT_REALM_EMOJI_UPDATE,
  LOGOUT,
  LOGIN_SUCCESS,
  ACCOUNT_SWITCH,
  EVENT_UPDATE_DISPLAY_SETTINGS,
  EVENT_REALM_FILTERS,
} from '../actionConstants';

// Initial state
const initialState = {
  canCreateStreams: true,
  crossRealmBots: [],
  twentyFourHourTime: false,
  emoji: {},
  filters: [],
  isAdmin: false,
  nonActiveUsers: [],
};

const convertRealmEmoji = (data): RealmEmojiById => {
  const emojis = {};
  Object.keys(data).forEach(id => {
    emojis[id] = { ...data[id], code: id.toString() };
  });
  return emojis;
};

export default (state: RealmState = initialState, action: Action): RealmState => {
  switch (action.type) {
    case LOGOUT:
    case LOGIN_SUCCESS:
    case ACCOUNT_SWITCH:
      return initialState;

    case REALM_INIT: {
      return {
        ...state,
        canCreateStreams: action.data.can_create_streams,
        crossRealmBots: action.data.cross_realm_bots,
        emoji: convertRealmEmoji(action.data.realm_emoji),
        filters: action.data.realm_filters,
        isAdmin: action.data.is_admin,
        nonActiveUsers: action.data.realm_non_active_users,
        twentyFourHourTime: action.data.twenty_four_hour_time,
      };
    }

    case EVENT_REALM_FILTERS:
      return {
        ...state,
        filters: action.realm_filters,
      };

    case EVENT_REALM_EMOJI_UPDATE:
      return {
        ...state,
        emoji: convertRealmEmoji(action.realm_emoji),
      };

    case EVENT_UPDATE_DISPLAY_SETTINGS:
      switch (action.setting_name) {
        case 'twenty_four_hour_time':
          return { ...state, twentyFourHourTime: action.setting };
        default:
          return state;
      }

    default:
      return state;
  }
};
<|endoftext|>


<commit_before>import * as types from '../constants'

const initialRoute = {path: ['videos']}
const initialState = {route: initialRoute}

export default function navigator(state = initialState, action) {
  switch (action.type) {
  case types.CHANGE_PATH:
    return Object.assign({}, state, {
      route: action.route
    });
  default:
    return state;
  }
}
<commit_msg>Remove navigator reducer<commit_after><|endoftext|>


<commit_before>/**
 * Module dependencies
 */

var envs = require('envs');
var webpack = require('webpack');
var write = require('fs').writeFileSync;
var list = require('fs').readdirSync;
var join = require('path').join;
var byExtension = require('./lib/loaders-by-extension');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var ResolveSelf = require('./lib/resolve-self');

var DISABLE_MIN = !!envs('DISABLE_MIN');
var NODE_ENV = envs('ASSET_ENV', envs('NODE_ENV', 'production'));
var DEVELOPMENT = NODE_ENV === 'development';
var HASH = typeof envs('DISABLE_HASH') === 'undefined';
var MANIFEST = envs('MANIFEST');

module.exports = function(dirname) {
  var config = {};

  /**
   * Configure the entries
   */

  var target = config.target = envs('BUILD_TARGET', 'web');

  // Autoload all of the modules
  config.entry = DEVELOPMENT ? {
    app: dirname + '/index.js'
  } : {
    main: dirname + '/index.js'
  };

  if (target === 'node') {
    config.entry = {
      server: dirname + '/server'
    };
  }

  config.output = {
    path: dirname,
    filename: (DEVELOPMENT || !HASH) ?
      '[name].js' :
      '[name]' + (DISABLE_MIN ? '' : '.min') + '.js?[chunkhash]',
    libraryTarget: 'this'
  };

  if (DEVELOPMENT) {
    config.output.pathinfo = true;
    config.output.publicPath = '/build/';

    if (config.target === 'web') {
      // use the eval builder for optimal speed in development
      config.devtool = 'eval';

      var entries = [config.entry.app];
      // append the hot reload entries
      entries.push('webpack-dev-server/client?http://localhost:' + envs('PORT', '3000'));
      entries.push('webpack/hot/dev-server');
      config.entry = entries;
    }
  }

  /**
   * Configure plugins
   */

  config.plugins = [
    new webpack.IgnorePlugin(/vertx/),
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify(NODE_ENV)
      }
    }),
    new webpack.ResolverPlugin([
      new ResolveSelf()
    ], ['normal'])
  ];

  if (target === 'node' || !DEVELOPMENT) {
    config.plugins.push(new ExtractTextPlugin('[name].css?[chunkhash]'));
  }

  if (!DEVELOPMENT) {
    config.plugins.push(
      new webpack.optimize.AggressiveMergingPlugin({
        moveToParents: true
      })
    );

    if (!envs('DISABLE_MIN')) config.plugins.push(
      new webpack.optimize.OccurrenceOrderPlugin(),
      new webpack.optimize.UglifyJsPlugin({output: {comments: false}}),
      new webpack.optimize.DedupePlugin()
    );

    if (MANIFEST) config.plugins.push(createManifest(MANIFEST));
  } else {
    // append the hot reload plugin
    if (config.target === 'web') config.plugins.push(new webpack.HotModuleReplacementPlugin());
  }

  /**
   * configure resolution
   */

  config.resolve = {
    extensions: ['', '.js', '.json', '.html'],
    modulesDirectories: ['web_modules', 'node_modules', 'src/modules']
  };

  /**
   * Configure loaders
   */

  config.module = {
    loaders: []
  };

  config.addLoader = function(ext, loader) {
    if (ext instanceof RegExp) return config.module.loaders.push({test: ext, loader: loader, loaders: loader});
    var obj = {};
    obj[ext] = loader;
    config.module.loaders.push.apply(config.module.loaders, byExtension(obj));
  };

  config.addLoader('json', 'json-loader');

  /**
   * Setup style loading
   */

  config.addStyle = function(ext, loader) {
    config.addLoader(ext, DEVELOPMENT && target !== 'node' ? 'style-loader!' + loader : ExtractTextPlugin.extract(loader));
  };

  config.addStyle('css', 'css-loader');
  config.addStyle('styl', 'css-loader!stylus-loader?paths=node_modules');

  /**
   * Configure development stuff
   */

  config.load = function() {
    return webpack(config);
  };

  return config;
};

function createManifest(manifest) {
  return function() {
    this.plugin('done', function(stats) {
      var json = stats.toJson()
      var byChunkName = json.assetsByChunkName;
      var out = json.assets.reduce(function(acc, asset) {
        if (!asset.chunkNames.length) {
          acc.chunks.push(asset.name);
          return acc;
        }
        if (~asset.name.indexOf('.css')) acc.styles.push(asset.name);
        if (~asset.name.indexOf('.js')) acc.scripts.push(asset.name);
        return acc;
      }, {
        styles: [],
        scripts: [],
        chunks: []
      });

      write(manifest, JSON.stringify(out, null, '  '));
    });
  };
}
<commit_msg>remove dedupe plugin; doesn't work<commit_after>/**
 * Module dependencies
 */

var envs = require('envs');
var webpack = require('webpack');
var write = require('fs').writeFileSync;
var list = require('fs').readdirSync;
var join = require('path').join;
var byExtension = require('./lib/loaders-by-extension');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var ResolveSelf = require('./lib/resolve-self');

var DISABLE_MIN = !!envs('DISABLE_MIN');
var NODE_ENV = envs('ASSET_ENV', envs('NODE_ENV', 'production'));
var DEVELOPMENT = NODE_ENV === 'development';
var HASH = typeof envs('DISABLE_HASH') === 'undefined';
var MANIFEST = envs('MANIFEST');

module.exports = function(dirname) {
  var config = {};

  /**
   * Configure the entries
   */

  var target = config.target = envs('BUILD_TARGET', 'web');

  // Autoload all of the modules
  config.entry = DEVELOPMENT ? {
    app: dirname + '/index.js'
  } : {
    main: dirname + '/index.js'
  };

  if (target === 'node') {
    config.entry = {
      server: dirname + '/server'
    };
  }

  config.output = {
    path: dirname,
    filename: (DEVELOPMENT || !HASH) ?
      '[name].js' :
      '[name]' + (DISABLE_MIN ? '' : '.min') + '.js?[chunkhash]',
    libraryTarget: 'this'
  };

  if (DEVELOPMENT) {
    config.output.pathinfo = true;
    config.output.publicPath = '/build/';

    if (config.target === 'web') {
      // use the eval builder for optimal speed in development
      config.devtool = 'eval';

      var entries = [config.entry.app];
      // append the hot reload entries
      entries.push('webpack-dev-server/client?http://localhost:' + envs('PORT', '3000'));
      entries.push('webpack/hot/dev-server');
      config.entry = entries;
    }
  }

  /**
   * Configure plugins
   */

  config.plugins = [
    new webpack.IgnorePlugin(/vertx/),
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify(NODE_ENV)
      }
    }),
    new webpack.ResolverPlugin([
      new ResolveSelf()
    ], ['normal'])
  ];

  if (target === 'node' || !DEVELOPMENT) {
    config.plugins.push(new ExtractTextPlugin('[name].css?[chunkhash]'));
  }

  if (!DEVELOPMENT) {
    config.plugins.push(
      new webpack.optimize.AggressiveMergingPlugin({
        moveToParents: true
      })
    );

    if (!envs('DISABLE_MIN')) config.plugins.push(
      new webpack.optimize.OccurrenceOrderPlugin(),
      new webpack.optimize.UglifyJsPlugin({output: {comments: false}})
    );

    if (MANIFEST) config.plugins.push(createManifest(MANIFEST));
  } else {
    // append the hot reload plugin
    if (config.target === 'web') config.plugins.push(new webpack.HotModuleReplacementPlugin());
  }

  /**
   * configure resolution
   */

  config.resolve = {
    extensions: ['', '.js', '.json', '.html'],
    modulesDirectories: ['web_modules', 'node_modules', 'src/modules']
  };

  /**
   * Configure loaders
   */

  config.module = {
    loaders: []
  };

  config.addLoader = function(ext, loader) {
    if (ext instanceof RegExp) return config.module.loaders.push({test: ext, loader: loader, loaders: loader});
    var obj = {};
    obj[ext] = loader;
    config.module.loaders.push.apply(config.module.loaders, byExtension(obj));
  };

  config.addLoader('json', 'json-loader');

  /**
   * Setup style loading
   */

  config.addStyle = function(ext, loader) {
    config.addLoader(ext, DEVELOPMENT && target !== 'node' ? 'style-loader!' + loader : ExtractTextPlugin.extract(loader));
  };

  config.addStyle('css', 'css-loader');
  config.addStyle('styl', 'css-loader!stylus-loader?paths=node_modules');

  /**
   * Configure development stuff
   */

  config.load = function() {
    return webpack(config);
  };

  return config;
};

function createManifest(manifest) {
  return function() {
    this.plugin('done', function(stats) {
      var json = stats.toJson()
      var byChunkName = json.assetsByChunkName;
      var out = json.assets.reduce(function(acc, asset) {
        if (!asset.chunkNames.length) {
          acc.chunks.push(asset.name);
          return acc;
        }
        if (~asset.name.indexOf('.css')) acc.styles.push(asset.name);
        if (~asset.name.indexOf('.js')) acc.scripts.push(asset.name);
        return acc;
      }, {
        styles: [],
        scripts: [],
        chunks: []
      });

      write(manifest, JSON.stringify(out, null, '  '));
    });
  };
}
<|endoftext|>


<commit_before>var path = require('path')
var level = require('level')
var crypto = require('crypto')
var mkdirp = require('mkdirp')
var pumpify = require('pumpify')
var pump = require('pump')
var cuid = require('cuid')
var fs = require('fs')
var fuse = require('fuse-bindings')
var lexint = require('lexicographic-integer')
var union = require('sorted-union-stream')
var events = require('events')
var mknod = require('mknod')
var subleveldown = require('subleveldown')
var enumerate = require('level-enumerate')

var noop = function () {}
var ENOENT = new Error('ENOENT')
ENOENT.code = 'ENOENT'

module.exports = function (home) {
  var that = {}

  var db = level(path.join(home, 'db'))
  var blobs = path.join(home, 'blobs')
  var mounts = path.join(home, 'mounts')

  var getId = enumerate(subleveldown(db, 'ids'))
  var files = subleveldown(db, 'files', {valueEncoding: 'json'})
  var parents = subleveldown(db, 'parents')

  var blobPath = function (hash) {
    return path.join(blobs, hash.slice(0, 2), hash.slice(2, 4), hash.slice(4))
  }

  var toIndexKey = function(name) {
    var depth = name.split('/').length - 1
    return lexint.pack(depth, 'hex') + '!' + name
  }

  that.add = function (layer, filename, stat, cb) {
    var key = layer + '!' + toIndexKey(filename)
    stat.ctime = stat.ctime || Date.now()
    stat.mtime = stat.mtime || Date.now()
    console.log('add', key)
    files.put(key, stat, cb)
  }

  that.get = function (layer, filename, cb) {
    var key = layer + '!' + toIndexKey(filename)
    console.log('get', key)
    files.get(key, cb)
  }

  that.del = function (layer, filename, cb) {
    var key = layer + '!' + toIndexKey(filename)
    files.del(key, cb)
  }

  that.createLayerStream = function (layer) {

  }

  that.createBlobReadStream = function (hash) {
    return fs.createReadStream(blobPath(hash))
  }

  that.createBlobWriteStream = function () {
    var sha = crypto.createHash('sha256')
    var tmp = path.join(os.tmpdir(), 'cauf-file-' + cuid())
    var ws = fs.createWriteStream(tmp)

    ws.on('finish', function () {
      stream.cork()
      stream.key = sha.digest('hex')
      var filename = blobPath(stream.key)
      mkdir(path.join(filename, '..'), function (err) {
        if (err) return stream.destroy(err)
        fs.rename(tmp, filename, function (err) {
          if (err) return stream.destroy(err)
          stream.uncork()
        })
      })
    })

    var stream = pumpify(through(write), ws)
    return stream
  }

  that.unmount = function (mnt, cb) {
    fuse.unmount(mnt, cb)
  }

  that.mount = function (mnt, opts) {
    if (!opts) opts = {}

    var mount = new events.EventEmitter()

    mount.id = null
    mount.writes = null
    mount.layers = null

    mount.unmount = function (cb) {
      that.unmount(mnt, cb)
    }

    var cow = function (name, cb) {
      that.get(mount.id, name, function (err, file) {
        if (file) return cb(null, file)

        console.log('copy-on-write for', mount.id, name)

        var copy = function (file) {
          var done = function (err) {
            if (err) return cb(err)

            var newFile = {
              mode: file ? file.mode : 33188,
              dev: file && file.dev,
              uid: file && file.uid,
              gid: file && file.gid,
              blob: newBlob
            }

            that.add(mount.id, name, newFile, function (err) {
              if (err) return cb(err)
              cb(null, newFile)
            })
          }

          mkdirp(path.join(newBlob, '..'), function (err) {
            if (err) return cb(err)
            if (!file) return done()
            if (file.dev) return mknod(newBlob, file.mode, file.dev, done) // special file
            pump(fs.createReadStream(file.blob), fs.createWriteStream(newBlob), done)
          })
        }

        var newBlob = path.join(mount.writes, name)
        var loop = function (i) {
          if (i < 0) return copy(null)
          that.get(mount.layers[i], name, function (err, file) {
            if (err) return loop(i - 1)
            copy(file.deleted ? null : file)
          })
        }

        loop(mount.layers.length - 2)
      })
    }

    var toCompareKey = function (data) {
      return data.key.slice(data.key.indexOf('!') + 1)
    }

    var createDirStream = function (layer, key) {
      return files.createReadStream({
        gt: layer + '!' + key,
        lt: layer + '!' + key + '\xff'
      })
    }

    var get = function (name, cb) {
      var loop = function (i) {
        if (i < 0) return cb(ENOENT)
        that.get(mount.layers[i], name, function (err, file) {
          if (err) return loop(i - 1)
          if (file.deleted) return cb(ENOENT)
          cb(null, file)
        })
      }

      loop(mount.layers.length - 1)
    }

    var del = function (name, cb) {
      var loop = function (i) {
        if (i < 0) return that.del(mount.id, name, cb)
        that.get(mount.layers[i], name, function (err, file) {
          if (err) return loop(i - 1)
          that.put(mount.id, name, {deleted: true}, cb)
        })
      }

      loop(mount.layers.length - 2)
    }

    var ready = function (root) {
      fuse.mount(mnt, {
        force: true,
        getattr: function (name, cb) {
          if (name === '/') return cb(0, root)

          get(name, function (err, file) {
            if (err) return cb(fuse.errno(err.code))

            var onstat = function (_, st) {
              if (!st) st = root
              cb(0, {
                mode: file.mode,
                size: st.size,
                uid: file.uid || st.uid,
                gid: file.gid || st.gid,
                dev: file.dev || st.dev,
                nlink: file.nlink || st.nlink,
                rdev: file.rdev || st.rdev,
                dev: file.dev || st.dev,
                blksize: file.blksize || st.blksize,
                blocks: file.blocks || st.blocks,
                ino: file.ino || st.ino,
                ctime: new Date(file.ctime || st.ctime.getTime()),
                mtime: new Date(file.mtime || st.mtime.getTime()),
                atime: file.atime || new Date()
              })
            }

            if (file.blob) fs.lstat(file.blob, onstat)
            else onstat(null, root)
          })
        },
        symlink: function (name, dst, cb) {
          cow(dst, function (err, file) { // cow is not needed - just use to get a file handle as it'll never cpy
            if (err) return cb(fuse.errno(err.code))
            fs.writeFile(file.blob, name, function (err) {
              if (err) return cb(fuse.errno(err.code))
              that.add(mount.id, dst, {mode: 41453, blob: file.blob}, function (err) {
                if (err) return cb(fuse.errno(err.code))
                cb(0)
              })
            })
          })
        },
        readlink: function (name, cb) {
          get(name, function (err, file) {
            if (err) return cb(fuse.errno(err.code))
            fs.readFile(file.blob, 'utf-8', function (err, link) {
              if (err) return cb(fuse.errno(err.code))
              cb(0, link)
            })
          })
        },
        link: function (name, dst, cb) {
          // doesn't work
          // get(name, function (err, file) {
          //   if (err) return cb(fuse.errno(err.code))
          //   fs.link(file.blob, path.join(mount.writes, dst), function (err) {
          //     if (err) return cb(fuse.errno(err.code))
          //     that.add(mount.id, dst, file, function (err) {
          //       if (err) return cb(fuse.errno(err.code))
          //       cb(0)
          //     })
          //   })
          // })
          console.error('hardlinks not implemented yet')
          cb(fuse.EPERM)
        },
        readdir: function (name, cb) {
          if (!/\/$/.test(name)) name += '/'
          var key = toIndexKey(name)

          var result = []
          var stream = createDirStream(mount.layers[mount.layers.length - 1], key)
          for (var i = mount.layers.length - 2; i >= 0; i--) {
            stream = union(stream, createDirStream(mount.layers[i], key), toCompareKey)
          }

          stream.on('error', function (err) {
            cb(fuse.errno(err.code))
          })

          stream.on('data', function (data) {
            if (data.value.deleted) return
            result.push(data.key.slice(data.key.lastIndexOf('/') + 1)) // haxx
          })

          stream.on('end', function () {
            cb(null, result)
          })
        },
        mknod: function (name, mode, dev, cb) {
          var blob = path.join(mount.writes, name)
          mknod(blob, mode, dev, function (err) {
            if (err) return cb(fuse.errno(err.code))
            that.add(mount.id, name, {mode: mode, dev: dev, blob: blob}, function (err) {
              if (err) return cb(fuse.errno(err.code))
              cb(0)
            })
          })
        },
        open: function (name, flags, cb) {
          var readonly = function () {
            get(name, function (err, file) {
              if (err) return cb(fuse.errno(err.code))
              if (file.dev) return writeMaybe() // special file - always cow

              fs.open(file.blob, 'r', function (err, fd) {
                if (err) return cb(fuse.errno(err.code))
                cb(0, fd)
              })
            })
          }

          var writeMaybe = function () {
            cow(name, function (err, file) {
              if (err) return cb(fuse.errno(err))
              fs.open(file.blob, flags, function (err, fd) {
                if (err) return cb(fuse.errno(err))
                cb(0, fd)
              })
            })
          }

          if (flags === 0) readonly() // readonly
          else writeMaybe() // cow
        },
        read: function (name, fd, buf, len, offset, cb) {
          fs.read(fd, buf, 0, len, offset, function (err, bytes) {
            if (err) return cb(fuse.errno(err.code))
            cb(bytes)
          })
        },
        release: function (name, fd, cb) {
          fs.close(fd, function (err) {
            if (err) return cb(fuse.errno(err.code))
            cb(0)
          })
        },
        create: function (name, mode, cb) {
          var blob = path.join(mount.writes, name)
          mkdirp(path.join(blob, '..'), function (err) {
            if (err) return cb(fuse.errno(err.code))
            fs.open(blob, 'w', mode, function (err, fd) {
              if (err) return cb(fuse.errno(err.code))
              that.add(mount.id, name, {mode: mode, blob: blob}, function (err) {
                if (err) return cb(fuse.errno(err.code))
                cb(0, fd)
              })
            })
          })
        },
        write: function (name, fd, buf, len, offset, cb) {
          fs.write(fd, buf, 0, len, offset, function (err, bytes) {
            if (err) return cb(fuse.errno(err.code))
            cb(bytes)
          })
        },
        unlink: function (name, cb) {
          var blob = path.join(mount.writes, name)
          fs.unlink(blob, function () { // ignore error as this is just gc
            del(name, function (err) {
              if (err) return cb(fuse.errno(err.code))
              cb(0)
            })
          })
        },
        mkdir: function (name, mode, cb) {
          that.add(mount.id, name, {mode: mode}, function (err) {
            if (err) return cb(fuse.errno(err.code))
            cb(0)
          })
        },
        rmdir: function (name, cb) {
          var blob = path.join(mount.writes, name)
          fs.rmdir(blob, function (err) { // ignore error as this is just gc
            del(name, function (err) {
              if (err) return cb(fuse.errno(err.code))
              cb(0)
            })
          })
        },
        utimens: function (name, ctime, mtime, cb) {
          cow(name, function (err, file) {
            if (err) return cb(fuse.errno(err.code))
            file.ctime = ctime.getTime()
            file.mtime = mtime.getTime()
            that.add(mount.id, name, file, function (err) {
              if (err) return cb(fuse.errno(err.code))
              cb(0)
            })
          })
        },
        chmod: function (name, mode, cb) {
          cow(name, function (err, file) {
            if (err) return cb(fuse.errno(err.code))
            file.mode = mode
            that.add(mount.id, name, file, function (err) {
              if (err) return cb(fuse.errno(err.code))
              cb(0)
            })
          })
        },
        chown: function (name, uid, gid, cb) {
          cow(name, function (err, file) {
            if (err) return cb(fuse.errno(err.code))
            file.uid = uid
            file.gid = gid
            that.add(mount.id, name, file, function (err) {
              if (err) return cb(fuse.errno(err.code))
              cb(0)
            })
          })
        },
        truncate: function (name, size, cb) {
          cow(name, function (err, file) {
            if (err) return cb(fuse.errno(err))
            fs.truncate(file.blob, size, function (err) {
              if (err) return cb(fuse.errno(err.code))
              cb(0)
            })
          })
        }
      }, function (err) {
        if (err) mount.emit('error', err)
        else mount.emit('ready')
      })
    }

    var onid = function (err, id) {
      if (err) return mount.emit('error', err)

      mount.id = id.toString()
      mount.writes = path.join(mounts, mount.id)
      mount.layers = [].concat(opts.layers || [], mount.id)
      mount.mountpoint = mnt

      mkdirp(mnt, function (err) {
        if (err) return mount.emit('error', err)
        mkdirp(mount.writes, function (err) {
          if (err) return mount.emit('error', err)
          fs.stat(mnt, function (err, st) {
            if (err) return mount.emit('error', err)
            ready(st)
          })
        })
      })
    }

    if (opts.id) return onid(null, opts.id)
    getId(mnt, onid)

    return mount
  }

  return that
}
<commit_msg>couple of fixes<commit_after>var path = require('path')
var level = require('level')
var crypto = require('crypto')
var mkdirp = require('mkdirp')
var pumpify = require('pumpify')
var pump = require('pump')
var cuid = require('cuid')
var fs = require('fs')
var fuse = require('fuse-bindings')
var lexint = require('lexicographic-integer')
var union = require('sorted-union-stream')
var events = require('events')
var mknod = require('mknod')
var subleveldown = require('subleveldown')
var enumerate = require('level-enumerate')

var noop = function () {}
var ENOENT = new Error('ENOENT')
ENOENT.code = 'ENOENT'

module.exports = function (home) {
  var that = {}

  var db = level(path.join(home, 'db'))
  var blobs = path.join(home, 'blobs')
  var mounts = path.join(home, 'mounts')

  var getId = enumerate(subleveldown(db, 'ids'))
  var files = subleveldown(db, 'files', {valueEncoding: 'json'})
  var parents = subleveldown(db, 'parents')

  var blobPath = function (hash) {
    return path.join(blobs, hash.slice(0, 2), hash.slice(2, 4), hash.slice(4))
  }

  var toIndexKey = function(name) {
    var depth = name.split('/').length - 1
    return lexint.pack(depth, 'hex') + '!' + name
  }

  that.add = function (layer, filename, stat, cb) {
    var key = layer + '!' + toIndexKey(filename)
    stat.ctime = stat.ctime || Date.now()
    stat.mtime = stat.mtime || Date.now()
    console.log('add', key)
    files.put(key, stat, cb)
  }

  that.get = function (layer, filename, cb) {
    var key = layer + '!' + toIndexKey(filename)
    console.log('get', key)
    files.get(key, cb)
  }

  that.del = function (layer, filename, cb) {
    var key = layer + '!' + toIndexKey(filename)
    files.del(key, cb)
  }

  that.createLayerStream = function (layer) {

  }

  that.createBlobReadStream = function (hash) {
    return fs.createReadStream(blobPath(hash))
  }

  that.createBlobWriteStream = function () {
    var sha = crypto.createHash('sha256')
    var tmp = path.join(os.tmpdir(), 'cauf-file-' + cuid())
    var ws = fs.createWriteStream(tmp)

    ws.on('finish', function () {
      stream.cork()
      stream.key = sha.digest('hex')
      var filename = blobPath(stream.key)
      mkdir(path.join(filename, '..'), function (err) {
        if (err) return stream.destroy(err)
        fs.rename(tmp, filename, function (err) {
          if (err) return stream.destroy(err)
          stream.uncork()
        })
      })
    })

    var stream = pumpify(through(write), ws)
    return stream
  }

  that.unmount = function (mnt, cb) {
    fuse.unmount(mnt, cb)
  }

  that.mount = function (mnt, opts) {
    if (!opts) opts = {}

    var mount = new events.EventEmitter()

    mount.id = null
    mount.writes = null
    mount.layers = null

    mount.unmount = function (cb) {
      that.unmount(mnt, cb)
    }

    var cow = function (name, cb) {
      that.get(mount.id, name, function (err, file) {
        if (file) return cb(null, file)

        console.log('copy-on-write for', mount.id, name)

        var copy = function (file) {
          var done = function (err) {
            if (err) return cb(err)

            var newFile = {
              mode: file ? file.mode : 33188,
              rdev: file && file.rdev,
              uid: file && file.uid,
              gid: file && file.gid,
              blob: newBlob
            }

            that.add(mount.id, name, newFile, function (err) {
              if (err) return cb(err)
              cb(null, newFile)
            })
          }

          mkdirp(path.join(newBlob, '..'), function (err) {
            if (err) return cb(err)
            if (!file) return done()
            if (file.rdev) return mknod(newBlob, file.mode, file.rdev, done) // special file
            pump(fs.createReadStream(file.blob), fs.createWriteStream(newBlob), done)
          })
        }

        var newBlob = path.join(mount.writes, name)
        var loop = function (i) {
          if (i < 0) return copy(null)
          that.get(mount.layers[i], name, function (err, file) {
            if (err) return loop(i - 1)
            copy(file.deleted ? null : file)
          })
        }

        loop(mount.layers.length - 2)
      })
    }

    var toCompareKey = function (data) {
      return data.key.slice(data.key.indexOf('!') + 1)
    }

    var createDirStream = function (layer, key) {
      return files.createReadStream({
        gt: layer + '!' + key,
        lt: layer + '!' + key + '\xff'
      })
    }

    var get = function (name, cb) {
      var loop = function (i) {
        if (i < 0) return cb(ENOENT)
        that.get(mount.layers[i], name, function (err, file) {
          if (err) return loop(i - 1)
          if (file.deleted) return cb(ENOENT)
          cb(null, file)
        })
      }

      loop(mount.layers.length - 1)
    }

    var del = function (name, cb) {
      var loop = function (i) {
        if (i < 0) return that.del(mount.id, name, cb)
        that.get(mount.layers[i], name, function (err, file) {
          if (err) return loop(i - 1)
          that.put(mount.id, name, {deleted: true}, cb)
        })
      }

      loop(mount.layers.length - 2)
    }

    var ready = function (root) {
      fuse.mount(mnt, {
        force: true,
        getattr: function (name, cb) {
          if (name === '/') return cb(0, root)

          get(name, function (err, file) {
            if (err) return cb(fuse.errno(err.code))

            var onstat = function (_, st) {
              if (!st) st = root
              cb(0, {
                mode: file.mode,
                size: st.size,
                uid: file.uid || st.uid,
                gid: file.gid || st.gid,
                dev: file.dev || st.dev,
                nlink: file.nlink || st.nlink,
                rdev: file.rdev || st.rdev,
                dev: file.dev || st.dev,
                blksize: file.blksize || st.blksize,
                blocks: file.blocks || st.blocks,
                ino: file.ino || st.ino,
                ctime: new Date(file.ctime || st.ctime.getTime()),
                mtime: new Date(file.mtime || st.mtime.getTime()),
                atime: file.atime || new Date()
              })
            }

            if (file.blob) fs.lstat(file.blob, onstat)
            else onstat(null, root)
          })
        },
        symlink: function (name, dst, cb) {
          cow(dst, function (err, file) { // cow is not needed - just use to get a file handle as it'll never cpy
            if (err) return cb(fuse.errno(err.code))
            fs.writeFile(file.blob, name, function (err) {
              if (err) return cb(fuse.errno(err.code))
              that.add(mount.id, dst, {mode: 41453, blob: file.blob}, function (err) {
                if (err) return cb(fuse.errno(err.code))
                cb(0)
              })
            })
          })
        },
        readlink: function (name, cb) {
          get(name, function (err, file) {
            if (err) return cb(fuse.errno(err.code))
            fs.readFile(file.blob, 'utf-8', function (err, link) {
              if (err) return cb(fuse.errno(err.code))
              cb(0, link)
            })
          })
        },
        link: function (name, dst, cb) {
          // doesn't work
          // get(name, function (err, file) {
          //   if (err) return cb(fuse.errno(err.code))
          //   fs.link(file.blob, path.join(mount.writes, dst), function (err) {
          //     if (err) return cb(fuse.errno(err.code))
          //     that.add(mount.id, dst, file, function (err) {
          //       if (err) return cb(fuse.errno(err.code))
          //       cb(0)
          //     })
          //   })
          // })
          console.error('hardlinks not implemented yet')
          cb(fuse.EPERM)
        },
        readdir: function (name, cb) {
          if (!/\/$/.test(name)) name += '/'
          var key = toIndexKey(name)

          var result = []
          var stream = createDirStream(mount.layers[mount.layers.length - 1], key)
          for (var i = mount.layers.length - 2; i >= 0; i--) {
            stream = union(stream, createDirStream(mount.layers[i], key), toCompareKey)
          }

          stream.on('error', function (err) {
            cb(fuse.errno(err.code))
          })

          stream.on('data', function (data) {
            if (data.value.deleted) return
            result.push(data.key.slice(data.key.lastIndexOf('/') + 1)) // haxx
          })

          stream.on('end', function () {
            cb(null, result)
          })
        },
        mknod: function (name, mode, dev, cb) {
          console.log('calling mknod', name)
          var blob = path.join(mount.writes, name)
          mknod(blob, mode, dev, function (err) {
            if (err) return cb(fuse.errno(err.code))
            that.add(mount.id, name, {mode: mode, rdev: dev, blob: blob}, function (err) {
              if (err) return cb(fuse.errno(err.code))
              cb(0)
            })
          })
        },
        open: function (name, flags, cb) {
          var readonly = function () {
            get(name, function (err, file) {
              if (err) return cb(fuse.errno(err.code))
              if (file.rdev) return writeMaybe() // special file - always cow

              fs.open(file.blob, 'r', function (err, fd) {
                if (err) return cb(fuse.errno(err.code))
                cb(0, fd)
              })
            })
          }

          var writeMaybe = function () {
            cow(name, function (err, file) {
              if (err) return cb(fuse.errno(err))
              fs.open(file.blob, flags, function (err, fd) {
                if (err) return cb(fuse.errno(err))
                cb(0, fd)
              })
            })
          }

          if (flags === 0) readonly() // readonly
          else writeMaybe() // cow
        },
        read: function (name, fd, buf, len, offset, cb) {
          fs.read(fd, buf, 0, len, offset, function (err, bytes) {
            if (err) return cb(fuse.errno(err.code))
            cb(bytes)
          })
        },
        release: function (name, fd, cb) {
          fs.close(fd, function (err) {
            if (err) return cb(fuse.errno(err.code))
            cb(0)
          })
        },
        create: function (name, mode, cb) {
          var blob = path.join(mount.writes, name)
          mkdirp(path.join(blob, '..'), function (err) {
            if (err) return cb(fuse.errno(err.code))
            fs.open(blob, 'w', mode, function (err, fd) {
              if (err) return cb(fuse.errno(err.code))
              that.add(mount.id, name, {mode: mode, blob: blob}, function (err) {
                if (err) return cb(fuse.errno(err.code))
                cb(0, fd)
              })
            })
          })
        },
        write: function (name, fd, buf, len, offset, cb) {
          fs.write(fd, buf, 0, len, offset, function (err, bytes) {
            if (err) return cb(fuse.errno(err.code))
            cb(bytes)
          })
        },
        unlink: function (name, cb) {
          var blob = path.join(mount.writes, name)
          fs.unlink(blob, function () { // ignore error as this is just gc
            del(name, function (err) {
              if (err) return cb(fuse.errno(err.code))
              cb(0)
            })
          })
        },
        mkdir: function (name, mode, cb) {
          that.add(mount.id, name, {mode: mode | 040000}, function (err) {
            if (err) return cb(fuse.errno(err.code))
            cb(0)
          })
        },
        rmdir: function (name, cb) {
          var blob = path.join(mount.writes, name)
          fs.rmdir(blob, function (err) { // ignore error as this is just gc
            del(name, function (err) {
              if (err) return cb(fuse.errno(err.code))
              cb(0)
            })
          })
        },
        utimens: function (name, ctime, mtime, cb) {
          cow(name, function (err, file) {
            if (err) return cb(fuse.errno(err.code))
            file.ctime = ctime.getTime()
            file.mtime = mtime.getTime()
            that.add(mount.id, name, file, function (err) {
              if (err) return cb(fuse.errno(err.code))
              cb(0)
            })
          })
        },
        chmod: function (name, mode, cb) {
          cow(name, function (err, file) {
            if (err) return cb(fuse.errno(err.code))
            file.mode = mode
            that.add(mount.id, name, file, function (err) {
              if (err) return cb(fuse.errno(err.code))
              cb(0)
            })
          })
        },
        chown: function (name, uid, gid, cb) {
          cow(name, function (err, file) {
            if (err) return cb(fuse.errno(err.code))
            file.uid = uid
            file.gid = gid
            that.add(mount.id, name, file, function (err) {
              if (err) return cb(fuse.errno(err.code))
              cb(0)
            })
          })
        },
        truncate: function (name, size, cb) {
          cow(name, function (err, file) {
            if (err) return cb(fuse.errno(err))
            fs.truncate(file.blob, size, function (err) {
              if (err) return cb(fuse.errno(err.code))
              cb(0)
            })
          })
        }
      }, function (err) {
        if (err) mount.emit('error', err)
        else mount.emit('ready')
      })
    }

    var onid = function (err, id) {
      if (err) return mount.emit('error', err)

      mount.id = id.toString()
      mount.writes = path.join(mounts, mount.id)
      mount.layers = [].concat(opts.layers || [], mount.id)
      mount.mountpoint = mnt

      mkdirp(mnt, function (err) {
        if (err) return mount.emit('error', err)
        mkdirp(mount.writes, function (err) {
          if (err) return mount.emit('error', err)
          fs.stat(mnt, function (err, st) {
            if (err) return mount.emit('error', err)
            ready(st)
          })
        })
      })
    }

    if (opts.id) return onid(null, opts.id)
    getId(mnt, onid)

    return mount
  }

  return that
}
<|endoftext|>