from datetime import datetime, timezone, timedelta import asyncio import functools import click from procs import flush_messages from payphone.db import setup, models from payphone.bot import bot from payphone.core import logging, config, constants logging.setup("Tasks") log = logging.logger def coroutine(f): @functools.wraps(f) def wrapper(*args, **kwargs): return asyncio.run(f(*args, **kwargs)) return wrapper @click.group() @coroutine async def main(): await setup.init() @main.command() @coroutine async def flush(): """Flush all messages in Redis to the database. Runs every 5 seconds.""" while True: await flush_messages.flush() await asyncio.sleep(5) @main.command() @coroutine async def delete_accounts(): """Delete all accounts that were scheduled for deletion. Runs every 1 hour.""" while True: total = await models.User.filter(is_deleting=True).delete() log.info("Deleted %s accounts scheduled for deletion.", total) await asyncio.sleep(60 * 60) @main.command() @coroutine async def hangup_inactive_calls(): """Hangs up inactive calls.""" await bot.login(config.TOKEN) await bot.redis.ping() while True: await asyncio.sleep(5) for call in await models.Call.filter(ended_at=None).prefetch_related( "channels" ): if call.started_at > datetime.now(timezone.utc) - timedelta(minutes=1): continue if ( await bot.redis.exists( constants.CALL_MESSAGES_TEMPLATE % call.id, constants.CALL_IS_ACTIVE % call.id, ) ) != 2: call.ended_at = datetime.now(timezone.utc) await call.save() log.info("Hung up call %s.", call.id) try: channels = [ await bot.get_or_fetch_channel(channel.id) for channel in call.channels ] for channel in channels: try: await channel.send( "☎️ The call was hung up because nobody replied." ) finally: pass finally: continue if __name__ == "__main__": main()