<commit_before>// Copyright 2012 Mark Cavage, Inc.  All rights reserved.

var EventEmitter = require('events').EventEmitter;
var url = require('url');
var util = require('util');

var assert = require('assert-plus');
var clone = require('clone');
var LRU = require('lru-cache');
var semver = require('semver');

var errors = require('./errors');

///--- Globals

var DEF_CT = 'application/octet-stream';

var ALLOW_HEADERS = [
        'accept-version',
        'content-type',
        'request-id',
        'x-api-version',
        'x-request-id'
];

var maxSatisfying = semver.maxSatisfying;

var BadRequestError = errors.BadRequestError;
var InvalidArgumentError = errors.InvalidArgumentError;
var InvalidVersionError = errors.InvalidVersionError;
var MethodNotAllowedError = errors.MethodNotAllowedError;
var ResourceNotFoundError = errors.ResourceNotFoundError;
var UnsupportedMediaTypeError = errors.UnsupportedMediaTypeError;

///--- Helpers

function matchContentType(type1, type2) {
        var matches = true;

        try {
                var t1 = type1.split('/');
                var t2 = type2.split('/');

                t1[1] = t1[1].split(';');
                t2[1] = t2[1].split(';');

                if (t1[0] !== t2[0] && t1[0] !== '*') {
                        matches = false;
                } else  if (t1[1][0] !== t2[1][0] && t1[1][0] !== '*') {
                        matches = false;
                } else if (t1[1].length !== t2[1].length) {
                        matches = false;
                } else {
                        t1[1].sort();
                        t2[1].sort();
                        for (var i = 0; i < t1[1].length; i++) {
                                if (t1[1][i] !== t2[1][i] &&
                                    t1[1][i] !== '*') {
                                        matches = false;
                                        break;
                                }
                        }
                }
        } catch (e) {
                matches = false;
        }

        return (matches);
}

function matchURL(re, req) {
        var i = 0;
        var result = re.exec(req.path());
        var params = {};

        if (!result)
                return (false);

        // This means the user original specified a regexp match, not a url
        // string like /:foo/:bar
        if (!re.restifyParams) {
                for (i = 1; i < result.length; i++)
                        params[(i - 1)] = result[i];

                return (params);
        }

        // This was a static string, like /foo
        if (re.restifyParams.length === 0)
                return (params);

        // This was the "normal" case, of /foo/:id
        re.restifyParams.forEach(function (p) {
                if (++i < result.length)
                        params[p] = decodeURIComponent(result[i]);
        });

        return (params);
}

function compileURL(options) {
        if (options.url instanceof RegExp)
                return (options.url);
        assert.string(options.url, 'url');

        var params = [];
        var pattern = '^';
        var re;
        var _url = url.parse(options.url).pathname;
        _url.split('/').forEach(function (frag) {
                if (frag.length <= 0)
                        return (false);

                pattern += '\\/+';
                if (frag.charAt(0) === ':') {
                        if (options.urlParamPattern) {
                                pattern += '(' + options.urlParamPattern + ')';
                        } else {
                                // Strictly adhere to RFC3986
                                pattern += '([a-zA-Z0-9-_~\\.%@]+)';
                        }
                        params.push(frag.slice(1));
                } else {
                        pattern += frag;
                }

                return (true);
        });

        if (pattern === '^')
                pattern += '\\/';
        pattern += '$';

        re = new RegExp(pattern, options.flags);
        re.restifyParams = params;

        return (re);
}

///--- API

function Router(options) {
        assert.object(options, 'options');
        assert.object(options.log, 'options.log');

        EventEmitter.call(this);

        this.cache = LRU({max: 100});
        this.contentType = options.contentType || [];
        if (!Array.isArray(this.contentType))
                this.contentType = [this.contentType];
        assert.arrayOfString(this.contentType, 'options.contentType');

        this.log = options.log;
        this.mounts = {};
        this.name = 'RestifyRouter';

        // A list of methods to routes
        this.routes = {
                DELETE: [],
                GET: [],
                HEAD: [],
                OPTIONS: [],
                PATCH: [],
                POST: [],
                PUT: []
        };

        // So we can retrun 405 vs 404, we maintain a reverse mapping of URLs
        // to method
        this.reverse = {};

        this.version = options.version || [];
        if (!Array.isArray(this.version))
                this.version = [this.version];
        assert.arrayOfString(this.version, 'options.version');

        this.version.forEach(function (v) {
                if (semver.valid(v))
                        return (true);

                throw new InvalidArgumentError('%s is not a valid semver', v);
        });
        this.version.sort();

}
util.inherits(Router, EventEmitter);
module.exports = Router;

Router.prototype.mount = function mount(options) {
        assert.object(options, 'options');
        assert.string(options.method, 'options.method');
        assert.string(options.name, 'options.name');

        var exists;
        var name = options.name;
        var route;
        var routes = this.routes[options.method];
        var self = this;
        var type = options.contentType || self.contentType;
        var version = options.version || self.version;

        if (!Array.isArray(type))
                type = [type];
        type.sort();

        if (!Array.isArray(version))
                version = [version];
        version.sort();

        exists = routes.some(function (r) {
                return (r.name === name);
        });
        if (exists)
                return (false);

        route = {
                name: name,
                method: options.method,
                path: compileURL({
                        url: options.path || options.url,
                        flags: options.flags,
                        urlParamPattern: options.urlParamPattern
                }),
                type: type,
                version: version
        };
        routes.push(route);

        if (!this.reverse[route.path.source])
                this.reverse[route.path.source] = [];

        if (this.reverse[route.path.source].indexOf(route.method) === -1)
                this.reverse[route.path.source].push(route.method);

        this.mounts[route.name] = route;

        this.emit('mount',
                  route.method,
                  route.path,
                  route.type,
                  route.version);

        return (route.name);
};

Router.prototype.unmount = function unmount(name) {
        var route = this.mounts[name];
        if (!route) {
                this.log.warn('router.unmount(%s): route does not exist', name);
                return (false);
        }

        var reverse = this.reverse[route.path.source];
        var routes = this.routes[route.method];
        this.routes[route.method] = routes.filter(function (r) {
                return (r.name !== route.name);
        });

        this.reverse[route.path.source] = reverse.filter(function (r) {
                return (r !== route.method);
        });

        if (this.reverse[route.path.source].length === 0)
                delete this.reverse[route.path.source];

        delete this.mounts[name];

        return (name);
};

Router.prototype.find = function find(req, res, callback) {
        var ct = req.headers['content-type'] || DEF_CT;
        var cacheKey = req.method + req.url + req.version() + ct;
        var cacheVal;
        var params;
        var r;
        var routes = this.routes[req.method] || [];
        var typed;
        var ver;

        if ((cacheVal = this.cache.get(cacheKey))) {
                callback(null, cacheVal.name, clone(cacheVal.params));
                return;
        }

        for (var i = 0; i < routes.length; i++) {
                try {
                        params = matchURL(routes[i].path, req);
                } catch (e) {
                        this.log.trace({err: e}, 'error parsing URL');
                        callback(new BadRequestError(e.message));
                        return;
                }

                if (params === false)
                        continue;

                // Not common
                if (routes[i].type.length !== 0) {
                        switch (req.method) {
                        case 'POST':
                        case 'PUT':
                                // On uploads, check if the supplied
                                // content-type matches the type of the route
                                typed = routes[i].type.some(function (t) {
                                        return (matchContentType(t, ct));
                                });
                                break;

                        default:
                                break;
                        }

                        if (typed === false)
                                continue;
                }

                if (routes[i].version.length === 0 ||
                    req.version() === '*' ||
                    (ver = maxSatisfying(routes[i].version,
                                         req.version()) || false)) {
                        r = routes[i];
                        break;
                }
        }

        //
        // In order, we check if the route exists, in which case, we're good.
        // Otherwise we look to see if ver was set to false; that would tell us
        // we indeed did find a matching route (method+url), but the version
        // field didn't line up, so we return bad version.  If no route and no
        // version, we now need to go walk the reverse map and look at whether
        // we should return 405 or 404.  If it was an OPTIONS request, we need
        // to handle this having been a preflight request.
        //

        if (params && r) {
                cacheVal = {
                        name: r.name,
                        params: params
                };
                this.cache.set(cacheKey, cacheVal);
                callback(null, r.name, clone(params));
                return;
        }

        if (typed === false) {
                callback(new UnsupportedMediaTypeError(ct));
                return;
        }
        if (ver === false) {
                callback(new InvalidVersionError(req.getVersion()));
                return;
        }

        // This is a very generic preflight handler - it does
        // not handle requiring authentication, nor does it do
        // any special checking for extra user headers. The
        // user will need to defined their own .opts handler to
        // do that
        function preflight(methods) {
                var headers = req.headers['access-control-request-headers'];
                var method = req.headers['access-control-request-method'];
                var origin = req.headers['origin'];

                if (req.method !== 'OPTIONS' ||
                    !origin ||
                    !method ||
                    methods.indexOf(method) === -1) {
                        return (false);
                }
                // Last, check request-headers
                var ok = true;
                (headers || []).forEach(function (h) {
                        h = h.toLowerCase();
                        ok = ALLOW_HEADERS.indexOf(h) !== -1 && ok;
                });
                if (!ok)
                        return (false);

                res.setHeader('Access-Control-Allow-Origin', '*');
                res.setHeader('Access-Control-Allow-Methods',
                              methods.join(', '));
                res.setHeader('Access-Control-Allow-Headers',
                              ALLOW_HEADERS.join(', '));
                res.setHeader('Access-Control-Max-Age', 3600);

                return (true);
        }

        // Check for 405 instead of 404
        var urls = Object.keys(this.reverse);
        for (i = 0; i < urls.length; i++) {
                if (matchURL(new RegExp(urls[i]), req)) {
                        var _methods = this.reverse[urls[i]].slice();
                        res.setHeader('Allow', _methods.join(', '));
                        if (preflight(_methods)) {
                                callback(null, true);
                                return;
                        }
                        var err = new MethodNotAllowedError('%s is not allowed',
                                                            req.method);
                        callback(err);
                        return;
                }
        }

        callback(new ResourceNotFoundError('%s does not exist', req.url));
};

