web-dev-qa-db-fra.com

Reconnexion d'un websocket dans Angular et rxjs?

J'ai une application basée sur ngrx/store (v2.2.2) et rxjs (v5.1.0) qui écoute un socket Web pour les données entrantes à l'aide d'un observable. Lorsque je lance l'application, je reçois parfaitement les données entrantes.

Cependant, après un certain temps (les mises à jour arrivent assez rarement), la connexion semble se perdre et je ne reçois plus de données entrantes. Mon code:

Le service

import { Injectable, OnInit } from '@angular/core';
import { Observable } from 'rxjs';

@Injectable()
export class MemberService implements OnInit {

  private websocket: any;
  private destination: string = "wss://notessensei.mybluemix.net/ws/time";

  constructor() { }

  ngOnInit() { }

  listenToTheSocket(): Observable<any> {

    this.websocket = new WebSocket(this.destination);

    this.websocket.onopen = () => {
      console.log("WebService Connected to " + this.destination);
    }

    return Observable.create(observer => {
      this.websocket.onmessage = (evt) => {
        observer.next(evt);
      };
    })
      .map(res => res.data)
      .share();
  }
}

L'abonné

  export class AppComponent implements OnInit {

  constructor(/*private store: Store<fromRoot.State>,*/ private memberService: MemberService) {}

  ngOnInit() {
    this.memberService.listenToTheSocket().subscribe((result: any) => {
      try {
        console.log(result);
        // const member: any = JSON.parse(result);
        // this.store.dispatch(new MemberActions.AddMember(member));
      } catch (ex) {
        console.log(JSON.stringify(ex));
      }
    })
  }
}

Que dois-je faire pour reconnecter le socket Web à l'expiration du délai, afin que l'observable continue d'émettre des valeurs entrantes?

J'ai jeté un coup d'œil à quelques questions et réponses ici , ici et ici et il n'a pas semblé répondre à cette question (d'une manière que je puisse comprendre).

Remarque: la Websocket située à wss://notessensei.mybluemix.net/ws/time est sous tension et émet un horodatage une fois par minute (au cas où on voudrait le tester).

Les conseils sont grandement appréciés!

6
stwissel

En fait, il y a maintenant un WebsocketSubject dans rxjs!

 import { webSocket } from 'rxjs/webSocket' // for RxJS 6, for v5 use Observable.webSocket

 let subject = webSocket('ws://localhost:8081');
 subject.subscribe(
    (msg) => console.log('message received: ' + msg),
    (err) => console.log(err),
    () => console.log('complete')
  );
 subject.next(JSON.stringify({ op: 'hello' }));

Il gère la reconnexion lorsque vous vous réabonnez à une connexion interrompue. Donc, par exemple, écrivez ceci pour vous reconnecter:

subject.retry().subscribe(...)

Voir la documentation pour plus d'informations. Malheureusement, la boîte de recherche ne montre pas la méthode, mais vous la trouvez ici:

http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#static-method-webSocket

cette navigation ne fonctionne pas dans mon navigateur. Recherchez "webSocket" sur cette page.

Source: http://reactivex.io/rxjs/file/es6/observable/dom/WebSocketSubject.js.html#lineNumber15

20
Herman

Pour rxjs 6, implémentation websocket.

import { webSocket } from 'rxjs/websocket';
let subject = webSocket('ws://localhost:8081');
1
carkod

Ce n'est peut-être pas la bonne réponse, mais c'est beaucoup trop pour un commentaire.

Le problème pourrait venir de votre service:

listenToTheSocket(): Observable<any> {
  this.websocket = new WebSocket(this.destination);

  this.websocket.onopen = () => {
    console.log("WebService Connected to " + this.destination);
  }

  return Observable.create(observer => {
    this.websocket.onmessage = (evt) => {
      observer.next(evt);
    };
  })
  .map(res => res.data)
  .share();
}

Pensez-vous que votre composant utilise plusieurs fois la méthode ngOnInit?
Vous devriez essayer de mettre un console.log dans ngOnInit pour en être sûr.

Parce que si vous le faites, dans votre service, vous remplacez le this.websocket par un nouveau.

Vous devriez essayer quelque chose comme ça à la place: 

@Injectable()
export class MemberService implements OnInit {

  private websocket: any;
  private websocketSubject$ = new BehaviorSubject<any>();
  private websocket$ = this.websocketSubject$.asObservable();

  private destination = 'wss://notessensei.mybluemix.net/ws/time';

  constructor() { }

  ngOnInit() { }

  listenToTheSocket(): Observable<any> {
    if (this.websocket) {
      return websocket$;
    }

    this.websocket = new WebSocket(this.destination);

    this.websocket.onopen = () => console.log(`WebService Connected to ${this.destination}`);

    this.websocket.onmessage = (res) => this.websocketSubject$.next(res => res.data);
  }
}

La BehaviorSubject enverra la dernière valeur si elle reçoit un événement avant de vous y abonner. De plus, comme il s'agit d'un sujet, inutile d'utiliser l'opérateur share.

1
maxime1992