Ksawery Kuklinski %!s(int64=8) %!d(string=hai) anos
pai
achega
e1d386fe2f
Modificáronse 10 ficheiros con 713 adicións e 2 borrados
  1. 4 1
      .gitignore
  2. 3 0
      .jshintrc
  3. 228 0
      availableTypes.json
  4. 36 0
      database.js
  5. 233 0
      engine.js
  6. 117 0
      index.js
  7. 10 1
      package.json
  8. 8 0
      test.js
  9. 4 0
      test2.js
  10. 70 0
      ts-query.js

+ 4 - 1
.gitignore

@@ -1,3 +1,7 @@
+# Customs
+database.sqlite
+config.json
+
 # Logs
 logs
 *.log
@@ -56,4 +60,3 @@ typings/
 
 # dotenv environment variables file
 .env
-

+ 3 - 0
.jshintrc

@@ -0,0 +1,3 @@
+{
+  "esversion": 6
+}

+ 228 - 0
availableTypes.json

@@ -0,0 +1,228 @@
+{
+  "game-server-query":{
+  	"Zombie Panic: Source": "zps",
+  	"7 Days to Die": "7dtd",
+  	"Age of Chivalry": "aoc",
+  	"Age of Empires 2": "aoe2",
+  	"Alien Arena": "alienarena",
+  	"Alien Swarm": "alienswarm",
+  	"Aliens vs Predator 2": "avp2",
+  	"Aliens vs Predator 2010": "avp2010",
+  	"America's Army": "americasarmy",
+  	"America's Army 2": "americasarmy2",
+  	"America's Army 3": "americasarmy3",
+  	"America's Army: Proving Grounds": "americasarmypg",
+  	"ARK: Survival Evolved": "ark",
+  	"ArmA Armed Assault 1": "arma",
+  	"ArmA Armed Assault 2": "arma2",
+  	"ArmA Armed Assault 3": "arma3",
+  	"Armagetron": "armagetron",
+  	"Baldur's Gate": "baldursgate",
+  	"Battlefield 1942": "bf1942",
+  	"Battlefield Vietnam": "bfv",
+  	"Battlefield 2": "bf2",
+  	"Battlefield 2142": "bf2142",
+  	"Battlefield: Bad Company 2": "bfbc2",
+  	"Battlefield 3": "bf3",
+  	"Battlefield 4": "bf4",
+  	"Breach": "breach",
+  	"Breed": "breed",
+  	"Brink": "brink",
+  	"Call of Duty": "cod",
+  	"Call of Duty: United Offensive": "coduo",
+  	"Call of Duty 2": "cod2",
+  	"Call of Duty 3": "cod3",
+  	"Call of Duty 4: Modern Warfare": "cod4",
+  	"Call of Duty: World at War": "codwaw",
+  	"Call of Duty: Modern Warfare 2": "codmw2",
+  	"Call of Duty: Modern Warfare 3": "codmw3",
+  	"Call of Juarez": "callofjuarez",
+  	"Chaser": "chaser",
+  	"Chrome": "chrome",
+  	"Codename Eagle": "codenameeagle",
+  	"Commandos 3: Destination Berlin": "commandos3",
+  	"Command and Conquer: Renegade": "cacrenegade",
+  	"Contact J.A.C.K.": "contactjack",
+  	"Counter-Strike 1.6": "cs16",
+  	"Counter-Strike: Condition Zero": "cscz",
+  	"Counter-Strike: Source": "css",
+  	"Counter-Strike: Global Offensive": "csgo",
+  	"Cross Racing Championship": "crossracing",
+  	"Crysis": "crysis",
+  	"Crysis Wars": "crysiswars",
+  	"Crysis 2": "crysis2",
+  	"Daikatana": "daikatana",
+  	"Dark Messiah of Might and Magic": "dmomam",
+  	"Darkest Hour": "darkesthour",
+  	"DayZ": "dayz",
+  	"DayZ Mod": "dayzmod",
+  	"Deadly Dozen: Pacific Theater": "deadlydozenpt",
+  	"Deer Hunter 2005": "dh2005",
+  	"Descent 3": "descent3",
+  	"Deus Ex": "deusex",
+  	"Devastation": "devastation",
+  	"Dino D-Day": "dinodday",
+  	"Dirt Track Racing 2": "dirttrackracing2",
+  	"Day of Defeat": "dod",
+  	"Day of Defeat: Source": "dods",
+  	"Doom 3": "doom3",
+  	"DOTA 2": "dota2",
+  	"Drakan": "drakan",
+  	"Enemy Territory Quake": "etqw",
+  	"F.E.A.R.": "fear",
+  	"F1 2002": "f12002",
+  	"F1 Challenge 99-02": "f1c9902",
+  	"Far Cry": "farcry2",
+  	"Fortress Forever": "fortressforever",
+  	"Flashpoint": "flashpoint",
+  	"Frontlines: Fuel of War": "ffow",
+  	"Garry's Mod": "garrysmod",
+  	"Ghost Recon: Advanced Warfighter": "graw",
+  	"Ghost Recon: Advanced Warfighter 2": "graw2",
+  	"Giants: Citizen Kabuto": "giantscitizenkabuto",
+  	"Global Operations": "globaloperations",
+  	"Gore": "gore",
+  	"Gunman Chronicles": "gunmanchronicles",
+  	"Half-Life 1 Deathmatch": "hldm",
+  	"Half-Life 2 Deathmatch": "hl2dm",
+  	"Halo": "halo",
+  	"Halo 2": "halo2",
+  	"Heretic 2": "heretic2",
+  	"Hexen World": "hexenworld",
+  	"The Hidden: Source": "hidden",
+  	"Hidden and Dangerous 2": "had2",
+  	"Homefront": "homefront",
+  	"Homeworld 2": "homeworld2",
+  	"IGI-2: Covert Strike": "igi2",
+  	"IL-2 Sturmovik": "il2",
+  	"Insurgency": "insurgency",
+  	"Iron Storm": "ironstorm",
+  	"James Bond: Nightfire": "jamesbondnightfire",
+  	"Just Cause 2 Multiplayer": "jc2mp",
+  	"Killing Floor": "killingfloor",
+  	"Kingpin: Life of Crime": "kingpin",
+  	"KISS Psycho Circus": "kisspc",
+  	"KzMod": "kzmod",
+  	"Left 4 Dead": "left4dead",
+  	"Left 4 Dead 2": "left4dead2",
+  	"Mafia 2 Multiplayer": "m2mp",
+  	"Medal of Honor: Allied Assault": "mohaa",
+  	"Medal of Honor: Pacific Assault": "mohpa",
+  	"Medal of Honor: Airborne": "mohab",
+  	"Medal of Honor: Spearhead": "mohsh",
+  	"Medal of Honor: Breakthrough": "mohbt",
+  	"Medal of Honor 2010": "moh2010",
+  	"Medal of Honor: Warfighter": "mohwf",
+  	"Minecraft": "minecraftping",
+  	"Monday Night Combat": "mnc",
+  	"Multi Theft Auto: Vice City": "mtavc",
+  	"Multi Theft Auto: San Andreas": "mtasa",
+  	"Mumble": "mumbleping",
+  	"Mutant Factions": "mutantfactions",
+  	"Nascar Thunder 2004": "nascarthunder2004",
+  	"netPanzer": "netpanzer",
+  	"No More Room in Hell": "nmrih",
+  	"Natural Selection": "ns",
+  	"Natural Selection 2": "ns2",
+  	"Need for Speed: Hot Pursuit 2": "nfshp2",
+  	"Nerf Arena Blast": "nab",
+  	"Neverwinter Nights": "nwn",
+  	"Neverwinter Nights 2": "nwn2",
+  	"Nexuiz": "nexuiz",
+  	"Nitro Family": "nitrofamily",
+  	"No One Lives Forever": "nolf",
+  	"No One Lives Forever 2": "nolf2",
+  	"Nuclear Dawn": "nucleardawn",
+  	"OpenArena": "openarena",
+  	"OpenTTD": "openttd",
+  	"Operation Flashpoint": "operationflashpoint",
+  	"Painkiller": "painkiller",
+  	"Postal 2": "postal2",
+  	"Prey": "prey",
+  	"Quake 1: QuakeWorld": "quake1",
+  	"Quake 2": "quake2",
+  	"Quake 3: Arena": "quake3",
+  	"Quake 4": "quake4",
+  	"Quake Live": "quakelive",
+  	"Rag Doll Kung Fu": "ragdollkungfu",
+  	"Rainbow Six": "r6",
+  	"Rainbow Six 2: Rogue Spear": "r6roguespear",
+  	"Rainbow Six 3: Raven Shield": "r6ravenshield",
+  	"RalliSport Challenge": "rallisportchallenge",
+  	"Rally Masters": "rallymasters",
+  	"Red Orchestra": "redorchestra",
+  	"Red Orchestra: Ostfront 41-45": "redorchestraost",
+  	"Red Orchestra 2": "redorchestra2",
+  	"Redline": "redline",
+  	"Reflex": "reflex",
+  	"Return to Castle Wolfenstein": "rtcw",
+  	"Ricochet": "ricochet",
+  	"Rise of Nations": "riseofnations",
+  	"Rune": "rune",
+  	"Rust": "rust",
+  	"San Andreas Multiplayer": "samp",
+  	"Serious Sam": "ss",
+  	"Serious Sam 2": "ss2",
+  	"Shattered Horizon": "shatteredhorizon",
+  	"The Ship": "ship",
+  	"Shogo": "shogo",
+  	"Shootmania": "shootmania",
+  	"SiN": "sin",
+  	"SiN Episodes": "sinep",
+  	"Soldat": "soldat",
+  	"Soldier of Fortune": "sof",
+  	"Soldier of Fortune 2": "sof2",
+  	"S.T.A.L.K.E.R.": "stalker",
+  	"Star Trek: Bridge Commander": "stbc",
+  	"Star Trek: Voyager - Elite Force": "stvef",
+  	"Star Trek: Voyager - Elite Force 2": "stvef2",
+  	"Star Wars: Battlefront": "swbf",
+  	"Star Wars: Battlefront 2": "swbf2",
+  	"Star Wars: Jedi Knight": "swjk",
+  	"Star Wars: Jedi Knight 2": "swjk2",
+  	"Star Wars: Republic Commando": "swrc",
+  	"Starbound": "starbound",
+  	"StarMade": "starmade",
+  	"Suicide Survival": "suicidesurvival",
+  	"SWAT 4": "swat4",
+  	"Sven Coop": "svencoop",
+  	"Synergy": "synergy",
+  	"Tactical Ops": "tacticalops",
+  	"Team Factor": "teamfactor",
+  	"Team Fortress Classic": "tfc",
+  	"Team Fortress 2": "tf2",
+  	"Teamspeak 2": "ts2",
+  	"Terminus": "terminus",
+  	"Terraria": "terraria",
+  	"Tony Hawk's Pro Skater 3": "thps3",
+  	"Tony Hawk's Pro Skater 4": "thps4",
+  	"Tony Hawk's Underground 2": "thu2",
+  	"TOXIKK": "toxikk",
+  	"Trackmania 2": "trackmania2",
+  	"Trackmania Forever": "trackmaniaforever",
+  	"Tremulous": "tremulous",
+  	"Tribes: Vengeance": "tribesvengeance",
+  	"Tron 2.0": "tron20",
+  	"Turok 2": "turok2",
+  	"Universal Combat": "universalcombat",
+  	"Unreal": "unreal",
+  	"Unreal Tournament": "ut",
+  	"Unreal Tournament 2003": "ut2003",
+  	"Unreal Tournament 2004": "ut2004",
+  	"Unreal Tournament 3": "ut3",
+  	"Urban Terror": "urbanterror",
+  	"V8 Supercar Challenge": "v8supercar",
+  	"Ventrilo": "ventrilo",
+  	"Vietcong": "vietcong",
+  	"Vietcong 2": "vietcong2",
+  	"Warsow": "warsow",
+  	"Wheel of Time": "wheeloftime",
+  	"Wolfenstein 2009": "wolfenstein2009",
+  	"Wolfenstein: Enemy Territory": "wolfensteinet",
+  	"Xpand Rally": "xpandrally",
+  	"Zombie Master": "zombiemaster"
+  },
+  "teamspeak-query": {
+    "Teamspeak 3":"ts3"
+  }
+}

