LayIM 是一个相当优秀的Web IM方案,封装了WebSocket,接入简单,我使用的场景是客服模式。
用户在页面、微信等发送消息,客服在后台回复,用户收到客服的回复,目前由于只考虑单客服,所以整体流程很简单。
后台使用Laravel 5.2
,Laravel
接入LayIM
主要借用了Redis
的Sub/Pub
功能,使用Nodejs
作为转发,达到快速开发的目的。流程如下:
LayIM
通过WebSocket链接NodeJS脚本,NodeJS脚本通过Redis的Sub/Pub链接Laravel.
LayIM
官方文档中使用的原生的WebSocket
,也提供了socket.io
库,由于NodeJS
使用的是socket.io
库,所以前台也要使用对应的库,方便接入。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
layui.use('layim', function() {
var layim = layui.layim;
var socket = io('ws://url.com:6001');
//连接成功时触发
socket.on('connect', function() {
layimStatus = 'connect';
socket.emit('join', '一个标示');
});
//监听reply消息标示
socket.on('reply', function(data) {
//把接收到的消息转发到聊天窗口
layim.getMessage(data); //data即你发送消息传递的数据(阅读:监听发送的消息)
});
//监听join消息标示
socket.on('join', function(msg) {
layer.msg(msg, {
icon: 1
});
});
//断开链接
socket.on('disconnect', function() {
layimStatus = 'disconnect';
layer.msg('聊天窗口链接失败,请刷新页面重试!', {
icon: 2,
time: 3000
});
});
socket.on('error', function() {
layimStatus = 'disconnect';
layer.msg('聊天窗口链接失败,请刷新页面重试!', {
icon: 2,
time: 3000
});
});
socket.on('reconnect', function() {
layimStatus = 'connect';
});
layim.config({
brief: true //简约模式,不显示主面板
,
title: '客服面板',
min: true,
mine: {
avatar: '/img/head.jpg',
username: '我是客服',
id: 1
},
maxLength: 500 //最长发送字符长度
});
layim.on('sendMessage', function(res) {
console.debug('sendMessage-res', res);
res['to']['msgid'] = replyMsgId;
socket.emit('reply', res);
replyMsgId = 0;
});
var $ = layui.jquery,
active = {
reply: function(username, openid, head, msgid) {
layim.chat({
name: username,
type: 'kefu',
avatar: head,
id: openid
});
}
};
$(document).on('click', '.reply', function() {
//获取用户名称
var t = $(this);
replyMsgId = t.data('id');
active.reply(t.data('name'), t.data('openid'), t.data('head'));
});
});
这里的NodeJS
代码很简单,依赖express
,ioredis
和socket.io
库。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var Redis = require('ioredis');
var sub = new Redis();
var pub = new Redis();
server.listen(6001);
app.get('/', function(req, res) {
res.send('欢迎来到知识的荒原!');
});
io.on('connection', function(socket) {
console.log('connection');
socket.on('reply', function(data) {
console.log('收到消息:');
console.log(data);
//推送到后台处理
pub.publish('reply.from', JSON.stringify(data));
});
//接收客户端的唯一编码,保存链接
socket.on('join', function(data) {
console.log(data + '加入');
socket.emit('join', '客服组件已加载');
});
socket.on('message', function(msg) {
console.log('get msg:');
console.log(msg);
});
socket.on('disconnect', function() {
console.log('close connection');
});
});
//监听reply.to消息
sub.psubscribe('reply.to', 'reply.error', function(channel, message) {
console.log('psubscribe wechat.to:');
});
sub.on('pmessage', function(pattern, channel, message) {
console.log(channel);
console.log(message);
var msg = JSON.parse(message);
if (channel == 'reply.to') {
var content = msg.data.content;
//这个是个Laravel发起的内容,用来发送一张图片到用户,type为自定义字段
if (msg.data.type == 'image') {
content = 'img[http://url.com/img/xxxx.jpg]';
}
var remsg = {
username: msg.data.username,
avatar: msg.data.head,
id: msg.data.openid,
msgtype: msg.data.type,
type: 'kefu',
content: content,
timestamp: Date.now()
};
io.emit('reply', remsg);
} else if (channel == 'wechat.error') {
io.emit('replyerr', message);
}
});
监听Redis
的subscribe
使用Laravel
的Artisan Console
来完成,是因为监听命令是一直运行的。
命令创建参考Laravel5.2 Artisan Console。
在命令的handle
方法中监听reply.from
即可。
需要使用依赖predis/predis ~1.0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public function handle() {
echo "run wechat:sub command\n";
try {
Redis::psubscribe(['reply.from'], function($message) {
$data = json_decode($message);
if (isset($data - > to) && isset($data - > mine)) {
$to = $data - > to;
$mine = $data - > mine;
//逻辑代码
}
});
} catch (\Exception $ex) {
echo "exception \n";
Log::debug('wechat:sub意外推出');
}
}
以上是一个最简单的流程,如果有Laravel发起的消息可以使用Laravel的事件(event)的广播事件来解决。
广播事件见Laravel Event文档
下面是一个参考:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<?php
namespace AppEvents;
use AppEventsEvent;
use IlluminateQueueSerializesModels;
use IlluminateContractsBroadcastingShouldBroadcast;
use IlluminateSupportFacadesLog;
class LayIMWebSocket extends Event implements ShouldBroadcast
{
use SerializesModels;
public $openid; //openid
public $username; //用户名
public $head; //头像
public $content; //内容
public $msgid; //消息id
public $type; //消息类型
/**
* Create a new event instance.
* @return void
*/
public function __construct($openid, $username, $head, $content, $msgid, $type)
{
$this -\> openid = $openid;
$this -\> username = $username;
$this -\> head = $head;
$this -\> content = $content;
$this -\> msgid = $msgid;
$this -\> type = $type;
}
/**
* Get the channels the event should be broadcast on.
* @return array
*/
public function broadcastOn()
{
//向网页推送
return ['wechat.to'];
}
/**
* 设置事件所在队列的名称
* @return string
*/
public function onQueue()
{
return 'app-layim';
}
}
整个流程的运行需要运行三个命令:
1、运行app\WebSocket下的index.js
1
node index.js
2、运行Laravel自定义命令,用来监听node转发的redis 发布 (许使用supervisor
维护进程)
1
php artisan layim:sub
3、运行Laravel队列,用来监控事件转发
1
php artisan queue:work --queue==app-layim --daemon
原网址: 访问
创建于: 2019-04-06 23:22:56
目录: default
标签: 无
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
最新评论