From: jweigele Date: Sun, 20 Sep 2020 19:46:55 +0000 (-0700) Subject: Logging support (debug is default for now) and some modularity on the command execution X-Git-Url: http://git.hexthepla.net/?a=commitdiff_plain;h=1f7805c7af92bf865d0e262118495a928f010e0a;p=grahbot Logging support (debug is default for now) and some modularity on the command execution --- diff --git a/Dockerfile b/Dockerfile index ebfe783..ed72f14 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,9 +5,8 @@ FROM ubuntu WORKDIR /usr/src/app # Run the command inside your image filesystem. -#RUN npm install RUN apt-get update -RUN apt-get install python3 python3-pip ffmpeg --no-install-recommends -y +RUN apt-get install -y --no-install-recommends python3-pip ffmpeg RUN pip3 install discord.py asynqp PyNaCl # Run the specified command within the container. diff --git a/grahbot.py b/grahbot.py index 340d1de..173adb3 100755 --- a/grahbot.py +++ b/grahbot.py @@ -11,6 +11,13 @@ import asyncio import json import traceback import os +import logging +log = logging.getLogger(__name__) +log.setLevel(logging.DEBUG) +ch = logging.StreamHandler() +ch.setFormatter(logging.Formatter('|%(levelname)s|%(asctime)s|%(module)s| %(message)s')) +log.addHandler(ch) + from collections import defaultdict, OrderedDict PERSISTENT_DIR = '/var/lib/grahbot' @@ -50,7 +57,7 @@ class GrahState(object): def get_voice_id(self, guild): - print('here is self.data for guild {}'.format(self.data['guild'])) + log.debug('here is self.data for guild {}'.format(self.data['guild'])) if str(guild.id) in self.data['guild']: return discord.utils.get(self.grahbot.voice_channels, id=self.data['guild'][str(guild.id)]) else: @@ -66,11 +73,11 @@ class GrahState(object): return None def get_user_guild(self, user): - print('Get user guild enter for {}'.format(user.id)) + log.debug('Get user guild enter for {}'.format(user.id)) if str(user.id) in self.data['user']: - print('Found user, returning..') + log.debug('Found user, returning..') retval = discord.utils.get(self.grahbot.guilds, id=self.data['user'][str(user.id)]) - print(retval) + log.debug(retval) if type(retval) != list: retval = [retval] return retval @@ -86,10 +93,10 @@ class HornClient(object): self.rabbit_config = config def process_msg(self, msg): - print('>> {}'.format(msg.body)) + log.debug('>> {}'.format(msg.body)) async def rabbit_connect(self): - print('Creating rabbitmq socket') + log.debug('Creating rabbitmq socket') # CREATE SOCKET sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) @@ -98,21 +105,21 @@ class HornClient(object): sock.connect((self.rabbit_config['host'], int(self.rabbit_config['port']))) connection = await asynqp.connect(virtual_host=self.rabbit_config['vhost'], username=self.rabbit_config['user'], password=self.rabbit_config['password'], sock=sock) - print('Connected to rabbitmq') + log.info('Connected to rabbitmq') channel = await connection.open_channel() - print('Declaring exchange') + log.debug('Declaring exchange') exchange = await channel.declare_exchange(self.rabbit_config['exchange'], 'topic', passive=True) # we have 10 users. Set up a queue for each of them # use different channels to avoid any interference # during message consumption, just in case. self.channel = await connection.open_channel() - print('Declaring queue') + log.debug('Declaring queue') self.queue = await self.channel.declare_queue('horn_listener') await self.queue.bind(exchange, routing_key=self.rabbit_config['exchange']) - print('Bound') + log.debug('Bound') await self.queue.consume(self.process_msg, no_ack=True) - print('Consumed a thing') + log.debug('Consumed a thing') # deliver 10 messages to each user while (True): @@ -128,8 +135,10 @@ class GrahDiscordException(Exception): class GrahDiscordBot(discord.Client, HornClient): AUDIO_FILES = ['mp3', '.ogg'] + CMD_MARKER = '!' + CMD_PREFIX = 'command_' def process_msg(self, msg): - print('Received a message!!! {}'.format(msg)) + log.debug('Received a message!!! {}'.format(msg)) if msg._properties['content_type'] == 'application/json': # decode the object from json obj = json.loads(msg.body.decode(msg._properties['content_encoding'])) @@ -137,10 +146,10 @@ class GrahDiscordBot(discord.Client, HornClient): obj = msg.body if 'output_type' in obj and obj['output_type'] == 'discord': - print('Received a horn for us! {}'.format(msg.body)) + log.debug('Received a horn for us! {}'.format(msg.body)) asyncio.ensure_future(self.horn(obj, properties=None)) else: - print('Received a horn not for us: {}'.format(msg.body)) + log.debug('Received a horn not for us: {}'.format(msg.body)) def __init__(self, config): self.config = config @@ -168,18 +177,18 @@ class GrahDiscordBot(discord.Client, HornClient): if use not in selections: self.used.pop(use) while len(self.used) < len(selections) and sample_name in self.used: - print('already used, researching') + log.debug('already used, researching') sample_name = random.choice(selections) self.used.append(sample_name) if len(self.used) == len(selections): self.used = [] sample_name = "{}/{}".format(self.config['airhorn_directory'], sample_name) - print('{} selected'.format(sample_name)) + log.debug('{} selected'.format(sample_name)) return sample_name async def horn(self, obj, properties): try: - print('Horn! {}'.format(obj)) + log.info('Horn! {}'.format(obj)) # exclusive access on each horn or not? if 'exclusive' in obj: exclusive = obj['exclusive'] @@ -195,7 +204,7 @@ class GrahDiscordBot(discord.Client, HornClient): sample_name = '{}/{}'.format(self.config['airhorn_directory'], obj['sample_name']) except: traceback.print_exc() - print('Error object was: {}'.format(obj)) + log.debug('Error object was: {}'.format(obj)) else: await self.msg_play_filename(sample_name, guild_id=obj['guild'], exclusive=exclusive) @@ -225,19 +234,19 @@ class GrahDiscordBot(discord.Client, HornClient): self.loop.close() async def on_ready(self): - print('Logged in as {} ({})'.format(self.user.name, self.user.id)) - print([x for x in self.get_all_channels()]) + log.debug('Logged in as {} ({})'.format(self.user.name, self.user.id)) + log.debug([x for x in self.get_all_channels()]) #await self.user.edit(nick='Varimathras') - print(dir(self)) - print(list(self.guilds)) + log.debug(dir(self)) + log.debug(list(self.guilds)) for guild in self.guilds: - print('Checking for rejoin of {}'.format(guild.__repr__())) + log.debug('Checking for rejoin of {}'.format(guild.__repr__())) if self.state.get_voice_id(guild): - print('Rejoining prior voice channel') + log.debug('Rejoining prior voice channel') await self.msg_join_voice_channel(self.state.get_voice_id(guild).name, guild) self.member_guilds = {} - print(self.voice_clients) - print('------') + log.debug(self.voice_clients) + log.debug('------') @property def voice_channels(self): @@ -281,23 +290,23 @@ class GrahDiscordBot(discord.Client, HornClient): self.state.get_voice(guild).play(discord.FFmpegPCMAudio(filename)) #self.player.start() else: - print('Was asked to play {} but no voice channel'.format(filename)) + log.debug('Was asked to play {} but no voice channel'.format(filename)) async def msg_join_voice_channel(self, channel_name, guild): - print('Called join voice channel') + log.debug('Called join voice channel') for vc in self.voice_channels: if vc.name == channel_name and (not guild or vc.guild == guild): - print('Found a voice channel to join {} {}'.format(vc, type(vc))) + log.debug('Found a voice channel to join {} {}'.format(vc, type(vc))) if self.state.get_voice(guild): if vc != self.state.get_voice(guild).channel: self.state.set_voice(guild, await self.state.get_voice(guild).move_to(vc)) else: self.state.set_voice(guild, await vc.connect()) - print('Joined voice channel {} {} (id: {})'.format(guild, vc.name, vc.id)) - print('Voice now {}'.format(self.state.get_voice(guild))) + log.info('Joined voice channel {} {} (id: {})'.format(guild, vc.name, vc.id)) + log.debug('Voice now {}'.format(self.state.get_voice(guild))) - print('Exit join voice') + log.debug('Exit join voice') def get_airhorn_filenames(self): retval = [] @@ -305,7 +314,7 @@ class GrahDiscordBot(discord.Client, HornClient): if self.is_audio_file(x): retval.append(x.lower()) retval = sorted([x[:-4] for x in retval]) - print('Found airhorn files:\n{}'.format('\n'.join(retval))) + log.debug('Found airhorn files:\n{}'.format('\n'.join(retval))) return retval @@ -318,24 +327,28 @@ class GrahDiscordBot(discord.Client, HornClient): cur_chars += len(yieldval) if index + 1 < len(filename_list): if len(filename_list[index+1]) + cur_chars > char_limit: - print('Yielding {}'.format(yieldval)) + log.debug('Yielding {}'.format(yieldval)) yield yieldval yieldval = [] cur_chars = 0 if yieldval: - print('Final yield {}'.format(yieldval)) + log.debug('Final yield {}'.format(yieldval)) yield yieldval async def oh_no(self, channel, exc): - print("Exception: {}\t{}".format(channel, exc)) - exc_string = 'Ruh Roh! {}: {}'.format(type(exc), str(exc)) + log.debug("Exception: {}\t{}".format(channel, exc)) + exc_string = 'Ruh Roh! {}'.format(str(exc)) traceback.print_exc() await channel.send(exc_string) def print_call(self, message): - print('#{} <{}>: {}'.format(message.channel, message.author, message.content)) + if isinstance(message.channel, discord.DMChannel): + guild_str = '' + else: + guild_str = str(message.channel.guild) + log.info('{}#{} <{}>: {}'.format(guild_str, message.channel, message.author, message.content)) def member_guild_list(self, member): @@ -344,12 +357,12 @@ class GrahDiscordBot(discord.Client, HornClient): def contextual_guild(self, message): channel = message.channel if isinstance(channel, discord.DMChannel): - print('Is a DM with {}'.format(channel.recipient)) + log.debug('Is a DM with {}'.format(channel.recipient)) retval = self.member_guild_list(channel.recipient) - print('Member guilds: {}'.format(retval)) + log.debug('Member guilds: {}'.format(retval)) return retval else: - print('Guild: {}'.format(channel.guild)) + log.debug('Guild: {}'.format(channel.guild)) return [channel.guild] @@ -359,70 +372,94 @@ class GrahDiscordBot(discord.Client, HornClient): else: return self.contextual_guild(message) - def select_guild(self, message): - print('Selectguild {}'.format(message.content)) + async def command_selectguild(self, message, guild): + log.debug('Selectguild {}'.format(message.content)) guilds = self.contextual_guild(message) if len(guilds) < 2: raise Exception('No, this is not needed') guild_name = message.content.replace('!selectguild ', '') for guild in guilds: if guild.name == guild_name: - print('Setting member {} to guild {}'.format(message.channel.recipient, guild.name)) + log.debug('Setting member {} to guild {}'.format(message.channel.recipient, guild.name)) self.member_guilds[message.channel.recipient] = [guild] self.state.set_user_guild(message.channel.recipient, guild) break - + async def command_sleep(self, message, guild): + await asyncio.sleep(5) + await message.channel.send('Done sleeping') + + async def command_join(self, message, guild): + log.info('Was instructed to join {} guild {}'.format(message.content.split(' ')[1], str(guild))) + await self.msg_join_voice_channel(message.content.split(' ')[1], guild=guild) + + async def command_play(self, message, guild): + log.info('Was instructed to play {}'.format(message.content.split(' ')[1])) + await self.msg_play_sound(name=' '.join(message.content.split(' ')[1:]), guild=guild) + + async def command_list(self, message, guild): + log.info('Asked for list') + for airhorn_files in self.chunk_it_up(self.get_airhorn_filenames()): + log.debug('Sending {}'.format(airhorn_files)) + await message.channel.send('```\n{}```'.format('\n'.join(airhorn_files))) + + async def command_leave(self, message, guild): + await self.state.get_voice(guild).disconnect() + self.state.set_voice(guild, None) + + async def command_help(self, message, guild): + await message.channel.send('```\n!join [channel]\n!play [file]\n!list (for all of them)\n!leave```') + + + async def command_whoami(self, message, guild): + await message.channel.send('```{}```'.format(self.debug_info())) def debug_info(self): return socket.gethostname() + + def get_command_names(self): + cmds = [self.CMD_SYMBOL+x.replace('command_', '') for x in dir(self) if x.startswith('command_')] + + def get_command_func(self, command_name): + command_func_names = [x for x in dir(self) if x.startswith(self.CMD_PREFIX)] + log.debug('searching for command with name {}'.format(command_name)) + log.debug('command func names {}'.format(command_func_names)) + search_func_name = '{}{}'.format(self.CMD_PREFIX, command_name) + if search_func_name in command_func_names: + search_func = getattr(self, search_func_name) + return search_func + raise GrahDiscordException('Did not find {} in commands'.format(command_name)) + + async def handle_command(self, message): + self.print_call(message) + log.debug('gettin guilds here') + guilds = self.channel_guild(message) + log.debug(guilds) + potential_command = message.content[1:].split(' ')[0] + + if potential_command == 'selectguild': + func = self.get_command_func(potential_command) + await func(message, guild=None) + return + + if len(guilds) == 0: + return + elif len(guilds) >1: + await message.channel.send('Too many guilds!!!\n{}'.format('\n'.join([str(x) for x in guilds]))) + return + elif len(guilds) == 1: + guild = guilds[0] + + func = self.get_command_func(potential_command) + await func(message, guild) + + async def on_message(self, message): try: if message.author != self.user: - print('gettin guilds here') - guilds = self.channel_guild(message) - print(guilds) - if message.content.startswith('!selectguild'): - self.select_guild(message) - return - - if len(guilds) == 0: - return - elif len(guilds) >1: - await message.channel.send('Too many guilds!!!\n{}'.format('\n'.join([str(x) for x in guilds]))) - return - elif len(guilds) == 1: - guild = guilds[0] - - if message.content.startswith('!sleep'): - await asyncio.sleep(5) - await message.channel.send('Done sleeping') - elif message.content.startswith('!join'): - self.print_call(message) - print('Was instructed to join {} guild {}'.format(message.content.split(' ')[1], str(guild))) - await self.msg_join_voice_channel(message.content.split(' ')[1], guild=guild) - elif message.content.startswith('!play'): - self.print_call(message) - print('Was instructed to play {}'.format(message.content.split(' ')[1])) - await self.msg_play_sound(name=' '.join(message.content.split(' ')[1:]), guild=guild) - elif message.content == '!list': - self.print_call(message) - for airhorn_files in self.chunk_it_up(self.get_airhorn_filenames()): - print('Sending {}'.format(airhorn_files)) - await message.channel.send('```\n{}```'.format('\n'.join(airhorn_files))) - elif message.content == '!leave': - await self.state.get_voice(guild).disconnect() - self.state.set_voice(guild, None) - elif message.content.startswith('!selectguild'): - self.print_call(message) - await self.select_guild(message) - elif message.content == '!help': - self.print_call(message) - await message.channel.send('```\n!join [channel]\n!play [file]\n!list (for all of them)\n!leave```') - elif message.content == '!whoami': - self.print_call(message) - await message.channel.send('```{}```'.format(self.debug_info())) + if message.content.startswith(self.CMD_MARKER): + await self.handle_command(message) except Exception as e: await self.oh_no(message.channel, e)