项目备份
This commit is contained in:
609
module/newWebRtcSync.js
Normal file
609
module/newWebRtcSync.js
Normal file
@@ -0,0 +1,609 @@
|
||||
/**
|
||||
* 【发起方】
|
||||
1. 创建 PeerConnection
|
||||
2. 采集本地流并添加到 PeerConnection
|
||||
3. 调用 createOffer() → 生成Offer
|
||||
4. 调用 setLocalDescription(offer) → 开始收集ICE候选
|
||||
5. 通过信令发送Offer给接收方
|
||||
6. 监听 onicecandidate → 发送ICE候选给接收方
|
||||
7. 接收接收方的Answer → 调用 setRemoteDescription(answer)
|
||||
8. 接收接收方的ICE候选 → 调用 addIceCandidate(candidate)
|
||||
|
||||
【接收方】
|
||||
1. 创建 PeerConnection
|
||||
2. 接收发起方的Offer → 调用 setRemoteDescription(offer)
|
||||
3. 调用 createAnswer() → 生成Answer
|
||||
4. 调用 setLocalDescription(answer) → 开始收集ICE候选
|
||||
5. 通过信令发送Answer给发起方
|
||||
6. 监听 onicecandidate → 发送ICE候选给发起方
|
||||
7. 接收发起方的ICE候选 → 调用 addIceCandidate(candidate)
|
||||
*/
|
||||
|
||||
/**
|
||||
* WebRTC 核心封装类(ES6 模块化)
|
||||
* 支持音视频互通、自定义数据传输、外部流管理
|
||||
* 开箱即用,无需额外依赖
|
||||
*/
|
||||
export class WebRTC_ModuleSimple {
|
||||
/**
|
||||
* 构造函数
|
||||
* @param {Object} options 初始化配置
|
||||
* @param {HTMLElement} options.localVideo 本地视频播放元素
|
||||
* @param {HTMLElement} options.remoteVideo 远端视频播放元素
|
||||
* @param {string} options.dataChannelLabel 数据通道标签(默认 'chat')
|
||||
* @param {Function} receivepeerCallback 回调函数
|
||||
*/
|
||||
constructor(options = {}) {
|
||||
this.current_time = new Date();
|
||||
// 基础配置
|
||||
this.config = {
|
||||
localVideo: options.localVideo,
|
||||
remoteVideo: options.remoteVideo,
|
||||
dataChannelLabel: options.dataChannelLabel || "chat",
|
||||
iceServers: [
|
||||
{ urls: "stun:stun.l.google.com:19302" },
|
||||
{ urls: "stun:stun.cloudflare.com:3478" },
|
||||
],
|
||||
};
|
||||
// WebRTC 核心对象
|
||||
this.peerConnection = null;
|
||||
this.dataChannel = null;
|
||||
// 媒体流管理
|
||||
this.localStream = null; // 本地流(可外部传入/获取)
|
||||
this.remoteStream = null; // 远端流(可外部获取)
|
||||
|
||||
// 事件回调(外部可自定义)
|
||||
this.callbacks = {
|
||||
onIceCandidate: (candidate) => {}, // ICE 候选生成
|
||||
onConnectSuccess: () => {}, // 连接成功
|
||||
onConnectFailed: () => {}, // 连接失败
|
||||
onRemoteStream: (stream) => {}, // 收到远端流
|
||||
onMessage: (data) => {}, // 收到自定义消息
|
||||
onClose: () => {}, // 连接关闭
|
||||
onState: (state) => {},
|
||||
};
|
||||
// 初始化 PeerConnection
|
||||
this._initPeerConnection();
|
||||
}
|
||||
/**
|
||||
* 初始化 RTCPeerConnection 核心对象
|
||||
* @private
|
||||
*/
|
||||
_initPeerConnection() {
|
||||
try {
|
||||
// 销毁旧实例
|
||||
if (this.peerConnection) {
|
||||
this.peerConnection.close();
|
||||
}
|
||||
// 浏览器兼容处理
|
||||
const RTCPeerConnection =
|
||||
window.RTCPeerConnection ||
|
||||
window.mozRTCPeerConnection ||
|
||||
window.webkitRTCPeerConnection;
|
||||
this.peerConnection = new RTCPeerConnection({
|
||||
iceServers: this.config.iceServers,
|
||||
});
|
||||
// 监听信令协商状态
|
||||
this.signalingStateListener();
|
||||
// 监听远程信息
|
||||
this.peerConnectionLisioner();
|
||||
} catch (error) {
|
||||
console.error("WebRTC 初始化失败:", error);
|
||||
this.callbacks.onConnectFailed();
|
||||
}
|
||||
}
|
||||
// 监听信令状态变化(Offer/Answer/Ice 协商)
|
||||
signalingStateListener() {
|
||||
// 初始状态打印
|
||||
console.warn(
|
||||
`[webRTC]${this.current_time.toLocaleTimeString()}初始信令状态:`,
|
||||
this.peerConnection.signalingState,
|
||||
);
|
||||
// 监听信令状态变化(Offer/Answer 协商)
|
||||
this.peerConnection.onsignalingstatechange = () => {
|
||||
/**
|
||||
* 信令状态枚举值(全阶段)
|
||||
* new 初始状态
|
||||
* have-local-offer 本地已设置 Offer 发起者:已调用 createOffer() + setLocalDescription(offer)
|
||||
* have-remote-offer 远端已设置 Offer 应答者:已调用 setRemoteDescription(offer)
|
||||
* have-local-answer 本地已设置 Answer 应答者:已调用 createAnswer() + setLocalDescription(answer)
|
||||
* have-remote-answer 远端已设置 Answer 发起者:已调用 setRemoteDescription(answer)
|
||||
* stable 协商完成,稳定状态
|
||||
* closed PeerConnection 已关闭
|
||||
*/
|
||||
const state = this.peerConnection.signalingState;
|
||||
console.warn(
|
||||
`[webRTC]${this.current_time.toLocaleTimeString()}初始信令变更:`,
|
||||
state,
|
||||
);
|
||||
state && this.callbacks.onState(state);
|
||||
// 根据状态执行不同逻辑
|
||||
switch (state) {
|
||||
case "new":
|
||||
console.warn(
|
||||
`[webRTC]${this.current_time.toLocaleTimeString()}【状态】未开始协商,可创建 Offer`,
|
||||
);
|
||||
break;
|
||||
case "have-local-offer":
|
||||
console.warn(
|
||||
`[webRTC]${this.current_time.toLocaleTimeString()}【状态】发起者已发 Offer,等待应答者 Answer`,
|
||||
);
|
||||
// 可触发 ICE 候选者发送逻辑
|
||||
break;
|
||||
case "have-remote-offer":
|
||||
console.warn(
|
||||
`[webRTC]${this.current_time.toLocaleTimeString()}【状态】应答者已收 Offer,可创建 Answer`,
|
||||
);
|
||||
break;
|
||||
case "stable":
|
||||
console.warn(
|
||||
`[webRTC]${this.current_time.toLocaleTimeString()}【状态】Offer/Answer 协商完成,进入 ICE 配对阶段`,
|
||||
);
|
||||
break;
|
||||
case "closed":
|
||||
console.warn(
|
||||
`[webRTC]${this.current_time.toLocaleTimeString()}【状态】PeerConnection 已关闭,协商终止`,
|
||||
);
|
||||
break;
|
||||
default:
|
||||
console.warn(
|
||||
`[webRTC]${this.current_time.toLocaleTimeString()}【状态】协商中:`,
|
||||
state,
|
||||
);
|
||||
}
|
||||
};
|
||||
// ICE 候选者收集 / 配对 / 连接
|
||||
this.peerConnection.onicegatheringstatechange = () => {
|
||||
/**
|
||||
* ICE 连接状态(iceConnectionState)
|
||||
* new 初始状态,未开始连接
|
||||
* checking 正在检查候选者配对
|
||||
* connected 已建立连接(P2P 成功)
|
||||
* completed 连接完成(所有候选者检查完毕)
|
||||
* failed ICE 协商失败
|
||||
* disconnected 连接断开(临时)
|
||||
* closed PeerConnection 已关闭
|
||||
*/
|
||||
const state = this.peerConnection.iceGatheringState;
|
||||
console.warn(
|
||||
`[webRTC]${this.current_time.toLocaleTimeString()}ICE 收集状态变更:`,
|
||||
state,
|
||||
);
|
||||
state && this.callbacks.onState(state);
|
||||
switch (state) {
|
||||
case "gathering":
|
||||
console.warn(
|
||||
`[webRTC]${this.current_time.toLocaleTimeString()}【ICE】开始收集候选者(host/srflx/relay)`,
|
||||
state,
|
||||
);
|
||||
break;
|
||||
case "complete":
|
||||
console.warn(
|
||||
`[webRTC]${this.current_time.toLocaleTimeString()}【ICE】候选者收集完成`,
|
||||
state,
|
||||
);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
peerConnectionLisioner() {
|
||||
if (!this.peerConnection) {
|
||||
return;
|
||||
}
|
||||
// 监听远端媒体流
|
||||
this.peerConnection.ontrack = (e) => {
|
||||
this.remoteStream = e.streams[0];
|
||||
// 绑定远端视频
|
||||
if (this.config.remoteVideo) {
|
||||
this.config.remoteVideo.srcObject = this.remoteStream;
|
||||
this.config.remoteVideo.play().catch(() => {});
|
||||
}
|
||||
this.callbacks.onRemoteStream(this.remoteStream);
|
||||
};
|
||||
// 监听peer连接状态
|
||||
this.peerConnection.onconnectionstatechange = () => {
|
||||
const state = this.peerConnection.connectionState;
|
||||
if (state === "connected") {
|
||||
this.callbacks.onConnectSuccess();
|
||||
} else if (state === "failed") {
|
||||
this.callbacks.onConnectFailed();
|
||||
} else if (state === "closed") {
|
||||
this.callbacks.onClose();
|
||||
}
|
||||
};
|
||||
// 监听远端创建的数据通道
|
||||
this.peerConnection.ondatachannel = (e) => {
|
||||
this.dataChannel = e.channel;
|
||||
this.dataChannelLisioner();
|
||||
};
|
||||
// 监听 ICE 候选(需通过信令服务器发给对方)
|
||||
this.peerConnection.onicecandidate = (e) => {
|
||||
e.candidate && this.callbacks.onIceCandidate(e.candidate);
|
||||
};
|
||||
// 监听 ICE 连接状态,排查失败原因
|
||||
this.peerConnection.oniceconnectionstatechange = () => {
|
||||
const state = this.peerConnection.iceConnectionState;
|
||||
console.info("ICE 连接状态:", state);
|
||||
// 捕获 ICE failed 状态,给出明确提示
|
||||
if (state === "failed") {
|
||||
console.error("ICE 协商失败!请检查 TURN 服务器配置或网络环境");
|
||||
// 可选:触发重新协商
|
||||
this.createOffer();
|
||||
}
|
||||
};
|
||||
// 新监听 ICE 候选者生成错误
|
||||
this.peerConnection.onicecandidateerror = (event) => {
|
||||
console.error(
|
||||
"ICE 候选者生成失败:",
|
||||
event.errorText,
|
||||
"错误码:",
|
||||
event.errorCode,
|
||||
);
|
||||
};
|
||||
}
|
||||
/**
|
||||
* 初始化数据通道(自定义消息传输)
|
||||
* @private
|
||||
*/
|
||||
dataChannelLisioner() {
|
||||
if (!this.dataChannel) return;
|
||||
// 数据通道打开
|
||||
this.dataChannel.onopen = () => console.info("数据通道已就绪");
|
||||
|
||||
// 接收自定义消息(自动解析JSON)
|
||||
this.dataChannel.onmessage = (e) => {
|
||||
let data = e.data;
|
||||
try {
|
||||
data = JSON.parse(data);
|
||||
} catch (err) {}
|
||||
this.callbacks.onMessage(data);
|
||||
this.dataChannelSendMsg(data);
|
||||
};
|
||||
// 数据通道错误
|
||||
this.dataChannel.onerror = (error) => console.error("数据通道异常:", error);
|
||||
// 数据通道关闭
|
||||
this.dataChannel.onclose = () => console.info("数据通道关闭");
|
||||
}
|
||||
/**
|
||||
* 采集本地音视频流(一键调用)
|
||||
* @param {Object} constraints 媒体约束(默认开启音视频)
|
||||
* @returns {Promise<MediaStream>} 本地媒体流
|
||||
*/
|
||||
async captureLocalStream(constraints = { video: true, audio: true }) {
|
||||
try {
|
||||
// getUserMedia 设备硬件:摄像头(视频)、麦克风(音频)
|
||||
// getDisplayMedia 屏幕 / 窗口 / 标签页:显示器内容(视频),可选采集系统音频
|
||||
this.localStream =
|
||||
await navigator.mediaDevices.getDisplayMedia(constraints);
|
||||
// 绑定本地视频
|
||||
if (this.config.localVideo) {
|
||||
this.config.localVideo.srcObject = this.localStream;
|
||||
this.config.localVideo.muted = true; // 静音避免回声
|
||||
this.config.localVideo.play().catch(() => {});
|
||||
}
|
||||
// 将流添加到连接
|
||||
this.localStream.getTracks().forEach((track) => {
|
||||
this.peerConnection.addTrack(track, this.localStream);
|
||||
});
|
||||
return this.localStream;
|
||||
} catch (error) {
|
||||
console.error("采集本地流失败:", error);
|
||||
throw new Error(`媒体权限不足或设备不可用: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 外部传入本地媒体流(支持屏幕共享等自定义流)
|
||||
* @param {MediaStream} stream 本地媒体流
|
||||
*/
|
||||
setLocalStream(stream) {
|
||||
if (!stream) throw new Error("媒体流不能为空");
|
||||
|
||||
this.localStream = stream;
|
||||
// 绑定视频(可选)
|
||||
if (this.config.localVideo) {
|
||||
this.config.localVideo.srcObject = stream;
|
||||
this.config.localVideo.muted = true;
|
||||
this.config.localVideo.play().catch(() => {});
|
||||
}
|
||||
// 添加到连接
|
||||
// stream.getTracks().forEach(track => {
|
||||
// this.peerConnection.addTrack(track, stream);
|
||||
// });
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本地媒体流
|
||||
* @returns {MediaStream|null} 本地流
|
||||
*/
|
||||
getLocalStream() {
|
||||
return this.localStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取远端媒体流
|
||||
* @returns {MediaStream|null} 远端流
|
||||
*/
|
||||
getRemoteStream() {
|
||||
return this.remoteStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发起方:创建 Offer 并开启数据通道
|
||||
* @returns {Promise<RTCSessionDescription>} Offer 对象
|
||||
*/
|
||||
async createOffer() {
|
||||
// 重置数据通道
|
||||
if (this.dataChannel) {
|
||||
this.dataChannel.close();
|
||||
this.dataChannel = null;
|
||||
}
|
||||
// 创建数据通道(发起方主动创建)
|
||||
this.dataChannel = this.peerConnection.createDataChannel(
|
||||
this.config.dataChannelLabel,
|
||||
);
|
||||
// 监听数据通道
|
||||
this.dataChannelLisioner();
|
||||
|
||||
const offer = await this.peerConnection.createOffer();
|
||||
// 设置本地offer
|
||||
await this.peerConnection.setLocalDescription(offer);
|
||||
return offer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 接收方:处理远端 Offer 并创建 Answer
|
||||
* @param {RTCSessionDescription} offer 远端 Offer
|
||||
* @returns {Promise<RTCSessionDescription>} Answer 对象
|
||||
*/
|
||||
async handleRemoteOffer(offer) {
|
||||
await this.peerConnection.setRemoteDescription(
|
||||
new RTCSessionDescription(offer),
|
||||
);
|
||||
const answer = await this.peerConnection.createAnswer();
|
||||
await this.peerConnection.setLocalDescription(answer);
|
||||
return answer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发起方:处理远端 Answer
|
||||
* @param {RTCSessionDescription} answer 远端 Answer
|
||||
*/
|
||||
async handleAnswer(answer) {
|
||||
try {
|
||||
// 检查当前信令状态,仅在非 stable 时设置
|
||||
if (this.peerConnection.signalingState !== "stable") {
|
||||
await this.peerConnection.setRemoteDescription(
|
||||
new RTCSessionDescription(answer),
|
||||
);
|
||||
console.info("远端 Answer 设置成功");
|
||||
} else {
|
||||
console.warn("PeerConnection 已处于稳定状态,无需重复设置 Answer");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("设置远端 Answer 失败:", error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加远端 ICE 候选
|
||||
* @param {RTCIceCandidate} candidate ICE 候选对象
|
||||
*/
|
||||
async addIceCandidate(candidate) {
|
||||
if (!candidate) return;
|
||||
try {
|
||||
if (this.peerConnection && candidate) {
|
||||
await this.peerConnection.addIceCandidate(
|
||||
new RTCIceCandidate(candidate),
|
||||
);
|
||||
console.info("ICE 候选者添加成功", candidate);
|
||||
} else return;
|
||||
} catch (error) {
|
||||
console.info(
|
||||
"操作失败,需要先设置【远端的SDP】:步骤1:先设置远端 Offer(发起者的 SDP)步骤2:再添加 ICE 候选者(此时已有 remoteDescription)步骤3:创建并设置本地 Answer(依赖 remoteDescription)",
|
||||
);
|
||||
console.error(error);
|
||||
if (error.message.includes("Unknown ufrag")) {
|
||||
// ufrag 不匹配,说明是旧会话候选者,直接丢弃
|
||||
console.warn("ICE 候选者 ufrag 不匹配,丢弃:", candidate);
|
||||
} else {
|
||||
// 其他错误(如未设置 remoteDescription),缓存候选者
|
||||
console.info("缓存 ICE 候选者,待会话就绪后处理");
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 发送自定义数据(支持字符串/对象)
|
||||
* @param {string|Object} data 要发送的数据
|
||||
*/
|
||||
dataChannelSendMsg(data) {
|
||||
if (!this.dataChannel || this.dataChannel.readyState !== "open") {
|
||||
throw new Error("数据通道未连接,无法发送消息");
|
||||
}
|
||||
const sendData = typeof data === "object" ? JSON.stringify(data) : data;
|
||||
this.dataChannel.send(sendData);
|
||||
}
|
||||
/**
|
||||
* 关闭连接并清理所有资源
|
||||
*/
|
||||
close() {
|
||||
// 关闭数据通道
|
||||
if (this.dataChannel) {
|
||||
this.dataChannel.close();
|
||||
this.dataChannel = null;
|
||||
}
|
||||
|
||||
// 关闭 PeerConnection
|
||||
if (this.peerConnection) {
|
||||
this.peerConnection.close();
|
||||
this.peerConnection = null;
|
||||
}
|
||||
|
||||
// 停止媒体流
|
||||
if (this.localStream) {
|
||||
this.localStream.getTracks().forEach((track) => track.stop());
|
||||
this.localStream = null;
|
||||
}
|
||||
|
||||
// 清空视频
|
||||
if (this.config.localVideo) this.config.localVideo.srcObject = null;
|
||||
if (this.config.remoteVideo) this.config.remoteVideo.srcObject = null;
|
||||
|
||||
this.callbacks.onClose();
|
||||
console.log("WebRTC 连接已完全关闭");
|
||||
}
|
||||
/**
|
||||
* 同步暂停指定毫秒数(阻塞主线程) 延迟一段时间运行 await this.delay(100);
|
||||
* @param {number} ms 暂停毫秒数
|
||||
*/
|
||||
delayAsync(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
/**
|
||||
* 同步暂停指定毫秒数(阻塞主线程)
|
||||
* @param {number} ms 暂停毫秒数
|
||||
*/
|
||||
delaySync(ms) {
|
||||
const start = Date.now();
|
||||
// 循环等待,直到时间差达到指定毫秒数
|
||||
while (Date.now() - start < ms) {
|
||||
// 空循环,消耗时间
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 注册事件回调
|
||||
* @param {Object} handlers 回调函数集合
|
||||
* 示例:rtc.on({ onMessage: (data) => console.log(data) })
|
||||
*/
|
||||
on(handlers) {
|
||||
Object.keys(handlers).forEach((key) => {
|
||||
if (this.callbacks[key] && typeof handlers[key] === "function") {
|
||||
this.callbacks[key] = handlers[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 封装websocket
|
||||
export class webSocket_ModuleSimple {
|
||||
constructor(url, receiveMessageCallback = null) {
|
||||
this.url = url;
|
||||
this.socket = null;
|
||||
this.heartbeatInterval = 30000; // 心跳间隔 30s
|
||||
this.reconnectInterval = 10000; // 重连间隔 10s
|
||||
this.maxReconnectAttempts = 5;
|
||||
this.reconnectAttempts = 0;
|
||||
this.heartbeatTimer = null;
|
||||
this.stopWs = false;
|
||||
this.receiveMessageCallback = receiveMessageCallback; // 接收消息回调函数
|
||||
this.callbacks = {
|
||||
onMessage: (data) => {}, // 收到自定义消息
|
||||
};
|
||||
}
|
||||
connect() {
|
||||
if (this.socket && this.socket.readyState === WebSocket.OPEN) return;
|
||||
this.socket = new WebSocket(this.url);
|
||||
this.socket.onopen = () => {
|
||||
console.log("连接成功", this.url);
|
||||
this.reconnectAttempts = 0;
|
||||
this.startHeartbeat();
|
||||
};
|
||||
this.socket.onmessage = (event) => {
|
||||
// console.log('收到消息:', event.data);
|
||||
this.receiveMessage(event);
|
||||
this.startHeartbeat(); // 收到消息重置心跳
|
||||
};
|
||||
this.socket.onclose = () => {
|
||||
console.log("连接关闭", this.url);
|
||||
if (!this.stopWs) this.handleReconnect();
|
||||
};
|
||||
this.socket.onerror = () => {
|
||||
console.log("连接错误", this.url);
|
||||
this.closeHeartbeat();
|
||||
};
|
||||
}
|
||||
/**
|
||||
* 同步暂停指定毫秒数(阻塞主线程) 延迟一段时间运行 await this.delay(100);
|
||||
* @param {number} ms 暂停毫秒数
|
||||
*/
|
||||
delayAsync(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
/**
|
||||
* 同步暂停指定毫秒数(阻塞主线程)
|
||||
* @param {number} ms 暂停毫秒数
|
||||
*/
|
||||
delaySync(ms) {
|
||||
const start = Date.now();
|
||||
// 循环等待,直到时间差达到指定毫秒数
|
||||
while (Date.now() - start < ms) {
|
||||
// 空循环,消耗时间
|
||||
}
|
||||
}
|
||||
async send(message) {
|
||||
if (this.socket?.readyState === WebSocket.OPEN) {
|
||||
await this.delayAsync(500);
|
||||
this.socket.send(JSON.stringify(message));
|
||||
} else {
|
||||
console.error("WebSocket 未连接");
|
||||
}
|
||||
}
|
||||
startHeartbeat() {
|
||||
this.closeHeartbeat();
|
||||
this.heartbeatTimer = setInterval(() => {
|
||||
if (this.socket?.readyState === WebSocket.OPEN) {
|
||||
this.socket.send(JSON.stringify({ type: "heartBeat" }));
|
||||
// console.log('发送心跳包');
|
||||
}
|
||||
}, this.heartbeatInterval);
|
||||
}
|
||||
closeHeartbeat() {
|
||||
clearInterval(this.heartbeatTimer);
|
||||
}
|
||||
handleReconnect() {
|
||||
if (this.reconnectAttempts < this.maxReconnectAttempts) {
|
||||
setTimeout(() => {
|
||||
console.log(`尝试重连 (${++this.reconnectAttempts})`);
|
||||
this.connect();
|
||||
}, this.reconnectInterval);
|
||||
} else {
|
||||
console.warn("达到最大重连次数,停止重连");
|
||||
}
|
||||
}
|
||||
close() {
|
||||
this.stopWs = true;
|
||||
this.socket?.close();
|
||||
this.closeHeartbeat();
|
||||
}
|
||||
/**
|
||||
* 接收到消息
|
||||
*/
|
||||
receiveMessage(event) {
|
||||
// 根据业务自行处理
|
||||
// console.info('[webSocket_ModuleSimple]receiveMessage:', event.data)
|
||||
this.receiveMessageCallback && this.receiveMessageCallback(event.data);
|
||||
this.callbacks.onMessage(event.data);
|
||||
}
|
||||
/**
|
||||
* 注册事件回调
|
||||
* @param {Object} handlers 回调函数集合
|
||||
* 示例:rtc.on({ onMessage: (data) => console.log(data) })
|
||||
*/
|
||||
on(handlers) {
|
||||
Object.keys(handlers).forEach((key) => {
|
||||
if (this.callbacks[key] && typeof handlers[key] === "function") {
|
||||
this.callbacks[key] = handlers[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// ---------------------------------------------->
|
||||
// 验证与使用
|
||||
|
||||
// const receiveMessage = (res) => {
|
||||
// console.log('接收消息回调:', res)
|
||||
// }
|
||||
// const wsClient = new WebSocketClient('`ws://localhost:8000/ws/0/`', receiveMessage);
|
||||
// wsClient.connect();
|
||||
// 发送业务消息
|
||||
// wsClient.send({ type: 'message', data: 'Hello Server' });
|
||||
Reference in New Issue
Block a user