Example #1
0
 def __init__(self, config):
     self.config = config
     self.client = APIClient(config.token)
     self.shards = {}
     self.config.shard_count = self.client.gateway_bot_get()['shards']
     if self.config.shard_count > 1:
         self.config.shard_count = 10
Example #2
0
def main():
    # Initialize the client
    print("Starting up...")
    # client = discord.Client()
    client = APIClient(settings.BOT_TOKEN)

    # Define event handlers for the client
    # on_ready may be called multiple times in the event of a reconnect,
    # hence the running flag
    @client.event
    async def on_ready():
        if this.running:
            return

        this.running = True

        # Set the playing status
        if settings.NOW_PLAYING:
            print("Setting NP game", flush=True)
            await client.change_presence(game=discord.Game(
                name=settings.NOW_PLAYING))
        print("Logged in!", flush=True)

        # Load all events
        print("Loading events...", flush=True)
        n_ev = 0
        for ev in BaseEvent.__subclasses__():
            event = ev()
            sched.add_job(event.run,
                          'interval', (client, ),
                          minutes=event.interval_minutes)
            n_ev += 1
        sched.start()
        print(f"{n_ev} events loaded", flush=True)

    # The message handler for both new message and edits
    async def common_handle_message(message):
        text = message.content
        if text.startswith(
                settings.COMMAND_PREFIX) and text != settings.COMMAND_PREFIX:
            cmd_split = text[len(settings.COMMAND_PREFIX):].split()
            try:
                await message_handler.handle_command(cmd_split[0].lower(),
                                                     cmd_split[1:], message,
                                                     client)
            except:
                print("Error while handling message", flush=True)
                raise

    @client.event
    async def on_message(message):
        await common_handle_message(message)

    @client.event
    async def on_message_edit(before, after):
        await common_handle_message(after)

    # Finally, set the bot running
    client.run(settings.BOT_TOKEN)
Example #3
0
 def __init__(self):
     self.client = None
     self.avatars = {}
     if self.TOKEN and not settings.IS_TEST:
         self.client = APIClient(self.TOKEN)
         members = self.client.guilds_members_list(self.GUILD).values()
         for member in members:
             self.avatars[member.user.username] = member.user.avatar_url
         for member in members:
             self.avatars[member.name] = member.user.avatar_url
Example #4
0
def guild_delete(guild):
    if not g.user.admin:
        return '', 401

    from disco.api.client import APIClient
    client = APIClient(current_app.config['token'])
    client.users_me_guilds_delete(guild.guild_id)

    guild.enabled = False
    guild.save()

    return '', 204
Example #5
0
    def __init__(self, config):
        super(Client, self).__init__()
        self.config = config

        self.events = Emitter()
        self.packets = Emitter()

        self.api = APIClient(self.config.token, self)
        self.gw = GatewayClient(self, self.config.max_reconnects,
                                self.config.encoder)
        self.state = State(self, StateConfig(self.config.get('state', {})))

        if self.config.manhole_enable:
            self.manhole_locals = {
                'client': self,
                'state': self.state,
                'api': self.api,
                'gw': self.gw,
            }

            self.manhole = DiscoBackdoorServer(
                self.config.manhole_bind,
                banner='Disco Manhole',
                localf=lambda: self.manhole_locals)
            self.manhole.start()
Example #6
0
class AutoSharder(object):
    def __init__(self, config):
        self.config = config
        self.client = APIClient(config.token)
        self.shards = {}
        self.config.shard_count = self.client.gateway_bot_get()['shards']
        if self.config.shard_count > 1:
            self.config.shard_count = 10

    def run_on(self, sid, raw):
        func = load_function(raw)
        return self.shards[sid].execute(func).wait(timeout=15)

    def run(self):
        for shard in range(self.config.shard_count):
            if self.config.manhole_enable and shard != 0:
                self.config.manhole_enable = False

            self.start_shard(shard)
            gevent.sleep(6)

        logging.basicConfig(
            level=logging.INFO,
            format=
            '{} [%(levelname)s] %(asctime)s - %(name)s:%(lineno)d - %(message)s'
            .format(id))

    def start_shard(self, sid):
        cpipe, ppipe = gipc.pipe(duplex=True,
                                 encoder=marshal.dumps,
                                 decoder=marshal.loads)
        gipc.start_process(run_shard, (self.config, sid, cpipe))
        self.shards[sid] = GIPCProxy(self, ppipe)
