Newer
Older
safe_production_front / public / DispatchLib / DispatchWsWorker.js
wangxitong on 16 Aug 41 KB first commit

//—————————————————————————————————————— parms ——————————————————————————————————————————

var DcInfo = {
    Account: "",
    ID: 0,
    Number: "",
    Name: "",
    ExtNumber: "",
    Password: "",
    ServerIP: "",
    ServerPort: 3002,
    Token: "",
    FleetID: 0,
    NginxIP: "",
    NginxPort: 1604,
    GisIP: "",
    GisPort: 8037,
    MsIP: "",
    FsIP: "",
    ManagePriv: 0,
    AddressBookFleetID: 0,
    Gb28181FleetID: 0,
    ServerTime: "",
    HeartbeatTime: 60,
};


//——————————————————————————————————————— MD5 ———————————————————————————————————————————
var hex_chr = "0123456789abcdef";
function rhex(num) {
    str = "";
    for (j = 0; j <= 3; j++)
        str += hex_chr.charAt((num >> (j * 8 + 4)) & 0x0F) +
            hex_chr.charAt((num >> (j * 8)) & 0x0F);
    return str;
}

function str2blks_MD5(str) {
    nblk = ((str.length + 8) >> 6) + 1;
    blks = new Array(nblk * 16);
    for (i = 0; i < nblk * 16; i++) blks[i] = 0;
    for (i = 0; i < str.length; i++)
        blks[i >> 2] |= str.charCodeAt(i) << ((i % 4) * 8);
    blks[i >> 2] |= 0x80 << ((i % 4) * 8);
    blks[nblk * 16 - 2] = str.length * 8;
    return blks;
}

function add4md5(x, y) {
    var lsw = (x & 0xFFFF) + (y & 0xFFFF);
    var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
    return (msw << 16) | (lsw & 0xFFFF);
}

function rol(num, cnt) {
    return (num << cnt) | (num >>> (32 - cnt));
}

