Example #1
1
def get_latency_or_offline(server_ip):
    print("Checking server " + server_ip)
    # noinspection PyBroadException
    try:
        server = MinecraftServer(server_ip)
        # MinecraftServer.lookup(server_ip)
        latency = server.status(retries=1).latency
        print("Server " + server_ip + " is online (latency: " + str(latency) + "ms)")
        return True, latency
    except Exception as e:
        print("Server " + server_ip + " is offline " + str(e))
        return False, str(e)
def bot_online(bot, update, args):
    """Ónline function to check status of a Minecraft server"""
    try:
        chat_id = update.message.chat_id
        address = args[0]
        server = MinecraftServer(address)
        status = server.status()
        bot.sendMessage(
            chat_id=chat_id,
            text=("{0} ({1}) v{2} {3}ms Players online {4}/{5}".format(
                status.description,
                address,
                status.version.name,
                status.latency,
                status.players.online,
                status.players.max
            )))
    except IndexError:
        bot.sendMessage(chat_id=chat_id, text=onlinetext)
    except OSError:
        bot.sendMessage(chat_id=chat_id, text=onlinetext)
Example #3
0
class Minecraft(commands.Cog):
    """Minecraft specific commands."""
    def __init__(self, bot):
        self.bot = bot

        # Get our variables
        self.host = getenv('SERVER_IP')
        self.query_port = int(getenv('QUERY_PORT'))
        self.rcon_port = int(getenv('RCON_PORT'))
        self.rcon_pwd = getenv('RCON_PASSWORD')

        # Init our endpoints
        self.query_server = MinecraftServer(self.host, self.query_port)

    @commands.command(name='test_status',
                      brief="Check our Minecraft server status.")
    @commands.has_permissions(administrator=True)
    async def status(self, ctx):
        """ Get server status """
        status = self.query_server.status()
        await ctx.channel.send(
            f"The server has {status.players.online} players and replied in {status.latency} ms"
        )

    @commands.command(name='msg', brief="Message the server or a player.")
    @commands.has_permissions(administrator=True)
    async def msg(self, ctx, msg=None, player=None):
        """ Message server or a specific player """
        if player is None:
            with MCRcon(host=self.host,
                        password=self.rcon_pwd,
                        port=self.rcon_port) as mcr:
                mcr.command(f"say {msg}")
                await ctx.channel.send(f"Messaged Minecraft server")
        else:
            with MCRcon(host=self.host,
                        password=self.rcon_pwd,
                        port=self.rcon_port) as mcr:
                resp = mcr.command(f"tell {player} {msg}")
                await ctx.channel.send(f"Server response: {resp}")
Example #4
0
def main():

    hostname = socket.gethostname()
    report_url = os.environ['REPORT_ROOMS_URL']
    if not report_url:
        raise Exception('REPORT_ROOMS_URL env var should be set')

    # retry until started
    while 1:
        try:
            # If you know the host and port, you may skip this and use MinecraftServer("example.org", 1234)
            server = MinecraftServer("127.0.0.1", 25565)

            while 1:
                # 'status' is supported by all Minecraft servers that are version 1.7 or higher.
                status = server.status()
                print("[{2}] The server has {0} players and replied in {1} ms".format(
                    status.players.online,
                    status.latency,
                    time.strftime("%d.%m.%Y %H:%M:%S")))
                req = urllib2.Request(report_url)
                data = {
                    'nodes' : [
                        {
                            'nodeId': hostname,
                            'rooms': status.players.online
                        }
                    ]
                }
                req.add_header('Content-Type', 'application/json')
                response = urllib2.urlopen(req, json.dumps(data))
                print('Reported server rooms: {0}'.format(response.info()))
                sleep(5)
        except Exception:
            type, value, traceback = sys.exc_info()
            print("Failed to connect to server {0}. Retrying".format(value))
            sleep(1)
Example #5
0
def getMCStats():
    global server_status
    global server_status_time
    
    server = MinecraftServer("localhost", 25565)

    try:
        javaProcess = getJavaProcess()  
        query = server.query()
        status = server.status()
    except (subprocess.CalledProcessError, socket.gaierror, ConnectionRefusedError, BrokenPipeError, socket.timeout):
        if server_status is not None:
                return {"online": server_status}
        else:
            return {"online": "offline"}

    javaMemory = javaProcess.memory_info().rss
    javaMemory = toSi(javaMemory, 1024)
    javaCPU = javaProcess.cpu_percent()

    size = subprocess.check_output("du -sh {}".format(PATH), shell=True)
    size_rx = re.search("^(.*?)(.)\t", size.decode("UTF-8", errors="replace"))
    size = size_rx.group(1) + " " + size_rx.group(2)

    resp = query.raw
    resp["online"] = "online"
    resp["players"] = query.players.names
    resp["latency"] = status.latency
    resp["minecraft_RAM"] = javaMemory
    resp["minecraft_CPU"] = javaCPU
    resp["minecraft_HDD"] = size

    if server_status == "stopping":
        resp["online"] = server_status

    return resp
Example #6
0
async def status(ctx: commands.Context):
    """Get the status of the server"""
    server = get_volume().server

    if server is not None:
        ip = server.public_net.ipv4.ip
        if server.status == 'running':
            async with ctx.channel.typing():
                try:
                    mc = MinecraftServer(ip)
                    status = mc.status()
                    await ctx.channel.send(
                        f"Minecraft server running at `{ip}`\r\n"
                        f"{status.description['text']} | "
                        f"{status.players.online}/{status.players.max} "
                        f"| {status.version.name}")
                except Exception as e:
                    await ctx.channel.send(
                        f"Server running at `{ip}` but could not read Minecraft status:\r\n`{e}`"
                    )
        else:
            await ctx.channel.send(f"Server `{server.status}` at `{ip}`")
    else:
        await ctx.channel.send(f"No server active")
Example #7
0
class MyClient(discord.Client):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    async def on_ready(self):
        print('Logged in as')
        print(self.user.name)
        print(self.user.id)
        print('------')
        self.channel = self.get_channel(int(
            os.environ['DISCORD_CHANNEL']))  # channel ID goes here
        self.mine_manager = os.environ["MINE_MANAGER"]
        self.mc_server = MinecraftServer(os.environ['MC_SERVER'])
        # await self.channel.send(WELCOME_MSG)
        activity = discord.CustomActivity("Miners: {}".format(0))
        await self.change_presence(status=discord.Status.idle,
                                   activity=activity)
        self.mc_is_up = True
        self.user_count = 0
        self.current_players = set()
        # create the background task and run it in the background
        self.bg_task = self.loop.create_task(self.my_background_task())

    async def my_background_task(self):
        await self.wait_until_ready()
        while not self.is_closed():
            await self.check_server_up()
            if self.is_up:
                await self.check_user_count()
                await self.check_shifts()
            await asyncio.sleep(15)  # task runs every 15 seconds

    async def check_server_up(self):
        change = False
        is_up = False
        # for i in range(0,3):
        try:
            ping = self.mc_server.ping()
            is_up = True
        except:
            pass
        change = self.mc_is_up != is_up
        if change:
            if is_up:
                # server came online
                await self.channel.send(SERVER_UP)
            else:
                await self.channel.send(SERVER_DOWN.format(self.mine_manager))
        self.is_up = is_up

    async def check_user_count(self):
        try:
            status = self.mc_server.status()
        except:
            return
        count = status.players.online
        change = count != self.user_count

        if change:
            status = discord.Status.online
            if count == 0:
                status = discord.Status.idle
            activity = discord.CustomActivity("Miners {}".format(count))
            await self.change_presence(status=status, activity=activity)

    async def check_shifts(self):
        try:
            query = self.mc_server.query()
        except:
            return
        current_players = set(query.players.names)
        diff = current_players - self.current_players
        self.current_players = current_players
        if len(diff) > 0:
            for p in diff:
                await self.channel.send(random.choice(LOGIN_MSG).format(p))
import sys
from mcstatus import MinecraftServer

server = MinecraftServer('minecraft.baffqd.com', 25565)

