基于xmpp.js搭建即时通讯客户端

写在前面

//环境配置
UI库:VUE  v2.5.17
客户端:electron v2.0.10
NODE:8.9.3
platform: win64

前期分析


在搭建之前,我搜集了一下关于xmpp库的资料。比较热门的两个库是:xmpp.js 和 strophe.js。OK,那接下来我们来评估一下两者的差别(截止本日,即2018/10/08)。

类别 \ 名称 xmpp strophe
github☆ 1600 1091
issue 32(open) 280(closed) 19(open) 186(closed)
最新提交 1天前 6天前
npm下载量/week 400 1000
文档完善度 还行
官方demo 简单易懂 看到头疼
es6 支持 不支持

其实还有个最重要的功能点的比较,我没有写出来,是因为xmpp的文档实在是一言难尽。有很多参数和功能都需要自己进github里边查看,所以到现在我还在摸索,也就没办法比较两者。
两者光看上边的信息分析,一般在星星数和更新数不相上下的情况下,我会选择文档齐全的。毕竟没有写在文档上的功能就相当于不存在。然而,坑总是与你不期而遇。strophe.js的官方demo是以JQ来搭配的,所以我要自己稍微修改一下安装和引用方式。如下:

# install
npm install strophe.js --save

# require
let client = require('strophe.js')

但是这是一次失败的改造,当我想要创建一个client时,被告知获取不到 connection 这个方法。打印如下:

console.log(Strophe,Strophe.Connection)
log

如果非要用script引用方式的话,也不是不可以,在官网上把js文件下载下来,放到static文件夹中,然后在main.js中引用。但是这样就使得更新变得很麻烦,一旦习惯了npm,要退回script时代真的是接受唔到啊!所以,我决定考虑一下xmpp.js。

介绍xmpp.js


xmpp.js是让web也能用上即时通讯的一个库。关于xmpp协议以及xmpp.js这个库概念上的东西,网上相关博客已有许多,我也不多做描述,主要是记录使用感。

  1. 文档查看方式
    ok,既然他们更新文档,那我也更新一下文档查看方式。目前,他们的官方文档分了两种:GIitHub官网。按现在的进度来看,官网是旧版本的。按需求查看吧。
    友情提示:用yarn安装时,node>=10.0.0

搭建客户端


因为v0.3.0和v0.5.0的搭建我都试过了,所以就都写写。
新版跟旧版,最明显的功能差就是,新版自带keep-alive,而旧版则是6秒下线。当初为了维持心跳,可把我一个小新人折腾坏了。

新版v0.5.0
         //先定义常量
        const {client, xml, jid} = require('@xmpp/client')
        const user = 'zxy';
        const psw = 'password';

        //这真的是很重要的一句话!!!!因为node不支持自签证书的,所以如果当你连接的是自签证书的网,建议你赶紧加上
        process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';

        //添加 domain的时候连接不上,为什么连不上?还不清楚
        const xmpp = client({
            service: 'xmpp://10.254.2.11:5222',
            // domain: '10.254.2.11',
            resource: 'PC-12334234hiasdhasgasd',
            username: user,
            password: psw,
        })

        //监听错误信息
        xmpp.on('error', err => {
            console.error('❌', err.toString())
        })

        //监听是否掉线
        xmpp.on('offline', () => {
            console.log('🛈', 'offline')
        })

        //监听是否上线
        xmpp.on('online', async address => {
            console.log('🗸', 'online as',address)

            // Sends a chat message to itself
            // 这是新版的官方文档写法,但是我这样写的时候无法获取到别人给我发的消息。
            // const message = xml(
            // 'message',
            // {type: 'chat', to: address},
            // xml('body', 'hello world')
            // )

            // 旧版官方的写法:旨在告诉服务器我已经上线了。发送了这句话后,我就可以收到服务器传来的消息。
            const presence = xml('presence', {}, 
                xml('show', {}, 'chat'),
                xml('status', {}, 'presence!'),
            )
            xmpp.send(presence)
        })

        //监听节点信息,不管是iq还是message,都是在这里监听到的。
        xmpp.on('stanza', stanza => {
            if (stanza.is('presence') && stanza.attrs.type === 'subscribe') {
                xmpp.send(
                    xml('presence', { to: stanza.attrs.from, type: 'subscribed' })
                );
            }

            // This is doing the echoing.
            if (stanza.is('message') && stanza.attrs.from !== client.jid) {
                console.log('⮈', stanza.toString())
                stanza.children.forEach(child => {
                    if (child.name === 'body') {
                        // do somethind 
                        // eg: put the message into your screen
                    }
                });
            }
        })

        // 监听状态
        xmpp.on('status', (status, value) => {
            console.log('status:', status, value ? value.toString() : '')
        })

        xmpp.start().catch(err=>{
            console.log(err)
        })

旧版v0.3.0

旧版大部分功能与新版是类似的,所以就不会每个功能点都注释一遍,只有特别要注意的地方才会写上。

      //aha,firstly we sholud import xmpp
      import {Client , xml} from 'xmpp.js'

      // 定义常量
      const client = new Client();
      const user = 'zxy';
      const psw = 'password';

      process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';

      client.on('error', err => {
        console.error('❌', err.toString())
      })

      client.on('status', (status, value) => {
        // console.log('🛈', status, value ? value.toString() : '')
      })

      client.on('online', jid => {
        // console.log('🗸', 'online as', jid.toString())
        client.send(
          xml('presence', {}, 
            xml('show', {}, 'chat'),
            xml('status', {}, 'I say everything you do!'),
          )
        );
        
        // Send keepalive,这是我在issue上找到的写法,但是对我无效
        // client.Socket.prototype.setTimeout(0)
        // client.Socket.prototype.setKeepAlive(true, 10000)   
      })

      client.on('stanza', stanza => {
        // console.log('⮈', stanza.toJSON())
        if (stanza.is('presence') && stanza.attrs.type === 'subscribe') {
          client.send(
            xml('presence', { to: stanza.attrs.from, type: 'subscribed' })
          );
        }

        // 服务器发送ping过来时,要回应他以示存在
        if(stanza.is('iq')){
          client.send(
            xml('iq', { to: stanza.attrs.from, type: 'result', from: client.jid })
          );
        }

        // This is doing the echoing.
        if (stanza.is('message') && stanza.attrs.from !== client.jid) {
          // console.log('message',stanza.toJSON())
          // console.log('message');
          
          stanza.children.forEach(child => {
            if (child.name === 'body') {
              // do something you like
            }
          });
        }
      })

      client.start('xmpp://10.254.2.11:5222')
        .catch(err => console.error('start failed', err.message));
      // 验证链接
      client.handle('authenticate', authenticate => {
        return authenticate(user, psw)
      })
      // 添加资源
      client.handle('bind', bind => {
        return bind('PC-12334234hiasdhasgasd')
      })

ok,这样就搭建成功了,但是新版目前有个问题就是:在启动服务时,会报超时的错误,但是事实上,他已经链接上了。毕竟我是可以接受以及发送消息的。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容