代码

index.js

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
const http = require('http');
const WebSocket = require('ws');
const miment = require('miment');

const server = http.createServer();
const wss = new WebSocket.Server({
server
});
const Redis = require("ioredis");
const redis = new Redis({
port: 6379, // Redis port
host: "127.0.0.1", // Redis host
family: 4, // 4 (IPv4) or 6 (IPv6)
// password: "123456",
db: 0
});

let userCount = 0
wss.on('connection', function connection(ws) {
userCount++
const ipInfo = ws._socket.remoteAddress

chatInit(ws)

ws.on('close', function close() {
userCount--
broadCast({
name: '系统消息',
time: miment().format('YYYY-MM-DD hh:mm:ss'),
con: `有人退出了!当前在线人数:${userCount}人`
})
});

ws.on('message', function incoming(msg) {
//发送信息

msg = JSON.parse(msg)
if (msg.name === 'admin' && msg.con === 'clear') {
clearRecords(ws)
} else {
msg.time = miment().format('YYYY-MM-DD hh:mm:ss')
msg.ipInfo = ipInfo
broadCast(msg)
saveRecords(msg)
}

});

});

function chatInit(ws) {
redis.get('chat:record').then((records) => {
if (records) {
ws.send(records);
}
ws.send(JSON.stringify({
name: '系统消息',
time: miment().format('YYYY-MM-DD hh:mm:ss'),
con: `链接已建立,可以开始聊天了!当前在线人数:${userCount}人`
}));
broadCastOther(ws, {
name: '系统消息',
time: miment().format('YYYY-MM-DD hh:mm:ss'),
con: `有新用户登录了!当前在线人数:${userCount}人`
})
});
}
//广播所有在线用户
function broadCast(msg) {
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify(msg));
}
});
}
//除自身外广播
function broadCastOther(ws, msg) {
wss.clients.forEach(function each(client) {
if (client !== ws && client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify(msg));
}
});
}


function saveRecords(msg) {
redis.get('chat:record').then((reply) => {
if (!reply) {
reply = [];
}
let records = typeof reply === 'string' ? JSON.parse(reply) : reply;
records.push(msg)
redis.set('chat:record', JSON.stringify(records)).then(() => { });
});
}

function clearRecords(ws) {
redis.del('chat:record').then((records) => {
ws.send(JSON.stringify({
name: '系统消息',
time: miment().format('YYYY-MM-DD hh:mm:ss'),
con: `消息记录已清除`
}));
});
}


server.listen(8111);

package.json

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
{
"name": "wss",
"version": "1.0.0",
"description": "ws",
"main": "index.js",
"scripts": {
"build": "npm i && cross-env NODE_ENV=prod pm2 start index.js -n wss",
"rebuild": "pm2 delete wss && npm i && cross-env NODE_ENV=prod pm2 start index.js -n wss",
"reload": "npm i && cross-env NODE_ENV=prod pm2 reload wss",
"start": "cross-env NODE_ENV=dev nodemon index.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^0.19.0",
"form-data": "^3.0.0",
"ioredis": "^4.14.1",
"miment": "^0.0.9",
"ws": "^7.2.1"
},
"devDependencies": {
"cross-env": "^5.2.0",
"nodemon": "^1.18.11"
},
"optionalDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
}
}

demo

http://tools.meaqua.fun/chat