6

I am creating a chat application with Angular 4 and websocket. For this, I've followed this Angular websocket tutorial

Here is the WebsocketService source code:

import { Injectable } from '@angular/core';
import * as Rx from 'rxjs/Rx';

@Injectable()
export class WebsocketService {
  constructor() { }

  private subject: Rx.Subject<MessageEvent>;

  public connect(url): Rx.Subject<MessageEvent> {
    if (!this.subject) {
      this.subject = this.create(url);
      console.log("Successfully connected: " + url);
    } 
    return this.subject;
  }

  private create(url): Rx.Subject<MessageEvent> {
    let ws = new WebSocket(url);

    let observable = Rx.Observable.create(
    (obs: Rx.Observer<MessageEvent>) => {
        ws.onmessage = obs.next.bind(obs);
        ws.onerror = obs.error.bind(obs);
        ws.onclose = obs.complete.bind(obs);
        return ws.close.bind(ws);
    })
let observer = {
        next: (data: Object) => {
            if (ws.readyState === WebSocket.OPEN) {
                ws.send(JSON.stringify(data));
            }
        }
    }
    return Rx.Subject.create(observer, observable);
  }

}

And it is my ChatService:

import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs/Rx';
import { WebsocketService } from './websocket.service';

const CHAT_URL = 'ws://echo.websocket.org/';

export interface Message {
    author: string,
    message: string
}

@Injectable()
export class ChatService {
    public messages: Subject<Message>;

    constructor(wsService: WebsocketService) {
        this.messages = <Subject<Message>>wsService
            .connect(CHAT_URL)
            .map((response: MessageEvent): Message => {
                let data = JSON.parse(response.data);
                return {
                    author: data.author,
                    message: data.message
                }
            });
    }
}

It works fine, but I want to detect the connection status. I want to know if the connection has been interrupted or the server is down.

For that, I tried to implement an isServerOn() function inside the WebsocketService class like this:

isServerOn(): Observable<boolean> {
    return Observable.of(!!this.subject);
}

But it has not resolve the problem. Is there anyone who has encourtered the same problem?

Thank you in advance.

2
  • what is "this.server" ? i doubt that it has a type of which it is possible to create an observable which does what you want by just calling Observable.of on it. Commented Dec 18, 2017 at 13:12
  • It's a typo, I mean this.subject Commented Dec 18, 2017 at 13:18

2 Answers 2

6

I suggest you use type definitions for socket.io-client in your Angular application. Then define a service as follows:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Observer } from 'rxjs/Observer';
import { Message } from '../model/message';
import { Event } from '../model/event';

import * as socketIo from 'socket.io-client';

const SERVER_URL = 'https://yourserverhost.com';

@Injectable()
export class SocketService {
    private socket;

    public initSocket(): void {
        this.socket = socketIo(SERVER_URL);
    }

    public send(message: Message): void {
        this.socket.emit('message', message);
    }

    public onEvent(event: Event): Observable<any> {
        return new Observable<Event>(observer => {
            this.socket.on(event, () => observer.next());
        });
    }
}

Define an Event enum:

export enum Event {
    CONNECT = 'connect',
    DISCONNECT = 'disconnect'
}

Then subscribe to your service functions from your Angular component:

export class ChatComponent implements OnInit {
  constructor(private socketService: SocketService) { }

   ngOnInit(): void {
    this.initIoConnection();
  }

  private initIoConnection(): void {
    this.socketService.initSocket();

    this.ioConnection = this.socketService.onMessage()
      .subscribe((message: Message) => {
        this.messages.push(message);
      });


    this.socketService.onEvent(Event.CONNECT)
      .subscribe(() => {
        console.log('Connected to the server');
      });

    this.socketService.onEvent(Event.DISCONNECT)
      .subscribe(() => {
        console.log('Disconnected');
      });
  }
}

Find the complete chat project, which is using Node.js, WebSockets and Angular here: https://github.com/luixaviles/socket-io-typescript-chat

Sign up to request clarification or add additional context in comments.

Comments

1

I am not sure what you want to achieve with

 return Observable.of(!!this.subject);

I do not think that it does what you think it does. Instead you should rather create your own BehaviorSubject and return the corresponding Observable like

isServerOn(): Observable<boolean> {
    return this.myServerOnSubject.asObservable();
}

At the corresponding online/offline code positions you then can emit the next value with

this.myServerOnSubject.next(true/false);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.