|
|
@@ -59,6 +59,83 @@ function ccPhoneBarSocket() {
|
|
|
var ws = null;
|
|
|
var wsuri = null;
|
|
|
var isConnected = false;
|
|
|
+ var wsDebug = {
|
|
|
+ connectId: 0,
|
|
|
+ connectedAt: null,
|
|
|
+ lastOpenAt: null,
|
|
|
+ lastCloseAt: null,
|
|
|
+ lastErrorAt: null,
|
|
|
+ lastSendAt: null,
|
|
|
+ lastSendAction: null,
|
|
|
+ lastRecvAt: null,
|
|
|
+ lastRecvStatus: null,
|
|
|
+ closeCode: null,
|
|
|
+ closeReason: null,
|
|
|
+ closeWasClean: null,
|
|
|
+ recentEvents: []
|
|
|
+ };
|
|
|
+
|
|
|
+ function maskWsUrl(url) {
|
|
|
+ if (!url) {
|
|
|
+ return url;
|
|
|
+ }
|
|
|
+ return url.replace(/loginToken=[^&]+/, 'loginToken=***');
|
|
|
+ }
|
|
|
+
|
|
|
+ function getReadyStateLabel(state) {
|
|
|
+ var map = {0: 'CONNECTING', 1: 'OPEN', 2: 'CLOSING', 3: 'CLOSED'};
|
|
|
+ return map[state] !== undefined ? map[state] : String(state);
|
|
|
+ }
|
|
|
+
|
|
|
+ function pushWsEvent(type, detail) {
|
|
|
+ wsDebug.recentEvents.push({
|
|
|
+ t: new Date().toISOString(),
|
|
|
+ type: type,
|
|
|
+ detail: detail || {}
|
|
|
+ });
|
|
|
+ if (wsDebug.recentEvents.length > 40) {
|
|
|
+ wsDebug.recentEvents.shift();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function logIpccWs(level, tag, payload) {
|
|
|
+ var prefix = '[IPCC-WS][' + tag + ']';
|
|
|
+ if (level === 'error') {
|
|
|
+ console.error(prefix, payload);
|
|
|
+ } else if (level === 'warn') {
|
|
|
+ console.warn(prefix, payload);
|
|
|
+ } else {
|
|
|
+ console.log(prefix, payload);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ this.getWsDebugSnapshot = function() {
|
|
|
+ var uptimeMs = wsDebug.connectedAt ? (Date.now() - wsDebug.connectedAt) : null;
|
|
|
+ return {
|
|
|
+ connectId: wsDebug.connectId,
|
|
|
+ wsUrl: maskWsUrl(wsuri),
|
|
|
+ connectedAt: wsDebug.connectedAt,
|
|
|
+ uptimeMs: uptimeMs,
|
|
|
+ lastOpenAt: wsDebug.lastOpenAt,
|
|
|
+ lastCloseAt: wsDebug.lastCloseAt,
|
|
|
+ lastErrorAt: wsDebug.lastErrorAt,
|
|
|
+ lastSendAt: wsDebug.lastSendAt,
|
|
|
+ lastSendAction: wsDebug.lastSendAction,
|
|
|
+ lastRecvAt: wsDebug.lastRecvAt,
|
|
|
+ lastRecvStatus: wsDebug.lastRecvStatus,
|
|
|
+ closeCode: wsDebug.closeCode,
|
|
|
+ closeReason: wsDebug.closeReason,
|
|
|
+ closeWasClean: wsDebug.closeWasClean,
|
|
|
+ isConnected: isConnected,
|
|
|
+ isCalling: _cc.isCalling,
|
|
|
+ callConnected: callConnected,
|
|
|
+ readyState: ws ? ws.readyState : null,
|
|
|
+ readyStateLabel: ws ? getReadyStateLabel(ws.readyState) : 'NO_WS',
|
|
|
+ extnum: _cc.callConfig.extnum,
|
|
|
+ opnum: _cc.callConfig.opnum,
|
|
|
+ recentEvents: wsDebug.recentEvents.slice()
|
|
|
+ };
|
|
|
+ };
|
|
|
/* 通话已建立 */
|
|
|
var callConnected = false;
|
|
|
/*
|
|
|
@@ -189,14 +266,29 @@ function ccPhoneBarSocket() {
|
|
|
this.setHeartbeat = function()
|
|
|
{
|
|
|
setInterval(function(){
|
|
|
- //如果启用了心跳,而且用户已经登录上线,则发送心跳数据
|
|
|
- if(_cc.callConfig.enableHeartBeat && _cc.getIsConnected()){
|
|
|
- console.debug("try to send heartbeat.");
|
|
|
- var heartBeat = {};
|
|
|
- heartBeat.action="setHearBeat";
|
|
|
- heartBeat.body = "{}";
|
|
|
- _cc.sendMsg(heartBeat);
|
|
|
+ if (!_cc.callConfig.enableHeartBeat) {
|
|
|
+ return;
|
|
|
}
|
|
|
+ var readyState = ws ? ws.readyState : null;
|
|
|
+ if (!_cc.getIsConnected()) {
|
|
|
+ logIpccWs('warn', 'heartbeat-skip', {
|
|
|
+ reason: 'not_connected',
|
|
|
+ readyState: readyState,
|
|
|
+ readyStateLabel: getReadyStateLabel(readyState)
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ logIpccWs('log', 'heartbeat-send', {
|
|
|
+ intervalSecs: _cc.callConfig.heartBeatIntervalSecs,
|
|
|
+ readyState: readyState,
|
|
|
+ readyStateLabel: getReadyStateLabel(readyState),
|
|
|
+ isCalling: _cc.isCalling,
|
|
|
+ callConnected: callConnected
|
|
|
+ });
|
|
|
+ var heartBeat = {};
|
|
|
+ heartBeat.action="setHearBeat";
|
|
|
+ heartBeat.body = "{}";
|
|
|
+ _cc.sendMsg(heartBeat, 'heartbeat');
|
|
|
}, _cc.callConfig.heartBeatIntervalSecs * 1000);
|
|
|
};
|
|
|
|
|
|
@@ -262,10 +354,19 @@ function ccPhoneBarSocket() {
|
|
|
};
|
|
|
|
|
|
//断开到呼叫控制服务器的连接
|
|
|
- this.disconnect = function(){
|
|
|
+ this.disconnect = function(reason){
|
|
|
+ pushWsEvent('disconnect_client', {
|
|
|
+ reason: reason || 'manual',
|
|
|
+ readyState: ws ? ws.readyState : null,
|
|
|
+ snapshot: _cc.getWsDebugSnapshot()
|
|
|
+ });
|
|
|
+ logIpccWs('warn', 'disconnect', {
|
|
|
+ reason: reason || 'manual',
|
|
|
+ snapshot: _cc.getWsDebugSnapshot()
|
|
|
+ });
|
|
|
// 检查 WebSocket 是否存在且连接正常
|
|
|
if (!ws || ws.readyState !== WebSocket.OPEN) {
|
|
|
- console.log('WebSocket 未连接或已关闭,无需发送断开指令');
|
|
|
+ logIpccWs('log', 'disconnect-skip', 'WebSocket 未连接或已关闭,无需发送断开指令');
|
|
|
return;
|
|
|
}
|
|
|
var cmdInfo = {};
|
|
|
@@ -273,7 +374,7 @@ function ccPhoneBarSocket() {
|
|
|
cmdInfo.body = {"cmd" : "disconnect", "args" : { "msg" : "disconnection opt triggered by js client." } };
|
|
|
ws.send(JSON.stringify(cmdInfo));
|
|
|
// 立即关闭 WebSocket 连接
|
|
|
- ws.close();
|
|
|
+ ws.close(1000, 'client disconnect');
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
@@ -352,33 +453,95 @@ function ccPhoneBarSocket() {
|
|
|
this.connect = function() {
|
|
|
// 如果已经在连接中,直接返回
|
|
|
if (ws && ws.readyState === WebSocket.CONNECTING) {
|
|
|
- console.log('[connect] WebSocket 正在连接中,请勿重复操作');
|
|
|
+ logIpccWs('warn', 'connect-skip', 'WebSocket 正在连接中,请勿重复操作');
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 先关闭旧的连接,避免重复登录
|
|
|
if (ws) {
|
|
|
- console.log('[connect] 检测到旧连接存在,先关闭旧连接');
|
|
|
+ logIpccWs('warn', 'connect-replace', {
|
|
|
+ oldReadyState: ws.readyState,
|
|
|
+ oldReadyStateLabel: getReadyStateLabel(ws.readyState)
|
|
|
+ });
|
|
|
try {
|
|
|
- ws.close();
|
|
|
+ ws.close(1000, 'reconnect');
|
|
|
} catch(e) {
|
|
|
- console.error('[connect] 关闭旧连接失败:', e);
|
|
|
+ logIpccWs('error', 'connect-close-old-failed', e);
|
|
|
}
|
|
|
ws = null;
|
|
|
}
|
|
|
|
|
|
- if ('WebSocket' in window)
|
|
|
- ws = new WebSocket(wsuri);
|
|
|
- else {
|
|
|
- console.log('您的浏览器不支持 websocket,您无法使用本页面的功能!');
|
|
|
+ if (!('WebSocket' in window)) {
|
|
|
+ logIpccWs('error', 'connect-unsupported', '浏览器不支持 WebSocket');
|
|
|
return;
|
|
|
}
|
|
|
+
|
|
|
+ wsDebug.connectId += 1;
|
|
|
+ pushWsEvent('connect_start', {
|
|
|
+ connectId: wsDebug.connectId,
|
|
|
+ wsUrl: maskWsUrl(wsuri)
|
|
|
+ });
|
|
|
+ logIpccWs('log', 'connect-start', {
|
|
|
+ connectId: wsDebug.connectId,
|
|
|
+ wsUrl: maskWsUrl(wsuri)
|
|
|
+ });
|
|
|
+ ws = new WebSocket(wsuri);
|
|
|
+
|
|
|
+ ws.onerror = function(evt) {
|
|
|
+ wsDebug.lastErrorAt = Date.now();
|
|
|
+ pushWsEvent('error', {
|
|
|
+ connectId: wsDebug.connectId,
|
|
|
+ readyState: ws ? ws.readyState : null,
|
|
|
+ eventType: evt && evt.type
|
|
|
+ });
|
|
|
+ logIpccWs('error', 'onerror', {
|
|
|
+ connectId: wsDebug.connectId,
|
|
|
+ readyState: ws ? ws.readyState : null,
|
|
|
+ readyStateLabel: ws ? getReadyStateLabel(ws.readyState) : 'NO_WS',
|
|
|
+ snapshot: _cc.getWsDebugSnapshot()
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
//收到消息
|
|
|
ws.onmessage = function(evt) {
|
|
|
+ var msg = null;
|
|
|
+ var resp_status = null;
|
|
|
+ try {
|
|
|
+ msg = JSON.parse(evt.data);
|
|
|
+ resp_status = msg["status"];
|
|
|
+ } catch (parseErr) {
|
|
|
+ logIpccWs('error', 'onmessage-parse-failed', {
|
|
|
+ raw: evt.data,
|
|
|
+ error: parseErr && parseErr.message
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ wsDebug.lastRecvAt = Date.now();
|
|
|
+ wsDebug.lastRecvStatus = resp_status;
|
|
|
+ pushWsEvent('recv', {
|
|
|
+ status: resp_status,
|
|
|
+ action: msg.action,
|
|
|
+ uuid: msg.object && msg.object.uuid
|
|
|
+ });
|
|
|
+
|
|
|
+ var isHeartbeatRelated = msg.action === 'setHearBeat' || resp_status === 'heartbeat' || resp_status === 204;
|
|
|
+ if (isHeartbeatRelated) {
|
|
|
+ logIpccWs('log', 'heartbeat-recv', {
|
|
|
+ status: resp_status,
|
|
|
+ msg: msg
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ logIpccWs('log', 'onmessage', {
|
|
|
+ status: resp_status,
|
|
|
+ uuid: msg.object && msg.object.uuid,
|
|
|
+ callType: msg.object && msg.object.callType,
|
|
|
+ msg: msg
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
console.log("recv msg from websocket server: ", evt.data);
|
|
|
- var msg = JSON.parse(evt.data);
|
|
|
console.log("parsed json data:", msg);
|
|
|
- var resp_status = msg["status"];
|
|
|
switch(resp_status) {
|
|
|
case 200:
|
|
|
isConnected = true;
|
|
|
@@ -505,20 +668,97 @@ function ccPhoneBarSocket() {
|
|
|
//关闭连接时触发
|
|
|
ws.onclose = function(evt) {
|
|
|
isConnected = false;
|
|
|
- _cc.notifyAll(ccPhoneBarSocket.eventList.ws_disconnected, "ipccserver 连接断开.");
|
|
|
+ wsDebug.lastCloseAt = Date.now();
|
|
|
+ wsDebug.closeCode = evt.code;
|
|
|
+ wsDebug.closeReason = evt.reason || '';
|
|
|
+ wsDebug.closeWasClean = evt.wasClean;
|
|
|
+ var snapshot = _cc.getWsDebugSnapshot();
|
|
|
+ pushWsEvent('close', {
|
|
|
+ code: evt.code,
|
|
|
+ reason: evt.reason || '',
|
|
|
+ wasClean: evt.wasClean,
|
|
|
+ connectId: wsDebug.connectId
|
|
|
+ });
|
|
|
+ logIpccWs('error', 'onclose', {
|
|
|
+ code: evt.code,
|
|
|
+ reason: evt.reason || '',
|
|
|
+ wasClean: evt.wasClean,
|
|
|
+ connectId: wsDebug.connectId,
|
|
|
+ msSinceLastSend: wsDebug.lastSendAt ? (Date.now() - wsDebug.lastSendAt) : null,
|
|
|
+ msSinceLastRecv: wsDebug.lastRecvAt ? (Date.now() - wsDebug.lastRecvAt) : null,
|
|
|
+ lastSendAction: wsDebug.lastSendAction,
|
|
|
+ lastRecvStatus: wsDebug.lastRecvStatus,
|
|
|
+ snapshot: snapshot
|
|
|
+ });
|
|
|
+ _cc.notifyAll(ccPhoneBarSocket.eventList.ws_disconnected, snapshot);
|
|
|
console.log("ipcc连接断开.", "disconnected");
|
|
|
console.log(evt);
|
|
|
- ws.close();
|
|
|
};
|
|
|
ws.onopen = function(evt) {
|
|
|
+ wsDebug.lastOpenAt = Date.now();
|
|
|
+ wsDebug.connectedAt = Date.now();
|
|
|
+ pushWsEvent('open', { connectId: wsDebug.connectId });
|
|
|
+ logIpccWs('log', 'onopen', {
|
|
|
+ connectId: wsDebug.connectId,
|
|
|
+ readyState: ws.readyState,
|
|
|
+ readyStateLabel: getReadyStateLabel(ws.readyState)
|
|
|
+ });
|
|
|
console.log("ipccserver websocket onopen...");
|
|
|
};
|
|
|
};
|
|
|
|
|
|
//发送消息给呼叫控制服务器
|
|
|
- this.sendMsg = function(jsonObject) {
|
|
|
+ this.sendMsg = function(jsonObject, sendTag) {
|
|
|
+ var action = jsonObject && jsonObject.action;
|
|
|
+ var payload = JSON.stringify(jsonObject);
|
|
|
+ if (!ws) {
|
|
|
+ logIpccWs('error', 'send-failed', {
|
|
|
+ sendTag: sendTag || action,
|
|
|
+ reason: 'ws_is_null',
|
|
|
+ payload: jsonObject
|
|
|
+ });
|
|
|
+ pushWsEvent('send_failed', { sendTag: sendTag || action, reason: 'ws_is_null' });
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (ws.readyState !== WebSocket.OPEN) {
|
|
|
+ logIpccWs('error', 'send-failed', {
|
|
|
+ sendTag: sendTag || action,
|
|
|
+ reason: 'ws_not_open',
|
|
|
+ readyState: ws.readyState,
|
|
|
+ readyStateLabel: getReadyStateLabel(ws.readyState),
|
|
|
+ payload: jsonObject
|
|
|
+ });
|
|
|
+ pushWsEvent('send_failed', {
|
|
|
+ sendTag: sendTag || action,
|
|
|
+ reason: 'ws_not_open',
|
|
|
+ readyState: ws.readyState
|
|
|
+ });
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ wsDebug.lastSendAt = Date.now();
|
|
|
+ wsDebug.lastSendAction = sendTag || action;
|
|
|
+ pushWsEvent('send', { sendTag: sendTag || action, action: action });
|
|
|
+ if (sendTag === 'heartbeat' || action === 'setHearBeat') {
|
|
|
+ logIpccWs('log', 'heartbeat-send-ok', { payload: jsonObject });
|
|
|
+ } else {
|
|
|
+ logIpccWs('log', 'send', { sendTag: sendTag || action, payload: jsonObject });
|
|
|
+ }
|
|
|
console.debug("ws.send:", jsonObject);
|
|
|
- ws.send(JSON.stringify(jsonObject));
|
|
|
+ try {
|
|
|
+ ws.send(payload);
|
|
|
+ return true;
|
|
|
+ } catch (sendErr) {
|
|
|
+ logIpccWs('error', 'send-exception', {
|
|
|
+ sendTag: sendTag || action,
|
|
|
+ error: sendErr && sendErr.message,
|
|
|
+ payload: jsonObject
|
|
|
+ });
|
|
|
+ pushWsEvent('send_exception', {
|
|
|
+ sendTag: sendTag || action,
|
|
|
+ error: sendErr && sendErr.message
|
|
|
+ });
|
|
|
+ return false;
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
this.changeUiOnHold = function() {
|
|
|
@@ -907,7 +1147,7 @@ function ccPhoneBarSocket() {
|
|
|
var cmdInfo = {};
|
|
|
cmdInfo.action="setAgentStatus";
|
|
|
cmdInfo.body = {"cmd" : "setStatus", "args" : { "status" : status } };
|
|
|
- ws.send(JSON.stringify(cmdInfo));
|
|
|
+ _cc.sendMsg(cmdInfo, 'setStatus:' + status);
|
|
|
};
|
|
|
|
|
|
//注销登录;
|
|
|
@@ -1033,7 +1273,13 @@ function ccPhoneBarSocket() {
|
|
|
var sessionControl = {};
|
|
|
sessionControl.action="call";
|
|
|
sessionControl.body = {"cmd" : action, "args" : argsObject };
|
|
|
- ws.send(JSON.stringify(sessionControl));
|
|
|
+ logIpccWs('log', 'callControl', {
|
|
|
+ cmd: action,
|
|
|
+ args: argsObject,
|
|
|
+ readyState: ws ? ws.readyState : null,
|
|
|
+ readyStateLabel: ws ? getReadyStateLabel(ws.readyState) : 'NO_WS'
|
|
|
+ });
|
|
|
+ _cc.sendMsg(sessionControl, 'call:' + action);
|
|
|
};
|
|
|
|
|
|
this.checkCallConfirmed = function () {
|