【前端】智能库房综合管理系统前端项目
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

235 lines
5.8 KiB

'use strict'
// import TS from '../demuxer/ts'
export default class WSSource {
timer = {
heartbeat: null,
streamInterrupt: null
}
reconnectInterval
shouldAttemptReconnect
progress = 0
reconnectTimeoutId = 0
reconnectCount = 0
callbacks = { connect: [], data: [] }
streaming = true
completed = false
established = false
isPaused = false
isStreamInterrupt = false
/** @type {TS} */
destination
/** @type {WebSocket} */
socket
/** @type {string} */
url
onEstablishedCallback
onCompletedCallback
onClosedCallback
onStreamInterruptCallback
onConnectedCallback
onStreamTimeoutFirstReceiveCallback
/**
*
* @param {string} url
* @param {import('../../types').PlayerOptions} options
*/
constructor(url, options) {
this.url = url
this.options = options
this.reconnectInterval =
options.reconnectInterval !== undefined ? options.reconnectInterval : 5
this.shouldAttemptReconnect = !!this.reconnectInterval
this.onEstablishedCallback = options.onSourceEstablished
this.onCompletedCallback = options.onSourceCompleted // Never used
this.onClosedCallback = options.onSourceClosed
this.onConnectedCallback = options.onSourceConnected
this.onStreamInterruptCallback = options.onSourceStreamInterrupt
this.onStreamContinueCallback = options.onSourceStreamContinue
}
connect(destination) {
this.destination = destination
}
changeUrl(url = '') {
clearTimeout(this.timer.streamInterrupt)
if (typeof url === 'string' && url !== '') {
if (this.url !== url) {
this.destroy()
this.url = url
this.start()
}
} else {
this.destroy()
this.url = ''
}
}
reload() {
this.destroy()
this.start()
}
destroy() {
clearTimeout(this.reconnectTimeoutId)
this.reconnectTimeoutId = 0
this.shouldAttemptReconnect = false
this.socket?.close()
if (this.socket) {
this.socket.onmessage = null
this.socket.onopen = null
this.socket.onerror = null
this.socket.onclose = null
this.socket.onmessage = null
this.socket = null
}
}
start() {
this.reconnectTimeoutId = 0
this.reconnectCount = 0
this.shouldAttemptReconnect = !!this.reconnectInterval
this.progress = 0
this.established = false
this.isPaused = false
this.wsConnect()
}
wsConnect() {
if (!this.url) return
// 连java的websocket时,第二个参数要么传值,要么不传值,不能传null,否则会一直出现连接失败的问题
try {
this.socket = new WebSocket(this.url, this.options?.protocols)
this.socket.binaryType = 'arraybuffer'
this.socket.onmessage = this.onMessage.bind(this)
this.socket.onopen = this.onOpen.bind(this)
this.socket.onerror = this.onError.bind(this)
this.socket.onclose = this.onClose.bind(this)
} catch (error) {
console.error('websocket connect error: ', error)
}
}
pause() {
if (!this.isPaused) {
clearTimeout(this.timer.streamInterrupt)
this.isPaused = true
if (this.socket?.readyState === WebSocket.OPEN) {
this.socket.onmessage = null
}
}
// if (this.reconnectTimeoutId) {
// clearTimeout(this.reconnectTimeoutId)
// this.reconnectTimeoutId = null
// }
}
continue() {
// Nothing to do here
if (this.isPaused) {
this.isPaused = false
if (this.socket == null) {
this.start()
} else if (this.socket?.readyState === WebSocket.OPEN) {
this.socket.onmessage = this.onMessage.bind(this)
this.startStreamTimeoutTimer()
}
}
}
onOpen() {
this.progress = 1
this.reconnectTimeoutId = 0
this.reconnectCount = 0
this.isOpened = true
if (this.onConnectedCallback) {
this.onConnectedCallback(this)
}
this.startStreamTimeoutTimer()
}
onError(err) {
console.error(err)
}
onClose() {
this.established = false
if (this.progress >= 1) {
// progress>=1,表示已经建立连接后的断开
this.progress = 0
if (this.onClosedCallback) {
this.onClosedCallback(this)
}
clearTimeout(this.reconnectTimeoutId)
this.reconnectTimeoutId = setTimeout(this.start.bind(this), 5000)
return
}
if (this.shouldAttemptReconnect && this.reconnectCount < 10) {
// 最多重连10次
clearTimeout(this.reconnectTimeoutId)
this.reconnectTimeoutId = setTimeout(
this.wsConnect.bind(this),
this.reconnectInterval * 1000
)
this.reconnectCount += 1
console.log('websocket 重连次数: ', this.reconnectCount)
}
}
/**
*
* @param {MessageEvent} ev
*/
onMessage(ev) {
this.startStreamTimeoutTimer()
try {
if (!this.established) {
this.established = true
this.isStreamInterrupt = false
this.onEstablishedCallback?.(this)
console.log(ev)
} else if (this.isStreamInterrupt) {
this.isStreamInterrupt = false
this.onStreamContinueCallback?.(this)
}
if (this.destination) {
this.destination.write(ev.data)
}
} catch (error) {
if (error.message?.indexOf('memory access out of bounds') > -1) {
this.reload()
} else {
console.error(error)
}
}
if (this.recorder) {
try {
this.recorder.write?.(ev.data)
} catch (error) {
this.recorder = null
}
}
}
startStreamTimeoutTimer() {
if (this.timer.streamInterrupt) {
clearTimeout(this.timer.streamInterrupt)
}
this.timer.streamInterrupt = setTimeout(() => {
console.warn('[JSMpeg]: 等待视频流超时')
this.timer.streamInterrupt = null
this.isStreamInterrupt = true
if (this.onStreamInterruptCallback) {
this.onStreamInterruptCallback()
}
}, 5000)
}
}