Router.prototype.toString = function toString() {
        var self = this;
        var str = this.name + ':\n';

        Object.keys(this.routes).forEach(function (k) {
                var routes = self.routes[k].map(function (r) {
                        return (r.name);
                });

                str += '\t\t' + k + ': [' + routes.join(', ') + ']\n';
        });

        return (str);
};
<commit_msg>#284 s/[]/""/<commit_after>// Copyright 2012 Mark Cavage, Inc.  All rights reserved.

var EventEmitter = require('events').EventEmitter;
var url = require('url');
var util = require('util');

var assert = require('assert-plus');
var clone = require('clone');
var LRU = require('lru-cache');
var semver = require('semver');

var errors = require('./errors');

///--- Globals

var DEF_CT = 'application/octet-stream';

var ALLOW_HEADERS = [
        'accept-version',
        'content-type',
        'request-id',
        'x-api-version',
        'x-request-id'
];

var maxSatisfying = semver.maxSatisfying;

var BadRequestError = errors.BadRequestError;
var InvalidArgumentError = errors.InvalidArgumentError;
var InvalidVersionError = errors.InvalidVersionError;
var MethodNotAllowedError = errors.MethodNotAllowedError;
var ResourceNotFoundError = errors.ResourceNotFoundError;
var UnsupportedMediaTypeError = errors.UnsupportedMediaTypeError;

///--- Helpers

function matchContentType(type1, type2) {
        var matches = true;

        try {
                var t1 = type1.split('/');
                var t2 = type2.split('/');

                t1[1] = t1[1].split(';');
                t2[1] = t2[1].split(';');

                if (t1[0] !== t2[0] && t1[0] !== '*') {
                        matches = false;
                } else  if (t1[1][0] !== t2[1][0] && t1[1][0] !== '*') {
                        matches = false;
                } else if (t1[1].length !== t2[1].length) {
                        matches = false;
                } else {
                        t1[1].sort();
                        t2[1].sort();
                        for (var i = 0; i < t1[1].length; i++) {
                                if (t1[1][i] !== t2[1][i] &&
                                    t1[1][i] !== '*') {
                                        matches = false;
                                        break;
                                }
                        }
                }
        } catch (e) {
                matches = false;
        }

        return (matches);
}

function matchURL(re, req) {
        var i = 0;
        var result = re.exec(req.path());
        var params = {};

        if (!result)
                return (false);

        // This means the user original specified a regexp match, not a url
        // string like /:foo/:bar
        if (!re.restifyParams) {
                for (i = 1; i < result.length; i++)
                        params[(i - 1)] = result[i];

                return (params);
        }

        // This was a static string, like /foo
        if (re.restifyParams.length === 0)
                return (params);

        // This was the "normal" case, of /foo/:id
        re.restifyParams.forEach(function (p) {
                if (++i < result.length)
                        params[p] = decodeURIComponent(result[i]);
        });

        return (params);
}

function compileURL(options) {
        if (options.url instanceof RegExp)
                return (options.url);
        assert.string(options.url, 'url');

        var params = [];
        var pattern = '^';
        var re;
        var _url = url.parse(options.url).pathname;
        _url.split('/').forEach(function (frag) {
                if (frag.length <= 0)
                        return (false);

                pattern += '\\/+';
                if (frag.charAt(0) === ':') {
                        if (options.urlParamPattern) {
                                pattern += '(' + options.urlParamPattern + ')';
                        } else {
                                // Strictly adhere to RFC3986
                                pattern += '([a-zA-Z0-9-_~\\.%@]+)';
                        }
                        params.push(frag.slice(1));
                } else {
                        pattern += frag;
                }

                return (true);
        });

        if (pattern === '^')
                pattern += '\\/';
        pattern += '$';

        re = new RegExp(pattern, options.flags);
        re.restifyParams = params;

        return (re);
}

///--- API

function Router(options) {
        assert.object(options, 'options');
        assert.object(options.log, 'options.log');

        EventEmitter.call(this);

        this.cache = LRU({max: 100});
        this.contentType = options.contentType || [];
        if (!Array.isArray(this.contentType))
                this.contentType = [this.contentType];
        assert.arrayOfString(this.contentType, 'options.contentType');

        this.log = options.log;
        this.mounts = {};
        this.name = 'RestifyRouter';

        // A list of methods to routes
        this.routes = {
                DELETE: [],
                GET: [],
                HEAD: [],
                OPTIONS: [],
                PATCH: [],
                POST: [],
                PUT: []
        };

        // So we can retrun 405 vs 404, we maintain a reverse mapping of URLs
        // to method
        this.reverse = {};

        this.version = options.version || [];
        if (!Array.isArray(this.version))
                this.version = [this.version];
        assert.arrayOfString(this.version, 'options.version');

        this.version.forEach(function (v) {
                if (semver.valid(v))
                        return (true);

                throw new InvalidArgumentError('%s is not a valid semver', v);
        });
        this.version.sort();

}
util.inherits(Router, EventEmitter);
module.exports = Router;

Router.prototype.mount = function mount(options) {
        assert.object(options, 'options');
        assert.string(options.method, 'options.method');
        assert.string(options.name, 'options.name');

        var exists;
        var name = options.name;
        var route;
        var routes = this.routes[options.method];
        var self = this;
        var type = options.contentType || self.contentType;
        var version = options.version || self.version;

        if (!Array.isArray(type))
                type = [type];
        type.sort();

        if (!Array.isArray(version))
                version = [version];
        version.sort();

        exists = routes.some(function (r) {
                return (r.name === name);
        });
        if (exists)
                return (false);

        route = {
                name: name,
                method: options.method,
                path: compileURL({
                        url: options.path || options.url,
                        flags: options.flags,
                        urlParamPattern: options.urlParamPattern
                }),
                type: type,
                version: version
        };
        routes.push(route);

        if (!this.reverse[route.path.source])
                this.reverse[route.path.source] = [];

        if (this.reverse[route.path.source].indexOf(route.method) === -1)
                this.reverse[route.path.source].push(route.method);

        this.mounts[route.name] = route;

        this.emit('mount',
                  route.method,
                  route.path,
                  route.type,
                  route.version);

        return (route.name);
};

Router.prototype.unmount = function unmount(name) {
        var route = this.mounts[name];
        if (!route) {
                this.log.warn('router.unmount(%s): route does not exist', name);
                return (false);
        }

        var reverse = this.reverse[route.path.source];
        var routes = this.routes[route.method];
        this.routes[route.method] = routes.filter(function (r) {
                return (r.name !== route.name);
        });

        this.reverse[route.path.source] = reverse.filter(function (r) {
                return (r !== route.method);
        });

        if (this.reverse[route.path.source].length === 0)
                delete this.reverse[route.path.source];

        delete this.mounts[name];

        return (name);
};

