<commit_before>#!/usr/bin/env node

var fs = require('fs');
var _ = require('lodash');
var http = require('http');
var https = require('https');
var domain = require('domain');
var moment = require('moment');
var parser = require('nomnom');
var Promise = require("bluebird");
var GithubApi = require('github');
var linkParser = require('parse-link-header');
var ghauth = Promise.promisify(require('ghauth'));
var commitStream = require('github-commit-stream');

// Increase number of concurrent requests
http.globalAgent.maxSockets = 30;
https.globalAgent.maxSockets = 30;

// It might be faster to just go through commits on the branch
// instead of iterating over closed issues, look into this later.
//
// Even better yet. I might just be able to do this with git log.
// tags: git log --tags --simplify-by-decoration --format="%ci%n%d"
// prs: git log --grep="Merge pull request #" --format="%s%n%ci%n%b"

// parse cli options
opts = parser
  .scriptName('github-changes')
  .option('owner', {
    abbr: 'o'
  , help: '(required) owner of the Github repository'
  , required: true
  })
  .option('repository', {
    abbr: 'r'
  , help: '(required) name of the Github repository'
  , required: true
  })
  .option('data', {
    abbr: 'd'
  , help: '(DEPRECATED) use pull requests or commits (choices: pulls, commits)'
  , choices: ['pulls', 'commits']
  , default: 'commits'
  })
  .option('branch', {
    abbr: 'b'
  , help: 'name of the default branch'
  , default: 'master'
  })
  .option('tag-name', {
    abbr: 'n'
  , help: 'tag name for upcoming release'
  , default: 'upcoming'
  })
  .option('auth', {
    abbr: 'a'
  , help: 'prompt to auth with Github - use this for private repos and higher rate limits'
  , flag: true
  })
  .option('token', {
    abbr: 'k'
  , help: 'need to use this or --auth for private repos and higher rate limits'
  })
  .option('file', {
    abbr: 'f'
  , help: 'name of the file to output the changelog to'
  , default: 'CHANGELOG.md'
  })
  .option('verbose', {
    abbr: 'v'
  , help: 'output details'
  , flag: true
  })
  .option('issue-body', {
    help: '(DEPRECATED) include the body of the issue (--data MUST equal \'pulls\')'
  , flag: true
  })
  .option('no-merges', {
    help: 'do not include merges'
  , flag: true
  })
  .option('only-merges', {
    help: 'only include merges'
  , flag: true
  })
  .option('only-pulls', {
    help: 'only include pull requests'
  , flag: true
  })
  .option('use-commit-body', {
    help: 'use the commit body of a merge instead of the message - "Merge branch..."'
  , flag: true
  })
  // TODO
  // .option('template', {
  //   abbr: 't'
  // , help: '(optional) template to use to generate the changelog'
  // })
  .parse()
;

if (opts['only-pulls']) opts.merges = true;

var currentDate = moment();

var github = new GithubApi({
  version: '3.0.0'
, timeout: 10000
});

// github auth token
var token = null;

// ~/.config/changelog.json will store the token
var authOptions = {
  configName : 'changelog'
, scopes     : ['user', 'public_repo', 'repo']
};

Promise.promisifyAll(github.repos);
Promise.promisifyAll(github.issues);
Promise.promisifyAll(github.pullRequests);

// TODO: Could probably fetch releases so we don't have to get the commit data
// for the sha of each tag to figure out the date. Could save alot on api
// calls.
var getTags = function(){
  var tagOpts = {
    user: opts.owner
  , repo: opts.repository
  };
  auth();
  return github.repos.getTagsAsync(tagOpts).map(function(ref){
    auth();
    return github.repos.getCommitAsync({
      user: tagOpts.user
    , repo: tagOpts.repo
    , sha: ref.commit.sha
    }).then(function(commit){
      opts.verbose && console.log('pulled commit data for tag - ', ref.name);
      return {
        name: ref.name
      , date: moment(commit.commit.committer.date)
      };
    });
  }).then(function(tags){
    return tags;
  });
};

var getPullRequests = function(){
  var issueOpts = {
    user: opts.owner
  , repo: opts.repository
  , state: 'closed'
  , sort: 'updated'
  , direction: 'desc'
  , per_page: 100
  , page: 1
  // , since: null // TODO: this is an improvement to save API calls
  };

  var getIssues = function(options){
    auth();
    return github.issues.repoIssuesAsync(options).then(function(issues){
      opts.verbose && console.log('issues pulled - ', issues.length);
      opts.verbose && console.log('issues page - ', options.page);
      return issues;
    });
  };

  return getIssues(issueOpts).then(function(issues){
    var linkHeader = linkParser(issues.meta.link)
    var totalPages = (linkHeader && linkHeader.last) ? linkHeader.last.page : 1;

    if (totalPages > issueOpts.page) {
      var allReqs = [];
      for(var i=issueOpts.page; i<totalPages; i++){
        var newOptions = _.clone(issueOpts, true);
        newOptions.page += i;
        allReqs.push(getIssues(newOptions));
      }
      return Promise.all(allReqs).reduce(function(issues, moreIssues){
        return issues.concat(moreIssues);
      }, issues);
    }
    return issues;
  }).map(function(issue){
    if (!issue.pull_request.html_url) return;

    auth();
    return github.pullRequests.getAsync({
      user: issueOpts.user
    , repo: issueOpts.repo
    , number: issue.number
    }).then(function(pr){
      if (pr.base.ref !== opts.branch) return;
      if (!pr.merged_at) return;
      return pr;
    });
  }).reduce(function(scrubbed, pr){
    if (pr) scrubbed.push(pr);
    return scrubbed;
  }, [])
  .then(function(prs){
    return prs;
  });
};

var getAllCommits = function() {
  opts.verbose && console.log('fetching commits');
  return new Promise(function(resolve, reject){
    var commits = [];
    commitStream({
      token: token
    , user: opts.owner
    , repo: opts.repository
    , sha: opts.branch
    , per_page: 100
    }).on('data', function(data){
      commits = commits.concat(data);
    }).on('end', function(error){
      if (error) return reject(error);
      opts.verbose && console.log('fetched all commits');
      return resolve(commits);
    });
  });
};

var getData = function() {
  if (opts.data === 'commits') return getAllCommits();
  return getPullRequests();
};

var tagger = function(sortedTags, data) {
  var date = null;
  if (opts.data === 'commits') date = moment(data.commit.committer.date);
  else date = moment(data.merged_at);

  var current = null;
  for (var i=0, len=sortedTags.length; i < len; i++) {
    var tag = sortedTags[i];
    if (tag.date < date) break;
    current = tag;
  }
  if (!current) current = {name: opts['tag-name'], date: currentDate};
  return current;
};

var prFormatter = function(data) {
  var currentTagName = '';
  var output = "## Change Log\n";
  data.forEach(function(pr){
    if (pr.tag === null) {
      currentTagName = opts['tag-name'];
      output+= "\n### " + opts['tag-name'];
      output+= "\n";
    } else if (pr.tag.name != currentTagName) {
      currentTagName = pr.tag.name;
      output+= "\n### " + pr.tag.name
      output+= " (" + pr.tag.date.utc().format("YYYY/MM/DD HH:mm Z") + ")";
      output+= "\n";
    }

    output += "- [#" + pr.number + "](" + pr.html_url + ") " + pr.title
    if (pr.user && pr.user.login) output += " (@" + pr.user.login + ")";
    if (opts['issue-body'] && pr.body && pr.body.trim()) output += "\n\n    >" + pr.body.trim().replace(/\n/ig, "\n    > ") +"\n";
    output += "\n";
  });
  return output.trim();
};