status = server.status()

print(status.players.online, end='')
sys.stdout.flush()
def get_status(address, port):
    server = MinecraftServer(address, port=25565)
    return server.status()
Example #10
0
class MServer:
    def __init__(self, address_in, port_in, yag_in):
        logging.debug('Initializing server')

        self.bad_internet = None
        if cfg.test_connection:
            self.test_internet()

        self.yag = yag_in
        self.int_server = MinecraftServer(address_in, port_in)
        self.server_info = {}
        self.server_stats = {}

        self.timers = {
            'update timer': None,
            'message timer': None,
            'ping timer': PTimer(15 * 60, None)
        }
        self.uptime = []
        self.downtime = []

        self.last_status = None
        self.reason_offline = None

        # send a first message (will run first update and populate info)
        self.send_message()

        # this uses the initial info and starts the loop
        self.previous_update = self.online()
        self.loop()

    def test_internet(self):
        if self.bad_internet is not None and (time.time() -
                                              self.bad_internet) / 60 < 15:
            logging.debug(
                'Internet already tested bad less than 15 minutes ago')
            return None
        logging.info('Testing internet connection...')
        test = speedtest.Speedtest()
        test.download()
        if test.results.ping > 100 or test.results.download < 1.0e6:
            logging.warning(
                f'Slow internet connection detected: {test.results.ping:.0f} ping {test.results.download / 1.0e6:.2f} Mbps download'
            )
            logging.warning(
                'Server results could be affected by poor internet connection')

            self.bad_internet = time.time()
        else:
            logging.info(
                f'Good internet connection: {test.results.ping:.0f} ping {test.results.download / 1.0e6:.2f} Mbps download'
            )
            self.bad_internet = None

    def loop(self):
        # checks if the status of the server has changed while triggering an update
        if not (self.update() == self.previous_update):
            self.timers['message timer'].cancel()
            # does not update before message sent because there was just an update
            self.send_message(update_before=False)
        # set update timer and previous status
        self.timers['update timer'] = PTimer(cfg.check_interval, self.loop)
        self.previous_update = self.online()

    def update(self, log=True, retries=0):
        logging.debug(f'Contacting Server {cfg.server_address}')
        try:
            self.last_status = self.int_server.status(cfg.fails_required)
        except socket.timeout:
            # this is usually what happens when the server is offline
            self.uptime = []
            self.downtime.append(time.time())
            logging.info('Attempt to contact server timed out')
            self.last_status = None
            self.reason_offline = 'Attempt to contact server timed out'
            return False
        except socket.gaierror:
            # this is usually what happens when the address is incorrect so the program exits
            logging.critical('Unable to resolve server address from config')
            input('Press enter to exit...')
            sys.exit(0)
        except OSError:
            # this usualyl happens when the server is still loading or overloaded
            self.uptime = []
            self.downtime.append(time.time())
            logging.warning('The server responded but not with info')
            time.sleep(2)
            self.last_status = None
            self.reason_offline = 'The server responded but not with info'
            # this retries the check a few times
            if retries < 3:
                return self.update(retries=retries + 1)
            else:
                return None

        self.uptime.append(time.time())
        self.downtime = []
        logging.debug('Contact with server successful')

        if cfg.high_ping is not 0 and self.last_status.latency > cfg.high_ping:
            logging.warning(
                f'High latency detected! ({self.last_status.latency:.1f} ms)')
            if cfg.test_on_high_ping:
                self.test_internet()

            if cfg.text_on_high_ping and self.bad_internet is None and not self.timers[
                    'ping timer'].is_alive():
                subject = f'{cfg.server_address} High Ping!'
                message = []
                if cfg.include_timestamp:
                    message.append(
                        f'[{datetime.now().strftime("%I:%M:%S %p")}]')
                message.append(
                    f'High ping of {self.last_status.latency:.0f} ms detected')
                self.yag.send(cfg.sms_gateway, subject, '\r'.join(message))
                logging.info(f'Sent text to {cfg.phone_str}')
                self.timers['ping timer'] = PTimer(15 * 60, None)

        # tests if this is the first successful contact with the server
        if not self.server_info:
            self.set_server_info()
            # after the server info is initially populated it is printed
            self.print_server_info()

        # if this update is supposed to be logged info is recorded
        if log:
            self.log_stats()

        return True

    def set_server_info(self):
        self.server_info['address'] = f'{cfg.server_address}:{cfg.server_port}'
        if type(self.last_status.description) is str:
            self.server_info['description'] = self.last_status.description
        else:
            self.server_info['description'] = self.last_status.description[
                'text']
        self.server_info['max players'] = self.last_status.players.max
        self.server_info['version'] = self.last_status.version.name
        if len(self.last_status.raw['modinfo']['modList']) > 0:
            self.server_info[
                'version'] += f" - {len(self.last_status.raw['modinfo']['modList'])} mods"
        else:
            self.server_info['version'] += ' - Vanilla'
        # this tests to see if query is enabled and disables player logging if needed
        try:
            query = self.int_server.query()
            self.server_info['query allowed'] = True
            self.server_info['gametype'] = query.raw['gametype']
        except socket.timeout:
            self.server_info['query allowed'] = False
            if cfg.include_player_log:
                logging.error(
                    'Query is not allowed on this server so individual players will not be logged!'
                )
                cfg.try_player_log = False
        # TODO should do a thing here where I record the sample players if query is disabled
        # TODO maybe there should be an option to print the sample players along with the status
        # TODO need to figure out if sample players go in server info or stats
        # TODO probably just make it a regular stats thing

    def log_stats(self):
        if 'pings' not in self.server_stats.keys():
            self.server_stats['pings'] = [{
                'ping': self.last_status.latency,
                'time': time.time()
            }]
        else:
            self.server_stats['pings'].append({
                'ping': self.last_status.latency,
                'time': time.time()
            })

        if 'max online' not in self.server_stats.keys():
            self.server_stats['max online'] = self.last_status.players.online
        else:
            self.server_stats['max online'] = max(
                self.server_stats['max online'],
                self.last_status.players.online)

        if cfg.include_player_log:
            query = self.int_server.query()
            if len(query.players.names) > 0:
                current_players = []
                for player_ob in query.players.names:
                    current_players.append(player_ob.name)

                if 'player summary' not in self.server_stats.keys():
                    self.server_stats['player summary'] = {}

                for player in self.server_stats['player summary'].keys():
                    self.server_stats['player summary'][player].append({
                        'online':
                        player in current_players,
                        'time':
                        time.time()
                    })

                for player in current_players:
                    if player not in self.server_stats['player summary'].keys(
                    ):
                        self.server_stats['player summary'][player] = [{
                            'online':
                            True,
                            'time':
                            time.time()
                        }]

    def print_server_info(self):
        if not self.server_info:
            logging.warning('No server info has been gathered yet')
        else:
            for data in self.server_info.keys():
                logging.info(
                    f'[SERVER INFO] {data.capitalize()}: {self.server_info[data]}'
                )

    def send_message(self, console=True, text=True, update_before=True):
        if update_before:
            self.update()

        # creates message and subject using config
        message = []
        if self.online():
            log_title = '[SERVER ONLINE]'
            subject = f'Status {cfg.server_address}: Online'
            if cfg.include_uptime:
                uptime_msg = f'Uptime: {int((self.get_uptime() - (self.get_uptime() % 86400)) / 86400)} days '
                uptime_msg += f'{(self.get_uptime() % 86400) / 3600:.1f} hrs'
                message.append(uptime_msg)
            if cfg.include_avg_ping:
                message.append(f'Avg ping: {self.get_avg_ping():.0f} ms')
            if cfg.include_max_ping:
                message.append(f'Max ping: {self.get_max_ping():.0f} ms')
            if cfg.include_last_ping:
                message.append(
                    f'Last ping: {self.server_stats["pings"][-1]["ping"]}')
            if cfg.include_max_players:
                message.append(
                    f'Max online: {self.server_stats["max online"]}/{self.server_info["max players"]}'
                )
            if cfg.include_player_log:
                message.append('Players online:')
                if not self.server_stats['player summary']:
                    message.append('None')
                else:
                    for player in self.server_stats['player summary'].keys():
                        message.append(
                            f'\r{player}: {self.get_player_time(player) / 3600:.1f} hrs'
                        )
        else:
            log_title = '[SERVER OFFLINE]'
            subject = f'{cfg.server_address} Status: Offline!'
            if cfg.include_downtime:
                downtime_msg = f'Downtime: {(self.get_downtime() - self.get_downtime() % 86400) / 3600:.1f} days '
                downtime_msg += f'{self.get_downtime() / 3600:.1f} hrs'
                message.append(downtime_msg)
            if cfg.include_fail_reason:
                message.append(self.reason_offline)

        # sends message to log
        if console:
            for line in message:
                logging.info(f'{log_title} {line}')

        # sends message through sms gateway
        if text:
            if cfg.include_timestamp:
                message.insert(0, datetime.now().strftime('%I:%M:%S %p'))
            self.yag.send(cfg.sms_gateway, subject, '\r'.join(message))
            logging.info(f'Sent text to {cfg.phone_str}')

        # clears out temporary data once message is sent
        self.server_stats = {}

        # sets next timer
        if self.timers['message timer'] is not None and self.timers[
                'message timer'].is_alive():
            self.timers['message timer'].cancel()
        if self.online() and cfg.up_text_interval > 0:
            self.timers['message timer'] = PTimer(cfg.up_text_interval,
                                                  self.send_message)
        if not self.online() and cfg.down_text_interval > 0:
            self.timers['message timer'] = PTimer(cfg.down_text_interval,
                                                  self.send_message)

    def online(self):
        return self.last_status is not None

    def get_avg_ping(self):
        if len(self.server_stats['pings']) == 1:
            return self.server_stats['pings'][0]['ping']
        total = 0
        for i in range(len(self.server_stats['pings']) - 1):
            total += self.server_stats['pings'][i]['ping'] * (
                self.server_stats['pings'][i + 1]['time'] -
                self.server_stats['pings'][i]['time'])
        return total / (self.server_stats['pings'][-1]['time'] -
                        self.server_stats['pings'][0]['time'])

    def get_player_time(self, player):
        if len(self.server_stats['player summary'][player]) == 1:
            return 0
        total = 0
        for i in range(len(self.server_stats['player summary'][player]) - 1):
            if self.server_stats['player summary'][player][i]['online']:
                total += self.server_stats['player summary'][player][i + 1]['time'] - \
                         self.server_stats['player summary'][player][i]['time']
        return total / (
            self.server_stats['player summary'][player][-1]['time'] -
            self.server_stats['player summary'][player][0]['time'])

    def get_max_ping(self):
        ping_vals = []
        for point in self.server_stats['pings']:
            ping_vals.append(point['ping'])
        return max(ping_vals)

    def get_uptime(self):
        return self.uptime[-1] - self.uptime[0]

    def get_downtime(self):
        return self.downtime[-1] - self.downtime[0]

    def stop(self):
        for timer in self.timers.keys():
            self.timers[timer].cancel()
