| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- "use strict";
- const common_vendor = require("../common/vendor.js");
- const utils_request = require("./request.js");
- const BASE_URL = utils_request.UPLOAD_URL;
- function getWsUrl() {
- return BASE_URL.replace(/^http/, "ws") + "/api/chat/ws/chat/websocket";
- }
- let socketTask = null;
- let isConnected = false;
- let subscriptionId = 0;
- const subscriptions = {};
- let reconnectCount = 0;
- const MAX_RECONNECT = 5;
- let reconnectTimer = null;
- let heartbeatTimer = null;
- let connectHeaders = {};
- let onConnectCallback = null;
- let onDisconnectCallback = null;
- function connectChat(options = {}) {
- const { token, onConnect, onDisconnect } = options;
- onConnectCallback = onConnect || null;
- onDisconnectCallback = onDisconnect || null;
- connectHeaders = {};
- if (token) {
- connectHeaders["Authorization"] = "Bearer " + token;
- }
- const wsUrl = getWsUrl();
- common_vendor.index.__f__("log", "at utils/chatSocket.js:46", "[ChatSocket] 连接中...", wsUrl);
- socketTask = common_vendor.index.connectSocket({
- url: wsUrl,
- header: {
- "Authorization": connectHeaders["Authorization"] || ""
- },
- success: () => {
- common_vendor.index.__f__("log", "at utils/chatSocket.js:54", "[ChatSocket] 连接请求已发送");
- },
- fail: (err) => {
- common_vendor.index.__f__("error", "at utils/chatSocket.js:57", "[ChatSocket] 连接失败", err);
- scheduleReconnect();
- }
- });
- socketTask.onOpen(() => {
- common_vendor.index.__f__("log", "at utils/chatSocket.js:63", "[ChatSocket] WebSocket 已打开,发送 STOMP CONNECT");
- sendStompConnect();
- });
- socketTask.onMessage((res) => {
- handleStompFrame(res.data);
- });
- socketTask.onClose((res) => {
- common_vendor.index.__f__("log", "at utils/chatSocket.js:72", "[ChatSocket] WebSocket 已关闭", res);
- isConnected = false;
- stopHeartbeat();
- if (onDisconnectCallback)
- onDisconnectCallback();
- scheduleReconnect();
- });
- socketTask.onError((err) => {
- common_vendor.index.__f__("error", "at utils/chatSocket.js:80", "[ChatSocket] WebSocket 错误", err);
- isConnected = false;
- });
- }
- function sendStompConnect() {
- const headers = {
- "accept-version": "1.1,1.0",
- "heart-beat": "10000,10000"
- };
- if (connectHeaders["Authorization"]) {
- headers["Authorization"] = connectHeaders["Authorization"];
- }
- sendFrame("CONNECT", headers, "");
- }
- function handleStompFrame(data) {
- if (!data || typeof data !== "string")
- return;
- const frames = data.split("\0");
- for (const raw of frames) {
- if (!raw.trim())
- continue;
- parseFrame(raw.trim());
- }
- }
- function parseFrame(raw) {
- const lines = raw.split("\n");
- if (lines.length === 0)
- return;
- const command = lines[0].trim();
- const headers = {};
- let bodyStart = 0;
- for (let i = 1; i < lines.length; i++) {
- const line = lines[i];
- if (line === "") {
- bodyStart = i + 1;
- break;
- }
- const colonIdx = line.indexOf(":");
- if (colonIdx > 0) {
- headers[line.substring(0, colonIdx).trim()] = line.substring(colonIdx + 1).trim();
- }
- }
- const body = lines.slice(bodyStart).join("\n").replace(/\0$/, "").trim();
- switch (command) {
- case "CONNECTED":
- common_vendor.index.__f__("log", "at utils/chatSocket.js:142", "[ChatSocket] STOMP 连接成功");
- isConnected = true;
- reconnectCount = 0;
- startHeartbeat();
- Object.keys(subscriptions).forEach((id) => {
- const sub = subscriptions[id];
- sendFrame("SUBSCRIBE", { id, destination: sub.destination, ack: "auto" }, "");
- });
- if (onConnectCallback)
- onConnectCallback();
- break;
- case "MESSAGE":
- handleStompMessage(headers, body);
- break;
- case "RECEIPT":
- common_vendor.index.__f__("log", "at utils/chatSocket.js:159", "[ChatSocket] 收到回执:", headers["receipt-id"]);
- break;
- case "ERROR":
- common_vendor.index.__f__("error", "at utils/chatSocket.js:163", "[ChatSocket] STOMP 错误:", headers["message"], body);
- break;
- }
- }
- function handleStompMessage(headers, body) {
- const destination = headers["destination"];
- if (!destination)
- return;
- let data = body;
- try {
- data = JSON.parse(body);
- } catch (e) {
- }
- Object.keys(subscriptions).forEach((id) => {
- const sub = subscriptions[id];
- if (destination === sub.destination || destination.startsWith(sub.destination)) {
- sub.callback(data, headers);
- }
- });
- }
- function subscribe(destination, callback) {
- const id = "sub-" + ++subscriptionId;
- subscriptions[id] = { destination, callback };
- if (isConnected) {
- sendFrame("SUBSCRIBE", { id, destination, ack: "auto" }, "");
- }
- return id;
- }
- function unsubscribe(id) {
- if (subscriptions[id]) {
- if (isConnected) {
- sendFrame("UNSUBSCRIBE", { id }, "");
- }
- delete subscriptions[id];
- }
- }
- function sendTextByWs(sessionId, content, msgType = "text", msgNo = "", senderId = null) {
- if (!isConnected) {
- common_vendor.index.__f__("warn", "at utils/chatSocket.js:238", "[ChatSocket] 未连接,无法发送消息");
- return false;
- }
- if (!msgNo) {
- msgNo = generateMsgNo();
- }
- const bodyObj = {
- msgType,
- sessionId,
- msgNo,
- content
- };
- if (senderId) {
- bodyObj.senderId = senderId;
- }
- const body = JSON.stringify(bodyObj);
- sendFrame("SEND", { destination: "/app/chat/send", "content-type": "application/json" }, body);
- return true;
- }
- function disconnectChat() {
- if (socketTask && isConnected) {
- sendFrame("DISCONNECT", { receipt: "disconnect-" + Date.now() }, "");
- }
- clearAll();
- if (socketTask) {
- socketTask.close({});
- socketTask = null;
- }
- }
- function clearAll() {
- isConnected = false;
- stopHeartbeat();
- if (reconnectTimer) {
- clearTimeout(reconnectTimer);
- reconnectTimer = null;
- }
- Object.keys(subscriptions).forEach((id) => delete subscriptions[id]);
- }
- function sendFrame(command, headers, body) {
- if (!socketTask)
- return;
- let frame = command + "\n";
- if (headers) {
- Object.keys(headers).forEach((key) => {
- frame += key + ":" + headers[key] + "\n";
- });
- }
- frame += "\n";
- if (body) {
- frame += body;
- }
- frame += "\0";
- socketTask.send({
- data: frame,
- fail: (err) => {
- common_vendor.index.__f__("error", "at utils/chatSocket.js:314", "[ChatSocket] 发送帧失败:", command, err);
- }
- });
- }
- function startHeartbeat() {
- stopHeartbeat();
- heartbeatTimer = setInterval(() => {
- if (isConnected && socketTask) {
- socketTask.send({
- data: "\n",
- fail: () => {
- }
- });
- }
- }, 1e4);
- }
- function stopHeartbeat() {
- if (heartbeatTimer) {
- clearInterval(heartbeatTimer);
- heartbeatTimer = null;
- }
- }
- function scheduleReconnect() {
- if (reconnectCount >= MAX_RECONNECT) {
- common_vendor.index.__f__("log", "at utils/chatSocket.js:347", "[ChatSocket] 达到最大重连次数,停止重连");
- return;
- }
- reconnectCount++;
- const delay = Math.min(3e3 * reconnectCount, 15e3);
- common_vendor.index.__f__("log", "at utils/chatSocket.js:352", `[ChatSocket] ${delay}ms 后进行第 ${reconnectCount} 次重连...`);
- reconnectTimer = setTimeout(() => {
- const token = common_vendor.index.getStorageSync("token");
- connectChat({
- token,
- onConnect: onConnectCallback,
- onDisconnect: onDisconnectCallback
- });
- }, delay);
- }
- function generateMsgNo() {
- return "MSG_" + Date.now() + "_" + Math.random().toString(36).slice(2, 8);
- }
- function isSocketConnected() {
- return isConnected;
- }
- exports.connectChat = connectChat;
- exports.disconnectChat = disconnectChat;
- exports.generateMsgNo = generateMsgNo;
- exports.isSocketConnected = isSocketConnected;
- exports.sendTextByWs = sendTextByWs;
- exports.subscribe = subscribe;
- exports.unsubscribe = unsubscribe;
- //# sourceMappingURL=../../.sourcemap/mp-weixin/utils/chatSocket.js.map
|