stomp-js / ng2-stompjs

Angular 6 and 7 - Stomp service over Websockets
https://stomp-js.github.io/
Apache License 2.0
182 stars 32 forks source link

Workaound: ng2-stompjs over SockJS in Angular 6 #70

Open srjovanovic opened 6 years ago

srjovanovic commented 6 years ago

Based on your setup, you might get error similar to following:

browser-crypto.js:3 Uncaught ReferenceError: global is not defined
    at Object../node_modules/sockjs-client/lib/utils/browser-crypto.js (browser-crypto.js:3)
    at __webpack_require__ (bootstrap:81)
    at Object../node_modules/sockjs-client/lib/utils/random.js (random.js:4)
    at __webpack_require__ (bootstrap:81)
    at Object../node_modules/sockjs-client/lib/utils/event.js (event.js:3)
    at __webpack_require__ (bootstrap:81)
    at Object../node_modules/sockjs-client/lib/transport/websocket.js (websocket.js:3)
    at __webpack_require__ (bootstrap:81)
    at Object../node_modules/sockjs-client/lib/transport-list.js (transport-list.js:5)
    at __webpack_require__ (bootstrap:81)

The actual issue can be solved by SockJs team, see: https://github.com/stomp-js/ng2-stompjs/issues/70#issuecomment-388056250.

Please see https://github.com/stomp-js/ng2-stompjs/issues/70#issuecomment-388061761 and https://github.com/stomp-js/ng2-stompjs/issues/70#issuecomment-397231994 for possible workarounds.

kum-deepak commented 6 years ago

Please see: https://stomp-js.github.io/ng2-stompjs/additional-documentation/sock-js.html

A sample at: https://github.com/stomp-js/ng4-stompjs-demo/tree/sockjs (branch sockjs)

srjovanovic commented 6 years ago

Thank you very much.

wsloth commented 6 years ago

Has this been confirmed to work with Angular 6? When following the documentation example I get a runtime error whilst connecting to the SockJS endpoint:

browser-crypto.js:3 Uncaught ReferenceError: global is not defined
    at Object../node_modules/sockjs-client/lib/utils/browser-crypto.js (browser-crypto.js:3)
    at __webpack_require__ (bootstrap:81)
    at Object../node_modules/sockjs-client/lib/utils/random.js (random.js:4)
    at __webpack_require__ (bootstrap:81)
    at Object../node_modules/sockjs-client/lib/utils/event.js (event.js:3)
    at __webpack_require__ (bootstrap:81)
    at Object../node_modules/sockjs-client/lib/transport/websocket.js (websocket.js:3)
    at __webpack_require__ (bootstrap:81)
    at Object../node_modules/sockjs-client/lib/transport-list.js (transport-list.js:5)
    at __webpack_require__ (bootstrap:81)
kum-deepak commented 6 years ago

The Angular 6 version of this library has only been released yesterday, so, I am doubtful if anyone has used in production at all.

I can be reasonably sure that no one would have used it with SockJS and Angular 6 by now 😄

Before I dig deeper, are you using 6.0.0 of this library (released yesterday)?

wsloth commented 6 years ago

Yes, I am! I am trying to use it for a prototype application where I have no control over how the backend works, but it seems it's not functioning with Angular 6 sadly.

If it's too much work I'll just downgrade to Angular 5, but it'd be nice to use all the new features from 6 while building something new.

kum-deepak commented 6 years ago

I can confirm that I am able to reproduce the issue. It seems to be reported here: https://github.com/sockjs/sockjs-client/issues/401

Not sure it would be an easy solution till the underlying thing gets fixed.

@wsloth if your underlying broker supports Websockets (which in all likelihood it should), you can use that instead of going through the SockJS emulation layer. Any particular reason you need SockJS?

wsloth commented 6 years ago

I see, it doesn't seem like an easy fix. I'm working on something of a code exercise where I have full control over the frontend, but none over the backend, so that is a bit of a shame.

I'll see if I can downgrade to Angular 5, or for the sake of making something beautiful ditch the SockJS protocol.

kum-deepak commented 6 years ago

Just curious what advantage are you getting with SockJS in comparison to standard WebSocket?

wsloth commented 6 years ago

Nothing really, it's just that the backend has already been made and SockJS was decided for the messaging protocol. If it were up to me, I'd be using standard WebSockets 😉

kum-deepak commented 6 years ago

I am always getting surprised people choosing SockJS instead of WebSockets which would internally use WebSockets anyway. Using SockJS does limit some of the functionality of this library as well.

So far most number of tickets on this project relate to SockJS issues 😄