Router.prototype.find = function find(req, res, callback) {
        var ct = req.headers['content-type'] || DEF_CT;
        var cacheKey = req.method + req.url + req.version() + ct;
        var cacheVal;
        var params;
        var r;
        var routes = this.routes[req.method] || [];
        var typed;
        var ver;

        if ((cacheVal = this.cache.get(cacheKey))) {
                callback(null, cacheVal.name, clone(cacheVal.params));
                return;
        }

        for (var i = 0; i < routes.length; i++) {
                try {
                        params = matchURL(routes[i].path, req);
                } catch (e) {
                        this.log.trace({err: e}, 'error parsing URL');
                        callback(new BadRequestError(e.message));
                        return;
                }

                if (params === false)
                        continue;

                // Not common
                if (routes[i].type.length !== 0) {
                        switch (req.method) {
                        case 'POST':
                        case 'PUT':
                                // On uploads, check if the supplied
                                // content-type matches the type of the route
                                typed = routes[i].type.some(function (t) {
                                        return (matchContentType(t, ct));
                                });
                                break;

                        default:
                                break;
                        }

                        if (typed === false)
                                continue;
                }

                if (routes[i].version.length === 0 ||
                    req.version() === '*' ||
                    (ver = maxSatisfying(routes[i].version,
                                         req.version()) || false)) {
                        r = routes[i];
                        break;
                }
        }

        //
        // In order, we check if the route exists, in which case, we're good.
        // Otherwise we look to see if ver was set to false; that would tell us
        // we indeed did find a matching route (method+url), but the version
        // field didn't line up, so we return bad version.  If no route and no
        // version, we now need to go walk the reverse map and look at whether
        // we should return 405 or 404.  If it was an OPTIONS request, we need
        // to handle this having been a preflight request.
        //

        if (params && r) {
                cacheVal = {
                        name: r.name,
                        params: params
                };
                this.cache.set(cacheKey, cacheVal);
                callback(null, r.name, clone(params));
                return;
        }

        if (typed === false) {
                callback(new UnsupportedMediaTypeError(ct));
                return;
        }
        if (ver === false) {
                callback(new InvalidVersionError(req.getVersion()));
                return;
        }

        // This is a very generic preflight handler - it does
        // not handle requiring authentication, nor does it do
        // any special checking for extra user headers. The
        // user will need to defined their own .opts handler to
        // do that
        function preflight(methods) {
                var headers = req.headers['access-control-request-headers'];
                var method = req.headers['access-control-request-method'];
                var origin = req.headers['origin'];

                if (req.method !== 'OPTIONS' ||
                    !origin ||
                    !method ||
                    methods.indexOf(method) === -1) {
                        return (false);
                }
                // Last, check request-headers
                var ok = true;
                /* JSSTYLED */
                (headers || '').split(/\s*,\s*/).forEach(function (h) {
                        h = h.toLowerCase();
                        ok = ALLOW_HEADERS.indexOf(h) !== -1 && ok;
                });
                if (!ok)
                        return (false);

                res.setHeader('Access-Control-Allow-Origin', '*');
                res.setHeader('Access-Control-Allow-Methods',
                              methods.join(', '));
                res.setHeader('Access-Control-Allow-Headers',
                              ALLOW_HEADERS.join(', '));
                res.setHeader('Access-Control-Max-Age', 3600);

                return (true);
        }

        // Check for 405 instead of 404
        var urls = Object.keys(this.reverse);
        for (i = 0; i < urls.length; i++) {
                if (matchURL(new RegExp(urls[i]), req)) {
                        var _methods = this.reverse[urls[i]].slice();
                        res.setHeader('Allow', _methods.join(', '));
                        if (preflight(_methods)) {
                                callback(null, true);
                                return;
                        }
                        var err = new MethodNotAllowedError('%s is not allowed',
                                                            req.method);
                        callback(err);
                        return;
                }
        }

        callback(new ResourceNotFoundError('%s does not exist', req.url));
};

Router.prototype.toString = function toString() {
        var self = this;
        var str = this.name + ':\n';

        Object.keys(this.routes).forEach(function (k) {
                var routes = self.routes[k].map(function (r) {
                        return (r.name);
                });

                str += '\t\t' + k + ': [' + routes.join(', ') + ']\n';
        });

        return (str);
};
<|endoftext|>


<commit_before>Router.configure({
    layoutTemplate : 'layout',
    loadingTemplate : 'loading',
    notFoundTemplate : 'notFound'
    // waitOn : function () {
    //     return Meteor.subscribe('posts');
    // }
});

Router.route('/', {name : 'landing'});
Router.route('/goalsettings', {name : 'showGoals'});
Router.route('/crylevel', {name : 'cryLevel'});

Router.route('/posts/:_id', {
    name : 'postPage',
    data : function() {
        return Posts.findOne(this.params._id);
    }
});

Router.route('/posts/:_id/edit', {
    name : 'postEdit',
    data : function () {
        return Posts.findOne(this.params._id);
    }
})

Router.route('/submit', {name : 'postSubmit'})

var requireLogin = function () {
    if (!Meteor.userId()) {
        if (Meteor.loggingIn()) {
            this.render('loadingTemplate');
        } else {
            Router.go('landing');
        }
        this.stop();
    } else {
        this.next();
    }
}

Router.onBeforeAction('dataNotFound', {only : 'postPage'});
Router.onBeforeAction(requireLogin, {except : 'landing'});<commit_msg>Add dashes to route paths<commit_after>Router.configure({
    layoutTemplate : 'layout',
    loadingTemplate : 'loading',
    notFoundTemplate : 'notFound'
    // waitOn : function () {
    //     return Meteor.subscribe('posts');
    // }
});

Router.route('/', {name : 'landing'});
Router.route('/goal-settings', {name : 'showGoals'});
Router.route('/cry-level', {name : 'cryLevel'});

Router.route('/posts/:_id', {
    name : 'postPage',
    data : function() {
        return Posts.findOne(this.params._id);
    }
});

Router.route('/posts/:_id/edit', {
    name : 'postEdit',
    data : function () {
        return Posts.findOne(this.params._id);
    }
})

Router.route('/submit', {name : 'postSubmit'})

var requireLogin = function () {
    if (!Meteor.userId()) {
        if (Meteor.loggingIn()) {
            this.render('loadingTemplate');
        } else {
            Router.go('landing');
        }
        this.stop();
    } else {
        this.next();
    }
}

Router.onBeforeAction('dataNotFound', {only : 'postPage'});
Router.onBeforeAction(requireLogin, {except : 'landing'});<|endoftext|>


<commit_before>var ipc = require('node-ipc');

/*
 * stores information about the location of participating processes in the job
 * each process key has a value of either 'local' or 'remote'
 * a special 'parent' key is present for the location of the klyng process
 */
var meta_routing_table = {};

/*
 * stores the ipc channels of each local process participating in the job
 * @key {String}: 'proc' + process rank
 * @value {ChildProcess}: a refernce to the process
 */
var locals_routiung_channels = {};

var remote_routing_channels = {}; //TBD

// holds a reference to the socket connected to klyng process
// to send monitoring messages across
var monitor_socket = null;

/*
 * checks if the routing data structures are empty
 * @return {Boolean}: true if empty, false otherwise
 */
function isClean() {
    var clean_meta = !Object.keys(meta_routing_table).length;
    var clean_locals = !Object.keys(locals_routiung_channels).length;
    var clean_remotes = !Object.keys(remote_routing_channels).length;
    var clean_monitor = (monitor_socket === null);

    return clean_meta && clean_locals && clean_remotes && clean_monitor;
}

/*
 * checks if the routing table contains remote members
 * @return {Boolean}: true if it has remotes, false otherwise
 */
 function hasRemotes() {
     return !Object.keys(remote_routing_channels).length;
 }

/*
 * builds a pure local routing table for jobs with no remotes
 * @param size {Number}: the size of the job
 * @return {Object}: the built table;
 */
function buildPureLocalTable(size) {
    var pureLocal = {};
    for(var id = 0; id < size; id++)
        pureLocal['proc' + id] = 'local';
    pureLocal.parent = 'local';

    return pureLocal;
}

/*
 * sets the meta routing table
 * @param table {Object}: the new job's table
 */
function setMetaTable(table) {
    meta_routing_table = table;
}

/*
 * sets the routing socket of the table
 * @param socket {Socket}
 */
function setMonitorSocket(socket) {
    monitor_socket = socket;
}

/*
 * sets a local channel of a process
 * @param rank {Number}
 * @param proc {ChildProcess}
 */
function setLocalChannel(rank, proc) {
    locals_routiung_channels['proc' + rank] = proc;
}

/*
* clears the router data structures
*/
function clear() {
    meta_routing_table = {};
    locals_routiung_channels = {};
    remote_routing_channels = {};
    monitor_socket = null;
}

