websocket 语音推送及重连机制

2021-02-22  本文已影响0人  McDu
let audioMap = {
    test1: '//xxx.mp3',
    test2: '//xxx.mp3',
    test3: '//xxx.mp3',
    test4: '//xxx.mp3'
};

let audioArr = [];
let rePlay = false;


let ws;
let lockReconnect = false; // 避免重复连接
let wsUrl = window.location.href.replace(/^http(s?:\/\/(.*?))\/.*$/, 'ws$1/ws/voice/remind.json');

function createWebSocket(url) {
    try {
        ws = new WebSocket(url);
        initEventHandle();
    } catch (e) {
        reconnect(url);
    }
}

function initEventHandle() {
    ws.onclose = function() {
        reconnect(wsUrl);
    };
    ws.onerror = function() {
        reconnect(wsUrl);
    };
    ws.onopen = function() {
        ws.send('hello start!');
        // 心跳检测重置
        heartCheck.reset().start();
    };
    ws.onmessage = function(event) {
        // 如果获取到消息,心跳检测重置
        // 拿到任何消息都说明当前连接是正常的
        heartCheck.reset().start();

        let data = JSON.parse(event.data);
        audioArr.length == 0 && (rePlay = true);

        if (data && data.length) {
            let newData = data.map(function(item) {
                return {
                    url: audioMap[item.voice_key],
                    priority: item.priority
                };
            });

            audioArr = audioArr.concat(newData);
            audioArr.sort(function(a, b) {
                return a.priority - b.priority;
            });

            rePlay && firstRender();
        }
    };
}

function reconnect(url) {
    if (lockReconnect) return;
    lockReconnect = true;

    // 没连接上会一直重连,设置延迟避免请求过多
    setTimeout(function() {
        createWebSocket(url);
        lockReconnect = false;
    }, 60000);
}


// 心跳检测
let heartCheck = {
    timeout: Math.floor(Math.random() * (90000 - 30000) + 30000),
    timeoutObj: null,
    serverTimeoutObj: null,
    reset: function() {
        clearTimeout(this.timeoutObj);
        clearTimeout(this.serverTimeoutObj);
        return this;
    },
    start: function() {
        let self = this;
        this.timeoutObj = setTimeout(function() {
            // 发送一个心跳,后端收到后,返回一个心跳消息,onmessage拿到返回的心跳就说明连接正常
            ws.send('HeartBeat');

            // 如果超过一定时间还没重置,说明后端主动断开了
            self.serverTimeoutObj = setTimeout(function() {
                // 如果直接执行reconnect 会触发onclose导致重连两次
                ws.close();
            }, self.timeout);
        }, this.timeout);
    }
};

let firstRender = function() {
    let oldAudio = document.getElementsByTagName('audio');
    if (oldAudio.length) {
        document.body.removeChild(oldAudio[0]);
    }

    let audio = new Audio();
    let playEndedHandler = function() {
        if (!audioArr.length) {
            return;
        }
        audio.src = audioArr.length && audioArr.shift().url;
        audio.play();
    };

    audio.preload = true;
    audio.autoplay = false;
    audio.src = audioArr.length && audioArr.shift().url;
    audio.addEventListener('ended', playEndedHandler, false);
    document.body.appendChild(audio);

    audio.muted = true;
    try {
        let isplay = audio.play();
        if (isplay !== undefined) {
            isplay.then(function() {
                audio.muted = false;
                audio.pause();
                setTimeout(function() {
                    audio.play();
                }, 100);
            }).catch(function(e) {
                audioArr = [];
                console.log(e);
            });
        }
    } catch (e) {
        audioArr = [];
        console.log(e);
    }

    audio.loop = false;
    rePlay = false;
};

createWebSocket(wsUrl);

上一篇下一篇

猜你喜欢

热点阅读