TheCoffee
TheCoffee

Reputation: 73

Discord api websocket gateway connection disconnects after some time

I don't know why but it keeps disconnecting. Sometimes it works for 1 hour, sometimes less and sometimes 2.5 hour-ish

import aiohttp
import asyncio
import json
import datetime, time

token = "123"

payload = {
    'op': 2,
    "d": {
        "token": token,
        "properties": {
            "$os": "windows",
            "$browser": "chrome",
            "$device": 'pc'
        }
    }
}



last_sequence = "null"

async def main():
    global last_sequence


    session = aiohttp.ClientSession()
    async with  session.ws_connect('wss://gateway.discord.gg/?v=9&encording=json') as ws:
        async for msg in ws:
            data = json.loads(msg.data)

            if data["op"] == 10:  # Hello
                await ws.send_json(payload)

                # (Keeps the connection alive!)
                asyncio.ensure_future(heartbeat(ws, data['d']['heartbeat_interval']))
            elif data["op"] == 11:  # Heartbeat ACK
                #print("Heartbeat Received")
                pass

            elif data["op"] == 0:  # Dispatch
                try:
                    if data['d']['guild_id']==("669653521007902751") and data['d']['channel_id']==("669653521007902766"):
                        print(f"{data['d']['content']}")
                        last_sequence = data['s']   
                        #print(data)  

                except:
                    pass

            elif data["op"] == 3: # Presence Update 
                print("This is OP 3", data)
            elif data["op"] == 4: # Voice State Update  
                print("This is OP 4", data)
            elif data["op"] == 6: # Resume
                print("This is OP 6", data)
            elif data["op"] == 7: # Reconnect, i don't know how this works. I was just testing it.
                await ws.send_json(
                    {"op": 6,
                        "d": {
                            "token":token,
                            "session_id": "null",
                            "seq": last_sequence
                    }})
                print("This is OP 7", data)
            elif data["op"] == 8: # Request Guild Members   
                print("This is OP 8", data)
            elif data["op"] == 9: # Invalid Session
                print("This is OP 9", data)


            else:
                print("What happened?", data)
                
        #await session.close()
    



async def heartbeat(ws, interval):
    while True:
        await asyncio.sleep(interval / 1000)  # seconds
        await ws.send_json({
            "op": 1,  # Heartbeat
            "d": last_sequence
        })
        print("Heartbeat Sent", last_sequence, time.strftime("%H:%M:%S", time.localtime()))




loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()

The error is

This is OP 7 {'t': None, 's': None, 'op': 7, 'd': None} Task was destroyed but it is pending! task: <Task pending name='Task-4' coro=<heartbeat() running at C:\Users\test\Desktop\Discord_Test\aio_test.py:83> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x00000214675B83D0>()]>>

Upvotes: 3

Views: 5393

Answers (1)

teksatan
teksatan

Reputation: 21

Your error is that on an opcode 7 you are not disconnecting. You are just sending the resume string. you need to FULLY close the connection, and reconnect THEN after you get the server hello, send the resume(with a valid session_id and seq, they cannot be null). the server is closing your connection because your sending data to it after it told you to disconnect/reconnect(opcode 7) then your code is crashing because it has a task waiting for the heartbeat when the server kills your connection.

EDIT: (You should store the session_id from the server READY event(after you identify(op 2), and the last "seq" number you received from the server to use them in your resume string for resuming.)

Discord now requires you to periodically reconnect(for no outwardly apparent reason) by sending you an opcode "7". You should make your bot disconnect and reconnect when you receive that opcode. You should then attempt to identify(opcode 2) or resume(opcode 6).

If you have a valid "session_id" and "seq" number you should send a resume(op 6), if not you should identify(op 2). Discord may respond to a resume with an opcode 9(invalid session) and set "d" to true(can try and resume) or false(need to re-identify). You should resend the correct opcode (2 or 6) depending on if d is true or false.(You supposedly do NOT need to disconnect/reconnect on an opcode 9, just resend the identify/resume payload)

https://discord.com/developers/docs/topics/gateway#reconnect

Additional information: https://github.com/discord/discord-api-docs/commit/d4ccc367966eef95b05c8e82ca6cac333ab586db

Lately I have been having another issue where discord is always returning an opcode 9 when I send a resume.

So discord sends an op 7 to my client. I reconnect and send an op 6 after I received the server hello opcode(10). I then immediately, and always receive an opcode 9 even though I am absolutely 100% sending the correct payload data etc for an opcode 6. I then have to resend an opcode 2(identify) and start a new session.

It seems odd discord is now making me restart my session every single time I try and resume after I get an opcode 7, and reconnect. If anyone knows why this is happening that would be nice. but it isn't a terribly big deal since i don't think discord would ever make you re-identify enough times to reach the 1000 identifys per day limit

(I have tried various lengths of time waiting before reconnecting btw)

Upvotes: 2

Related Questions