/*
 * routes a message to the parent process
 * @param id {Number}: the job's id
 * @param message {Object}: the message to be routed
 */
 function routeToParent(message) {
    if(meta_routing_table.parent === 'local') {
        ipc.server.emit(monitor_socket, 'MONITOR:MSG', message);
    }
}

/*
 * routes a message to a process by rank
 * @param to {Number}: the recepient's rank
 * @param msg {Object}: the message to route
 */
function routeTo(to, msg) {
    if(meta_routing_table['proc' + to] === 'local') {
        locals_routiung_channels['proc' + to].send(msg);
    }
}

module.exports = {
    isClean: isClean,
    hasRemotes: hasRemotes,
    buildPureLocalTable: buildPureLocalTable,
    setMetaTable: setMetaTable,
    setMonitorSocket: setMonitorSocket,
    setLocalChannel: setLocalChannel,
    clear: clear,
    routeToParent: routeToParent,
    routeTo: routeTo
};
<commit_msg>implemented routing to remote parent<commit_after>var ipc = require('node-ipc');

/*
 * stores information about the location of participating processes in the job
 * each process key has a value of either 'local' or 'remote'
 * a special 'parent' key is present for the location of the klyng process
 */
var meta_routing_table = {};

/*
 * stores the ipc channels of each local process participating in the job
 * @key {String}: 'proc' + process rank
 * @value {ChildProcess}: a refernce to the process
 */
var locals_routiung_channels = {};

var remote_routing_channels = {}; //TBD

// holds a reference to the socket connected to klyng process
// to send monitoring messages across
var monitor_socket = null;

/*
 * checks if the routing data structures are empty
 * @return {Boolean}: true if empty, false otherwise
 */
function isClean() {
    var clean_meta = !Object.keys(meta_routing_table).length;
    var clean_locals = !Object.keys(locals_routiung_channels).length;
    var clean_remotes = !Object.keys(remote_routing_channels).length;
    var clean_monitor = (monitor_socket === null);

    return clean_meta && clean_locals && clean_remotes && clean_monitor;
}

/*
 * checks if the routing table contains remote members
 * @return {Boolean}: true if it has remotes, false otherwise
 */
 function hasRemotes() {
     return !Object.keys(remote_routing_channels).length;
 }

/*
 * builds a pure local routing table for jobs with no remotes
 * @param size {Number}: the size of the job
 * @return {Object}: the built table;
 */
function buildPureLocalTable(size) {
    var pureLocal = {};
    for(var id = 0; id < size; id++)
        pureLocal['proc' + id] = 'local';
    pureLocal.parent = 'local';

    return pureLocal;
}

/*
 * sets the meta routing table
 * @param table {Object}: the new job's table
 */
function setMetaTable(table) {
    meta_routing_table = table;
}

/*
 * sets the routing socket of the table
 * @param socket {Socket}
 */
function setMonitorSocket(socket) {
    monitor_socket = socket;
}

/*
 * sets a local channel of a process
 * @param rank {Number}
 * @param proc {ChildProcess}
 */
function setLocalChannel(rank, proc) {
    locals_routiung_channels['proc' + rank] = proc;
}

/*
* clears the router data structures
*/
function clear() {
    meta_routing_table = {};
    locals_routiung_channels = {};
    remote_routing_channels = {};
    monitor_socket = null;
}

/*
 * routes a message to the parent process
 * @param id {Number}: the job's id
 * @param message {Object}: the message to be routed
 */
 function routeToParent(message) {
    if(meta_routing_table.parent === 'local') {
        ipc.server.emit(monitor_socket, 'MONITOR:MSG', message);
    }
    else {
        monitor_socket.emit('MONITOR:MSG', message);
    }
}

/*
 * routes a message to a process by rank
 * @param to {Number}: the recepient's rank
 * @param msg {Object}: the message to route
 */
function routeTo(to, msg) {
    if(meta_routing_table['proc' + to] === 'local') {
        locals_routiung_channels['proc' + to].send(msg);
    }
}

module.exports = {
    isClean: isClean,
    hasRemotes: hasRemotes,
    buildPureLocalTable: buildPureLocalTable,
    setMetaTable: setMetaTable,
    setMonitorSocket: setMonitorSocket,
    setLocalChannel: setLocalChannel,
    clear: clear,
    routeToParent: routeToParent,
    routeTo: routeTo
};
<|endoftext|>


<commit_before>Router.configure({
    layoutTemplate: 'layout',
    //loadingTemplate: 'loading',
    waitOn: function () {
        return [Meteor.subscribe('users')];
    }
});
Router.map(function () {
    this.route('roomList', {
        path: '/',
        waitOn: function () {
            return Meteor.subscribe('availableRooms');
        },
        data: function () {
            return Rooms.find();
        }
    });
    this.route('roomView', {
        name: 'roomView',
        path: '/room/:_id',
        subscriptions: function () {
            Session.set('messageLimit', 10);
            return [
                Meteor.subscribe('availableRooms'),
                Meteor.subscribe('currentRooms'),
                Meteor.subscribe('notifications'),
                Meteor.subscribe('emojis'),
            ];
        },
        action: function () {
            Session.set('currentRoom', this.params._id);
            var room = Rooms.findOne({_id: this.params._id});
            if (!room) {
                Router.go('roomList');
            }
            if (!_.contains(room.users, Meteor.userId())) {
                Meteor.call('joinRoom', room._id, function (err, id) {
                    if (err) {
                        Router.go('roomList');
                    }
                }); //TODO: on error goto fail
            }
            this.go('chat');
        }
    });

    this.route('chat',{
        subscriptions: function () {
            Session.set('messageLimit', 10);
            return [
                Meteor.subscribe('availableRooms'),
                Meteor.subscribe('currentRooms'),
                Meteor.subscribe('notifications'),
                Meteor.subscribe('emojis'),
            ];
        },
        action: function(){
            this.render('roomView');
        }
    });
});

Router.onBeforeAction(function (pause) {
    if (!Meteor.userId()) {
        return this.render('login');
    }
    else {
        this.next();
    }
});<commit_msg>changed default route to chat<commit_after>Router.configure({
    layoutTemplate: 'layout',
    //loadingTemplate: 'loading',
    waitOn: function () {
        return [Meteor.subscribe('users')];
    }
});
Router.map(function () {
    this.route('roomView', {
        name: 'roomView',
        path: '/room/:_id',
        subscriptions: function () {
            Session.set('messageLimit', 10);
            return [
                Meteor.subscribe('availableRooms'),
                Meteor.subscribe('currentRooms'),
                Meteor.subscribe('notifications'),
                Meteor.subscribe('emojis'),
            ];
        },
        action: function () {
            Session.set('currentRoom', this.params._id);
            var room = Rooms.findOne({_id: this.params._id});
            if (!room) {
                Router.go('roomList');
            }
            if (!_.contains(room.users, Meteor.userId())) {
                Meteor.call('joinRoom', room._id, function (err, id) {
                    if (err) {
                        Router.go('roomList');
                    }
                }); //TODO: on error goto fail
            }
            this.go('chat');
        }
    });

    this.route('chat',{
        path:'/',
        subscriptions: function () {
            Session.set('messageLimit', 10);
            return [
                Meteor.subscribe('availableRooms'),
                Meteor.subscribe('currentRooms'),
                Meteor.subscribe('notifications'),
                Meteor.subscribe('emojis'),
            ];
        },
        action: function(){

            this.render('roomView');
        }
    });
});

Router.onBeforeAction(function (pause) {
    if (!Meteor.userId()) {
        return this.render('login');
    }
    else {
        this.next();
    }
});<|endoftext|>


<commit_before>var ipc = require('node-ipc');

/*
 * stores information about the location of participating processes in the job
 * each process key has a value of either 'local' or 'remote'
 * a special 'parent' key is present for the location of the klyng process
 */
var meta_routing_table = {};

/*
 * stores the ipc channels of each local process participating in the job
 * @key {String}: 'proc' + process rank
 * @value {ChildProcess}: a refernce to the process
 */
var locals_routiung_channels = {};

/*
 * stores the ipc tcp channels of each remote beacon participating in the job
 * @key {String}: 'sock_' + ip:port
 * @value {Socket}
 */
var remote_routing_channels = {};

// holds a reference to the socket connected to klyng process
// to send monitoring messages across
var monitor_socket = null;

/*
 * checks if the routing data structures are empty
 * @return {Boolean}: true if empty, false otherwise
 */
function isClean() {
    var clean_meta = !Object.keys(meta_routing_table).length;
    var clean_locals = !Object.keys(locals_routiung_channels).length;
    var clean_remotes = !Object.keys(remote_routing_channels).length;
    var clean_monitor = (monitor_socket === null);

    return clean_meta && clean_locals && clean_remotes && clean_monitor;
}

