/**
* WebSocket 通信模块
* @module $ui/utils/socket
*/
import Events from './events'
/**
* 验证参数是否合法
* @private
* @param {object} options
* @returns {boolean}
*/
function validateParam(options = {}) {
if (!window.WebSocket) {
throw new Error('浏览器不支持 WebSocket')
}
if (!options.server) {
throw new Error('缺少 server 参数')
}
return true
}
/**
* Socket 类
* @export
*
* @example
* const socket = new Socket({
* server: WEB_SOCKET_SOCKET
* })
* socket.$on('open', function () {
* socket.send('发送消息')
* })
* socket.$on('message', function (m) {
* console.log('收到信息:' + m)
* })
*
*/
export default class Socket extends Events {
/**
* 构造函数
* @constructor
* @param {object} options 实例化参数
* @param {string} options.server 服务器地址,如:ws://127.0.0.1:3000
* @param {boolean} [options.reconnect=true] 是否自动重连接
* @param {boolean} [options.reconnectDelay=3000] 重连接延时
*/
constructor(options = {}) {
super()
validateParam(options)
this.options = {
server: '',
reconnect: true,
reconnectDelay: 3000,
maxConnectTimes: 0,
...options
}
this.isConnected = false
this.ws = null
this.reconnectTimer = null
this.isReconnecting = false
this.connectTimes = 0
this.connect()
}
/**
* 建立连接
*/
connect() {
const o = this.options
this.ws = new WebSocket(o.server)
this.ws.onmessage = this.handleMessage.bind(this)
this.ws.onopen = this.handleOpen.bind(this)
this.ws.onclose = this.handleClose.bind(this)
this.ws.onerror = this.handleError.bind(this) // this.handleConnect.bind(this)
this.connectTimes += 1 // 连接次数+1
}
delayReconnect() {
if (this.options.maxConnectTimes > 0 && this.connectTimes >= this.options.maxConnectTimes) { // 超过最大重连次数
console.log('ws stop forever, please run ‘handleConnect’ to restart')
return
}
this.isConnected = false
this.isReconnecting = true
this.reconnectTimer = setTimeout(() => {
this.reconnect()
}, this.options.reconnectDelay)
}
handleOpen() {
this.isConnected = true
/**
* 连接建立成功触发
* @event open
*/
this.$emit('open', this)
}
handleClose() {
/**
* 连接关闭触发
* @event close
*/
this.$emit('close', this)
if (this.options.reconnect && !this.isReconnecting) {
this.delayReconnect()
}
}
handleError() {
/**
* 连接错误触发
* @event error
*/
this.$emit('error', this)
if (this.options.reconnect && !this.isReconnecting) {
this.delayReconnect()
}
}
handleConnect() {
this.connectTimes = 0
this.isConnected = false
this.reconnectTimer = setTimeout(() => {
this.reconnect()
}, this.options.reconnectDelay)
}
handleMessage(evt) {
let info = evt.data
if (info) {
const regex = /^\{[\W\w]*\}$/
info = regex.test(info) ? JSON.parse(info) : info;
}
/**
* 收到消息触发
* @event message
* @param {String|Object} info 消息
*/
this.$emit('message', info)
}
/**
* 重新连接
*/
reconnect() {
clearTimeout(this.reconnectTimer)
if (this.isConnected) return
this.isReconnecting = false
this.connect()
}
/**
* 发送信息
* @param {Object|String} message 消息内容
*/
send(message) {
const str = typeof message === 'object' ? JSON.stringify(message) : message
this.ws.send(str)
}
/**
* 获取WebSocket状态
* @returns {*}
*/
getState() {
// 0: 未连接,1:已连接,2:正在关闭,3:已关闭或连接打不开
return this.ws.readyState
}
/**
* 关闭连接
*/
close() {
this.ws.close()
}
/**
* 销毁
*/
destroy() {
this.close()
super.destroy()
this.ws.onmessage = null
this.ws.onopen = null
this.ws.onclose = null
this.ws.onerror = null
this.ws = null
}
}