Example #11
0
def alsobot_test_callback(room, event):
    server = MinecraftServer(MINECRAFTSERVERNAME)
    status = server.status()
    info_string = "The server has {0} players and replied in {1} ms".format(
        status.players.online, status.latency)
    room.send_text(info_string)
Example #12
0
async def on_message(message):
    msg = message.content
    print(str(message.guild) + " : " + str(message.channel))

    if (msg.split()[0] == "-subscan"):
        domain = msg.split()[1]
        await message.channel.send("> --- Subdomains of " + domain + " ---")
        for subdomain in subdomains:
            try:
                fullsub = str(subdomain) + "." + str(domain)
                ipofsub = socket.gethostbyname(str(fullsub))

                await message.channel.send("> " + fullsub + " - " + ipofsub)
            except:
                pass

    if (msg.split()[0] == "-dedscan"):
        domain = msg.split()[1]
        await message.channel.send("> --- Dedicated servers of " + domain +
                                   " ---")

        ip_list = []
        ais = socket.getaddrinfo(domain, 0, 0, 0, 0)
        for result in ais:
            ip_list.append(result[-1][0])
            ip_list = list(set(ip_list))

        for x in range(len(ip_list)):
            await message.channel.send("> " + ip_list[x])

    if (msg.split()[0] == "-help"):
        await message.channel.send(
            "```css\n--- [Comandos ToxicBot] ---\n--- By [Niki#8160] ---\n \nPrefix: -\n \n-subscan [dominio]: Escanea subdominios de ese dominio\n-dedscan [dominio]: Muestra los servidores dedicados de ese dominio\n-sqliscan [url]: Escanea la url para encontrar vulnerabilidades sql injection```"
        )

    if (msg.split()[0] == "-sqliscan"):
        url = msg.split()[1]
        if (url[len(url) - 1]) != "/":
            url += "/"

        await message.channel.send("> --- Vulnerable pages of " + url + " ---")

        f = open("keywords.txt", "r")
        keywords = f.readlines()
        f.close()

        working = []

        for x in range(len(keywords)):
            keywords[x].replace("\n", "")

        for x in range(len(keywords)):
            keyword = keywords[x].replace("\n", "")
            keywordurl = url + keyword + ".php?id=" + str(
                random.randint(1, 100))
            if (check(keywordurl)):
                working.append(keywordurl)
                print("Working: " + keywordurl)
                await message.channel.send("> Found: " + keywordurl)
            else:
                print("Not working: " + keywordurl)

        if (len(working) == 0):
            await message.channel.send("> No vulnerable pages were found!")

    if (msg.split()[0] == "-ipinfo"):
        ip = msg.split()[1]

        await message.channel.send("> --- Info of " + ip + " ---")

        proc = subprocess.Popen(["curl", "ipinfo.io/" + ip],
                                stdout=subprocess.PIPE,
                                shell=True)
        (out, err) = proc.communicate()
        out = out.decode().replace("\n", "").replace("{", "").replace(
            "}", "").replace('"', "")

        if ("Wrong ip" in out):
            proc2 = subprocess.Popen(
                ["curl", "ipinfo.io/" + socket.gethostbyname(ip)],
                stdout=subprocess.PIPE,
                shell=True)
            (out, err) = proc2.communicate()
            out = out.decode().replace("\n", "").replace("{", "").replace(
                "}", "").replace('"', "")

        info = out.split(",")

        for x in range(len(info)):
            if (info[x].split()[0] != "readme:"):
                await message.channel.send("> " + info[x])

    if (msg.split()[0] == "!kickall"):
        ip = msg.split()[1]
        port = int(msg.split()[2])
        profiles = []
        factories = []

        await message.channel.send("> Connecting...")
        server = MinecraftServer(ip, port)

        await message.channel.send("> Getting status...")
        status = server.status()

        await message.channel.send("> Getting players...")
        print(status.description)
        players = status.description

        await message.channel.send("> Kicking all players...")

        for x in range(len(players)):
            profiles.append(OfflineProfile(players[x]))
            factories.append(BotClientFactory(profiles[x]))
            factories[x] = factories[x].connect(ip, port)

        reactor.run()

        await message.channel.send("> Kickall completed!")
Example #13
0
from mcstatus import MinecraftServer
import time
from subprocess import call
import os

# Wait for the server to start
print('Waiting for server to go live')
while True:
    time.sleep(5)
    try:
        server = MinecraftServer('localhost', 25565)
        mc_status = server.status()
        break
    except:
        print('Server is down - current time: ' + str(int(time.time())))

print('Server is live, checking player counts')
player_last_seen = int(time.time())

while True:
    time.sleep(5)

    # Get the server player count
    try:
        server = MinecraftServer('localhost', 25565)
        mc_status = server.status()
        player_count = mc_status.players.online
    except:
        print('Server is down - current time: ' + str(int(time.time())))
        player_count = 0
