Example #1
0
    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.
Example #3
0
    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()
Example #4
0
 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.
    """