srjovanovic commented 6 years ago

I can confirm that ng2-stompjs over SockJS is working with Angular 6. But I'm having problems with subscribe, after reconnecting subscription doubles.

kum-deepak commented 6 years ago

Not sure if that would work - in your index.html file, in the header try adding the following:

  <script type="application/javascript">
    var global = window;
  </script>

I am unable to test it myself though

kum-deepak commented 6 years ago

@srjovanovic your issue may be linked to something else. Will you be able to share a sample repository that shows StompJS working with Angular6 and also your issue.

srjovanovic commented 6 years ago

@kum-deepak I've made more test with Angular 5, and I can confirm that my issue has nothing with Angular 6. So ng2-stompjs and SockJS are working for me on Angular 6.

aceleghin commented 6 years ago

After upgrade angular and ng2-stompjs I have the same error:

Uncaught ReferenceError: global is not defined at Object../node_modules/sockjs-client/lib/utils/browser-crypto.js (browser-crypto.js:3) at webpack_require__ (bootstrap:81) at Object../node_modules/sockjs-client/lib/utils/random.js (random.js:4) at webpack_require (bootstrap:81) at Object../node_modules/sockjs-client/lib/utils/event.js (event.js:3) at __webpack_require (bootstrap:81) at Object../node_modules/sockjs-client/lib/transport/websocket.js (websocket.js:3) at webpack_require__ (bootstrap:81) at Object../node_modules/sockjs-client/lib/transport-list.js (transport-list.js:5) at webpack_require__ (bootstrap:81)

And following your link https://stomp-js.github.io/ng2-stompjs/additional-documentation/sock-js.html I see a old library sockjs-client...

aceleghin commented 6 years ago

@srjovanovic Can you show me an example of stompjs working with angular 6? or maybe your code?

srjovanovic commented 6 years ago

@lippomano

Service: ` import {Injectable} from "@angular/core"; import {ENV} from "@app/environments"; import {StompConfig, StompRService, StompState} from "@stomp/ng2-stompjs"; import {Message} from "@stomp/stompjs"; import {Platform} from "ionic-angular"; import {Observable, Subscription} from "rxjs/Rx"; import * as SockJS from "sockjs-client"; import {Auth0Service} from "../auth-service/auth0-service"; import {NotificationsProvider} from "../notifications-service/notifications-service";

@Injectable() export class SocketStompProvider { public stompConfig: StompConfig; public stompEndpoint: string = "endpointName"; public stompStatus: string; public stompStatusId: number; public messages: Observable; private readonly showStompStatusId: boolean; private reconnectEnabled: boolean; private readonly reconnectTimeout: number; private subscription: Subscription; private serverSocket; private topic: string = "/queue/messages"; private loggedProfileDetails; private accountToken: string; private bearerToken: string; private readonly debugService: boolean = false;

constructor(private stompService: StompRService,
            private notificationsService: NotificationsProvider,
            private oAuthService: OAuthService,
            private platform: Platform) {
    this.debugService = (ENV.LOG_LEVEL !== "0");
    if (this.debugService) {
        this.stateStompService();
    }
    this.stompStatus = "STARTING";
    this.reconnectTimeout = 15000;
    this.reconnectEnabled = false;
    this.showStompStatusId = this.debugService;
}

public reinitializeServiceSocketConnection() {
    this.initServiceSocketConnection(this.stompEndpoint);
}

public socketProvider(serverUrl) {
    return new SockJS(serverUrl);
}

public unsubscribeStompTopic() {
    if (this.subscription) {
        this.subscription.unsubscribe();
        this.subscription = null;
        this.messages = null;
    }
}

public disconnectSocketFromService() {
    if (this.stompStatus === "CONNECTED") {
        this.reconnectEnabled = false;
        this.unsubscribeStompTopic();
        this.stompService.disconnect();
    }
}

public setStompServiceConfiguration() {
    this.stompConfig = {
        debug: this.debugService,
        headers: {},
        heartbeat_in: 30000,
        heartbeat_out: 30000,
        reconnect_delay: this.reconnectTimeout,
        url: this.serverSocket,
    };
}

public getEndpointAuthorizationHeader(): string {
    let authorizeEndpoint = null;
    this.loadAuthTokensFromStorage();
    if (this.accountToken) {
        authorizeEndpoint = "?" +
            "Authorization=" + this.bearerToken +
            "&Account-Info=" + this.accountToken;
    }
    return authorizeEndpoint;
}

public stateStompService() {
    this.stompService.state
        .map((state: number) => StompState[state])
        .subscribe((status: string) => {
            this.stompStatus = status;
            if (this.reconnectEnabled && this.stompStatus === "CLOSED" &&
                this.notificationsService.notificationsEnabled) {
                this.oAuthService.getNewAccessTokenNotification();
                this.reinitializeServiceSocketConnection();
            }
            if (this.showStompStatusId) {
                switch (status) {
                    case "CLOSED": {
                        this.stompStatusId = 0;
                        break;
                    }
                    case "TRYING": {
                        this.stompStatusId = 1;
                        break;
                    }
                    case "CONNECTED": {
                        this.stompStatusId = 2;
                        break;
                    }
                    case "DISCONNECTING": {
                        this.stompStatusId = 3;
                        break;
                    }

                }
            }
        });
}

public onSendMessage(messageText) {
    this.stompService.publish(this.topic, messageText);
}

private initServiceSocketConnection(stompEndpoint: string) {
    if (this.notificationsService.notificationsEnabled) {
        const authorizationHeader = this.getEndpointAuthorizationHeader();
        if (authorizationHeader) {
            this.serverSocket = this.socketProvider(ENV.URL + stompEndpoint + authorizationHeader);
            this.setStompServiceConfiguration();
            if (!this.subscription) {
                this.subscribeStompTopic();
            }
            if (this.stompStatus !== "CONNECTED" && this.stompStatus !== "TRYING") {
                this.connectSocketToService();
            }
            this.notificationsService.getNotificationsHistory();
        }
    }
}

private subscribeStompTopic() {
    if (!this.subscription) {
        this.messages = this.stompService.subscribe(this.topic);
        this.subscription = this.messages.subscribe(this.onNewMessage);
    }
}

private onNewMessage = (message: Message) => {
    this.notificationsService.processMessage(JSON.parse(message.body));
};

private loadAuthTokensFromStorage() {
    this.loggedProfileDetails = JSON.parse(localStorage.getItem("profile-cm"));
    if (this.loggedProfileDetails) {
        this.accountToken = this.loggedProfileDetails.accountInfoToken;
    }
    this.bearerToken = "Bearer " + localStorage.getItem("access_token");
}

private connectSocketToService() {
    this.stompService.config = this.stompConfig;
    this.stompService.initAndConnect();
    this.reconnectEnabled = true;
}

}`