/*
 * checks if the routing table contains remote members
 * @return {Boolean}: true if it has remotes, false otherwise
 */
 function hasRemotes() {
     return !Object.keys(remote_routing_channels).length;
 }

/*
 * builds a pure local routing table for jobs with no remotes
 * @param size {Number}: the size of the job
 * @return {Object}: the built table;
 */
function buildPureLocalTable(size) {
    var pureLocal = {};
    for(var id = 0; id < size; id++)
        pureLocal['proc' + id] = 'local';
    pureLocal.parent = 'local';

    return pureLocal;
}

/*
 * sets the meta routing table
 * @param table {Object}: the new job's table
 */
function setMetaTable(table) {
    meta_routing_table = table;
}

/*
 * sets the routing socket of the table
 * @param socket {Socket}
 */
function setMonitorSocket(socket) {
    monitor_socket = socket;
}

/*
 * sets a local channel of a process
 * @param rank {Number}
 * @param proc {ChildProcess}
 */
function setLocalChannel(rank, proc) {
    locals_routiung_channels['proc' + rank] = proc;
}

/*
 * sets a remote channel of a beacon
 * @param id {String}: the identifing 'ip:port' connection string
 * @param sock {Socket}: the socket to the beacon
 */
 function setRemoteChannel(id, sock) {
     remote_routing_channels['sock_' + id] = sock;
 }

/*
* clears the router data structures
*/
function clear() {
    meta_routing_table = {};
    locals_routiung_channels = {};
    remote_routing_channels = {};
    monitor_socket = null;
}

/*
 * routes a message to the parent process
 * @param id {Number}: the job's id
 * @param message {Object}: the message to be routed
 */
 function routeToParent(message) {
    if(meta_routing_table.parent === 'local') {
        // fall to common ipc instance if klyng's is not there (happens in unit tests)
        ipc = ipc.klyngLocal || ipc;
        ipc.server.emit(monitor_socket, 'MONITOR:MSG', message);
    }
    else {
        monitor_socket.emit('MONITOR:MSG', message);
    }
}

/*
 * routes a message to a process by rank
 * @param to {Number}: the recepient's rank
 * @param msg {Object}: the message to route
 */
function routeTo(to, msg) {
    if(meta_routing_table['proc' + to] === 'local') {
        locals_routiung_channels['proc' + to].send(msg);
    }
    else {
        var id = meta_routing_table['proc' + to];
        remote_routing_channels['sock_' + id].emit('KLYNG:MSG', msg);
    }
}

module.exports = {
    isClean: isClean,
    hasRemotes: hasRemotes,
    buildPureLocalTable: buildPureLocalTable,
    setMetaTable: setMetaTable,
    setMonitorSocket: setMonitorSocket,
    setLocalChannel: setLocalChannel,
    setRemoteChannel: setRemoteChannel,
    clear: clear,
    routeToParent: routeToParent,
    routeTo: routeTo
};
<commit_msg>implemented buildTableFromPlan function<commit_after>var ipc = require('node-ipc');

/*
 * stores information about the location of participating processes in the job
 * each process key has a value of either 'local' or 'remote'
 * a special 'parent' key is present for the location of the klyng process
 */
var meta_routing_table = {};

/*
 * stores the ipc channels of each local process participating in the job
 * @key {String}: 'proc' + process rank
 * @value {ChildProcess}: a refernce to the process
 */
var locals_routiung_channels = {};

/*
 * stores the ipc tcp channels of each remote beacon participating in the job
 * @key {String}: 'sock_' + ip:port
 * @value {Socket}
 */
var remote_routing_channels = {};

// holds a reference to the socket connected to klyng process
// to send monitoring messages across
var monitor_socket = null;

/*
 * checks if the routing data structures are empty
 * @return {Boolean}: true if empty, false otherwise
 */
function isClean() {
    var clean_meta = !Object.keys(meta_routing_table).length;
    var clean_locals = !Object.keys(locals_routiung_channels).length;
    var clean_remotes = !Object.keys(remote_routing_channels).length;
    var clean_monitor = (monitor_socket === null);

    return clean_meta && clean_locals && clean_remotes && clean_monitor;
}

/*
 * checks if the routing table contains remote members
 * @return {Boolean}: true if it has remotes, false otherwise
 */
 function hasRemotes() {
     return !Object.keys(remote_routing_channels).length;
 }

/*
 * builds a pure local routing table for jobs with no remotes
 * @param size {Number}: the size of the job
 * @return {Object}: the built table;
 */
function buildPureLocalTable(size) {
    var pureLocal = {};
    for(var id = 0; id < size; id++)
        pureLocal['proc' + id] = 'local';
    pureLocal.parent = 'local';

    return pureLocal;
}

/*
 * builds a routing table using a given job distribution plan
 * @param plan {Object}: job plan
 * @return {Object}: the built table
 */
function buildTableFromPlan(plan) {
    var table = {};
    for(var host in plan) {
        var hostinfo = plan[host];

        if(hostinfo.start === 0) {
            table.parent = host;
        }

        for(var i = 0; i < hostinfo.count; i++) {
            table['proc' + (hostinfo.start + i)] = host;
        }
    }

    return table;
}

/*
 * sets the meta routing table
 * @param table {Object}: the new job's table
 */
function setMetaTable(table) {
    meta_routing_table = table;
}

/*
 * sets the routing socket of the table
 * @param socket {Socket}
 */
function setMonitorSocket(socket) {
    monitor_socket = socket;
}

/*
 * sets a local channel of a process
 * @param rank {Number}
 * @param proc {ChildProcess}
 */
function setLocalChannel(rank, proc) {
    locals_routiung_channels['proc' + rank] = proc;
}

/*
 * sets a remote channel of a beacon
 * @param id {String}: the identifing 'ip:port' connection string
 * @param sock {Socket}: the socket to the beacon
 */
 function setRemoteChannel(id, sock) {
     remote_routing_channels['sock_' + id] = sock;
 }

/*
* clears the router data structures
*/
function clear() {
    meta_routing_table = {};
    locals_routiung_channels = {};
    remote_routing_channels = {};
    monitor_socket = null;
}

/*
 * routes a message to the parent process
 * @param id {Number}: the job's id
 * @param message {Object}: the message to be routed
 */
 function routeToParent(message) {
    if(meta_routing_table.parent === 'local') {
        // fall to common ipc instance if klyng's is not there (happens in unit tests)
        ipc = ipc.klyngLocal || ipc;
        ipc.server.emit(monitor_socket, 'MONITOR:MSG', message);
    }
    else {
        monitor_socket.emit('MONITOR:MSG', message);
    }
}

/*
 * routes a message to a process by rank
 * @param to {Number}: the recepient's rank
 * @param msg {Object}: the message to route
 */
function routeTo(to, msg) {
    if(meta_routing_table['proc' + to] === 'local') {
        locals_routiung_channels['proc' + to].send(msg);
    }
    else {
        var id = meta_routing_table['proc' + to];
        remote_routing_channels['sock_' + id].emit('KLYNG:MSG', msg);
    }
}

module.exports = {
    isClean: isClean,
    hasRemotes: hasRemotes,
    buildPureLocalTable: buildPureLocalTable,
    buildTableFromPlan: buildTableFromPlan,
    setMetaTable: setMetaTable,
    setMonitorSocket: setMonitorSocket,
    setLocalChannel: setLocalChannel,
    setRemoteChannel: setRemoteChannel,
    clear: clear,
    routeToParent: routeToParent,
    routeTo: routeTo
};
<|endoftext|>


<commit_before>/**
 * Dependencies
 */

var debug = require('debug')('koa-router')
  , methods = require('methods')
  , parse = require('url').parse
  , Route = require('./route');

/**
 * Expose `Router`
 */

module.exports = Router;

/**
 * Initialize Router.
 *
 * @param {Application} app Optional. Extends app with methods such
 * as `app.get()`, `app.post()`, etc.
 * @return {Router}
 * @api public
 */

function Router(app) {
  if (!(this instanceof Router)) {
    var router = new Router(app);
    return router.middleware();
  }

  this.methods = ['OPTIONS'];
  this.routes = [];

  // extend application
  if (app) this.extendApp(app);
};

/**
 * Router prototype
 */

var router = Router.prototype;

/**
 * Router middleware factory. Returns router middleware which dispatches route
 * middleware corresponding to the request.
 *
 * @param {Function} next
 * @return {Function}
 * @api public
 */

