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)
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}")
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)
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
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")
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()
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()
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)
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!")
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
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)
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())
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()
def get_nr_players(): from mcstatus import MinecraftServer server = MinecraftServer(HOST, PORT) return server.status().players.online
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
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)
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)
#!/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>')
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
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)))
def add_status_to_results(name): server = MinecraftServer(f"{name}.{BASE_URL}", PORT) status = server.status() results[name] = status.raw