Example #14
0
async def on_message(message):
    #Variable set up
    global storedStats, storedEmojiUnique, storedEmojiUniversal
    #Used for user identification
    isVerified = "false"
    isAdmin = "false"
    #Address to server
    mcServer = MinecraftServer(IP, PORT)

    #If the bot sent the message, ignore
    if message.author == client.user:
        return

    #Determines user permissions(will later check agaisnt role name)
    for item in message.author.roles:
        if (str(item) == "Minecraft"):
            isVerified = "true"
        if (str(item) == "ADMIN"):
            isAdmin = "true"

    #Depending on which server the message was in: what emoji set should be used
    if str(message.guild.id) == str(UNIQUE_SERVER):
        animatedEmoji = storedEmojiUnique
    else:  #All other servers use the generic set
        animatedEmoji = storedEmojiUniversal

    #Show info about the minecraft server
    if message.content.lower() == "!mc":
        if (isVerified == "true"):
            try:
                status = mcServer.status()
                query = mcServer.query()
                players = query.players.online
                if players == 0:
                    await message.channel.send(
                        "The server is Online with no active players")
                elif players == 1:
                    await message.channel.send(
                        "The server is Online with 1 active player: {}".format(
                            ", ".join(query.players.names)))
                elif players > 1:
                    await message.channel.send(
                        "The server is Online with {} active players: {}".
                        format(players, ", ".join(query.players.names)))
            except ConnectionError:
                await message.channel.send(
                    "Server is Offline (Unless it has just been booted up)")
        else:
            await message.channel.send("You do not have permission to do that")

    #Run the mc server, if it is not running
    if message.content.lower() == "!mcstart":
        if (isVerified == "true"):
            try:
                status = mcServer.status()
                await message.channel.send("The server is already Online!")
            except ConnectionError:
                os.system(
                    '(cd {}; ./{})'.format(MC_FOLDER, MC_RUNNABLE_SCRIPT)
                )  #Run a script that will correctly start your server
                await message.channel.send(
                    "Server is Offline. Bootup has started, it usually takes up to about 2 minutes to finish booting and become visible online so please be patient"
                )
                return
            return
        else:
            await message.channel.send("You do not have permission to do that")

    #Stop the mc server, if it is empty
    if message.content.lower() == "!mcstop":
        if (isVerified == "true"):
            try:
                status = mcServer.status()
                players = status.players.online
                if players > 0:
                    await message.channel.send(
                        "The server still has players on it! The server must be empty before shutdown can happen"
                    )
                else:
                    with open(
                            "{}".format(PID_TXT), "r"
                    ) as myfile:  #path to text file that stores the PID of the minecraft server, so that the server can be told to shut down
                        pid = myfile.read()
                    os.system("kill -15 {}".format(pid))
                    await message.channel.send("Server has shut down")
            except ConnectionError:
                await message.channel.send(
                    "The server is already Offline (Or if you just booted it up, hasn't come Online yet)"
                )
        else:
            await message.channel.send("You do not have permission to do that")

    #Splits the message, so the first word can be matched to a command, and use the rest of the words as parameters
    splitMessage = message.content.lower().split()
    if (len(splitMessage) == 2):  #If the command has a parameter
        if (splitMessage[0] == "!react"):
            for emoji in animatedEmoji:
                if splitMessage[1] == emoji:
                    await message.delete()
                    async for react in message.channel.history(limit=1):
                        await react.add_reaction(animatedEmoji[emoji])
                        return
            return

        if (splitMessage[0] == "!delete"):
            if (isAdmin == "true"):
                #This can be optimized by sending a batch delete rather then increment once
                #It's somehwere in the discord.py api
                async for delete in message.channel.history(
                        limit=(int(splitMessage[1]) + 1)):
                    await delete.delete()
                return
            else:
                message.channel.send('You do not have permission to do that')
                return

        if (splitMessage[0] == '!attack'):
            #A little game where users can attack eachother
            #These variable names NEED to be cleaned up
            messageParameter = splitMessage[1]
            targetUserID = [
                messageParameter[:2], messageParameter[2:-1],
                messageParameter[-1:]
            ]  #This isolates just the ID number of the targeted user
            if targetUserID[
                    1][:
                       1] == '!':  #Sometimes discord leaves an ! in the id, but sometimes not. Not sure why but this purges it as it causes bugs with storing data(duplicated users)
                targetUserID[1] = targetUserID[1][1:]
            if targetUserID[0] == '<@' and targetUserID[
                    2] == '>':  #After formatting the code, if it is correctly formatted
                if int(targetUserID[1]) == int(
                        client.user.id
                ):  #Checks if it was the bot that was targeted in the attack
                    await message.channel.send(
                        '<a:angryAwooGlitch:691087516819914772>')
                    return
                damage = random.randint(1, 29)
                if str(message.author.id) not in storedStats:
                    storedStats[str(message.author.id)] = {
                        'hp': 50,
                        'damage': 0,
                        'deaths': 0
                    }
                elif str(targetUserID[1]) not in storedStats:
                    storedStats[str(targetUserID[1])] = {
                        'hp': 50,
                        'damage': 0,
                        'deaths': 0
                    }

                storedStats[str(targetUserID[1])]['hp'] -= damage
                if storedStats[str(targetUserID[1])]['hp'] <= 0:
                    storedStats[str(targetUserID[1])]['deaths'] += 1
                    storedStats[str(targetUserID[1])]['hp'] = 50
                    if str(message.author.id) == str(targetUserID[1]):
                        await message.channel.send(
                            '<a:blobhang:691023822576549930>')
                        await message.channel.send(
                            '<@{}> killed themselves'.format(message.author.id)
                        )
                        return
                    await message.channel.send('<:killed:690998665686548483>')
                    await message.channel.send(
                        '<@{}> dealt {} damage, killing {}!'.format(
                            message.author.id, '{:,}'.format(damage),
                            messageParameter))
                    storedStats[str(message.author.id)]['damage'] += damage
                else:
                    await message.channel.send(
                        'You dealt {0} damage to {1}\n{1} has {2} HP remaining'
                        .format(
                            '{:,}'.format(damage), messageParameter,
                            '{:,}'.format(
                                (storedStats[str(targetUserID[1])]['hp']))))
                    storedStats[str(message.author.id)]['damage'] += damage
            return

    if splitMessage[0] == '!roll':
        if len(splitMessage) == 2:
            await message.channel.send("<@{}> rolled a {}".format(
                message.author.id, random.randint(1, int(splitMessage[1]))))
        else:
            await message.channel.send(
                "Type a space and a number after !roll to roll a dice that size"
            )
        return

    if message.content.lower() == '!stats':
        if str(message.author.id) not in storedStats:
            storedStats[str(message.author.id)] = {
                'hp': 50,
                'damage': 0,
                'deaths': 0
            }
        await message.channel.send(
            '<@{}>\nHP: {}\nDamage Dealt: {}\nDeaths: {}'.format(
                str(message.author.id),
                '{:,}'.format(storedStats[str(message.author.id)]['hp']),
                '{:,}'.format(storedStats[str(message.author.id)]['damage']),
                '{:,}'.format(storedStats[str(message.author.id)]['deaths'])))

    if message.content.lower() == '!save' and (isAdmin == "true"):
        with open('attacks.json', 'w') as fp:
            json.dump(storedStats, fp)
        print("data saved to server")
        await message.channel.send("data saved to server")

    if message.content.lower() == '!load' and (isAdmin == "true"):
        jsonFile = open('attacks.json')
        jsonStr = jsonFile.read()
        storedStats = json.loads(jsonStr)
        print("save data loaded")
        await message.channel.send("save data loaded")

    if message.content.lower() == '!flip':
        if random.randint(1, 2) == 1:  #heads
            await message.add_reaction('👧')  #react heads
        else:
            await message.add_reaction('🐀')  #react tails
        return

    if message.content.lower() == '!list':
        listedEmoji = ''  #initializes the variable so that values can be 'added' into it
        for key in animatedEmoji:
            listedEmoji += '{} --> {}\n'.format(key, animatedEmoji[key])
        await message.channel.send(listedEmoji)
        return

    #The following searches the user's message to see if any of the custom emoji set matches
    #If it does then it will replace it, and resend the message on behalf of the user
    #	while also deleting the original users message
    #To identify the original user who sent the message, it also @'s them
    modifiedMessage = message.content
    switchFlag = 0  #A flag that determines of a match was made, and if the users message should be replaced
    for key in animatedEmoji:
        matchCheck = re.search(
            re.escape(key), message.content,
            flags=re.I)  #Check if the message has a replacable emoji
        if (str(matchCheck) != "None"):
            modifiedMessage = re.sub(re.escape(key),
                                     animatedEmoji[key],
                                     modifiedMessage,
                                     flags=re.I)
            switchFlag = 1  #sets a flag that a match was made, and should replace the message
    if switchFlag == 1:  #ONLY replace if a match was found
        await message.channel.send('<@{}>:'.format(message.author.id))
        await message.delete()
        await message.channel.send(modifiedMessage)