Example #7
0
 def __init__(self, settings, client=None, max_channels_per_category=50):
     """Accepts Django settings object and optional Discord APIClient (for testing)."""
     self._client = client or APIClient(settings.DISCORD_API_TOKEN)
     self._guild_id = settings.DISCORD_GUILD_ID
     self._puzzle_category_name = settings.DISCORD_PUZZLE_CATEGORY
     self._archived_category_name = settings.DISCORD_ARCHIVE_CATEGORY
     self._puzzle_announcements_id = settings.DISCORD_PUZZLE_ANNOUNCEMENTS_CHANNEL
     self._max_channels_per_category = max_channels_per_category
Example #8
0
    def execute_url(cls, url, **kwargs):
        from disco.api.client import APIClient

        results = WEBHOOK_URL_RE.findall(url)
        if len(results) != 1:
            return Exception('Invalid Webhook URL')

        return cls(id=results[0][0],
                   token=results[0][1]).execute(client=APIClient(None),
                                                **kwargs)
Example #9
0
class AutoSharder(object):
    def __init__(self, config):
        self.config = config
        self.client = APIClient(config.token)
        self.shards = {}
        self.config.shard_count = self.client.gateway_bot_get()['shards']
        if self.config.shard_count > 1:
            self.config.shard_count = 10

    def run_on(self, sid, raw):
        func = load_function(raw)
        return self.shards[sid].execute(func).wait(timeout=15)

    def run(self):
        for shard in range(self.config.shard_count):
            if self.config.manhole_enable and shard != 0:
                self.config.manhole_enable = False

            self.start_shard(shard)
            gevent.sleep(6)

        logging.basicConfig(
            level=logging.INFO,
            format=
            '{} [%(levelname)s] %(asctime)s - %(name)s:%(lineno)d - %(message)s'
            .format(id))

    @staticmethod
    def dumps(data):
        if isinstance(data, (basestring, int, long, bool, list, set, dict)):
            return '\x01' + marshal.dumps(data)
        elif isinstance(data, object) and data.__class__.__name__ == 'code':
            return '\x01' + marshal.dumps(data)
        else:
            return '\x02' + pickle.dumps(data)

    @staticmethod
    def loads(data):
        enc_type = data[0]
        if enc_type == '\x01':
            return marshal.loads(data[1:])
        elif enc_type == '\x02':
            return pickle.loads(data[1:])

    def start_shard(self, sid):
        cpipe, ppipe = gipc.pipe(duplex=True,
                                 encoder=self.dumps,
                                 decoder=self.loads)
        gipc.start_process(run_shard, (self.config, sid, cpipe))
        self.shards[sid] = GIPCProxy(self, ppipe)
Example #10
0
def get_root_rwr_servers_status():
    """Check the status of the RWR root servers."""
    from models import RwrRootServer, RwrRootServerStatus, Variable
    from disco.api.client import APIClient as DiscordAPIClient
    from flask import url_for
    from rwrs import db
    import rwr.constants
    import helpers
    import arrow

    click.echo('Pinging servers')

    hosts_to_ping = [server['host'] for group in rwr.constants.ROOT_RWR_SERVERS for server in group['servers']]
    rwr_root_servers = RwrRootServer.query.filter(RwrRootServer.host.in_(hosts_to_ping)).all()
    rwr_root_servers_by_host = {rwr_root_server.host: rwr_root_server for rwr_root_server in rwr_root_servers}
    servers_down_count_then = sum([1 for rwr_root_server in rwr_root_servers if rwr_root_server.status == RwrRootServerStatus.DOWN])
    servers_down_count_now = 0

    for host in hosts_to_ping:
        click.echo(host, nl=False)

        is_server_up = helpers.ping(host)

        if is_server_up:
            click.secho(' Up', fg='green')
        else:
            click.secho(' Down', fg='red')

            servers_down_count_now += 1

        if host not in rwr_root_servers_by_host:
            rwr_root_server = RwrRootServer()
            rwr_root_server.host = host
        else:
            rwr_root_server = rwr_root_servers_by_host[host]

        rwr_root_server.status = RwrRootServerStatus.UP if is_server_up else RwrRootServerStatus.DOWN

        db.session.add(rwr_root_server)

    Variable.set_value('last_root_rwr_servers_check', arrow.utcnow().floor('minute'))

    click.echo('Persisting to database')

    db.session.commit()

    message = None

    if servers_down_count_then == 0 and servers_down_count_now > 0:
        with app.app_context():
            message = ':warning: Online multiplayer is having issues right now. Are the devs aware? If not, poke **pasik** or **JackMayol**. Some details here: {}'.format(url_for('online_multiplayer_status', _external=True))
    elif servers_down_count_then > 0 and servers_down_count_now == 0:
        message = ':white_check_mark: Outage update: online multiplayer is back up and running!'

    if message:
        click.echo('Sending Discord bot message')

        discord_api_client = DiscordAPIClient(app.config['DISCORD_BOT_TOKEN'])
        discord_api_client.channels_messages_create(app.config['DISCORD_BOT_CHANNEL_ID'], message)

    click.secho('Done', fg='green')
