|
|
@@ -0,0 +1,236 @@
|
|
|
+class WsSocket {
|
|
|
+ /**
|
|
|
+ * Websocket 连接
|
|
|
+ *
|
|
|
+ * @var Websocket
|
|
|
+ */
|
|
|
+ connect = null
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 配置信息
|
|
|
+ *
|
|
|
+ * @var Object
|
|
|
+ */
|
|
|
+ config = {
|
|
|
+ heartbeat: {
|
|
|
+ setInterval: null,
|
|
|
+ pingInterval: 20000,
|
|
|
+ pingTimeout: 60000
|
|
|
+ },
|
|
|
+ reconnect: {
|
|
|
+ lockReconnect: false,
|
|
|
+ setTimeout: null, // 计时器对象
|
|
|
+ time: 5000, // 重连间隔时间
|
|
|
+ number: 1000 // 重连次数
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 最后心跳时间
|
|
|
+ lastTime = 0
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 自定义绑定消息事件
|
|
|
+ *
|
|
|
+ * @var Array
|
|
|
+ */
|
|
|
+ onCallBacks = []
|
|
|
+
|
|
|
+ defaultEvent = {
|
|
|
+ onError: evt => {},
|
|
|
+ onOpen: evt => {},
|
|
|
+ onClose: evt => {}
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建 WsSocket 的实例
|
|
|
+ *
|
|
|
+ * @param {Function} urlCallBack url闭包函数
|
|
|
+ * @param {Object} events 原生 WebSocket 绑定事件
|
|
|
+ */
|
|
|
+ constructor(urlCallBack, events) {
|
|
|
+ this.urlCallBack = urlCallBack
|
|
|
+
|
|
|
+ // 定义 WebSocket 原生方法
|
|
|
+ this.events = Object.assign({}, this.defaultEvent, events)
|
|
|
+
|
|
|
+ this.on('connect', data => {
|
|
|
+ this.config.heartbeat.pingInterval = data.ping_interval * 1000
|
|
|
+ this.config.heartbeat.pingTimeout = data.ping_timeout * 1000
|
|
|
+ this.heartbeat()
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 事件绑定
|
|
|
+ *
|
|
|
+ * @param {String} event 事件名
|
|
|
+ * @param {Function} callBack 回调方法
|
|
|
+ */
|
|
|
+ on(event, callBack) {
|
|
|
+ this.onCallBacks[event] = callBack
|
|
|
+ return this
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 加载 WebSocket
|
|
|
+ */
|
|
|
+ loadSocket() {
|
|
|
+ const url = this.urlCallBack()
|
|
|
+ const connect = new WebSocket(url)
|
|
|
+ connect.onerror = this.onError.bind(this)
|
|
|
+ connect.onopen = this.onOpen.bind(this)
|
|
|
+ connect.onmessage = this.onMessage.bind(this)
|
|
|
+ connect.onclose = this.onClose.bind(this)
|
|
|
+ this.connect = connect
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 连接 Websocket
|
|
|
+ */
|
|
|
+ connection() {
|
|
|
+ this.connect === null && this.loadSocket()
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 掉线重连 Websocket
|
|
|
+ */
|
|
|
+ reconnect() {
|
|
|
+ // 没连接上会一直重连,设置延迟避免请求过多
|
|
|
+ clearTimeout(this.config.reconnect.setTimeout)
|
|
|
+
|
|
|
+ this.config.reconnect.setTimeout = setTimeout(() => {
|
|
|
+ this.connection()
|
|
|
+
|
|
|
+ console.log(`网络连接已断开,正在尝试重新连接...`)
|
|
|
+ }, this.config.reconnect.time)
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解析接受的消息
|
|
|
+ *
|
|
|
+ * @param {Object} evt Websocket 消息
|
|
|
+ */
|
|
|
+ onParse(evt) {
|
|
|
+ const { event, payload } = JSON.parse(evt.data)
|
|
|
+
|
|
|
+ return {
|
|
|
+ event: event,
|
|
|
+ payload: payload,
|
|
|
+ orginData: evt.data
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 打开连接
|
|
|
+ *
|
|
|
+ * @param {Object} evt Websocket 消息
|
|
|
+ */
|
|
|
+ onOpen(evt) {
|
|
|
+ this.lastTime = new Date().getTime()
|
|
|
+
|
|
|
+ this.events.onOpen(evt)
|
|
|
+
|
|
|
+ this.ping()
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 关闭连接
|
|
|
+ *
|
|
|
+ * @param {Object} evt Websocket 消息
|
|
|
+ */
|
|
|
+ onClose(evt) {
|
|
|
+ this.events.onClose(evt)
|
|
|
+
|
|
|
+ this.connect.close()
|
|
|
+
|
|
|
+ this.connect = null
|
|
|
+
|
|
|
+ evt.code === 1006 && this.reconnect()
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 连接错误
|
|
|
+ *
|
|
|
+ * @param {Object} evt Websocket 消息
|
|
|
+ */
|
|
|
+ onError(evt) {
|
|
|
+ this.events.onError(evt)
|
|
|
+ this.connect.close()
|
|
|
+ this.connect = null
|
|
|
+ this.reconnect()
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 接收消息
|
|
|
+ *
|
|
|
+ * @param {Object} evt Websocket 消息
|
|
|
+ */
|
|
|
+ onMessage(evt) {
|
|
|
+ this.lastTime = new Date().getTime()
|
|
|
+ const payload = evt.data
|
|
|
+ console.log(payload)
|
|
|
+ const result = this.onParse(evt)
|
|
|
+
|
|
|
+ // 判断消息事件是否被绑定
|
|
|
+ // eslint-disable-next-line no-prototype-builtins
|
|
|
+ if (this.onCallBacks.hasOwnProperty(result.event)) {
|
|
|
+ this.onCallBacks[result.event](result.payload, result.orginData)
|
|
|
+ } else {
|
|
|
+ console.warn(`WsSocket 消息事件[${result.event}]未绑定...`)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * WebSocket 心跳检测
|
|
|
+ */
|
|
|
+ heartbeat() {
|
|
|
+ this.config.heartbeat.setInterval = setInterval(() => {
|
|
|
+ const t = new Date().getTime()
|
|
|
+
|
|
|
+ if (t - this.lastTime > this.config.heartbeat.pingTimeout) {
|
|
|
+ this.reconnect()
|
|
|
+ } else {
|
|
|
+ this.ping()
|
|
|
+ }
|
|
|
+ }, this.config.heartbeat.pingInterval)
|
|
|
+ }
|
|
|
+
|
|
|
+ ping() {
|
|
|
+ this.connect.send('{"event":"heartbeat","payload":"ping"}')
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 聊天发送数据
|
|
|
+ *
|
|
|
+ * @param {Object} mesage
|
|
|
+ */
|
|
|
+ send(mesage) {
|
|
|
+ this.connect.send(JSON.stringify(mesage))
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 关闭连接
|
|
|
+ */
|
|
|
+ close() {
|
|
|
+ this.connect.close()
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 推送消息
|
|
|
+ *
|
|
|
+ * @param {String} event 事件名
|
|
|
+ * @param {Object} data 数据
|
|
|
+ */
|
|
|
+ emit(event, data) {
|
|
|
+ const payload = JSON.stringify({ event, data })
|
|
|
+
|
|
|
+ if (this.connect && this.connect.readyState === 1) {
|
|
|
+ this.connect.send(payload)
|
|
|
+ } else {
|
|
|
+ alert('WebSocket 连接已关闭...')
|
|
|
+ console.error('WebSocket 连接已关闭...', this.connect)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+export default WsSocket
|