Example #15
0
async def on_message(message):
    """On message portion, most of the actual programming is in this function."""
    if message.author == client.user:
        return

    msgSplit = message.content.split()
    #If the message content is **only** an image, this
    #prevents an error message from clogging the console.
    try:
        msgSplit[0]
    except IndexError:
        return

    #Makes cBasePrompt = 0 usable
    if cBasePrompt == "0":
        cPrompt = '<@' + str(client.user.id) + '>'
    else:
        cPrompt = cBasePrompt

    #Detects if the bot was called
    if msgSplit[0] == cPrompt:

        #<prompt> help - Lists commands
        if msgSplit[1].lower() == 'help':
            await message.channel.send('''The commands available are:
{0} Help - Displays this message
{0} List - List the players online at {1}
{0} Ping - Ping the bot
{0} Source - Github Source Code'''.format(cPrompt, cIP))

        #<prompt> ping - Pings the bot
        if msgSplit[1].lower() == 'ping':
            await message.channel.send('Pong!')
            print('Pong\'ed user ' + str(message.author)
                  + ' :: ' + str(getTime()))

        #<prompt> list - Lists players online. Only the amount is
        #listed if cEnableNames is False
        if msgSplit[1].lower() == 'list':
            mcServer = MinecraftServer(cIP, cPort)
            serverStatus = mcServer.status()

            if serverStatus.players.online == 0:
                if cSkipNoPlayers is False:
                    await message.channel.send(cNoPlayers.format(cIP))

            elif cEnableNames is True and '{1}' in cMessageSend:
                if serverStatus.players.online != 0:
                    onPlayers = serverStatus.players.online
                    mcQuery = mcServer.query()
                    await messagge.channel.send(cMessageSend.format(onPlayers,
                                                ", ".join(mcQuery.players.names), cIP))

            else:
                await message.channel.send(cMessageSend.format(serverStatus.players.online))

        #<prompt> source - Github link
        if msgSplit[1].lower() == 'source':
            await message.channel.send('''MCPD v2.0, licensed under the MIT license.
Full source code at:
https://github.com/SuperShadowPlay/MCPD''')
            print(str(message.author) + ' Requested Source :: ' + getTime())
Example #16
0
class MinecraftStatus():
    def __init__(self, serverUrl, localIp, rconPort, queryPort, rconPassword):
        self.serverUrl = serverUrl
        self.localServer = MinecraftServer(localIp, queryPort)
        self.urlServer = MinecraftServer(serverUrl, queryPort)
        self.rcon = MCRcon(localIp, rconPassword, port=rconPort)
        self.previousPlayerAmountOnline = None
        self.rconConnect()

    def rconConnect(self):
        try:
            self.rcon.connect()
        except ConnectionRefusedError:
            logger.error("RCON Connection refused")
        except:
            logger.error("Unexpected error while trying to connect to RCON")

    def generateStatus(self):
        tps = ""
        urlLatency = -1
        localLatency = -1
        playerAmountOnline = -1
        maxPlayerAmount = -1
        playerList = ""
        mapName = ""

        try:
            urlStatus = self.urlServer.status()
            urlLatency = str(urlStatus.latency)
        except:
            logger.error("Error while contacting server over url")

        try:
            localStatus = self.localServer.status()
            localLatency = str(localStatus.latency)
            playerAmountOnline = localStatus.players.online
            maxPlayerAmount = localStatus.players.max
            players = localStatus.players.sample
            if playerAmountOnline > 0:
                for player in players:
                    playerList += player.name + ", "
                playerList = playerList[:-2]  # Remove last comma
                playerList += "."
        except:
            logger.error("Error getting local server status")

        try:
            tps = self.rcon.command("tps")
        except:
            logger.error("Rcon connection failed")
            self.rconConnect()
        tps = tps[29:]
        tps = tps.replace('§a', '')

        response = "```"
        response += 'Status report for ' + self.serverUrl + ': \n'
        if urlLatency != -1:
            response += "The server replied over DNS in " + \
                str(urlLatency) + 'ms\n'
        else:
            response += "The server did not reply over DNS\n"
        if localLatency != -1:
            response += "The server replied over the local network in " + \
                str(localLatency) + " ms\n"
            if playerAmountOnline > 0:
                response += "The server has " + \
                    str(playerAmountOnline) + "/" + \
                    str(maxPlayerAmount) + " players online.\n"
                response += "Online players: " + playerList + "\n"
            else:
                response += "No players are currently playing. Please do something about that :)\n"
            response += "The TPS for the server (1m,5m,15m) are: " + tps + "\n"
        else:
            response += "The server did not reply over the local network\n"
        response += "```"
        return response

    async def watch(self, sendNotifications):
        if self.previousPlayerAmountOnline is None:
            self.previousPlayerAmountOnline = self.localServer.status(
            ).players.online
            logger.debug("Initting prev players online")
        while True:  # TODO: add stop flag
            localStatus = self.localServer.status()
            playerAmountOnline = localStatus.players.online
            if playerAmountOnline != self.previousPlayerAmountOnline:
                logger.debug("Playercount changed!")
                self.previousPlayerAmountOnline = playerAmountOnline
                if playerAmountOnline == 1:
                    await sendNotifications(
                        "Someone started playing on the server :D")
                elif playerAmountOnline == 0:
                    await sendNotifications(
                        "Awh, the server is all empty now :(")
            await asyncio.sleep(0.5)

    def say(self, message):
        self.command("say " + message)

    def command(self, message):
        try:
            self.rcon.command(message)
        except BrokenPipeError:
            logger.error("No Pipe for RCON command")
            self.rconConnect()
Example #17
0
def get_nr_players():
    from mcstatus import MinecraftServer
    server = MinecraftServer(HOST, PORT)
    return server.status().players.online
Example #18
0
def getMCServerData():
    cfg.debug(f"getMCServerData", DEBUG)
    # get mc server info
    mcServer = "minecraft.tas.qld.edu.au"
    conn = create_connection(cfg.DB)
    sql = "SELECT MAX(maxPing), date from ping"
    cfg.debug(sql, DEBUG)

    cur = conn.cursor()
    cur.execute(sql)
    maxPing = cur.fetchone()[0]

    sql = "SELECT COUNT(name) FROM members"
    cur.execute(sql)
    count = cur.fetchone()[0]

    try:


        server = MinecraftServer(mcServer)
        status = server.status()

        latency = status.latency

        playersOnLine = status.players.online
        playersMax = status.players.max

        query = server.query()
        playersList = query.players.names
        cfg.debug(f"Playerlist: {playersList}", DEBUG)

        now = datetime.datetime.now()
        # get max ping from db.



        if latency > maxPing:
            sql = f"INSERT INTO ping (maxPing, date) VALUES ({status.latency}, '{now}')"
            cfg.debug(sql , DEBUG)
            cur.execute(sql )
            conn.commit()
            maxPing = f"{latency} ms"

        percent = math.floor(playersOnLine / playersMax * 100)

    except Exception as e:
        cfg.debug(f"MC error {e}", True)
        playersList = []
        playersOnLine = 0
        playersMax = 20
        percent = 0
        latency = "OFFLINE"
        count = 0


    # listOfPlayers = "THIS WILL BE A LIST OF ALL PLAYERS"
    serverData = {
        "ip": mcServer,
        "latency": f"{latency} ms",
        "playersList": playersList,
        "playerCount": playersOnLine,
        "playersMax": playersMax,
        "percent": percent,
        "maxPing": f"{maxPing} ms",
        "docLink": latestDoc,
        "discord": discordInvite,
        "members": count
    }
    cfg.debug(f"mc server data: {serverData} ", True)
    return serverData