+ 36 - 0
database.js

@@ -0,0 +1,36 @@
+var Sequelize = require('sequelize');
+
+exports.sequelize = new Sequelize('stats', '', '', {
+  host: 'localhost',
+  dialect: 'sqlite',
+  storage: './database.sqlite',
+  // logging: true
+});
+
+exports.server = exports.sequelize.define("server", {
+  type: {
+    type: Sequelize.STRING
+  },
+  name:{
+    type: Sequelize.STRING
+  },
+  address:{
+    type: Sequelize.STRING
+  }
+});
+
+exports.traffic = exports.sequelize.define("traffic", {
+  players:{
+    type: Sequelize.INTEGER
+  },
+  maxplayers:{
+    type: Sequelize.INTEGER
+  }
+});
+
+var Traffic = exports.traffic;
+var Server = exports.server;
+
+Traffic.belongsTo(Server);
+
+exports.sequelize.sync();

+ 233 - 0
engine.js

@@ -0,0 +1,233 @@
+// Requirments
+
+const fs = require('fs');
+const path = require('path');
+const db = require("./database");
+const gmquery = require('game-server-query');
+const tsquery = require('./ts-query').query;
+
+// Status Handler
+
+var rawTypes = JSON.parse(fs.readFileSync("availableTypes.json", "utf-8"));
+var types = {};
+var x;
+for(x in rawTypes){
+  if(!rawTypes.hasOwnProperty(x)){
+    continue;
+  }
+  Object.assign(types, rawTypes[x]);
+}
+
+exports.getServerTypes = function () {
+  return types;
+};
+
+var statusHandlers = {
+  "game-server-query": function (type, address, callback) {
+    var port = parseInt(address.split(":")[1]);
+    address = address.split(":")[0];
+    var options = {type: type, host: address};
+    if(port){
+      options.port = port;
+    }
+    gmquery(
+      options,
+      function(state) {
+        if(state.error){
+          callback({
+            offline: true
+          });
+        }else {
+          callback(state);
+        }
+      }
+    );
+  },
+  "teamspeak-query": function (type, address, callback) {
+    var port = parseInt(address.split(":")[1]);
+    address = address.split(":")[0];
+    var options = {type: type, host: address};
+    if(port){
+      options.port = port;
+    }
+    const query = tsquery(options.host, options.port, function (err, data) {
+      if(err){
+        callback({
+          offline: true,
+          error: err
+        });
+      }else{
+        callback(data);
+      }
+    });
+  }
+};
+
+var responseHandlers = {
+  defaultHandler: function (data, server) {
+    var frame = {};
+    if(typeof(data.players) == "number"){
+      frame.players = data.players;
+    }else if(data.players && data.players.length >= 0){
+      frame.players = data.players.length;
+    }
+    if(typeof(data.maxplayers) == "number"){
+      frame.maxplayers = data.maxplayers;
+    }
+    console.log(frame);
+    if(frame.maxplayers && frame.players >= 0){
+      db.traffic.create({
+        server: server,
+        maxplayers: frame.maxplayers,
+        players: frame.players
+      }, {
+        include: [{
+          model: db.server,
+          as: 'server'
+        }]
+      });
+    }
+  },
+  query: {
+    "game-server-query": function (data, server) {
+      var frame = {};
+      if(typeof(data.players) == "number"){
+        frame.players = data.players;
+      }else if(data.players && data.players.length >= 0){
+        frame.players = data.players.length;
+      }
+      if(typeof(data.maxplayers) == "number"){
+        frame.maxplayers = data.maxplayers;
+      }
+      console.log(frame);
+      if(frame.maxplayers && frame.players >= 0){
+        db.traffic.create({
+          serverId: server,
+          maxplayers: frame.maxplayers,
+          players: frame.players
+        });
+      }
+    },
+    "teamspeak-query": function (data, server) {
+      var frame = {};
+      if(data.virtualserver_maxclients){
+        frame.maxplayers = data.virtualserver_maxclients;
+      }
+      if(data.virtualserver_clientsonline){
+        frame.players = data.virtualserver_clientsonline;
+      }
+      if(frame.maxplayers && frame.players >= 0){
+        db.traffic.create({
+          serverId: server,
+          maxplayers: frame.maxplayers,
+          players: frame.players
+        });
+      }
+    }
+  },
+  game: {
+
+  }
+};
+
+var searchQueryType = function (type) {
+  var x;
+  for(x in rawTypes){
+    if(!rawTypes.hasOwnProperty(x)){
+      continue;
+    }
+    var y;
+    for(y in rawTypes[x]) {
+      if(!rawTypes[x].hasOwnProperty(y)) {
+        continue;
+      }
+      if(rawTypes[x][y] == type){
+        return x;
+      }
+    }
+  }
+};
+
+exports.statusGrabber = {
+  getHandler: function (type) {
+    var x = statusHandlers[searchQueryType(type)];
+    if(x){
+      return x;
+    }
+    throw new Error("No handler for "+type+" type");
+  },
+  getStatus: function (type, address, callback){
+    var handler = this.getHandler(type);
+    handler(type, address, callback);
+  },
+  getResponseHandler: function (type) {
+    var queryType = searchQueryType(type);
+    if(responseHandlers.game[type]){
+      return responseHandlers.game[type];
+    }else if(responseHandlers.query[queryType]){
+      return responseHandlers.query[queryType];
+    }else{
+      return responseHandlers.defaultHandler;
+    }
+  },
+  getTraffic: function (callback) {
+    db.traffic.findAll().then(function(servers) {
+      callback(servers);
+    });
+  }
+};
+
+// Server menager
+
+exports.serverMenager = {
+  list: function (callback) {
+    // callback(serversList)
+    //   serversList - Array of servers
+    db.server.findAll().then(function(servers) {
+      callback(servers);
+    });
+  },
+  getByID: function (id, callback) {
+    db.server.findById(id).then(function (server) {
+      callback(server);
+    }).catch(function () {
+      callback("No server with this id");
+    });
+  },
+  add: function (type, address, name) {
+    db.server.create({
+      type: type,
+      name: name,
+      address: address
+    });
+  },
+  remove: function (id) {
+    db.server.destroy({
+      where:{
+        id: id
+      }
+    });
+  }
+};
+
+// Config menager
+
+var configFilePath = path.resolve("./config.json");
+const defaultConfig = {
+  lang: "en"
+};
+exports.configMenager = {
+  config: {},
+  load: function () {
+    if(fs.existsSync(configFilePath)){
+      this.config = JSON.parse(fs.readFileSync(configFilePath));
+    }else{
+      this.config = defaultConfig;
+      this.save();
+    }
+  },
+  save: function () {
+    fs.writeFileSync(configFilePath, JSON.stringify(this.config, null, "\t"));
+  }
+};
+exports.configMenager.load();

