const {
|
invokeCallbackHandler: invoke
|
} = UniServiceJSBridge
|
const eventNames = ['open', 'close', 'error', 'message']
|
const callbacks = {}
|
const socketTasks = []
|
/**
|
* SocketTask
|
*/
|
class SocketTask {
|
/**
|
* WebSocket实例
|
*/
|
_webSocket
|
/**
|
* 构造函数
|
* @param {string} url
|
* @param {Array} protocols
|
*/
|
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 { data, code, reason } = event
|
const res = name === 'message'
|
? { data }
|
: name === 'close'
|
? { code, reason }
|
: {}
|
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)
|
}
|
}
|
})
|
})
|
const propertys = ['CLOSED', 'CLOSING', 'CONNECTING', 'OPEN', 'readyState']
|
propertys.forEach((property) => {
|
Object.defineProperty(this, property, {
|
get () {
|
return webSocket[property]
|
}
|
})
|
})
|
} catch (e) {
|
error = e
|
}
|
callback(error, this)
|
}
|
|
/**
|
* 发送
|
* @param {any} data
|
*/
|
send (options = {}) {
|
const data = options.data
|
const ws = this._webSocket
|
try {
|
if (ws.readyState !== ws.OPEN) {
|
throw new Error('SocketTask.readyState is not OPEN')
|
}
|
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
|
const arrgs = []
|
arrgs.push(options.code || 1000)
|
if (typeof options.reason === 'string') {
|
arrgs.push(options.reason)
|
}
|
try {
|
ws.close(...arrgs)
|
this._callback(options, 'closeSocket:ok')
|
} catch (error) {
|
this._callback(options, `closeSocket:fail ${error}`)
|
}
|
}
|
|
/**
|
* 通用回调处理
|
*/
|
_callback ({
|
success,
|
fail,
|
complete
|
}, errMsg) {
|
const data = {
|
errMsg
|
}
|
if (/:ok$/.test(errMsg)) {
|
if (typeof success === 'function') {
|
success(data)
|
}
|
} else {
|
if (typeof fail === 'function') {
|
fail(data)
|
}
|
}
|
if (typeof complete === 'function') {
|
complete(data)
|
}
|
}
|
}
|
eventNames.forEach(item => {
|
const name = item[0].toUpperCase() + item.substr(1)
|
SocketTask.prototype[`on${name}`] = function (callback) {
|
this._callbacks[item].push(callback)
|
}
|
})
|
/**
|
* 创建一个 WebSocket 连接
|
* @param {any} data 数据
|
* @return {SocketTask}
|
*/
|
export function connectSocket ({
|
url,
|
protocols
|
}, callbackId) {
|
return new SocketTask(url, protocols, (error, socketTask) => {
|
if (!error) {
|
socketTasks.push(socketTask)
|
}
|
invoke(callbackId, {
|
errMsg: 'connectSocket:' + (error ? `fail ${error}` : 'ok')
|
})
|
})
|
}
|
/**
|
* 通过 WebSocket 连接发送数据
|
* @param {any} options
|
* @param {string} callbackId
|
*/
|
export function sendSocketMessage (options, callbackId) {
|
const socketTask = socketTasks[0]
|
if (socketTask && socketTask.readyState === socketTask.OPEN) {
|
socketTask.send(Object.assign({}, options, {
|
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) {
|
const socketTask = socketTasks[0]
|
if (socketTask) {
|
socketTask.close(Object.assign({}, options, {
|
complete (res) {
|
invoke(callbackId, res)
|
}
|
}))
|
} else {
|
invoke(callbackId, {
|
errMsg: 'closeSocket:fail WebSocket is not connected'
|
})
|
}
|
}
|
/**
|
* 监听事件
|
* @param {string} method
|
*/
|
function on (method) {
|
return function (callbackId) {
|
callbacks[method] = callbackId
|
}
|
}
|
/**
|
* 监听WebSocket连接打开事件
|
* @param {Function} cb
|
*/
|
export const onSocketOpen = on('open')
|
/**
|
* 监听WebSocket错误
|
* @param {Function} cb
|
*/
|
export const onSocketError = on('error')
|
/**
|
* 监听WebSocket接受到服务器的消息事件
|
* @param {Function} cb
|
*/
|
export const onSocketMessage = on('message')
|
/**
|
* 监听WebSocket关闭
|
* @param {Function} callback
|
*/
|
export const onSocketClose = on('close')
|