Example #19
0
class Server:
    def __init__(self):
        self.name = ''
        self.GameName = ''
        self.nameArray = []
        self.idleName = ''
        self.minecraftserver = None
        self.timer = 0

    async def run(self, ctx, macadress):
        if self.name in minecraftNameArray:
            send_magic_packet(macadress)
            self.GameName = 'Minecraft'
            self.nameArray = minecraftNameArray
            self.idleName = 'Minecraft'
            embed = discord.Embed(title=f'Abriendo server de {self.GameName}',
                                  colour=discord.Color.blue(),
                                  description='Puede tardar un poco...')
            embed.set_image(
                url=
                'https://i.pinimg.com/originals/02/a3/09/02a3098f242e38c1b8e76c37bbd3c5d6.gif'
            )

            message = await ctx.send(embed=embed)
            await asyncio.sleep(5)
            p = subprocess.Popen("RunMinecraftServer.bat",
                                 stderr=subprocess.PIPE,
                                 stdout=subprocess.PIPE,
                                 text=True)
            err = p.communicate()[1]
            if err[2:35] == 'remote_abrir_mcserver.bat started':
                embed = discord.Embed(
                    title=f'Servidor de Minecraft abierto :white_check_mark:',
                    colour=discord.Color.green())
                embed.set_image(
                    url=
                    'https://media1.tenor.com/images/b5947d684ea4b0f0ed083c0b217fb76e/tenor.gif?itemid=15531052'
                )
                await message.edit(embed=embed)
                self.minecraftserver = MinecraftServer(localServerIp)

            else:
                raise er.CantAccessRemoteServer

        elif self.name in conanExilesNameArray:
            # subprocess.Popen("RunConanExilesServer.bat")
            # self.GameName = 'Conan Exiles'
            raise er.ServerNotYetImplemented
        elif self.name in killingFloorNameArray:
            # subprocess.Popen("RunKillingFloorServer.bat")
            # self.GameName = 'Conan Exiles'
            raise er.ServerNotYetImplemented
        else:
            raise er.UnexpectedRunError

    async def stop(self, ctx, client):  # noqa
        if self.GameName == 'Minecraft':
            if await self.isNotEmpty():
                raise er.CantClosePopulatedServer
            with MCRcon(localServerIp, rconPass) as mcr:
                mcr.command("stop")

            embed = discord.Embed(
                title=f'Cerrando server de {self.GameName}...',
                colour=discord.Color.orange())
            embed.set_image(
                url=
                'https://media1.tenor.com/images/217c1afecaa90100c7796949ee045173/tenor.gif'
            )
            message = await ctx.send(embed=embed)
            while True:
                await asyncio.sleep(5)
                try:
                    self.minecraftserver.status()
                except socket.timeout:
                    break
            try:
                await self.removeFromActiveServers()
            except ValueError:
                await ctx.send("Este servidor no está abierto.")
                return

            embed = discord.Embed(title=f'Server de {self.GameName} cerrado.',
                                  colour=discord.Color.green())
            embed.set_image(
                url=
                'https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/284b6a8e-dc16-4274-bab4-ce7f8d872263'
                '/d6byo72-78d16a50-a398-4176-ae84-72c6083b50a7.png?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9'
                '.eyJzdWIiOiJ1cm46YXBwOiIsImlzcyI6InVybjphcHA6Iiwib2JqIjpbW3sicGF0aCI6IlwvZlwvMjg0YjZhOGUtZGMxNi'
                '00Mjc0LWJhYjQtY2U3ZjhkODcyMjYzXC9kNmJ5bzcyLTc4ZDE2YTUwLWEzOTgtNDE3Ni1hZTg0LTcyYzYwODNiNTBhNy5wbmc'
                'ifV1dLCJhdWQiOlsidXJuOnNlcnZpY2U6ZmlsZS5kb3dubG9hZCJdfQ.qiOeCjNfyNe3RQ7FZekhvvvKTlc1K'
                '5BmTdDG75tQSVY')
            await message.edit(embed=embed)
            if not activeServers:
                current_status = 'Servers Cerrados'
                discord_status = discord.Status.idle
                await client.change_presence(
                    status=discord_status,
                    activity=discord.Game(name=current_status))
            loop = asyncio.get_event_loop()
            await loop.run_in_executor(ThreadPoolExecutor(), sleepserverpc)

    async def playerlist(self):  # noqa
        if self.GameName == 'Minecraft':
            try:
                query = self.minecraftserver.query()
            except socket.timeout:
                await self.removeFromActiveServers()
                raise er.ServerIsNotRunning
            playerlist = query.players.names
            return playerlist

    async def isNotEmpty(self):  # noqa
        if self.GameName == 'Minecraft':
            try:
                status = self.minecraftserver.status()
            except socket.timeout:
                await self.removeFromActiveServers()
                raise er.ServerIsNotRunning
            if status.players.online == 0:
                return False
            else:
                return True

    async def playerCount(self):  # noqa
        if self.GameName == 'Minecraft':
            try:
                status = self.minecraftserver.status()
            except socket.timeout:
                await self.removeFromActiveServers()
                return
            return status.players.online

    async def removeFromActiveServers(self):  # noqa
        for server in activeServers:
            if server.GameName == self.GameName:
                activeServers.remove(server)

    async def shutdown(self):
        if self.GameName == 'Minecraft':
            if await self.isNotEmpty():
                self.timer = 0
                return
            with MCRcon(localServerIp, rconPass) as mcr:
                mcr.command("stop")
            while True:
                await asyncio.sleep(5)
                try:
                    self.minecraftserver.status()
                except socket.timeout:
                    break
            try:
                await self.removeFromActiveServers()
            except ValueError:
                return
            loop = asyncio.get_event_loop()
            await loop.run_in_executor(ThreadPoolExecutor(), sleepserverpc)
Example #20
0
async def on_disconnect():
    takenGuild = bot.get_guild(843707273087549450)
    channel = takenGuild.text_channels
    nameChannel = None
    for x in channel:

        if x.name == "cập-nhật-thông-tin-server":
            nameChannel = x
            break

    A_mgs = []  #Empty list to put all the messages in the log
    async for x in nameChannel.history(limit=100):
        A_mgs.append(x)
    await nameChannel.delete_messages(A_mgs)

    date_time_now = datetime.datetime.now()
    date_time_now = str(date_time_now)
    date_time_now = date_time_now[:19] + date_time_now[26:]
    msg = ""
    status = None
    statusNgrok_str = None
    statusServer_str = None
    players = 0
    latency = 0
    res = 0

    try:
        res = urllib.request.urlopen("http://localhost:4040/status").getcode()
    except:
        res = 0

    if res == 200:

        os.system("curl  http://localhost:4040/api/tunnels > tunnels.json")

        with open('tunnels.json') as data_file:
            datajson = json.load(data_file)

        msg_spilt = []
        for i in datajson['tunnels']:
            if (str(i['name']) == "minefc"):
                msg = msg + i['public_url']
                msg = msg.replace("tcp://", "")
        msg_spilt = msg.split(":")
        msg = "IP hiện tại của server : " + msg
        try:
            server = MinecraftServer(msg_spilt[0], int(msg_spilt[1]))
            status = server.status()
            players = status.players.online
            latency = status.latency

            statusServer_str = "<:greendot:844047684955799572> đang hoạt động"
            statusNgrok_str = "<:greendot:844047684955799572> đang hoạt động"
        except:
            statusServer_str = "<:reddot:844050179845652530> đã dừng"
            statusNgrok_str = "<:greendot:844047684955799572> đang hoạt động"
    else:
        statusServer_str = "<:reddot:844050179845652530> đã dừng"
        statusNgrok_str = "<:reddot:844050179845652530> đã dừng"

    embed = discord.Embed(
        title=f"{msg}",
        description=
        f"Tình trạng Server Minecraft: {statusServer_str}\n>>>Hiện tại đang có {players}/174 người chơi đang online.\n>>>Ping : {latency} ms\nTình trạng Ngrok: {statusNgrok_str}\nTự động cập nhật sau mỗi 10s.\nNgoài ra bot còn nhiều lệnh khác, nhập !help để biết thêm chi tiết!",
        color=0x00ff00)
    embed.set_footer(
        text=
        f" Made by TKG - {date_time_now} - Theo múi giờ UTC+7 của Đông Lào",
        icon_url=bot_ava)

    embed = await nameChannel.send(embed=embed)
