背景:
最近有个小项目,包括一个小功能就是讨论组聊天;
应用场景不是很大,给大家提供一种实现聊天室的思路;
存储用户信息
1.首先每个用户连接socket是由一个"key",我们需要存储这个key ,当分发消息的时候是需要用到这个;
2.讨论组不唯一,用户连接ws的时候需要连接所有的聊天室消息;
3.用map分连接的用户,当用户发送ws请求时,map添加用户的key;
router.ws('/:id', (socket, req) => {
let channelArr = req.params.id.split(',')
channelArr.forEach(item => {
connectedMap.has(item) ? connectedMap.get(item).add(socket) : connectedMap.set(item, new Set().add(socket))
console.log(`进入频道${item},当前在线人数${connectedMap.get(item).size}`)
})
})
分发消息
分发消息到我们map里所有的连接用户
socket.on('message', function (msg) {
let data = JSON.parse(msg)
//存数据库
//分发消息
if (data.type === 'message') {
broadcast(connectedMap.get(data.channel), JSON.stringify(data))
//消息存储数据库
saveMessage(data)
}
})
离开聊天室断开连接
socket.on('close', function () {
channelArr.forEach(item => {
connectedMap.get(item).delete(socket)
console.log(`离开频道${item},当前在线人数${connectedMap.get(item).size}`)
})
})
分发消息函数
function broadcast (conns, msg) {
// 群发消息给所有用户
conns.forEach(item => {
item.send(msg)
})
}
如果大型的app,并发数高;这种方法不适用;可采用Redis Channel 订阅redis消息,ws分发到各个用户这种办法
所有源码预览
const express = require('express')
const expressWS = require('express-ws')
const res = require('express/lib/response')
const router = express.Router()
const mysql = require('mysql')
expressWS(router)
let connectedMap = new Map()
let count = 0
const executeSql = require('../db/mysql')
const dateService = require('../untils/date')
//存放所有连接的用户
router.ws('/:id', (socket, req) => {
let channelArr = req.params.id.split(',')
console.log(channelArr)
channelArr.forEach(item => {
connectedMap.has(item) ? connectedMap.get(item).add(socket) : connectedMap.set(item, new Set().add(socket))
console.log(`进入频道${item},当前在线人数${connectedMap.get(item).size}`)
})
/**
* 传送格式
* {
* type:'message',
* message:'',
* name:'',
* avatar:'',
* channel:'',
* userId:'',
* }
*/
socket.on('message', function (msg) {
let data = JSON.parse(msg)
//存数据库
//分发消息
if (data.type === 'message') {
broadcast(connectedMap.get(data.channel), JSON.stringify(data))
saveMessage(data)
}
})
socket.on('close', function () {
channelArr.forEach(item => {
connectedMap.get(item).delete(socket)
console.log(`离开频道${item},当前在线人数${connectedMap.get(item).size}`)
})
})
})
function broadcast (conns, msg) {
// 群发消息给所有用户
conns.forEach(item => {
item.send(msg)
})
}
//单独发送给一个用户
function sendMsg (conn, type, data) {
conn.send(JSON.stringify({ type: type, data: data }))
}
router.get('/getGroups', async (req, res) => {
const userId = req.query.userId
const sql = 'SELECT id, group_name FROM group_info WHERE id IN (SELECT group_id FROM group_member WHERE user_id = ?)'
try {
const result = await executeSql(sql, [userId])
res.json({ code: 200, data: result })
} catch (error) {
console.error(error)
res.status(500).json({ message: 'Internal server error' })
}
})
//聊天记录存数据库函数
async function saveMessage (data) {
}
module.exports = router