前端开发基于node.js的im初实现

前端开发与java开发哪个好
java开发前端后端
web前端开发 java

这次本来准备做一个基于话题讨论的小程序,需要用到im,所以就做了一个demo,初步实现了im功能。

im需要使用websocket实现功能,微信小程序实现了websocket接口,可以直接使用;服务端这边选用了ws包,比较简单上手。

一、小程序实现
1、连接wss wx.connectSocket()
2、发送消息 wx.connectSocket(JSON.stringify(msg))
3、监听消息 wx.onSocketMessage()
4、只要界面保持,保持连接 ,微信这边如果超过60s无响应,会自动关闭socket
javascript 代码

var timerId = 0,
    _this = this
var timeout = 55000
function keepAlive() {
    wx.sendSocketMessage({
        data: JSON.stringify({
            type: ‘keep’,
        }),
    })
    console.log(‘keep alive’)
}
timerId = setInterval(function() {
    keepAlive()
}, timeout)

5、关闭连接
javascript 代码

wx.onSocketClose(function(res) {
    console.log(‘WebSocket 已关闭!’)
})

二、服务端
1、wss首先需要配置nginx,这里共用了https的证书
2、搭建wss服务器
wss = new WebSocketServer({
port: 4000
});
3、监听客户端
整体思路是:所有的聊天数据全部换存在redis里面,每日定时任务schedule更新数据到数据库中
每次客户端获取聊天数据是从redis里面获取,最多50条数据记录
为了识别用户,每次连接ws后,客户端会发送一条type=log的用户,夹带者用户user_id和话题chat_id,然后服务器端将该用户放置到对应聊天室内
客户端发送聊天数据,type=msg, 服务器会实时广播给所有客户端,并将聊天记录存入对应redis
客户端断开连接用户数据从redis列表中移除

每次重启node服务器会断开所有的ws连接需要作出判断

javascript 代码

/**
* Create websocket server.
*/
var WebSocketServer = require(‘ws’).Server
var chatDao = require(‘../../dao/chatDao’)
var schedule = require(‘node-schedule’) //定时任务
var Redis = require(‘ioredis’)
var redis = new Redis()
var async = require(‘async’) //事件控制
module.exports = {
    // 连接池
    clients: {},
    connectionIDCounter: 0,
    //定时任务
    createSchedule: function(time) {
        var rule = new schedule.RecurrenceRule()
        rule.hour = time
        // rule.second = time;
        var j = schedule.scheduleJob(rule, function() {
            console.log(‘scheduleJob’)
            //所有话题入库
            async.waterfall(
                [
                    function(callback) {
                        redis.get(‘chat’).then(function(result) {
                            callback(null, JSON.parse(result))
                        })
                    },
                ],
                function(err, results) {
                    var l = results.length
                    for (var i = 0; i < l; i++) {
                        redis.get(‘chat’ + results[i]).then(function(result) {
                            result = JSON.parse(result)
                            var l = result.content.length //可能不存在聊天记录
                            // 聊天记录数据超过200的留下最新的50条记录在redis,其他的数据全部入库
                            if (l >= 200) {
                                var arr = result.content.slice(0, l – 50) //截取数组
                                //把对象的转成纯数组
                                var values = []
                                arr.forEach(function(n, i) {
                                    var _arr = []
                                    for (var m in n) {
                                        if (
                                            m != ‘avatarUrl’ &&
                                            m != ‘nickName’
                                        ) {
                                            _arr.push(n[m])
                                        }
                                    }
                                    values.push(_arr)
                                })
                                result.content = result.content.slice(l – 51, l) //留下50条记录
                                redis.set(‘chat67’, JSON.stringify(result)) // 保证有初始值,json转数组
                                //更新聊天记录表
                                chatDao.updatechatRecordbythemeId(
                                    values,
                                    function(err, ret) {
                                        console.log(ret)
                                    },
                                )
                            }
                        })
                    }
                },
            )
        })
    },
    //用户插入到话题列表
    addUserIntoWSuser: function(ws, msg) {
        var _this = this
        redis.get(‘chat’ + msg.theme_id).then(function(result) {
            result = JSON.parse(result)
            console.log(‘redis theme list: ‘, result)
            //存入用户id
            try {
                if (result.user.indexOf(msg.user_writer_id) < 0) {
                    result.user.push(msg.user_writer_id)
                    // console.log(msg);
                }
            } catch (err) {
                result = {
                    theme_id: msg.theme_id,
                    content: [],
                    user: [],
                }
                result.user.push(msg.user_writer_id) //存入用户id
            }
            //创建话题的缓存
            if (!_this.clients.hasOwnProperty(‘chat’ + msg.theme_id)) {
                _this.clients[‘chat’ + msg.theme_id] = []
            }
            ws.id = _this.connectionIDCounter++
            _this.clients[‘chat’ + msg.theme_id].push(ws) //用户入群
            console.log(
                ‘addUserIntoWSuser: ‘,
                _this.clients,
                result.user,
                ws._socket._handle.fd,
            )
            redis.set(‘chat’ + msg.theme_id, JSON.stringify(result)) //数据成功存储到redis
        })
    },
    //话题存入缓存中
    addContentIntoWScontent: function(msg) {
        redis.get(‘chat’ + msg.theme_id).then(function(result) {
            result = JSON.parse(result)
            result.content.push(msg) //存入聊天记录
            console.log(‘addContentIntoWScontent: ‘, result.content)
            redis.set(‘chat’ + msg.theme_id, JSON.stringify(result)) //数据成功存储到redis
        })
    },
    //初始化websocket服务器
    initWebSocketServer: function() {
        var _this = this
        var msgTmp
        // 监听websocket服务器
        wss = new WebSocketServer({
            port: 4000,
        })
        this.createSchedule(3) //每天凌晨3点定时任务
        wss.on(‘connection’, function(ws) {
            // console.log(ws);
            ws.on(‘message’, function(message) {
                if (message) {
                    msgTmp = JSON.parse(message)
                    if (msgTmp.type == ‘msg’) {
                        //话题存入缓存中
                        _this.addContentIntoWScontent(msgTmp)
                        try {
                            _this.clients[‘chat’ + msgTmp.theme_id].forEach(
                                function callback(ws1, index, array) {
                                    console.log(‘broadcast: ‘, message)
                                    if (ws.isAlive === false)
                                        _this.clients[
                                            ‘chat’ + msgTmp.theme_id
                                        ].splice(index, 1)
                                    ws1.send(message)
                                },
                            )
                        } catch (err) {
                            console.error(err, new Date())
                        }
                    } else if (msgTmp.type == ‘log’) {
                        // 用户数据将该连接加入连接池
                        _this.addUserIntoWSuser(ws, msgTmp)
                    } else if (msgTmp.type == ‘keep’) {
                        console.log(message)
                    } else {
                        console.log(message)
                    }
                }
            })
            // 连接关闭时,将其移出对应话题连接池
            ws.on(‘close’, function(message) {
                console.log(message)
            })
        })
    },
}
java前端累还是开发累
java web前端开发流程
学java还是前端开发
» 本文来自:前端开发者 » 《前端开发基于node.js的im初实现》
» 本文链接地址:https://www.rokub.com/8148.html
» 您也可以订阅本站:https://www.rokub.com
赞(0)
64K

评论 抢沙发

评论前必须登录!