利用NKN Pub/Sub 功能,我们能快速、方便的实现在线客服功能。这里我们用NKN javascript SDK来介绍如何定制化一个客服系统。
准备工作
- 客户端UI,本篇不详细介绍实现过程
- 服务端UI,这里方便演示,我们使用 D-Chat, 也可以使用移动客户端 nMobile 创建 Private Group
- SDK: nkn-wallet , nkn-multiclient
$ yarn add nkn-wallet
$ yarn add nkn-multiclient
实现客服组
普通的sub接口类似聊天室,每个人都能自由的进出,自由的传递数据。那如何保证客户发送的消息只让客服组的人接收呢?答案是 permission control
- 订阅一个私有topic,为了和普通topic区分开来,我们使用自定义格式:
topic.address
使用移动客户端 nMobile 创建 Private Group 可跳过此步骤
import Wallet from 'nkn-wallet'
// 生成一个Wallet,用来管理私有topic
let wallet = Wallet.newWallet('PASSWORD')
// 如果已经有 Wallet
// let wallet = Wallet.restoreWalletBySeed('SEED','PASSWORD')
let seed = wallet.getSeed() // 保存seed
// 订阅一个私有topic
let address = `${wallet.getPublicKey()}`
let topic = `TOPIC.${address}`
// 添加address,受meta的大小限制每次分页记录的数组不要太长
wallet.subscribe(topic, 400000, `__0__.__permission__`, JSON.stringify({accept: [{addr:'ADDRESS1'},{addr:'ADDRESS2'},/*...*/]}))
wallet.subscribe(topic, 400000, `__1__.__permission__`, JSON.stringify({accept: [{addr:'ADDRESS3'},{addr:'ADDRESS3'},/*...*/]}))
// ......
- 客户端获取topic里的客服地址列表
import Client from 'nkn-multiclient'
let client = Client()
// 获取客服列表
let getSubscribers = async function (topic, owner) {
let i = 0
let members = []
while (true) {
// 以 __i__ 为分页索引,查询所有分页
let res = await client.clients[0].getSubscription(`${topic}`, `__${i}__.__permission__.${owner}`)
let meta
try {
meta = JSON.parse(res.meta)
} catch (e) {
break
}
if (meta && meta.accept && meta.accept.length > 0) {
// 有数据合并到数组
meta.accept.forEach(x=> members.push(x.addr))
} else {
// 没有数据则退出
break
}
i++
}
return members
}
- 发送、接收客服消息
async function main (){
// 获取客服列表
let dests = await getSubscribers(topic, address)
// 封装 D-Chat 可以识别的私聊类型
let data = {
contentType: 'text',
id: uuidv4(), // import uuidv4 from 'uuid/v4'
content: 'hello world',
isPrivate: true,
timestamp: new Date().getTime()
}
client.on('connect', function () {
// 群发消息给客服
client.send(dests, JSON.stringify(data))
})
// 接收客服消息
client.on('message', function (src, data) {
// src: 发送人地址, data: 接收到的数据
let message = JSON.parse(data)
if (message.contentType === 'text') {
// TODO ... 显示message到界面
// 封装D-Chat的可以识别的回执消息体
let receipt = {
contentType: 'receipt',
id: uuidv4(), // import uuidv4 from 'uuid/v4'
timestamp: new Date().getTime(),
targetID: message.id,
isPrivate: true
}
// 发送回执消息
client.send(dests, JSON.stringify(receipt))
}
})
}
main()