| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- const http = require("http")
- ,https = require("https")
- ,Url = require("./url.js").Url
- ,config = require("../config.js")
- ,sessionManager = require("./session.js").SessionManager
- ,IrcConnection = require("./ircServer/ircConnection.js").IrcConnection
- ,AccountController = require("./controller/accountController.js").AccountController
- ,ApiController = require("./controller/apiController.js").ApiController
- ,MultiChatManager = require("./multichatManager.js").MultiChatManager
- ,AccountManager = require("./models/accounts.js").accountManager
- ,Slack = require("./slack.js").Slack
- ,slackManager = require("./slackManager.js").SlackManager
- ,FaviconWriter = require("./faviconWriter.js").FaviconWriter;
- function Server() {
- var ctx = this,
- errSocks = [],
- ircSocks = [],
- lastSockId = 0;
- this.httpServ = http.createServer(function(req, res) {
- res.ended = false;
- res.once('end', () => {
- res.ended = true;
- });
- ctx.onRequest(req, res);
- });
- this.httpServ.on("connection", (sock) => {
- sock.id = ++lastSockId;
- sock.once('close', () => {
- let i = ircSocks.indexOf(sock.id);
- if (i !== -1)
- ircSocks.splice(i, 1);
- i = errSocks.indexOf(sock.id);
- if (i !== -1)
- errSocks.splice(i, 1);
- });
- sock.on("data", (data) => {
- var dataStrArr = data.toString("utf-8").split(/\r?\n/g);
- for (var i =0, nbLines =dataStrArr.length; i < nbLines; i++)
- if ((/^(NICK|PASS) /).test(dataStrArr[i])) {
- var i = errSocks.indexOf(sock.id);
- if (i >= 0) {
- errSocks.splice(i, 1);
- ircSocks.push(sock.id);
- var con = new IrcConnection(sock);
- dataStrArr.forEach((str) => { con.parse(str); });
- }
- break;
- }
- });
- });
- // Default behaviour is to destroy connection, we would like to switch to IRC protocol instead
- this.httpServ.removeAllListeners("clientError");
- this.httpServ.on("clientError", (err, sock) => {
- if (ircSocks.indexOf(sock.id) === -1 && errSocks.indexOf(sock.id) === -1) {
- errSocks.push(sock.id);
- setTimeout(() => {
- if (errSocks.indexOf(sock.id) !== -1) {
- sock.destroy(err);
- }
- }, 1);
- }
- });
- this.httpServ.listen(config.port, ctx.onListen);
- }
- Server.parseCookies = function(req) {
- var cookies = req.headers.cookie
- ,cookieObj = null;
- if (cookies) {
- cookieObj = {};
- cookies = cookies.split(";");
- for (var cookieIndex =0, nbCookies =cookies.length; cookieIndex < nbCookies; cookieIndex++) {
- var cookieParts = cookies[cookieIndex].indexOf("=")
- ,cookieKey = null
- ,cookieValue = null;
- if (cookieParts === -1) {
- cookieKey = cookies[cookieIndex].trim();
- } else {
- cookieKey = cookies[cookieIndex].substr(0, cookieParts).trim();
- cookieValue = cookies[cookieIndex].substr(cookieParts +1).trim();
- }
- cookieObj[cookieKey] = cookieValue;
- }
- }
- return cookieObj;
- };
- Server.stringifyCookies = function(cookies) {
- var cookieString = "";
- for (var cookieKey in cookies) {
- cookieString += cookieString;
- if (cookies[cookieString] !== null) {
- cookieString += "=";
- }
- cookieString += "; ";
- }
- return cookieString;
- };
- Server.prototype.onListen = function() {
- console.log("onListen");
- };
- Server.prototype.execTemplate = function(template, req, res) {
- var resp = template.exec(req, res, this);
- if (resp && resp.body) {
- if (resp.status)
- res.writeHeader(resp.status);
- res.end(resp.body);
- }
- // else something is running asynchronously, let template close request later..
- };
- Server.prototype.execRequest = function(req, res) {
- if (req.urlObj.isTemplate() && req.urlObj.template.needLogin === false) {
- return this.execTemplate(req.urlObj.template, req, res);
- } else if (req.urlObj.isPublic()) {
- if (!config.isDebug)
- res.setHeader('Cache-Control', 'private, max-age=' +15 * 60);
- res.setHeader('Content-Length', req.urlObj.serve.stat.size);
- res.writeHeader("200");
- req.urlObj.getReadStream().pipe(res, { end: true });
- sessionManager.saveSession(req.session);
- return; // async pipe will close when finished
- } else if (!req.account) {
- res.writeHeader("302", { Location: "login" });
- res.end();
- } else if (req.urlObj.isTemplate()) {
- return this.execTemplate(req.urlObj.template, req, res);
- } else if (req.urlObj.match(["favicon.png"])) {
- if (!config.isDebug)
- res.setHeader('Cache-Control', 'private, max-age=' +15 * 60);
- var unreadHi = (req.urlObj.queryTokens.h && req.urlObj.queryTokens.h[0]) ? parseInt(req.urlObj.queryTokens.h[0], 10) : 0
- ,unread = (req.urlObj.queryTokens.m && req.urlObj.queryTokens.m[0]) ? parseInt(req.urlObj.queryTokens.m[0], 10) : 0;
- FaviconWriter.write(unreadHi, unread, (buf) => {
- res.writeHeader("200");
- res.end(buf);
- });
- sessionManager.saveSession(req.session);
- return;
- } else {
- // Api / dynamic content
- var apiSuccess = false;
- res.chatContext = new MultiChatManager();
- var services = req.account.getServices();
- for (var serviceId in services) {
- switch (services[serviceId].type) {
- case "Slack":
- res.chatContext.push(slackManager.lazyGet(serviceId, services[serviceId].oauthParam, req.reqT));
- break;
- default:
- console.error("Unknown service type for ", services[serviceId], " with account #" +req.account.id);
- }
- }
- if (req.urlObj.urlParts[0] === "account") {
- AccountController.onRequest(req, res, this);
- } else if (req.urlObj.urlParts[0] === "api") {
- ApiController.onRequest(req, res, this);
- } else {
- this.execTemplate(require('./template/_404.js'), req, res);
- }
- }
- };
- Server.prototype.onRequest = function(req, res) {
- req.reqT = Date.now();
- req.cookies = Server.parseCookies(req);
- req.session = sessionManager.forRequest(req);
- req.urlObj = new Url(req.url);
- req.account = null;
- if (req.session) {
- var self = this;
- AccountManager.fromId(req.session.accountId, (acc) => {
- req.account = acc;
- self.execRequest(req, res);
- });
- } else {
- this.execRequest(req, res);
- }
- };
- module.exports.HttpServ = Server;
|