Example #11
0
 def __init__(self, settings, client=None, max_channels_per_category=50):
     """Accepts Django settings object and optional Discord APIClient (for testing)."""
     self._client = client or APIClient(settings.DISCORD_API_TOKEN)
     self._max_channels_per_category = max_channels_per_category
Example #12
0
 def __init__(self):
     self.client = None
     self.avatars = None
     if self.TOKEN and not settings.IS_TEST:
         self.client = APIClient(self.TOKEN)
Example #13
0
class DiscordInterface:
    TOKEN = None  # FIXME a long token from Discord

    # the next two should be big decimal numbers; in Discord, you can right
    # click and Copy ID to get them
    GUILD = 'FIXME'
    HINT_CHANNEL = 'FIXME'

    # You also need to enable the "Server Members Intent" under the "Privileged
    # Gateway Intents" section of the "Bot" page of your application from the
    # Discord Developer Portal. Or you can comment out the code that
    # initializes `self.avatars` below.

    def __init__(self):
        self.client = None
        self.avatars = None
        if self.TOKEN and not settings.IS_TEST:
            self.client = APIClient(self.TOKEN)

    def get_avatars(self):
        if self.avatars is None:
            self.avatars = {}
            if self.client is not None:
                members = self.client.guilds_members_list(self.GUILD).values()
                for member in members:
                    self.avatars[member.user.username] = member.user.avatar_url
                for member in members:
                    self.avatars[member.name] = member.user.avatar_url
        return self.avatars

    # If you get an error code 50001 when trying to create a message, even
    # though you're sure your bot has all the permissions, it might be because
    # you need to "connect to and identify with a gateway at least once"??
    # https://discord.com/developers/docs/resources/channel#create-message

    # I spent like four hours trying to find weird asynchronous ways to do this
    # right before each time I send a message, but it seems maybe you actually
    # just need to do this once and your bot can create messages forever?
    # disco.py's Client (not APIClient) wraps an APIClient and a GatewayClient,
    # the latter of which does this. So I believe you can fix this by running a
    # script like the following *once* on your local machine (it will, as
    # advertised, run forever; just kill it after a few seconds)?

    # from gevent import monkey
    # monkey.patch_all()
    # from disco.client import Client, ClientConfig
    # Client(ClientConfig({'token': TOKEN})).run_forever()

    def update_hint(self, hint):
        HintsConsumer.send_to_all(
            json.dumps({
                'id':
                hint.id,
                'content':
                render_to_string('hint_list_entry.html', {
                    'hint': hint,
                    'now': timezone.localtime()
                })
            }))
        embed = MessageEmbed()
        embed.author.url = hint.full_url()
        if hint.claimed_datetime:
            embed.color = 0xdddddd
            embed.timestamp = hint.claimed_datetime.isoformat()
            embed.author.name = 'Claimed by {}'.format(hint.claimer)
            if hint.claimer in self.get_avatars():
                embed.author.icon_url = self.get_avatars()[hint.claimer]
            debug = 'claimed by {}'.format(hint.claimer)
        else:
            embed.color = 0xff00ff
            embed.author.name = 'U N C L A I M E D'
            claim_url = hint.full_url(claim=True)
            embed.title = 'Claim: ' + claim_url
            embed.url = claim_url
            debug = 'unclaimed'

        if self.client is None:
            message = hint.long_discord_message()
            logger.info('Hint, {}: {}\n{}'.format(debug, hint, message))
            logger.info('Embed: {}'.format(embed.to_dict()))
        elif hint.discord_id:
            try:
                self.client.channels_messages_modify(self.HINT_CHANNEL,
                                                     hint.discord_id,
                                                     embed=embed)
            except Exception:
                dispatch_general_alert(
                    'Discord API failure: modify\n{}'.format(
                        traceback.format_exc()))
        else:
            message = hint.long_discord_message()
            try:
                discord_id = self.client.channels_messages_create(
                    self.HINT_CHANNEL, message, embed=embed).id
            except Exception:
                dispatch_general_alert(
                    'Discord API failure: create\n{}'.format(
                        traceback.format_exc()))
                return
            hint.discord_id = discord_id
            hint.save(update_fields=('discord_id', ))

    def clear_hint(self, hint):
        HintsConsumer.send_to_all(json.dumps({'id': hint.id}))
        if self.client is None:
            logger.info('Hint done: {}'.format(hint))
        elif hint.discord_id:
            # try:
            #     self.client.channels_messages_delete(
            #         self.HINT_CHANNEL, hint.discord_id)
            # except Exception:
            #     dispatch_general_alert('Discord API failure: delete\n{}'.format(
            #         traceback.format_exc()))
            # hint.discord_id = ''
            # hint.save(update_fields=('discord_id',))

            # what DPPH did instead of deleting messages:
            # (nb. I tried to make these colors color-blind friendly)

            embed = MessageEmbed()
            if hint.status == 'ANS':
                embed.color = 0xaaffaa
            elif hint.status == 'REF':
                embed.color = 0xcc6600
            # nothing for obsolete

            embed.author.name = '{} by {}'.format(hint.status, hint.claimer)
            embed.author.url = hint.full_url()
            embed.description = hint.response[:250]
            if hint.claimer in self.get_avatars():
                embed.author.icon_url = self.get_avatars()[hint.claimer]
            debug = 'claimed by {}'.format(hint.claimer)
            try:
                self.client.channels_messages_modify(
                    self.HINT_CHANNEL,
                    hint.discord_id,
                    content=hint.short_discord_message(),
                    embed=embed)
            except Exception:
                dispatch_general_alert(
                    'Discord API failure: modify\n{}'.format(
                        traceback.format_exc()))
