From 9eafc53c91eb9b3972cb0cd938991a1fec3f92b4 Mon Sep 17 00:00:00 2001 From: Calvin Montgomery Date: Mon, 3 Jun 2013 23:56:06 -0400 Subject: [PATCH] start experimenting with a fallback layer --- channel.js | 2 + notwebsocket.js | 118 ++++++++++++++++++++++++++++++++++ server.js | 48 ++++++++++++++ www/assets/js/callbacks.js | 7 ++ www/assets/js/notwebsocket.js | 50 ++++++++++++++ www/channel.html | 1 + 6 files changed, 226 insertions(+) create mode 100644 notwebsocket.js create mode 100644 www/assets/js/notwebsocket.js diff --git a/channel.js b/channel.js index 9aad63a6..af565ed4 100644 --- a/channel.js +++ b/channel.js @@ -19,6 +19,7 @@ var Logger = require("./logger.js"); var InfoGetter = require("./get-info.js"); var Server = require("./server.js"); var io = Server.io; +var NWS = require("./notwebsocket"); var Rank = require("./rank.js"); var Auth = require("./auth.js"); var ChatCommand = require("./chatcommand.js"); @@ -760,6 +761,7 @@ Channel.prototype.sendRecentChat = function(user) { Channel.prototype.sendAll = function(message, data) { io.sockets.in(this.name).emit(message, data); + NWS.inRoom(this.name).emit(message, data); } Channel.prototype.broadcastPlaylistMeta = function() { diff --git a/notwebsocket.js b/notwebsocket.js new file mode 100644 index 00000000..8cee92f0 --- /dev/null +++ b/notwebsocket.js @@ -0,0 +1,118 @@ +const chars = "abcdefghijklmnopqsrtuvwxyz" + + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + + "0123456789"; + + +var NotWebsocket = function() { + this.hash = ""; + for(var i = 0; i < 30; i++) { + this.hash += chars[parseInt(Math.random() * (chars.length - 1))]; + } + + this.pktqueue = []; + this.handlers = {}; + this.room = ""; +} + +NotWebsocket.prototype.emit = function(msg, data) { + //hack because something fishy is going on + if(typeof msg === "object") { + data = msg["1"]; + msg = msg["0"]; + } + var pkt = [msg, data]; + this.pktqueue.push(pkt); +} + +NotWebsocket.prototype.poll = function() { + var q = this.pktqueue; + this.pktqueue = []; + return q; +} + +NotWebsocket.prototype.on = function(msg, callback) { + if(!(msg in this.handlers)) + this.handlers[msg] = []; + this.handlers[msg].push(callback); +} + +NotWebsocket.prototype.recv = function(urlstr) { + var msg, data; + try { + var js = JSON.parse(urlstr); + msg = js[0]; + data = js[1]; + } + catch(e) { + console.log("Failed to parse NWS string"); + } + if(!msg) + return; + if(!(msg in this.handlers)) + return; + for(var i = 0; i < this.handlers[msg].length; i++) { + this.handlers[msg][i](data); + } +} + +NotWebsocket.prototype.join = function(rm) { + this.room = rm; +} + +NotWebsocket.prototype.disconnect = function() { + +} + +function sendJSON(res, obj) { + var response = JSON.stringify(obj, null, 4); + if(res.callback) { + response = res.callback + "(" + response + ")"; + } + var len = unescape(encodeURIComponent(response)).length; + + res.setHeader("Content-Type", "application/json"); + res.setHeader("Content-Length", len); + res.end(response); +} + +var clients = {}; +function newConnection(req, res) { + var nws = new NotWebsocket(); + clients[nws.hash] = nws; + sendJSON(res, nws.hash); + return nws; +} +exports.newConnection = newConnection; + +function msgReceived(req, res) { + var h = req.params.hash; + if(h in clients) { + if(req.params.str == "poll") { + sendJSON(res, clients[h].poll()); + } + else { + clients[h].recv(unescape(req.params.str)); + sendJSON(res, ""); + } + } +} +exports.msgReceived = msgReceived; + +function inRoom(rm) { + var cl = []; + for(var h in clients) { + if(clients[h].room == rm) { + cl.push(clients[h]); + } + } + + return { + emit: function() { + for(var i = 0; i < this.cl.length; i++) { + this.cl[i].emit(arguments); + } + }, + cl: cl + }; +} +exports.inRoom = inRoom; diff --git a/server.js b/server.js index 1676ad3a..5362237a 100644 --- a/server.js +++ b/server.js @@ -18,6 +18,7 @@ Logger.syslog.log("Starting CyTube v" + VERSION); var Config = require("./config.js"); var express = require("express"); var API = require("./api.js"); +var NWS = require("./notwebsocket"); var app = express(); app.get("/r/:channel(*)", function(req, res, next) { @@ -34,6 +35,53 @@ app.get("/api/:apireq(*)", function(req, res, next) { API.handle(req.url.substring(5), req, res); }); +function getClientIP(req) { + var ip; + var forward = req.header("x-forwarded-for"); + if(forward) { + ip = forward.split(",")[0]; + } + if(!ip) { + ip = req.connection.remoteAddress; + } + return ip; +} + +app.get("/nws/connect", function(req, res, next) { + var socket = NWS.newConnection(req, res); + var ip = getClientIP(req); + if(Database.checkGlobalBan(ip)) { + Logger.syslog.log("Disconnecting " + ip + " - bant"); + socket.emit("kick", { + reason: "You're globally banned!" + }); + socket.disconnect(true); + return; + } + socket.on("disconnect", function() { + exports.clients[ip]--; + }); + if(!(ip in exports.clients)) { + exports.clients[ip] = 1; + } + else { + exports.clients[ip]++; + } + if(exports.clients[ip] > Config.MAX_PER_IP) { + socket.emit("kick", { + reason: "Too many connections from your IP address" + }); + socket.disconnect(true); + return; + } + var user = new User(socket, ip); + Logger.syslog.log("Accepted connection from /" + user.ip); +}); + +app.get("/nws/:hash/:str", function(req, res, next) { + NWS.msgReceived(req, res); +}); + app.get("/:thing(*)", function(req, res, next) { res.sendfile(__dirname + "/www/" + req.params.thing); }); diff --git a/www/assets/js/callbacks.js b/www/assets/js/callbacks.js index 2c2201b5..b2f36ec1 100644 --- a/www/assets/js/callbacks.js +++ b/www/assets/js/callbacks.js @@ -835,6 +835,7 @@ Callbacks = { } } +/* $.getScript(IO_URL+"/socket.io/socket.io.js", function() { try { socket = io.connect(IO_URL); @@ -846,3 +847,9 @@ $.getScript(IO_URL+"/socket.io/socket.io.js", function() { Callbacks.disconnect(); } }); +*/ + +socket = new NotWebsocket(); +for(var key in Callbacks) { + socket.on(key, Callbacks[key]); +} diff --git a/www/assets/js/notwebsocket.js b/www/assets/js/notwebsocket.js new file mode 100644 index 00000000..2add0ade --- /dev/null +++ b/www/assets/js/notwebsocket.js @@ -0,0 +1,50 @@ +var NotWebsocket = function() { + this.connected = false; + $.getJSON(WEB_URL + "/nws/connect", function(data) { + this.hash = data; + this.connected = true; + this.recv(["connect", undefined]); + this.pollint = setInterval(function() { + this.poll(); + }.bind(this), 100); + }.bind(this)); + + this.handlers = {}; +} + +NotWebsocket.prototype.emit = function(msg, data) { + if(!this.connected) { + setTimeout(function() { + this.emit(msg, data); + }.bind(this), 100); + } + var pkt = [msg, data]; + var str = escape(JSON.stringify(pkt)); + $.getJSON(WEB_URL+"/nws/"+this.hash+"/"+str, function(){}); +} + +NotWebsocket.prototype.on = function(msg, callback) { + if(!(msg in this.handlers)) + this.handlers[msg] = []; + this.handlers[msg].push(callback); +} + +NotWebsocket.prototype.poll = function() { + if(!this.connected) + return; + $.getJSON(WEB_URL+"/nws/"+this.hash+"/poll", function(data) { + for(var i = 0; i < data.length; i++) { + console.log("DBG", data[i]); + this.recv(data[i]); + } + }.bind(this)); +} + +NotWebsocket.prototype.recv = function(pkt) { + var msg = pkt[0], data = pkt[1]; + if(!(msg in this.handlers)) + return; + for(var i = 0; i < this.handlers[msg].length; i++) { + this.handlers[msg][i](data); + } +} diff --git a/www/channel.html b/www/channel.html index a1977ff2..c3413473 100644 --- a/www/channel.html +++ b/www/channel.html @@ -313,6 +313,7 @@ +