srjovanovic commented 6 years ago

Relevant package versions: angular/common: 6.0.2 angular/compiler: 6.0.2 angular/compiler-cli: 6.0.2 angular/core: 6.0.2 angular/forms: 6.0.2 angular/http: 6.0.2 angular/platform-browser: 6.0.2 angular/platform-browser-dynamic: 6.0.2 stomp/ng2-stompjs: 4.0.0 rxjs: 6.1.0 rxjs-compat: 6.1.0 sockjs-client: 1.1.4 tsickle: 0.28.0 typescript: 2.7.2 webpack: 4.8.3 zone.js: 0.8.26

aceleghin commented 6 years ago

@srjovanovic I have a configuration like you but if I use new SockJS(sockUrl); in config for the stomp url I have the errors posted in the previous comment. Any idea why I have these errors?

P.s. If I use for example an url like ws://127.0.0.1:15674/ws without initializing a new SockJS it seems working but I need to initialize sockJS with an url like http:...

srjovanovic commented 6 years ago

As you can see from my code, I'm using newSockJS(serverUrl), for dev env I use serverUrl=https://localhost:9000/

aceleghin commented 6 years ago

@srjovanovic @kum-deepak just tried with the example in angular 6 ng6-example and I follow this way with sockJS And I still have the same error, I can't understand how you don't have error

kum-deepak commented 6 years ago

It is definitely not working for me 😃. Copying from my earlier comments:

The underlying issue is in SockJS and the way Angular 6 is trying to bundle the code. It is reported here: sockjs/sockjs-client#401. Not sure it would be an easy solution till the underlying thing gets fixed.

Not sure if it would work. In your index.html file, in the header try adding the following:

  <script type="application/javascript">
    var global = window;
  </script>

Be warned 😄, test your application, this may have unintended side effects.

A better solution, if you can, switch to standard Websockets.

aceleghin commented 6 years ago

@kum-deepak thanks for your feedback, what type of side effects?

kum-deepak commented 6 years ago

Generally global is used by NodeJS, it is not used by browsers. SockJS code is expecting global to have certain methods, in case of browsers those methods are attached to window. So, the above snippet is likely to provide a workaround.

