async def background_task_rotation_hype(self) -> None: rotation_hype_channel_id = configuration.get_int( 'rotation_hype_channel_id') if not rotation_hype_channel_id: logging.warning('rotation hype channel is not configured') return channel = self.get_channel(rotation_hype_channel_id) if not isinstance(channel, discord.abc.Messageable): logging.warning('rotation hype channel is not a text channel') return while self.is_ready(): until_rotation = rotation.next_rotation() - dtutil.now() last_run_time = rotation.last_run_time() if until_rotation < datetime.timedelta( 7) and last_run_time is not None: if dtutil.now() - last_run_time < datetime.timedelta( minutes=5): hype = await rotation_hype_message() if hype: await channel.send(hype) timer = 5 * 60 else: timer = int( (until_rotation - datetime.timedelta(7)).total_seconds()) await asyncio.sleep(timer)
def lint(argv: List[str]) -> None: """ Invoke Pylint with our preferred options """ print('>>>> Running pylint') args = [ '--rcfile=.pylintrc', # Load rcfile first. '--ignored-modules=alembic,MySQLdb,flask_sqlalchemy,distutils.dist', # override ignored-modules (codacy hack) '--load-plugins', 'pylint_quotes,pylint_monolith', # Plugins '-f', 'parseable', # Machine-readable output. '-j', str(configuration.get_int( 'pylint_threads')), # Use four cores for speed. ] args.extend(argv or find_files(file_extension='py')) # pylint: disable=import-outside-toplevel import pylint.lint try: linter = pylint.lint.Run(args, exit=False) except PicklingError: print('Error while running pylint with multiprocessing') configuration.write('pylint_threads', 1) lint(argv) return if linter.linter.msg_status: raise TestFailedException(linter.linter.msg_status)
async def background_task_tournaments(self) -> None: try: await self.wait_until_ready() tournament_channel_id = configuration.get_int( 'tournament_channel_id') if not tournament_channel_id: return channel = self.get_channel(tournament_channel_id) while not self.is_closed: info = tournaments.next_tournament_info() diff = info['next_tournament_time_precise'] if info['sponsor_name']: message = 'A {sponsor} sponsored tournament'.format( sponsor=info['sponsor_name']) else: message = 'A free tournament' embed = discord.Embed(title=info['next_tournament_name'], description=message) if diff <= 0: embed.add_field( name='Starting now', value= 'Check <#334220558159970304> for further annoucements') elif diff <= 14400: embed.add_field(name='Starting in:', value=dtutil.display_time(diff, 2)) embed.add_field(name='Pre-register now:', value='https://gatherling.com') if diff <= 14400: embed.set_image( url=fetcher.decksite_url('/favicon-152.png')) # See #2809. # pylint: disable=no-value-for-parameter,unexpected-keyword-arg await channel.send(embed=embed) if diff <= 300: # Five minutes, final warning. Sleep until the tournament has started. timer = 301 elif diff <= 1800: # Half an hour. Sleep until 5 minute warning. timer = diff - 300 elif diff <= 3600: # One hour. Sleep until half-hour warning. timer = diff - 1800 else: # Wait until four hours before tournament. timer = 3600 + diff % 3600 if diff > 3600 * 6: # The timer can afford to get off-balance by doing other background work. await self.background_task_spoiler_season() multiverse.update_bugged_cards() if timer < 300: timer = 300 print('diff={0}, timer={1}'.format(diff, timer)) await asyncio.sleep(timer) except Exception: # pylint: disable=broad-except await self.on_error('background_task_tournaments')
async def background_task_league_end(self) -> None: tournament_channel_id = configuration.get_int( 'tournament_reminders_channel_id') if not tournament_channel_id: logging.warning('tournament channel is not configured') return channel = self.get_channel(tournament_channel_id) if not isinstance(channel, discord.abc.Messageable): logging.warning('tournament channel could not be found') return while self.is_ready: try: league = await fetch_tools.fetch_json_async( fetcher.decksite_url('/api/league')) except fetch_tools.FetchException as e: logging.error( "Couldn't reach decksite or decode league json with error message(s) {e}", e='; '.join(str(x) for x in e.args)) logging.info('Sleeping for 5 minutes and trying again.') await asyncio.sleep(300) continue if not league: await asyncio.sleep(300) continue diff = round((dtutil.parse_rfc3339(league['end_date']) - datetime.datetime.now(tz=datetime.timezone.utc)) / datetime.timedelta(seconds=1)) embed = discord.Embed( title=league['name'], description= 'League ending soon - any active runs will be cut short.') if diff <= 60 * 60 * 24: embed.add_field(name='Ending in:', value=dtutil.display_time(diff, 2)) embed.set_image(url=fetcher.decksite_url('/favicon-152.png')) # See #2809. # pylint: disable=no-value-for-parameter,unexpected-keyword-arg await channel.send(embed=embed) if diff <= 5 * 60: # Five minutes, final warning. timer = 301 elif diff <= 1 * 60 * 60: # 1 hour. Sleep until five minute warning. timer = diff - 300 elif diff <= 24 * 60 * 60: # 1 day. Sleep until one hour warning. timer = diff - 1800 else: # Sleep for 1 day, plus enough to leave us with a whole number of days timer = 24 * 60 * 60 + diff % (24 * 60 * 60) if timer < 300: timer = 300 await asyncio.sleep(timer) logging.warning('naturally stopping league reminders')
def decksite_url(path: str = '/') -> str: hostname = configuration.get_str('decksite_hostname') port = configuration.get_int('decksite_port') if port != 80: hostname = '{hostname}:{port}'.format(hostname=hostname, port=port) url = parse.urlunparse((configuration.get_str('decksite_protocol'), hostname, path, '', '', '')) assert url is not None return url
def __init__(self, db: str) -> None: warnings.filterwarnings('error', category=MySQLdb.Warning) self.name = db self.host = configuration.get_str('mysql_host') self.port = configuration.get_int('mysql_port') self.user = configuration.get_str('mysql_user') self.passwd = configuration.get_str('mysql_passwd') self.connect()
async def background_task_tournaments(self) -> None: tournament_channel_id = configuration.get_int( 'tournament_reminders_channel_id') if not tournament_channel_id: logging.warning('tournament channel is not configured') return channel = self.get_channel(tournament_channel_id) if not isinstance(channel, discord.abc.Messageable): logging.warning('ERROR: could not find tournament_channel_id {id}', id=tournament_channel_id) return while self.is_ready: info = tournaments.next_tournament_info() diff = info['next_tournament_time_precise'] if info['sponsor_name']: message = 'A {sponsor} sponsored tournament'.format( sponsor=info['sponsor_name']) else: message = 'A free tournament' embed = discord.Embed(title=info['next_tournament_name'], description=message) if diff <= 1: embed.add_field( name='Starting now', value='Check <#334220558159970304> for further annoucements' ) elif diff <= 14400: embed.add_field(name='Starting in:', value=dtutil.display_time(diff, 2)) embed.add_field(name='Pre-register now:', value='https://gatherling.com') if diff <= 14400: embed.set_image(url=fetcher.decksite_url('/favicon-152.png')) # See #2809. # pylint: disable=no-value-for-parameter,unexpected-keyword-arg await channel.send(embed=embed) if diff <= 300: # Five minutes, final warning. Sleep until the tournament has started. timer = 301 elif diff <= 1800: # Half an hour. Sleep until 5 minute warning. timer = diff - 300 elif diff <= 3600: # One hour. Sleep until half-hour warning. timer = diff - 1800 else: # Sleep for one hour plus enough to have a whole number of hours left. timer = 3600 + diff % 3600 if diff > 3600 * 6: # The timer can afford to get off-balance by doing other background work. await multiverse.update_bugged_cards_async() if timer < 300: timer = 300 await asyncio.sleep(timer) logging.warning('naturally stopping tournament reminders')
def run() -> None: """Make a 'safe' (no personal info) copy of the current prod db for download by devs.""" host = configuration.get_str('mysql_host') port = configuration.get_int('mysql_port') usr = configuration.get_str('mysql_user') pwd = configuration.get_str('mysql_passwd') db = configuration.get_str('decksite_database') if not (host or port or usr or pwd or db): safe_pwd = 'PRESENT' if pwd else 'MISSING' raise InvalidArgumentException(f'Unable to dump dev db with {host} {port} {usr} pwd:{safe_pwd} {db}') base_command = ['mysqldump', '-h', host, '-P', str(port), '-u', usr, f'-p{pwd}'] structure = subprocess.check_output(base_command + ['--no-data', db]) data = subprocess.check_output(base_command + [f'--ignore-table={db}.person_note', db]) with gzip.open('shared_web/static/dev-db.sql.gz', 'wb') as f: f.write(structure) f.write(data)
def is_tournament_channel(channel: TextChannel) -> bool: tournament_channel_id = configuration.get_int('tournament_channel_id') if not tournament_channel_id: return False return channel.id == tournament_channel_id
def logsite_url(path: str = '/') -> str: return site_url(configuration.get_str('logsite_protocol'), configuration.get_str('logsite_hostname'), configuration.get_int('logsite_port'), path)