router.middleware = function() {
  var router = this;

  return function *dispatch(next) {
    var matchedRoutes;

    // Parameters for this route
    if (!(this.params instanceof Array)) {
      this.params = [];
    }

    debug('%s %s', this.method, this.path);

    // Find routes matching requested path
    if (matchedRoutes = router.match(this.path, this.params)) {
      var methodsAvailable = {};

      // Find matched route for requested method
      for (var len = matchedRoutes.length, i=0; i<len; i++) {
        var route = matchedRoutes[i];

        for (var l = route.methods.length, n=0; n<l; n++) {
          var method = route.methods[n];

          methodsAvailable[method] = true;

          // if method and path match, dispatch route middleware
          if (method === this.method) {
            debug('dispatch "%s" %s', route.path, route.regexp);
            return yield route.middleware.call(this, next);
          }
        }
      }

      // matches path but not method, so return 405 Method Not Allowed
      // unless this is an OPTIONS request.
      this.status = (this.method === 'OPTIONS' ? 204 : 405);
      this.set('Allow', Object.keys(methodsAvailable).join(", "));
    }
    else {
      // Could not find any route matching the requested path
      // simply yield to downstream koa middleware
      return yield next;
    }

    // a route matched the path but not method.
    // currently status is prepared as 204 or 405
    // If the method is in fact unknown at the router level,
    // send 501 Not Implemented
    if (!~router.methods.indexOf(this.method)) {
      this.status = 501;
    }
  };
};

/**
 * Create `router.verb()` methods, where *verb* is one of the HTTP verbes such
 * as `router.get()` or `router.post()`.
 */

methods.forEach(function(method) {
  router[method] = function(name, path, middleware) {
    var args = Array.prototype.slice.call(arguments);
    args.splice(typeof path == 'function' ? 1 : 2, 0, [method]);

    return this.register.apply(this, args);
  };
});

// Alias for `router.delete()` because delete is a reserved word
router.del = router['delete'];

/**
 * Register route with all methods.
 *
 * @param {String} name Optional.
 * @param {String|RegExp} path
 * @param {Function} middleware You may also pass multiple middleware.
 * @return {Route}
 * @api public
 */

router.all = function(name, path, middleware) {
  var args = Array.prototype.slice.call(arguments);
  args.splice(typeof path == 'function' ? 1 : 2, 0, methods);

  return this.register.apply(this, args);
};

/**
 * Redirect `path` to `destination` URL with optional 30x status `code`.
 *
 * @param {String} source URL, RegExp, or route name.
 * @param {String} destination URL or route name.
 * @param {Number} code HTTP status code (default: 301).
 * @return {Route}
 * @api public
 */

router.redirect = function(source, destination, code) {
  // lookup source route by name
  if (source instanceof RegExp || source[0] != '/') {
    source = this.route(source);
  }

  // lookup destination route by name
  if (destination instanceof RegExp || destination[0] != '/') {
    destination = this.route(destination);
  }

  return this.all(source, function *() {
    this.redirect(destination);
    this.status = code || 301;
  });
};

/**
 * Create and register a route.
 *
 * @param {String} name Optional.
 * @param {String|RegExp} path Path string or regular expression.
 * @param {Array} methods Array of HTTP verbs.
 * @param {Function} middleware Multiple middleware also accepted.
 * @return {Route}
 * @api public
 */

router.register = function(name, path, methods, middleware) {
  if (path instanceof Array) {
    middleware = Array.prototype.slice.call(arguments, 2);
    methods = path;
    path = name;
    name = null;
  }
  else {
    middleware = Array.prototype.slice.call(arguments, 3);
  }

  // create route
  var route = new Route(path, methods, middleware, name);

  // register route with router
  this.routes.push(route);

  // register route methods with router (for 501 responses)
  route.methods.forEach(function(method) {
    if (!~this.methods.indexOf(method)) {
      this.methods.push(method);
    }
  }, this);

  return route;
};

/**
 * Lookup route with given `name`.
 *
 * @param {String} name
 * @return {Route|false}
 * @api public
 */

router.route = function(name) {
  for (var len = this.routes.length, i=0; i<len; i++) {
    if (this.routes[i].name == name) {
      return this.routes[i];
    }
  }

  return false;
};

/**
 * Generate URL for route using given `params`.
 *
 * @param {String} name route name
 * @param {Object} params url parameters
 * @return {String|Error}
 * @api public
 */

router.url = function(name, params) {
  var route = this.route(name);

  if (route) {
    var args = Array.prototype.slice.call(arguments, 1);
    return route.url.apply(route, args);
  }

  return new Error("No route found for name: " + name);
};

/**
 * Match given `path` and return corresponding routes.
 *
 * @param {String} path
 * @param {Array} params populated with captured url parameters
 * @return {Array|false} Returns matched routes or false.
 * @api private
 */

router.match = function(path, params) {
  var routes = this.routes;
  var matchedRoutes = [];

  for (var len = routes.length, i=0; i<len; i++) {
    debug('test "%s" %s', routes[i].path, routes[i].regexp);

    if (routes[i].match(path, params)) {
      debug('match "%s" %s', routes[i].path, routes[i].regexp);
      matchedRoutes.push(routes[i]);
    }
  }

  return matchedRoutes.length > 0 ? matchedRoutes : false;
};

/**
 * Extend given `app` with router methods.
 *
 * @param {Application} app
 * @return {Application}
 * @api private
 */

router.extendApp = function(app) {
  ['all', 'redirect', 'register', 'url'].concat(methods)
  .forEach(function(method) {
    app[method] = Router.prototype[method].bind(this);
  }, this);

  return app;
};

/**
 * Merge b into a.
 *
 * @param {Object} a
 * @param {Object} b
 * @return {Object} a
 * @api private
 */

function merge(a, b) {
  if (!b) return a;
  for (var k in b) a[k] = b[k];
  return a;
}
<commit_msg>make  available on app<commit_after>/**
 * Dependencies
 */

var debug = require('debug')('koa-router')
  , methods = require('methods')
  , parse = require('url').parse
  , Route = require('./route');

/**
 * Expose `Router`
 */

module.exports = Router;

/**
 * Initialize Router.
 *
 * @param {Application} app Optional. Extends app with methods such
 * as `app.get()`, `app.post()`, etc.
 * @return {Router}
 * @api public
 */

function Router(app) {
  if (!(this instanceof Router)) {
    var router = new Router(app);
    return router.middleware();
  }

  this.methods = ['OPTIONS'];
  this.routes = [];

  // extend application
  if (app) this.extendApp(app);
};

/**
 * Router prototype
 */

var router = Router.prototype;

/**
 * Router middleware factory. Returns router middleware which dispatches route
 * middleware corresponding to the request.
 *
 * @param {Function} next
 * @return {Function}
 * @api public
 */

router.middleware = function() {
  var router = this;

  return function *dispatch(next) {
    var matchedRoutes;

    // Parameters for this route
    if (!(this.params instanceof Array)) {
      this.params = [];
    }

    debug('%s %s', this.method, this.path);

    // Find routes matching requested path
    if (matchedRoutes = router.match(this.path, this.params)) {
      var methodsAvailable = {};

      // Find matched route for requested method
      for (var len = matchedRoutes.length, i=0; i<len; i++) {
        var route = matchedRoutes[i];

        for (var l = route.methods.length, n=0; n<l; n++) {
          var method = route.methods[n];

          methodsAvailable[method] = true;

          // if method and path match, dispatch route middleware
          if (method === this.method) {
            debug('dispatch "%s" %s', route.path, route.regexp);
            return yield route.middleware.call(this, next);
          }
        }
      }

      // matches path but not method, so return 405 Method Not Allowed
      // unless this is an OPTIONS request.
      this.status = (this.method === 'OPTIONS' ? 204 : 405);
      this.set('Allow', Object.keys(methodsAvailable).join(", "));
    }
    else {
      // Could not find any route matching the requested path
      // simply yield to downstream koa middleware
      return yield next;
    }

    // a route matched the path but not method.
    // currently status is prepared as 204 or 405
    // If the method is in fact unknown at the router level,
    // send 501 Not Implemented
    if (!~router.methods.indexOf(this.method)) {
      this.status = 501;
    }
  };
};

/**
 * Create `router.verb()` methods, where *verb* is one of the HTTP verbes such
 * as `router.get()` or `router.post()`.
 */

methods.forEach(function(method) {
  router[method] = function(name, path, middleware) {
    var args = Array.prototype.slice.call(arguments);
    args.splice(typeof path == 'function' ? 1 : 2, 0, [method]);

    return this.register.apply(this, args);
  };
});

// Alias for `router.delete()` because delete is a reserved word
router.del = router['delete'];

/**
 * Register route with all methods.
 *
 * @param {String} name Optional.
 * @param {String|RegExp} path
 * @param {Function} middleware You may also pass multiple middleware.
 * @return {Route}
 * @api public
 */

