semi-rewrote mcping
This commit is contained in:
parent
5008da1331
commit
13df70da1b
|
@ -1,4 +1,3 @@
|
|||
# TODO: Rewrite this whole mess
|
||||
import socket
|
||||
import struct
|
||||
import json
|
||||
|
@ -8,24 +7,39 @@ from util import hook
|
|||
|
||||
try:
|
||||
import DNS
|
||||
# Please remember to install the dependency 'pydns'
|
||||
pydns_installed = True
|
||||
has_dns = True
|
||||
except ImportError:
|
||||
pydns_installed = False
|
||||
has_dns = False
|
||||
|
||||
|
||||
mccolors = [u"\x0300,\xa7f", u"\x0301,\xa70", u"\x0302,\xa71", u"\x0303,\xa72", u"\x0304,\xa7c", u"\x0305,\xa74",
|
||||
u"\x0306,\xa75", u"\x0307,\xa76", u"\x0308,\xa7e", u"\x0309,\xa7a", u"\x0310,\xa73", u"\x0311,\xa7b",
|
||||
u"\x0312,\xa71", u"\x0313,\xa7d", u"\x0314,\xa78", u"\x0315,\xa77", u"\x02,\xa7l", u"\x0310,\xa79",
|
||||
u"\x09,\xa7o", u"\x13,\xa7m", u"\x0f,\xa7r", u"\x15,\xa7n"]
|
||||
mc_colors = [(u'\xa7f', u'\x0300'), (u'\xa70', u'\x0301'), (u'\xa71', u'\x0302'), (u'\xa72', u'\x0303'),
|
||||
(u'\xa7c', u'\x0304'), (u'\xa74', u'\x0305'), (u'\xa75', u'\x0306'), (u'\xa76', u'\x0307'),
|
||||
(u'\xa7e', u'\x0308'), (u'\xa7a', u'\x0309'), (u'\xa73', u'\x0310'), (u'\xa7b', u'\x0311'),
|
||||
(u'\xa71', u'\x0312'), (u'\xa7d', u'\x0313'), (u'\xa78', u'\x0314'), (u'\xa77', u'\x0315'),
|
||||
(u'\xa7l', u'\x02'), (u'\xa79', u'\x0310'), (u'\xa7o', u'\t'), (u'\xa7m', u'\x13'),
|
||||
(u'\xa7r', u'\x0f'), (u'\xa7n', u'\x15')]
|
||||
|
||||
|
||||
def mc_color_format(motd):
|
||||
for colorcombo in mccolors:
|
||||
colorarray = colorcombo.split(",")
|
||||
motd = motd.replace(colorarray[1], colorarray[0])
|
||||
motd = motd.replace(u"\xa7k", "")
|
||||
return motd
|
||||
## EXCEPTIONS
|
||||
|
||||
|
||||
class PingError(Exception):
|
||||
def __init__(self, text):
|
||||
self.text = text
|
||||
|
||||
def __str__(self):
|
||||
return self.text
|
||||
|
||||
|
||||
class ParseError(Exception):
|
||||
def __init__(self, text):
|
||||
self.text = text
|
||||
|
||||
def __str__(self):
|
||||
return self.text
|
||||
|
||||
|
||||
## MISC
|
||||
|
||||
|
||||
def unpack_varint(s):
|
||||
|
@ -38,17 +52,14 @@ def unpack_varint(s):
|
|||
if not b & 0x80:
|
||||
return d
|
||||
|
||||
pack_data = lambda d: struct.pack('>b', len(d)) + d
|
||||
pack_port = lambda i: struct.pack('>H', i)
|
||||
|
||||
def pack_data(d):
|
||||
return struct.pack('>b', len(d)) + d
|
||||
|
||||
|
||||
def pack_port(i):
|
||||
return struct.pack('>H', i)
|
||||
## DATA FUNCTIONS
|
||||
|
||||
|
||||
def mcping_modern(host, port):
|
||||
""" pings a server using the modern (1.7+) protocol and returns formatted output """
|
||||
""" pings a server using the modern (1.7+) protocol and returns data """
|
||||
# connect to the server
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.connect((host, port))
|
||||
|
@ -86,12 +97,19 @@ def mcping_modern(host, port):
|
|||
from pprint import pprint
|
||||
pprint(data)
|
||||
return "Invalid data - check console ({})".format(e)
|
||||
return mc_color_format(u"{}\x0f - {}\x0f - {}/{} players.".format(desc, version, online,
|
||||
max_players)).replace("\n", u"\x0f - ")
|
||||
|
||||
output = {
|
||||
"motd": format_colors(desc),
|
||||
"motd_raw": desc,
|
||||
"version": version,
|
||||
"players": online,
|
||||
"players_max": max_players
|
||||
}
|
||||
return output
|
||||
|
||||
|
||||
def mcping_legacy(host, port):
|
||||
""" pings a server using the legacy (1.6 and older) protocol and returns formatted output """
|
||||
""" pings a server using the legacy (1.6 and older) protocol and returns data """
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.connect((host, port))
|
||||
sock.send('\xfe\x01')
|
||||
|
@ -105,16 +123,29 @@ def mcping_legacy(host, port):
|
|||
if len(data) == 1:
|
||||
# failed to decode data, server is using old format
|
||||
data = values.split(u'\xa7')
|
||||
message = u"{} - {}/{} players".format(mc_color_format(data[0]), data[1], data[2])
|
||||
output = {
|
||||
"motd": format_colors(data[0]),
|
||||
"motd_raw": data[0],
|
||||
"version": None,
|
||||
"players": data[1],
|
||||
"players_max": data[2]
|
||||
}
|
||||
else:
|
||||
# decoded data, server is using new format
|
||||
message = u"{} \x0f- {} - {}/{} players".format(mc_color_format(data[3]),
|
||||
mc_color_format(data[2]), data[4], data[5])
|
||||
output = {
|
||||
"motd": format_colors(data[3]),
|
||||
"motd_raw": data[3],
|
||||
"version": data[2],
|
||||
"players": data[4],
|
||||
"players_max": data[5]
|
||||
}
|
||||
sock.close()
|
||||
return message
|
||||
return output
|
||||
|
||||
|
||||
def get_srv_data(domain):
|
||||
## FORMATTING/PARSING FUNCTIONS
|
||||
|
||||
def check_srv(domain):
|
||||
""" takes a domain and finds minecraft SRV records """
|
||||
DNS.DiscoverNameServers()
|
||||
srv_req = DNS.Request(qtype='srv')
|
||||
|
@ -130,61 +161,55 @@ def parse_input(inp):
|
|||
""" takes the input from the mcping command and returns the host and port """
|
||||
inp = inp.strip().split(" ")[0]
|
||||
if ":" in inp:
|
||||
# the port is defined in the input string
|
||||
host, port = inp.split(":", 1)
|
||||
try:
|
||||
port = int(port)
|
||||
except:
|
||||
raise Exception("The port '{}' is invalid.".format(port))
|
||||
if port > 65535 or port < 0:
|
||||
raise ParseError("The port '{}' is invalid.".format(port))
|
||||
except ValueError:
|
||||
raise ParseError("The port '{}' is invalid.".format(port))
|
||||
return host, port
|
||||
if pydns_installed:
|
||||
srv_data = get_srv_data(inp)
|
||||
if has_dns:
|
||||
# the port is not in the input string, but we have PyDNS so look for a SRV record
|
||||
srv_data = check_srv(inp)
|
||||
if srv_data:
|
||||
return str(srv_data[1]), int(srv_data[0])
|
||||
# return default port
|
||||
return inp, 25565
|
||||
|
||||
|
||||
@hook.command
|
||||
@hook.command("mcp6")
|
||||
def mcping6(inp):
|
||||
"""mcping6 <server>[:port] - Ping a Minecraft server version 1.6 or smaller to check status."""
|
||||
#try:
|
||||
host, port = parse_input(inp)
|
||||
#except Exception as ex:
|
||||
# return ex.args[0]
|
||||
try:
|
||||
return mcping_legacy(host, port)
|
||||
except:
|
||||
return "The 1.6 server {}:{} looks offline from here.".format(host, port)
|
||||
def format_colors(motd):
|
||||
for original, replacement in mc_colors:
|
||||
motd = motd.replace(original, replacement)
|
||||
motd = motd.replace(u"\xa7k", "")
|
||||
return motd
|
||||
|
||||
|
||||
@hook.command
|
||||
@hook.command("mcp7")
|
||||
def mcping7(inp):
|
||||
"""mcping <server>[:port] - Ping a Minecraft server version 1.7 or greater to check status."""
|
||||
try:
|
||||
host, port = parse_input(inp)
|
||||
except Exception as ex:
|
||||
return ex.args[0]
|
||||
try:
|
||||
return mcping_modern(host, port)
|
||||
except:
|
||||
return "The 1.7 server {}:{} looks offline from here.".format(host, port)
|
||||
def format_output(data):
|
||||
if data["version"]:
|
||||
return u"{motd}\x0f - {version}\x0f - {players}/{players_max}" \
|
||||
u" players.".format(**data).replace("\n", u"\x0f - ")
|
||||
else:
|
||||
return u"{motd}\x0f - {players}/{players_max}" \
|
||||
u" players.".format(**data).replace("\n", u"\x0f - ")
|
||||
|
||||
|
||||
@hook.command
|
||||
@hook.command("mcp")
|
||||
def mcping(inp):
|
||||
"""mcping <server>[:port] - Ping a Minecraft server to check status."""
|
||||
# try:
|
||||
host, port = parse_input(inp)
|
||||
#except Exception as e:
|
||||
# return e.args[0]
|
||||
#
|
||||
try:
|
||||
host, port = parse_input(inp)
|
||||
except ParseError as e:
|
||||
return "Could not parse input: {}".format(e)
|
||||
|
||||
try:
|
||||
return mcping_modern(host, port)
|
||||
except:
|
||||
data = mcping_modern(host, port)
|
||||
return format_output(data)
|
||||
except PingError:
|
||||
try:
|
||||
return mcping_legacy(host, port)
|
||||
except:
|
||||
data = mcping_legacy(host, port)
|
||||
return format_output(data)
|
||||
except PingError:
|
||||
return "The server {} ({}:{}) looks offline from here.".format(inp, host, port)
|
||||
|
|
Reference in New Issue