+ 117 - 0
index.js

@@ -0,0 +1,117 @@
+const express = require('express');
+const bodyparser = require('body-parser');
+const async = require('async');
+var app = express();
+var engine = require("./engine");
+
+app.use(bodyparser.urlencoded({
+  extended: true
+}));
+app.use(bodyparser.json());
+
+app.get("/", function (req, res) {
+  // TODO Frontend app
+  return res.send("WIP");
+});
+
+app.get("/api/types", function (req, res) {
+  res.type('json');
+  res.send(JSON.stringify(engine.getServerTypes()));
+});
+
+app.get("/api/servers/list", function (req,res) {
+  engine.serverMenager.list(function (data) {
+    res.type('json');
+    res.send(JSON.stringify(data));
+  });
+});
+
+app.post("/api/servers/add", function (req,res) {
+  var type = req.body.type;
+  var name = req.body.name;
+  var address = req.body.address;
+  engine.serverMenager.add(type, address, name);
+  res.send("");
+});
+
+app.post("/api/servers/remove", function (req, res) {
+  var id = req.body.id;
+  engine.serverMenager.remove(id);
+  res.send("");
+});
+
+app.get("/api/trafic/update", function (req, res) {
+  engine.serverMenager.list(function (data) {
+    async.map(data, function (data, callback) {
+      var server = data;
+      engine.statusGrabber.getStatus(server.type, server.address, function(data) {
+        var h = engine.statusGrabber.getResponseHandler(server.type);
+        h(data, server.get("id"));
+        callback(null, data);
+      });
+    }, function (err, map) {
+      res.type("json");
+      res.send(JSON.stringify(map));
+    });
+  });
+});
+
+app.get("/api/trafic/update/:id", function (req, res) {
+  engine.serverMenager.getByID(Number(req.params.id), function (data) {
+    if(typeof data == "string"){
+      res.type("text");
+      res.send(data);
+      return;
+    }
+    var server = data;
+    engine.statusGrabber.getStatus(server.type, server.address, function(data) {
+      var h = engine.statusGrabber.getResponseHandler(server.type);
+      h(data, server.get("id"));
+      res.type("json");
+      res.send(JSON.stringify(data));
+    });
+  });
+});
+
+app.get("/api/status", function (req, res) {
+  engine.serverMenager.list(function (data) {
+    async.map(data, function (data, callback) {
+      var server = data;
+      engine.statusGrabber.getStatus(server.type, server.address, function(data) {
+        callback(null, data);
+      });
+    }, function (err, map) {
+      res.type("json");
+      res.send(JSON.stringify(map));
+    });
+  });
+});
+
+app.get("/api/status/:id", function (req, res) {
+  engine.serverMenager.getByID(Number(req.params.id), function (data) {
+    if(typeof data == "string"){
+      res.type("text");
+      res.send(data);
+      return;
+    }
+    var server = data;
+    engine.statusGrabber.getStatus(server.type, server.address, function(data) {
+      if(data){
+        res.type("json");
+        data["_id"] = Number(req.params.id);
+        res.send(JSON.stringify(data));
+      }else{
+        res.send("Intertnal Error");
+      }
+    });
+  });
+});
+
+app.get("/api/trafic/get/all", function (req, res) {
+  engine.statusGrabber.getTraffic(function (data) {
+    res.type('json');
+    res.send(JSON.stringify(data));
+  });
+});
+
+app.listen(80);