Example #14
0
 def __init__(self):
     self.api = APIClient(settings.DISCORD_BOT_TOKEN)
     self.guild = self.api.http(Routes.USERS_ME_GUILDS_LIST).json()[0]
Example #15
0
class DiscordAPI:

    def __init__(self):
        self.api = APIClient(settings.DISCORD_BOT_TOKEN)
        self.guild = self.api.http(Routes.USERS_ME_GUILDS_LIST).json()[0]


    def is_user_in_guild(self, user_id):
        members = self.api.guilds_members_list(self.guild['id']).keys()
        return int(user_id) in members


    def kick_member(self, user_id):
        try:
            reason = "User no longer had the correct access level for discord"
            self.api.guilds_members_kick(self.guild['id'], user_id, reason)
            return True
        except:
            return False


    def set_name(self, user_id, name):
        try:
            self.api.guilds_members_modify(self.guild['id'], user_id, nick=name)
            return True
        except:
            return False


    # Roles is a list of role name strings
    def update_roles(self, user_id, roles):
        # Find roles we need to create
        guild_roles = self.api.guilds_roles_list(self.guild['id'])
        guild_roles_map = map(lambda x: x.name, guild_roles)
        for role_name in Set(roles).difference(guild_roles_map):
            role = self.api.guilds_roles_create(self.guild['id'])
            self.api.guilds_roles_modify(self.guild['id'], role.id, name=role_name)
            guild_roles.append(role)

        # Build snowflake list
        snowflakes = []
        for role in roles:
            snowflakes.append(filter(lambda x: x.name == role, guild_roles)[0].id)

        self.api.guilds_members_modify(self.guild['id'], user_id, roles=snowflakes)
def create_client():
    return APIClient(env("DISCORD_TOKEN", default=""))