Now the risk part, global might be used by some other libraries conditionally. Whatever I can imagine, it should not have negative impacts. Only way to be sure would be to test your application with this added (I mean the entire application).

aceleghin commented 6 years ago

It's working, but I have to test it more accurately.

satyendra-123 commented 6 years ago

Getting the below error in browser after updating to angular 6 browser-crypto.js:3 Uncaught ReferenceError: global is not defined at Object../node_modules/sockjs-client/lib/utils/browser-crypto.js (browser-crypto.js:3) at webpack_require__ (bootstrap:76) at Object../node_modules/sockjs-client/lib/utils/random.js (random.js:4) at webpack_require (bootstrap:76) at Object../node_modules/sockjs-client/lib/utils/event.js (event.js:3) at __webpack_require (bootstrap:76) at Object../node_modules/sockjs-client/lib/transport/websocket.js (websocket.js:3) at webpack_require__ (bootstrap:76) at Object../node_modules/sockjs-client/lib/transport-list.js (transport-list.js:5) at webpack_require__ (bootstrap:76)

@kum-deepak thanks for your feedback, It does the workaround for me. Is there anything with the compatible dependency for angular 6 to fix it ?

kum-deepak commented 6 years ago

@satyendra-123 unfortunately the issue can only be fixed either by Angular team or by SockJS team.

tnobody commented 6 years ago

I fixed it for with adding this line:

(window as any).global = window;

to angular-clis polyfill.ts file. right now couldn't see any sideeffects

tamama commented 6 years ago

@kum-deepak Your workaround-fix works for me for raw SockJS connection:

I will next try using the stomp protocol over it, and will update you soon.

FYI: [vagrant@london-node-230 ~]$ ng --version

 _                      _                 ____ _     ___
/ \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|

/ △ \ | ' \ / | | | | |/ _ | '| | | | | | | / _ | | | | (| | || | | (| | | | || |_ | | // __| ||_, |_,||_,|| __|__|| |/

Angular CLI: 6.0.7 Node: 8.11.2 OS: linux x64 Angular: ...

Package Version

@angular-devkit/architect 0.6.7 @angular-devkit/core 0.6.7 @angular-devkit/schematics 0.6.7 @schematics/angular 0.6.7 @schematics/update 0.6.7 rxjs 6.2.0 typescript 2.7.2

[vagrant@london-node-230 ~]$

tamama commented 6 years ago

@kum-deepak Your workaround-fix works.

joaquintoral commented 5 years ago

image

I am getting undefined here. Why is that?

kum-deepak commented 5 years ago

Typically the CONNECTED frame (in response to CONNECT frame from the client) from broker returns a server header. If a broker does not return this header it will show undefined as above.

Which broker are you using?

This is not an error, this value is not used other than reporting it in log. It should not impact your usage.

bhabanipattanayak commented 5 years ago

@kum-deepak Hi Deepak,

Is there any way now to convert the protocol to http instead of wss. I am getting "global is not defined"

kum-deepak commented 5 years ago

If the URL supported by your broker starts with ws: or wss:, it supports WebSockets. In that case you do not need SockJS.

You can not interchange wss: and http: - both are different protocols.

If the broker only supports http, then follow https://github.com/stomp-js/ng2-stompjs/issues/70#issuecomment-388056250 as a workaround for "global is not defined"

goldy12103 commented 3 years ago

Getting the below error in browser in angular 9 browser-crypto.js:3 Uncaught ReferenceError: global is not defined at Object../node_modules/sockjs-client/lib/utils/browser-crypto.js (browser-crypto.js:3) at webpack_require (bootstrap:76) at Object../node_modules/sockjs-client/lib/utils/random.js (random.js:4) at webpack_require (bootstrap:76) at Object../node_modules/sockjs-client/lib/utils/event.js (event.js:3) at webpack_require (bootstrap:76) at Object../node_modules/sockjs-client/lib/transport/websocket.js (websocket.js:3) at webpack_require (bootstrap:76) at Object../node_modules/sockjs-client/lib/transport-list.js (transport-list.js:5) at webpack_require (bootstrap:76)

@kum-deepak seems like still the error is not fixed by angular or sockJS team , is there any better solution without using this (window as any).global = window;

kum-deepak commented 3 years ago

@goldy12103, this is not fixable by the Angular team. It would need fixing by the SockJS team.

goldy12103 commented 3 years ago

@kum-deepak

Is there any better solution without using this (window as any).global = window; ???

kum-deepak commented 3 years ago

Please scan this thread. There are other solutions, however, all of those lead to the same thing.

goldy12103 commented 3 years ago

Thanks Anyway !!