router.all = function(name, path, middleware) {
  var args = Array.prototype.slice.call(arguments);
  args.splice(typeof path == 'function' ? 1 : 2, 0, methods);

  return this.register.apply(this, args);
};

/**
 * Redirect `path` to `destination` URL with optional 30x status `code`.
 *
 * @param {String} source URL, RegExp, or route name.
 * @param {String} destination URL or route name.
 * @param {Number} code HTTP status code (default: 301).
 * @return {Route}
 * @api public
 */

router.redirect = function(source, destination, code) {
  // lookup source route by name
  if (source instanceof RegExp || source[0] != '/') {
    source = this.route(source);
  }

  // lookup destination route by name
  if (destination instanceof RegExp || destination[0] != '/') {
    destination = this.route(destination);
  }

  return this.all(source, function *() {
    this.redirect(destination);
    this.status = code || 301;
  });
};

/**
 * Create and register a route.
 *
 * @param {String} name Optional.
 * @param {String|RegExp} path Path string or regular expression.
 * @param {Array} methods Array of HTTP verbs.
 * @param {Function} middleware Multiple middleware also accepted.
 * @return {Route}
 * @api public
 */

router.register = function(name, path, methods, middleware) {
  if (path instanceof Array) {
    middleware = Array.prototype.slice.call(arguments, 2);
    methods = path;
    path = name;
    name = null;
  }
  else {
    middleware = Array.prototype.slice.call(arguments, 3);
  }

  // create route
  var route = new Route(path, methods, middleware, name);

  // register route with router
  this.routes.push(route);

  // register route methods with router (for 501 responses)
  route.methods.forEach(function(method) {
    if (!~this.methods.indexOf(method)) {
      this.methods.push(method);
    }
  }, this);

  return route;
};

/**
 * Lookup route with given `name`.
 *
 * @param {String} name
 * @return {Route|false}
 * @api public
 */

router.route = function(name) {
  for (var len = this.routes.length, i=0; i<len; i++) {
    if (this.routes[i].name == name) {
      return this.routes[i];
    }
  }

  return false;
};

/**
 * Generate URL for route using given `params`.
 *
 * @param {String} name route name
 * @param {Object} params url parameters
 * @return {String|Error}
 * @api public
 */

router.url = function(name, params) {
  var route = this.route(name);

  if (route) {
    var args = Array.prototype.slice.call(arguments, 1);
    return route.url.apply(route, args);
  }

  return new Error("No route found for name: " + name);
};

/**
 * Match given `path` and return corresponding routes.
 *
 * @param {String} path
 * @param {Array} params populated with captured url parameters
 * @return {Array|false} Returns matched routes or false.
 * @api private
 */

router.match = function(path, params) {
  var routes = this.routes;
  var matchedRoutes = [];

  for (var len = routes.length, i=0; i<len; i++) {
    debug('test "%s" %s', routes[i].path, routes[i].regexp);

    if (routes[i].match(path, params)) {
      debug('match "%s" %s', routes[i].path, routes[i].regexp);
      matchedRoutes.push(routes[i]);
    }
  }

  return matchedRoutes.length > 0 ? matchedRoutes : false;
};

/**
 * Extend given `app` with router methods.
 *
 * @param {Application} app
 * @return {Application}
 * @api private
 */

router.extendApp = function(app) {
  ['all', 'redirect', 'register', 'url', 'del'].concat(methods)
  .forEach(function(method) {
    app[method] = Router.prototype[method].bind(this);
  }, this);

  return app;
};

/**
 * Merge b into a.
 *
 * @param {Object} a
 * @param {Object} b
 * @return {Object} a
 * @api private
 */

function merge(a, b) {
  if (!b) return a;
  for (var k in b) a[k] = b[k];
  return a;
}
<|endoftext|>


<commit_before>var express  = require('express'),
    handlers = require('./handlers'),
    models   = require('./models'),
    helpers  = require('./helpers'),
    errors   = require('./errors'),
    spike    = require('./spike'),
    scripts  = require('../scripts.json');

function tag(label) {
  return function (req, res, next) {
    req[label] = true;
    next();
  };
}

module.exports = function (app) {
  // A sandbox object to contain some specific objects that are commonly used by
  // handlers. In future it would be ideal that each handler only receives the
  // objects that it requires.
  var sandbox = {
    store:   app.store,
    models:  models,
    mailer:  app.mailer,
    helpers: helpers.createHelpers(app)
  }, binHandler, sessionHandler, errorHandler;

  // Create handlers for accepting incoming requests.
  binHandler = new handlers.BinHandler(sandbox);
  sessionHandler = new handlers.SessionHandler(sandbox);
  errorHandler = new handlers.ErrorHandler(sandbox);

  // Special redirects (to external sources)
  app.get(['/video', '/videos', '/tutorials'], function (req, res) {
    res.redirect('http://www.youtube.com/playlist?list=PLXmT1r4krsTooRDWOrIu23P3SEZ3luIUq');
  });

  app.get('/about', function (req, res) {
    res.redirect('https://github.com/remy/jsbin/blob/master/README.markdown');
  });

  app.get(['/issues', '/bugs'], function (req, res) {
    res.redirect('https://github.com/remy/jsbin/issues/');
  });

  // Handler Events

  binHandler.on('updated', spike.ping.bind(spike));
  binHandler.on('reload', spike.reload.bind(spike));
  binHandler.on('latest-for-user', spike.updateUserSpikes.bind(spike));
  binHandler.on('new-revision', spike.bumpRevision.bind(spike));

  binHandler.on('render-scripts', spike.appendScripts.bind(spike, app.settings.version));

  // Load the bin from the store when encountered in the url. Also handles the
  // "latest" url action.
  app.param('bin', binHandler.loadBin, binHandler.checkPrivate);
  app.param('rev', binHandler.loadBinRevision);
  app.param('name', sessionHandler.loadUser);

  // Set up the routes.
  app.get('/', binHandler.getDefault);
  app.get('/gist/*', binHandler.getDefault);
  app.post('/', binHandler.getFromPost);

  // Runner
  app.get('/runner', function (req, res) {
    res.render('runner', {
      scripts: app.get('is_production') ? false : scripts.runner,
      static: sandbox.helpers.urlForStatic()
    });
  });

  app.get('/api/:bin/:rev?', binHandler.apiGetBin);
  app.post('/api/save', binHandler.apiCreateBin);
  app.post('/api/:bin/save', binHandler.apiCreateRevision);

  // Login/Create account.
  app.post('/sethome', sessionHandler.routeSetHome);
  app.post('/logout', sessionHandler.logoutUser);
  app.post('/forgot', sessionHandler.forgotPassword);
  app.get('/forgot', sessionHandler.requestToken);
  app.get('/reset', sessionHandler.resetPassword);

  // GitHub auth
  app.get('/auth/github', sessionHandler.github);
  app.get('/auth/github/callback', sessionHandler.githubPassportCallback, sessionHandler.githubCallback);

  // List
  app.get('/list/:user', binHandler.getUserBins);
  app.get('/list',       binHandler.getUserBins);
  app.get('/show/:user', binHandler.getUserBins);
  app.get('/user/:user', binHandler.getUserBins);

  // TODO: Need to add an authentication handler - also handle user not logged in
  app.get('/pro', sessionHandler.setProAccount);

  // Latest
  app.get('/:bin/latest((.|\/):format)?', binHandler.redirectToLatest);
  app.get('/:bin/latest/edit', binHandler.redirectToLatest);

  // Quick and easy urls for test - allows me to do /rem/last on my mobile devices
  app.get('/:name/last(\-:n)?/:quiet(quiet)?', tag('keepLatest'), binHandler.getLatestForUser, spike.getStream, binHandler.getBinPreview);
  app.get('/:name/last(\-:n)?/edit', binHandler.getLatestForUser, binHandler.getBin);
  app.get('/:name/last(\-:n)?/watch', binHandler.getLatestForUser, binHandler.live, binHandler.getBin);

  // Edit
  app.get('/:bin/:rev?/edit', binHandler.getBin);
  app.get('/:bin/:rev?/watch', tag('live'), binHandler.getBin);
  app.get('/:bin/:rev?/embed', tag('embed'), binHandler.getBin);

  app.post('/:bin/:rev?/report', binHandler.report);

  // Save
  app.post('/save', binHandler.createBin);

  // Use this handler to check for a user creating/claiming their own bin url.
  // We use :url here to prevent loadBin() being called and returning a not
  // found error.
  app.post('/:url/save', binHandler.claimBin);

  // If the above route fails then it's either a clone or a revision. Which
  // the handler can check in the post body.
  app.post('/:bin/:rev?/save', binHandler.createRevisionOrClone);
  app.post('/:bin/:rev?/reload', binHandler.reload);

  // Private
  app.post('/:bin/:rev?/private', binHandler.setBinAsPrivate);
  app.post('/:bin/:rev?/public', binHandler.setBinAsPublic);

  // Archive
  app.post('/:bin/:rev/archive', binHandler.archiveBin.bind(null, true));
  // Unarchive
  app.post('/:bin/:rev/unarchive', binHandler.archiveBin.bind(null, false));

  // Download
  app.get('/:bin/:rev?/download', binHandler.downloadBin);

  // Source
  app.get('/:bin/:rev?/source', binHandler.getBinSource);
  app.get('/:bin/:rev?.:format(js|json|css|html|md|markdown|stylus|less|coffee|jade)', binHandler.getBinSourceFile);
  app.get('/:bin/:rev?/:format(js)', function (req, res) {
    // Redirect legacy /js suffix to the new .js extension.
    res.redirect(301, req.path.replace(/\/js$/, '.js'));
  });

  // Log
  app.get('/:bin/:rev/log', spike.getLog);
  app.post('/:bin/:rev/log', spike.postLog);

  // Preview
  app.get('/:bin/:quiet(quiet)?', spike.getStream, binHandler.getBinPreview);
  app.get('/:bin/:rev?/:quiet(quiet)?', spike.getStream, binHandler.getBinPreview);

  // Handle failed auth requests.
  app.use(sessionHandler.githubCallbackWithError);

  // Catch all
  app.use(errorHandler.notFound);

  // Error handler.
  app.use(errorHandler.httpError);

  // Final connect error handler when in development.
  app.configure('development', function () {
    app.use(express.errorHandler({showStack: true, dumpExceptions: true}));
  });

  // Final connect error handler when in development.
  app.configure('production', function () {
    app.use(errorHandler.uncaughtError);
  });
};
<commit_msg>Removing /pro handler<commit_after>var express  = require('express'),
    handlers = require('./handlers'),
    models   = require('./models'),
    helpers  = require('./helpers'),
    errors   = require('./errors'),
    spike    = require('./spike'),
    scripts  = require('../scripts.json');

