作者:陈畏民

源起

往年暑假的前半段工夫, 在家捣鼓了一个情侣类web利用, 基于aspnetcore和angular搭建的; 暑假中实现了'告白', '相册', '说说', '纪念日'这些性能, 而后前端界面上留一个性能的坑位: 聊天, 点击这个聊天按钮, 能够看到四个字, 那就是敬请期待; 部署上线后, 用户当然只有我和我的"好敌人"应用, "好敌人"先跨了我真棒, 而后问聊天性能马上能够用了吧? 我缄默了, 心想着这个性能前面用signalr试试看吧; 当初曾经2020秋了, 聊天性能的界面上仍旧是那四个字: 敬请期待

!

这个国庆, 我意识到不能再拖了, 本人埋的坑, 应该趁早把它填了, 否则"好敌人"会感觉你很菜, 一个"简略的"聊天性能都做不进去;

遇见声网(agora)

最开始想用signalr本人实现聊天性能的, 然而思考到一方面, 本人的服务器资源无限(1核1G轻量应用服务器); 另一方面, 本身精力能力无限, 写进去兴许不难, 然而要写好确是不简略的; 于是寻思着找找现成的货色用用吧, 机缘巧合, 我据说了声网(agora), 于是去他的官网看了一番, 看到有具体的文档, 足量的收费额度...于是决定先白嫖试用一下

对于agora

顺便找了一下agora的相干材料, 看起来是挺靠谱的, 在寰球都有数据中心和服务器; 小米、陌陌、新东方等知名企业都用过他们的云服务;

基于agora的rtm sdk给我的利用加上聊天性能

参考官网的文档

我的环境

  • win10零碎
  • npm包治理
  • angular8.x
  • vscode

步骤

装置依赖

npm i agora-rtm-sdk
装置完后须要批改下agora-rtm-sdk/index.d.ts的文件的2258
原来的内容为:

export type { RtmChannel, RtmClient, RtmEvents, RtmMessage, RtmStatusCode };

批改为:

export { RtmChannel, RtmClient, RtmEvents, RtmMessage, RtmStatusCode };

不批改的话, 编译会报错

引入依赖

因为是在在angular组件ChatComponent中实现聊天相干的性能, 所以在其中引入rtm sdk的依赖 import AgoraRTM from 'agora-rtm-sdk';

创立rtm客户端并登陆到agora的rtm服务器

一行代码创立rtm客户端:

const rtmClient = AgoraRTM.createInstance('<your app id>');

<details>
<summary>登陆到rtm服务器</summary>

const rtmClient = AgoraRTM.createInstance('fd033b52ca5d40599efc96f6e2131639');async function rtmClientLogin(user: User) {  try {    await rtmClient.login({ token: null, uid: user.id });  } catch(err) {    console.log('AgoraRTM client login failure', err);  }}// 在组件的 ngOnInit 办法中调用 rtmClientLoginasync ngOnInit() {    try {      let user = await this.userServ.getUser().toPromise();      if (user instanceof User) {        this.user = user;        rtmClientLogin(this.user);      } else {        throw new Error('无奈获取用户数据');      }    } catch(err) {      this.notifyServ.error('初始化聊天组件失败', null);      console.error('初始化聊天组件失败', err);    }  }

</details>

ps: 测试阶段, 所以应用的rtm的受权形式是AppID, 如果要应用这种受权形式, 在rtm控制台创立我的项目的时候要留神一下, 身份认证模式勾选 App ID, 否则在登陆到rtm服务器的时候, 会报红

发送/接管音讯

音讯发送失败须要告诉用户, 谬误告诉间接应用了antdesign的NzNotificationService, 在构造函数注入即可; 这个利用中, 相互发消息的单方是情侣, User示意以后用户, User.Spouse示意用户的伴侣; 音讯发送胜利须要清空发送音讯文字框并将发送的音讯退出音讯数组中, 让angular更新视图

<details>
<summary>发送音讯</summary>