var commitFormatter = function(data) {
  var currentTagName = '';
  var output = "## Change Log\n";
  data.forEach(function(commit){
    // exits
    if ((opts.merges === false) && commit.parents.length > 1) return '';
    if ((opts['only-merges']) && commit.parents.length < 2) return '';
    if (
      (opts['only-pulls'])
    && !(/^Merge pull request #/i.test(commit.commit.message))
    ) return '';

    var messages = commit.commit.message.split('\n');
    var message = messages.shift();

    if (opts['use-commit-body'] && commit.parents.length > 1) {
      message = messages.join(' ').trim();
      if (message === '') return;
    }

    if (commit.tag === null) {
      currentTagName = opts['tag-name'];
      output+= "\n### " + opts['tag-name'];
      output+= "\n";
    } else if (commit.tag.name != currentTagName) {
      currentTagName = commit.tag.name;
      output+= "\n### " + commit.tag.name
      output+= " (" + commit.tag.date.utc().format("YYYY/MM/DD HH:mm Z") + ")";
      output+= "\n";
    }

    // if it's a pull request, then the link should be to the pull request
    if (/^Merge pull request #/i.test(commit.commit.message)){
      var prNumber = commit.commit.message.split('#')[1].split(' ')[0];
      var author = commit.commit.message.split(/\#\d+\sfrom\s/)[1].split('/')[0];
      var url = "https://github.com/"+opts.owner+"/"+opts.repository+"/pull/"+prNumber;
      output += "- [#" + prNumber + "](" + url + ") " + message;
      output += " (@" + author + ")";
    } else { //otherwise link to the commit
      output += "- [" + commit.sha.substr(0, 7) + "](" + commit.html_url + ") " + message;
      if (commit.author && commit.author.login) output += " (@" + commit.author.login + ")";
    }
    output += "\n";
  });
  return output.trim();
};

var formatter = function(data) {
  if (opts.data === 'commits') return commitFormatter(data);
  return prFormatter(data);
};

var getGithubToken = function() {
  if (opts.token) return Promise.resolve({token: opts.token});
  if (opts.auth) return ghauth(authOptions);
  return Promise.resolve({});
};

var auth = function() {
  if (!token) return;
  github.authenticate({type: 'oauth', token: token});
};

var task = function() {
  getGithubToken()
    .then(function(authData){
      if (!authData.token) return;
      token = authData.token;
    })
    .then(function(){
      return Promise.all([getTags(), getData()])
    })
    .spread(function(tags, data){
      allTags = _.sortBy(tags, 'date').reverse();
      return data;
    })
    .map(function(data){
      data.tag = tagger(allTags, data);
      data.tagDate = data.tag.date;
      return data;
    })
    .then(function(data){
      data = _.sortBy(data, 'tagDate').reverse();
      return data;
    })
    .then(function(data){
      fs.writeFileSync(opts.file, formatter(data));
    })
    .then(function(){
      process.exit(0);
    })
    .catch(function(error){
      console.error('error', error);
      console.error('stack', error.stack);
      process.exit(1);
    })
  ;
};

var done = function (error) {
  if (!error) process.exit(0);
  console.log(error);
  console.log(error.stack);
  process.exit(1);
};

var runner = function () {
  var d = domain.create();
  d.on('error', done);
  d.run(task);
};

runner();<commit_msg>add option to order by semver<commit_after>#!/usr/bin/env node

var fs = require('fs');
var _ = require('lodash');
var http = require('http');
var https = require('https');
var domain = require('domain');
var moment = require('moment');
var parser = require('nomnom');
var semver = require('semver');
var Promise = require("bluebird");
var GithubApi = require('github');
var linkParser = require('parse-link-header');
var ghauth = Promise.promisify(require('ghauth'));
var commitStream = require('github-commit-stream');

// Increase number of concurrent requests
http.globalAgent.maxSockets = 30;
https.globalAgent.maxSockets = 30;

// It might be faster to just go through commits on the branch
// instead of iterating over closed issues, look into this later.
//
// Even better yet. I might just be able to do this with git log.
// tags: git log --tags --simplify-by-decoration --format="%ci%n%d"
// prs: git log --grep="Merge pull request #" --format="%s%n%ci%n%b"

// parse cli options
opts = parser
  .scriptName('github-changes')
  .option('owner', {
    abbr: 'o'
  , help: '(required) owner of the Github repository'
  , required: true
  })
  .option('repository', {
    abbr: 'r'
  , help: '(required) name of the Github repository'
  , required: true
  })
  .option('data', {
    abbr: 'd'
  , help: '(DEPRECATED) use pull requests or commits (choices: pulls, commits)'
  , choices: ['pulls', 'commits']
  , default: 'commits'
  })
  .option('branch', {
    abbr: 'b'
  , help: 'name of the default branch'
  , default: 'master'
  })
  .option('tag-name', {
    abbr: 'n'
  , help: 'tag name for upcoming release'
  , default: 'upcoming'
  })
  .option('auth', {
    abbr: 'a'
  , help: 'prompt to auth with Github - use this for private repos and higher rate limits'
  , flag: true
  })
  .option('token', {
    abbr: 'k'
  , help: 'need to use this or --auth for private repos and higher rate limits'
  })
  .option('file', {
    abbr: 'f'
  , help: 'name of the file to output the changelog to'
  , default: 'CHANGELOG.md'
  })
  .option('verbose', {
    abbr: 'v'
  , help: 'output details'
  , flag: true
  })
  .option('issue-body', {
    help: '(DEPRECATED) include the body of the issue (--data MUST equal \'pulls\')'
  , flag: true
  })
  .option('no-merges', {
    help: 'do not include merges'
  , flag: true
  })
  .option('only-merges', {
    help: 'only include merges'
  , flag: true
  })
  .option('only-pulls', {
    help: 'only include pull requests'
  , flag: true
  })
  .option('use-commit-body', {
    help: 'use the commit body of a merge instead of the message - "Merge branch..."'
  , flag: true
  })
  .option('order-semver', {
    help: 'use semantic versioning for the ordering instead of the tag date'
  , flag: true
  })
  // TODO
  // .option('template', {
  //   abbr: 't'
  // , help: '(optional) template to use to generate the changelog'
  // })
  .parse()
;

if (opts['only-pulls']) opts.merges = true;

var currentDate = moment();

var github = new GithubApi({
  version: '3.0.0'
, timeout: 10000
});

// github auth token
var token = null;

// ~/.config/changelog.json will store the token
var authOptions = {
  configName : 'changelog'
, scopes     : ['user', 'public_repo', 'repo']
};

Promise.promisifyAll(github.repos);
Promise.promisifyAll(github.issues);
Promise.promisifyAll(github.pullRequests);

// TODO: Could probably fetch releases so we don't have to get the commit data
// for the sha of each tag to figure out the date. Could save alot on api
// calls.
var getTags = function(){
  var tagOpts = {
    user: opts.owner
  , repo: opts.repository
  };
  auth();
  return github.repos.getTagsAsync(tagOpts).map(function(ref){
    auth();
    return github.repos.getCommitAsync({
      user: tagOpts.user
    , repo: tagOpts.repo
    , sha: ref.commit.sha
    }).then(function(commit){
      opts.verbose && console.log('pulled commit data for tag - ', ref.name);
      return {
        name: ref.name
      , date: moment(commit.commit.committer.date)
      };
    });
  }).then(function(tags){
    return tags;
  });
};

var getPullRequests = function(){
  var issueOpts = {
    user: opts.owner
  , repo: opts.repository
  , state: 'closed'
  , sort: 'updated'
  , direction: 'desc'
  , per_page: 100
  , page: 1
  // , since: null // TODO: this is an improvement to save API calls
  };

  var getIssues = function(options){
    auth();
    return github.issues.repoIssuesAsync(options).then(function(issues){
      opts.verbose && console.log('issues pulled - ', issues.length);
      opts.verbose && console.log('issues page - ', options.page);
      return issues;
    });
  };

  return getIssues(issueOpts).then(function(issues){
    var linkHeader = linkParser(issues.meta.link)
    var totalPages = (linkHeader && linkHeader.last) ? linkHeader.last.page : 1;

    if (totalPages > issueOpts.page) {
      var allReqs = [];
      for(var i=issueOpts.page; i<totalPages; i++){
        var newOptions = _.clone(issueOpts, true);
        newOptions.page += i;
        allReqs.push(getIssues(newOptions));
      }
      return Promise.all(allReqs).reduce(function(issues, moreIssues){
        return issues.concat(moreIssues);
      }, issues);
    }
    return issues;
  }).map(function(issue){
    if (!issue.pull_request.html_url) return;

    auth();
    return github.pullRequests.getAsync({
      user: issueOpts.user
    , repo: issueOpts.repo
    , number: issue.number
    }).then(function(pr){
      if (pr.base.ref !== opts.branch) return;
      if (!pr.merged_at) return;
      return pr;
    });
  }).reduce(function(scrubbed, pr){
    if (pr) scrubbed.push(pr);
    return scrubbed;
  }, [])
  .then(function(prs){
    return prs;
  });
};

var getAllCommits = function() {
  opts.verbose && console.log('fetching commits');
  return new Promise(function(resolve, reject){
    var commits = [];
    commitStream({
      token: token
    , user: opts.owner
    , repo: opts.repository
    , sha: opts.branch
    , per_page: 100
    }).on('data', function(data){
      commits = commits.concat(data);
    }).on('end', function(error){
      if (error) return reject(error);
      opts.verbose && console.log('fetched all commits');
      return resolve(commits);
    });
  });
};

var getData = function() {
  if (opts.data === 'commits') return getAllCommits();
  return getPullRequests();
};

var tagger = function(sortedTags, data) {
  var date = null;
  if (opts.data === 'commits') date = moment(data.commit.committer.date);
  else date = moment(data.merged_at);

  var current = null;
  for (var i=0, len=sortedTags.length; i < len; i++) {
    var tag = sortedTags[i];
    if (tag.date < date) break;
    current = tag;
  }
  if (!current) current = {name: opts['tag-name'], date: currentDate};
  return current;
};

var prFormatter = function(data) {
  var currentTagName = '';
  var output = "## Change Log\n";
  data.forEach(function(pr){
    if (pr.tag === null) {
      currentTagName = opts['tag-name'];
      output+= "\n### " + opts['tag-name'];
      output+= "\n";
    } else if (pr.tag.name != currentTagName) {
      currentTagName = pr.tag.name;
      output+= "\n### " + pr.tag.name
      output+= " (" + pr.tag.date.utc().format("YYYY/MM/DD HH:mm Z") + ")";
      output+= "\n";
    }

    output += "- [#" + pr.number + "](" + pr.html_url + ") " + pr.title
    if (pr.user && pr.user.login) output += " (@" + pr.user.login + ")";
    if (opts['issue-body'] && pr.body && pr.body.trim()) output += "\n\n    >" + pr.body.trim().replace(/\n/ig, "\n    > ") +"\n";
    output += "\n";
  });
  return output.trim();
};

var commitFormatter = function(data) {
  var currentTagName = '';
  var output = "## Change Log\n";
  data.forEach(function(commit){
    // exits
    if ((opts.merges === false) && commit.parents.length > 1) return '';
    if ((opts['only-merges']) && commit.parents.length < 2) return '';
    if (
      (opts['only-pulls'])
    && !(/^Merge pull request #/i.test(commit.commit.message))
    ) return '';

    var messages = commit.commit.message.split('\n');
    var message = messages.shift().trim();

    if (opts['use-commit-body'] && commit.parents.length > 1) {
      message = messages.join(' ').trim();
      if (message === '') return;
    }

    if (commit.tag === null) {
      currentTagName = opts['tag-name'];
      output+= "\n### " + opts['tag-name'];
      output+= "\n";
    } else if (commit.tag.name != currentTagName) {
      currentTagName = commit.tag.name;
      output+= "\n### " + commit.tag.name
      output+= " (" + commit.tag.date.utc().format("YYYY/MM/DD HH:mm Z") + ")";
      output+= "\n";
    }

    // if it's a pull request, then the link should be to the pull request
    if (/^Merge pull request #/i.test(commit.commit.message)){
      var prNumber = commit.commit.message.split('#')[1].split(' ')[0];
      var author = commit.commit.message.split(/\#\d+\sfrom\s/)[1].split('/')[0];
      var url = "https://github.com/"+opts.owner+"/"+opts.repository+"/pull/"+prNumber;
      output += "- [#" + prNumber + "](" + url + ") " + message;
      output += " (@" + author + ")";
    } else { //otherwise link to the commit
      output += "- [" + commit.sha.substr(0, 7) + "](" + commit.html_url + ") " + message;
      if (commit.author && commit.author.login) output += " (@" + commit.author.login + ")";
    }
    output += "\n";
  });
  return output.trim();
};

var formatter = function(data) {
  if (opts.data === 'commits') return commitFormatter(data);
  return prFormatter(data);
};

var getGithubToken = function() {
  if (opts.token) return Promise.resolve({token: opts.token});
  if (opts.auth) return ghauth(authOptions);
  return Promise.resolve({});
};

var auth = function() {
  if (!token) return;
  github.authenticate({type: 'oauth', token: token});
};

var task = function() {
  getGithubToken()
    .then(function(authData){
      if (!authData.token) return;
      token = authData.token;
    })
    .then(function(){
      return Promise.all([getTags(), getData()])
    })
    .spread(function(tags, data){
      allTags = _.sortBy(tags, 'date').reverse();
      return data;
    })
    .map(function(data){
      data.tag = tagger(allTags, data);
      data.tagDate = data.tag.date;
      return data;
    })
    .then(function(data){
      // order by date DESC
      if (!opts['order-semver']) return _.sortBy(data, 'tagDate').reverse();

      // order by semver DESC
      data = data.sort(function(a,b){
        if (a.tag.name === opts['tag-name']) return 1;
        if (b.tag.name === opts['tag-name']) return -1;
        return semver.compare(a.tag.name, b.tag.name);
      }).reverse();
      return data;
    })
    .then(function(data){
      fs.writeFileSync(opts.file, formatter(data));
    })
    .then(function(){
      process.exit(0);
    })
    .catch(function(error){
      console.error('error', error);
      console.error('stack', error.stack);
      process.exit(1);
    })
  ;
};

var done = function (error) {
  if (!error) process.exit(0);
  console.log(error);
  console.log(error.stack);
  process.exit(1);
};

var runner = function () {
  var d = domain.create();
  d.on('error', done);
  d.run(task);
};

runner();<|endoftext|>


<commit_before>"use strict";

// To lint the JS code in this project, run:
//
//   jslint.js bin/piped.js lib/*.js --nomen --plusplus --white --node --continue --eqeq --vars --evil --forin --regexp
//
// Also see:
//
//   http://www.jslint.com/

// *********************************
// Libraries
// *********************************

var U               = require('util');
var Base            = require('../lib/base');
var C               = require('../lib/common').common();
var Configurator    = require('../lib/configurator');
var LocalListen     = require('../lib/local_listen');
var RemoteSend      = require('../lib/remote_send');
var RemotePool      = require('../lib/remote_pool');
var AdminServer     = require('../lib/admin_server');
var Dispatcher      = require('../lib/dispatcher');

// *********************************
// Utility functions
// *********************************

function _usage( msg ) {
    var usage = "\
Usage: node bin/piped.js [--config=/path/to/configfile] [--option=value, ...]\n\
\n\
Examples:\n\
    node bin/piped.js --config=/etc/piped/config.js --debug --trace\n\
\n\
    node bin/piped.js --servers='[\"tcp://foo:1234\"]' --admin_port=/tmp/admin.sock\n";

    return msg ? "ERROR: " + msg + "\n\n" + usage : usage;
}

// *********************************
// Main program
// *********************************

(function( opts ) {
    // Callback will be called when the config is ready to go.
    Configurator.Configurator( opts, function( config_object ) {

        // We only care about the config at this point, not the
        // default config or options passed in
        var config = config_object.config;

        /* Basic error checking */

        // Did you want usage info?
        if( config_object.opts.help || config_object.opts.h ) {
            process.stderr.write( _usage() );
            process.exit(0);
        }

        // No servers means fatality; where would we connect to?
        if( !config.servers[0].length) {
            throw( _usage("No server entries detected: " + U.inspect( config.servers )) );
        }

        // No ports means fatality: where would you connect to?
        if(!config.udp_port && !config.tcp_port && !config.unix_socket && !config.stdin) {
            throw( _usage("No listening sockets detected: " + U.inspect( config )) );
        }

        var BO = new Base.BaseObject();

        // This will now be available to any other object building
        // off of BaseObject; It's the FIRST thing we should set, so
        // all other code can access it.
        BO._set_config_object( config_object );

        // If you enabled trace, let's show you the config we're
        // running with
        C._trace( config_object );

        // We'll add all the listeners we have here.
        var state = BO.state_object();

        // *********************************
        // Admin Server
        // *********************************
        state.listeners.admin = AdminServer.AdminServer( config.admin_port, config.admin_bind_address );

        // *********************************
        // Statsd backend?
        // *********************************

        if( config.statsd_port ) {
            var statsd = RemoteSend.UDP(
                            'statsd', config.statsd_port, config.statsd_host );

            BO._set_statsd_object( statsd );

            C._debug( U.format( 'Using statsd backend udp://%s:%s',
                config.statsd_host, config.statsd_port ) );
        }

        // *********************************
        // Remote connections
        // *********************************
        RemotePool.RemotePool(config.servers).connect_to_servers(function(remote_pool) {

            // LocalListeners expect to be provided a callback function on
            // what to do with the incoming data/connection they receive.
            // We use a dispatcher class for that, and we'll hand a dispatch
            // function as the callback
            var dispatcher = Dispatcher.Dispatcher( );

            // Remotes are now established. Time to listen locally to start
            // accepting traffic.

            // *********************************
            // TCP server
            // *********************************

            if( config.tcp_port ) {
                state.listeners.tcp = new LocalListen.Stream(
                    'tcp', config.tcp_port, config.bind_address, dispatcher.dispatch
                );
            }

            // *********************************
            // Unix socket
            // *********************************

            if( config.unix_socket ) {
                state.listeners.socket = new LocalListen.Stream(
                    'socket', config.unix_socket, false, dispatcher.dispatch
                );
            }

            // *********************************
            // UDP server
            // *********************************

            if( config.udp_port ) {
                state.listeners.udp = new LocalListen.UDP(
                    'udp', config.udp_port, config.bind_address, dispatcher.dispatch
                );
            }

            // *********************************
            // Stdin
            // *********************************

            if( config.stdin ) {
                state.listeners.stdin = new LocalListen.STDIN(
                    'stdin', dispatcher.dispatch );
            }

        });
    });
}( process.argv.slice(2) ) );
<commit_msg>* make it possible to disable the admin server<commit_after>"use strict";

// To lint the JS code in this project, run:
//
//   jslint.js bin/piped.js lib/*.js --nomen --plusplus --white --node --continue --eqeq --vars --evil --forin --regexp
//
// Also see:
//
//   http://www.jslint.com/

// *********************************
// Libraries
// *********************************

var U               = require('util');
var Base            = require('../lib/base');
var C               = require('../lib/common').common();
var Configurator    = require('../lib/configurator');
var LocalListen     = require('../lib/local_listen');
var RemoteSend      = require('../lib/remote_send');
var RemotePool      = require('../lib/remote_pool');
var AdminServer     = require('../lib/admin_server');
var Dispatcher      = require('../lib/dispatcher');

// *********************************
// Utility functions
// *********************************

function _usage( msg ) {
    var usage = "\
Usage: node bin/piped.js [--config=/path/to/configfile] [--option=value, ...]\n\
\n\
Examples:\n\
    node bin/piped.js --config=/etc/piped/config.js --debug --trace\n\
\n\
    node bin/piped.js --servers='[\"tcp://foo:1234\"]' --admin_port=/tmp/admin.sock\n";

    return msg ? "ERROR: " + msg + "\n\n" + usage : usage;
}

// *********************************
// Main program
// *********************************

(function( opts ) {
    // Callback will be called when the config is ready to go.
    Configurator.Configurator( opts, function( config_object ) {

        // We only care about the config at this point, not the
        // default config or options passed in
        var config = config_object.config;

        /* Basic error checking */

        // Did you want usage info?
        if( config_object.opts.help || config_object.opts.h ) {
            process.stderr.write( _usage() );
            process.exit(0);
        }

        // No servers means fatality; where would we connect to?
        if( !config.servers[0].length) {
            throw( _usage("No server entries detected: " + U.inspect( config.servers )) );
        }

        // No ports means fatality: where would you connect to?
        if(!config.udp_port && !config.tcp_port && !config.unix_socket && !config.stdin) {
            throw( _usage("No listening sockets detected: " + U.inspect( config )) );
        }

        var BO = new Base.BaseObject();

        // This will now be available to any other object building
        // off of BaseObject; It's the FIRST thing we should set, so
        // all other code can access it.
        BO._set_config_object( config_object );

        // If you enabled trace, let's show you the config we're
        // running with
        C._trace( config_object );

        // We'll add all the listeners we have here.
        var state = BO.state_object();

        // *********************************
        // Admin Server
        // *********************************

        // You may have /explicitly/ disabled it. Fine, then we won't start it
        if( config.admin_port ) {
            state.listeners.admin = AdminServer.AdminServer( config.admin_port, config.admin_bind_address );
        }

        // *********************************
        // Statsd backend?
        // *********************************

        if( config.statsd_port ) {
            var statsd = RemoteSend.UDP(
                            'statsd', config.statsd_port, config.statsd_host );

            BO._set_statsd_object( statsd );

            C._debug( U.format( 'Using statsd backend udp://%s:%s',
                config.statsd_host, config.statsd_port ) );
        }

        // *********************************
        // Remote connections
        // *********************************
        RemotePool.RemotePool(config.servers).connect_to_servers(function(remote_pool) {

            // LocalListeners expect to be provided a callback function on
            // what to do with the incoming data/connection they receive.
            // We use a dispatcher class for that, and we'll hand a dispatch
            // function as the callback
            var dispatcher = Dispatcher.Dispatcher( );

            // Remotes are now established. Time to listen locally to start
            // accepting traffic.

            // *********************************
            // TCP server
            // *********************************

            if( config.tcp_port ) {
                state.listeners.tcp = new LocalListen.Stream(
                    'tcp', config.tcp_port, config.bind_address, dispatcher.dispatch
                );
            }

            // *********************************
            // Unix socket
            // *********************************

            if( config.unix_socket ) {
                state.listeners.socket = new LocalListen.Stream(
                    'socket', config.unix_socket, false, dispatcher.dispatch
                );
            }

            // *********************************
            // UDP server
            // *********************************

            if( config.udp_port ) {
                state.listeners.udp = new LocalListen.UDP(
                    'udp', config.udp_port, config.bind_address, dispatcher.dispatch
                );
            }

            // *********************************
            // Stdin
            // *********************************

            if( config.stdin ) {
                state.listeners.stdin = new LocalListen.STDIN(
                    'stdin', dispatcher.dispatch );
            }

        });
    });
}( process.argv.slice(2) ) );
<|endoftext|>


<commit_before>#!/usr/bin/env node

var argv = require('optimist').argv;

// Build sails instance
var sails = require('../lib');
sails.config = {
  appPath: process.cwd(),
  prod: argv.prod,

  // Indicate that this is a mock config
  mock: true
};
if(argv.verbose){
  sails.config.log = {level: 'verbose'};
}
require('../lib/configuration')(sails).load(function (err) {
  if (err) throw new Error(err);

  // Dependencies
  var _ = require('lodash'),
    utils = require('./utils.js')(sails),
    fs = utils.fs,
    generate = require('./generate.js')(sails),
    newSailsApp = require('./new.js')(sails);

  // If coffeescript is not installed, fail silently
  try {
    require('coffee-script');
    sails.log.verbose('Enabling CoffeeScript...');
  } catch (e) {
    sails.log.verbose('CoffeeScript not installed.');
  }

  // Stringify args
  argv._ = _.map(argv._, function (arg) {
    return arg + '';
  });

  // Known errors
  var errors = {
    badLocalSails: function (requiredVersion) {
      return 'You may consider reinstalling Sails locally (npm install sails@' + requiredVersion + ').';
    }
  };

  // Read package.json file in specified path
  function getPackage(path) {
    path = require('underscore.string').rtrim(path, '/');
    var packageJson = fs.readFileSync(path + '/package.json', 'utf-8');
    try {
      packageJson = JSON.parse(packageJson);
    } catch (e) {
      return false;
    }
    return packageJson;
  }

  // Start this app
  if (argv._[0] && _.contains(['lift', 'raise', 'launch', 'start', 'server', 'run', 's', 'l'], argv._[0])) {

    require('./lift.js')(sails)(argv);
  }

  // Check if console was requested, if so, launch console
  else if (_.contains(['console'], argv._[0])) {
    console.log();
    sails.log('Welcome to the Sails console (v' + sails.version + ')');
    sails.log('( to exit, type <CTRL>+<C> )');

    sails.lift({
      log: {
        level: 'silent'
      }
    }, function () {
      repl = require("repl").start("sails> ");
      repl.on('exit', function () {
        sails.log.verbose('Closing console');
        process.exit();
      });
    });

    return;
  }

  // Check for newer version and upgrade if available.
  else if (_.contains(['upgrade'], argv._[0])) {
    var sys = require('sys');
    var exec = require('child_process').exec;
    var child;
    var http = require('http');
    var newest;
    var current;
    var options = {
      host: 'registry.npmjs.org',
      port: 80,
      path: '/sails'
    };
    http.get(options, function (res) {
      var jsond = '';
      var body = '';
      res.on('data', function (chunk) {
        body += chunk;
      });
      res.on('end', function () {
        jsond = JSON.parse(body);
        if (jsond['dist-tags'].latest > sails.version) {
          // executes `pwd`
          child = exec("npm install sails@" + jsond['dist-tags'].latest, function (error, stdout, stderr) {
            if (error !== null) {
              console.log('exec error: ' + error);
            }
            console.log("Upgrade Complete:  You are now on Sails Version: " + jsond['dist-tags'].latest);
          });
        } else {
          console.log("Already Up To Date");
        }
      });
    }).on('error', function (e) {
      console.error(e);
    });
  }

  // Get the sails version
  else if (argv.v || argv.version || (argv._[0] && _.contains(['v', 'version'], argv._[0]))) {
    sails.log.info('v' + sails.version);
  }

  // Basic usage
  else if (argv._.length === 0) {
    console.log('');
    sails.log('Welcome to Sails! (v' + sails.version + ')');
    console.log('');
    sailsUsage();
  }

  // Generate file(s)
  else if (argv._[0] && (argv._[0].match(/^g$|^ge$|^gen$|^gene$|^gener$|^genera$|^generat$|^generate$/) || argv.g || argv.generate)) {

    verifyArg(1, 'Please specify the name for the new model and controller as the second argument.');

    // Generate a model
    if (argv._[1] === 'model') {
      var entity = argv._[2];
      verifyArg(2, 'Please specify the name for the new model as the third argument.');

      // Figure out attributes based on args
      var options = _.extend({}, argv);
      var args = argv._.splice(3);
      options.attributes = [];
      _.each(args, function (attribute, i) {
        var parts = attribute.split(':');
        if (!parts[1]) {
          sails.log.error('Please specify the type for attribute ' + (i + 1) + ' "' + parts[0] + '".');
          process.exit(1);
        }
        options.attributes.push({
          name: parts[0],
          type: parts[1].toUpperCase()
        });
      });

      sails.log.warn('For the record :: to serve the blueprint API for this model,');
      sails.log.warn('you\'ll also need to have an empty controller.');
      generate.generateModel(entity, options);
      sails.log.info("Generated model for " + entity + '!');
    }

    // Generate a controller
    else if (argv._[1] === 'controller') {
      var entity = argv._[2];
      verifyArg(2, 'Please specify the name for the new controller as the third argument.');

      // Figure out actions based on args
      var options = _.extend({}, argv);
      options.actions = argv._.splice(3);

      generate.generateController(entity, options);
      sails.log.info("Generated controller for " + entity + '!');
    }

    // // Generate a view
    // else if(argv._[1] === 'view') {
    // 	var entity = argv._[2];
    // 	verifyArg(2, "Please specify the name for the new view as the third argument.");
    // 	// Figure out actions based on args
    // 	var options = _.extend({},argv);
    // 	options.actions = argv._.splice(3);
    // 	generate.generateView(entity, options);
    // }

    // Generate an adapter
    else if (argv._[1] === 'adapter') {
      var entity = argv._[2];
      verifyArg(2, "Please specify the name for the new argument as the third argument.");

      // Figure out attributes based on args
      var options = _.extend({}, argv);
      generate.generateAdapter(entity, options);
      sails.log.info("Generated adapter for " + entity + '!');
    }
    // Otherwise generate a model and controller
    else {
      var entity = argv._[1];
      verifyArg(1, "Please specify the name of the entity as the second argument to generate a model, controller, and view.");
      sails.log.info("Generating model and controller for " + entity + '...');

      var options = _.extend({}, argv);
      options.actions = argv._.splice(2);

      generate.generateModel(entity, options);
      generate.generateController(entity, options);
    }
  }

  // Create a new app
  // second argument == app name
  else if (argv._[0].match(/^new$/)) {

    verifyArg(1, "Please specify the name of the new project directory to create: e.g.\n sails new <appName>");

    // Default to ejs templates for new projects, but allow user to override with --template
    var template = 'ejs';
    if (argv.template) {
      template = argv.template;
    }

    // Default to not using the script linker functionality, but allow an override
    // with --linker option
    var useLinker = false
    if (argv.linker) {
      useLinker = true;
    }

    // TODO: change to single options object we pass in.
    newSailsApp(argv._[1], template, useLinker);
  }

  // Build a www directory of everyting from /.tmp/public (aka /assets)
  else if (argv._[0].match(/^build$/)) {
    return sails.build();
  }

  // Unknown command, print out usage
  else {
    console.log('');
    sailsUsage();
    sails.log.error(argv._[0] + ' is not a valid action.');
  }

  // Display usage
  function sailsUsage() {
    function leftColumn(str) {
      var n = (33 - str.length);
      return str + require('underscore.string').repeat(' ', n);
    }

    var usage = 'Usage: sails <command>\n\n';
    usage += leftColumn('sails lift') + 'Run this Sails app (in the current dir)\n';
    usage += leftColumn('  [--dev]') + 'with development environment specified \n';
    usage += leftColumn('  [--prod]') + 'with production environment specified \n';
    usage += leftColumn('sails console') + 'Run this Sails app (in the current dir & in interactive mode.)\n';
    usage += leftColumn('sails new <appName>') + 'Create a new Sails project in a folder called <appName>\n';
    usage += leftColumn('sails new <appName> --linker') + 'Create a new Sails project in a folder called <appName>, using automatic asset linking\n';
    usage += leftColumn('sails generate <foo>') + 'Generate api/models/Foo.js and api/controllers/FooController.js\n';
    usage += leftColumn('sails generate model <foo>') + 'Generate api/models/Foo.js\n';
    usage += leftColumn('sails generate controller <foo>') + 'Generate api/controllers/FooController.js\n';
    usage += leftColumn('sails version') + 'Get the current globally installed Sails version';

    sails.log.info(usage);
  }

  // Verify that an argument exists
  function verifyArg(argNo, msg) {
    if (!argv._[argNo]) {
      sails.log.error(msg);
      process.exit(1);
    }
  }
});<commit_msg>Added a "sails issue" command for building out management commands to run within the context of a sails app.<commit_after>#!/usr/bin/env node

var argv = require('optimist').argv;

// Build sails instance
var sails = require('../lib');
sails.config = {
  appPath: process.cwd(),
  prod: argv.prod,

  // Indicate that this is a mock config
  mock: true
};
if(argv.verbose){
  sails.config.log = {level: 'verbose'};
}
require('../lib/configuration')(sails).load(function (err) {
  if (err) throw new Error(err);

  // Dependencies
  var _ = require('lodash'),
    utils = require('./utils.js')(sails),
    fs = utils.fs,
    generate = require('./generate.js')(sails),
    newSailsApp = require('./new.js')(sails);

  // If coffeescript is not installed, fail silently
  try {
    require('coffee-script');
    sails.log.verbose('Enabling CoffeeScript...');
  } catch (e) {
    sails.log.verbose('CoffeeScript not installed.');
  }

  // Stringify args
  argv._ = _.map(argv._, function (arg) {
    return arg + '';
  });

  // Known errors
  var errors = {
    badLocalSails: function (requiredVersion) {
      return 'You may consider reinstalling Sails locally (npm install sails@' + requiredVersion + ').';
    }
  };

  // Read package.json file in specified path
  function getPackage(path) {
    path = require('underscore.string').rtrim(path, '/');
    var packageJson = fs.readFileSync(path + '/package.json', 'utf-8');
    try {
      packageJson = JSON.parse(packageJson);
    } catch (e) {
      return false;
    }
    return packageJson;
  }

  // Start this app
  if (argv._[0] && _.contains(['lift', 'raise', 'launch', 'start', 'server', 'run', 's', 'l'], argv._[0])) {

    require('./lift.js')(sails)(argv);
  }

  // Check if console was requested, if so, launch console
  else if (_.contains(['console'], argv._[0])) {
    console.log();
    sails.log('Welcome to the Sails console (v' + sails.version + ')');
    sails.log('( to exit, type <CTRL>+<C> )');

    sails.lift({
      log: {
        level: 'silent'
      }
    }, function () {
      repl = require("repl").start("sails> ");
      repl.on('exit', function () {
        sails.log.verbose('Closing console');
        process.exit();
      });
    });

    return;
  }

  // Check for newer version and upgrade if available.
  else if (_.contains(['upgrade'], argv._[0])) {
    var sys = require('sys');
    var exec = require('child_process').exec;
    var child;
    var http = require('http');
    var newest;
    var current;
    var options = {
      host: 'registry.npmjs.org',
      port: 80,
      path: '/sails'
    };
    http.get(options, function (res) {
      var jsond = '';
      var body = '';
      res.on('data', function (chunk) {
        body += chunk;
      });
      res.on('end', function () {
        jsond = JSON.parse(body);
        if (jsond['dist-tags'].latest > sails.version) {
          // executes `pwd`
          child = exec("npm install sails@" + jsond['dist-tags'].latest, function (error, stdout, stderr) {
            if (error !== null) {
              console.log('exec error: ' + error);
            }
            console.log("Upgrade Complete:  You are now on Sails Version: " + jsond['dist-tags'].latest);
          });
        } else {
          console.log("Already Up To Date");
        }
      });
    }).on('error', function (e) {
      console.error(e);
    });
  }

  // Get the sails version
  else if (argv.v || argv.version || (argv._[0] && _.contains(['v', 'version'], argv._[0]))) {
    sails.log.info('v' + sails.version);
  }

  // Basic usage
  else if (argv._.length === 0) {
    console.log('');
    sails.log('Welcome to Sails! (v' + sails.version + ')');
    console.log('');
    sailsUsage();
  }

  // Generate file(s)
  else if (argv._[0] && (argv._[0].match(/^g$|^ge$|^gen$|^gene$|^gener$|^genera$|^generat$|^generate$/) || argv.g || argv.generate)) {

    verifyArg(1, 'Please specify the name for the new model and controller as the second argument.');

    // Generate a model
    if (argv._[1] === 'model') {
      var entity = argv._[2];
      verifyArg(2, 'Please specify the name for the new model as the third argument.');

      // Figure out attributes based on args
      var options = _.extend({}, argv);
      var args = argv._.splice(3);
      options.attributes = [];
      _.each(args, function (attribute, i) {
        var parts = attribute.split(':');
        if (!parts[1]) {
          sails.log.error('Please specify the type for attribute ' + (i + 1) + ' "' + parts[0] + '".');
          process.exit(1);
        }
        options.attributes.push({
          name: parts[0],
          type: parts[1].toUpperCase()
        });
      });

      sails.log.warn('For the record :: to serve the blueprint API for this model,');
      sails.log.warn('you\'ll also need to have an empty controller.');
      generate.generateModel(entity, options);
      sails.log.info("Generated model for " + entity + '!');
    }

    // Generate a controller
    else if (argv._[1] === 'controller') {
      var entity = argv._[2];
      verifyArg(2, 'Please specify the name for the new controller as the third argument.');

      // Figure out actions based on args
      var options = _.extend({}, argv);
      options.actions = argv._.splice(3);

      generate.generateController(entity, options);
      sails.log.info("Generated controller for " + entity + '!');
    }

    // // Generate a view
    // else if(argv._[1] === 'view') {
    // 	var entity = argv._[2];
    // 	verifyArg(2, "Please specify the name for the new view as the third argument.");
    // 	// Figure out actions based on args
    // 	var options = _.extend({},argv);
    // 	options.actions = argv._.splice(3);
    // 	generate.generateView(entity, options);
    // }

    // Generate an adapter
    else if (argv._[1] === 'adapter') {
      var entity = argv._[2];
      verifyArg(2, "Please specify the name for the new argument as the third argument.");

      // Figure out attributes based on args
      var options = _.extend({}, argv);
      generate.generateAdapter(entity, options);
      sails.log.info("Generated adapter for " + entity + '!');
    }
    // Otherwise generate a model and controller
    else {
      var entity = argv._[1];
      verifyArg(1, "Please specify the name of the entity as the second argument to generate a model, controller, and view.");
      sails.log.info("Generating model and controller for " + entity + '...');

      var options = _.extend({}, argv);
      options.actions = argv._.splice(2);

      generate.generateModel(entity, options);
      generate.generateController(entity, options);
    }
  }

  // Create a new app
  // second argument == app name
  else if (argv._[0].match(/^new$/)) {

    verifyArg(1, "Please specify the name of the new project directory to create: e.g.\n sails new <appName>");

    // Default to ejs templates for new projects, but allow user to override with --template
    var template = 'ejs';
    if (argv.template) {
      template = argv.template;
    }

    // Default to not using the script linker functionality, but allow an override
    // with --linker option
    var useLinker = false
    if (argv.linker) {
      useLinker = true;
    }

    // TODO: change to single options object we pass in.
    newSailsApp(argv._[1], template, useLinker);
  }

  // Build a www directory of everyting from /.tmp/public (aka /assets)
  else if (argv._[0].match(/^build$/)) {
    return sails.build();
  }

  /**
   * Run a management command. Management commands should take a single callback argument.
   *
   * Usage: sails issue <foo>
   *    – where <foo> is exported from <sails.config.appPath>/commands
   */
  else if (argv._[0].match(/^issue$/)) {

    verifyArg(1, 'Please specity the name of the command to run: e.g.\n sails issue <command>');

    var command = argv._[1],
        commands;

    try {
      commands = require(sails.config.appPath + '/commands');
    } catch(e) {
      sails.log.error('\nModule not found. Tips:\n' +
        '* Make sure to run this command from your app path where app.js is located.\n' +
        '* Make sure commands/index.js" exists at your app root.');
      process.exit(e.code);
    }

    if (!_.has(commands, command)) {
      sails.log.error('Command not found. Does ' + sails.config.appPath + '/commands/index.js export "' + command + '"?');
      process.exit(1);
    }

    sails.lift({
      log: {
        level: 'silent'
      }
    }, function () {
      sails.log.verbose('Issuing task "' + command + '"...');
      commands[command](function() {
        sails.log.verbose('Crew successfully carried out their task: "' + command + '"!');
        process.exit();
      });
    });

    return;
  }

  // Unknown command, print out usage
  else {
    console.log('');
    sailsUsage();
    sails.log.error(argv._[0] + ' is not a valid action.');
  }

  // Display usage
  function sailsUsage() {
    function leftColumn(str) {
      var n = (33 - str.length);
      return str + require('underscore.string').repeat(' ', n);
    }

    var usage = 'Usage: sails <command>\n\n';
    usage += leftColumn('sails lift') + 'Run this Sails app (in the current dir)\n';
    usage += leftColumn('  [--dev]') + 'with development environment specified \n';
    usage += leftColumn('  [--prod]') + 'with production environment specified \n';
    usage += leftColumn('sails console') + 'Run this Sails app (in the current dir & in interactive mode.)\n';
    usage += leftColumn('sails new <appName>') + 'Create a new Sails project in a folder called <appName>\n';
    usage += leftColumn('sails new <appName> --linker') + 'Create a new Sails project in a folder called <appName>, using automatic asset linking\n';
    usage += leftColumn('sails generate <foo>') + 'Generate api/models/Foo.js and api/controllers/FooController.js\n';
    usage += leftColumn('sails generate model <foo>') + 'Generate api/models/Foo.js\n';
    usage += leftColumn('sails generate controller <foo>') + 'Generate api/controllers/FooController.js\n';
    usage += leftColumn('sails version') + 'Get the current globally installed Sails version\n';
    usage += leftColumn('sails issue <command>') + 'Run a management command (exported by commands/index.js)';

    sails.log.info(usage);
  }

  // Verify that an argument exists
  function verifyArg(argNo, msg) {
    if (!argv._[argNo]) {
      sails.log.error(msg);
      process.exit(1);
    }
  }
});<|endoftext|>


<commit_before>#!/usr/bin/env node

const koa = require('koa')
const program = require('commander')
const exec = require('child_process').execSync

const serve = require('koa-static')
const mount = require('koa-mount')
const compress = require('koa-compress')
const handlebars = require('koa-handlebars')
const router = require('koa-router')()
const sendfile = require('koa-sendfile')
const bodyParser = require('koa-body')
const jwt = require('koa-jwt')

const db = require('../lib/db')
const helpers = require('../lib/helpers')
const log = require('../lib/log')

const app = koa()
const rope = db.rope

program
  .option('-w, --watch', 'Rebuild site if files change')
  .option('-p, --port <port>', 'The port on which your site will be available', parseInt)
  .parse(process.argv)

process.on('SIGINT', () => rope.close(() => {
  process.exit(0)
}))

try {
  exec('muffin build', {stdio: [0, 1]})
} catch (err) {
  console.error(err)
  process.exit(1)
}

app.use(compress())

router.use('/api', jwt({
  secret: process.env.SESSION_SECRET
}).unless({
  path: [/token-auth/, /token-refresh/, /reset-password/]
}))

router.use(bodyParser({
  multipart: true
}))

function getRoutes (path) {
  // Retrieve routes from passed path
  return require('../lib/routes/' + path).routes()
}

// Register media routes and API
router.use('/uploads*', getRoutes('uploads'))
router.use('/api', getRoutes('api'))

// Serve assets of admin area...
app.use(mount('/admin', serve(__dirname + '/../dist')))

// ...and the Ember app
router.get('/admin*', function *() {
  yield* sendfile.call(this, __dirname + '/../dist/index.html')
  if (!this.status) this.throw(404)
})

// Serve frontend assets
app.use(mount('/assets', serve(process.cwd() + '/dist')))

router.get('/login', function *(next) {
  yield next
  this.redirect('/admin/login')
})

// Log HTTP requests to console
app.use(function *(next){
  var start = new Date
  yield next
  var ms = new Date - start

  if (this.url.split('/')[1] == 'api') {
    return
  }

  console.log('%s %s - %s', this.method, this.url, ms)
})

const frontRouter = require('../lib/routes/front')

// Enable new instance of rendering engine for front
frontRouter.use(handlebars({
  cache: app.env !== 'development',
  root: process.cwd() + '/views',
  layoutsDir: '../layouts',
  viewsDir: '/',
  defaultLayout: 'default',
  helpers
}))

// Register front routes
router.use('/', frontRouter.routes())

app.use(router.routes())
app.use(router.allowedMethods())

app.listen(program.port || process.env.PORT, function () {
  const port = this.address().port
  const url = 'http://localhost:' + port

  if (!program.watch) {
    return console.log('Muffin is running: ' + url)
  }

  const browserSync = require('browser-sync').create()

  browserSync.init({
    proxy: url,
    logPrefix: 'muffin',
    logFileChanges: false,
    notify: false,
    ui: false
  })
})
<commit_msg>Don't serve if not a site<commit_after>#!/usr/bin/env node

const koa = require('koa')
const program = require('commander')
const colors = require('colors')
const exec = require('child_process').execSync

const serve = require('koa-static')
const mount = require('koa-mount')
const compress = require('koa-compress')
const handlebars = require('koa-handlebars')
const router = require('koa-router')()
const sendfile = require('koa-sendfile')
const bodyParser = require('koa-body')
const jwt = require('koa-jwt')

const db = require('../lib/db')
const helpers = require('../lib/helpers')
const log = require('../lib/log')
const utils = require('../lib/utils')

const app = koa()
const rope = db.rope

program
  .option('-w, --watch', 'Rebuild site if files change')
  .option('-p, --port <port>', 'The port on which your site will be available', parseInt)
  .parse(process.argv)

process.on('SIGINT', () => rope.close(() => {
  process.exit(0)
}))

if (!utils.isSite()) {
  console.error('No site in here!'.red)
  process.exit(1)
}

try {
  exec('muffin build', {stdio: [0, 1]})
} catch (err) {
  console.error(err)
  process.exit(1)
}

app.use(compress())

router.use('/api', jwt({
  secret: process.env.SESSION_SECRET
}).unless({
  path: [/token-auth/, /token-refresh/, /reset-password/]
}))

router.use(bodyParser({
  multipart: true
}))

function getRoutes (path) {
  // Retrieve routes from passed path
  return require('../lib/routes/' + path).routes()
}

// Register media routes and API
router.use('/uploads*', getRoutes('uploads'))
router.use('/api', getRoutes('api'))

// Serve assets of admin area...
app.use(mount('/admin', serve(__dirname + '/../dist')))

// ...and the Ember app
router.get('/admin*', function *() {
  yield* sendfile.call(this, __dirname + '/../dist/index.html')
  if (!this.status) this.throw(404)
})

// Serve frontend assets
app.use(mount('/assets', serve(process.cwd() + '/dist')))

router.get('/login', function *(next) {
  yield next
  this.redirect('/admin/login')
})

// Log HTTP requests to console
app.use(function *(next){
  var start = new Date
  yield next
  var ms = new Date - start

  if (this.url.split('/')[1] == 'api') {
    return
  }

  console.log('%s %s - %s', this.method, this.url, ms)
})

const frontRouter = require('../lib/routes/front')

// Enable new instance of rendering engine for front
frontRouter.use(handlebars({
  cache: app.env !== 'development',
  root: process.cwd() + '/views',
  layoutsDir: '../layouts',
  viewsDir: '/',
  defaultLayout: 'default',
  helpers
}))

// Register front routes
router.use('/', frontRouter.routes())

app.use(router.routes())
app.use(router.allowedMethods())

app.listen(program.port || process.env.PORT, function () {
  const port = this.address().port
  const url = 'http://localhost:' + port

  if (!program.watch) {
    return console.log('Muffin is running: ' + url)
  }

  const browserSync = require('browser-sync').create()

  browserSync.init({
    proxy: url,
    logPrefix: 'muffin',
    logFileChanges: false,
    notify: false,
    ui: false
  })
})
<|endoftext|>


<commit_before>#!/usr/bin/env node

// Packages
const asyncToGen = require('async-to-gen/register')
const updateNotifier = require('update-notifier')
const {red} = require('chalk')
const nodeVersion = require('node-version')
const isAsyncSupported = require('is-async-supported')

// Ours
const pkg = require('../package')

// Support for keywords "async" and "await"
if (!isAsyncSupported()) {
  asyncToGen({
    exclude: null,
    sourceMaps: false
  })
}

// Throw an error if node version is too low
if (nodeVersion.major < 6) {
  console.error(`${red('Error!')} Serve requires at least version 6 of Node. Please upgrade!`)
  process.exit(1)
}

// Let user know if there's an update
// This isn't important when deployed to Now
if (!process.env.NOW && pkg.dist) {
  updateNotifier({pkg}).notify()
}

// Load package core with async/await support
require('../lib')
<commit_msg>Perfected mechanism for transpilation<commit_after>#!/usr/bin/env node

// Native
const path = require('path')

// Packages
const asyncToGen = require('async-to-gen/register')
const updateNotifier = require('update-notifier')
const {red} = require('chalk')
const nodeVersion = require('node-version')
const isAsyncSupported = require('is-async-supported')

// Ours
const pkg = require('../package')

// Support for keywords "async" and "await"
if (!isAsyncSupported()) {
  const packageDir = path.basename(path.join(__dirname, '..'))
  const modulesDir = path.join(packageDir, 'node_modules')

  asyncToGen({
    excludes: new RegExp(`.*${modulesDir}.*`),
    sourceMaps: false
  })
}

// Throw an error if node version is too low
if (nodeVersion.major < 6) {
  console.error(`${red('Error!')} Serve requires at least version 6 of Node. Please upgrade!`)
  process.exit(1)
}

// Let user know if there's an update
// This isn't important when deployed to Now
if (!process.env.NOW && pkg.dist) {
  updateNotifier({pkg}).notify()
}

// Load package core with async/await support
require('../lib')
<|endoftext|>


<commit_before>#!/usr/bin/env node

var nopt = require('nopt');
var options = {
  'help': Boolean,
  'from' : [ 'textjson' ],
  'to' : [ 'xelatex', 'html5' ],
  'standalone' : Boolean,
};
var shorthands = {
  'h' : '--help',
  'f' : '--from',
  't' : '--to',
  's' : '--standalone',
};
var parsed = nopt(options, shorthands);

if (parsed.help) {
  console.log([
    'Usage: texts [OPTIONS] [FILES]',
    '',
    'Options:',
    '  -f FORMAT             --from=FORMAT',
    '  -t FORMAT             --to=FORMAT',
    '  -s                    --standalone',
    '  -h                    --help',
  ].join('\n'));
  process.exit(1);
}

parsed.from = parsed.from || 'textjson';
parsed.to   = parsed.to   || 'html5';
parsed.standalone = parsed.standalone || false;

var writerOptions = { standalone: parsed.standalone };

// option parsing completed

var io = require('../lib/io');
var fs = require('fs');
var reader = require('../lib/reader/' + parsed.from);
var writer = require('../lib/writer/' + parsed.to);

if (parsed.argv.remain.length) {
  // process files
  parsed.argv.remain.forEach(function(inputFile) {
    var input = fs.readFileSync(inputFile);
    var text = reader(input);
    var output = writer(text, writerOptions);
    io.writeOutput(output);
  });
} else {
  // process stdin
  io.readInput(function (err, input) {
    var text = reader(input);
    var output = writer(text, writerOptions);
    io.writeOutput(output);
  });
}
<commit_msg>Allow Text input and TextJSON output in CLI.<commit_after>#!/usr/bin/env node

var nopt = require('nopt');
var options = {
  'help': Boolean,
  'from' : [ 'textjson', 'text' ],
  'to' :   [ 'textjson', 'xelatex', 'html5' ],
  'standalone' : Boolean,
};
var shorthands = {
  'h' : '--help',
  'f' : '--from',
  't' : '--to',
  's' : '--standalone',
};
var parsed = nopt(options, shorthands);

if (parsed.help) {
  console.log([
    'Usage: texts [OPTIONS] [FILES]',
    '',
    'Options:',
    '  -f FORMAT             --from=FORMAT',
    '  -t FORMAT             --to=FORMAT',
    '  -s                    --standalone',
    '  -h                    --help',
  ].join('\n'));
  process.exit(1);
}

parsed.from = parsed.from || 'textjson';
parsed.to   = parsed.to   || 'html5';
parsed.standalone = parsed.standalone || false;

var writerOptions = { standalone: parsed.standalone };

// option parsing completed

var io = require('../lib/io');
var fs = require('fs');
var reader = require('../lib/reader/' + parsed.from);
var writer = require('../lib/writer/' + parsed.to);

if (parsed.argv.remain.length) {
  // process files
  parsed.argv.remain.forEach(function(inputFile) {
    var input = fs.readFileSync(inputFile);
    var text = reader(input);
    var output = writer(text, writerOptions);
    io.writeOutput(output);
  });
} else {
  // process stdin
  io.readInput(function (err, input) {
    var text = reader(input);
    var output = writer(text, writerOptions);
    io.writeOutput(output);
  });
}
<|endoftext|>


<commit_before>#!/usr/bin/env node
/*
	Copyright (c) 2014 Guilherme Prá Vieira

	This file is part of Wysia.

	Wysia is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as
	published by the Free Software Foundation, either version 3 of
	the License, or (at your option) any later version.

	Wysia is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
	GNU Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public
	License along with Wysia. If not, see <http://www.gnu.org/licenses/>.
*/
var vm = require('vm');
var fs = require('fs');
var glob = require('glob');
var path = require('path');
var http = require('http');
var express = require('express');
var hbs = require('handlebars');
var marked = require('marked');
var args = require('../src/arguments');
var merge = require('../src/merge');
hbs.registerHelper (
	'markdown', function(text) {
		if(!text) {
			return '';
		}
		return new hbs.SafeString (
			marked (
				text
				, {
					gfm: true
					, sanitize: true
					, breaks: true
					, tables: true
				}
			)
		);
	}
);
var app = express();
if(app.get('env') === 'development') {
	app.use(express.logger());
}
app.use(express.static(__dirname + '/../public'));
app.use (
	express.static (
		path.resolve(process.cwd(), args['templates-dir'])
	)
);
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use (
	function(req, res, next) {
		res.send_error = function(err) {
			if(err.bad_request) {
				res.status(400);
			}
			else
			if(err.not_found) {
				res.status(404);
			}
			else {
				res.status(500);
			}
			if(!err.stack) {
				res.send(err);
				console.error("Non-standard error thrown:", err);
			}
			else {
				res.set('Content-Type', 'text/plain');
				res.send(err.stack);
				console.error(err.stack);
			}
		};
		next();
	}
);
var shared_state = (function() {
	try {
		var path = args['templates-dir']
				+ '/' + args['wysia-subdir']
				+ '/initial-shared-state.json';
		return JSON.parse(fs.readFileSync(path, 'utf8'));
	}
	catch(err) {
		if(err.code !== 'ENOENT') {
			console.error("Error loading initial shared state:", err);
			console.log("Starting with empty shared_state.");
		}
	}
	return {};
})();
function render(shell, page, models, cookies, cb) {
	var shell_template;
	var page_template;
	var model_data = {};
	var partials = {};
	(function load_shell() {
		if(!shell) {
			load_page();
		}
		else {
			var file_name = shell + '.hbs';
			var path = args['templates-dir'] + '/' + file_name;
			fs.readFile (
				path, 'utf8', function(err, template) {
					if(err) {
						cb(err);
						return;
					}
					shell_template = template;
					load_page();
				}
			);
		}
	})();
	function load_page() {
		var file_name = page + '.hbs';
		var path = args['templates-dir'] + '/' + file_name;
		fs.readFile (
			path, 'utf8', function(err, template) {
				if(err) {
					cb(err);
					return;
				}
				page_template = template;
				load_models();
			}
		);
	}
	function load_models() {
		var load_count = 0;
		(function load_model(err, model) {
			if(err) {
				cb(err);
				return;
			}
			if(model) {
				try {
					var loaded_model = JSON.parse(model);
					model_data = merge(model_data, loaded_model);
				}
				catch(err) {
					cb(err);
					return;
				}
			}
			if(load_count < models.length) {
				var file_name = models[load_count++] + '.json';
				var path = args['templates-dir']
						+ '/' + args['wysia-subdir']
						+ '/' + file_name;
				fs.readFile(path, 'utf8', load_model);
			}
			else {
				merge_shared_state();
			}
		})();
	}
	function merge_shared_state() {
		try {
			model_data = merge(model_data, shared_state);
		}
		catch(err) {
			cb(err);
			return;
		}
		merge_cookies();
	}
	function merge_cookies() {
		if(!cookies) {
			load_partials();
			return;
		}
		try {
			for(var key in cookies) {
				cookies[key] = (function execute_copies(node) {
					if(typeof(node) !== 'object') {
						return node;
					}
					var keys = Object.keys(node);
					if(keys[0] !== '$copy') {
						for(var key in node) {
							node[key] = execute_copies(node[key]);
						}
						return node;
					}
					var path = node[keys[0]].split('.');
					return path.reduce (
						function(current_path_node, next_path_node_name) {
							if(typeof(current_path_node) !== 'object') {
								return undefined;
							}
							return current_path_node[next_path_node_name];
						}
						, model_data
					);
				})(cookies[key]);
			}
			model_data = merge(model_data, cookies);
		}
		catch(err) {
			cb(err);
			return;
		}
		load_partials();
	}
	function load_partials() {
		var glob_ = args['templates-dir'] + '/*.partial.hbs';
		var partial_files;
		glob (
			glob_, function(err, files) {
				if(err) {
					cb(err);
					return;
				}
				partial_files = files;
				load_partial();
			}
		);
		var load_count = 0;
		function load_partial(err, name, partial) {
			if(err) {
				cb(err);
				return;
			}
			if(partial) {
				partials[name] = partial;
			}
			if(load_count < partial_files.length) {
				var path_ = partial_files[load_count++];
				var name = path.basename(path_, '.partial.hbs');
				fs.readFile (
					path_, 'utf8', function(err, partial) {
						load_partial(err, name, partial);
					}
				);
			}
			else {
				render_();
			}
		}
	}
	function render_() {
		try {
			model_data.is_wysia = true;
			for(var name in partials) {
				var partial = partials[name];
				hbs.registerPartial(name, partial);
			}
			var html = hbs.compile(page_template)(model_data);
			if(shell_template) {
				model_data.page_html = html;
				html = hbs.compile(shell_template)(model_data);
			}
			for(var name in partials) {
				hbs.unregisterPartial(name);
			}
			cb(null, html);
		}
		catch(err) {
			cb(err);
		}
	}
}
function get_handler(req, res) {
	var shell = req.params.shell || null;
	var page = req.params.page;
	var models = [];
	if(req.params.models) {
		models = req.params.models.split(',');
	}
	var cookies = {};
	if(req.headers.cookie) {
		try {
			cookies = JSON.parse(unescape(req.headers.cookie));
		}
		catch(err) {
			console.error("Failed to parse cookies:", req.headers.cookie + ".");
		}
	}
	render (
		shell, page, models, cookies, function(err, html) {
			if(err) {
				res.send_error(err);
				return;
			}
			res.send(html);
		}
	);
}
function post_handler(req, res) {
	if(req.body['$state-update-logic']) {
		var cookies = (function() {
			if(req.headers.cookie) {
				try {
					return JSON.parse(unescape(req.headers.cookie));
				}
				catch(err) {
					console.error("Failed to parse cookies:", req.headers.cookie + ".");
					return undefined;
				}
			}
			return {};
		})();
		var set_cookies_if_any = function() {
			if(cookies !== undefined) {
				res.set('Set-Cookie', escape(JSON.stringify(cookies)));
			}
		};
		try {
			vm.runInNewContext (
				req.body['$state-update-logic']
				, {
					state: shared_state
					, cookies: cookies
					, form_data: req.body
				}
			);
		}
		catch(err) {
			set_cookies_if_any();
			res.send_error(err);
			return;
		}
		set_cookies_if_any();
	}
	res.redirect(req.url);
}
app.get('/:shell,:page', get_handler);
app.post('/:shell,:page', post_handler);
app.get('/:shell,:page/:models', get_handler);
app.post('/:shell,:page/:models', post_handler);
app.get('/:page', get_handler);
app.post('/:page', post_handler);
app.get('/:page/:models', get_handler);
app.post('/:page/:models', post_handler);
app.listen(args.port);
console.log("Wysia started on port", args.port + ".");
<commit_msg>refactor: Replace local variable with rvalue.<commit_after>#!/usr/bin/env node
/*
	Copyright (c) 2014 Guilherme Prá Vieira

	This file is part of Wysia.

	Wysia is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as
	published by the Free Software Foundation, either version 3 of
	the License, or (at your option) any later version.

	Wysia is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
	GNU Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public
	License along with Wysia. If not, see <http://www.gnu.org/licenses/>.
*/
var vm = require('vm');
var fs = require('fs');
var glob = require('glob');
var path = require('path');
var http = require('http');
var express = require('express');
var hbs = require('handlebars');
var marked = require('marked');
var args = require('../src/arguments');
var merge = require('../src/merge');
hbs.registerHelper (
	'markdown', function(text) {
		if(!text) {
			return '';
		}
		return new hbs.SafeString (
			marked (
				text
				, {
					gfm: true
					, sanitize: true
					, breaks: true
					, tables: true
				}
			)
		);
	}
);
var app = express();
if(app.get('env') === 'development') {
	app.use(express.logger());
}
app.use(express.static(__dirname + '/../public'));
app.use (
	express.static (
		path.resolve(process.cwd(), args['templates-dir'])
	)
);
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use (
	function(req, res, next) {
		res.send_error = function(err) {
			if(err.bad_request) {
				res.status(400);
			}
			else
			if(err.not_found) {
				res.status(404);
			}
			else {
				res.status(500);
			}
			if(!err.stack) {
				res.send(err);
				console.error("Non-standard error thrown:", err);
			}
			else {
				res.set('Content-Type', 'text/plain');
				res.send(err.stack);
				console.error(err.stack);
			}
		};
		next();
	}
);
var shared_state = (function() {
	try {
		var path = args['templates-dir']
				+ '/' + args['wysia-subdir']
				+ '/initial-shared-state.json';
		return JSON.parse(fs.readFileSync(path, 'utf8'));
	}
	catch(err) {
		if(err.code !== 'ENOENT') {
			console.error("Error loading initial shared state:", err);
			console.log("Starting with empty shared_state.");
		}
	}
	return {};
})();
function render(shell, page, models, cookies, cb) {
	var shell_template;
	var page_template;
	var model_data = {};
	var partials = {};
	(function load_shell() {
		if(!shell) {
			load_page();
		}
		else {
			var file_name = shell + '.hbs';
			var path = args['templates-dir'] + '/' + file_name;
			fs.readFile (
				path, 'utf8', function(err, template) {
					if(err) {
						cb(err);
						return;
					}
					shell_template = template;
					load_page();
				}
			);
		}
	})();
	function load_page() {
		var file_name = page + '.hbs';
		var path = args['templates-dir'] + '/' + file_name;
		fs.readFile (
			path, 'utf8', function(err, template) {
				if(err) {
					cb(err);
					return;
				}
				page_template = template;
				load_models();
			}
		);
	}
	function load_models() {
		var load_count = 0;
		(function load_model(err, model) {
			if(err) {
				cb(err);
				return;
			}
			if(model) {
				try {
					var loaded_model = JSON.parse(model);
					model_data = merge(model_data, loaded_model);
				}
				catch(err) {
					cb(err);
					return;
				}
			}
			if(load_count < models.length) {
				var file_name = models[load_count++] + '.json';
				var path = args['templates-dir']
						+ '/' + args['wysia-subdir']
						+ '/' + file_name;
				fs.readFile(path, 'utf8', load_model);
			}
			else {
				merge_shared_state();
			}
		})();
	}
	function merge_shared_state() {
		try {
			model_data = merge(model_data, shared_state);
		}
		catch(err) {
			cb(err);
			return;
		}
		merge_cookies();
	}
	function merge_cookies() {
		if(!cookies) {
			load_partials();
			return;
		}
		try {
			for(var key in cookies) {
				cookies[key] = (function execute_copies(node) {
					if(typeof(node) !== 'object') {
						return node;
					}
					var keys = Object.keys(node);
					if(keys[0] !== '$copy') {
						for(var key in node) {
							node[key] = execute_copies(node[key]);
						}
						return node;
					}
					var path = node[keys[0]].split('.');
					return path.reduce (
						function(current_path_node, next_path_node_name) {
							if(typeof(current_path_node) !== 'object') {
								return undefined;
							}
							return current_path_node[next_path_node_name];
						}
						, model_data
					);
				})(cookies[key]);
			}
			model_data = merge(model_data, cookies);
		}
		catch(err) {
			cb(err);
			return;
		}
		load_partials();
	}
	function load_partials() {
		var glob_ = args['templates-dir'] + '/*.partial.hbs';
		var partial_files;
		glob (
			glob_, function(err, files) {
				if(err) {
					cb(err);
					return;
				}
				partial_files = files;
				load_partial();
			}
		);
		var load_count = 0;
		function load_partial(err, name, partial) {
			if(err) {
				cb(err);
				return;
			}
			if(partial) {
				partials[name] = partial;
			}
			if(load_count < partial_files.length) {
				var path_ = partial_files[load_count++];
				var name = path.basename(path_, '.partial.hbs');
				fs.readFile (
					path_, 'utf8', function(err, partial) {
						load_partial(err, name, partial);
					}
				);
			}
			else {
				render_();
			}
		}
	}
	function render_() {
		try {
			model_data.is_wysia = true;
			for(var name in partials) {
				hbs.registerPartial(name, partials[name]);
			}
			var html = hbs.compile(page_template)(model_data);
			if(shell_template) {
				model_data.page_html = html;
				html = hbs.compile(shell_template)(model_data);
			}
			for(var name in partials) {
				hbs.unregisterPartial(name);
			}
			cb(null, html);
		}
		catch(err) {
			cb(err);
		}
	}
}
function get_handler(req, res) {
	var shell = req.params.shell || null;
	var page = req.params.page;
	var models = [];
	if(req.params.models) {
		models = req.params.models.split(',');
	}
	var cookies = {};
	if(req.headers.cookie) {
		try {
			cookies = JSON.parse(unescape(req.headers.cookie));
		}
		catch(err) {
			console.error("Failed to parse cookies:", req.headers.cookie + ".");
		}
	}
	render (
		shell, page, models, cookies, function(err, html) {
			if(err) {
				res.send_error(err);
				return;
			}
			res.send(html);
		}
	);
}
function post_handler(req, res) {
	if(req.body['$state-update-logic']) {
		var cookies = (function() {
			if(req.headers.cookie) {
				try {
					return JSON.parse(unescape(req.headers.cookie));
				}
				catch(err) {
					console.error("Failed to parse cookies:", req.headers.cookie + ".");
					return undefined;
				}
			}
			return {};
		})();
		var set_cookies_if_any = function() {
			if(cookies !== undefined) {
				res.set('Set-Cookie', escape(JSON.stringify(cookies)));
			}
		};
		try {
			vm.runInNewContext (
				req.body['$state-update-logic']
				, {
					state: shared_state
					, cookies: cookies
					, form_data: req.body
				}
			);
		}
		catch(err) {
			set_cookies_if_any();
			res.send_error(err);
			return;
		}
		set_cookies_if_any();
	}
	res.redirect(req.url);
}
app.get('/:shell,:page', get_handler);
app.post('/:shell,:page', post_handler);
app.get('/:shell,:page/:models', get_handler);
app.post('/:shell,:page/:models', post_handler);
app.get('/:page', get_handler);
app.post('/:page', post_handler);
app.get('/:page/:models', get_handler);
app.post('/:page/:models', post_handler);
app.listen(args.port);
console.log("Wysia started on port", args.port + ".");
<|endoftext|>


<commit_before>//no need to create namespace, we are in a sandbox

Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/Task.jsm");
Components.utils.import("resource://gre/modules/osfile.jsm");

let wait4startup = false;
let statuspanel = null;
let window = null;

//Observer to catch loading of thunderbird main window
let onLoadObserver = {
    observe: function(aSubject, aTopic, aData) {
        if (wait4startup) onLoadAction();
  }
}

//Observer to catch changing syncstate and to update the status bar.
let syncstateObserver = {
    observe: function (aSubject, aTopic, aData) {
        //update status bar
        let status = window.document.getElementById("tbsync.status");
        if (status) {

            let label = "TbSync: ";

            //check if any account is syncing, if not switch to idle
            let accounts = tbSync.db.getAccounts();
            let idle = true;
            let err = false;
            for (let i=0; i<accounts.IDs.length && idle; i++) {
                //set idle to false, if at least one account is syncing
                if (tbSync.isSyncing(accounts.IDs[i])) idle = false;

                //check for errors
                switch (tbSync.db.getAccountSetting(accounts.IDs[i], "status")) {
                    case "OK":
                    case "disabled":
                    case "notsyncronized":
                    case "nolightning":
                    case "syncing":
                        break;
                    default:
                        err = true;
                }
            }

            if (idle) {
                if (err) label +=tbSync.getLocalizedMessage("info.error");
                else label += tbSync.getLocalizedMessage("info.idle");
            } else {
                label += tbSync.getLocalizedMessage("info.sync");
            }
            status.label = label;

        }
    }
}

//Observer to open the account manager
let openManagerObserver = {
    observe: function (aSubject, aTopic, aData) {
        if (tbSync.enabled) {
            // check, if a window is already open and just put it in focus
            if (tbSync.prefWindowObj === null) tbSync.prefWindowObj = window.open("chrome://tbsync/content/manager/accountManager.xul", "TbSyncAccountManagerWindow", "chrome,centerscreen");
            tbSync.prefWindowObj.focus();
        } else {
            popupNotEnabled();
        }
    }
}

//function ligthningSyncRequest () {
//    if (tbSync.enabled) tbSync.syncAccount('sync'); else popupNotEnabled();
//}

let syncTimer = {
    timer: Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer),

    start: function () {
        this.timer.cancel();
        this.timer.initWithCallback(this.event, 60000, 3); //run timer every 60s
    },

    cancel: function () {
        this.timer.cancel();
    },

    event: {
        notify: function (timer) {
            if (tbSync.enabled) {
                //get all accounts and check, which one needs sync (accounts array is without order, extract keys (ids) and loop over them)
                let accounts = tbSync.db.getAccounts();
                for (let i=0; i<accounts.IDs.length; i++) {
                    let syncInterval = accounts.data[accounts.IDs[i]].autosync * 60 * 1000;
                    let lastsynctime = accounts.data[accounts.IDs[i]].lastsynctime;

                    if (tbSync.isEnabled(accounts.IDs[i]) && (syncInterval > 0) && ((Date.now() - lastsynctime) > syncInterval)) {
                    tbSync.syncAccount("sync",accounts.IDs[i]);
                    }
                }
            }
        }
    }
}

function install(data, reason) {
}

function uninstall(data, reason) {
}

function startup(data, reason) {
    //possible reasons: APP_STARTUP, ADDON_ENABLE, ADDON_INSTALL, ADDON_UPGRADE, or ADDON_DOWNGRADE.

    //set default prefs
    let branch = Services.prefs.getDefaultBranch("extensions.tbsync.");
    branch.setBoolPref("enable", true);
    branch.setBoolPref("delay", true);
    branch.setBoolPref("block", false);

    branch.setBoolPref("log.toconsole", false);
    branch.setBoolPref("log.tofile", false);
    branch.setBoolPref("log.easdata", true);

    branch.setIntPref("eas.timeout", 90000);
    branch.setIntPref("eas.synclimit", 7);
    branch.setIntPref("eas.maxitems", 50);

    branch.setBoolPref("eas.use_tzpush_contactsync_code", true);

    branch.setBoolPref("hidephones", false);
    branch.setBoolPref("showanniversary", false);
    branch.setCharPref("provider.eas", "Exchange Active Sync");
    branch.setCharPref("provider.dav", "CalDAV/CardDAV (sabre/dav, ownCloud, Nextcloud)");

    branch.setCharPref("clientID.type", "");
    branch.setCharPref("clientID.useragent", "");

    Components.utils.import("chrome://tbsync/content/tbsync.jsm");

    //Map local writeAsyncJSON into tbSync
    tbSync.writeAsyncJSON = writeAsyncJSON;

    if (reason == APP_STARTUP) {
        //enable observer to call onLoadAction after thunderbird startup finished
        wait4startup  = true;
    } else {
        //disable observer to call onLoadAction, call it directly
        wait4startup  = false;
        onLoadAction();
    }

    syncTimer.start();

    Services.obs.addObserver(onLoadObserver, "mail-startup-done", false);
    Services.obs.addObserver(openManagerObserver, "tbsync.openManager", false);
    Services.obs.addObserver(syncstateObserver, "tbsync.changedSyncstate", false);
}

function shutdown(data, reason) {
    //possible reasons: APP_SHUTDOWN, ADDON_DISABLE, ADDON_UNINSTALL, ADDON_UPGRADE, or ADDON_DOWNGRADE

	//cancel sync timer
	syncTimer.cancel();

	//remove our observer
    Services.obs.removeObserver(onLoadObserver, "mail-startup-done");
    Services.obs.removeObserver(openManagerObserver, "tbsync.openManager");
    Services.obs.removeObserver(syncstateObserver, "tbsync.changedSyncstate");

    //abort write timers and write current file content to disk
    if (tbSync.enabled) {
        tbSync.db.changelogTimer.cancel();
        tbSync.db.accountsTimer.cancel();
        tbSync.db.foldersTimer.cancel();
        writeAsyncJSON(tbSync.db.accounts, tbSync.db.accountsFile);
        writeAsyncJSON(tbSync.db.folders, tbSync.db.foldersFile);
        writeAsyncJSON(tbSync.db.changelog, tbSync.db.changelogFile);
    }

    //close window (if open)
    if (tbSync.prefWindowObj !== null) tbSync.prefWindowObj.close();

    //remove UI elements
    if (statuspanel && window && window.document) window.document.getElementById("status-bar").removeChild(statuspanel);

    //unload javascript module
    tbSync.dump("TbSync shutdown","Unloading module.");
    Components.utils.unload("chrome://tbsync/content/tbsync.jsm");
}

function onLoadAction() {
    window = Components.classes["@mozilla.org/appshell/window-mediator;1"]
                              .getService(Components.interfaces.nsIWindowMediator)
                              .getMostRecentWindow("mail:3pane");
    if (window) {
        statuspanel = window.document.createElement('statusbarpanel');
        statuspanel.setAttribute("label","TbSync");
        statuspanel.setAttribute("id","tbsync.status");
        statuspanel.setAttribute("onclick","Services.obs.notifyObservers(null, 'tbsync.openManager', null);");
        window.document.getElementById("status-bar").appendChild(statuspanel);

        //if (window.document.getElementById("calendar-synchronize-button")) {
        //    window.document.getElementById("calendar-synchronize-button").addEventListener("command", ligthningSyncRequest, false);
        //}

        //init tbSync logic
        tbSync.init();
    } else {
        tbSync.dump("FAIL", "Could not init UI, because mail:3pane window not found.");
    }
}

function popupNotEnabled () {
    let msg = "Oops! TbSync was not able to start!\n\n";
    tbSync.dump("Oops", "Trying to open account manager, but init sequence not yet finished");

    if (!tbSync.prefSettings.getBoolPref("log.tofile")) {
        if (window.confirm(msg + "It is not possible to trace this error, because debug log is currently not enabled. Do you want to enable debug log now, to help fix this error?")) {
            tbSync.prefSettings.setBoolPref("log.tofile", true);
            window.alert("TbSync debug log has been enabled, please restart Thunderbird and again try to open TbSync.");
        }
    } else {
        if (window.confirm(msg + "To help fix this error, you could send a debug log to the TbSync developer. Do you want to open the debug log now?")) {
            tbSync.openFileTab("debug.log");
        }
    }
}

function writeAsyncJSON (obj, filename) {
    let filepath = tbSync.getAbsolutePath(filename);
    let storageDirectory = tbSync.storageDirectory;
    let json = tbSync.encoder.encode(JSON.stringify(obj));

    Task.spawn(function* () {
        //MDN states, instead of checking if dir exists, just create it and catch error on exist (but it does not even throw)
        yield OS.File.makeDir(storageDirectory);
        yield OS.File.writeAtomic(filepath, json, {tmpPath: filepath + ".tmp"});
    }).catch(Components.utils.reportError);
}
<commit_msg>add observer to init sync<commit_after>//no need to create namespace, we are in a sandbox

Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/Task.jsm");
Components.utils.import("resource://gre/modules/osfile.jsm");

let wait4startup = false;
let statuspanel = null;
let window = null;

//Observer to catch loading of thunderbird main window
let onLoadObserver = {
    observe: function(aSubject, aTopic, aData) {
        if (wait4startup) onLoadAction();
  }
}

//Observer to catch changing syncstate and to update the status bar.
let syncstateObserver = {
    observe: function (aSubject, aTopic, aData) {
        //update status bar
        let status = window.document.getElementById("tbsync.status");
        if (status) {

            let label = "TbSync: ";

            //check if any account is syncing, if not switch to idle
            let accounts = tbSync.db.getAccounts();
            let idle = true;
            let err = false;
            for (let i=0; i<accounts.IDs.length && idle; i++) {
                //set idle to false, if at least one account is syncing
                if (tbSync.isSyncing(accounts.IDs[i])) idle = false;

                //check for errors
                switch (tbSync.db.getAccountSetting(accounts.IDs[i], "status")) {
                    case "OK":
                    case "disabled":
                    case "notsyncronized":
                    case "nolightning":
                    case "syncing":
                        break;
                    default:
                        err = true;
                }
            }

            if (idle) {
                if (err) label +=tbSync.getLocalizedMessage("info.error");
                else label += tbSync.getLocalizedMessage("info.idle");
            } else {
                label += tbSync.getLocalizedMessage("info.sync");
            }
            status.label = label;

        }
    }
}

//Observer to open the account manager
let openManagerObserver = {
    observe: function (aSubject, aTopic, aData) {
        if (tbSync.enabled) {
            // check, if a window is already open and just put it in focus
            if (tbSync.prefWindowObj === null) tbSync.prefWindowObj = window.open("chrome://tbsync/content/manager/accountManager.xul", "TbSyncAccountManagerWindow", "chrome,centerscreen");
            tbSync.prefWindowObj.focus();
        } else {
            popupNotEnabled();
        }
    }
}

//Observer to init sync
let initSyncObserver = {
    observe: function (aSubject, aTopic, aData) {
        if (tbSync.enabled) {
            tbSync.syncAccount('sync');
        } else {
            popupNotEnabled();
        }
    }
}

let syncTimer = {
    timer: Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer),

    start: function () {
        this.timer.cancel();
        this.timer.initWithCallback(this.event, 60000, 3); //run timer every 60s
    },

    cancel: function () {
        this.timer.cancel();
    },

    event: {
        notify: function (timer) {
            if (tbSync.enabled) {
                //get all accounts and check, which one needs sync (accounts array is without order, extract keys (ids) and loop over them)
                let accounts = tbSync.db.getAccounts();
                for (let i=0; i<accounts.IDs.length; i++) {
                    let syncInterval = accounts.data[accounts.IDs[i]].autosync * 60 * 1000;
                    let lastsynctime = accounts.data[accounts.IDs[i]].lastsynctime;

                    if (tbSync.isEnabled(accounts.IDs[i]) && (syncInterval > 0) && ((Date.now() - lastsynctime) > syncInterval)) {
                    tbSync.syncAccount("sync",accounts.IDs[i]);
                    }
                }
            }
        }
    }
}

function install(data, reason) {
}

function uninstall(data, reason) {
}

function startup(data, reason) {
    //possible reasons: APP_STARTUP, ADDON_ENABLE, ADDON_INSTALL, ADDON_UPGRADE, or ADDON_DOWNGRADE.

    //set default prefs
    let branch = Services.prefs.getDefaultBranch("extensions.tbsync.");
    branch.setBoolPref("enable", true);
    branch.setBoolPref("delay", true);
    branch.setBoolPref("block", false);

    branch.setBoolPref("log.toconsole", false);
    branch.setBoolPref("log.tofile", false);
    branch.setBoolPref("log.easdata", true);

    branch.setIntPref("eas.timeout", 90000);
    branch.setIntPref("eas.synclimit", 7);
    branch.setIntPref("eas.maxitems", 50);

    branch.setBoolPref("eas.use_tzpush_contactsync_code", true);

    branch.setBoolPref("hidephones", false);
    branch.setBoolPref("showanniversary", false);
    branch.setCharPref("provider.eas", "Exchange Active Sync");
    branch.setCharPref("provider.dav", "CalDAV/CardDAV (sabre/dav, ownCloud, Nextcloud)");

    branch.setCharPref("clientID.type", "");
    branch.setCharPref("clientID.useragent", "");

    Components.utils.import("chrome://tbsync/content/tbsync.jsm");

    //Map local writeAsyncJSON into tbSync
    tbSync.writeAsyncJSON = writeAsyncJSON;

    if (reason == APP_STARTUP) {
        //enable observer to call onLoadAction after thunderbird startup finished
        wait4startup  = true;
    } else {
        //disable observer to call onLoadAction, call it directly
        wait4startup  = false;
        onLoadAction();
    }

    syncTimer.start();

    Services.obs.addObserver(onLoadObserver, "mail-startup-done", false);
    Services.obs.addObserver(openManagerObserver, "tbsync.openManager", false);
    Services.obs.addObserver(syncstateObserver, "tbsync.changedSyncstate", false);
}

function shutdown(data, reason) {
    //possible reasons: APP_SHUTDOWN, ADDON_DISABLE, ADDON_UNINSTALL, ADDON_UPGRADE, or ADDON_DOWNGRADE

	//cancel sync timer
	syncTimer.cancel();

	//remove our observer
    Services.obs.removeObserver(onLoadObserver, "mail-startup-done");
    Services.obs.removeObserver(openManagerObserver, "tbsync.openManager");
    Services.obs.removeObserver(syncstateObserver, "tbsync.changedSyncstate");

    //abort write timers and write current file content to disk
    if (tbSync.enabled) {
        tbSync.db.changelogTimer.cancel();
        tbSync.db.accountsTimer.cancel();
        tbSync.db.foldersTimer.cancel();
        writeAsyncJSON(tbSync.db.accounts, tbSync.db.accountsFile);
        writeAsyncJSON(tbSync.db.folders, tbSync.db.foldersFile);
        writeAsyncJSON(tbSync.db.changelog, tbSync.db.changelogFile);
    }

    //close window (if open)
    if (tbSync.prefWindowObj !== null) tbSync.prefWindowObj.close();

    //remove UI elements
    if (statuspanel && window && window.document) window.document.getElementById("status-bar").removeChild(statuspanel);

    //unload javascript module
    tbSync.dump("TbSync shutdown","Unloading module.");
    Components.utils.unload("chrome://tbsync/content/tbsync.jsm");
}

function onLoadAction() {
    window = Components.classes["@mozilla.org/appshell/window-mediator;1"]
                              .getService(Components.interfaces.nsIWindowMediator)
                              .getMostRecentWindow("mail:3pane");
    if (window) {
        statuspanel = window.document.createElement('statusbarpanel');
        statuspanel.setAttribute("label","TbSync");
        statuspanel.setAttribute("id","tbsync.status");
        statuspanel.setAttribute("onclick","Services.obs.notifyObservers(null, 'tbsync.openManager', null);");
        window.document.getElementById("status-bar").appendChild(statuspanel);

        //if (window.document.getElementById("calendar-synchronize-button")) {
        //    window.document.getElementById("calendar-synchronize-button").addEventListener("command", ligthningSyncRequest, false);
        //}

        //init tbSync logic
        tbSync.init();
    } else {
        tbSync.dump("FAIL", "Could not init UI, because mail:3pane window not found.");
    }
}

function popupNotEnabled () {
    let msg = "Oops! TbSync was not able to start!\n\n";
    tbSync.dump("Oops", "Trying to open account manager, but init sequence not yet finished");

    if (!tbSync.prefSettings.getBoolPref("log.tofile")) {
        if (window.confirm(msg + "It is not possible to trace this error, because debug log is currently not enabled. Do you want to enable debug log now, to help fix this error?")) {
            tbSync.prefSettings.setBoolPref("log.tofile", true);
            window.alert("TbSync debug log has been enabled, please restart Thunderbird and again try to open TbSync.");
        }
    } else {
        if (window.confirm(msg + "To help fix this error, you could send a debug log to the TbSync developer. Do you want to open the debug log now?")) {
            tbSync.openFileTab("debug.log");
        }
    }
}

function writeAsyncJSON (obj, filename) {
    let filepath = tbSync.getAbsolutePath(filename);
    let storageDirectory = tbSync.storageDirectory;
    let json = tbSync.encoder.encode(JSON.stringify(obj));

    Task.spawn(function* () {
        //MDN states, instead of checking if dir exists, just create it and catch error on exist (but it does not even throw)
        yield OS.File.makeDir(storageDirectory);
        yield OS.File.writeAtomic(filepath, json, {tmpPath: filepath + ".tmp"});
    }).catch(Components.utils.reportError);
}
<|endoftext|>