import { getAssets } from '@/api/asset' import store from '@/store' import { State, AssetType } from '@/constant' import { createClient, decodePayload, sm4 } from '@/utils/mqtt' const NAMESPACE = 'asset' export const Topic = { PRELOAD: 'preload', DEL: 'delete', PULL: 'pull', PLAY: 'play', STOP: 'stop', DOWNLOAD: 'download' } export const MediaType = { IMAGE: 1, VIDEO: 2, WEB: 3 } export const MediaStatus = { ERROR: -1, WAITING: 0, LOADING: 1, LOADED: 2 } export function takeOver (device, { onMessage, onCreated, onClose, debug }) { const { id, productId } = device debug('正在连接...') let force = false const prefix = `${productId}/${id}/${NAMESPACE}` let client = createClient({ clientId: `${store.getters.account}_takeover_${id}`, reconnectPeriod: 0, will: { topic: `${prefix}/${Topic.STOP}`, payload: createPayload(createMessageId()), qos: 2, retain: false } }) const messageMap = new Map() const onMqttMessage = (event, paylaod) => { const needMessageId = event !== Topic.DOWNLOAD const messageId = paylaod.messageId if (needMessageId && !messageMap.has(messageId)) { return } console.log('Take Over MQTT', event, paylaod) const requestPayload = needMessageId ? messageMap.get(messageId) : null needMessageId && messageMap.delete(messageId) switch (event) { case Topic.PRELOAD: debug('预加载资源接收成功') break case Topic.DEL: debug('删除资源成功') break case Topic.PULL: debug('资源拉取成功') break case Topic.PLAY: debug(`播放${requestPayload.asset.name}成功`) break case Topic.STOP: debug('结束') break case Topic.DOWNLOAD: if (!paylaod.complete) { return } debug('有资源状态更新') break default: return } onMessage(event, paylaod, requestPayload) } const mock = { do (event, messageId, payload) { this[event](messageId, payload) }, preload (messageId, payload) { onMqttMessage(Topic.PRELOAD, { messageId }) setTimeout(() => { payload.assets.forEach(asset => { if (asset.type !== MediaType.WEB) { onMqttMessage(Topic.DOWNLOAD, { messageId: createMessageId, asset, complete: true, success: [true, false][Math.random() * 2 | 0] }) } }) }, 2000) }, delete (messageId) { onMqttMessage(Topic.DEL, { messageId, failures: [] }) }, pull (messageId) { getAssets({ pageNum: 1, pageSize: 10, type: [AssetType.IMAGE, AssetType.VIDEO][Math.random() * 2 | 0], status: State.RESOLVED }).then(({ data }) => { onMqttMessage(Topic.PULL, { messageId, assets: data.map(({ type, originalName, keyName, size, md5 }) => { return { type, name: originalName, keyName, size, md5, status: [MediaStatus.ERROR, MediaStatus.LOADING, MediaStatus.LOADED, MediaStatus.WAITING][Math.random() * 3 | 0] } }) }, true, true) }) }, play (messageId) { onMqttMessage(Topic.PLAY, { messageId }) }, stop (messageId) { onMqttMessage(Topic.STOP, { messageId }) } } const send = (event, paylaod) => { const messageId = createMessageId() messageMap.set(messageId, paylaod) if (__DEV__) { mock.do(event, messageId, paylaod) } else { client.publish(`${prefix}/${event}`, createPayload(messageId, paylaod)) } } client.on('error', e => { console.log('Take Over MQTT error: ', e) }) client.on('connect', () => { console.log('Take Over MQTT connected') debug('连接成功') client.subscribe(`${prefix}/+/#`) onCreated(createProxy(device, send, () => { force = true client.end(true) }, debug)) }) client.on('close', () => { console.log('Take Over MQTT closed') if (!force) { debug('连接发生异常,已断开') client.end(true) } }) client.on('end', () => { console.log('Take Over MQTT end') client = null messageMap.clear() force && debug('连接已断开') onClose() }) client.on('message', (topic, payload) => { const result = /^\d+\/\d+\/asset\/(.+)\/reply$/.exec(topic) if (result) { onMqttMessage(result[1], JSON.parse(decodePayload(null, payload))) } }) return client } function createMessageId () { return `${store.getters.account}_${Math.random().toString(16).slice(2)}` } function createPayload (messageId, payload) { return sm4.encrypt(JSON.stringify({ messageId, timestamp: `${Date.now()}`, ...payload })) } function createProxy (device, send, close, debug) { const { wide, high } = device return { close, send, preload (assets) { debug('预加载资源...') send(Topic.PRELOAD, { assets }) }, del (assets) { debug('删除资源...') send(Topic.DEL, { assets }) }, pull () { debug('资源拉取...') send(Topic.PULL) }, play (asset, rect) { debug(`播放${asset.name}...`) send(Topic.PLAY, { asset, top: 0, left: 0, width: wide, height: high, ...rect }) }, stop () { debug('结束播放...') send(Topic.STOP) } } }