Example #21
0
#!/usr/bin/env python3
import sys, cgi, socket

from mcstatus import MinecraftServer

AVATAR_URI = 'https://crafatar.com/avatars/{}.png'

if len(sys.argv) < 3:
    print(f'usage: {sys.argv[0]} host port', file=sys.stderr)
    exit()

print('<div class="serverStatus">')

server = MinecraftServer(sys.argv[1], int(sys.argv[2]))
try:
    stat = server.status()
except (ConnectionError, socket.error):
    print(
        f'<div class="error">The server at {cgi.escape(sys.argv[1])}:{sys.argv[2]} appears to be down.</div>'
    )
else:
    print(
        f'<div class="statusLine"><span class="serverName">{cgi.escape(stat.description)}</span> is up: <span class="online">{stat.players.online}</span>/<span class="max">{stat.players.max}</span> players</div>'
    )
    if stat.players.online:
        print('<div class="players">')
        for player in stat.players.sample:
            print(
                f'\t<div class="player"><img src="{AVATAR_URI.format(player.id)}"/><p class="name">{cgi.escape(player.name)}</p></div>'
            )
        print('</div>')
Example #22
0
from mcstatus import MinecraftServer

# Server details.
server_hostname = "mc.mxc42.com"
server_port = 4242

# Make a server object with the right connection properties.
server = MinecraftServer(server_hostname, server_port)

# 'query' has to be enabled in a servers' server.properties file.
# It may give more information than a ping, such as a full player list or mod information.
query = server.status()

