Open xgqfrms opened 5 years ago
"use strict";
/**
*
* @author xgqfrms
* @license MIT
* @copyright xgqfrms
*
* @description WS client
* @augments
* @example
* @link
*
*/
const url = `ws://www.xgqfrms.xyz/chat/?token=666666`;
let ws = new WebSocket(url);
let log = console.log;
ws.onopen = function(e) {
log(`已经建立连接 open`, ws.readyState);
log(`B uid = 6845422`);
// log(`e = `, e);
if (ws.readyState === 1) {
allReady();
}
};
ws.onerror = function(e) {
log(`连接异常 error`, ws.readyState);
// log(`e = `, e);
// if (ws.readyState === 4) {
// unSubscribe();
// }
unSubscribe();
};
ws.onmessage = function(res) {
log(`B 收到消息 message`, ws.readyState);
let data = res.data;
data = JSON.parse(data);
// let origin = res.origin;
// log(`res & e = `, res);
// log(`typeof(data) = `, typeof(data));
// log(`res.origin = `, origin);
log(`res.data = `, JSON.stringify(data, null, 4));
let {
Action,
} = data;
switch (Action) {
case 20:
let {
// SendUserID,
Info,
} = data;
handleList(Info);
break;
case 21:
(() => {
let {
SendUserID,
Info,
} = data;
handleNewMessages(Info, SendUserID);
})();
break;
case 1:
if (Action) {
handleNew();
} else {
handleMessage();
}
break;
case 4:
// subscribe();
break;
case 5:
// unSubscribe();
break;
default:
// sendMsg();
break;
}
};
ws.onclose = function(e) {
log(`已经关闭连接 close`, ws.readyState);
if (ws.readyState === 3) {
// 关闭连接
unSubscribe();
}
// log(`e = `, e);
};
const allReady = () => {
let msg = {
Action: 20,
LastMsgIds: [],
};
log(`B 准备就绪`);
let str_msg = JSON.stringify(msg);
ws.send(str_msg);
};
const sendMsg = (text = `` ) => {
let msg = {
Action: 1,
ReciveUserID: "6845488",
Info: text ? text : `B 文本消息 text`,
MsgType: 1,// 消息类型,number, 可取值: 1-文本、2-图片、3-表情、4-视频、5-音频
};
// let msg = {
// Action: 1,
// SendUserID: "6845422",
// ReciveUserID: "6845488",
// SerialNumber: "消息序列",
// Info: text,
// MsgType: 1,// 消息类型,number, 可取值: 1-文本、2-图片、3-表情、4-视频、5-音频
// };
log(`B 发送聊天消息`);
let str_msg = JSON.stringify(msg);
ws.send(str_msg);
};
const handleList = (datas = [], debug = false) => {
// log(`list =`, JSON.stringify(datas, null, 4));
let result = [];
let chat_list_uids = [];
if (datas.length) {
datas.forEach(
(obj, i) => {
let {
ChatUserName: userName,
ChatUserID: userId,
CompanyName: corpName,
Top: isTop,
Hide: isHidden,
} = obj;
let temp = {
userName,
userId,
corpName,
isTop,
isHidden,
text: "default news placeholder",
time: "",
count: 0,
};
result.push(temp);
chat_list_uids.push(userId);
// chat_list_uids.push({
// userId,
// });
}
);
}
listAutoGenerator(result);
// TODO old + new
window.localStorage.setItem(`chat_list`, JSON.stringify(result));
window.localStorage.setItem(`chat_list_uids`, JSON.stringify(chat_list_uids));
// return result;
};
const handleNewMessages = (datas = [], selfId = ``, debug = false) => {
// log(`New Messages =`, JSON.stringify(datas, null, 4));
let result = [];
let chat_list = JSON.parse(window.localStorage.getItem(`chat_list`));
let chat_list_uids = JSON.parse(window.localStorage.getItem(`chat_list_uids`));
log(`chat_list =`, chat_list);
log(`chat_list_uids =`, chat_list_uids);
if (chat_list_uids.length) {
window.DB = window.DB || {};
chat_list_uids.forEach(
(item, i) => {
window.DB[item] = window.DB[item] || [];
// DB Store
}
);
}
// chat_list_uids.includes(senderUid);
if (datas.length) {
datas.forEach(
(obj, i) => {
let {
SendUserID: senderUid,
ReciveUserID: receiverUid,
SerialNumber: serialNum,
MsgID: msgId,
Info: text,
// MsgType: msgType,
SendTime: time,
UnReadMsgCount: count,
} = obj;
if (senderUid !== selfId) {
let temp = {
senderUid,
receiverUid,
serialNum,
msgId,
// msgType,
text,
time,
count,
};
window.DB[senderUid].push(temp);
// result.push(temp);
// window.DB[6845333];
}
}
);
}
// listAutoUpdater(result);
// window.localStorage.setItem(`chat_list_messages`, JSON.stringify(result));
// return result;
};
const handleNew = (datas = [], debug = false) => {
//
};
const handleMessage = (datas = [], debug = false) => {
//
};
const handleHistoryMessage = (datas = [], debug = false) => {
// self + others
};
let LastMsgId = ``;
const subscribe = () => {
let msg = {
Action: 4,
SendUserID: "6845422",
ReciveUserID: "6845488",
SerialNumber: "消息序列",
LastMsgId: 605337337539633200,
// LastMsgId: LastMsgId,
// LastMsgId,
};
log(`B 订阅消息`);
let str_msg = JSON.stringify(msg);
ws.send(str_msg);
};
const unSubscribe = () => {
let msg = {
Action: 5,
};
log(`B 取消订阅`);
let str_msg = JSON.stringify(msg);
ws.send(str_msg);
log(`B 取消订阅 OK`);
};
const listAutoGenerator = (list = []) => {
// log(`%cchat_list =`, `color: #f0f;`, `%c${JSON.stringify(list, null, 4)}`, `color: red;`);
// log(`%cchat_list =\n%c${JSON.stringify(list, null, 4)}`, `color: #f0f;`, `color: #0f0; background: #000;`);
log(`%cchat_list =\n%c${JSON.stringify(list, null, 4)}`, `color: #f0f;`, `color: #3f3;`);
let msgBox = document.querySelector(`[data-dom="msg-box"]`);
let html = ``;
if (list.length) {
list.forEach(
(obj, i) => {
let {
userName,
// userId,
// corpName,
text,
count,
// time,
} = obj;
if (count > 0) {
html += `
<p class="msg" data-uid="">
<span class="msg-name">${userName}</span>
${text}
<span class="msg-count">${count}</span>
</p>
`;
} else {
html += `
<p class="msg" data-uid="">
<span class="msg-name">${userName}</span>
${text}
</p>
`;
}
}
);
msgBox.insertAdjacentHTML(`beforeend`, html);
}
};
let msgBox = document.querySelector(`[data-dom="msg-box"]`);
const autoListBind = () => {
let msgs = [...document.querySelectorAll(`[data-dom="msg"]`)];
if (msgs.length) {
msgs.forEach(
(msg, i) => {
let bindOnceFlag = msg.dataset.bindOnceFlag || false;
if (!bindOnceFlag) {
msg.addEventListener(`click`, () => {
msg.dataset.bindOnceFlag = true;
// i ??? data-uid
});
}
}
)
}
};
var timerID = 0;
function keepAlive() {
var timeout = 20000;
if (webSocket.readyState == webSocket.OPEN) {
webSocket.send('');
}
timerId = setTimeout(keepAlive, timeout);
}
function cancelKeepAlive() {
if (timerId) {
clearTimeout(timerId);
}
}
https://www.jstips.co/en/javascript/working-with-websocket-timeout/ https://docs.k6.io/docs/websockets
心跳检测
服务端支持Ping/Pong
客户端不支持Ping/Pong
服务端向客户端发送 Ping 检测; 客户端向服务端相应 Pong 应答
客户端向服务端发送自定义的 heartbeat 检测空消息; 服务端添加判断逻辑,忽略收到的消息,以保持会话的持续连接,防止2分钟内没有消息通信,断开 websocket 连接!
https://github.com/xgqfrms/FEIQA/issues/87#issuecomment-516341470
https://stackoverflow.com/questions/10585355/sending-websocket-ping-pong-frame-from-browser
ws.onopen = function(e) {
log(`已经建立连接 open`, ws.readyState);
log(`B uid = 6845422`);
// log(`e = `, e);
if (ws.readyState === 1) {
allReady();
autoKeepAlive();
// ping
// ws.send(0x9);
// pong
// ws.send(0xA);
}
};
https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers
seems not work ?
// ping
ws.send(0x9);
// pong
ws.send(0xA);
https://github.com/websockets/ws/issues/977
still not work
ws.onping = function(e) {
log(`ping`, ws.readyState);
// ws.ping();
};
ws.onpong = function(e) {
log(`pong`, ws.readyState);
// ws.ping();
};
ws.on(`ping`, function heartbeat() {
log(`ping`);
// this.isAlive = true;
});
ws.on(`pong`, function heartbeat() {
log(`pong`);
// this.isAlive = true;
});
// ws.ping();
// ws.ping(0x9);
// ws.pong();
// ws.pong(0xA);
let ws = new WebSocket('wss://echo.websocket.org/');
ws.onmessage = function (res) {
console.log(`res.data =`, res.data);
};
https://django-websocket-redis.readthedocs.io/en/latest/heartbeats.html
https://codeday.me/bug/20170714/39844.html
https://group.swoole.com/question/107170
我搜了一圈 貌似在现有的websocket的api中,没有提供ping的接口。 所以暂时我还是使用普通的发消息搞的心跳
https://websocket.org/ wss://echo.websocket.org
https://websocket.org/book.html
https://github.com/vjwang/WebSocketBook
// Send a Blob
var blob = new Blob("blob contents");
ws.send(blob);
// Send an ArrayBuffer
var a = new Uint8Array([8,6,7,5,3,0,9]);
ws.send(a.buffer);
http://file.allitebooks.com/20150518/The%20Definitive%20Guide%20to%20HTML5%20WebSocket.pdf
"use strict";
/**
*
* @author xgqfrms
* @license MIT
* @copyright xgqfrms
*
* @description WS client
* @augments
* @example
* @link
*
*/
const url = `ws://xgqfrms.xyz/api/chat/?token=11`;
// const url = `wss://echo.websocket.org`;
let ws = new WebSocket(url);
let log = console.log;
let MSG_COUNTER = 1;
let startTime = new Date().getTime();
let endTime = ``;
var timerID = 0;
function autoKeepAlive() {
let timeout = 30 * 1000;
if (ws.readyState === 1) {
// ws.readyState === ws.OPEN
// ws.OPEN == 1
log(`B keep alive && heart beat`);
ws.send(``);
// ws.send(`keep alive!`);
}
timerID = setTimeout(autoKeepAlive, timeout);
}
function cancelKeepAlive() {
if (timerID) {
clearTimeout(timerID);
}
}
ws.onopen = function(e) {
log(`已经建立连接 open`, ws.readyState);
log(`B uid = 6845422`);
// ws.ping();
// ws.ping(0x9);
// ws.pong();
// ws.pong(0xA);
// log(`e = `, e);
if (ws.readyState === 1) {
allReady();
autoKeepAlive();
// ping
// ws.send(0x9);
// pong
// ws.send(0xA);
}
};
// ws.onping = function(e) {
// log(`连接 ping`, ws.readyState);
// // ws.ping();
// };
// ws.onpong = function(e) {
// log(`连接 pong`, ws.readyState);
// // ws.ping();
// };
// ws.on(`ping`, function heartbeat() {
// log(`连接 ping`);
// // this.isAlive = true;
// });
// ws.on(`pong`, function heartbeat() {
// log(`连接 pong`);
// // this.isAlive = true;
// });
ws.onerror = function(e) {
log(`连接异常 error`, ws.readyState);
log(`连接异常 e = `, e);
// if (ws.readyState === 4) {
// unSubscribe();
// }
unSubscribe();
cancelKeepAlive();
};
ws.onmessage = function(res) {
log(`B 收到消息 message`, ws.readyState);
let data = res.data;
data = JSON.parse(data);
// let origin = res.origin;
// log(`res & e = `, res);
// log(`typeof(data) = `, typeof(data));
// log(`res.origin = `, origin);
log(`res.data = `, JSON.stringify(data, null, 4));
let {
Action,
} = data;
switch (Action) {
case 20:
let {
// SendUserID,
Info,
} = data;
handleList(Info);
break;
case 21:
(() => {
let {
SendUserID,
Info,
} = data;
handleBlockMessages(Info, SendUserID);
})();
break;
case 1:
(() => {
handleNewMessage(data);
})();
// if (Action) {
// handleNew();
// } else {
// handleMessage();
// }
break;
case 4:
// subscribe();
break;
case 5:
// unSubscribe();
break;
default:
// sendMsg();
break;
}
};
ws.onclose = function(e) {
log(`已经关闭连接 close`, ws.readyState);
log(`连接关闭 e = `, e);
endTime = new Date().getTime();
let timer = (endTime - startTime) / 1000;
log(`auto 关闭 timer`, timer);
if (ws.readyState === 3) {
// 关闭连接
unSubscribe();
cancelKeepAlive();
}
};
const allReady = () => {
let msg = {
Action: 20,
// LastMsgIds: [],
LastMsgIds: [
{
K: "6845488",
V: 605775149602742300,
// UserId: "6845488",
// LastMsgId: 605775149602742300,
},
],
};
log(`B 准备就绪`);
let str_msg = JSON.stringify(msg);
ws.send(str_msg);
};
const sendMsg = (text = `` ) => {
let timestamp = new Date().getTime();
let msg = {
Action: 1,
ReciveUserID: "6845488",
Info: text ? text : `B 文本消息 text ${MSG_COUNTER}`,
MsgType: 1,// 消息类型,number, 可取值: 1-文本、2-图片、3-表情、4-视频、5-音频
SerialNumber: `B ${timestamp}`,
};
MSG_COUNTER ++;
// let msg = {
// Action: 1,
// SendUserID: "6845422",
// ReciveUserID: "6845488",
// SerialNumber: "消息序列",
// Info: text,
// MsgType: 1,// 消息类型,number, 可取值: 1-文本、2-图片、3-表情、4-视频、5-音频
// };
log(`B 发送聊天消息`);
let str_msg = JSON.stringify(msg);
ws.send(str_msg);
};
const handleList = (datas = [], debug = false) => {
// log(`list =`, JSON.stringify(datas, null, 4));
let result = [];
let chat_list_uids = [];
if (datas.length) {
datas.forEach(
(obj, i) => {
let {
ChatUserName: userName,
ChatUserID: userId,
ChatUserLogo: userIcon,
CompanyName: corpName,
Top: isTop,
Hide: isHidden,
} = obj;
let temp = {
userName,
userId,
userIcon,
corpName,
isTop,
isHidden,
text: "",
// text: "default news placeholder",
time: "",
count: 0,
};
result.push(temp);
chat_list_uids.push(userId);
// chat_list_uids.push({
// userId,
// });
}
);
}
listAutoGenerator(result);
// TODO old + new
window.localStorage.setItem(`chat_list`, JSON.stringify(result));
window.localStorage.setItem(`chat_list_uids`, JSON.stringify(chat_list_uids));
// return result;
};
const handleBlockMessages = (datas = [], selfId = ``, debug = false) => {
// log(`New Messages =`, JSON.stringify(datas, null, 4));
// let result = [];
let chat_list = JSON.parse(window.localStorage.getItem(`chat_list`));
let chat_list_uids = JSON.parse(window.localStorage.getItem(`chat_list_uids`));
log(`chat_list =`, chat_list);
log(`chat_list_uids =`, chat_list_uids);
if (chat_list_uids.length) {
window.DB = window.DB || {};
chat_list_uids.forEach(
(item, i) => {
window.DB[item] = window.DB[item] || [];
// DB Store
}
);
}
if (datas.length) {
datas.forEach(
(obj, i) => {
let {
SendUserID: senderUid,
ReciveUserID: receiverUid,
SerialNumber: serialNum,
MsgID: msgId,
Info: text,
// MsgType: msgType,
SendTime: time,
// ReciverReaded: false,
// ReceiverReaded: false,
UnReadMsgCount: count,
} = obj;
if (senderUid !== selfId) {
let temp = {
senderUid,
receiverUid,
serialNum,
msgId,
// msgType,
text,
time,
count,
};
window.DB[senderUid].push(temp);
}
}
);
}
if (chat_list.length) {
chat_list = chat_list.map(
(obj, i) => {
let {
userId,
} = obj;
let l = window.DB[userId].length;
let temp = {};
if (l > 0) {
let {
count,
msgId,
// receiverUid,
senderUid,
serialNum,
text,
time,
} = window.DB[userId][l - 1];
temp = Object.assign(obj, {
count,
lastMsgId: msgId,
// receiverUid,
senderUid,
serialNum,
text,
time,
});
} else {
temp = Object.assign(obj, {});
// temp = Object.assign(obj, {
// lastMsgId: null,
// });
}
log(`temp =`, JSON.stringify(temp, null, 4));
return temp;
}
);
// autoUpdateList();
listAutoGenerator(chat_list);
}
};
const handleNewMessage = (obj = {}, debug = false) => {
let chat_list = JSON.parse(window.localStorage.getItem(`chat_list`));
let chat_list_uids = JSON.parse(window.localStorage.getItem(`chat_list_uids`));
log(`chat_list =`, chat_list);
log(`chat_list_uids =`, chat_list_uids);
if (Object.keys(obj).length) {
let {
SendUserID: senderUid,
ReciveUserID: receiverUid,
SerialNumber: serialNum,
MsgID: msgId,
Info: text,
// MsgType: msgType,
SendTime: time,
// ReciverReaded: false,
// ReceiverReaded: false,
UnReadMsgCount: count,
} = obj;
if (!chat_list_uids.includes(senderUid)) {
log(`not exist DB Store!`, senderUid);
chat_list_uids.push(senderUid);
// chat_list.push({
// senderUid,
// });
window.DB[senderUid] = window.DB[senderUid] || [];
// window.localStorage.setItem(`chat_list`, JSON.stringify(result));
window.localStorage.setItem(`chat_list_uids`, JSON.stringify(chat_list_uids));
} else {
log(`exist DB Store!`, senderUid);
}
if (chat_list.length) {
chat_list = chat_list.map(
(obj, i) => {
let {
userId,
} = obj;
let l = window.DB[userId].length;
let temp = {};
if (senderUid === userId) {
if (l > 0) {
temp = Object.assign(obj, {
count,
lastMsgId: msgId,
// receiverUid,
senderUid,
serialNum,
text,
time,
});
} else {
temp = Object.assign(obj, {});
// temp = Object.assign(obj, {
// lastMsgId: null,
// });
}
log(`temp =`, JSON.stringify(temp, null, 4));
} else {
temp = obj;
}
return temp;
}
);
// autoUpdateList();
listAutoGenerator(chat_list);
}
}
};
const handleNew = (datas = [], debug = false) => {
//
};
const handleHistoryMessage = (datas = [], debug = false) => {
// self + others
};
let LastMsgId = ``;
const subscribe = (LastMsgId = ``) => {
let msg = {
Action: 4,
SendUserID: "6845422",
ReciveUserID: "6845488",
SerialNumber: "消息序列",
// LastMsgId: 605792912446627800,
// LastMsgId: LastMsgId,
LastMsgId,
};
log(`B 订阅消息`);
let str_msg = JSON.stringify(msg);
ws.send(str_msg);
};
const unSubscribe = () => {
let msg = {
Action: 5,
};
log(`B 取消订阅`);
let str_msg = JSON.stringify(msg);
ws.send(str_msg);
log(`B 取消订阅 OK`);
};
const listAutoGenerator = (list = []) => {
// log(`%cchat_list =\n%c${JSON.stringify(list, null, 4)}`, `color: #f0f;`, `color: #3f3;`);
let msgBox = document.querySelector(`[data-dom="msg-box"]`);
msgBox.innerHTML = ``;
let html = ``;
if (list.length) {
list.forEach(
(obj, i) => {
let {
userName,
// userId,
// corpName,
text,
count,
// time,
lastMsgId,
} = obj;
if (!lastMsgId) {
lastMsgId = ``;
}
if (count > 0) {
html += `
<p class="msg" data-uid="" data-dom="msg" data-LastMsgId="${lastMsgId}">
<span class="msg-name">${userName}</span>
${text}
<span class="msg-count">${count}</span>
</p>
`;
} else {
html += `
<p class="msg" data-uid="" data-dom="msg" data-LastMsgId="${lastMsgId}">
<span class="msg-name">${userName}</span>
${text}
</p>
`;
}
}
);
msgBox.insertAdjacentHTML(`beforeend`, html);
}
setTimeout(() => {
autoListBind();
}, 0);
};
// let msgBox = document.querySelector(`[data-dom="msg-box"]`);
const autoListBind = () => {
let msgs = [...document.querySelectorAll(`[data-dom="msg"]`)];
if (msgs.length) {
msgs.forEach(
(msg, i) => {
let bindOnceFlag = msg.dataset.bindOnceFlag || false;
if (!bindOnceFlag) {
msg.addEventListener(`click`, () => {
msg.dataset.bindOnceFlag = true;
let LastMsgId = msg.dataset.lastmsgid;
// let LastMsgId = msg.dataset.LastMsgId;
log(`click LastMsgId`, LastMsgId);
if(LastMsgId) {
subscribe(LastMsgId);
}
});
} else {
log(`only bind once!`);
}
}
)
} else {
log(`no auto subscribe`);
}
};
websocket & bug
https://www.cnblogs.com/xgqfrms/p/11067070.html
https://www.cnblogs.com/xgqfrms/p/11242198.html