231 lines
6.4 KiB
Python
231 lines
6.4 KiB
Python
import json
|
|
import socket
|
|
import time
|
|
import math
|
|
import random
|
|
import supybot.callbacks as callbacks
|
|
from supybot.commands import *
|
|
import supybot.ircdb as ircdb
|
|
import supybot.utils as utils
|
|
|
|
def filterServersByName(server_list, arg, field):
|
|
result = []
|
|
for i in range(len(server_list)):
|
|
if arg.lower().strip()\
|
|
in server_list[i][field].lower().strip():
|
|
result.append(server_list[i])
|
|
return result
|
|
|
|
def filterServersByNum(server_list, arg, field, typeconv):
|
|
result = []
|
|
if arg.startswith("<"): # less comparing
|
|
try: num = typeconv(arg[1:])
|
|
except: return
|
|
for i in range(0, len(server_list)):
|
|
if typeconv(server_list[i][field]) < num:
|
|
result.append(server_list[i])
|
|
elif arg.startswith(">"): # more comparing
|
|
try: num = typeconv(arg[1:])
|
|
except: return
|
|
for i in range(0, len(server_list)):
|
|
if typeconv(server_list[i][field]) > num:
|
|
result.append(server_list[i])
|
|
elif arg.startswith("!"): # NOT
|
|
try: num = typeconv(arg[1:])
|
|
except: return
|
|
for i in range(0, len(server_list)):
|
|
if typeconv(server_list[i][field]) != num:
|
|
result.append(server_list[i])
|
|
elif arg == "highest":
|
|
highest = [0, 0]
|
|
for i in range(0, len(server_list)):
|
|
if typeconv(server_list[i][field]) > highest[0]:
|
|
highest[0] = typeconv(server_list[i][field])
|
|
highest[1] = i
|
|
result = [server_list[highest[1]]]
|
|
elif arg == "lowest":
|
|
lowest = [None, 0]
|
|
for i in range(0, len(server_list)):
|
|
if lowest[0] is None or\
|
|
typeconv(server_list[i][field]) < lowest[0]:
|
|
lowest[0] = typeconv(server_list[i][field])
|
|
lowest[1] = i
|
|
result = [server_list[lowest[1]]]
|
|
else:
|
|
try: num = typeconv(arg)
|
|
except: return server_list
|
|
for i in range(len(server_list)):
|
|
if typeconv(server_list[i][field]) == num:
|
|
result.append(server_list[i])
|
|
return result
|
|
|
|
class Minetest(callbacks.Plugin):
|
|
"""Adds some Minetest-related commands
|
|
"""
|
|
|
|
thteaded = True
|
|
|
|
def up(self, irc, msg, args, address, portlist):
|
|
"""address [ports]
|
|
|
|
Checks if a Minetest server is up.
|
|
Ports can be in the format port1,port2,port3-port5."""
|
|
if address == None:
|
|
irc.error("Give me a Server Address")
|
|
return
|
|
if not '.' in address:
|
|
irc.error("Invalid Address")
|
|
return
|
|
|
|
if ':' in address:
|
|
try:
|
|
ports = [int(address.split(":")[1])]
|
|
except ValueError: #The string couldn't be converted to an int
|
|
irc.reply("Invalid usage, see help Minetest up")
|
|
return
|
|
address = address.split(":")[0]
|
|
elif portlist is None:
|
|
ports = [30000]
|
|
else:
|
|
ports = self.getPorts(portlist, irc)
|
|
if ports == None:
|
|
return
|
|
|
|
if len(ports) != 1 and irc.isChannel(msg.args[0]):
|
|
irc.reply("To check multiple Ports please use Query")
|
|
return
|
|
if len(ports) > 6:
|
|
irc.error("Too many Ports specified")
|
|
return
|
|
|
|
for port in ports:
|
|
message = self.ServerUp(address, port)
|
|
if message:
|
|
irc.reply(message)
|
|
else:
|
|
irc.reply("Error: Maybe you typed the address wrong?")
|
|
up = wrap(up, ['something', optional('something')])
|
|
|
|
|
|
|
|
def server(self, irc, msg, args, options):
|
|
'''[--{name,address,players,ping,port} <value>]
|
|
|
|
On numeric options like 'ping', 'port' and 'players' <value> can be num, <num, >num, !num, highest, or lowest.
|
|
'''
|
|
data = utils.web.getUrl("http://servers.minetest.net/list")
|
|
server_list = json.loads(data.decode("UTF-8"))["list"]
|
|
|
|
#Run through every filter suplied while we have a result
|
|
for option in options:
|
|
if len(server_list) > 0:
|
|
server_list = self.serverSearchFilters[option[0]]\
|
|
(self.serverSearchFilters, server_list, option[1])
|
|
|
|
if len(server_list) == 0:
|
|
irc.reply("No results.")
|
|
return
|
|
|
|
choice = random.randrange(0, len(server_list))
|
|
|
|
server = server_list[choice]
|
|
|
|
clients = str(server["clients"]) + "/" + str(server["clients_top"])
|
|
|
|
address = server["address"]
|
|
if not server["port"] == "30000":
|
|
address = address + " | Port: " + server["port"]
|
|
|
|
irc.reply("%s | %s | Clients: %s | Version: %s | Ping: %s" %\
|
|
(server["name"], address, clients, server["version"], server["ping"]))
|
|
|
|
server = wrap(server, [getopts({
|
|
#Number values are "something" to allow for <, !, highest, etc.
|
|
"name": "something",
|
|
"address": "something",
|
|
"version": "something",
|
|
"game": "something",
|
|
"players": "something",
|
|
"ping": "something",
|
|
"port": "something"
|
|
})])
|
|
|
|
#--Helpers--#
|
|
|
|
serverSearchFilters = {
|
|
"address": lambda filters, server_list, arg: filters["byName"](server_list, arg, "address"),
|
|
"name": lambda filters, server_list, arg: filters["byName"](server_list, arg, "name"),
|
|
"version": lambda filters, server_list, arg: filters["byName"](server_list, arg, "version"),
|
|
"game": lambda filters, server_list, arg: filters["byName"](server_list, arg, "gameid"),
|
|
|
|
"players": lambda filters, server_list, arg: filters["byNum"](server_list, arg, "clients", int),
|
|
"ping": lambda filters, server_list, arg: filters["byNum"](server_list, arg, "ping", float),
|
|
"port": lambda filters, server_list, arg: filters["byNum"](server_list, arg, "port", int),
|
|
|
|
"byName": filterServersByName,
|
|
"byNum" : filterServersByNum
|
|
|
|
}
|
|
|
|
def ServerUp(self, address, port):
|
|
repres = address + ':' + str(port)
|
|
try:
|
|
start = time.time()
|
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
sock.settimeout(2.5)
|
|
buf = b'\x4f\x45\x74\x03\x00\x00\x00\x01'
|
|
sock.sendto(buf, (address, port))
|
|
data, addr = sock.recvfrom(1000)
|
|
if data:
|
|
peer_id = data[12:14]
|
|
buf = b'\x4f\x45\x74\x03' + peer_id + b'\x00\x00\x03'
|
|
sock.sendto(buf, (address, port))
|
|
sock.close()
|
|
end = time.time()
|
|
return "%s is up (%dms)" % (repres,int((end-start)*1000))
|
|
else:
|
|
return "%s seems to be down " % repres
|
|
except socket.timeout:
|
|
return "%s seems to be down " % repres
|
|
except:
|
|
return None
|
|
|
|
def getPorts(self, port, irc):
|
|
if '-' in port or ',' in port:
|
|
ports = []
|
|
ports_ = port.split(',')
|
|
for p in ports_:
|
|
if '-' in p:
|
|
if len(p.split('-')) != 2:
|
|
irc.error("Invalid Port List")
|
|
return None
|
|
else:
|
|
try:
|
|
a = int(p.split('-')[0])
|
|
except:
|
|
irc.error("Invalid Port: %s" % p.split('-')[0])
|
|
return None
|
|
try:
|
|
b = int(p.split('-')[1]) + 1
|
|
except:
|
|
irc.error("Invalid Port: %s" % p.split('-')[1])
|
|
return None
|
|
for i in range(a, b):
|
|
ports.append(i)
|
|
else:
|
|
try:
|
|
ports.append(int(p))
|
|
except:
|
|
irc.error("Invalid Port: %s" % p)
|
|
return None
|
|
else:
|
|
try:
|
|
ports = [int(port)]
|
|
except:
|
|
irc.error("Invalid port")
|
|
return None
|
|
return ports
|
|
|
|
Class = Minetest
|
|
|