Guest User

sprites.js

a guest
Nov 26th, 2012
21,281
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // includes
  2. var cluster = require('cluster');
  3. var cpuCount = require('os').cpus().length;
  4. var util = require("util");
  5. var http = require("http");
  6. var url = require('url');
  7. var fs = require('fs');
  8.  
  9. // max number of connections
  10. var MAX_CONNECTIONS = 1000000;
  11. // keep alive interval
  12. var KEEPALIVE_INTERVAL = 2*60*1000;
  13.  
  14. // configuration file
  15. var config = { messages: 0 };
  16. // number of connections
  17. var connections = 0;
  18. // list of channels
  19. var channel = [];
  20. // map of ID -> node
  21. var idmap = new Array(MAX_CONNECTIONS);
  22. // head of free id list
  23. var pHead;
  24.  
  25. // attempt to read config file
  26. fs.readFile("config.json", "utf8", function(err, data)
  27. {
  28.     if(err) { return; }
  29.  
  30.     // parse config file
  31.     config = JSON.parse(data);
  32. });
  33.  
  34. // save config file every couple of minutes
  35. setInterval(function()
  36. {
  37.     // write config file
  38.     fs.writeFile("config.json", JSON.stringify(config, null, 4), "utf8");
  39. }, 2*60*1000);
  40.  
  41. // initialize free id list
  42. for(var v=0;v<MAX_CONNECTIONS;v++)
  43. {
  44.     // allocate list entry
  45.     var pCur = new Object();
  46.     // assign id
  47.     pCur.id = v;
  48.  
  49.     // if there is no head, we're it
  50.     if(pHead === undefined) { pCur.pNext = pCur.pPrev = pHead = pCur; }
  51.  
  52.     // insert into list
  53.     pCur.pNext = pHead;
  54.     pCur.pPrev = pHead.pPrev;
  55.     pHead.pPrev.pNext = pCur;
  56.     pHead.pPrev = pCur;
  57. }
  58.  
  59. // connect left and right nodes
  60. function connectNodesLR(pL, pR)
  61. {
  62.     pL.pR = pR;
  63.     pR.pL = pL;
  64.     return;
  65. }
  66.  
  67. // connect top and bottom nodes
  68. function connectNodesTB(pT, pB)
  69. {
  70.     pT.pB = pB;
  71.     pB.pT = pT;
  72.     return;
  73. }
  74.  
  75. // insert node at the end of list
  76. function insertNode(name, pNode)
  77. {
  78.     // reference channel
  79.     var c = channel[name];
  80.  
  81.     // if channel does not exist, create it
  82.     if(c === undefined) { c = channel[name] = []; c.pHead = c.pTail = 0; }
  83.  
  84.     // debug log
  85.     //util.log("node inserted into " + name + " with id " + pHead.id + " (" + connections + " connections)");
  86.  
  87.     // add node to idmap
  88.     idmap[pHead.id] = pNode;
  89.  
  90.     // remember head item so we can delete it
  91.     var pDelete = pHead;
  92.  
  93.     // remove id from free id list
  94.     pHead.pNext.pPrev = pHead.pPrev;
  95.     pHead.pPrev.pNext = pHead.pNext;
  96.     pHead = pHead.pNext;
  97.  
  98.     // delete old head
  99.     delete pDelete;
  100.  
  101.     // special case for head
  102.     if(c.pHead == 0)
  103.     {
  104.         // initialize head and tail
  105.         c.pHead = c.pTail = pNode;
  106.  
  107.         // initialize neighbors
  108.         c.pHead.pL = c.pHead;
  109.         c.pHead.pR = c.pHead;
  110.         c.pHead.pT = c.pHead;
  111.         c.pHead.pB = c.pHead;
  112.        
  113.         return;
  114.     }
  115.  
  116.     // note: insert can occur after any node, but we'll use tail
  117.     var pPrev = c.pTail;
  118.  
  119.     // reference nodes
  120.     var pL = pPrev;
  121.     var pR = pPrev.pR;
  122.     var pB = pL.pB;
  123.     var pT = pR.pT;
  124.     var pC = pNode;
  125.  
  126.     // apply connections
  127.     connectNodesLR(pL, pC);
  128.     connectNodesLR(pC, pR);
  129.     connectNodesTB(pL, pR);
  130.     connectNodesTB(pC, pB);
  131.     connectNodesTB(pT, pC);
  132.  
  133.     // special case adjustment for N=3
  134.     if(pL.pL == pR)
  135.     {
  136.         var p0 = c.pHead;
  137.         var p1 = c.pHead.pR;
  138.         var p2 = c.pHead.pR.pR;
  139.  
  140.         connectNodesTB(p0, p2);
  141.         connectNodesTB(p1, p0);
  142.         connectNodesTB(p2, p1);
  143.     }
  144.  
  145.     // update tail, if necessary
  146.     if(pL == c.pTail) { c.pTail = pC; }
  147.  
  148.     return;    
  149. }
  150.  
  151. // delete node
  152. function deleteNode(name, id, pNode)
  153. {
  154.     // reference channel
  155.     var c = channel[name];
  156.  
  157.     // debug log
  158.     //util.log("node " + id + " deleted from " + name);
  159.  
  160.     // remove node from idmap
  161.     delete idmap[id];
  162.  
  163.     // allocate list entry
  164.     var pCur = new Object();
  165.     // assign id
  166.     pCur.id = id;
  167.  
  168.     // if there is no head, we're it
  169.     if(pHead === undefined) { pCur.pNext = pCur.pPrev = pHead = pCur; }
  170.  
  171.     // insert into list
  172.     pCur.pNext = pHead;
  173.     pCur.pPrev = pHead.pPrev;
  174.     pHead.pPrev = pCur;
  175.     pHead.pPrev.pNext = pCur;
  176.  
  177.     // reference nodes
  178.     var pL = pNode.pL;
  179.     var pR = pNode.pR;
  180.     var pT = pNode.pT;
  181.     var pB = pNode.pB;
  182.  
  183.     // apply connections
  184.     connectNodesLR(pL, pR);
  185.     connectNodesTB(pL, pB);
  186.     connectNodesTB(pT, pR);
  187.  
  188.     // update tail, if necessary
  189.     if(pNode == c.pTail) { c.pTail = pNode.pL; }
  190.     // update head, if necessary
  191.     if(pNode == c.pHead) { c.pHead = pNode.pR; }
  192.  
  193.     // if this was the last node, delete the channel
  194.     if(pNode == c.pHead) { delete channel[name]; }
  195.     // special case adjustment for N=2
  196.     else if(c.pHead == c.pTail.pL)
  197.     {
  198.         var p0 = c.pHead;
  199.         var p1 = c.pHead.pR;
  200.  
  201.         connectNodesTB(p0, p1);
  202.         connectNodesTB(p1, p0);
  203.     }
  204.  
  205.     return;
  206. }
  207.  
  208. // send message
  209. function sendMessage(query)
  210. {
  211.     // reference channel
  212.     var c = channel[query.name];
  213.  
  214.     // sanity check
  215.     if(c === undefined) { return; }
  216.  
  217.     // find node for the specified ID
  218.     var pNode = idmap[query.id];
  219.  
  220.     // sanity check
  221.     if(pNode === undefined) { return; }
  222.  
  223.     // detect appropriate neighbor
  224.     if(parseFloat(query.wx) > 0) { pNode = pNode.pR; }
  225.     else if(parseFloat(query.wx) < 0) { pNode = pNode.pL; }
  226.     if(parseFloat(query.wy) > 0) { pNode = pNode.pB; }
  227.     else if(parseFloat(query.wy) < 0) { pNode = pNode.pT; }
  228.  
  229.     // forward the message (messages are delimited by 2 endlines)
  230.     pNode.write(JSON.stringify(query) + "\n\n");
  231.  
  232.     // increment messages count
  233.     config.messages++;
  234.  
  235.     // debug log
  236.     //util.log(query.uri + " (" + query.id + ") [" + query.x + ", " + query.y + "]");
  237.  
  238.     return;
  239. }
  240.  
  241. function closeConnection(name, id, res)
  242. {
  243.     // delete node
  244.     deleteNode(name, id, res);
  245.  
  246.     // decrement connection count
  247.     connections--;
  248.    
  249.     return;
  250. }
  251.  
  252. function onClose()
  253. {
  254.     // "this" is req.connection
  255.     closeConnection(this.name, this.id, this.res);
  256.     clearInterval(this.interval);
  257.    
  258.     return;
  259. }
  260.  
  261. function onRequest(req, res)
  262. {
  263.     // parse url
  264.     var parsed = url.parse(req.url, true);
  265.  
  266.     // handle channel join
  267.     if(parsed.pathname == '/channel/join')
  268.     {
  269.         // grab free id
  270.         var id = pHead.id;
  271.  
  272.         // prepare keep alive string
  273.         var keepAlive = JSON.stringify( { 'cmd' : 'set_id', 'id' : id } ) + "\n\n";
  274.  
  275.         // prepare keep alive function
  276.         res.keepAliveFunc = function()
  277.         {
  278.             // send keep alive
  279.             res.write( keepAlive );
  280.  
  281.         };
  282.  
  283.         // cache variables
  284.         req.connection.name = parsed.query.name;
  285.         req.connection.id = id;
  286.         req.connection.res = res;
  287.         req.connection.interval = setInterval(res.keepAliveFunc, KEEPALIVE_INTERVAL);
  288.  
  289.         // increment connection count
  290.         connections++;
  291.  
  292.         // insert node
  293.         insertNode(parsed.query.name, res);
  294.  
  295.         // add connection close listener
  296.         req.connection.addListener('close', onClose);
  297.         // disable Nagle algorithm
  298.         req.connection.setNoDelay(true);
  299.         // disable connection timeout
  300.         req.connection.setTimeout(0);
  301.  
  302.         // send header
  303.         res.writeHead(200, {'Content-type':'text/plain'});
  304.         // send id
  305.         res.write( JSON.stringify( { 'cmd' : 'set_id', 'id' : id } ) + "\n\n" );
  306.         res.write( JSON.stringify( { 'cmd' : 'set_reconnect', 'timeout' : 4*60*1000 } ) + "\n\n" );
  307.     }
  308.     // handle channel send
  309.     else if(parsed.pathname == '/channel/send')
  310.     {
  311.         // send message
  312.         sendMessage(parsed.query);
  313.         // this request is done
  314.         res.end( JSON.stringify( { 'result' : '0' } ) );
  315.     }
  316.     // handle network traversal
  317.     else if(parsed.pathname == '/channel/neighbors')
  318.     {
  319.         // reference channel
  320.         var c = channel[parsed.query.name];
  321.  
  322.         // if channel does not exist, return an error
  323.         if(c === undefined)
  324.         {
  325.             // this request is done
  326.             res.end( JSON.stringify( { 'result' : '1' } ) );
  327.         }
  328.         // otherwise, check for the specified ID
  329.         else
  330.         {
  331.             // find node for the specified ID
  332.             var pNode = (parsed.query.id) ? idmap[parsed.query.id] : c.pHead;
  333.  
  334.             // result state
  335.             var result;
  336.  
  337.             // if this ID doesn't exists, return an error
  338.             if(pNode === undefined)
  339.             {
  340.                 // prepare result
  341.                 result = JSON.stringify( { 'result' : '2' } );
  342.             }
  343.             // otherwise, use the ID
  344.             else
  345.             {
  346.                 // prepare result
  347.                 result = JSON.stringify(
  348.                 {
  349.                     'result' : 0,
  350.                     'p0' : pNode.pT.pL.connection.id,
  351.                     'p1' : pNode.pT.connection.id,
  352.                     'p2' : pNode.pT.pR.connection.id,
  353.                     'p3' : pNode.pL.connection.id,
  354.                     'p4' : pNode.connection.id,
  355.                     'p5' : pNode.pR.connection.id,
  356.                     'p6' : pNode.pB.pL.connection.id,
  357.                     'p7' : pNode.pB.connection.id,
  358.                     'p8' : pNode.pB.pR.connection.id
  359.                 } );
  360.             }
  361.  
  362.             // send result in jsonp format
  363.             res.end( "result('" + result + "')" );
  364.         }
  365.     }
  366.     // handle channel count
  367.     else if(parsed.pathname == '/connections/count')
  368.     {
  369.         // send header
  370.         res.writeHead(200, {'Content-type':'text/plain'});
  371.         // send connections count
  372.         res.end( "result('" + JSON.stringify( { 'count' : connections } ) + "')" );
  373.     }
  374.     // handle channel count
  375.     else if(parsed.pathname == '/messages/count')
  376.     {
  377.         // send header
  378.         res.writeHead(200, {'Content-type':'text/plain'});
  379.         // send messages count
  380.         res.end( "result('" + JSON.stringify( { 'count' : config.messages } ) + "')" );
  381.     }
  382.     // handle garbage collection
  383.     else if(parsed.pathname == '/debug/gc')
  384.     {
  385.         // perform garbage collection
  386.         gc();
  387.  
  388.         // send header
  389.         res.writeHead(200, {'Content-type':'text/plain'});
  390.         // send result
  391.         res.end( JSON.stringify( { 'result' : '0' } ) );
  392.     }
  393.     // handle anything else
  394.     else
  395.     {
  396.         // send header
  397.         res.writeHead(200, {'Content-type':'text/plain'});
  398.         // send result
  399.         res.end( "nope" );
  400.     }
  401. };
  402.  
  403. function onWorkerRequest(req, res)
  404. {
  405.     // parse url
  406.     var parsed = url.parse(req.url, true);
  407.  
  408.     // retrieve query        
  409.     var query = { fwd : parsed.query };
  410.  
  411.     // forward query
  412.     process.send(query);
  413.  
  414.     // this request is done
  415.     res.end( JSON.stringify( { 'result' : '0' } ) );
  416. }
  417.  
  418. // master needs to listen
  419. if(cluster.isMaster)
  420. {
  421.     // listen on public port 8080
  422.     http.createServer(onRequest).listen(8080);
  423.  
  424.     // Fork worker(s) to handle send requests
  425.     for(var v=0;v<cpuCount-1;v++)
  426.     {
  427.         var worker = cluster.fork();
  428.  
  429.         // Event on worker death
  430.         cluster.on('death', function(worker) { console.log('worker ' + worker.pid + ' died'); });
  431.  
  432.         // Event on message
  433.         worker.on('message', function(msg)
  434.         {
  435.             // process forwarded query
  436.             if(msg && msg.fwd) { sendMessage(msg.fwd); }
  437.         });
  438.     }
  439. }
  440. // worker needs to fwd requests
  441. else
  442. {
  443.     // listen on public port 8081
  444.     http.createServer(onWorkerRequest).listen(8081);
  445. }
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×