socket.js 4.9 KB
Newer Older
1 2 3 4 5 6
const {
  invokeCallbackHandler: invoke
} = UniServiceJSBridge
const eventNames = ['open', 'close', 'error', 'message']
const callbacks = {}
const socketTasks = []
fxy060608's avatar
fxy060608 已提交
7 8 9 10 11 12 13 14 15 16 17 18 19
/**
 * SocketTask
 */
class SocketTask {
  /**
   * WebSocket实例
   */
  _webSocket
  /**
   * 构造函数
   * @param {string} url
   * @param {Array} protocols
   */
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
  constructor (url, protocols, callback) {
    let error
    try {
      const webSocket = this._webSocket = new WebSocket(url, protocols)
      webSocket.binaryType = 'arraybuffer'
      this._callbacks = {}
      eventNames.forEach(name => {
        this._callbacks[name] = []
        webSocket.addEventListener(name, event => {
          const res = name === 'message' ? {
            data: event.data
          } : {}
          this._callbacks[name].forEach(callback => {
            try {
              callback(res)
            } catch (e) {
              console.error(`thirdScriptError\n${e};at socketTask.on${name[0].toUpperCase() + name.substr(1)} callback function\n`, e)
            }
          })
          if (this === socketTasks[0] && callbacks[name]) {
            invoke(callbacks[name], res)
          }
          if (name === 'error' || name === 'close') {
            const index = socketTasks.indexOf(this)
            if (index >= 0) {
              socketTasks.splice(index, 1)
            }
          }
        })
      })
      let propertys = ['CLOSED', 'CLOSING', 'CONNECTING', 'OPEN', 'readyState']
      propertys.forEach((property) => {
        Object.defineProperty(this, property, {
          get () {
            return webSocket[property]
          }
        })
      })
    } catch (e) {
      error = e
    }
    callback(error, this)
fxy060608's avatar
fxy060608 已提交
62 63 64 65 66 67
  }
  /**
   * 发送
   * @param {any} data
   */
  send (options = {}) {
68
    const data = options.data
fxy060608's avatar
fxy060608 已提交
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
    const ws = this._webSocket
    try {
      ws.send(data)
      this._callback(options, 'sendSocketMessage:ok')
    } catch (error) {
      this._callback(options, `sendSocketMessage:fail ${error}`)
    }
  }
  /**
   * 关闭
   * @param {number} code
   * @param {string} reason
   */
  close (options = {}) {
    const ws = this._webSocket
84 85 86 87 88
    const arrgs = []
    arrgs.push(options.code || 1000)
    if (typeof options.reason === 'string') {
      arrgs.push(options.reason)
    }
fxy060608's avatar
fxy060608 已提交
89
    try {
90
      ws.close(...arrgs)
fxy060608's avatar
fxy060608 已提交
91 92 93 94 95 96 97 98 99 100 101 102 103
      this._callback(options, 'sendSocketMessage:ok')
    } catch (error) {
      this._callback(options, `sendSocketMessage:fail ${error}`)
    }
  }
  /**
   * 通用回调处理
   */
  _callback ({
    success,
    fail,
    complete
  }, errMsg) {
104
    const data = {
fxy060608's avatar
fxy060608 已提交
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
      errMsg
    }
    if (/:ok$/.test(errMsg)) {
      if (typeof success === 'function') {
        success(data)
      }
    } else {
      if (typeof fail === 'function') {
        fail(data)
      }
    }
    if (typeof complete === 'function') {
      complete(data)
    }
  }
}
121 122 123 124 125 126
eventNames.forEach(item => {
  const name = item[0].toUpperCase() + item.substr(1)
  SocketTask.prototype[`on${name}`] = function (callback) {
    this._callbacks[item].push(callback)
  }
})
fxy060608's avatar
fxy060608 已提交
127 128 129 130 131 132 133 134 135
/**
 * 创建一个 WebSocket 连接
 * @param {any} data 数据
 * @return {SocketTask}
 */
export function connectSocket ({
  url,
  protocols
}, callbackId) {
136 137 138 139
  return new SocketTask(url, protocols, (error, socketTask) => {
    if (!error) {
      socketTasks.push(socketTask)
    }
fxy060608's avatar
fxy060608 已提交
140
    invoke(callbackId, {
141
      errMsg: 'connectSocket:' + (error ? `fail ${error}` : 'ok')
fxy060608's avatar
fxy060608 已提交
142
    })
143
  })
fxy060608's avatar
fxy060608 已提交
144 145 146 147 148 149 150
}
/**
 * 通过 WebSocket 连接发送数据
 * @param {any} options
 * @param {string} callbackId
 */
export function sendSocketMessage (options, callbackId) {
151 152 153
  const socketTask = socketTasks[0]
  if (socketTask && socketTask.readyState === socketTask.OPEN) {
    socketTask.send(Object.assign({}, options, {
fxy060608's avatar
fxy060608 已提交
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
      complete (res) {
        invoke(callbackId, res)
      }
    }))
  } else {
    invoke(callbackId, {
      errMsg: 'sendSocketMessage:fail WebSocket is not connected '
    })
  }
}
/**
 * 关闭WebSocket连接
 * @param {any} options
 * @param {string} callbackId
 */
export function closeSocket (options, callbackId) {
170 171 172
  const socketTask = socketTasks[0]
  if (socketTask) {
    socketTask.close(Object.assign({}, options, {
fxy060608's avatar
fxy060608 已提交
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
      complete (res) {
        invoke(callbackId, res)
      }
    }))
  } else {
    invoke(callbackId, {
      errMsg: 'closeSocket:fail WebSocket is not connected'
    })
  }
}
/**
 * 监听事件
 * @param {string} method
 */
function on (method) {
188
  return function (callbackId) {
189
    callbacks[method] = callbackId
fxy060608's avatar
fxy060608 已提交
190 191 192 193 194 195
  }
}
/**
 * 监听WebSocket连接打开事件
 * @param {Function} cb
 */
196
export const onSocketOpen = on('open')
fxy060608's avatar
fxy060608 已提交
197 198 199 200
/**
 * 监听WebSocket错误
 * @param {Function} cb
 */
201
export const onSocketError = on('error')
fxy060608's avatar
fxy060608 已提交
202 203 204 205
/**
 * 监听WebSocket接受到服务器的消息事件
 * @param {Function} cb
 */
206
export const onSocketMessage = on('message')
fxy060608's avatar
fxy060608 已提交
207 208 209 210
/**
 * 监听WebSocket关闭
 * @param {Function} callback
 */
211
export const onSocketClose = on('close')