async sendMessage() {  if (!this.newMessage) {    return;  }  const spouseId = this.user.spouse.id;  try {    const result = await rtmClient.sendMessageToPeer({      text: this.newMessage    }, spouseId);    if (!result.hasPeerReceived) {      throw new Error('对方未承受音讯');    } else {      this.messages.push({        text: this.newMessage,        sender: this.user,        receiver: this.user.spouse,        dateSended: new Date()      });      this.newMessage = undefined;    }  } catch (err) {    this.notifyServ.error('发送音讯失败', null);    console.log('发送音讯失败', err);  }}

</details>

<br/>

ngOnInit生命周期函数中监听收到新音讯事件, 收到新音讯后, 将新音讯退出音讯数组中, angular会通过数据绑定更新视图, 渲染ui

<details>
<summary>监听并解决收到新音讯事件</summary>

async ngOnInit() {  try {    let user = await this.userServ.getUser().toPromise();    if (user instanceof User) {      this.user = user;      rtmClientLogin(this.user);      监听接管到音讯事件      rtmClient.on('MessageFromPeer', (rtmMessage, peerId) => {        this.messages.push({          text: rtmMessage.text,          sender: this.user.spouse,          receiver: this.user,          dateSended: new Date()        });      });          } else {      throw new Error('无奈获取用户数据');    }  } catch(err) {    this.notifyServ.error('初始化聊天组件失败', null);    console.error('初始化聊天组件失败', err);  }}

</details>


<details>
<summary>前端html代码</summary>

<div id="container">    <div class="messages">        <div class="message-item"             *ngFor="let msg of messages">            <div class="sendedMessage"                 *ngIf="msg.sender.id === user.id">                <span class="message-text">{{msg.text}}</span>                <span>                    <nz-avatar nzIcon="user"                               [nzSrc]="msg.receiver.profileImageUrl"></nz-avatar>                </span>            </div>            <div class="receviedMessage"                 *ngIf="msg.sender.id === user.spouse.id">                <span>                    <nz-avatar nzIcon="user"                               [nzSrc]="msg.sender.profileImageUrl"></nz-avatar>                </span>                <span class="message-text">{{msg.text}}</span>            </div>        </div>    </div>    <div class="new-message">        <div nz-row             nzJustify="end">            <div nz-col                 nzSpan="18">                <textarea nz-input                          [(ngModel)]="newMessage"                          [nzAutosize]="{ minRows: 1, maxRows: 6 }"></textarea>            </div>            <div nz-col                 nzSpan="6">                <button nz-button                        nzType="primary"                        class="mx-auto"                        style="width: 100%;"                        (click)="sendMessage()">发送</button>            </div>        </div>    </div></div>

</details>


<details>
<summary>前端css</summary>

:host {    height: 100%;    display: block;    position: relative;}#container {    height: 100%;    display: flex;    flex-direction: column;    padding-top: 4px;}.messages {    flex-grow: 1;}nz-alert {    display: block;    position: absolute;    top: 50%;    left: 50%;    transform: translate(-50%, -50%);    width: 85%;    text-align: center;}.sendedMessage {    display: flex;    justify-content: flex-end;    align-items: center;    margin-bottom: 8px;}.receviedMessage {    margin-bottom: 8px;}.message-text {    background: #fff;    padding: 8px 4px;}.sendedMessage .message-text {    margin-right: 4px;}.receviedMessage .message-text {    margin-left: 4px;}

</details>

成果如何?

动图演示:

静图:

小结

上文基于agora的rtm sdk, 初步实现了简略的聊天性能; 体验下来感觉很不便, 不须要关注后端实现, 只须要解决前端逻辑即可轻松构建出实时聊天性能; 当然, 正式在生产环境应用, 还是须要后端配合生成一个身份认证令牌(token)来保障安全性的; 上文临时只实现了文字的发送接管, 实际上rtm sdk还反对文件和图片的收发, 性能很弱小, 有机会再持续摸索。


更多实时互动相干内容,可点击进入声网RTC 开发者社区进行查看