+ 10 - 1
package.json

@@ -4,7 +4,16 @@
   "description": "Simple stats for game servers",
   "main": "index.js",
   "scripts": {
+    "start": "node index.js"
   },
   "author": "",
-  "license": "ISC"
+  "license": "ISC",
+  "dependencies": {
+    "async": "^2.1.4",
+    "body-parser": "^1.16.1",
+    "express": "^4.14.1",
+    "game-server-query": "^1.0.10",
+    "sequelize": "^3.30.2",
+    "sqlite3": "^3.1.8"
+  }
 }

+ 8 - 0
test.js

@@ -0,0 +1,8 @@
+
+const tsquery = require('./ts-query').query;
+const query = tsquery("parad0x.pl", "10010", function (err, darta) {
+  if(err){
+    console.log(err);
+  }
+  console.log(darta);
+});

+ 4 - 0
test2.js

@@ -0,0 +1,4 @@
+var toggle = -1;
+setInterval(function () {
+  toggle = -toggle;
+}, 1000);

+ 70 - 0
ts-query.js

@@ -0,0 +1,70 @@
+const net = require('net');
+
+unescape = function(str) {
+  return String(str).replace(/\\\\/g, '\\')
+    .replace(/\\\//g, '/')
+    .replace(/\\p/g, '|')
+    .replace(/\\n/g, '\n')
+    .replace(/\\r/g, '\r')
+    .replace(/\\t/g, '\t')
+    .replace(/\\v/g, '\v')
+    .replace(/\\f/g, '\f')
+    .replace(/\\s/g, ' ');
+};
+
+const formated = function (string) {
+  string = string.split(" ");
+  var obj = {}, temp;
+  for (var x in string) {
+    if (string.hasOwnProperty(x)) {
+      temp = string[x].split("=");
+      obj[temp[0].replace("\r", '')] = unescape(temp[1]);
+    }
+  }
+  return obj;
+};
+
+exports.query = function(host, port, callback){
+  var socket = new net.Socket();
+  var temp = String();
+  var obj, result, error = "Some problem";
+  host = host || "localhost";
+  port = port || 10011;
+  socket.on("close", function (he) {
+    if(typeof(result) == "undefined" || he){
+      callback(error);
+    }else{
+      callback(null, result);
+    }
+  });
+  socket.on("error", function (e) {
+    error = e.code;
+  });
+  socket.on("data", function (data) {
+    // console.log(String(data));
+    var str = String(data);
+    for (var x in str) {
+      if (!str.hasOwnProperty(x)) {
+        continue;
+      }
+      var char = str[x];
+      // console.log(str[x], "\n");
+      if(char === '\n'){
+        obj = formated(temp);
+        if(!obj.error){
+          result = obj;
+        }
+        temp = String();
+      }else{
+        temp += char;
+      }
+    }
+  });
+  socket.connect({
+    port: port,
+    host: host
+  });
+  socket.write("use 1\n");
+  socket.write("serverinfo\n");
+  socket.end();
+};