function tag(label) {
  return function (req, res, next) {
    req[label] = true;
    next();
  };
}

module.exports = function (app) {
  // A sandbox object to contain some specific objects that are commonly used by
  // handlers. In future it would be ideal that each handler only receives the
  // objects that it requires.
  var sandbox = {
    store:   app.store,
    models:  models,
    mailer:  app.mailer,
    helpers: helpers.createHelpers(app)
  }, binHandler, sessionHandler, errorHandler;

  // Create handlers for accepting incoming requests.
  binHandler = new handlers.BinHandler(sandbox);
  sessionHandler = new handlers.SessionHandler(sandbox);
  errorHandler = new handlers.ErrorHandler(sandbox);

  // Special redirects (to external sources)
  app.get(['/video', '/videos', '/tutorials'], function (req, res) {
    res.redirect('http://www.youtube.com/playlist?list=PLXmT1r4krsTooRDWOrIu23P3SEZ3luIUq');
  });

  app.get('/about', function (req, res) {
    res.redirect('https://github.com/remy/jsbin/blob/master/README.markdown');
  });

  app.get(['/issues', '/bugs'], function (req, res) {
    res.redirect('https://github.com/remy/jsbin/issues/');
  });

  // Handler Events

  binHandler.on('updated', spike.ping.bind(spike));
  binHandler.on('reload', spike.reload.bind(spike));
  binHandler.on('latest-for-user', spike.updateUserSpikes.bind(spike));
  binHandler.on('new-revision', spike.bumpRevision.bind(spike));

  binHandler.on('render-scripts', spike.appendScripts.bind(spike, app.settings.version));

  // Load the bin from the store when encountered in the url. Also handles the
  // "latest" url action.
  app.param('bin', binHandler.loadBin, binHandler.checkPrivate);
  app.param('rev', binHandler.loadBinRevision);
  app.param('name', sessionHandler.loadUser);

  // Set up the routes.
  app.get('/', binHandler.getDefault);
  app.get('/gist/*', binHandler.getDefault);
  app.post('/', binHandler.getFromPost);

  // Runner
  app.get('/runner', function (req, res) {
    res.render('runner', {
      scripts: app.get('is_production') ? false : scripts.runner,
      static: sandbox.helpers.urlForStatic()
    });
  });

  app.get('/api/:bin/:rev?', binHandler.apiGetBin);
  app.post('/api/save', binHandler.apiCreateBin);
  app.post('/api/:bin/save', binHandler.apiCreateRevision);

  // Login/Create account.
  app.post('/sethome', sessionHandler.routeSetHome);
  app.post('/logout', sessionHandler.logoutUser);
  app.post('/forgot', sessionHandler.forgotPassword);
  app.get('/forgot', sessionHandler.requestToken);
  app.get('/reset', sessionHandler.resetPassword);

  // GitHub auth
  app.get('/auth/github', sessionHandler.github);
  app.get('/auth/github/callback', sessionHandler.githubPassportCallback, sessionHandler.githubCallback);

  // List
  app.get('/list/:user', binHandler.getUserBins);
  app.get('/list',       binHandler.getUserBins);
  app.get('/show/:user', binHandler.getUserBins);
  app.get('/user/:user', binHandler.getUserBins);

  // Latest
  app.get('/:bin/latest((.|\/):format)?', binHandler.redirectToLatest);
  app.get('/:bin/latest/edit', binHandler.redirectToLatest);

  // Quick and easy urls for test - allows me to do /rem/last on my mobile devices
  app.get('/:name/last(\-:n)?/:quiet(quiet)?', tag('keepLatest'), binHandler.getLatestForUser, spike.getStream, binHandler.getBinPreview);
  app.get('/:name/last(\-:n)?/edit', binHandler.getLatestForUser, binHandler.getBin);
  app.get('/:name/last(\-:n)?/watch', binHandler.getLatestForUser, binHandler.live, binHandler.getBin);

  // Edit
  app.get('/:bin/:rev?/edit', binHandler.getBin);
  app.get('/:bin/:rev?/watch', tag('live'), binHandler.getBin);
  app.get('/:bin/:rev?/embed', tag('embed'), binHandler.getBin);

  app.post('/:bin/:rev?/report', binHandler.report);

  // Save
  app.post('/save', binHandler.createBin);

  // Use this handler to check for a user creating/claiming their own bin url.
  // We use :url here to prevent loadBin() being called and returning a not
  // found error.
  app.post('/:url/save', binHandler.claimBin);

  // If the above route fails then it's either a clone or a revision. Which
  // the handler can check in the post body.
  app.post('/:bin/:rev?/save', binHandler.createRevisionOrClone);
  app.post('/:bin/:rev?/reload', binHandler.reload);

  // Private
  app.post('/:bin/:rev?/private', binHandler.setBinAsPrivate);
  app.post('/:bin/:rev?/public', binHandler.setBinAsPublic);

  // Archive
  app.post('/:bin/:rev/archive', binHandler.archiveBin.bind(null, true));
  // Unarchive
  app.post('/:bin/:rev/unarchive', binHandler.archiveBin.bind(null, false));

  // Download
  app.get('/:bin/:rev?/download', binHandler.downloadBin);

  // Source
  app.get('/:bin/:rev?/source', binHandler.getBinSource);
  app.get('/:bin/:rev?.:format(js|json|css|html|md|markdown|stylus|less|coffee|jade)', binHandler.getBinSourceFile);
  app.get('/:bin/:rev?/:format(js)', function (req, res) {
    // Redirect legacy /js suffix to the new .js extension.
    res.redirect(301, req.path.replace(/\/js$/, '.js'));
  });

  // Log
  app.get('/:bin/:rev/log', spike.getLog);
  app.post('/:bin/:rev/log', spike.postLog);

  // Preview
  app.get('/:bin/:quiet(quiet)?', spike.getStream, binHandler.getBinPreview);
  app.get('/:bin/:rev?/:quiet(quiet)?', spike.getStream, binHandler.getBinPreview);

  // Handle failed auth requests.
  app.use(sessionHandler.githubCallbackWithError);

  // Catch all
  app.use(errorHandler.notFound);

  // Error handler.
  app.use(errorHandler.httpError);

  // Final connect error handler when in development.
  app.configure('development', function () {
    app.use(express.errorHandler({showStack: true, dumpExceptions: true}));
  });

  // Final connect error handler when in development.
  app.configure('production', function () {
    app.use(errorHandler.uncaughtError);
  });
};
<|endoftext|>