#Help determining why a socket in context is null

11 messages · Page 1 of 1 (latest)

tardy pondBOT
#

🔎 This post has been indexed in our web forum and will be seen by search engines so other users can find it outside Discord

🕵️ Your user profile is private by default and won't be visible to users outside Discord, if you want to be visible in the web forum you can add the "Public Profile" role in id:customize

✅ You can mark a message as the answer for your post with Right click -> Apps -> Mark Solution
(if you don't see the option, try refreshing Discord with Ctrl + R)

supple hedge
#

So I have a SocketContext provider like so:


import React, { createContext, useContext, useEffect, useState } from 'react';
import UserProvider, {SessionContext} from "./UserProvider";

type WebSocketContextType = {
    socket: WebSocket | null,
    subscribeToAllMessages: (callback: (message: WebsocketMessage) => void) => void;
    subscribeToMessageName: (name: string, callback: (message: WebsocketMessage) => void) => void;
    unsubscribeToMessageName: (name: string, callback: (message: WebsocketMessage) => void) => void;
    unsubscribeFromAllMessages: (callback: (message: WebsocketMessage) => void) => void;
    emit: (message: WebsocketMessage) => void;

    connected: boolean;
};



export type WebsocketMessage = {
    name: string,
    type: string,
    message: any
}

export const WebsocketContext = createContext<WebSocketContextType>({
    socket: null,
    subscribeToAllMessages: () =>{},
    subscribeToMessageName: () =>{},
    unsubscribeToMessageName: () =>{},
    unsubscribeFromAllMessages: () =>{},
    emit: () =>{},
    connected: false,
});
#

export const WebSocketProvider: React.FC = ({ children }) => {
    const { sessionToken } = useContext(SessionContext);
    const [socket, setSocket] = useState<WebSocket | null>(null);
    const [connected, setConnected] = useState<boolean>(false);
    const allMessageSubscribers = new Set<(message: WebsocketMessage) => void>();
    const singleMessageSubscribers = new Map<string, Set<(message: WebsocketMessage) => void>>();

    useEffect(() => {
        console.log('trying to connect')
        const newSocket = new WebSocket('ws://localhost:8044');

        newSocket.onopen = () => {
            console.log('Connected to WebSocket');
            setSocket(newSocket);
            setConnected(true);
        };

        newSocket.onerror = (err) => {
            console.log('failed to connect', err);
            setConnected(false);
        }
        newSocket.onclose = (err) => {
            console.log('socket closed', err);
            setConnected(false);
        }
        newSocket.onmessage = (event) => {
            const message = event.data.toString();
            const parsedMessage: WebsocketMessage = JSON.parse(message);
            allMessageSubscribers.forEach((subscriber) => subscriber(message));
            if (singleMessageSubscribers.has(parsedMessage.name)) {
                const subscribers = singleMessageSubscribers.get(parsedMessage.name);
                if (subscribers) subscribers.forEach((subscriber) => subscriber(message));
            }
        };

        return () => {
            if (socket) {
                socket.close();
            }
        };
    }, [sessionToken]);
#
 useEffect(() => {
        if (socket && connected) {
            emit({
                name: 'handshake',
                type: 'auth',
                message: {
                    'token': sessionToken
                }
            });
        }

    }, [socket, connected]);

    const subscribeToAllMessages = (callback: (message: WebsocketMessage) => void) => {
        allMessageSubscribers.add(callback);
    };

    const subscribeToMessageName = (name: string, callback: (message: WebsocketMessage) => void) => {
        if (!singleMessageSubscribers.has(name)) {
            singleMessageSubscribers.set(name, new Set<(message: WebsocketMessage) => void>([callback]));
        } else {
            const subscribers = singleMessageSubscribers.get(name);
            if (subscribers) subscribers.add(callback);
        }
    };
    const unsubscribeToMessageName = (name: string, callback: (message: WebsocketMessage) => void) => {
        if (singleMessageSubscribers.has(name)) {
            const subscribers = singleMessageSubscribers.get(name);
            if (subscribers) {
                subscribers.delete(callback);
                if (subscribers.size === 0) singleMessageSubscribers.delete(name);
            }
        }
    };

    const emit = (message: WebsocketMessage) => {
        alert(socket + ' ' + JSON.stringify(message));
        socket?.send(JSON.stringify(message));
    }
    const unsubscribeFromAllMessages = (callback: (message: WebsocketMessage) => void) => {
        allMessageSubscribers.delete(callback);
    };

    const value: WebSocketContextType = {
        socket: socket,
        subscribeToAllMessages,
        subscribeToMessageName,
        unsubscribeToMessageName,
        unsubscribeFromAllMessages,
        emit,
        connected,
    };

    return <WebsocketContext.Provider value={value}>{children}</WebsocketContext.Provider>;
};```
#

Component:

const WheelPage: React.FC<WheelPageProps> = ({  }) => {
    //const { sessionToken, loggedIn, validatingAuth, login, logout } = useContext(SessionContext);
    const { subscribeToMessageName, unsubscribeToMessageName, emit, socket, connected } = useContext(WebsocketContext);
    const [wheel, setWheel] = useState<Wheel>();

    const onSocket = (message: WebsocketMessage) => {
        console.log(message);
        if (message.type === 'spin') wheel?.startSpinning();
    };
    const onHandshake = (message: WebsocketMessage) => {
        console.log('got handshakes ' + message);
        console.log(socket);
        if (socket) {
            const pingMessage: WebsocketMessage = {
                name: 'wheel',
                type: 'ping',
                message: null
            }
            emit(pingMessage);
        }

    };


    useEffect(() => {
        subscribeToMessageName('wheel', onSocket);
        subscribeToMessageName('handshake', onHandshake);
    }, [socket]);
....
#

I have a useEffect in the WebsocketContext that when connected, emits a handshake request, (server then responds with a handshake response)
So in my component, i subscribe to the handshake messages,
My component receives the handshake just fine,
But when it emits the pingMessage, socket is NULL. But socket can't be null, as i just received a socket message. The socket is also not closed.
Does anyone have any idea what the issue may be? My theory is some async stuff with useEffect but I'm not having any luck

#

Help determining why a socket in context is null

#

just baffles me how the onHandshake callback can get called, but detect socket as null

supple hedge
#

anyone know? am i maybe using the context wrong?

#

i've also tried adding "connected" as the dependency in the useEffect, with and without socket too

#

same results