stomp-js / rx-stomp

STOMP adaptor for RxJS
Apache License 2.0
112 stars 21 forks source link

Multiple connections with different broker URL at the same time and destroying the connection #415

Closed rjculaway closed 2 years ago

rjculaway commented 2 years ago

Hello @kum-deepak,

I'm currently try to connect to multiple web socket connections at the same time. I created a web socket service where i'm able to pass a broker URL from whatever component that requires web socket. Here's my code:


import { InjectableRxStompConfig, RxStompService, rxStompServiceFactory } from '@stomp/ng2-stompjs';
import { IMessage } from '@stomp/stompjs';

import { BehaviorSubject, Observable } from 'rxjs';

import { environment } from 'src/environments/environment';
import { AuthService } from './auth.service';

@Injectable({
    providedIn: 'root',
})
export class WebSocketService implements OnDestroy {
    private rxStompConfig: InjectableRxStompConfig;
    private rxStompService: RxStompService;

    constructor(private authService: AuthService) {
        console.log('creating...');
    }

    ngOnDestroy(): void {
        this.disconnect();

        console.log('disconnecting...');
    }

    get connectionState$(): BehaviorSubject<any> {
        return this.rxStompService.connectionState$;
    }

    activate(): void {
        this.rxStompService.activate();
    }

    deactivate(): void {
        this.rxStompService.deactivate();
    }

    connect(websocketUrl: string): void {
        this.rxStompConfig = this.getConfig(websocketUrl);
        this.rxStompService = rxStompServiceFactory(this.rxStompConfig);
        this.rxStompService.activate();
    }

    disconnect(): void {
        this.rxStompService.deactivate();
    }

    watch(topic: string): Observable<IMessage> {
        return this.rxStompService.watch(topic);
    }

    private getConfig(websocketUrl: string): InjectableRxStompConfig {
        const config: InjectableRxStompConfig = {
            heartbeatIncoming: 0,
            heartbeatOutgoing: 40000,
            reconnectDelay: 500,
            logRawCommunication: true,

            beforeConnect: (client: any): void | Promise<void> => {
                const token = this.authService.getJwtToken();
                const brokerURL = `wss://${environment.hostName}${websocketUrl}${token}`;

                if (token) {
                    client.configure({
                        brokerURL,
                    });
                } else {
                    this.ngOnDestroy();
                }
            },

            debug: (message: string): void => {
                console.warn(new Date());
                console.warn(message);
                console.warn('----------------------------------- \n -----------------------------------');
            },
        };

        return config;
    }
}

I think connections are being established correctly, but I just want to get your input to know whether this is the correct way of doing this.

I use it in this fashion:

Component A webSocketService.connect('connectionA')

Component B webSocketService.connect('connectionB');

When I connect to connectionB won't this affect connectionA since i'm technically using the same service?

My other concern is, how do i disconnect from all connections when for example my session expires due to either being idle or logging out?

Would really appreciate your help on this. Thank you so much!

kum-deepak commented 2 years ago

While the approach is not incorrect, but, quite roundabout.

Some minor notes:

I would suggest the following approach to achieve what you need:

rjculaway commented 2 years ago

Hi @kum-deepak

Taking your advice, I created different configs inheriting InjectableRxStompConfig. I also have created different services inheriting RxStompService, initializing them using factories.

So now in my module, I have

providers: [
        {
            provide: IotStompConfig
        },
        {
            provide: IotStompService,
            useFactory: iotStompServiceFactory,
            deps: [IotStompConfig]
        }
    ]

and a factory that does the initialization

export const iotStompServiceFactory= (rxStompConfig: IotStompConfig): IotStompService=> {
    const rxStompService = new IotStompService();

    rxStompService.configure(rxStompConfig);
    rxStompService.activate();

    return rxStompService;
};
kum-deepak commented 2 years ago

I think this is a good approach. :+1: