Edited at

AngularからMattermostにWebSocketで接続して投稿内容を取得する

タイトルのことがやりたかっただけなんですけど。

Mattermostに投稿があった時に、Angularでもその内容をリアルタイムで表示したくてですね。APIに定期的にアクセスしてもいいんですけど、せっかくなのでWebSocketで接続したい。

というわけで、"Angular WebSocket"あたりで検索してみたところ、Socket.IOを使うだのObserverやら使うだの、かなり難度の高い方法ばかりでてくるんですが……

最終的に、下記のコードだけで実現できました。


app.component.ts

import { Component, OnInit } from '@angular/core';

import { webSocket } from "rxjs/webSocket";
const subject = webSocket('wss://mattermost-server/api/v4/websocket');

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {

constructor() { }

ngOnInit() {
subject.subscribe(
(message: any) => {
if(message.event == 'posted') console.log(JSON.parse(message.data.post).message);
},
err => console.log(err),
() => console.log('complete')
);
}
}


んもー、すごく簡単じゃないですか。いやー、RxJS便利。

ここにたどり着くまでにあれこれ遠回りしましたよ。

ちなみに、素のJavaScriptだとこんな感じ。

const socket = new WebSocket("wss://mattermost-server/api/v4/websocket");

socket.addEventListener("message", event => {
let message = JSON.parse(event.data);
if(message.event == 'posted') console.log(JSON.parse(message.data.post).message);
});

そう、こんな風にシンプルに書きたかったんですよ。んもー。


追記。サービス化するとこんな感じ。


websocket.service.ts

import { Injectable } from '@angular/core';

import { Subject } from 'rxjs';
import { webSocket } from "rxjs/webSocket";
const subject = webSocket('wss://mattermost-server/api/v4/websocket');

@Injectable({
providedIn: 'root'
})
export class WebsocketService {

data = new Subject<any>();
data$= this.data.asObservable();

constructor() {
subject.subscribe(
(message: any) => {
this.data.next(message);
},
err => console.log(err),
() => console.log('complete')
);
}
}



app.component.ts

import { Component, OnInit } from '@angular/core';

import { WebsocketService } from './websocket.service';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {

constructor(
private websocket: WebsocketService,
) {}

ngOnInit() {
this.websocket.data$.subscribe(
(message: any) => {
if(message.event == 'posted') console.log(JSON.parse(message.data.post).message);
}
);
}
}


サービス側で、イベント種別毎だとかチャンネル毎だとかで分けてnextに流すと便利なんだろうな……

気が向いたら実装してみよう。