0

This is a very basic question in my eyes, but I have spent hours trying to figure out the issue, and can't wrap my head around it.

I have a class called WSManager that has a variety of methods to manage a WebSocket connection using the ws module and the Discord API. For some strange reason, my class turns into the WebSocket instance inside of the class, which is very strange, as I now can't access the handleHello method.

The error I get:

TypeError: this.handleHello is not a function
    at WebSocket.handleWSMessage (/home/samthefam/Projects/Official/Personal/discord-halo/src/WSManager.ts:51:25)
    at WebSocket.emit (events.js:375:28)
    at Receiver.receiverOnMessage (/home/samthefam/Projects/Official/Personal/discord-halo/node_modules/ws/lib/websocket.js:833:20)
    at Receiver.emit (events.js:375:28)
    at Receiver.dataMessage (/home/samthefam/Projects/Official/Personal/discord-halo/node_modules/ws/lib/receiver.js:517:14)
    at Receiver.getData (/home/samthefam/Projects/Official/Personal/discord-halo/node_modules/ws/lib/receiver.js:435:17)
    at Receiver.startLoop (/home/samthefam/Projects/Official/Personal/discord-halo/node_modules/ws/lib/receiver.js:143:22)
    at Receiver._write (/home/samthefam/Projects/Official/Personal/discord-halo/node_modules/ws/lib/receiver.js:78:10)
    at writeOrBuffer (internal/streams/writable.js:358:12)
    at Receiver.Writable.write (internal/streams/writable.js:303:10)
[ERROR] 08:07:20 TypeError: this.handleHello is not a function

Here are the important parts of the script:

// ...imports

class WSManager {
    private ws?: WebSocket;
    
    constructor(private client: Client)
        // ...initalise properties
    }

    public async connect(): Promise<void> {
        this.ws = await this.createWebSocket(); // This is the line that appears to cause 'this' to turn into 'this.ws', however it doesn't break until 'this.handleHello()' strangely.
        this.handleWSConnection();
    }

    private handleWSConnection(): void {
        this.ws.on("message", this.handleWSMessage);
        // ...other events
    }

    private handleWSMessage(rawData: string): void {
        // ...do stuff
        this.handleHello();
    }

    public async getWSEndpoint(token: string): Promise<string> {
        const { data: wsEndpointData }: { data: WSEndpointData } =
            await axios.get(`${apiEndpoint}/gateway/bot`, {
                headers: {
                    Authorization: `Bot ${token}`,
                },
            });

        return wsEndpointData.url;
    }

    private async createWebSocket() {
        const wsEndpoint = await this.getWSEndpoint(this.client.token);

        return new WebSocket(
            `${wsEndpoint}/?v=${config.gatewayVersion}&encoding=json`
        );
    }

    handleHello(data: HelloData): void {
        const hbInterval: number = data.d.heartbeat_interval;
        this.hbData.d = data.s;
        this.sequenceNumber = data.s;

        setTimeout(() => {
            this.heartbeat();

            setInterval(() => {
                this.heartbeat();
            }, hbInterval);
        }, hbInterval * Math.random());

        this.identify();
    }
}

export default WSManager;

All help would be greatly appreciated.

conaticus
  • 301
  • 1
  • 4
  • 14

1 Answers1

2

This happens because handleWSMessage is called without this being bound to your object.

The problem is here:

this.ws.on("message", this.handleWSMessage);

Change it to:

this.ws.on("message", data => this.handleWSMessage(data));
trincot
  • 317,000
  • 35
  • 244
  • 286