import asyncio,websockets,logging,ujson,argparse from apscheduler.schedulers.asyncio import AsyncIOScheduler parser = argparse.ArgumentParser() # Command line specific arguments parser.add_argument('--token', help='Bot Authentication Token', default=None) parser.add_argument('--sequence', help='Bot Authentication Sequence', default=None) parser.add_argument('--session', help='Bot Authentication Session', default=None) class tinyclient(): def __init__ (self, *args, **kwargs): self.opcode_map = {0:'dispatch',1:'heartbeat',2:'identify',3:'presence',4:'voice_state',5:'voice_ping',6:'resume',7:'reconnect',8:'request_members',9:'invalidate_session',10:'hello',11:'heartbeat_ack',12:'guild_sync'} self.last_sequence = kwargs.pop('sequence',None) self.session_id = kwargs.pop('session',None) self.token=kwargs.pop('token',None) self.user=None self.scheduler = AsyncIOScheduler(timezone='utc') self.scheduler.start() self.websocket = None self.log = logging.getLogger(__name__) #self.log.setLevel(logging.DEBUG) #self.log.addHandler(logging.StreamHandler()) self.loop = asyncio.get_event_loop() def event(self, coro): if not asyncio.iscoroutinefunction(coro): raise Exception('event registered must be a coroutine function') setattr(self, coro.__name__, coro) self.log.debug('{0.__name__} has successfully been registered as an event'.format(coro)) return coro def dispatch(self, event, *args, **kwargs): self.log.debug('Dispatching event {}'.format(event)) method = 'on_' + event handler = 'handle_' + event if hasattr(self, handler): o = getattr(self, handler) asyncio.async(o(*args, **kwargs), loop=self.loop) if hasattr(self, method): o = getattr(self, method) asyncio.async(o(*args, **kwargs), loop=self.loop) async def next_message(self): message = await self.websocket.recv() o = ujson.loads(message) self.last_sequence = o.get('s') return o async def run(self,*args,**kwargs): async with websockets.connect('wss://gateway.discord.gg/?encoding=json&v=6') as self.websocket: while True: o = await self.next_message() event_name = self.opcode_map[o.get('op')] self.dispatch(event_name, o) async def handle_hello(self,data): interval = int(data.get('d').get('heartbeat_interval')) / 1000 self.scheduler.add_job(self.websocket.send, 'interval', seconds=interval, args=(ujson.dumps({"op": 1, "d": self.last_sequence}),)) if self.last_sequence and self.session_id: resume = {"op":6,"d":{"token":self.token, "session_id":self.session_id, "seq":self.last_sequence}} await self.websocket.send(ujson.dumps(resume)) else: identify = {"op":2,"d":{"token":self.token,"properties":{"os":"Linux"},"large_threshold":250,"synced_guilds":[],"presence":{"status":"online","since":0,"afk":False,"game":None},"compress":False}} await self.websocket.send(ujson.dumps(identify)) async def handle_dispatch(self, data): if data.get('t') == 'READY': self.session_id = data.get('d').get('session_id') self.user = data.get('d').get('user') if data.get('t'): event_name = data.get('t').lower() self.dispatch(event_name, data) def bot_main(run=False): # Parse out all our command line arguments args = parser.parse_args() logging.info("token=%s, sequence=%s, session=%s,",args.token,args.sequence,args.session) # create a new bot-class instance t = tinyclient(token=args.token,sequence=args.sequence,session=args.session) @t.event async def on_message_delete(*args): data, = args id = data.get('d').get('id') @t.event async def on_message_update(*args): data, = args id = data.get('d').get('id') @t.event async def on_message_create(*args): data, = args asyncio.get_event_loop().run_until_complete(t.run()) asyncio.get_event_loop().run_forever() if __name__ == "__main__": # configure basic logging (also muting noisy libs) logging.basicConfig(level=logging.INFO,format='%(levelname)-6s%(name)-8s%(asctime)s - %(message)s') [logging.getLogger(x).setLevel(logging.ERROR) for x in ['apscheduler']] bot_main(True)