SocketCluster / socketcluster-client

JavaScript client for SocketCluster
MIT License
291 stars 92 forks source link

socketcluster client #100

Closed astutesoftware closed 6 years ago

astutesoftware commented 6 years ago

I am writing a javascript client and use this

var socket;

var init=function()
{
 socket = socketCluster.connect(options, function(status){
    console.log(socket);
});
}

When i use the global var socket all the .on events report no such method.

How do i overcome this?

Basically what i need is to wait for a couple of HTML DOM processes to end and then start the socketCluster connection but the moment i move the socket var inside a variable inside a function everything goes for a toss.

DarkMukke commented 6 years ago

Not sure because the code is a bit vague but are you missing the async aspect ? Eg are you waiting for the init to run ? Because before init, socket is undefined.

astutesoftware commented 6 years ago

init gets called on document load of the page. I have some GUI elements to be rendered first and would like to create the socket after rendering everything.

DarkMukke commented 6 years ago

Although it shouldn't make a difference, I am not sure why you are waiting for the DOM to be loaded. a connection to the socket cluster should not be waiting for the UI to be loaded first. Over HTTP/1.1 your browser can load 10(ish) resources at the same time per somain/subdomain/port.

can you console.log() the global socket client right before you call the socket.on() that is causing the issue ? Because as state before, if this is undefined, you are calling them too soon and they need to be called after the init.

Also you could try and get around this with a promise wrapper (which you will need to compile with either babel or a promise polyfill on the fly)

For example (this is from one of my own projects, where the whole thing is browserified on deploy)

    const scClient = require('socketcluster-client');

    class SocketWrapper {

        constructor(socketConfig) {

            //setup with empty callbacks for now for typehinting
            this.connectionResolver = () => {
            };
            this.connectionError = () => {
            };
            this.socketConfig = socketConfig;

            //setup connection promise
            this.connectionPromise();

            //bind connection promises
            this.socket.on('connect', (socket) => {
                this.connectionResolver(socket)
            });
            this.socket.on('disconnect', () => {
                //reconnect, get new promise
                this.connectionPromise();
            });
            this.socket.on('error', (err) => {
                this.connectionError(err)
            });
        }

        connectionPromise() {
            this.connection = new Promise((resolve, reject) => {
                this.connectionResolver = resolve;
                this.connectionError = reject;
            });
            //new connect event will fire, so new promise will be resolved
            this.socket = scClient.connect(this.socketConfig);
        }

        on(eventName, callback) {
            this.connection
                .then(() => {
                    this.socket.on(eventName, (data) => {
                        callback(Promise.resolve(data));
                    });
                });

        }

        subscribe(eventName, callback) {
            this.connection
                .then(() => {
                    let channel = this.socket.subscribe(eventName);
                    channel.watch((data) => {
                        callback(Promise.resolve(data));
                    });
                });

        }
    }

    module.exports = {SocketWrapper: SocketWrapper};

Usage:

    const socketConfig = {
        hostname: "socket.server.com",
        port: 3000
    };
    const {SocketWrapper} = require('./SocketWrapper');
    const wrapper = new SocketWrapper(socketConfig);

    wrapper.on('myEvent', (eventHandler) => {
        eventHandler
            .then((event) => {
                //do something with the data
            })
            .catch((err) => {
                console.log(err.stack);
            });
    });

This ensures that there is always an open connection to the cluster when calling on or subscribe, it also handles the watch for subscribe, so you don't have to write a handler for it yourself. it also deals with errors in a bit of a better way.

Granted this may sound like an extreme solution for your problem, but the point I am trying to make is that you can't ever call any of the socket functions, if the socket isn't initialised.

astutesoftware commented 6 years ago

Thanks for the detailed reply. Here is what my scenario is. I have a single page application. User comes in.. signs up.. logs on to the service and then qualifies to connect to the socket and chat or message. Considering that sockets are expensive I would want to utilize it only when required. For ex. i have a banned client and would not want him to access the service. So hence had this issue. A simple workaround would be to move him to a different page and connect which is a dirty hack. So thought might as well post an issue here and get some feedback.

Thanks again.

DarkMukke commented 6 years ago

i don't think there's an issue with what you are trying to do, i think there is an issue with the code.

have you console.log'ed the socket before you call .on() or where the error occurs ?