print(query.players.online)
class Server:
    def __init__(self,
                 ip,
                 port,
                 api_port,
                 node_id,
                 api_player_team=None,
                 reattach=False,
                 config=os.path.join(ROOT_DIR, 'configs/azurebatch.cfg')):
        if api_player_team is None:
            api_player_team = {}
        self.ip = ip
        self.port = port
        self.api = api_port
        self.node_id = node_id
        self.config = configparser.ConfigParser()
        self.config.read(config)
        self.id = f"{self.ip}:{self.port}"
        self.teams = []
        self.players = []
        self.player_team = {}
        self.master_player_team_map = api_player_team
        self.playercount = 0
        if not reattach:
            self.state = Server.State.INITIALIZING
        else:
            self.state = Server.State.STABLE
        self.last_request_time = None

        self.countfailures = 0
        self.maxFailsBeforeDown = 13
        self.mcServer = MinecraftServer(self.ip, self.port)

    def __hash__(self):
        return self.node_id.__hash__()

    def __lt__(self, other):
        if isinstance(other, Server):
            return self.playercount < other.playercount
            # if self.ip == other.ip:
            #     return self.port < other.port
            # else:
            #     return self.ip < other.ip
        else:
            raise ArithmeticError

    def __eq__(self, other):
        if isinstance(other, Server):
            return self.id == other.id
        elif isinstance(other, str):
            return self.id == other
        else:
            return False

    def eligible_for_new_teams(self):
        if self.state == Server.State.STABLE and len(self.teams) < int(
                self.config.get('SERVER', 'maxTeamsPerServer')):
            return True
        else:
            return False

    def is_ready(self):
        if self.state < Server.State.STABLE:
            return False
        return True

    def _is_mc_alive(self):
        #  Check to see if the server is up yet:
        # srv = MinecraftServer(self.ip, self.port)
        stat = ""
        try:
            stat = self.mcServer.status()
            if len(stat.raw) > 0:
                self.countfailures = 0
                return True
            # if (stat.raw['players']['online'] >= 0):
            #     self.countfailures = 0
            #     return True
            # Continue onwards and update the player lists!
        except timeout:
            # The Server is not up yet.
            print(f"[IsAlive]Server can't be accessed yet")
            self.countfailures += 1

        except KeyError:
            # The status return doesn't have a players or online segment
            print(f"Something weird with Status response: {stat.raw}")

        except ConnectionRefusedError:
            print(f"Err: Connection Refused? Is Alive {self.ip}:{self.port}")
            self.countfailures += 1

        except OSError:
            print(f"Err: OS Error - no response: {self.ip}:{self.port}")
            self.countfailures += 1

        except Exception as e:
            print(f"Err: Something else happened:{self.ip}:{self.port} \n {e}")
            self.countfailures += 1

        return False

    def _get_team_for_player(self, playerName):
        if self.master_player_team_map is not None:
            if playerName.lower() in self.master_player_team_map.keys():
                return self.master_player_team_map[playerName.lower()]
        return -1

    def poll(self):
        print(f"{datetime.datetime.now()} Running Poll: {self.id}")
        if self.state == Server.State.INITIALIZING:
            #  Check to see if the server is up yet:
            if self._is_mc_alive():
                self.state = Server.State.STABLE
            elif self.countfailures > self.maxFailsBeforeDown * 2:
                self.state = Server.State.CRASHED
            return

        if self.state == Server.State.STABLE or self.state == Server.State.WAITING_FOR_MERGE:
            # Check if the server is still up. Update the active player lists
            # srv = MinecraftServer(self.ip, self.port)
            stat = ""
            try:
                stat = self.mcServer.status(tries=10)

                self.playercount = stat.players.online
                playersdetected = {}
                if stat.players.sample is not None:
                    for player in stat.players.sample:
                        playersdetected.update({player.id: player.name})

                # Update player and team arrays
                self.player_team = {
                    player: team
                    for player, team in self.player_team.items()
                    if player in playersdetected.keys()
                }

                if len(self.player_team) < len(playersdetected):
                    players_to_search = {
                        player: name
                        for player, name in playersdetected.items()
                        if player not in self.player_team
                    }
                    for player, name in players_to_search.items():
                        team2 = self._get_team_for_player(name)
                        self.player_team.update({player: team2})

                self.players = list(self.player_team.keys())
                self.playercount = len(self.players)
                self.teams = list(set(self.player_team.values()))
                self.countfailures = 0

                self.check_is_server_api_alive()

                return

            except timeout:
                # The Server is not up yet.
                print(f"Error! Is Server Down?")
                self.countfailures += 1
                # self.state = Server.State.CRASHED

            except ConnectionRefusedError:
                print(
                    f"Err: Connection Refused - state STABLE? {self.ip}:{self.port}"
                )
                self.countfailures += 1
                # self.state = Server.State.CRASHED

            except KeyError:
                # The status return doesn't have a players or online segment
                print(f"Something weird with Status response: {stat.raw}")
                # self.countfailures += 1

            except Exception as e:
                print(f"Something else went wrong... {e}")
                self.countfailures += 1

            if self.countfailures > self.maxFailsBeforeDown:
                self.state = Server.State.CRASHED
            return

        if self.state == Server.State.STABLE_BUT_TASK_FAILED:
            # Ping the API port to see if its back up!
            self.check_is_server_api_alive()

            stat = ""
            try:
                stat = self.mcServer.status()

                self.playercount = stat.players.online
                playersdetected = {}
                if stat.players.sample is not None:
                    for player in stat.players.sample:
                        playersdetected.update({player.id: player.name})

                # Update player and team arrays
                self.player_team = {
                    player: team
                    for player, team in self.player_team.items()
                    if player in playersdetected.keys()
                }

                if len(self.player_team) < len(playersdetected):
                    players_to_search = {
                        player: name
                        for player, name in playersdetected.items()
                        if player not in self.player_team
                    }
                    for player, name in players_to_search.items():
                        team = self._get_team_for_player(name)
                        self.player_team.update({player: team})

                self.players = list(self.player_team.keys())
                self.playercount = len(self.players)
                self.teams = list(set(self.player_team.values()))
                self.countfailures = 0

                return

            except timeout:
                # The Server is not up yet.
                print(f"Error! Is Server Down?")
                self.countfailures += 1
                # self.state = Server.State.CRASHED
                # return
            except ConnectionRefusedError:
                print(
                    f"Err: Connection Refused? - Stable failed task {self.ip}:{self.port}"
                )
                self.countfailures += 1
                # self.state = Server.State.CRASHED
                # return False
            except KeyError:
                # The status return doesn't have a players or online segment
                print(f"Something weird with Status response: {stat.raw}")

            except Exception as e:
                print(f"Something else went wrong... {e}")
                self.countfailures += 1
                # return

            if self.countfailures > self.maxFailsBeforeDown:
                self.state = Server.State.CRASHED
            return

        if self.state == Server.State.REQUESTED_DEACTIVATION:
            max_seconds_raw = self.config.get('SERVER',
                                              'maxRequestProcessTime')
            max_seconds = int(
                max_seconds_raw
            ) if max_seconds_raw and max_seconds_raw.isdecimal() else 600
            delta = datetime.timedelta(seconds=max_seconds)
            if delta < (datetime.datetime.now() - self.last_request_time):
                print(
                    "enough time has passed! We should now check to see if the server is behaving"
                )
                self.state = Server.State.CONFIRMING_DEACTIVATION

            return

        if self.state == Server.State.CONFIRMING_DEACTIVATION:

            # srv = MinecraftServer(self.ip, self.port)
            stat = ""
            try:
                stat = self.mcServer.status()
                if stat.players.online > 0:
                    print(
                        f"Error: Something went wrong with {self.id}. Should we re-send the request? {stat.raw}"
                    )
                    # TODO: Resend the deactivation request.
                    return
                else:
                    self.state = Server.State.DEACTIVATED  # No players online
            except timeout:
                # The Server is down
                print(f"Server {self.id} has been deactivated")
                self.state = Server.State.DEACTIVATED
                return
            except ConnectionRefusedError:
                print(f"Server {self.id} has been deactivated")
                self.state = Server.State.DEACTIVATED
                return
            except KeyError:
                # The server isn't down, but the status return doesn't have a players or online segment
                print(f"Something weird with Status response: {stat.raw}")
                return
            except Exception as e:
                print(f"Something else went wrong: {e}")
                return

        if self.state == Server.State.CRASHED:
            print(f"This server is crashed! {self.id} - is it back up?")
            if self._is_mc_alive():
                self.state = Server.State.STABLE
            # TODO: Send msg to restart the server.
            return

        else:
            print(
                f"This server has been deactivated! Please don't run  me anymore!"
            )
            return

    def check_is_server_api_alive(self):
        ## Ping the API port to confirm it is available!
        try:
            check_val = self.send_msg_to_server(
                LBFormattedMsg(MCCommands.HELLO))
            if check_val is not None and len(check_val) > 0:
                if self.state == Server.State.STABLE_BUT_TASK_FAILED:
                    print("yay! I'm back alive")
                    self.state = Server.State.STABLE

                return True

        except ConnectionRefusedError as e:
            if self.state == Server.State.STABLE:
                print("error - unable to connect to API. Please restart me!")
                self.state = Server.State.STABLE_BUT_TASK_FAILED
        except Exception as e:
            print("General Error " + e)

        return False

    def add_player(self, playerUUID, teamID):
        # Send msg to server?
        # self.teams.append(teamID)
        # self.players.append(playerUUID)
        self.player_team.update({playerUUID: teamID})
        self.players = list(self.player_team.keys())
        self.teams = list(set(self.player_team.values()))
        self.playercount += 1

    def decommission(self, newServer=None):
        if self.state != Server.State.STABLE:  # Cannot call decommission on a transitioning server.
            return False
        if not self._is_mc_alive():
            self.state = Server.State.CRASHED
            return False

        if newServer is None and self.playercount > 0:
            return False

        if newServer is not None:
            newServer.state = Server.State.WAITING_FOR_MERGE
            self.state = Server.State.REQUESTED_DEACTIVATION
            self.last_request_time = datetime.datetime.now()
            print("Transitioning Players to a new server")
            msg = LBFormattedMsg(
                MCCommands.DEALLOCATE,
                f'{{"IP":"{newServer.ip}", "PORT":{newServer.port}}}')
            self.send_msg_threaded_to_server(msg)

            #  noTODO: send msg to server
        else:
            print("Decommissioning this server")
            self.state = Server.State.CONFIRMING_DEACTIVATION  # No need to wait! Skip to the fun parts!
            self.last_request_time = datetime.datetime.now()
            msg = LBFormattedMsg(MCCommands.DEALLOCATE, "test Dealloc")
            self.send_msg_threaded_to_server(msg)
            #  noTODO: send msg to server

    def send_msg_threaded_to_server(self, msg: LBFormattedMsg):

        thread = threading.Thread(target=self.send_msg_to_server, args=(msg, ))
        thread.setDaemon(True)
        thread.start()
        return True

    def send_msg_to_server(self, lb_fmt_msg: LBFormattedMsg):

        # self.socket = socket.create_connection(addr, timeout=timeout)
        #
        #
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
            sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
            sock.connect((self.ip, self.api))
            sock.settimeout(2)

            print("sending data to the server...")
            sock.sendall(bytes(lb_fmt_msg.msg + "\n", "utf-8"))
            print("data sent!")
            received = str(sock.recv(1024), "utf-8")
            print(f"received data from the server: {received}")
            return received
            # self.assertEqual(received, expected_response)

    @total_ordering
    class State(Enum):
        """
        Server State holder - prevents inadvertent re-requests to a server
        """
        INITIALIZING = -1  # Server has not yet started.
        STABLE = 0  # No changes needed or all changes completed
        WAITING_FOR_MERGE = 1  # No new teams should enter this server because it is expecting a merge. Also, shouldn't get flagged for deallocation.
        REQUESTED_DEACTIVATION = 2  # A change has been requested & sent to the server
        CONFIRMING_DEACTIVATION = 3  # An appropriate amount of time has passed for the server to ack. and apply the change
        DEACTIVATED = 4  # The server has acknowledged that the requested change is complete
        STABLE_BUT_TASK_FAILED = 91  # Edge case: can't connect to the Python API on a node.
        CRASHED = 99  # Server is unexpectedly inaccessible.

        def __lt__(self, other):
            if self.__class__ is other.__class__:
                return self.value < other.value
            return NotImplemented
Example #24
0
from mcstatus import MinecraftServer

# If you know the host and port, you may skip this and use MinecraftServer("example.org", 1234)
# server = MinecraftServer.lookup("bcsn.us:25565")
server = MinecraftServer("184.18.202.133:25565")

# 'status' is supported by all Minecraft servers that are version 1.7 or higher.
status = server.status()
print("The server has {0} players and replied in {1} ms".format(status.players.online, status.latency))

# 'ping' is supported by all Minecraft servers that are version 1.7 or higher.
# It is included in a 'status' call, but is exposed separate if you do not require the additional info.
latency = server.ping()
print("The server replied in {0} ms".format(latency))

# 'query' has to be enabled in a servers' server.properties file.
# It may give more information than a ping, such as a full player list or mod information.
query = server.query()
print("The server has the following players online: {0}".format(", ".join(query.players.names)))
Example #25
0
def add_status_to_results(name):
    server = MinecraftServer(f"{name}.{BASE_URL}", PORT)
    status = server.status()

    results[name] = status.raw