function cmn(q, a, b, x, s, t) {
    return add4md5(rol(add4md5(add4md5(a, q), add4md5(x, t)), s), b);
}
function ff(a, b, c, d, x, s, t) {
    return cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function gg(a, b, c, d, x, s, t) {
    return cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function hh(a, b, c, d, x, s, t) {
    return cmn(b ^ c ^ d, a, b, x, s, t);
}
function ii(a, b, c, d, x, s, t) {
    return cmn(c ^ (b | (~d)), a, b, x, s, t);
}

function MD5(str) {
    x = str2blks_MD5(str);
    var a = 1732584193;
    var b = -271733879;
    var c = -1732584194;
    var d = 271733878;

    var x_length = x.length;
    for (var i = 0; i < x_length; i += 16) {
        var olda = a;
        var oldb = b;
        var oldc = c;
        var oldd = d;
        a = ff(a, b, c, d, x[i + 0], 7, -680876936);
        d = ff(d, a, b, c, x[i + 1], 12, -389564586);
        c = ff(c, d, a, b, x[i + 2], 17, 606105819);
        b = ff(b, c, d, a, x[i + 3], 22, -1044525330);
        a = ff(a, b, c, d, x[i + 4], 7, -176418897);
        d = ff(d, a, b, c, x[i + 5], 12, 1200080426);
        c = ff(c, d, a, b, x[i + 6], 17, -1473231341);
        b = ff(b, c, d, a, x[i + 7], 22, -45705983);
        a = ff(a, b, c, d, x[i + 8], 7, 1770035416);
        d = ff(d, a, b, c, x[i + 9], 12, -1958414417);
        c = ff(c, d, a, b, x[i + 10], 17, -42063);
        b = ff(b, c, d, a, x[i + 11], 22, -1990404162);
        a = ff(a, b, c, d, x[i + 12], 7, 1804603682);
        d = ff(d, a, b, c, x[i + 13], 12, -40341101);
        c = ff(c, d, a, b, x[i + 14], 17, -1502002290);
        b = ff(b, c, d, a, x[i + 15], 22, 1236535329);
        a = gg(a, b, c, d, x[i + 1], 5, -165796510);
        d = gg(d, a, b, c, x[i + 6], 9, -1069501632);
        c = gg(c, d, a, b, x[i + 11], 14, 643717713);
        b = gg(b, c, d, a, x[i + 0], 20, -373897302);
        a = gg(a, b, c, d, x[i + 5], 5, -701558691);
        d = gg(d, a, b, c, x[i + 10], 9, 38016083);
        c = gg(c, d, a, b, x[i + 15], 14, -660478335);
        b = gg(b, c, d, a, x[i + 4], 20, -405537848);
        a = gg(a, b, c, d, x[i + 9], 5, 568446438);
        d = gg(d, a, b, c, x[i + 14], 9, -1019803690);
        c = gg(c, d, a, b, x[i + 3], 14, -187363961);
        b = gg(b, c, d, a, x[i + 8], 20, 1163531501);
        a = gg(a, b, c, d, x[i + 13], 5, -1444681467);
        d = gg(d, a, b, c, x[i + 2], 9, -51403784);
        c = gg(c, d, a, b, x[i + 7], 14, 1735328473);
        b = gg(b, c, d, a, x[i + 12], 20, -1926607734);
        a = hh(a, b, c, d, x[i + 5], 4, -378558);
        d = hh(d, a, b, c, x[i + 8], 11, -2022574463);
        c = hh(c, d, a, b, x[i + 11], 16, 1839030562);
        b = hh(b, c, d, a, x[i + 14], 23, -35309556);
        a = hh(a, b, c, d, x[i + 1], 4, -1530992060);
        d = hh(d, a, b, c, x[i + 4], 11, 1272893353);
        c = hh(c, d, a, b, x[i + 7], 16, -155497632);
        b = hh(b, c, d, a, x[i + 10], 23, -1094730640);
        a = hh(a, b, c, d, x[i + 13], 4, 681279174);
        d = hh(d, a, b, c, x[i + 0], 11, -358537222);
        c = hh(c, d, a, b, x[i + 3], 16, -722521979);
        b = hh(b, c, d, a, x[i + 6], 23, 76029189);
        a = hh(a, b, c, d, x[i + 9], 4, -640364487);
        d = hh(d, a, b, c, x[i + 12], 11, -421815835);
        c = hh(c, d, a, b, x[i + 15], 16, 530742520);
        b = hh(b, c, d, a, x[i + 2], 23, -995338651);
        a = ii(a, b, c, d, x[i + 0], 6, -198630844);
        d = ii(d, a, b, c, x[i + 7], 10, 1126891415);
        c = ii(c, d, a, b, x[i + 14], 15, -1416354905);
        b = ii(b, c, d, a, x[i + 5], 21, -57434055);
        a = ii(a, b, c, d, x[i + 12], 6, 1700485571);
        d = ii(d, a, b, c, x[i + 3], 10, -1894986606);
        c = ii(c, d, a, b, x[i + 10], 15, -1051523);
        b = ii(b, c, d, a, x[i + 1], 21, -2054922799);
        a = ii(a, b, c, d, x[i + 8], 6, 1873313359);
        d = ii(d, a, b, c, x[i + 15], 10, -30611744);
        c = ii(c, d, a, b, x[i + 6], 15, -1560198380);
        b = ii(b, c, d, a, x[i + 13], 21, 1309151649);
        a = ii(a, b, c, d, x[i + 4], 6, -145523070);
        d = ii(d, a, b, c, x[i + 11], 10, -1120210379);
        c = ii(c, d, a, b, x[i + 2], 15, 718787259);
        b = ii(b, c, d, a, x[i + 9], 21, -343485551);
        a = add4md5(a, olda);
        b = add4md5(b, oldb);
        c = add4md5(c, oldc);
        d = add4md5(d, oldd);
    }
    return rhex(a) + rhex(b) + rhex(c) + rhex(d);
}

function Md5_Encrpt(pwd) {
    var hash1 = MD5(pwd);
    var hash2 = hash1 + Md5_Encrpt.seed;
    var hash = MD5(hash2);
    return hash;
}

Md5_Encrpt.seed = "urqBaQevSCFpjsMjD88eSDAZNvbY";

function guid() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        var r = Math.random() * 16 | 0,
            v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}

//———————————————————————————————————————— status ————————————————————————————————————————————

//登录状态
const LOGINSTATUS_NULL = 0;     //空闲
const LOGINSTATUS_LOGIN = 1;    //已登录
const LOGINSTATUS_RELOGIN = 2;  //重登中

var LoginStatus = LOGINSTATUS_NULL; //登录状态
var LastHeartbeatTime = 0;

//心跳定时器
function timer_heartbeat() { }
var timer_heartbeat_interval = null;
timer_heartbeat.start = function () {
    console.log("timer_heartbeat.start");
    if (timer_heartbeat_interval) {
        clearInterval(timer_heartbeat_interval);
        timer_heartbeat_interval = null;
    }
    timer_heartbeat_interval = setInterval(function () {
        if (Date.parse(new Date()) / 1000 - LastHeartbeatTime > DcInfo.HeartbeatTime * 5) {
            //心跳超时,开始重连
            if (websocket) {
                if (websocket.hasOpen) {
                    websocket.close();
                }
                websocket = null;
            }
            onDisconnectServer();

            return;
        }
        msg = new WsBaseMsg("Common_HeartBeat_Req", 999);
        msg.Set("nBattery", 0);
        msg.Set("nNetflow", 0);
        msg.Send();

    }, DcInfo.HeartbeatTime * 1000);
}
timer_heartbeat.stop = function () {
    console.log("timer_heartbeat.stop");
    if (timer_heartbeat_interval) {
        clearInterval(timer_heartbeat_interval);
        timer_heartbeat_interval = null;
    }
}

//重连定时器
function timer_reconnect() { }
var timer_reconnect_interval = null;
timer_reconnect.start = function () {
    console.log("timer_reconnect.start");
    if (timer_reconnect_interval) {
        clearInterval(timer_reconnect_interval);
        timer_reconnect_interval = null;
    }
    timer_reconnect_interval = setInterval(function () {
        if (websocket) {
            websocket_onopen();
        } else {
            newWebSocket();
        }
        
    }, 5000);
}
timer_reconnect.stop = function () {
    console.log("timer_reconnect.stop");
    if (timer_reconnect_interval) {
        clearInterval(timer_reconnect_interval);
        timer_reconnect_interval = null;
    }
}

//登录成功
onLoginSucess = function () {
    if (LoginStatus == LOGINSTATUS_NULL) {
        //首次登录成功
        //开启心跳定时器
        timer_heartbeat.start();

        var msgData = {
            Msg: "ServerLinkStatusNotify",
            Type: 1,
        };
        postMessage(msgData);

    } else if (LoginStatus == LOGINSTATUS_LOGIN) {

    } else if (LoginStatus == LOGINSTATUS_RELOGIN) {
        //重连后的业务
        //关闭重连定时器
        timer_reconnect.stop();

        //开启心跳定时器
        timer_heartbeat.start();

        var msgData = {
            Msg: "ServerLinkStatusNotify",
            Type: 1,
        };
        postMessage(msgData);

        PttOnline();
    }
    LoginStatus = LOGINSTATUS_LOGIN;
    LastHeartbeatTime = Date.parse(new Date()) / 1000;

    
}

//掉线
onDisconnectServer = function () {
    //关闭心跳定时器
    timer_heartbeat.stop();

    //开启重连定时器
    timer_reconnect.start();

    //上报掉线状态
    var msgData = {
        Msg: "ServerLinkStatusNotify",
        Type: 2,
    };
    postMessage(msgData);
    LastHeartbeatTime = 0;
    LoginStatus = LOGINSTATUS_RELOGIN;

    PttOffline();
    VideoOffline();
    VoipOffline();
}


//——————————————————————————————————————— webworker ——————————————————————————————————————————
//Msg:消息 parm:消息内容
webworker_onmessage = function (evt) {
    if (evt && evt.data && evt.data.Msg) {
        if (evt.data.Msg.indexOf("Audio") == 0) {
            onWebWorkerMessage_Poc(evt.data);
            return;
        }
        console.log("webworker_onmessage ", evt.data.Msg);

        if (evt.data.Msg.indexOf("Ptt") == 0) {
            onWebWorkerMessage_Poc(evt.data);
        } else if (evt.data.Msg.indexOf("MonitorVideo") == 0) {
            onWebWorkerMessage_Video(evt.data);
        } else if (evt.data.Msg.indexOf("Voip") == 0) {
            onWebWorkerMessage_Voip(evt.data);
        } else if (evt.data.Msg.indexOf("Sub") == 0) {
            onWebWorkerMessage_Sub(evt.data);
        } else if (evt.data.Msg.indexOf("Sys") == 0) {
            onWebWorkerMessage_Sys(evt.data);
        }  else {
            switch (evt.data.Msg) {
                case "Uninitialize":
                    Uninitialize(evt.data);
                    break
                case "LoginReq":
                    Login(evt.data);
                    break
                case "LogoutReq":
                    Logout(evt.data);
                    break
                case "LocSetParmReq":
                    LocSetParm(evt.data);
                    break
                case "MsgBroadcastReq":
                    MsgBroadcast(evt.data);
                    break
            }
        }
    }
}

CloseWorker = function () {
    var msgData = {
        WsMsg: "closed",
    };

    postMessage(msgData);

    self.close();
}

Uninitialize = function (parm) {
    //销毁资源
    if (websocket && websocket.hasOpen) {

        //Logout();
        websocket.close();
    }

    CloseWorker();
}

//登录
Login = function (parm) {

    DcInfo.Account = parm.Name;
    if (typeof parm.Password != 'undefined') {
        DcInfo.Password = Md5_Encrpt(parm.Password);
    }
    DcInfo.Token = parm.Token;
    DcInfo.ServerIP = parm.Server;
    DcInfo.ServerPort = parm.Port;

    if (websocket && websocket.hasOpen) {
        websocket_onopen();
    }
    else {
        newWebSocket();
    }
}

//注销
Logout = function (parm) {

    PttOffline();
    VideoOffline();
    VoipOffline();

    if (LoginStatus == LOGINSTATUS_LOGIN) {

        msg = new WsBaseMsg("Common_Logout_Req", 2);
        msg.Send();

        timer_heartbeat.stop();

        setTimeout(() => {
            if (websocket) {
                if (websocket.hasOpen) {
                    websocket.close();
                }
                websocket = null;
            }
        }, 3000);

    } else if (LoginStatus == LOGINSTATUS_RELOGIN) {
        timer_reconnect.stop();
    }
    LoginStatus = LOGINSTATUS_NULL;
}


var VoipCallID = 1100;
var SysThirdID = undefined;
/************************** 订阅 ******************************/

var SubOnlineIDList = new Map();
var SubOnlineNumList = new Map();
var SubVoipList = new Map();
var SubLocList = new Map();


setInterval(function () {
    var numlist = []

    for (let [number, id] of SubOnlineNumList) {
        numlist.push(number);
    }

    if (numlist.length) {
        msg = new WsBaseMsg("Sub_Online_Req", 410);
        msg.Set("nOperationType", 9);
        msg.Set("nRequsetID", 0);
        msg.Set("lUserIDList", []);
        msg.Set("lUserNumList", numlist);

        msg.Send();
    }

    numlist = []
    for (let [number, id] of SubVoipList) {
        numlist.push(number);
    }

    if (numlist.length) {
        msg = new WsBaseMsg("Sub_Voip_Req", 430);
        msg.Set("nOperationType", 9);
        msg.Set("nRequsetID", 0);
        msg.Set("lUserNumList", numlist);

        msg.Send();
    }

    numlist = []
    for (let [number, id] of SubLocList) {
        numlist.push(number);
    }

    if (numlist.length) {
        msg = new WsBaseMsg("Sub_Loc_Req", 420);
        msg.Set("nOperationType", 9);
        msg.Set("nRequsetID", 0);
        msg.Set("lUserNumList", numlist);

        msg.Send();
    }


}, 4*60*1000);


onWebWorkerMessage_Sub = function (parm) {
    switch (parm.Msg) {
        case "SubVoipStatusReq":
            SubVoipStatusReq(parm);
            break
        case "SubLocReq":
            SubLocReq(parm);
            break
        case "SubOnlineReq":
            SubOnlineReq(parm);
            break
    }
}

SubVoipStatusReq = function (parm) {
    if (parm.Type && parm.ExtNum) {

        var numlist = []

        if (parm.Type > 0) {
            //开始
            SubVoipList.set(parm.ExtNum, 1);
        } else {
            //停止
            SubVoipList.delete(parm.ExtNum);
        }
        numlist.push(parm.ExtNum);

        msg = new WsBaseMsg("Sub_Voip_Req", 430);
        msg.Set("nOperationType", parm.Type);
        msg.Set("nRequsetID", 0);
        msg.Set("lUserNumList", numlist);

        msg.Send();
    }
}

SubLocReq = function (parm) {
    if (parm.Type && parm.Number) {

        var numlist = []

        if (parm.Type > 0) {
            //开始
            SubLocList.set(parm.Number, 1);
        } else {
            //停止
            SubLocList.delete(parm.Number);
        }
        numlist.push(parm.Number);

        msg = new WsBaseMsg("Sub_Loc_Req", 420);
        msg.Set("nOperationType", parm.Type);
        msg.Set("nRequsetID", 0);
        msg.Set("lUserNumList", numlist);

        msg.Send();
    }
}


SubOnlineReq = function (parm) {
    var idlist = []
    var numlist = []

    if (parm.UserList && parm.UserList[0]) {
        for (var i = 0; i < parm.UserList.length; i++)
        {
            if (typeof parm.UserList[i].UserID == "number") {
                idlist.push(parm.UserList[i].UserID)
            } else if (typeof parm.UserList[i].UserNum == "string") {
                numlist.push(parm.UserList[i].UserNum)
            }
        }

        if (parm.Type > 0) {
            //开始
            for (var i = 0; i < idlist.length; i++)
            {
                SubOnlineIDList.set(idlist[i], '');
            }

            for (var i = 0; i < numlist.length; i++)
            {
                SubOnlineNumList.set(numlist[i], 0);
            }  

        } else {
            //停止
            for (var i = 0; i < idlist.length; i++)
            {
                var number = SubOnlineIDList.get(idlist[i]);
                if (typeof number != 'undefined') {
                    numlist.push(number);
                    SubOnlineNumList.delete(number);
                }

                SubOnlineIDList.delete(idlist[i]);
            }

            for (var i = 0; i < numlist.length; i++)
            {
                SubOnlineNumList.delete(numlist[i]);
            } 
        }

        msg = new WsBaseMsg("Sub_Online_Req", 410);
        msg.Set("nOperationType", parm.Type);
        msg.Set("nRequsetID", 0);
        msg.Set("lUserIDList", idlist);
        msg.Set("lUserNumList", numlist);

        msg.Send();
    }
}

onWsTextMessage_Sub = function (msg) {
    switch (msg.msg) {
        case "Sub_Online_Rsp":
            onWs_Sub_Online_Rsp(msg.data)
            break;
        case "Sub_Online_Notify":
            onWs_Sub_Online_Notify(msg.data)
            break;
        case "Sub_Loc_Rsp":
            onWs_Sub_Loc_Rsp(msg.data)
            break;
        case "Sub_Loc_Notify":
            onWs_Sub_Loc_Notify(msg.data)
            break;
        case "Sub_Voip_Rsp":
            onWs_Sub_Voip_Rsp(msg.data)
            break;
        case "Sub_Voip_Notify":
            onWs_Sub_Voip_Notify(msg.data)
            break;
    }
}

onWs_Sub_Online_Rsp = function (data) {
    if (data.nOperationType == 1) {
        var lUserNumList = data.lUserNumList;
        var lUserIDList = data.lUserIDList;
        for (var i = 0; i < lUserIDList.length; i++)
        {
            SubOnlineIDList.set(lUserIDList[i], lUserNumList[i]);
            SubOnlineNumList.set(lUserNumList[i], lUserIDList[i]);
        }
    }
}

onWs_Sub_Online_Notify = function (data) {
    var StatusList = [];
    var lUserNumList = data.lUserNumList;
    var lUserStatusList = data.lUserStatusList;
    for (var i = 0; i < lUserNumList.length; i++)
    {
        var id = SubOnlineNumList.get(lUserNumList[i]);
        if (typeof id != 'undefined') {
            StatusList.push({
                UserID: id,
                UserNum: lUserNumList[i],
                Status: lUserStatusList[i],
            })
        }
    }

    if (StatusList.length > 0) {
        var msgData = {
            Msg: "StatusNotify",
            StatusList: StatusList,
        };
        postMessage(msgData);
    }
}

onWs_Sub_Loc_Rsp = function (data) {

}

onWs_Sub_Loc_Notify = function (data) {

    var lUserNumList = data.lUserNumList;
    var lLongitudeTypeList = data.lLongitudeTypeList;
    var lLongitudeList = data.lLongitudeList;
    var lLatitudeTypeList = data.lLatitudeTypeList;
    var lLatitudeList = data.lLatitudeList;
    var lLocTimeList = data.lLocTimeList;
    var lLocSpeedList = data.lLocSpeedList;
    var lLocWayList = data.lLocWayList;
    var lDescriptionList = data.lDescriptionList;

    for (var i = 0; i < lUserNumList.length; i++)
    {
        var msgData = {
            Msg: "LocUpdateNotify",
            Number: lUserNumList[i],
            LongitudeType: lLongitudeTypeList[i],
            Longitude: lLongitudeList[i],
            LatitudeType: lLatitudeTypeList[i],
            Latitude: lLatitudeList[i],
            Time: lLocTimeList[i],
            Velocity: lLocSpeedList[i],
            Direction: lLocWayList[i],
            Radius: 50,
            Description: lDescriptionList[i],
        };
        postMessage(msgData);
    }
}

onWs_Sub_Voip_Rsp = function (data) {

}

onWs_Sub_Voip_Notify = function (data) {

    var lUserNumList = data.lUserNumList;
    var lUserStatusList = data.lUserStatusList;
    var lExtNumList = data.lExtNumList;
    var lUserNameList = data.lUserNameList;

    for (var i = 0; i < lUserNumList.length; i++)
    {
        var msgData = {
            Msg: "VoipDispatchMoniterStatusNotify",
            ExtNum: lUserNumList[i],
            Status: lUserStatusList[i],
            Remote: lExtNumList[i],
            RemoteName: lUserNameList[i],
        };
        postMessage(msgData);
    }

}



/************************** 通知 ******************************/
//终端定位参数设置
LocSetParm = function (Number, ID, Type, Interval) {
    if (typeof Number == "string" && typeof ID == "number" && typeof Type == "number" && typeof Interval ==
        "number") {
        // var msg = new Object;
        // parm.Msg = "LocSetParmReq";
        // parm.Number = Number;
        // parm.ID = ID;
        // parm.Type = Type;
        // parm.Interval = Interval;
        // websocket_send(msg);
        return 0;
    } else {
        return -1;
    }
}


//发送广播通知
MsgBroadcast = function (parm) {
    if (typeof parm.NoticeID == "number") {
        msg = new WsBaseMsg("Common_SendServerMsg_Req", 601);
        msg.Set("nOperationType", 31);
        msg.Set("nNoticeID", parm.NoticeID);
        msg.Set("cNotifyMsg", {});

        msg.Send();
        return 0;
    }
}

onWebWorkerMessage_Sys = function (parm) {
    switch (parm.Msg) {
        case "SysSetThirdID":
            SysSetThirdID(parm);
            break
    }
}

//设置业务ThirdID
SysSetThirdID = function (parm) {
    SysThirdID = parm.ThirdID;
}

//——————————————————————————————————————— weboscket ———————————————————————————————————————————
var websocket = null;


var msg_parm = [
    "",
    "nUserID",                 //	number	用户ID
    "cPassword",               //	string	密码
    "cUserName",               //	string	用户名
    "cUserNumber",             //	string	用户号码
    "cGroupNumber",            //	string	群组号码
    "cGroupName",              //	string	群组名称
    "lGroupIDList",            //	list:number	群组ID列表
    "lGroupNameList",          //	list:string	群组名称列表
    "nGroupID",                //	number	群组ID
    "nLocInterval",            //	number	定位间隔
    "nStartTime",              //	number	开始时间
    "nLongitudeType",          //	number	经度类型
    "nLongitude",              //	number	经度
    "nLatitude",               //	number	纬度类型
    "nLatitudeType",           //	number	纬度
    "nLocTime",                //	number	定位时间
    "nGroupCount",             //	number	群组数量
    "nSysConfig",              //	number	系统配置
    "nLocSwitch",              //	number	定位开关
    "nAudioTs",                //	number	语音时间戳
    "nRtpPort",                //	number	RTP端口号
    "nRtpActieTime",           //	number	RTP心跳间隔
    "nHeartbeatTime",          //	number	tcp心跳时间
    "nAudioFrameCount",        //	number	语音帧数/包
    "nAuthUserID",             //	number	话权占用者ID
    "nAudioBufferCount",       //	number	语音缓冲包数量
    "cIP",                     //	string	IP地址
    "nCallMode",               //	number	呼叫类型
    "nCallID",                 //	number	呼叫ID
    "nCalledUserID",           //	number	被叫用户ID
    "lUserNumList",            //	list:string	用户号码列表
    "lGroupNumList",           //	list:string	群组号码列表
    "nUserStatus",             //	number	用户状态
    "nCallingUserID",          //	number	主叫用户ID
    "nCalledGroupID",          //	number	被叫群组ID
    "nGroupHostType",          //	number	群组守候类型
    "nCallingUserType",        //	number	主叫类型
    "cCallingUserName",        //	string	主叫用户名称
    "cCalledUserName",         //	string	被叫用户名称
    "cCalledGroupName",        //	string	被叫群组名称
    "nCalledType",             //	number	被叫类型
    "nResult",                 //	number	结果值
    "nReportType",             //	number	上报类型
    "nLocStatus",              //	number	定位状态
    "nRequsetID",              //	number	请求ID
    "nLocRadius",              //	number	定位精度范围
    "nUdpPort",                //	number	udp端口
    "nLocTimeLength",          //	number	定位时长
    "nTempGroupID",            //	number	临时组呼ID
    "nPageIndex",              //	number	查询分页页码
    "nPageCount",              //	number	查询每页条目数
    "nTotalCount",             //	number	查询条目总数
    "nFleetID",                //	number	集团ID
    "nGroupPriorityList",      //	list:number	群组优先级列表
    "cUeModel",                //	string	终端型号
    "lUserNameList",           //	list:string	用户名称列表
    "lUserIDList",             //	list:number	用户ID列表
    "cUUID",                   //	string	UUID
    "lUserStatusList",         //	list:number	用户状态列表
    "",                        //	number	查询请求类型
    "nOperationType",          //	number	操作类型
    "nLocSpeed",               //	number	速度
    "nLocWay",                 //	number	方向
    "nDuration",               //	number	时长
    "nForceRelease",           //	number	话权是否强制释放
    "cNewPassword",            //	string	新密码
    "nServerPort",             //	number	服务器端口
    "nAudioBufferMinCount",    //	number	语音缓冲包最小数量
    "nAudioBufferMaxCount",    //	number	语音缓冲包最大数量
    "",                        //   废弃
    "lExtNumList",             //	list:string	分机号列表
    "cLocAddress",             //	string	位置描述
    "nLoginTime",              //	number	登录时间
    "cExtNum",                 //	string	分机号
    "nSystemType",             //	number	系统类型
    "nPrivilege",              //	number	权限
    "lGroupNumList",           //	list:string	群组号码列表
    "nPriority",               //	number	优先级
    "lSystemTypeList",         //	list:number	系统类型列表
    "nDispatchMode",           //	number	调度类型
    "cCallingUserNum",         //	string	主叫用户号码
    "cCalledUserNum",          //	string	被叫用户号码
    "cCalledGroupNum",         //	string	被叫群组号码
    "nNoticeID",               //	number	通知ID
    "cMEID",                   //	string	终端MEID
    "nGroupMemberCount",       //	number	群组成员数量
    "nGroupOnlineMemberCount", //	number	群组在线成员数量
    "nLocAutoLoc",             //	number	自动定位模式
    "nLocReportMode",          //	number	定位上报方式
    "nLocReportType",          //	number	定位上报类型
    "nLocInterval",            //	number	定位间隔
    "cDescription",            //	string	描述文字
    "nGroupAuthority",         //	number	管理权限
    "",                        //   废弃
    "cMsgIndex",               //	string	消息编号
    "nMsgType",                //	number	消息类型
    "cMsgContent",             //	string	消息内容
    "cMsgAttach",              //	string	消息附件
    "",                        //   废弃
    "nRetCode",                //	number	结果值
    "nSSRC",                   //	number	RTP包SSRC值
    "nAddressBookFleetID",     //	number	通讯录fleetID
    "cCallingNickname",        //	string	昵称
    "nServerID",               //	number	级联服务器ID
    "lServerIDList",           //	list:number	级联服务器ID列表
    "cNotifyMsg",              //	object	通知消息内容
    "nCallIdleTime",           //	number	呼叫释放时长
    "nVideoResolution",        //	number	视频分辨率
    "nVideoResolution",        //	number	终端摄像头
    "cICCID",                  //	number	终端ICCID
    "cToken",                  //	string	token
    "cNginxIP",                //	string	nginx IP
    "nNginxPort",              //	number	nginx端口
    "nGisPort",                //	number	定位上报端口
    "cMsIP",                   //	string	MsIP
    "cFsIP",                   //	string	FsIP
    "cServerTime",             //	string	服务器当前时间
    "nBattery",                //	number	终端电量
    "nNetflow",                //	number	终端流量
    "nClientType",             //	number	客户端类型
    "nReasonCode",             //	number	原因值
    "cReasonString",           //	string	原因描述
    "cServiceName",            //	string	业务名称
    "nServiceStatus",          //	number	业务状态
];

//等待消息应答map
WsMsgWaitRspList = new Map();

WsBaseMsg = function (msg, id) {
    this.msg = msg;
    this.id = id;
    this.user = DcInfo.Number;
    this.token = DcInfo.Token;
    this.data = {};

    this.onRspFail = function (reason) {
        //console.log("WsMsg ", msg, " onRspFail ", reason);
    }
}

WsBaseMsg.prototype.Set = function (name, value) {
    this.data[name] = value;
}

WsBaseMsg.prototype.Send = function (Rsponse) {
    var str = JSON.stringify(this);
    if (websocket && websocket.hasOpen) {
        websocket.send(str);
        console.log("websocket_send: " + str);

        if (Rsponse) {
            var self = this;
            this.timeout = setTimeout(() => {
                WsMsgWaitRspList.delete(Rsponse)
                self.onRspFail("timeout");
            }, 2000);

            var req = WsMsgWaitRspList.get(Rsponse);
            if (req) {
                clearTimeout(req.timeout)
                WsMsgWaitRspList.delete(Rsponse)
            }

            WsMsgWaitRspList.set(Rsponse, this)
            //console.log("startMsgTimeout " + this.msg + " " + this.timeout + " " + WsMsgWaitRspList.size);
        }
    }
    else {
        console.log("websocket_send fail: " + str);
        this.onRspFail("noconnect");
    }
}


//新建链接
newWebSocket = function () {


    var url = ""
    if (self.location.protocol == 'https:') {
        var port = DcInfo.ServerPort + 1;
        url = "wss://" + DcInfo.ServerIP + ":" + port + "/ws"
    } else {
        url = "ws://" + DcInfo.ServerIP + ":" + DcInfo.ServerPort + "/ws"
    }
    
    console.log("New WebSocket To ", url);
    try {
        websocket = new WebSocket(url);
        websocket.hasOpen = false;
        websocket.binaryType = 'arraybuffer';
        websocket.onopen = websocket_onopen;
        websocket.onclose = websocket_onclose;
        websocket.onmessage = websocket_onmessage;
        websocket.onerror = websocket_onerror;
    } catch (error) {
        console.error(error);
    }

}




websocket_send = function (msg) {
    var str = JSON.stringify(msg);

    if (websocket && websocket.hasOpen) {
        websocket.send(str);
        console.log("websocket_send: " + str);
    }
    else {
        console.log("websocket_send fail: " + str);
    }
}

websocket_onopen = function (evt) {
    websocket.hasOpen = true;
    msg = new WsBaseMsg("Common_Login_Req", 1);
    msg.onRspFail = function (reason) {
        var msgData = {
            Msg: "LoginRsp",
            Result: 5,
            LoginInfo: {},
        };

        if (reason == "timeout") {
            msgData.Result = 5;
        }
        else {
            msgData.Result = 4;
        }

        postMessage(msgData);
    }

    msg.Set("cUserNumber", DcInfo.Account);
    msg.Set("cToken", DcInfo.Token);
    msg.Set("cPassword", DcInfo.Password);
    msg.Set("cMEID", "");
    msg.Set("cICCID", "");
    msg.Set("cUeType", "");
    msg.Set("nClientType", 2);
    msg.Send("Common_Login_Rsp");
}

websocket_onclose = function (evt) {
    console.log("websocket_onclose", evt);
    if (websocket) {
        if (websocket.hasOpen && LoginStatus == LOGINSTATUS_LOGIN) {
            //断链,启动重连定时器
            onDisconnectServer();
        } else if (websocket.hasOpen && LoginStatus == LOGINSTATUS_NULL) {
            //链接失败
            var msgData = {
                Msg: "LoginRsp",
                Result: 5,
                LoginInfo: {},
            };
            postMessage(msgData);
        }
    }

    websocket = null;
}

websocket_onerror = function (evt) {
    console.log("websocket_onerror", evt);
}


websocket_onmessage = function (evt) {
    if (evt) {
        if (typeof (evt.data) == "string") {
            console.log("websocket_onmessage:" + evt.data);
            msg = JSON.parse(evt.data);
            onWsTextMessage(msg);
        }
        else if (evt.data instanceof ArrayBuffer) {
            //console.log("websocket_onmessage binary ", + evt.data.length);
            RecvBinaryData(evt.data);
        }
    }

}

//——————————————————————————————————————— weboscket 接收 ———————————————————————————————————————————
onWsTextMessage = function (msg) {
    //    this.msg = msg;
    //this.id = DcInfo.ID;
    //this.user = DcInfo.Number;
    //this.token = DcInfo.Token;
    //this.data = {};
    if (msg && msg.msg) {
        var req = WsMsgWaitRspList.get(msg.msg);
        if (req) {
            //清除应答超时
            //console.log("clearMsgTimeout " + req.msg + " " + req.timeout + " " + WsMsgWaitRspList.size);
            clearTimeout(req.timeout)
            WsMsgWaitRspList.delete(msg.msg)
        }

        if (msg.msg.indexOf("Poc_") == 0) {
            onWsTextMessage_Poc(msg);
        } else if (msg.msg.indexOf("Video_") == 0) {
            onWsTextMessage_Video(msg);
        } else if (msg.msg.indexOf("Voip_") == 0) {
            onWsTextMessage_Voip(msg);
        } else if (msg.msg.indexOf("Sub_") == 0) {
            onWsTextMessage_Sub(msg);
        } else {

            switch (msg.msg) {
                case "Common_Login_Rsp":
                    onWs_Common_Login_Rsp(msg.data)
                    break;
                case "Common_Logout_Rsp":
                    onWs_Common_Logout_Rsp(msg.data)
                    break;
                case "Common_HeartBeat_Notify":
                    onWs_Common_HeartBeat_Notify(msg.data)
                    break;
                case "Common_HeartBeat_Rsp":
                    onWs_Common_HeartBeat_Rsp(msg.data)
                    break;
                case "Common_KickOff_Notify":
                    onWs_Common_KickOff_Notify(msg.data)
                    break;
                case "Common_ServerMsg_Notify":
                    onWs_Common_ServerMsg_Notify(msg.data)
                    break;
                case "Common_ServerStatus_Notify":
                    onWs_Common_ServerStatus_Notify(msg.data)
                    break;
                case "Common_CallDc_Notify":
                    onWs_Common_CallDc_Notify(msg.data)
                    break;
                case "Common_Sos_Notify":
                    onWs_Common_Sos_Notify(msg.data)
                    break;
            }
        }

    }
}

//登录请求
onWs_Common_Login_Rsp = function (data) {
    if (data.nRetCode === 0) {
        //登录成功
        DcInfo.ID = data.nUserID;
        DcInfo.Name = data.cUserName;
        DcInfo.Number = data.cUserNumber;
        DcInfo.ExtNumber = data.cUserNumber;
        DcInfo.Token = data.cToken;
        DcInfo.Password = data.cPassword;
        DcInfo.FleetID = data.nFleetID;
        DcInfo.NginxIP = data.cNginxIP;
        DcInfo.NginxPort = data.nNginxPort;
        DcInfo.GisIP = data.cGisIP;
        DcInfo.GisPort = data.nGisPort;
        DcInfo.MsIP = data.cMsIP;
        DcInfo.FsIP = data.cFsIP;
        DcInfo.ManagePriv = data.nGroupAuthority;
        DcInfo.AddressBookFleetID = data.nAddressBookFleetID;
        DcInfo.Gb28181FleetID = data.nGb28181FleetID;
        DcInfo.ServerTime = data.cServerTime;
        DcInfo.HeartbeatTime = 45;

        if (LoginStatus == LOGINSTATUS_NULL) {

            var msgData = {
                Msg: "LoginRsp",
                Result: 0,
                LoginInfo: DcInfo,
            };

            msgData.LoginInfo.Longitude = "" + (data.nLongitude / 100000.0);
            msgData.LoginInfo.Latitude = "" + (data.nLatitude / 100000.0);
            msgData.LoginInfo.LocalVersion = "";
            msgData.LoginInfo.ServerVersion = "";
            msgData.LoginInfo.DownloadUrl = "";
            msgData.LoginInfo.ServerTime = data.cServerTime;


            postMessage(msgData);
        }
        onLoginSucess();

    } else {
        //登录失败
        if (data.nRetCode == undefined) {
            data.nRetCode = 1001;
        }

        var Result = 4;
        switch (data.nRetCode) {
            case 1:
                Result = 2;
                break;
            case 2:
                Result = 7;
                break;
            default:
                Result = 4;
                break;
        }

        var msgData = {
            Msg: "LoginRsp",
            Result: Result,
            LoginInfo: {},
        };

        postMessage(msgData);
    }
}

//注销应答
onWs_Common_Logout_Rsp = function (data) {

}

//反向心跳
onWs_Common_HeartBeat_Notify = function (data) {
    msg = new WsBaseMsg("Common_HeartBeat_Req", 999);
    msg.Set("nBattery", 0);
    msg.Set("nNetflow", 0);
    msg.Send();
}

//心跳应答
onWs_Common_HeartBeat_Rsp = function (data) {
    if (data.nRetCode === 0) {
        LastHeartbeatTime = Date.parse(new Date()) / 1000;
    } else {
        //心跳错误
        //重新登录
        Logout();
    }
}

//被踢下线
onWs_Common_KickOff_Notify = function (data) {
    timer_heartbeat.stop();
    LoginStatus = LOGINSTATUS_NULL;
    setTimeout(() => {
        if (websocket) {
            if (websocket.hasOpen) {
                websocket.close();
            }
            websocket = null;
        }
    }, 2000);

    var msgData = {
        Msg: "ServerLinkStatusNotify",
        Type: 9,
    };
    postMessage(msgData);
}

//服务器消息通知
onWs_Common_ServerMsg_Notify = function (data) {
    var type = data.nOperationType;
    if (type == 8) //电子围栏告警通知
    {
        var msgData = {
            Msg: "FenceNotify",
            AlarmID: data.cNotifyMsg.AlarmID,
            AlarmTime: data.cNotifyMsg.AlarmTime,
            AlarmType: data.cNotifyMsg.AlarmType,
            Number: data.cNotifyMsg.SubscriberID,
            RuleID: data.cNotifyMsg.RuleID,
            RegionID: data.cNotifyMsg.RegionID,
        };
        postMessage(msgData);
    } 
    else if (type == 9) //电子围栏告警处理通知
    {
        var msgData = {
            Msg: "FenceHandleNotify",
            AlarmID: data.cNotifyMsg.alarm_id,
            Handler: data.cNotifyMsg.User_id,
            HandleTime: (new Date()).toLocaleString(),
        };
        postMessage(msgData);
    }
    else
    {
        var msgData = {
            Msg: "ServerBroadcastNotify",
            UserID: data.nCallingUserID,
            UserNumber: data.cCallingUserNum,
            UserName: data.cCallingUserName,
            OperType: data.nOperationType,
            NoticeID: data.nNoticeID,
            GroupNum: "" + data.nNoticeID,
            Result: 0,
            Content: data.cNotifyMsg,
        };
        postMessage(msgData);
    }
}

//服务器状态通知
onWs_Common_ServerStatus_Notify = function (data) {
    var msgData = {
        Msg: "ServerLinkStatusNotify",
        Type: 0,
    };

    if (data.nServiceStatus === 1) {
        //业务恢复
        if (data.cServiceName == "Poc") {
            msgData.Type = 7;
            PttOnline();
        } else if (data.cServiceName == "Video") {
            msgData.Type = 3;
            VideoOnline();
        } else if (data.cServiceName == "Voip") {
            msgData.Type = 5;
            VoipOnline();
        }
    } else {
        //业务异常
        if (data.cServiceName == "Poc") {
            msgData.Type = 8;
            PttOffline();
        } else if (data.cServiceName == "Video") {
            msgData.Type = 4;
            VideoOffline();
        } else if (data.cServiceName == "Voip") {
            msgData.Type = 6;
            VoipOffline();
        }
    }

    if (msgData.Type) {
        postMessage(msgData);
    }

}

onWs_Common_CallDc_Notify = function (data) {
    //老接口兼容
    var msgData = {
        Msg: "ServerBroadcastNotify",
        UserID: data.nCallingUserID,
        UserNumber: data.cCallingUserNum,
        UserName: data.cCallingUserName,
        OperType: data.nOperationType,
        NoticeID: 0,
        GroupNum: "",
        Result: data.nCallMode,
        Content: {},
    };
    postMessage(msgData);
}

onWs_Common_Sos_Notify = function (data) {
    //老接口兼容
    var msgData = {
        Msg: "ServerBroadcastNotify",
        UserID: data.nCallingUserID,
        UserNumber: data.cCallingUserNum,
        UserName: data.cCallingUserName,
        OperType: 2,
        NoticeID: data.nNoticeID,
        GroupNum: data.CalledGroupNum,
        Result: data.nNoticeID,
        Content: {},
    };
    postMessage(msgData);
}

//——————————————————————————————————————— 初始化 ———————————————————————————————————————————
//msg:消息 parm:消息内容
webworker_init = function () {
    console.log("WsWorker Start");
    postMessage({
        WsMsg: "opened"
    });
    //self.addEventListener('message', webworker_onmessage, false);
    self.onmessage = webworker_onmessage;
}

webworker_init();

self.importScripts("DispatchWsWorkerPoc.js");
self.importScripts("DispatchWsWorkerVideo.js");
self.importScripts("DispatchWsWorkerVoip.js");