SHARE
TWEET

Untitled

a guest Aug 18th, 2019 74 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/home/winston/venv/ping_servers/bin/python
  2. # pip3 install nbt mcstatus tabulate
  3.  
  4.  
  5. """
  6. Ping servers in the servers.dat
  7.  
  8. Works on Mac, should work on Windows and Linux.
  9. """
  10.  
  11.  
  12. from nbt.nbt import NBTFile
  13. import os
  14. from mcstatus import MinecraftServer
  15. from collections import namedtuple
  16. import platform
  17. import multiprocessing
  18. from tabulate import tabulate
  19.  
  20.  
  21. Server = namedtuple('Server', ['name', 'ip', 'port'])
  22. PingResult = namedtuple('PingResult', ['server', 'status', 'error'])
  23.  
  24. # To deal with a Pickler error on the PingResponse object.
  25. Status = namedtuple('Status', ['players', 'latency', 'motd', 'version'])
  26. Players = namedtuple('Players', ['online', 'max'])
  27.  
  28.  
  29. MINECRAFT_DIRS = {
  30.     'Darwin': 'Library/Application Support/minecraft',
  31.     'Linux': '.minecraft',
  32.     'Windows': '.minecraft',
  33. }
  34.  
  35.  
  36. def get_minecraft_dir():
  37.     return os.path.join(
  38.         os.getenv('HOME'),
  39.         MINECRAFT_DIRS[platform.system()]
  40.     )
  41.  
  42.  
  43. def get_servers():
  44.     minecraft_dir = get_minecraft_dir()
  45.     os.chdir(minecraft_dir)
  46.     with open('servers.dat', 'rb') as buf:
  47.         s = NBTFile(buffer=buf)
  48.     for server in s['servers']:
  49.         name = server['name'].valuestr()
  50.         address = server['ip'].valuestr()
  51.         ip, port = get_host_port(address)
  52.         yield Server(name=name, ip=ip, port=port)
  53.  
  54.  
  55. def get_host_port(address, default=25565):
  56.     address = address.strip(' \t')
  57.     if address[0] == '[' or address.count(':') == 1:
  58.         host, _, port = address.rpartition(':')
  59.         return host.strip('[]'), int(port)
  60.     return address, default
  61.  
  62.  
  63. def ping_server(server):
  64.     s = MinecraftServer(server.ip, server.port)
  65.     try:
  66.         res = s.status()
  67.         # avoid pickler error on PingResponse class
  68.         p = Players(res.players.online, res.players.max)
  69.         res = Status(
  70.             players=p,
  71.             latency=res.latency,
  72.             motd=res.description,
  73.             version=res.version.name,
  74.         )
  75.         error = None
  76.     except IOError as ex:
  77.         res = None
  78.         error = ex
  79.     return PingResult(server, res, error)
  80.  
  81.  
  82. def ping_servers(servers):
  83.     for server in servers:
  84.         yield ping_server(server)
  85.  
  86.  
  87. def ping_servers_async(servers):
  88.     pool = multiprocessing.Pool(10)
  89.     yield from pool.map(ping_server, servers)
  90.  
  91.  
  92. def format_address(ip, port, default_port=25565):
  93.     if int(port) == default_port:
  94.         return ip
  95.     L = []
  96.     if ':' in ip: # ipv6
  97.         L.append('[', ip, ']')
  98.     else:
  99.         L.append(ip)
  100.     L.extend([':', str(port)])
  101.     return ''.join(L)
  102.  
  103.  
  104. def format_server(s):
  105.     head = '{0} ({1})'.format(
  106.         s.server.name,
  107.         format_address(s.server.ip, s.server.port),
  108.     )
  109.     if not s.status:
  110.         body = 'is offline.'
  111.     else:
  112.         body = '{v}, has {online}/{cap} players, ~{lag} ms lag.'.format(
  113.             #                s.status.motd,
  114.             v=s.status.version,
  115.             online=s.status.players.online,
  116.             cap=s.status.players.max,
  117.             lag=round(s.status.latency),
  118.         )
  119.     return ' '.join([head, body])
  120.  
  121.  
  122. def tabulate_servers(servers):
  123.     L = []
  124.     for s in servers:
  125.         entry = [s.server.name, format_address(s.server.ip, s.server.port)]
  126.         if s.status:
  127.             entry.extend([
  128.                 s.status.version,
  129.                 s.status.players.online,
  130.                 s.status.players.max,
  131.                 round(s.status.latency),
  132.             ])
  133.         else:
  134.             entry.extend([None]*4)
  135.         L.append(entry)
  136.     return tabulate(
  137.         L,
  138.         headers=['Name', 'Address', 'Version', 'Online', 'Max', 'Lag (ms)'],
  139.     )
  140.  
  141.  
  142. def main():
  143.     responses = ping_servers_async(get_servers())
  144.     print(tabulate_servers(responses))
  145.  
  146.  
  147. if __name__ == '__main__':
  148.     main()
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top