forked from Minecraft/minecraft_manager
Compare commits
1 Commits
master
...
external-b
Author | SHA1 | Date |
---|---|---|
Etzelia | fa8908531c |
28
api/api.py
28
api/api.py
|
@ -1,8 +1,7 @@
|
||||||
import socket, logging, os, datetime, pytz, mcstatus, random, string
|
import socket, requests, logging, os, datetime, pytz, mcstatus, random, string
|
||||||
from minecraft_manager.models import Alert
|
from minecraft_manager.models import Alert
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from minecraft_manager.bot.discord import send as discord_send, DestType
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -39,24 +38,35 @@ def plugin(key, command):
|
||||||
|
|
||||||
|
|
||||||
def discord_mcm(message='', embed=None, ping=False):
|
def discord_mcm(message='', embed=None, ping=False):
|
||||||
channel_id = getattr(settings, 'DISCORD_MCM_CHANNEL', None)
|
discord_mcm_webhook = getattr(settings, 'DISCORD_MCM_WEBHOOK', None)
|
||||||
if channel_id:
|
if discord_mcm_webhook:
|
||||||
ping_list = getattr(settings, 'DISCORD_PING_LIST', [])
|
ping_list = getattr(settings, 'DISCORD_PING_LIST', [])
|
||||||
if ping and ping_list:
|
if ping and ping_list:
|
||||||
ping_list = ["<@&{0}>".format(ping) for ping in ping_list]
|
ping_list = ["<@&{0}>".format(ping) for ping in ping_list]
|
||||||
message = "{0}\n{1}".format(" ".join(ping_list), message)
|
message = "{0}\n{1}".format(" ".join(ping_list), message)
|
||||||
discord_send(DestType.CHANNEL, channel_id, message, embed)
|
data = {}
|
||||||
|
if message:
|
||||||
|
data['content'] = message
|
||||||
|
if embed:
|
||||||
|
data['embeds'] = embed
|
||||||
|
return requests.post(discord_mcm_webhook, json=data)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def discord_notification(message='', embed=None, ping=False):
|
def discord_notification(message='', embed=None, ping=False):
|
||||||
channel_id = getattr(settings, 'DISCORD_NOTIFICATION_CHANNEL', None)
|
discord_notification_webhook = getattr(settings, 'DISCORD_NOTIFICATION_WEBHOOK', None)
|
||||||
if channel_id:
|
if discord_notification_webhook:
|
||||||
ping_list = getattr(settings, 'DISCORD_PING_LIST', [])
|
ping_list = getattr(settings, 'DISCORD_PING_LIST', [])
|
||||||
if ping and ping_list:
|
if ping and ping_list:
|
||||||
ping_list = ["<@&{0}>".format(ping) for ping in ping_list]
|
ping_list = ["<@&{0}>".format(ping) for ping in ping_list]
|
||||||
message = "{0}\n{1}".format(" ".join(ping_list), message)
|
message = "{0}\n{1}".format(" ".join(ping_list), message)
|
||||||
discord_send(DestType.CHANNEL, channel_id, message, embed)
|
data = {}
|
||||||
|
if message:
|
||||||
|
data['content'] = message
|
||||||
|
if embed:
|
||||||
|
data['embeds'] = embed
|
||||||
|
return requests.post(discord_notification_webhook, json=data)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def strip_format(message):
|
def strip_format(message):
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
import subprocess
|
import subprocess, os
|
||||||
|
|
||||||
|
|
||||||
class Bot:
|
class Bot:
|
||||||
|
@ -17,10 +17,11 @@ class Bot:
|
||||||
self.restart = restart if restart else self._restart
|
self.restart = restart if restart else self._restart
|
||||||
self.status = status if status else self._status
|
self.status = status if status else self._status
|
||||||
self.display = display if display else self._display
|
self.display = display if display else self._display
|
||||||
|
self.dir = "{}/assets/".format(os.path.dirname(os.path.abspath(__file__))) if self.asset else self.bot_dir
|
||||||
|
|
||||||
def _start(self):
|
def _start(self):
|
||||||
screen = 'screen -S {0}_{1} -d -m {2} {3}{1}.bot.py'
|
screen = 'screen -S {0}_{1} -d -m {2} {3}{1}.bot.py'
|
||||||
subprocess.run(screen.format(self.plugin_port, self.name, self.executable, self.bot_dir),
|
subprocess.run(screen.format(self.plugin_port, self.name, self.executable, self.dir),
|
||||||
shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
|
||||||
def _stop(self):
|
def _stop(self):
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import django
|
||||||
|
|
||||||
|
sep = os.sep
|
||||||
|
path = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
path = path.split(sep)[:-3]
|
||||||
|
project = path[-1]
|
||||||
|
path = sep.join(path)
|
||||||
|
sys.path.append(path)
|
||||||
|
print("Setting path for {0}: {1}".format(project, path))
|
||||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{}.settings".format(project))
|
||||||
|
django.setup()
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from minecraft_manager.bot.discord import Discord
|
||||||
|
|
||||||
|
token = getattr(settings, 'DISCORD_BOT_TOKEN', None)
|
||||||
|
bot = Discord(token)
|
||||||
|
|
||||||
|
bot.run_bot()
|
118
bot/discord.py
118
bot/discord.py
|
@ -13,29 +13,11 @@ from minecraft_manager.utils import url_path
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
discord_loop = None
|
|
||||||
discord_bot = None
|
|
||||||
description = '''
|
description = '''
|
||||||
A Discord bot connected to an MCM instance.
|
A Discord bot connected to an MCM instance.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
class DiscordStatus(Enum):
|
|
||||||
STOPPED = 0
|
|
||||||
STARTING = 1
|
|
||||||
STARTED = 2
|
|
||||||
STOPPING = 3
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name.title()
|
|
||||||
|
|
||||||
def is_running(self):
|
|
||||||
return self != DiscordStatus.STOPPED
|
|
||||||
|
|
||||||
|
|
||||||
discord_status = DiscordStatus.STOPPED
|
|
||||||
|
|
||||||
|
|
||||||
class Discord(commands.Bot):
|
class Discord(commands.Bot):
|
||||||
discord_game = 'MCM'
|
discord_game = 'MCM'
|
||||||
prefix = getattr(settings, 'DISCORD_BOT_PREFIX', '!')
|
prefix = getattr(settings, 'DISCORD_BOT_PREFIX', '!')
|
||||||
|
@ -43,14 +25,13 @@ class Discord(commands.Bot):
|
||||||
superuser_roles = getattr(settings, 'DISCORD_SUPERUSER_ROLES', [])
|
superuser_roles = getattr(settings, 'DISCORD_SUPERUSER_ROLES', [])
|
||||||
error_users = getattr(settings, 'DISCORD_ERROR_USERS', [])
|
error_users = getattr(settings, 'DISCORD_ERROR_USERS', [])
|
||||||
|
|
||||||
def __init__(self, token, loop):
|
def __init__(self, token):
|
||||||
super().__init__(command_prefix=self.prefix, description=description, case_insensitive=True, help_command=None, activity=discord.Game(name=self.discord_game), loop=loop)
|
super().__init__(command_prefix=self.prefix, description=description, case_insensitive=True, help_command=None,
|
||||||
|
activity=discord.Game(name=self.discord_game))
|
||||||
self.token = token
|
self.token = token
|
||||||
self.load_extension("minecraft_manager.bot.commands")
|
self.load_extension("minecraft_manager.bot.commands")
|
||||||
|
|
||||||
async def on_ready(self):
|
async def on_ready(self):
|
||||||
global discord_status
|
|
||||||
discord_status = DiscordStatus.STARTED
|
|
||||||
print('Logged in as')
|
print('Logged in as')
|
||||||
print(self.user.name)
|
print(self.user.name)
|
||||||
print(self.user.id)
|
print(self.user.id)
|
||||||
|
@ -80,10 +61,6 @@ class Discord(commands.Bot):
|
||||||
embed.description = content
|
embed.description = content
|
||||||
await self.discord_message(channel, embed)
|
await self.discord_message(channel, embed)
|
||||||
|
|
||||||
async def on_disconnect(self):
|
|
||||||
global discord_status
|
|
||||||
discord_status = DiscordStatus.STOPPED
|
|
||||||
|
|
||||||
async def discord_message(self, dest, message):
|
async def discord_message(self, dest, message):
|
||||||
if isinstance(message, discord.Embed):
|
if isinstance(message, discord.Embed):
|
||||||
for idx, field in enumerate(message.fields):
|
for idx, field in enumerate(message.fields):
|
||||||
|
@ -107,81 +84,14 @@ class Discord(commands.Bot):
|
||||||
await self.discord_message(user, '```python\n{}```'.format(error))
|
await self.discord_message(user, '```python\n{}```'.format(error))
|
||||||
|
|
||||||
def run_bot(self):
|
def run_bot(self):
|
||||||
global discord_loop
|
loop = asyncio.get_event_loop()
|
||||||
loop = True
|
try:
|
||||||
while loop:
|
loop.run_until_complete(self.start(self.token))
|
||||||
try:
|
except KeyboardInterrupt:
|
||||||
discord_loop.run_until_complete(self.start(self.token))
|
logger.info("Bot received keyboard interrupt")
|
||||||
except KeyboardInterrupt:
|
except Exception as e:
|
||||||
logger.info("Bot received keyboard interrupt")
|
print(e)
|
||||||
loop = False
|
logger.info('Bot encountered the following unhandled exception %s', e)
|
||||||
except Exception as e:
|
finally:
|
||||||
print(e)
|
loop.run_until_complete(self.logout())
|
||||||
logger.info('Bot encountered the following unhandled exception %s', e)
|
logger.info("Bot shutting down...")
|
||||||
loop = False
|
|
||||||
|
|
||||||
|
|
||||||
def start():
|
|
||||||
global discord_loop, discord_bot, discord_status
|
|
||||||
if discord_status != DiscordStatus.STOPPED:
|
|
||||||
return
|
|
||||||
token = getattr(settings, 'DISCORD_BOT_TOKEN', None)
|
|
||||||
discord_loop = asyncio.new_event_loop()
|
|
||||||
discord_bot = Discord(token, discord_loop)
|
|
||||||
thread = threading.Thread(target=discord_bot.run_bot)
|
|
||||||
thread.start()
|
|
||||||
discord_status = DiscordStatus.STARTING
|
|
||||||
|
|
||||||
|
|
||||||
def stop():
|
|
||||||
global discord_loop, discord_bot, discord_status
|
|
||||||
if discord_status == DiscordStatus.STARTED:
|
|
||||||
discord_loop.create_task(discord_bot.close())
|
|
||||||
discord_status = DiscordStatus.STOPPING
|
|
||||||
discord_loop = None
|
|
||||||
discord_bot = None
|
|
||||||
|
|
||||||
|
|
||||||
def restart():
|
|
||||||
def _restart():
|
|
||||||
stop()
|
|
||||||
while discord_status.is_running():
|
|
||||||
pass
|
|
||||||
start()
|
|
||||||
if discord_status != DiscordStatus.STARTED:
|
|
||||||
return
|
|
||||||
thread = threading.Thread(target=_restart)
|
|
||||||
thread.start()
|
|
||||||
|
|
||||||
|
|
||||||
def status():
|
|
||||||
return discord_status.is_running()
|
|
||||||
|
|
||||||
|
|
||||||
def display():
|
|
||||||
return str(discord_status)
|
|
||||||
|
|
||||||
|
|
||||||
class DestType(Enum):
|
|
||||||
CHANNEL = 1
|
|
||||||
USER = 2
|
|
||||||
|
|
||||||
|
|
||||||
def send(dest_type: DestType, dest_id: int, message: str = "", embed: discord.Embed = None):
|
|
||||||
async def _send():
|
|
||||||
if dest_type == DestType.CHANNEL:
|
|
||||||
dest = discord_bot.get_channel(dest_id)
|
|
||||||
elif dest_type == DestType.USER:
|
|
||||||
dest = discord_bot.get_user(dest_id)
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
if message is not None:
|
|
||||||
await dest.send(message)
|
|
||||||
if embed is not None:
|
|
||||||
for idx, field in enumerate(embed.fields):
|
|
||||||
if not field.value:
|
|
||||||
embed.set_field_at(idx, name=field.name, value="N/A")
|
|
||||||
await dest.send(embed=embed)
|
|
||||||
global discord_loop, discord_bot
|
|
||||||
if discord_loop:
|
|
||||||
discord_loop.create_task(_send())
|
|
||||||
|
|
|
@ -23,6 +23,10 @@ Optional
|
||||||
|
|
||||||
``BOT_DIR`` - The path to your bot directory.
|
``BOT_DIR`` - The path to your bot directory.
|
||||||
|
|
||||||
|
``DISCORD_NOTIFICATION_WEBHOOK`` - The URL for the webhook used for notifications.
|
||||||
|
|
||||||
|
``DISCORD_MCM_WEBHOOK`` - The URL for the webhook used for Applications, Tickets, and Warnings.
|
||||||
|
|
||||||
``DISCORD_BOT_TOKEN`` - The token to use to run the Discord bot. This must be generated by you in the Discord developer area.
|
``DISCORD_BOT_TOKEN`` - The token to use to run the Discord bot. This must be generated by you in the Discord developer area.
|
||||||
|
|
||||||
``DISCORD_PING_LIST`` - A list of Discord Role IDs to ping whenever certain messages are sent.
|
``DISCORD_PING_LIST`` - A list of Discord Role IDs to ping whenever certain messages are sent.
|
||||||
|
|
4
views.py
4
views.py
|
@ -18,8 +18,6 @@ from minecraft_manager.overview import overview_data
|
||||||
from minecraft_manager.utils import resolve_player
|
from minecraft_manager.utils import resolve_player
|
||||||
import minecraft_manager.api.api as API
|
import minecraft_manager.api.api as API
|
||||||
from minecraft_manager.bot import Bot
|
from minecraft_manager.bot import Bot
|
||||||
from minecraft_manager.bot.discord import start as discord_start, stop as discord_stop, restart as discord_restart, \
|
|
||||||
status as discord_status, display as discord_display
|
|
||||||
|
|
||||||
|
|
||||||
class Overview(View):
|
class Overview(View):
|
||||||
|
@ -467,7 +465,7 @@ class Bots(View):
|
||||||
bots.append(Bot(file.replace('.bot.py', ''), False, sys.executable))
|
bots.append(Bot(file.replace('.bot.py', ''), False, sys.executable))
|
||||||
# Also get packaged MCM bots
|
# Also get packaged MCM bots
|
||||||
if getattr(settings, 'DISCORD_BOT_TOKEN', None):
|
if getattr(settings, 'DISCORD_BOT_TOKEN', None):
|
||||||
bots.append(Bot("Discord-MCM", True, None, discord_start, discord_stop, discord_restart, discord_status, discord_display))
|
bots.append(Bot("Discord-MCM", True, sys.executable))
|
||||||
return bots
|
return bots
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
|
|
Loading…
Reference in New Issue