async def on_message(self, message): full_cmd = message.content.split() if not full_cmd: return cmd = full_cmd[0] if not cmd: return if not cmd[0] == settings["prefix"]: return cmd = cmd[len(settings["prefix"]):] # skip past "!" # check cooldown for this channel. guild = message.guild if not guild: return channel = str( guild.id) # this is a unique int representing this discord server. author = message.author is_mod = (author.guild_permissions.administrator if author.guild_permissions else False) context = CommandContext( author=AuthorInfo(name=message.author.display_name, is_mod=is_mod), channel=channel, platform="discord", ) db = Database.get() content = " ".join(full_cmd[1:] or []) if check_cooldown(db, context.channel): # Enforce cooldown for this channel. return try: resp = self.logic.exec(context, cmd, content) if resp: embed = discord.Embed( title="LogicEFTBot", url="https://eft.bot", description="The Free Tarkov Bot", color=0x780A81, ) # embed.set_thumbnail(url="") #Will be implimented soon embed.add_field(name=cmd.capitalize() + " check", value=resp, inline=True) await message.channel.send(embed=embed) reset_cooldown(context.channel) except CommandNotFoundException: # just be silent if we don't know the command. pass except Exception as e: # Log all other exceptions. log.error( f"Exception processing command ({cmd}) for channel '{guild.name}' (id={context.channel}) -" ) log.error(e) traceback.print_exc()
def run_bot(queue: Queue, feedbackQueue: Queue) -> None: """ Represents one of the running bot connections. We also provide a periodic callback to listen to newly appearing channels. """ # This is a fork. reset all copied signal handlers. def noop_signal_handler(sig, frame): # ignore signals pass signal.signal(signal.SIGINT, noop_signal_handler) bot = TwitchIrcBot(Database.get( True)) # important to recreate the db conn, since it has been forked. def between_frames() -> None: # this is run when the twitch bot has free time, roughly every 5s. volume = bot.processed_commands bot.processed_commands = 0 try: channel = queue.get(timeout=0.1) # block for no more than 100ms. if channel: if channel == END_OF_LIFE: # exit command. bot.disconnect() # we need to be careful to empty the queue before exiting, so that # there is not a deadlock. # see: https://stackoverflow.com/questions/31665328/python-3-multiprocessing-queue-deadlock-when-calling-join-before-the-queue-is-em while not queue.empty(): queue.get() os._exit(0) else: feedbackQueue.put( ShardUpdate( status=":smiley: Healthy", message=f"Joining #{channel}", RPM=volume, )) # issue a join command to the twitch bot. bot.do_join(str(channel)) feedbackQueue.put( ShardUpdate(status=bot.status, message=bot.message, RPM=volume)) except Empty: # nothing to do. pass bot.set_periodic(between_frames, 5) bot.start() # note- this blocks + runs indefinitely.
async def on_message(self, message): full_cmd = message.content.split() if not full_cmd: return cmd = full_cmd[0] if not cmd: return if not cmd[0] == settings["prefix"]: return cmd = cmd[len(settings["prefix"]):] # skip past "!" # check cooldown for this channel. guild = message.guild if not guild: return channel = str( guild.id) # this is a unique int representing this discord server. author = message.author is_mod = (author.guild_permissions.administrator if author.guild_permissions else False) context = CommandContext( author=AuthorInfo(name=message.author.display_name, is_mod=is_mod), channel=channel, platform="discord", ) db = Database.get() content = " ".join(full_cmd[1:] or []) if check_cooldown(db, context.channel): # Enforce cooldown for this channel. return try: resp = self.logic.exec(context, cmd, content) if isinstance(resp, str): await message.channel.send(resp) elif isinstance(resp, discord.Embed): await message.channel.send(embed=resp) else: log.error("Unknown response: {}".format(str(resp))) reset_cooldown(context.channel) except CommandNotFoundException: # just be silent if we don't know the command. pass except Exception as e: # Log all other exceptions. log.error( f"Exception processing command ({cmd}) for channel '{guild.name}' (id={context.channel}) -" ) log.error(e) traceback.print_exc()
def __init__(self): super().__init__() self.logic = DiscordEFTBot(Database.get())
def run_bot(queue: Queue, feedbackQueue: Queue) -> None: """ Represents one of the running bot connections. We also provide a periodic callback to listen to newly appearing channels. """ # This is a fork. reset all copied signal handlers. def noop_signal_handler(sig, frame): # ignore signals pass signal.signal(signal.SIGINT, noop_signal_handler) bot = TwitchIrcBot(Database.get( True)) # important to recreate the db conn, since it has been forked. def between_frames() -> None: # this is run when the twitch bot has free time, roughly every 5s. volume = bot.processed_commands bot.processed_commands = 0 try: commands = [] target_time = time.time() + 2 while time.time() < target_time: # for 2 seconds, attempt to read all of the items out of the queue. # we don't want to spend too much time here, since this is called every 5 seconds, # and we have a responsibility to PONG the server. try: command = queue.get(timeout=0.1) if command: commands.append(command) except Empty: # no more items left to pull break for command in commands: if command == END_OF_LIFE: # exit command. bot.disconnect() # we need to be careful to empty the queue before exiting, so that # there is not a deadlock. # see: https://stackoverflow.com/questions/31665328/python-3-multiprocessing-queue-deadlock-when-calling-join-before-the-queue-is-em while not queue.empty(): queue.get() os._exit(0) else: feedbackQueue.put( ShardUpdate( status=":smiley: Healthy", message=f"Joining #{command}", RPM=volume, )) # issue a join command to the twitch bot. bot.do_join(str(command)) feedbackQueue.put( ShardUpdate(status=bot.status, message=bot.message, RPM=volume)) except Exception as e: # nothing to do. log.error("Exception in shard: %s", str(e)) bot.set_periodic(between_frames, 5) bot.start() # note- this blocks + runs indefinitely.
import threading import math import os import json from typing import Callable, List, Any, List, Dict, Optional, Union from dataclasses import dataclass from queue import Empty from multiprocessing import Queue, Process from twitch import TwitchIrcBot from bot.database import Database from bot.config import settings, BOT_UI_ENABLED from bot.log import log from rich.table import Table from rich.live import Live DB: Database = Database.get() DB_OBSERVER_THREAD = None DB_OBSERVER_THREAD_LIVE = True ABORT_STARTUP = False SHUTDOWN_COMPLETE = False END_OF_LIFE = -1 TOTAL_SHARDS = 0 SHUTDOWN_INITIATED: threading.Event = threading.Event() @dataclass class ShardUpdate: """ An update for a shard to give the master process. """