<commit_before>/**
 * Copyright 2013, 2016 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/

module.exports = function(RED) {
	"use strict";
	var bodyParser = require("body-parser");
	var cookieParser = require("cookie-parser");
	var getBody = require('raw-body');
	var cors = require('cors');
	var jsonParser = bodyParser.json();
	var urlencParser = bodyParser.urlencoded({
		extended : true
	});
	var onHeaders = require('on-headers');
	var typer = require('media-typer');
	var isUtf8 = require('is-utf8');

	function rawBodyParser(req, res, next) {
		if (req._body) {
			return next();
		}
		req.body = "";
		req._body = true;

		var isText = true;
		var checkUTF = false;

		if (req.headers['content-type']) {
			var parsedType = typer.parse(req.headers['content-type']);
			if (parsedType.type === "text") {
				isText = true;
			} else if (parsedType.subtype === "xml" || parsedType.suffix === "xml") {
				isText = true;
			} else if (parsedType.type !== "application") {
				isText = false;
			} else if (parsedType.subtype !== "octet-stream") {
				checkUTF = true;
			}
		}

		getBody(req, {
			length : req.headers['content-length'],
			encoding : isText ? "utf8" : null
		}, function(err, buf) {
			if (err) {
				return next(err);
			}
			if (!isText && checkUTF && isUtf8(buf)) {
				buf = buf.toString();
			}

			req.body = buf;
			next();
		});
	}

	var corsSetup = false;

	function createRequestWrapper(node, req) {
		// This misses a bunch of properties (eg headers). Before we use this function
		// need to ensure it captures everything documented by Express and HTTP modules.
		var wrapper = {
			_req : req
		};
		var toWrap = ["param", "get", "is", "acceptsCharset", "acceptsLanguage", "app", "baseUrl", "body", "cookies", "fresh", "hostname", "ip", "ips", "originalUrl", "params", "path", "protocol", "query", "route", "secure", "signedCookies", "stale", "subdomains", "xhr", "socket" // TODO: tidy this up
		];
		toWrap.forEach(function(f) {
			if ( typeof req[f] === "function") {
				wrapper[f] = function() {
					node.warn(RED._("httpin.errors.deprecated-call", {
						method : "msg.req." + f
					}));
					var result = req[f].apply(req, arguments);
					if (result === req) {
						return wrapper;
					} else {
						return result;
					}
				};
			} else {
				wrapper[f] = req[f];
			}
		});

		return wrapper;
	}

	function createResponseWrapper(node, res) {
		var wrapper = {
			_res : res
		};
		var toWrap = ["append", "attachment", "cookie", "clearCookie", "download", "end", "format", "get", "json", "jsonp", "links", "location", "redirect", "render", "send", "sendfile", "sendFile", "sendStatus", "set", "status", "type", "vary"];
		toWrap.forEach(function(f) {
			wrapper[f] = function() {
				node.warn(RED._("httpin.errors.deprecated-call", {
					method : "msg.res." + f
				}));
				var result = res[f].apply(res, arguments);
				if (result === res) {
					return wrapper;
				} else {
					return result;
				}
			};
		});
		return wrapper;
	}

	var corsHandler = function(req, res, next) {
		next();
	};

	if (RED.settings.httpNodeCors) {
		corsHandler = cors(RED.settings.httpNodeCors);
		RED.httpNode.options("*", corsHandler);
	}

	function HTTPAuth0(n) {
		RED.nodes.createNode(this, n);
		this.name = n.name;
		this.role = n.role;
		this.group = n.group;
		this.auth0 = n.auth0;
		this.cookieMaxAge = Number(n.maxage || 900000);
		this.Auth0 = RED.nodes.getNode(this.auth0);
		if (RED.settings.httpNodeRoot !== false) {

			if (!n.url) {
				this.warn(RED._("httpin.errors.missing-path"));
				return;
			}
			this.url = n.url;
			this.method = n.method;

			var node = this;

			this.errorHandler = function(err, req, res, next) {
				node.warn(err);
				res.sendStatus(500);
			};

			this.callback = function(req, res) {
				var msgid = RED.util.generateId();
				res._msgid = msgid;
				if (node.method.match(/^(post|delete|put|options|patch)$/)) {
					node.send({
						_msgid : msgid,
						req : req,
						res : createResponseWrapper(node, res),
						payload : req.body
					});
				} else if (node.method == "get") {
					node.send({
						_msgid : msgid,
						req : req,
						res : createResponseWrapper(node, res),
						payload : req.query
					});
				} else {
					node.send({
						_msgid : msgid,
						req : req,
						res : createResponseWrapper(node, res)
					});
				}
			};

			function parseBearerToken(req) {
				var auth;
				if (!req.headers || !( auth = req.headers.authorization)) {
					return null;
				}
				var parts = auth.split(' ');
				if (2 > parts.length)
					return null;
				var schema = parts.shift().toLowerCase();
				var token = parts.join(' ');
				if ('bearer' != schema)
					return null;
				return token;
			}

			var httpMiddleware = function(req, res, next) {
				var request = require('request');
				var jwt = require('jsonwebtoken');
				var jwtToken = req.cookies['id_token'] || parseBearerToken(req);
				var tokenProviderUrl = node.Auth0.getTokenAddress();
				var auth0TokenSecret = process.env.AUTH0_CLIENT_SECRET || node.Auth0.getTokenSecret();

				if (!req.cookies['id_token'] && jwtToken) {
					node.log("httpMiddleware: SET COOKIE " + jwtToken.substring(0, 10));
					if (jwtToken === "null") {
						res.clearCookie('id_token');
					} else {
						res.cookie('id_token', jwtToken, { maxAge: node.cookieMaxAge, httpOnly: true });
					}
				}

				function requestTokenInfo(req, res, next) {
					node.log("httpMiddleware:" + tokenProviderUrl);
					var options = {
						uri : tokenProviderUrl,
						method : 'POST',
						json : {
							id_token : jwtToken
						}
					};
					request(options, function(error, response, body) {
						if (!error && response.statusCode == 200) {
							req.tokeninfo = body || { user_id: "auth0|anonymous" };
							req.tokeninfo.authorized = true;
							req.tokeninfo.email = req.tokeninfo.email || req.tokeninfo.user_id.replace('|', '@');
							if (node.role && req.tokeninfo && req.tokeninfo.roles && req.tokeninfo.roles.indexOf(node.role) == -1) {
								req.tokeninfo.authorized = false;
							}
							if (node.group && req.tokeninfo && req.tokeninfo.groups && req.tokeninfo.groups.indexOf(node.group) == -1) {
								req.tokeninfo.authorized = false;
							}
							if (req.tokeninfo.authorized) {
								if (!req.cookies['email']) {
									res.cookie('email', req.tokeninfo.email, { maxAge: parseInt(node.cookieMaxAge) || 900000, httpOnly: true });
									res.cookie('roles', req.tokeninfo.roles, { maxAge: parseInt(node.cookieMaxAge) || 900000, httpOnly: true });
									res.cookie('groups', req.tokeninfo.groups, { maxAge: parseInt(node.cookieMaxAge) || 900000, httpOnly: true });
								}
								next();
							} else {
								res.setHeader('Content-Type', 'application/json');
								res.status(403).end(JSON.stringify({
									required : {
										role : node.role,
										group : node.group,
									},
									message : "Require ROLE:'" + node.role + "' and GROUP:'" + node.group + "' to access the requested resource."
								}));
							}
						} else {
							res.setHeader('Content-Type', 'application/json');
							res.status(401).end(JSON.stringify({
								message : "The JWT token '" + options.json.id_token + "' is invalid."
							}));
						}
					});
				}
				if (auth0TokenSecret) {
					jwt.verify(jwtToken, new Buffer(auth0TokenSecret, 'base64'), function(tokenError, decoded) {
						if (!tokenError) {
							node.log("httpMiddleware:" + decoded.aud);
							if (!req.cookies['email']) {
								tokenProviderUrl = decoded.iss + "tokeninfo";
								requestTokenInfo(req, res, next);
							} else {
								req.tokeninfo = {
									user_id: decoded.sub,
									email: req.cookies['email'],
									roles: req.cookies['roles'],
									groups: req.cookies['groups'],
									client_id: decoded.aud,
									user_info: decoded.iss + "tokeninfo",
									jwt_token: jwtToken
								};
								next();
							}
						} else {
							node.log("httpMiddleware:" + tokenError);
							res.setHeader('Content-Type', 'application/json');
							res.status(401).end(JSON.stringify({
								message : tokenError
							}));
						}
					});
				} else {
					tokenProviderUrl = node.Auth0.getTokenAddress();
					requestTokenInfo(req, res, next);
				}
			};

			if (RED.settings.httpNodeMiddleware) {
				if ( typeof RED.settings.httpNodeMiddleware === "function") {
					httpMiddleware = RED.settings.httpNodeMiddleware;
				}
			}

			var metricsHandler = function(req, res, next) {
				next();
			};

			if (this.metric()) {
				metricsHandler = function(req, res, next) {
					var startAt = process.hrtime();
					onHeaders(res, function() {
						if (res._msgid) {
							var diff = process.hrtime(startAt);
							var ms = diff[0] * 1e3 + diff[1] * 1e-6;
							var metricResponseTime = ms.toFixed(3);
							var metricContentLength = res._headers["content-length"];
							//assuming that _id has been set for res._metrics in HttpOut node!
							node.metric("response.time.millis", {
								_msgid : res._msgid
							}, metricResponseTime);
							node.metric("response.content-length.bytes", {
								_msgid : res._msgid
							}, metricContentLength);
						}
					});
					next();
				};
			}

			if (this.method == "get") {
				RED.httpNode.get(this.url, cookieParser(), httpMiddleware, corsHandler, metricsHandler, this.callback, this.errorHandler);
			} else if (this.method == "post") {
				RED.httpNode.post(this.url, cookieParser(), httpMiddleware, corsHandler, metricsHandler, jsonParser, urlencParser, rawBodyParser, this.callback, this.errorHandler);
			} else if (this.method == "put") {
				RED.httpNode.put(this.url, cookieParser(), httpMiddleware, corsHandler, metricsHandler, jsonParser, urlencParser, rawBodyParser, this.callback, this.errorHandler);
			} else if (this.method == "patch") {
				RED.httpNode.patch(this.url, cookieParser(), httpMiddleware, corsHandler, metricsHandler, jsonParser, urlencParser, rawBodyParser, this.callback, this.errorHandler);
			} else if (this.method == "delete") {
				RED.httpNode.delete(this.url, cookieParser(), httpMiddleware, corsHandler, metricsHandler, jsonParser, urlencParser, rawBodyParser, this.callback, this.errorHandler);
			}

			this.on("close", function() {
				var node = this;
				RED.httpNode._router.stack.forEach(function(route, i, routes) {
					if (route.route && route.route.path === node.url && route.route.methods[node.method]) {
						routes.splice(i, 1);
					}
				});
			});
		} else {
			this.warn(RED._("httpin.errors.not-created"));
		}
	}

	RED.nodes.registerType("http-auth0", HTTPAuth0);

	function Auth0ServerSetup(n) {
		RED.nodes.createNode(this, n);
		this.connected = false;
		this.connecting = false;
		this.usecount = 0;
		// Config node state
		this.name = n.name;
		this.address = n.address;
		this.secret = n.secret;

		var node = this;
		this.register = function() {
			node.usecount += 1;
		};

		this.deregister = function() {
			node.usecount -= 1;
			if (node.usecount == 0) {
			}
		};
		this.getTokenAddress = function() {
			return node.address;
		};
		this.getTokenSecret = function() {
			return node.secret;
		};

		this.on('close', function(closecomplete) {
			if (this.connected) {
				this.on('disconnected', function() {
					closecomplete();
				});
				node.queue.close().then(function() {
					node.log(RED._('closed'));
				});
			} else {
				closecomplete();
			}
		});
	}

	RED.nodes.registerType("auth0-server", Auth0ServerSetup);
};
<commit_msg>Autoset maxAge<commit_after>/**
 * Copyright 2013, 2016 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/

module.exports = function(RED) {
	"use strict";
	var bodyParser = require("body-parser");
	var cookieParser = require("cookie-parser");
	var getBody = require('raw-body');
	var cors = require('cors');
	var jsonParser = bodyParser.json();
	var urlencParser = bodyParser.urlencoded({
		extended : true
	});
	var onHeaders = require('on-headers');
	var typer = require('media-typer');
	var isUtf8 = require('is-utf8');

	function rawBodyParser(req, res, next) {
		if (req._body) {
			return next();
		}
		req.body = "";
		req._body = true;

		var isText = true;
		var checkUTF = false;

		if (req.headers['content-type']) {
			var parsedType = typer.parse(req.headers['content-type']);
			if (parsedType.type === "text") {
				isText = true;
			} else if (parsedType.subtype === "xml" || parsedType.suffix === "xml") {
				isText = true;
			} else if (parsedType.type !== "application") {
				isText = false;
			} else if (parsedType.subtype !== "octet-stream") {
				checkUTF = true;
			}
		}

		getBody(req, {
			length : req.headers['content-length'],
			encoding : isText ? "utf8" : null
		}, function(err, buf) {
			if (err) {
				return next(err);
			}
			if (!isText && checkUTF && isUtf8(buf)) {
				buf = buf.toString();
			}

			req.body = buf;
			next();
		});
	}

	var corsSetup = false;

	function createRequestWrapper(node, req) {
		// This misses a bunch of properties (eg headers). Before we use this function
		// need to ensure it captures everything documented by Express and HTTP modules.
		var wrapper = {
			_req : req
		};
		var toWrap = ["param", "get", "is", "acceptsCharset", "acceptsLanguage", "app", "baseUrl", "body", "cookies", "fresh", "hostname", "ip", "ips", "originalUrl", "params", "path", "protocol", "query", "route", "secure", "signedCookies", "stale", "subdomains", "xhr", "socket" // TODO: tidy this up
		];
		toWrap.forEach(function(f) {
			if ( typeof req[f] === "function") {
				wrapper[f] = function() {
					node.warn(RED._("httpin.errors.deprecated-call", {
						method : "msg.req." + f
					}));
					var result = req[f].apply(req, arguments);
					if (result === req) {
						return wrapper;
					} else {
						return result;
					}
				};
			} else {
				wrapper[f] = req[f];
			}
		});

		return wrapper;
	}

	function createResponseWrapper(node, res) {
		var wrapper = {
			_res : res
		};
		var toWrap = ["append", "attachment", "cookie", "clearCookie", "download", "end", "format", "get", "json", "jsonp", "links", "location", "redirect", "render", "send", "sendfile", "sendFile", "sendStatus", "set", "status", "type", "vary"];
		toWrap.forEach(function(f) {
			wrapper[f] = function() {
				node.warn(RED._("httpin.errors.deprecated-call", {
					method : "msg.res." + f
				}));
				var result = res[f].apply(res, arguments);
				if (result === res) {
					return wrapper;
				} else {
					return result;
				}
			};
		});
		return wrapper;
	}

	var corsHandler = function(req, res, next) {
		next();
	};

	if (RED.settings.httpNodeCors) {
		corsHandler = cors(RED.settings.httpNodeCors);
		RED.httpNode.options("*", corsHandler);
	}

	function HTTPAuth0(n) {
		RED.nodes.createNode(this, n);
		this.name = n.name;
		this.role = n.role;
		this.group = n.group;
		this.auth0 = n.auth0;
		this.cookieMaxAge = Number(n.maxage || 900000);
		this.Auth0 = RED.nodes.getNode(this.auth0);
		if (RED.settings.httpNodeRoot !== false) {

			if (!n.url) {
				this.warn(RED._("httpin.errors.missing-path"));
				return;
			}
			this.url = n.url;
			this.method = n.method;

			var node = this;

			this.errorHandler = function(err, req, res, next) {
				node.warn(err);
				res.sendStatus(500);
			};

			this.callback = function(req, res) {
				var msgid = RED.util.generateId();
				res._msgid = msgid;
				if (node.method.match(/^(post|delete|put|options|patch)$/)) {
					node.send({
						_msgid : msgid,
						req : req,
						res : createResponseWrapper(node, res),
						payload : req.body
					});
				} else if (node.method == "get") {
					node.send({
						_msgid : msgid,
						req : req,
						res : createResponseWrapper(node, res),
						payload : req.query
					});
				} else {
					node.send({
						_msgid : msgid,
						req : req,
						res : createResponseWrapper(node, res)
					});
				}
			};

			function parseBearerToken(req) {
				var auth;
				if (!req.headers || !( auth = req.headers.authorization)) {
					return null;
				}
				var parts = auth.split(' ');
				if (2 > parts.length)
					return null;
				var schema = parts.shift().toLowerCase();
				var token = parts.join(' ');
				if ('bearer' != schema)
					return null;
				return token;
			}

			var httpMiddleware = function(req, res, next) {
				var request = require('request');
				var jwt = require('jsonwebtoken');
				var jwtToken = req.cookies['id_token'] || parseBearerToken(req);
				var tokenProviderUrl = node.Auth0.getTokenAddress();
				var auth0TokenSecret = process.env.AUTH0_CLIENT_SECRET || node.Auth0.getTokenSecret();

				if (!req.cookies['id_token'] && jwtToken) {
					node.log("httpMiddleware: SET COOKIE " + jwtToken.substring(0, 10));
					if (jwtToken === "null") {
						res.clearCookie('id_token');
					} else {
						res.cookie('id_token', jwtToken, { maxAge: node.cookieMaxAge, httpOnly: true });
					}
				}

				function requestTokenInfo(req, res, next, maxAge) {
					node.log("httpMiddleware:" + tokenProviderUrl);
					var options = {
						uri : tokenProviderUrl,
						method : 'POST',
						json : {
							id_token : jwtToken
						}
					};
					request(options, function(error, response, body) {
						if (!error && response.statusCode == 200) {
							req.tokeninfo = body || { user_id: "auth0|anonymous" };
							req.tokeninfo.authorized = true;
							req.tokeninfo.email = req.tokeninfo.email || req.tokeninfo.user_id.replace('|', '@');
							if (node.role && req.tokeninfo && req.tokeninfo.roles && req.tokeninfo.roles.indexOf(node.role) == -1) {
								req.tokeninfo.authorized = false;
							}
							if (node.group && req.tokeninfo && req.tokeninfo.groups && req.tokeninfo.groups.indexOf(node.group) == -1) {
								req.tokeninfo.authorized = false;
							}
							if (req.tokeninfo.authorized) {
								if (!req.cookies['email']) {
									res.cookie('email', req.tokeninfo.email, { maxAge: maxAge || parseInt(node.cookieMaxAge) || 900000, httpOnly: true });
									res.cookie('roles', req.tokeninfo.roles, { maxAge: maxAge || parseInt(node.cookieMaxAge) || 900000, httpOnly: true });
									res.cookie('groups', req.tokeninfo.groups, { maxAge: maxAge || parseInt(node.cookieMaxAge) || 900000, httpOnly: true });
								}
								next();
							} else {
								res.setHeader('Content-Type', 'application/json');
								res.status(403).end(JSON.stringify({
									required : {
										role : node.role,
										group : node.group,
									},
									message : "Require ROLE:'" + node.role + "' and GROUP:'" + node.group + "' to access the requested resource."
								}));
							}
						} else {
							res.setHeader('Content-Type', 'application/json');
							res.status(401).end(JSON.stringify({
								message : "The JWT token '" + options.json.id_token + "' is invalid."
							}));
						}
					});
				}
				if (auth0TokenSecret) {
					jwt.verify(jwtToken, new Buffer(auth0TokenSecret, 'base64'), function(tokenError, decoded) {
						if (!tokenError) {
							node.log("httpMiddleware:" + decoded.aud);
							if (!req.cookies['email']) {
								tokenProviderUrl = decoded.iss + "tokeninfo";
								requestTokenInfo(req, res, next, parseInt(decoded.exp - new Date().getTime()/1000));
							} else {
								req.tokeninfo = {
									user_id: decoded.sub,
									email: req.cookies['email'],
									roles: req.cookies['roles'],
									groups: req.cookies['groups'],
									client_id: decoded.aud,
									user_info: decoded.iss + "tokeninfo",
									jwt_token: jwtToken
								};
								next();
							}
						} else {
							node.log("httpMiddleware:" + tokenError);
							res.setHeader('Content-Type', 'application/json');
							res.status(401).end(JSON.stringify({
								message : tokenError
							}));
						}
					});
				} else {
					tokenProviderUrl = node.Auth0.getTokenAddress();
					requestTokenInfo(req, res, next);
				}
			};

			if (RED.settings.httpNodeMiddleware) {
				if ( typeof RED.settings.httpNodeMiddleware === "function") {
					httpMiddleware = RED.settings.httpNodeMiddleware;
				}
			}

			var metricsHandler = function(req, res, next) {
				next();
			};

			if (this.metric()) {
				metricsHandler = function(req, res, next) {
					var startAt = process.hrtime();
					onHeaders(res, function() {
						if (res._msgid) {
							var diff = process.hrtime(startAt);
							var ms = diff[0] * 1e3 + diff[1] * 1e-6;
							var metricResponseTime = ms.toFixed(3);
							var metricContentLength = res._headers["content-length"];
							//assuming that _id has been set for res._metrics in HttpOut node!
							node.metric("response.time.millis", {
								_msgid : res._msgid
							}, metricResponseTime);
							node.metric("response.content-length.bytes", {
								_msgid : res._msgid
							}, metricContentLength);
						}
					});
					next();
				};
			}

			if (this.method == "get") {
				RED.httpNode.get(this.url, cookieParser(), httpMiddleware, corsHandler, metricsHandler, this.callback, this.errorHandler);
			} else if (this.method == "post") {
				RED.httpNode.post(this.url, cookieParser(), httpMiddleware, corsHandler, metricsHandler, jsonParser, urlencParser, rawBodyParser, this.callback, this.errorHandler);
			} else if (this.method == "put") {
				RED.httpNode.put(this.url, cookieParser(), httpMiddleware, corsHandler, metricsHandler, jsonParser, urlencParser, rawBodyParser, this.callback, this.errorHandler);
			} else if (this.method == "patch") {
				RED.httpNode.patch(this.url, cookieParser(), httpMiddleware, corsHandler, metricsHandler, jsonParser, urlencParser, rawBodyParser, this.callback, this.errorHandler);
			} else if (this.method == "delete") {
				RED.httpNode.delete(this.url, cookieParser(), httpMiddleware, corsHandler, metricsHandler, jsonParser, urlencParser, rawBodyParser, this.callback, this.errorHandler);
			}

			this.on("close", function() {
				var node = this;
				RED.httpNode._router.stack.forEach(function(route, i, routes) {
					if (route.route && route.route.path === node.url && route.route.methods[node.method]) {
						routes.splice(i, 1);
					}
				});
			});
		} else {
			this.warn(RED._("httpin.errors.not-created"));
		}
	}

	RED.nodes.registerType("http-auth0", HTTPAuth0);

	function Auth0ServerSetup(n) {
		RED.nodes.createNode(this, n);
		this.connected = false;
		this.connecting = false;
		this.usecount = 0;
		// Config node state
		this.name = n.name;
		this.address = n.address;
		this.secret = n.secret;

		var node = this;
		this.register = function() {
			node.usecount += 1;
		};

		this.deregister = function() {
			node.usecount -= 1;
			if (node.usecount == 0) {
			}
		};
		this.getTokenAddress = function() {
			return node.address;
		};
		this.getTokenSecret = function() {
			return node.secret;
		};

		this.on('close', function(closecomplete) {
			if (this.connected) {
				this.on('disconnected', function() {
					closecomplete();
				});
				node.queue.close().then(function() {
					node.log(RED._('closed'));
				});
			} else {
				closecomplete();
			}
		});
	}

	RED.nodes.registerType("auth0-server", Auth0ServerSetup);
};
<|endoftext|>


<commit_before>var http = require('http')
  , url = require('url')
  , fs = require('fs')
  , io = require('socket.io')
  , sys = require(process.binding('natives').util ? 'util' : 'sys')
  , server;

//node basic stuff
server = http.createServer(function(req, res){
  var path = url.parse(req.url).pathname;
  switch (path){
    case '/':
      res.writeHead(200, {'Content-Type': 'text/html'});
      res.write('
Welcome. Try the chat example.
');
      res.end();
      break;

    case '/json.js':
    case '/jquery.js':
    case '/knockout-latest.js':
    case '/knockout.live.plugin.js':
    case '/chat.html':
      fs.readFile(__dirname + path, function(err, data){
        if (err) return send404(res);
        res.writeHead(200, {'Content-Type': path == 'json.js' ? 'text/javascript' : 'text/html'})
        res.write(data, 'utf8');
        res.end();
      });
      break;

    default: send404(res);
  }
}),

send404 = function(res){
  res.writeHead(404);
  res.write('404');
  res.end();
};

server.listen(8080);

var io = io.listen(server)
  , clients = []
  , syncObjs = {knockoutObjects: {}};
//Be sure to send the message to everyone except the sender, otherwise we'll see recursion hell
io.sockets.on('connection', function(client){
  clients.push(client);
  // send all objects temporarily stored
  client.emit("message",syncObjs);

  client.on('message', function(message) {
    // append sync values to temporary storage
    // here you could block people trying to manually update via socket.send live readonly observables with named IDs
    syncObjs["knockoutObjects"][message.id] = message.value;
    for(var i=0,j=clients.length; i < j;i++ ) {
        if(clients[i].id !== client.id)
            clients[i].emit("message",message);
    }
  });

  client.on('disconnect', function(){
    for(var i=0,j=clients.length; i < j;i++ ) {
        if(!!clients[i]["id"])
            if(clients[i].id == client.id)
                clients.splice(i,1);
    }
  });
});

<commit_msg>new server.js<commit_after>var app     = require('express')(),
  http    = require('http').Server(app),
  io      = require('socket.io')(http, {serveClient: false} ),
  clients   = [],
  syncObjs  = {knockoutObjects: {}},
  port    = 4000;

http.listen( port, function(){
  console.log('listening on *:'+port);
});

io.on('connection', function(socket) {

  clients.push(socket);

  socket.emit("message",syncObjs);

  socket.on('message', function(message) {
    // append sync values to temporary storage
    // here you could block people trying to manually update via socket.send live readonly observables with named IDs
    syncObjs['knockoutObjects'][message.id] = message.value;
    for(var i=0,j=clients.length; i < j;i++ ) {
        if(clients[i].id !== socket.id)
            clients[i].emit("message",message);
    }
  });

  socket.on('disconnect', function(){
      for(var i=0,j=clients.length; i < j;i++ ) {
          if(!!clients[i]['id'])
              if(clients[i].id == socket.id)
                  clients.splice(i,1);
      }
        console.log(socket.id,'disconnected ------------- ');
        console.log(clients);
  });

});
<|endoftext|>


<commit_before>
//Core node modules
var express = require ('express');
var path = require('path');
var logger = require('morgan');
var bodyParser = require('body-parser');

//3rd party npm libraries
var swig = require('swig'):
var React = require('react');
var Router = require('react-router');
var routes = require('./app/routes');
var async = require('async');
var request = require('request');
var _ = require('underscore');

var mongoose = require('mongoose');
var Character = require('./models/character');
var config = require('./config');

mongoose.connect(config.database);
mongoose.connection.on('error', function(){
	console.info("Error, could not connect ot MongoDB. Run mongod please.");
})

var app = express();

//Express middleware
app.set('port', process.env.PORT || 3000);
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:false}));
app.use(express.static(path.join(__dirname, 'public')));

//API middlewares
app.post('/api/characters', function(req,res,next){
	var gender = req.body.gender;
	var characterName = req.body.name;
	var characterIdLookupUrl = 'https://api.eveonline.com/eve/CharacterID.xml.aspx?names='+characterName;

	var parser = new xml2js.Parser();

	async.waterfall([
		function(callback){
			request.get(characterIdLookupUrl, function(err,request,xml){

				if(err) return next(err);
				parser.parseString(xml,function(err,parsedXml){

					try{
						var characterId = parsedXml.eveapi.result[0].rowset[0].row[0].$.characterID;

						Character.findeOne({characterId: characterId}, function(err, character){
							if(err) return next(err);

							if(character){
								return res.status(409).send({message:character.name + ' is already in the database'});
							}
							callback(err, characterId);
						});
					}catch(e){
						return res.status(400).send({message:"XML parse error."});
					}
				});
			});

		},

		function(characterId){
			var characterInfoUrl = 'https://api.eveonline.com/eve/CharacterInfo.xml.aspx?characterID='+characterId;

			request.get({url:characterInfoUrl},funciton(err,request,xml){
				if(err) return next(err);
				parser.parseString(xml, function(err, parsedXml){
					if(err) return res.send(err);
					try{
						var name = parsedXml.eveapi.result[0].characterName[0];
						var race = parsedXml.eveapi.result[0].race[0];
						var bloodline = parsedXml.eveapi.result[0].bloodline[0];

						var character = new Character({
							characterId: characterId,
							name : name,
							race : race,
							bloodline : bloodline,
							gender : gender,
							random: [Math.random(), 0]
						});

						character.save(function(err){
							if(err) return next(err);
							res.send({message: characterName + ' has been added successfully.'});

						});

					}catch(e){
						res.status(404).send({message: characterName + " is not a registered character."});
					}
				});
			});
		}

		]);
});

//API routes

//returns two random  characters in the home component
app.get('/api/characters', function(req,res,next){
	var choices = ['Female', 'Male'];
	var randomGender = _.sample(choices);

	Character.find({random: {$near:[Math.random(),0]}})
	.where('voted', false)
	.where('gender', randomGender)
	.limit(2)
	.exec(function(err,characters){
		if(err) return next(err);

		if(characters.length === 2){
			return res.send(characters);
		}

		var oppositeGender = _.first(_.without(choices, randomGender));

		Character
		.find({random: {$near: [Math.random(),0]}})
		.where('voted', false)
		.where('gender', oppositeGender)
		.limit(2)
		.exec(function(err,characters){
			if(err) return next(err);

			if(characters.length === 2){
				return res.send(characters);
			}

			Character.update({}, {$set:{voted:false]}}, {multi:true}, function(err){
				if(err) return next(err);
				res.send([]);
			}
		});
		});
	});

//Update winning and losing count for both chars

app.put('/api/characters', function(req,res,next){
	var winner = req.body.winner;
	var loser = req.body.loser;

	if(!winner || !loser){
		return res.status(400).send({message:'voting requires two characters'});
	}

	if(winner === loser){
		return res.status(400).send({message:"can not vote for same char!"});
	}

	async.parallel([
		function(callback) {
			Character.findOne({ characterId: winner }, function(err, winner) {
				callback(err, winner);
			});
		},
		function(callback) {
			Character.findOne({ characterId: loser }, function(err, loser) {
				callback(err, loser);
			});
		}
		],

		function(err, results) {
			if (err) return next(err);

			var winner = results[0];
			var loser = results[1];

			if (!winner || !loser) {
				return res.status(404).send({ message: 'One of the characters no longer exists.' });
			}

			if (winner.voted || loser.voted) {
				return res.status(200).end();
			}

			async.parallel([
				function(callback) {
					winner.wins++;
					winner.voted = true;
					winner.random = [Math.random(), 0];
					winner.save(function(err) {
						callback(err);
					});
				},
				function(callback) {
					loser.losses++;
					loser.voted = true;
					loser.random = [Math.random(), 0];
					loser.save(function(err) {
						callback(err);
					});
				}
				], function(err) {
					if (err) return next(err);
					res.status(200).end();
				});
		});
});

//React middleware
app.use(function(req,res){
	Router.run(routes, req.path, function(Handler){
		var html = React.renderToString(React.createElement(Handler));
		var page = swig.renderFile('views/index.html',{html:html});
		res.send(page);
	});
});

var server = require('http').createServer(app);
var io = require('socket.io')(server);
var onlineUsers = 0;

io.sockets.on('connection', function(socket){
	onlineUsers++;

	io.sockets.emit('onlineUsers', {onlineUsers:onlineUsers});

	socket.on('disconnect', function(){
		onlineUsers --;
		io.sockets.emit('onlineUsers', {onlineUsers:onlineUsers});
	});
});

server.listen(app.get('port', function(){
	console.log('Express server listening on port ' + app.get('port'));
});<commit_msg>api routes for stats, report, top100, bottom100<commit_after>
//Core node modules
var express = require ('express');
var path = require('path');
var logger = require('morgan');
var bodyParser = require('body-parser');

//3rd party npm libraries
var swig = require('swig'):
var React = require('react');
var Router = require('react-router');
var routes = require('./app/routes');
var async = require('async');
var request = require('request');
var _ = require('underscore');

var mongoose = require('mongoose');
var Character = require('./models/character');
var config = require('./config');

mongoose.connect(config.database);
mongoose.connection.on('error', function(){
	console.info("Error, could not connect ot MongoDB. Run mongod please.");
})

var app = express();

//Express middleware
app.set('port', process.env.PORT || 3000);
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:false}));
app.use(express.static(path.join(__dirname, 'public')));

//API middlewares
app.post('/api/characters', function(req,res,next){
	var gender = req.body.gender;
	var characterName = req.body.name;
	var characterIdLookupUrl = 'https://api.eveonline.com/eve/CharacterID.xml.aspx?names='+characterName;

	var parser = new xml2js.Parser();

	async.waterfall([
		function(callback){
			request.get(characterIdLookupUrl, function(err,request,xml){

				if(err) return next(err);
				parser.parseString(xml,function(err,parsedXml){

					try{
						var characterId = parsedXml.eveapi.result[0].rowset[0].row[0].$.characterID;

						Character.findeOne({characterId: characterId}, function(err, character){
							if(err) return next(err);

							if(character){
								return res.status(409).send({message:character.name + ' is already in the database'});
							}
							callback(err, characterId);
						});
					}catch(e){
						return res.status(400).send({message:"XML parse error."});
					}
				});
			});

		},

		function(characterId){
			var characterInfoUrl = 'https://api.eveonline.com/eve/CharacterInfo.xml.aspx?characterID='+characterId;

			request.get({url:characterInfoUrl},funciton(err,request,xml){
				if(err) return next(err);
				parser.parseString(xml, function(err, parsedXml){
					if(err) return res.send(err);
					try{
						var name = parsedXml.eveapi.result[0].characterName[0];
						var race = parsedXml.eveapi.result[0].race[0];
						var bloodline = parsedXml.eveapi.result[0].bloodline[0];

						var character = new Character({
							characterId: characterId,
							name : name,
							race : race,
							bloodline : bloodline,
							gender : gender,
							random: [Math.random(), 0]
						});

						character.save(function(err){
							if(err) return next(err);
							res.send({message: characterName + ' has been added successfully.'});

						});

					}catch(e){
						res.status(404).send({message: characterName + " is not a registered character."});
					}
				});
			});
		}

		]);
});

//API routes

//returns two random  characters in the home component
app.get('/api/characters', function(req,res,next){
	var choices = ['Female', 'Male'];
	var randomGender = _.sample(choices);

	Character.find({random: {$near:[Math.random(),0]}})
	.where('voted', false)
	.where('gender', randomGender)
	.limit(2)
	.exec(function(err,characters){
		if(err) return next(err);

		if(characters.length === 2){
			return res.send(characters);
		}

		var oppositeGender = _.first(_.without(choices, randomGender));

		Character
		.find({random: {$near: [Math.random(),0]}})
		.where('voted', false)
		.where('gender', oppositeGender)
		.limit(2)
		.exec(function(err,characters){
			if(err) return next(err);

			if(characters.length === 2){
				return res.send(characters);
			}

			Character.update({}, {$set:{voted:false]}}, {multi:true}, function(err){
				if(err) return next(err);
				res.send([]);
			}
		});
		});
	});

//Update winning and losing count for both chars

app.put('/api/characters', function(req,res,next){
	var winner = req.body.winner;
	var loser = req.body.loser;

	if(!winner || !loser){
		return res.status(400).send({message:'voting requires two characters'});
	}

	if(winner === loser){
		return res.status(400).send({message:"can not vote for same char!"});
	}

	async.parallel([
		function(callback) {
			Character.findOne({ characterId: winner }, function(err, winner) {
				callback(err, winner);
			});
		},
		function(callback) {
			Character.findOne({ characterId: loser }, function(err, loser) {
				callback(err, loser);
			});
		}
		],

		function(err, results) {
			if (err) return next(err);

			var winner = results[0];
			var loser = results[1];

			if (!winner || !loser) {
				return res.status(404).send({ message: 'One of the characters no longer exists.' });
			}

			if (winner.voted || loser.voted) {
				return res.status(200).end();
			}

			async.parallel([
				function(callback) {
					winner.wins++;
					winner.voted = true;
					winner.random = [Math.random(), 0];
					winner.save(function(err) {
						callback(err);
					});
				},
				function(callback) {
					loser.losses++;
					loser.voted = true;
					loser.random = [Math.random(), 0];
					loser.save(function(err) {
						callback(err);
					});
				}
				], function(err) {
					if (err) return next(err);
					res.status(200).end();
				});
		});
});

//returns total $ of chars
app.get('/api/characters/count', function(req,res,next){
	Character.count({}, function(err,count){
		if(err) return next(err);
		res.send({count:count});
	}
})

//look up character by name
app.get('/api/characters/search', function(req,res,next){
	var characterName = new RegExp(req.query.name, 'i');

	Character.findOne({name:characterName}, function(err,chaacter){
		if(err) return next(err);

		if(!character){
			return res.status(404).send({message: "Char not found"});
		}

		res.send(character);
	})
})

//returns character details

app.get('/api/characters/:id', function(req,res,next){
	var id = reqs.params.id;

	Character.findOne({characterId: id}, function(err,character){
		if(err) return next(err);

		if(!character){
			return res.status(404).send({message: "Char not found"});
		}

		res.send(character);
	})
})

//get top 1000 chars

app.get('/api/chracters/top', function(req,res,next){
	//this allows users to send in ambiguos params.
	var params = req.query;
	var conditions = {};

	//take params, massage them with regex and add them to conditions
	_.each(params, function(value,key){
		conditions[key] = new RegExp('^' + value + '$', 'i');
	});

	Character
	.find(conditions)
	.sort('-wins')
	.limit(100)
	.exec(function(err,characters){
		if(err) return next(err);

		characters.sort(function(a,b){
			if (a.wins / (a.wins + a.losses) < b.wins / (b.wins + b.losses)) { return 1; }
			if (a.wins / (a.wins + a.losses) > b.wins / (b.wins + b.losses)) { return -1; }
			return 0;
		});

		res.send(characters);
	});
});

//lowest 100 chars
app.get('/api/characters/shame', function(req, res, next) {
  Character
    .find()
    .sort('-losses')
    .limit(100)
    .exec(function(err, characters) {
      if (err) return next(err);
      res.send(characters);
    });
});

//allow users to report bad images
app.post('/api/report', function(req, res, next) {
  var characterId = req.body.characterId;

  Character.findOne({ characterId: characterId }, function(err, character) {
    if (err) return next(err);

    if (!character) {
      return res.status(404).send({ message: 'Character not found.' });
    }

    character.reports++;

    if (character.reports > 4) {
      character.remove();
      return res.send({ message: character.name + ' has been deleted.' });
    }

    character.save(function(err) {
      if (err) return next(err);
      res.send({ message: character.name + ' has been reported.' });
    });
  });
});

//stats!
app.get('/api/stats', function(req, res, next) {
  async.parallel([
      function(callback) {
        Character.count({}, function(err, count) {
          callback(err, count);
        });
      },
      function(callback) {
        Character.count({ race: 'Amarr' }, function(err, amarrCount) {
          callback(err, amarrCount);
        });
      },
      function(callback) {
        Character.count({ race: 'Caldari' }, function(err, caldariCount) {
          callback(err, caldariCount);
        });
      },
      function(callback) {
        Character.count({ race: 'Gallente' }, function(err, gallenteCount) {
          callback(err, gallenteCount);
        });
      },
      function(callback) {
        Character.count({ race: 'Minmatar' }, function(err, minmatarCount) {
          callback(err, minmatarCount);
        });
      },
      function(callback) {
        Character.count({ gender: 'Male' }, function(err, maleCount) {
          callback(err, maleCount);
        });
      },
      function(callback) {
        Character.count({ gender: 'Female' }, function(err, femaleCount) {
          callback(err, femaleCount);
        });
      },
      function(callback) {
        Character.aggregate({ $group: { _id: null, total: { $sum: '$wins' } } }, function(err, totalVotes) {
            var total = totalVotes.length ? totalVotes[0].total : 0;
            callback(err, total);
          }
        );
      },
      function(callback) {
        Character
          .find()
          .sort('-wins')
          .limit(100)
          .select('race')
          .exec(function(err, characters) {
            if (err) return next(err);

            var raceCount = _.countBy(characters, function(character) { return character.race; });
            var max = _.max(raceCount, function(race) { return race });
            var inverted = _.invert(raceCount);
            var topRace = inverted[max];
            var topCount = raceCount[topRace];

            callback(err, { race: topRace, count: topCount });
          });
      },
      function(callback) {
        Character
          .find()
          .sort('-wins')
          .limit(100)
          .select('bloodline')
          .exec(function(err, characters) {
            if (err) return next(err);

            var bloodlineCount = _.countBy(characters, function(character) { return character.bloodline; });
            var max = _.max(bloodlineCount, function(bloodline) { return bloodline });
            var inverted = _.invert(bloodlineCount);
            var topBloodline = inverted[max];
            var topCount = bloodlineCount[topBloodline];

            callback(err, { bloodline: topBloodline, count: topCount });
          });
      }
    ],
    function(err, results) {
      if (err) return next(err);

      res.send({
        totalCount: results[0],
        amarrCount: results[1],
        caldariCount: results[2],
        gallenteCount: results[3],
        minmatarCount: results[4],
        maleCount: results[5],
        femaleCount: results[6],
        totalVotes: results[7],
        leadingRace: results[8],
        leadingBloodline: results[9]
      });
    });
});

//React middleware
app.use(function(req,res){
	Router.run(routes, req.path, function(Handler){
		var html = React.renderToString(React.createElement(Handler));
		var page = swig.renderFile('views/index.html',{html:html});
		res.send(page);
	});
});

var server = require('http').createServer(app);
var io = require('socket.io')(server);
var onlineUsers = 0;

io.sockets.on('connection', function(socket){
	onlineUsers++;

	io.sockets.emit('onlineUsers', {onlineUsers:onlineUsers});

	socket.on('disconnect', function(){
		onlineUsers --;
		io.sockets.emit('onlineUsers', {onlineUsers:onlineUsers});
	});
});

server.listen(app.get('port', function(){
	console.log('Express server listening on port ' + app.get('port'));
});<|endoftext|>


<commit_before>"use strict";

// polyfill websockets in Node
if (typeof(WebSocket) == "undefined") global.WebSocket = require('ws');

var uuid       = require('node-uuid'),
    Moo        = require('./moo.js'),
    MooMessage = require('./moomsg.js'),
    Core       = require('./core.js');

function RoonApi(o) {
    this._service_request_handlers = {};

    if (typeof(o.extension_id)    != 'string') throw new Error("Roon Extension options is missing the required 'extension_id' property.");
    if (typeof(o.display_name)    != 'string') throw new Error("Roon Extension options is missing the required 'display_name' property.");
    if (typeof(o.display_version) != 'string') throw new Error("Roon Extension options is missing the required 'display_version' property.");
    if (typeof(o.publisher)       != 'string') throw new Error("Roon Extension options is missing the required 'publisher' property.");
    if (typeof(o.email)           != 'string') throw new Error("Roon Extension options is missing the required 'email' property.");

    if (typeof(o.set_persisted_state) == 'undefined')
        this.set_persisted_state = state => { this.save_config("roonstate", state); };
    else
        this.set_persisted_state = o.set_persisted_state;

    if (typeof(o.get_persisted_state) == 'undefined')
        this.get_persisted_state = () => { return this.load_config("roonstate") || {}; };
    else
        this.get_persisted_state = o.get_persisted_state;

    if (o.core_found && !o.core_lost) throw new Error("Roon Extension options .core_lost is required if you implement .core_found.");
    if (!o.core_found && o.core_lost) throw new Error("Roon Extension options .core_found is required if you implement .core_lost.");
    if (o.core_paired && !o.core_unpaired) throw new Error("Roon Extension options .core_unpaired is required if you implement .core_paired.");
    if (!o.core_paired && o.core_unpaired) throw new Error("Roon Extension options .core_paired is required if you implement .core_unpaired.");

    if (o.core_paired && o.core_found) throw new Error("Roon Extension options can not specify both .core_paired and .core_found.");

    if (o.core_found    && typeof(o.core_found)    != "function") throw new Error("Roon Extensions options has a .core_found which is not a function");
    if (o.core_lost     && typeof(o.core_lost)     != "function") throw new Error("Roon Extensions options has a .core_lost which is not a function");
    if (o.core_paired   && typeof(o.core_paired)   != "function") throw new Error("Roon Extensions options has a .core_paired which is not a function");
    if (o.core_unpaired && typeof(o.core_unpaired) != "function") throw new Error("Roon Extensions options has a .core_unpaired which is not a function");

    this.extension_opts = o;

    this.extension_reginfo = {
        extension_id:      o.extension_id,
        display_name:      o.display_name,
        display_version:   o.display_version,
        publisher:         o.publisher,
        email:             o.email,
        required_services: [],
        optional_services: [],
        provided_services: []
    };
    if (o.website) this.extension_reginfo.website = o.website;
}

RoonApi.prototype.init_services = function(o) {
    if (!Array.isArray(o.required_services)) o.required_services = [];
    if (!Array.isArray(o.optional_services)) o.optional_services = [];
    if (!Array.isArray(o.provided_services)) o.provided_services = [];

    if (o.required_services.length || o.optional_services.length)
	if (!this.extension_opts.core_paired && !this.extension_opts.core_found) throw new Error("Roon Extensions options has required or optional services, but has neither .core_paired nor .core_found.");

    if (this.extension_opts.core_paired) {
	let svc = this.register_service("com.roonlabs.pairing:1", {
	    subscriptions: [
	    {
		subscribe_name:   "subscribe_pairing",
		unsubscribe_name: "unsubscribe_pairing",
		start: (req) => {
		    req.send_continue("Subscribed", { paired_core_id: this.paired_core_id });
		}
	    }
	    ],
	    methods: {
		get_pairing: (req) => {
		    req.send_complete("Success", { paired_core_id: this.paired_core_id });
		},
		pair: (req) => {
		    this.paired_core_id = req.moo.core.core_id;
		    svc.send_continue_all("subscribe_pairing", "Changed", { paired_core_id: this.paired_core_id  })
		},
	    }
	});

	this.pairing_service_1 = {
	    services: [ svc ],

	    found_core: core => {
		if (!this.paired_core_id) {
		    let settings = this.get_persisted_state();
		    settings.paired_core_id = core.core_id;
		    this.set_persisted_state(settings);

		    this.paired_core_id = core.core_id;
		    svc.send_continue_all("subscribe_pairing", "Changed", { paired_core_id: this.paired_core_id  })
		}
		if (core.core_id == this.paired_core_id)
		    if (this.extension_opts.core_paired) this.extension_opts.core_paired(core);
	    },
	    lost_core: core => {
		if (core.core_id == this.paired_core_id)
		    if (this.extension_opts.core_unpaired) this.extension_opts.core_unpaired(core);
	    },
	};
	o.provided_services.push(this.pairing_service_1);
    }

    this.extension_reginfo.provided_services.push({
	services: [ this.register_service("com.roonlabs.ping:1", {
	    methods: {
		ping: function(req) {
		    req.send_complete("Success");
		},
	    }
	}) ]
    });

    o.required_services.forEach(svcobj => { svcobj.services.forEach(svc => { this.extension_reginfo.required_services.push(svc.name); }); });
    o.optional_services.forEach(svcobj => { svcobj.services.forEach(svc => { this.extension_reginfo.optional_services.push(svc.name); }); });
    o.provided_services.forEach(svcobj => { svcobj.services.forEach(svc => { this.extension_reginfo.provided_services.push(svc.name); }); });
};

// - pull in Sood and provide discovery methods in Node, but not in WebBrowser
//
// - implement save_config/load_config based on:
//      Node:       require('fs')
//      WebBrowser: localStroage
//
if (typeof(window) == "undefined") {
    RoonApi.prototype.start_discovery = function() {
	if (this._sood) return;
	this._sood = require('./sood.js');
        this._sood.on('message', msg => {
//	    console.log(msg);
            if (msg.props.service_id == "00720724-5143-4a9b-abac-0e50cba674bb" && msg.props.unique_id) {
		let host = msg.from.ip;
                this.connect(host, msg.props.http_port);
            }
        });
        this._sood.start(() => {
	    this._sood.query({ '_tid':uuid.v4(), query_service_id: "00720724-5143-4a9b-abac-0e50cba674bb" });
	});
    };

    var fs = require('fs');
    RoonApi.prototype.save_config = function(k, v) {
        try {
            let config;
            try {
                let content = fs.readFileSync("config.json", { encoding: 'utf8' });
                config = JSON.parse(content);
            } catch (e) {
                config = {};
            }
            if (v === undefined || v === null)
                delete(config[k]);
            else
                config[k] = v;
            fs.writeFileSync("config.json", JSON.stringify(config, null, '    '));
        } catch (e) { }
    };

    RoonApi.prototype.load_config = function(k) {
        try {
            let content = fs.readFileSync("config.json", { encoding: 'utf8' });
            return JSON.parse(content)[k];
        } catch (e) {
            return undefined;
        }
    };

} else {
    RoonApi.prototype.save_config = function(k, v) {
        if (v === undefined || v === null)
            localStorage.removeItem(k);
        else
            localStorage.setItem(k, JSON.stringify(v));
    };
    RoonApi.prototype.load_config = function(k) {
        try {
            let r = localStorage.getItem(k);
            return r ? JSON.parse(r) : undefined;
        } catch (e) {
            return undefined;
        }
    };
}

RoonApi.prototype.register_service = function(svcname, spec) {
    let ret = {
	_subtypes: { }
    };

    if (spec.subscriptions) {
	for (let x in spec.subscriptions) {
	    let s = spec.subscriptions[x];
	    let subname = s.subscribe_name;
	    ret._subtypes[subname] = { };
	    spec.methods[subname] = (req) => {
		// XXX make sure req.body.subscription_key exists or respond send_complete with error

		var newreq = {
		    send_continue: function() {
			req.send_continue.apply(req, arguments);
		    },
		    send_complete: function() {
			req.send_complete.apply(req, arguments);
			delete(ret._subtypes[subname][req.body.subscription_key]);
		    }
		};
		s.start(newreq, req);
		ret._subtypes[subname][req.body.subscription_key] = newreq;
	    };
	    spec.methods[s.unsubscribe_name] = (req) => {
		// XXX make sure req.body.subscription_key exists or respond send_complete with error
                delete(ret._subtypes[subname][req.body.subscription_key]);
		if (s.end) s.end(req);
		req.send_complete("Unsubscribed");
	    };
	}
    }

    // process incoming requests from the other side
    this._service_request_handlers[svcname] = req => {
	// make sure the req's request name is something we know about
        if (req) {
            let method = spec.methods[req.msg.name];
            if (method) {
                method(req);
            } else {
                req.send_complete("InvalidRequest", { error: "unknown request name (" + svcname + ") : " + req.msg.name });
            }
        } else {
            if (spec.subscriptions) {
                for (let x in spec.subscriptions) {
                    let s = spec.subscriptions[x];
                    let subname = s.subscribe_name;
                    ret._subtypes[subname] = { };
                    if (s.end) s.end(req);
                }
            }
        }
    };

    ret.name = svcname;
    ret.send_continue_all = (subtype, name, props) => { for (let x in ret._subtypes[subtype]) ret._subtypes[subtype][x].send_continue(name, props); };
    ret.send_complete_all = (subtype, name, props) => { for (let x in ret._subtypes[subtype]) ret._subtypes[subtype][x].send_complete(name, props); };
    return ret;
};

RoonApi.prototype.connect = function() {
    var host, cb;

    var i = 0;
    host = arguments[i++];
    if (typeof(arguments[i]) != "function") host += ":" + arguments[i++];
    cb = arguments[i++];

    var ret = {
        ws: new WebSocket('ws://' + host + '/api')
    };
    if (typeof(window) != "undefined") ret.ws.binaryType = 'arraybuffer';

    ret.ws.onopen = () => {
//        console.log("OPEN");
        ret.moo = new Moo(ret.ws);

        ret.moo.send_request("com.roonlabs.registry:1/info",
			 (msg, body) => {
			     if (!msg) return;
			     let s = this.get_persisted_state();
			     if (s.tokens && s.tokens[body.core_id]) this.extension_reginfo.token = s.tokens[body.core_id];

			     ret.moo.send_request("com.roonlabs.registry:1/register", this.extension_reginfo,
					      (msg, body) => {
						  if (!msg) { // lost connection
						      if (ret.moo.core) {
							  if (this.pairing_service_1)        this.pairing_service_1.lost_core(ret.moo.core);
							  if (this.extension_opts.core_lost) this.extension_opts.core_lost(ret.moo.core);
							  ret.moo.core = undefined;
						      }
						  } else if (msg.name == "Registered") {
						      ret.moo.core = new Core(ret.moo, this, body);

						      let settings = this.get_persisted_state();
						      if (!settings.tokens) settings.tokens = {};
						      settings.tokens[body.core_id] = body.token;
						      this.set_persisted_state(settings);

						      if (this.pairing_service_1)         this.pairing_service_1.found_core(ret.moo.core);
						      if (this.extension_opts.core_found) this.extension_opts.core_found(ret.moo.core);
						  }
					      });
			 });
    };

    ret.ws.onclose = () => {
//        console.log("CLOSE");
        Object.keys(this._service_request_handlers).forEach(e => this._service_request_handlers[e] && this._service_request_handlers[e](null));
	if (ret.moo) ret.moo.close();
	ret.moo = undefined;
        ret.ws.close();
        cb && cb();
    };

    ret.ws.onerror = err => {
//        console.log("ERROR", err);
	if (ret.moo) ret.moo.close();
	ret.moo = undefined;
        ret.ws.close();
    };

    ret.ws.onmessage = event => {
//        console.log("GOTMSG");
	if (!ret.moo) return;
        var msg = ret.moo.parse(event.data);
        if (!msg) return;
        var body = msg.body;
        delete(msg.body);
        if (msg.verb == "REQUEST") {
            console.log('<-', msg.verb, msg.request_id, msg.service + "/" +  msg.name, body ? JSON.stringify(body) : "");
            var req = new MooMessage(ret.moo, msg, body);
            var handler = this._service_request_handlers[msg.service];
            if (handler)
                handler(req);
            else
                req.send_complete("InvalidRequest", { error: "unknown service: " + msg.service });
        } else {
            console.log('<-', msg.verb, msg.request_id, msg.name, body ? JSON.stringify(body) : "");
            ret.moo.handle_response(msg, body);
        }
    };

    return ret;
};

exports = module.exports = RoonApi;
<commit_msg>fix ping service registeration<commit_after>"use strict";

// polyfill websockets in Node
if (typeof(WebSocket) == "undefined") global.WebSocket = require('ws');

var uuid       = require('node-uuid'),
    Moo        = require('./moo.js'),
    MooMessage = require('./moomsg.js'),
    Core       = require('./core.js');

function RoonApi(o) {
    this._service_request_handlers = {};

    if (typeof(o.extension_id)    != 'string') throw new Error("Roon Extension options is missing the required 'extension_id' property.");
    if (typeof(o.display_name)    != 'string') throw new Error("Roon Extension options is missing the required 'display_name' property.");
    if (typeof(o.display_version) != 'string') throw new Error("Roon Extension options is missing the required 'display_version' property.");
    if (typeof(o.publisher)       != 'string') throw new Error("Roon Extension options is missing the required 'publisher' property.");
    if (typeof(o.email)           != 'string') throw new Error("Roon Extension options is missing the required 'email' property.");

    if (typeof(o.set_persisted_state) == 'undefined')
        this.set_persisted_state = state => { this.save_config("roonstate", state); };
    else
        this.set_persisted_state = o.set_persisted_state;

    if (typeof(o.get_persisted_state) == 'undefined')
        this.get_persisted_state = () => { return this.load_config("roonstate") || {}; };
    else
        this.get_persisted_state = o.get_persisted_state;

    if (o.core_found && !o.core_lost) throw new Error("Roon Extension options .core_lost is required if you implement .core_found.");
    if (!o.core_found && o.core_lost) throw new Error("Roon Extension options .core_found is required if you implement .core_lost.");
    if (o.core_paired && !o.core_unpaired) throw new Error("Roon Extension options .core_unpaired is required if you implement .core_paired.");
    if (!o.core_paired && o.core_unpaired) throw new Error("Roon Extension options .core_paired is required if you implement .core_unpaired.");

    if (o.core_paired && o.core_found) throw new Error("Roon Extension options can not specify both .core_paired and .core_found.");

    if (o.core_found    && typeof(o.core_found)    != "function") throw new Error("Roon Extensions options has a .core_found which is not a function");
    if (o.core_lost     && typeof(o.core_lost)     != "function") throw new Error("Roon Extensions options has a .core_lost which is not a function");
    if (o.core_paired   && typeof(o.core_paired)   != "function") throw new Error("Roon Extensions options has a .core_paired which is not a function");
    if (o.core_unpaired && typeof(o.core_unpaired) != "function") throw new Error("Roon Extensions options has a .core_unpaired which is not a function");

    this.extension_opts = o;

    this.extension_reginfo = {
        extension_id:      o.extension_id,
        display_name:      o.display_name,
        display_version:   o.display_version,
        publisher:         o.publisher,
        email:             o.email,
        required_services: [],
        optional_services: [],
        provided_services: []
    };
    if (o.website) this.extension_reginfo.website = o.website;
}

RoonApi.prototype.init_services = function(o) {
    if (!Array.isArray(o.required_services)) o.required_services = [];
    if (!Array.isArray(o.optional_services)) o.optional_services = [];
    if (!Array.isArray(o.provided_services)) o.provided_services = [];

    if (o.required_services.length || o.optional_services.length)
	if (!this.extension_opts.core_paired && !this.extension_opts.core_found) throw new Error("Roon Extensions options has required or optional services, but has neither .core_paired nor .core_found.");

    if (this.extension_opts.core_paired) {
	let svc = this.register_service("com.roonlabs.pairing:1", {
	    subscriptions: [
	    {
		subscribe_name:   "subscribe_pairing",
		unsubscribe_name: "unsubscribe_pairing",
		start: (req) => {
		    req.send_continue("Subscribed", { paired_core_id: this.paired_core_id });
		}
	    }
	    ],
	    methods: {
		get_pairing: (req) => {
		    req.send_complete("Success", { paired_core_id: this.paired_core_id });
		},
		pair: (req) => {
		    this.paired_core_id = req.moo.core.core_id;
		    svc.send_continue_all("subscribe_pairing", "Changed", { paired_core_id: this.paired_core_id  })
		},
	    }
	});

	this.pairing_service_1 = {
	    services: [ svc ],

	    found_core: core => {
		if (!this.paired_core_id) {
		    let settings = this.get_persisted_state();
		    settings.paired_core_id = core.core_id;
		    this.set_persisted_state(settings);

		    this.paired_core_id = core.core_id;
		    svc.send_continue_all("subscribe_pairing", "Changed", { paired_core_id: this.paired_core_id  })
		}
		if (core.core_id == this.paired_core_id)
		    if (this.extension_opts.core_paired) this.extension_opts.core_paired(core);
	    },
	    lost_core: core => {
		if (core.core_id == this.paired_core_id)
		    if (this.extension_opts.core_unpaired) this.extension_opts.core_unpaired(core);
	    },
	};
	o.provided_services.push(this.pairing_service_1);
    }

    this.extension_reginfo.provided_services.push({
	this.register_service("com.roonlabs.ping:1", {
	    methods: {
		ping: function(req) {
		    req.send_complete("Success");
		},
	    }
	})
    });

    o.required_services.forEach(svcobj => { svcobj.services.forEach(svc => { this.extension_reginfo.required_services.push(svc.name); }); });
    o.optional_services.forEach(svcobj => { svcobj.services.forEach(svc => { this.extension_reginfo.optional_services.push(svc.name); }); });
    o.provided_services.forEach(svcobj => { svcobj.services.forEach(svc => { this.extension_reginfo.provided_services.push(svc.name); }); });
};

// - pull in Sood and provide discovery methods in Node, but not in WebBrowser
//
// - implement save_config/load_config based on:
//      Node:       require('fs')
//      WebBrowser: localStroage
//
if (typeof(window) == "undefined") {
    RoonApi.prototype.start_discovery = function() {
	if (this._sood) return;
	this._sood = require('./sood.js');
        this._sood.on('message', msg => {
//	    console.log(msg);
            if (msg.props.service_id == "00720724-5143-4a9b-abac-0e50cba674bb" && msg.props.unique_id) {
		let host = msg.from.ip;
                this.connect(host, msg.props.http_port);
            }
        });
        this._sood.start(() => {
	    this._sood.query({ '_tid':uuid.v4(), query_service_id: "00720724-5143-4a9b-abac-0e50cba674bb" });
	});
    };

    var fs = require('fs');
    RoonApi.prototype.save_config = function(k, v) {
        try {
            let config;
            try {
                let content = fs.readFileSync("config.json", { encoding: 'utf8' });
                config = JSON.parse(content);
            } catch (e) {
                config = {};
            }
            if (v === undefined || v === null)
                delete(config[k]);
            else
                config[k] = v;
            fs.writeFileSync("config.json", JSON.stringify(config, null, '    '));
        } catch (e) { }
    };

    RoonApi.prototype.load_config = function(k) {
        try {
            let content = fs.readFileSync("config.json", { encoding: 'utf8' });
            return JSON.parse(content)[k];
        } catch (e) {
            return undefined;
        }
    };

} else {
    RoonApi.prototype.save_config = function(k, v) {
        if (v === undefined || v === null)
            localStorage.removeItem(k);
        else
            localStorage.setItem(k, JSON.stringify(v));
    };
    RoonApi.prototype.load_config = function(k) {
        try {
            let r = localStorage.getItem(k);
            return r ? JSON.parse(r) : undefined;
        } catch (e) {
            return undefined;
        }
    };
}

RoonApi.prototype.register_service = function(svcname, spec) {
    let ret = {
	_subtypes: { }
    };

    if (spec.subscriptions) {
	for (let x in spec.subscriptions) {
	    let s = spec.subscriptions[x];
	    let subname = s.subscribe_name;
	    ret._subtypes[subname] = { };
	    spec.methods[subname] = (req) => {
		// XXX make sure req.body.subscription_key exists or respond send_complete with error

		var newreq = {
		    send_continue: function() {
			req.send_continue.apply(req, arguments);
		    },
		    send_complete: function() {
			req.send_complete.apply(req, arguments);
			delete(ret._subtypes[subname][req.body.subscription_key]);
		    }
		};
		s.start(newreq, req);
		ret._subtypes[subname][req.body.subscription_key] = newreq;
	    };
	    spec.methods[s.unsubscribe_name] = (req) => {
		// XXX make sure req.body.subscription_key exists or respond send_complete with error
                delete(ret._subtypes[subname][req.body.subscription_key]);
		if (s.end) s.end(req);
		req.send_complete("Unsubscribed");
	    };
	}
    }

    // process incoming requests from the other side
    this._service_request_handlers[svcname] = req => {
	// make sure the req's request name is something we know about
        if (req) {
            let method = spec.methods[req.msg.name];
            if (method) {
                method(req);
            } else {
                req.send_complete("InvalidRequest", { error: "unknown request name (" + svcname + ") : " + req.msg.name });
            }
        } else {
            if (spec.subscriptions) {
                for (let x in spec.subscriptions) {
                    let s = spec.subscriptions[x];
                    let subname = s.subscribe_name;
                    ret._subtypes[subname] = { };
                    if (s.end) s.end(req);
                }
            }
        }
    };

    ret.name = svcname;
    ret.send_continue_all = (subtype, name, props) => { for (let x in ret._subtypes[subtype]) ret._subtypes[subtype][x].send_continue(name, props); };
    ret.send_complete_all = (subtype, name, props) => { for (let x in ret._subtypes[subtype]) ret._subtypes[subtype][x].send_complete(name, props); };
    return ret;
};

RoonApi.prototype.connect = function() {
    var host, cb;

    var i = 0;
    host = arguments[i++];
    if (typeof(arguments[i]) != "function") host += ":" + arguments[i++];
    cb = arguments[i++];

    var ret = {
        ws: new WebSocket('ws://' + host + '/api')
    };
    if (typeof(window) != "undefined") ret.ws.binaryType = 'arraybuffer';

    ret.ws.onopen = () => {
//        console.log("OPEN");
        ret.moo = new Moo(ret.ws);

        ret.moo.send_request("com.roonlabs.registry:1/info",
			 (msg, body) => {
			     if (!msg) return;
			     let s = this.get_persisted_state();
			     if (s.tokens && s.tokens[body.core_id]) this.extension_reginfo.token = s.tokens[body.core_id];

			     ret.moo.send_request("com.roonlabs.registry:1/register", this.extension_reginfo,
					      (msg, body) => {
						  if (!msg) { // lost connection
						      if (ret.moo.core) {
							  if (this.pairing_service_1)        this.pairing_service_1.lost_core(ret.moo.core);
							  if (this.extension_opts.core_lost) this.extension_opts.core_lost(ret.moo.core);
							  ret.moo.core = undefined;
						      }
						  } else if (msg.name == "Registered") {
						      ret.moo.core = new Core(ret.moo, this, body);

						      let settings = this.get_persisted_state();
						      if (!settings.tokens) settings.tokens = {};
						      settings.tokens[body.core_id] = body.token;
						      this.set_persisted_state(settings);

						      if (this.pairing_service_1)         this.pairing_service_1.found_core(ret.moo.core);
						      if (this.extension_opts.core_found) this.extension_opts.core_found(ret.moo.core);
						  }
					      });
			 });
    };

    ret.ws.onclose = () => {
//        console.log("CLOSE");
        Object.keys(this._service_request_handlers).forEach(e => this._service_request_handlers[e] && this._service_request_handlers[e](null));
	if (ret.moo) ret.moo.close();
	ret.moo = undefined;
        ret.ws.close();
        cb && cb();
    };

    ret.ws.onerror = err => {
//        console.log("ERROR", err);
	if (ret.moo) ret.moo.close();
	ret.moo = undefined;
        ret.ws.close();
    };

    ret.ws.onmessage = event => {
//        console.log("GOTMSG");
	if (!ret.moo) return;
        var msg = ret.moo.parse(event.data);
        if (!msg) return;
        var body = msg.body;
        delete(msg.body);
        if (msg.verb == "REQUEST") {
            console.log('<-', msg.verb, msg.request_id, msg.service + "/" +  msg.name, body ? JSON.stringify(body) : "");
            var req = new MooMessage(ret.moo, msg, body);
            var handler = this._service_request_handlers[msg.service];
            if (handler)
                handler(req);
            else
                req.send_complete("InvalidRequest", { error: "unknown service: " + msg.service });
        } else {
            console.log('<-', msg.verb, msg.request_id, msg.name, body ? JSON.stringify(body) : "");
            ret.moo.handle_response(msg, body);
        }
    };

    return ret;
};

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


<commit_before>var express = require('express');
var path = require('path');
var app = express();

app
    .use('/', express.static(path.join(__dirname, '/')))
    .use('/', express.directory(path.join(__dirname, '/')))
    .listen('3000');
<commit_msg>removes server.js<commit_after><|endoftext|>


<commit_before>'use strict'

const express = require('express')
const Slapp = require('slapp')
const ConvoStore = require('slapp-convo-beepboop')
const Context = require('slapp-context-beepboop')

// use `PORT` env var on Beep Boop - default to 3000 locally
var port = process.env.PORT || 3000

var slapp = Slapp({
  // Beep Boop sets the SLACK_VERIFY_TOKEN env var
  verify_token: process.env.SLACK_VERIFY_TOKEN,
  convo_store: ConvoStore(),
  context: Context()
})

var HELP_TEXT = `
I will respond to the following messages:
\`help\` - to see this message.
\`hi\` - to demonstrate a conversation that tracks state.
\`thanks\` - to demonstrate a simple response.
\`<type-any-other-text>\` - to demonstrate a random emoticon response, some of the time :wink:.
\`attachment\` - to see a Slack attachment message.
`

//*********************************************
// Setup different handlers for messages
//*********************************************

// response to the user typing "help"
slapp.message('help', ['mention', 'direct_message'], (msg) => {
  msg.say(HELP_TEXT)
})

// "Conversation" flow that tracks state - kicks off when user says hi, hello or hey
slapp
  .message('^(hi|hello|hey)$', ['direct_mention', 'direct_message'], (msg, text) => {
    msg
      .say(`${text}, how are you?`)
      // sends next event from user to this route, passing along state
      .route('how-are-you', { greeting: text })
  })
  .route('how-are-you', (msg, state) => {
    var text = (msg.body.event && msg.body.event.text) || ''

    // user may not have typed text as their next action, ask again and re-route
    if (!text) {
      return msg
        .say("Whoops, I'm still waiting to hear how you're doing.")
        .say('How are you?')
        .route('how-are-you', state)
    }

    // add their response to state
    state.status = text

    msg
      .say(`Ok then. What's your favorite color?`)
      .route('color', state)
  })
  .route('color', (msg, state) => {
    var text = (msg.body.event && msg.body.event.text) || ''

    // user may not have typed text as their next action, ask again and re-route
    if (!text) {
      return msg
        .say("I'm eagerly awaiting to hear your favorite color.")
        .route('color', state)
    }

    // add their response to state
    state.color = text

    msg
      .say('Thanks for sharing.')
      .say(`Here's what you've told me so far: \`\`\`${JSON.stringify(state)}\`\`\``)
    // At this point, since we don't route anywhere, the "conversation" is over
  })

// Can use a regex as well
slapp.message(/^(thanks|thank you)/i, ['mention', 'direct_message'], (msg) => {
  // You can provide a list of responses, and a random one will be chosen
  // You can also include slack emoji in your responses
  msg.say([
    "You're welcome :smile:",
    'You bet',
    ':+1: Of course',
    'Anytime :sun_with_face: :full_moon_with_face:'
  ])
})

// demonstrate returning an attachment...
slapp.message('attachment', ['mention', 'direct_message'], (msg) => {
  msg.say({
    text: 'Check out this amazing attachment! :confetti_ball: ',
    attachments: [{
      text: 'Slapp is a robust open source library that sits on top of the Slack APIs',
      title: 'Slapp Library - Open Source',
      image_url: 'https://storage.googleapis.com/beepboophq/_assets/bot-1.22f6fb.png',
      title_link: 'https://beepboophq.com/',
      color: '#7CD197'
    }]
  })
})

// Catch-all for any other responses not handled above
slapp.message('.*', ['direct_mention', 'direct_message'], (msg) => {
  // respond only 40% of the time
  if (Math.random() < 0.4) {
    msg.say([':wave:', ':pray:', ':raised_hands:'])
  }
})

// LAN message
slapp.
  message('(\\b(lan)\\b)|(\\b(Ian)\\b)', 'ambient', (msg) => {
    var today = new Date();
    var lan = new Date('April 13, 2017 18:00');
    var difference = (lan - today.getTime()) / 1000;
    msg
      .say([
      'LAN starts at 18:00 on Thursday the 13th of April 2017.',
      'la la la la I\'m not listening',
      '6pm. Thursday. 13/04.',
      'Ask @vyper',
      difference + ' seconds to go.',
      Math.round(difference / 60) + ' minutes to go.',
      Math.round(difference / 60 / 60) + ' hours to go.',
      Math.round(difference / 86400) + ' days to go.'
    ])

  })

// attach Slapp to express server
var server = slapp.attachToExpress(express())

// start http server
server.listen(port, (err) => {
  if (err) {
    return console.error(err)
  }

  console.log(`Listening on port ${port}`)
})
<commit_msg>added extra insults<commit_after>'use strict'

const express = require('express')
const Slapp = require('slapp')
const ConvoStore = require('slapp-convo-beepboop')
const Context = require('slapp-context-beepboop')

// use `PORT` env var on Beep Boop - default to 3000 locally
var port = process.env.PORT || 3000

var slapp = Slapp({
  // Beep Boop sets the SLACK_VERIFY_TOKEN env var
  verify_token: process.env.SLACK_VERIFY_TOKEN,
  convo_store: ConvoStore(),
  context: Context()
})

var HELP_TEXT = `
I will respond to the following messages:
\`help\` - to see this message.
\`hi\` - to demonstrate a conversation that tracks state.
\`thanks\` - to demonstrate a simple response.
\`<type-any-other-text>\` - to demonstrate a random emoticon response, some of the time :wink:.
\`attachment\` - to see a Slack attachment message.
`

//*********************************************
// Setup different handlers for messages
//*********************************************

// response to the user typing "help"
slapp.message('help', ['mention', 'direct_message'], (msg) => {
  msg.say(HELP_TEXT)
})

// "Conversation" flow that tracks state - kicks off when user says hi, hello or hey
slapp
  .message('^(hi|hello|hey)$', ['direct_mention', 'direct_message'], (msg, text) => {
    msg
      .say(`${text}, how are you?`)
      // sends next event from user to this route, passing along state
      .route('how-are-you', { greeting: text })
  })
  .route('how-are-you', (msg, state) => {
    var text = (msg.body.event && msg.body.event.text) || ''

    // user may not have typed text as their next action, ask again and re-route
    if (!text) {
      return msg
        .say("Whoops, I'm still waiting to hear how you're doing.")
        .say('How are you?')
        .route('how-are-you', state)
    }

    // add their response to state
    state.status = text

    msg
      .say(`Ok then. What's your favorite color?`)
      .route('color', state)
  })
  .route('color', (msg, state) => {
    var text = (msg.body.event && msg.body.event.text) || ''

    // user may not have typed text as their next action, ask again and re-route
    if (!text) {
      return msg
        .say("I'm eagerly awaiting to hear your favorite color.")
        .route('color', state)
    }

    // add their response to state
    state.color = text

    msg
      .say('Thanks for sharing.')
      .say(`Here's what you've told me so far: \`\`\`${JSON.stringify(state)}\`\`\``)
    // At this point, since we don't route anywhere, the "conversation" is over
  })

// Can use a regex as well
slapp.message(/^(thanks|thank you)/i, ['mention', 'direct_message'], (msg) => {
  // You can provide a list of responses, and a random one will be chosen
  // You can also include slack emoji in your responses
  msg.say([
    "You're welcome :smile:",
    'You bet',
    ':+1: Of course',
    'Anytime :sun_with_face: :full_moon_with_face:'
  ])
})

// demonstrate returning an attachment...
slapp.message('attachment', ['mention', 'direct_message'], (msg) => {
  msg.say({
    text: 'Check out this amazing attachment! :confetti_ball: ',
    attachments: [{
      text: 'Slapp is a robust open source library that sits on top of the Slack APIs',
      title: 'Slapp Library - Open Source',
      image_url: 'https://storage.googleapis.com/beepboophq/_assets/bot-1.22f6fb.png',
      title_link: 'https://beepboophq.com/',
      color: '#7CD197'
    }]
  })
})

// Catch-all for any other responses not handled above
slapp.message('.*', ['direct_mention', 'direct_message'], (msg) => {
  // respond only 40% of the time
  if (Math.random() < 0.4) {
    msg.say([':wave:', ':pray:', ':raised_hands:'])
  }
})

// LAN message
slapp.
  message('(\\b(lan)\\b)|(\\b(Ian)\\b)', 'ambient', (msg) => {
    var today = new Date();
    var lan = new Date('April 13, 2017 18:00');
    var difference = (lan - today.getTime()) / 1000;
    msg
      .say([
      'LAN starts at 18:00 on Thursday the 13th of April 2017.',
      'la la la la I\'m not listening',
      '6pm. Thursday. 13/04.',
      'Ask @vyper',
      difference + ' seconds to go.',
      Math.round(difference / 60) + ' minutes to go.',
      Math.round(difference / 60 / 60) + ' hours to go.',
      Math.round(difference / 86400) + ' days to go.'
    ]).route('thanks', state)
  }).route('thanks', (msg, state) => {
    var text = (msg.body.event && msg.body.event.text) || ''
    if (text.includes("thanks")) {
      return msg
        .say([
          'Douchebag.',
          'Dickhole.',
          'Tool.'
        ])
  }

// attach Slapp to express server
var server = slapp.attachToExpress(express())

// start http server
server.listen(port, (err) => {
  if (err) {
    return console.error(err)
  }

  console.log(`Listening on port ${port}`)
})
<|endoftext|>


<commit_before>'use strict';

var express = require('express');
var routes = require('./app/routes/index.js');
var mongoose = require('mongoose');
var passport = require('passport');
var session = require('express-session');

var app = express();
require('dotenv').load();
require('./app/config/passport')(passport);

mongoose.connect(process.env.MONGO_URI);

app.use('/controllers', express.static(process.cwd() + '/app/controllers'));
app.use('/public', express.static(process.cwd() + '/public'));
app.use('/common', express.static(process.cwd() + '/app/common'));

app.use(session({
	secret: 'secretClementine',
	resave: false,
	saveUninitialized: true
}));

app.use(passport.initialize());
app.use(passport.session());

routes(app, passport);

var port = process.env.PORT || 8080;
app.listen(port,  function () {
	console.log('Node.js listening on port ' + port + '...');
});<commit_msg>File not needed<commit_after><|endoftext|>


<commit_before>var express = require( 'express' );
var server = express();

server.use( express.static( __dirname + '/app' ) );

//var port = process.env.PORT;
var port = 5000;

server.listen( port, function() {
  console.log( 'server listening on port ' + port );
});<commit_msg>updating port for heroku<commit_after>var express = require( 'express' );
var server = express();

server.use( express.static( __dirname + '/app' ) );

var port = process.env.PORT;
//var port = 5000;

server.listen( port, function() {
  console.log( 'server listening on port ' + port );
});<|endoftext|>


<commit_before>var express = require('express');

var port = process.env.PORT || '3000';
var host = process.env.HOST || '0.0.0.0';

var app = express();

app.use(express.static('src'))
  .set('views', 'views')
  .set('view engine', 'ejs');

app.get('/', function (req, res) {
  res.render('index', { page: 'home' });
});

app.get('/login', function (req, res) {
  res.render('pages/login.ejs');
});

app.listen(port, host, function () {
  console.log('Server running', host, ':', port);
});
<commit_msg>:rotating_light: Removed linter warns<commit_after>var express = require('express');

var port = process.env.PORT || '3000';
var host = process.env.HOST || '0.0.0.0';

var app = express();

app.use(express.static('src'))
  .set('views', 'views')
  .set('view engine', 'ejs');

app.get('/', function (req, res) {
  res.render('index', {page: 'home'});
});

app.get('/login', function (req, res) {
  res.render('pages/login.ejs');
});

app.listen(port, host, function () {
  console.log('Server running', host, ':', port);
});
<|endoftext|>


<commit_before>var config = require('./config');
var express = require('express');
var app = express();
var compression = require('compression');
var bodyParser = require('body-parser');

app.use(compression({ level: 9 }));
app.use(bodyParser.json());
app.set('port', config.get('PORT'));
app.use(express.static('public'));
require('./api/routes')(app);

app.use(function forceLiveDomain(req, res, next) {
  // Don't allow user to hit Heroku now that we have a domain, see http://is.gd/OmQ9Yp
  if (config.get('NODE_ENV') === 'production') {
    var host = req.get('Host');
    if (host === 'paw-production.herokuapp.com') {
      return res.redirect(301, 'https://paw.isl.co/' + req.originalUrl);
    }
  }

  return next();
});

app.use(function redirectAllPaths(req, res, next) {
  // Redirect all paths to / to avoid 404's
  var originalUrl = req.originalUrl;
  if (originalUrl) {
    return res.redirect(301, '/');
  }
  return next();
});

var server = app.listen(app.get('port'), function() {
  var host = server.address().address;
  var port = server.address().port;

  console.log('paw-api listening at http://%s:%s', host, port);
});
<commit_msg>fix hostname<commit_after>var config = require('./config');
var express = require('express');
var app = express();
var compression = require('compression');
var bodyParser = require('body-parser');

app.use(compression({ level: 9 }));
app.use(bodyParser.json());
app.set('port', config.get('PORT'));
app.use(express.static('public'));
require('./api/routes')(app);

app.use(function forceLiveDomain(req, res, next) {
  // Don't allow user to hit Heroku now that we have a domain, see http://is.gd/OmQ9Yp
  if (config.get('NODE_ENV') === 'production') {
    var host = req.hostname;
    if (host === 'paw-production.herokuapp.com') {
      return res.redirect(301, 'https://paw.isl.co/' + req.originalUrl);
    }
  }

  return next();
});

app.use(function redirectAllPaths(req, res, next) {
  // Redirect all paths to / to avoid 404's
  var originalUrl = req.originalUrl;
  if (originalUrl) {
    return res.redirect(301, '/');
  }
  return next();
});

var server = app.listen(app.get('port'), function() {
  var host = server.address().address;
  var port = server.address().port;

  console.log('paw-api listening at http://%s:%s', host, port);
});
<|endoftext|>