【實作紀錄】Agora × Angular 實時訊息(聊天室)

Ray
11 min readOct 22, 2021

--

本文前置:需要一Agora控制台已存在項目。
本文重點:在本地端(localhost)完成簡易聊天室。

架構說明

建立一個Component及Service,分別負責處理控制及服務。

cd src/appng g c agora-rtmng g s agora-rtm

App.component基本不動,只在App.component.html中將Component引入。

<app-agora-rtm></app-agora-rtm>

安裝SDK

npm install agora-rtm-sdk

import 進剛剛建的Service(agora-rtm.service.ts)

import AgoraRTM, { RtmChannel, RtmClient, RtmMessage } from ‘agora-rtm-sdk’;

核心程式碼(agora-rtm.service)

這邊要負責主要的邏輯,讓Component能控制。

我們需要建立的Function()為:

  1. 初始化對象變數
  2. 初始化本地端
  3. 建立頻道
  4. 登入使用者
  5. 對頻道發出訊息
  6. 對特定人發出訊息
  7. 離開頻道

以及其他像是

  1. 取得本地端資料
  2. 取得頻道資料

知道要做什麼之後,一步一步來。

1.初始化對象變數

private rtm: { client: RtmClient | null, channel: RtmChannel | null } = {  client: null, //本地端資料  channel: null //頻道資料}

2.初始化本地端

initRTMClient(): RtmClient {if (!this.rtm.client) {  this.rtm.client =   AgoraRTM.createInstance
(
"<你的Agora項目 AppID>",
{ enableLogUpload: false }
);
} return this.rtm.client;}

3.建立頻道

createRTMChannel(channelId: string): RtmChannel | undefined {  if (!this.rtm.client) {    return;  }  this.rtm.channel = this.rtm.client.createChannel(channelId);  return this.rtm.channel}

4.登入使用者

先寫好Function,等等讓component控制,目的是只需要給UID(在該頻道內必須是唯一)以及該UID對應到的token

如何拿到UID跟其對應的TOKEN:到控制台輸入你想要的UID,然後會產生入一對應TOKEN。

這邊要注意的是,雖然上面寫Channel Name,但其實對RTM來說它是UID
async loginRTMClient(uid: string,token:string) {  if (!this.rtm.client) {    return;  }  const config = {    uid: uid,    token: token  }  await this.rtm.client.login(config);}

5.對頻道發出訊息

async sendChannelMessage(message: RtmMessage) {  if (!this.rtm.channel) {    return;  }  await this.rtm.channel.sendMessage(message);}

6.對特定人發出訊息

async sendPeerMessage(message: RtmMessage, toUserId: string) {  if (!this.rtm.client) {    return;  }  await this.rtm.client.sendMessageToPeer(message, toUserId);}

7.離開頻道

離開頻道

async leaveRTMChannel() {  if (!this.rtm.channel) {    return;  }  await this.rtm.channel.leave();}

登出

async logoutRTMClient() {  if (!this.rtm.client) {    return;  }  await this.rtm.client.logout();}

有了上面兩個後,可以再寫一個Function給ngDestory時呼叫

async destroyRTM() {  await this.leaveRTMChannel();  await this.logoutRTMClient();  this.rtm.client = null;  this.rtm.channel = null;}

其他

1.取得本地端資料

getRTMClient(): RtmClient | null {  return this.rtm.client;}

2.取得頻道資料

getRTMChannel(): RtmChannel | null {  return this.rtm.channel;}

控制部分(agora-rtm.component.ts)

上面Service已經都把邏輯寫好了,這邊只需要負責呼叫就行,不過這邊要額外再寫一個負責訂閱事件的功能。

這邊主要的流程及功能為:

0.建立HTML基礎樣式
1.初始化RTM
2.訂閱Client端訊息
3.訂閱頻道訊息
4.送出頻道訊息
5.送出密語
7.建立訊息的div 輸出到HTML上
8.Destory

知道要做什麼之後,一步一步來。

0.建立HTML基礎樣式

簡單做一個身分選擇、加入、送出輸入訊息的HTML

<p>選擇登入身分</p>  <select #user>    <option value=”0">Ray</option>    <option value=”1">Dev</option>  </select>
<br> <button (click)=”initRTM(user.value)”>加入頻道</button> <button (click)=”destoryRTM()”>離開頻道</button>
<br> <input #inputMsg id =”inputMsg”> <button (click)=”sendChannelMessage(inputMsg.value)”>送出</button>
<div
id = “log”
style=”display: flex; flex-direction: column-reverse;”
>
</div>

簡單說明:依照選擇的身分,將下拉選單所選的Index值傳給initRTM(),讓initRTM()知道要用什麼身分登入。

以及將Input的資料傳給sendChannelMessage(),將輸入的資料送出。這邊只是參考,沒有一定要照這樣做。

再來開始把上面的Function一個一個補上。

1.初始化RTM

(訂閱的Function在後面,第3及第4項)

async initRTM(index: string) {
if (index == ‘0’) { this.uid = “<UID>”; // 我上面的範例 這邊是Ray this.token = “<UID對應到的TOKEN>” } else { this.uid = “<UID>”; // 我上面的範例 這邊是Dev this.token = “<UID對應到的TOKEN>” }
this.agoraRTMService.initRTMClient(); this.subscribeRTMClientEvent(); await this.agoraRTMService.loginRTMClient(this.uid, this.token); const channel = this.agoraRTMService.createRTMChannel(‘Test’); this.subscribeRTMChannelEvent(); await channel?.join().then(() => { this.createChatLogDiv(“歡迎:” + this.uid + “加入”); })}

初始化的部分第一步是先根據下拉選單給出對應的UID以及TOKEN,正常來說應該是讓使用者輸入一個UID後呼叫API回傳TOKEN再拿這些資料做登入,這邊求方便先寫這樣。

再來是呼叫Service的initRTMClient()、登入、建立頻道、加入頻道,這個Component在initRTM()需要做的只有寫訂閱的Function。

2.訂閱Client端訊息

(createChatLogDiv在後面,第7項)

subscribeRTMClientEvent() {this.agoraRTMService.getRTMClient()!.on(‘MessageFromPeer’, (message, peerId) => { if (message.messageType === ‘TEXT’) {  this.createChatLogDiv(`(密語) ${peerId} 對你說: ‘${message.text}’`); }});}

3.訂閱頻道訊息

subscribeRTMChannelEvent() {  this.agoraRTMService.getRTMChannel()!.on(‘ChannelMessage’, (message, memberId) => {    if (message.messageType === ‘TEXT’) {    this.createChatLogDiv(memberId + “:” + message.text);  }}); this.agoraRTMService.getRTMChannel()!.on(‘MemberJoined’, memberId => {    this.createChatLogDiv(“歡迎:” + memberId + “加入”);});this.agoraRTMService.getRTMChannel()!.on(‘MemberLeft’, memberId => {    this.createChatLogDiv(memberId + “離開”);});}

4.送出頻道訊息

sendChannelMessage(msg: string) {if (msg == "") { return; }  this.agoraRTMService.sendChannelMessage({ text: msg });  this.createChatLogDiv(this.uid + ":" + msg);}

5.送出密語

sendPeerMessage(msg: string) {  this.agoraRTMService.sendPeerMessage({ text: msg }, '<對方UID>');}

7.建立訊息的div 輸出到HTML上

createChatLogDiv(msg: string) {(<HTMLInputElement>document.getElementById("log")).appendChild(document.createElement('div')).append(msg)}

8.Destory

ngOnDestroy() {  this.destoryRTM();}destoryRTM() {  this.agoraRTMService.destroyRTM().then(() => {    this.createChatLogDiv(this.uid + “離開”);  });}

成果

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

No responses yet

Write a response