|
@@ -11,16 +11,19 @@ import mmh3
|
|
import threading
|
|
import threading
|
|
import traceback
|
|
import traceback
|
|
import concurrent.futures
|
|
import concurrent.futures
|
|
|
|
+
|
|
|
|
+from apscheduler.schedulers.background import BackgroundScheduler
|
|
|
|
+
|
|
import src.core.callcenter.cache as Cache
|
|
import src.core.callcenter.cache as Cache
|
|
-from src.core.callcenter.api import MakeCallContext
|
|
|
|
-from src.core.callcenter.constant import SK, EMPTY
|
|
|
|
|
|
+from src.core.callcenter.api import MakeCallContext, DelayAction
|
|
|
|
+from src.core.callcenter.constant import SK, EMPTY, CTI_ENGINE_DELAY_ACTION_LOCK, HOLD_MUSIC_PATH
|
|
from src.core.callcenter.esl.constant.esl_constant import BRIDGE_VARIABLES, BRIDGE, HANGUP, NORMAL_CLEARING, SIP_HEADER, SPACE, SPLIT, SOFIA, \
|
|
from src.core.callcenter.esl.constant.esl_constant import BRIDGE_VARIABLES, BRIDGE, HANGUP, NORMAL_CLEARING, SIP_HEADER, SPACE, SPLIT, SOFIA, \
|
|
ORIGINATE, PARK, SET, EAVESDROP, SMF_ALEG, EXECUTE, PLAYBACK, PAUSE, TRANSFER, UUID_TRANSFER, UUID_BROADCAST, UUID_BREAK, UUID_HOLD, \
|
|
ORIGINATE, PARK, SET, EAVESDROP, SMF_ALEG, EXECUTE, PLAYBACK, PAUSE, TRANSFER, UUID_TRANSFER, UUID_BROADCAST, UUID_BREAK, UUID_HOLD, \
|
|
UUID_RECORD, UUID_SETVAR, UUID_GETVAR
|
|
UUID_RECORD, UUID_SETVAR, UUID_GETVAR
|
|
import src.core.callcenter.esl.utils.esl_event_util as EslEventUtil
|
|
import src.core.callcenter.esl.utils.esl_event_util as EslEventUtil
|
|
import src.core.callcenter.esl.handler as event_handler
|
|
import src.core.callcenter.esl.handler as event_handler
|
|
from src.core.callcenter.esl.constant.sip_header_constant import sipHeaderHoldMusic, profile1, profile2
|
|
from src.core.callcenter.esl.constant.sip_header_constant import sipHeaderHoldMusic, profile1, profile2
|
|
-from src.core.callcenter.enumeration import CallCause, DeviceType
|
|
|
|
|
|
+from src.core.callcenter.enumeration import CallCause, DeviceType, DelayActionEnum, HangupDir, CallType, NextType
|
|
from src.core.callcenter.esl.handler.default_esl_event_handler import DefaultEslEventHandler
|
|
from src.core.callcenter.esl.handler.default_esl_event_handler import DefaultEslEventHandler
|
|
from src.core.datasource import SERVE_HOST
|
|
from src.core.datasource import SERVE_HOST
|
|
from src.core.voip.constant import *
|
|
from src.core.voip.constant import *
|
|
@@ -38,9 +41,19 @@ class InboundClient:
|
|
self.default_event_handler = DefaultEslEventHandler(self, self.bot_agent, self.logger)
|
|
self.default_event_handler = DefaultEslEventHandler(self, self.bot_agent, self.logger)
|
|
self.host, self.port, self.password = SERVE_HOST, '8021', '4918257983818884358'
|
|
self.host, self.port, self.password = SERVE_HOST, '8021', '4918257983818884358'
|
|
self.executors = {x: concurrent.futures.ThreadPoolExecutor(max_workers=1) for x in range(self.thread_num)}
|
|
self.executors = {x: concurrent.futures.ThreadPoolExecutor(max_workers=1) for x in range(self.thread_num)}
|
|
-
|
|
|
|
threading.Thread(target=self.start, args=()).start()
|
|
threading.Thread(target=self.start, args=()).start()
|
|
|
|
|
|
|
|
+ self.delay_action_executor = concurrent.futures.ThreadPoolExecutor(max_workers=5)
|
|
|
|
+ self.delay_action_scheduler = BackgroundScheduler()
|
|
|
|
+ self.delay_action_scheduler.add_job(self.do_delay_action, 'interval', seconds=1, max_instances=1)
|
|
|
|
+ self.delay_action_scheduler.start()
|
|
|
|
+
|
|
|
|
+ def submit_delay_action(self):
|
|
|
|
+ for name, member in DelayActionEnum.__members__.items():
|
|
|
|
+ action_messages = Cache.get_delay_message(name)
|
|
|
|
+ for action_message in action_messages:
|
|
|
|
+ self.delay_action_executor.submit(self.do_delay_action, name, action_message)
|
|
|
|
+
|
|
def scan_esl_event_handlers(self):
|
|
def scan_esl_event_handlers(self):
|
|
import inspect
|
|
import inspect
|
|
import importlib
|
|
import importlib
|
|
@@ -111,6 +124,72 @@ class InboundClient:
|
|
except:
|
|
except:
|
|
traceback.print_exc()
|
|
traceback.print_exc()
|
|
|
|
|
|
|
|
+ def do_delay_action(self, action, message):
|
|
|
|
+ delay_action = DelayAction.from_json(message)
|
|
|
|
+ flag = Cache.lock_delay_action(delay_action.uuid)
|
|
|
|
+ if not flag:
|
|
|
|
+ self.logger.info("异步延迟执行操作重复 action:%s msg:%s", action, message)
|
|
|
|
+ return
|
|
|
|
+ delay_action_enum = DelayActionEnum.get_by_code(action)
|
|
|
|
+ if not delay_action_enum:
|
|
|
|
+ self.logger.info("异步延迟执行 delayActionEnum为空 action:%s msg:%s", action, message)
|
|
|
|
+ return
|
|
|
|
+
|
|
|
|
+ if DelayActionEnum.CALL_TIMEOUT_HANGUP == delay_action_enum:
|
|
|
|
+ self.exec_when_call_timeout(delay_action.call_id, delay_action.device_id)
|
|
|
|
+ elif DelayActionEnum.PLAY_TIMEOUT_HANGUP == delay_action_enum:
|
|
|
|
+ self.exec_when_play_timeout(delay_action.call_id)
|
|
|
|
+ elif DelayActionEnum.ACD_TIMEOUT_PLAY == delay_action_enum:
|
|
|
|
+ self.exec_when_acd_timeout(delay_action.call_id)
|
|
|
|
+
|
|
|
|
+ def exec_when_call_timeout(self, call_id, device_id):
|
|
|
|
+ call_info = Cache.get_call_info(call_id)
|
|
|
|
+ if not call_info or not (device_id in call_info.device_list):
|
|
|
|
+ return
|
|
|
|
+ device_info = call_info.device_info_map.get(device_id)
|
|
|
|
+ if device_info and device_info.answer_time is None:
|
|
|
|
+ self.logger.info("call:%s deviceId:%s execWhenCallTimeOut", call_id, device_id)
|
|
|
|
+ device_info.hangup_cause = CallCause.CALL_TIMEOUT.name
|
|
|
|
+ call_info.next_commands = []
|
|
|
|
+ if device_info.device_type <= DeviceType.ROBOT.code:
|
|
|
|
+ call_info.hangup_dir = HangupDir.PLATFORM_HANGUP.code
|
|
|
|
+ call_info.hangup_code = CallCause.CALL_TIMEOUT.code
|
|
|
|
+ # if device_info.device_type.code == DeviceType.CUSTOMER.code:
|
|
|
|
+ # call_info.user_no_answer_end_call = True
|
|
|
|
+
|
|
|
|
+ if not device_info.end_time and device_info.device_type.code == DeviceType.CUSTOMER.code:
|
|
|
|
+ channel = self.show_channel(device_id)
|
|
|
|
+ if channel:
|
|
|
|
+ delay_action = DelayAction(call_id=call_id, device_id=device_id)
|
|
|
|
+ Cache.add_delay_message(DelayActionEnum.CALL_TIMEOUT_DECR, delay_action, timeouts=20)
|
|
|
|
+ Cache.add_call_info(call_info)
|
|
|
|
+ self.hangup_call(call_id, device_id, CallCause.CALL_TIMEOUT)
|
|
|
|
+
|
|
|
|
+ def exec_when_play_timeout(self, call_id):
|
|
|
|
+ call_info = Cache.get_call_info(call_id)
|
|
|
|
+ if not call_info or not call_info.next_commands:
|
|
|
|
+ return
|
|
|
|
+ self.logger.debug("播放结束音乐失败,进行挂机 callId:%s", call_id)
|
|
|
|
+ next_types = [x.next_type for x in call_info.next_commands]
|
|
|
|
+ if NextType.NEXT_HANGUP.code in next_types:
|
|
|
|
+ for device_id in call_info.device_list:
|
|
|
|
+ self.hangup_call(call_id, device_id, CallCause.PLAY_TIMEOUT)
|
|
|
|
+
|
|
|
|
+ def exec_when_acd_timeout(self, call_id):
|
|
|
|
+ call_info = Cache.get_call_info(call_id)
|
|
|
|
+ if not call_info:
|
|
|
|
+ self.logger.info("exec_when_acd_timeout callInfo为空 callId: {}", call_id)
|
|
|
|
+ return
|
|
|
|
+ device_list = [v for k,v in call_info.device_info_map.items() if v.device_type == DeviceType.CUSTOMER]
|
|
|
|
+ if device_list and len(device_list) == 1:
|
|
|
|
+ device_id = device_list[0].device_id
|
|
|
|
+ self.bridge_break(device_id)
|
|
|
|
+ self.hold_play(device_id, HOLD_MUSIC_PATH)
|
|
|
|
+ self.play_timeout(call_id, timeout=30)
|
|
|
|
+ Cache.add_call_info(call_info)
|
|
|
|
+ self.logger.info("waitingTimeOut 开始播放结束音乐 callId:%s customerDeviceId:%s playFile:%s", call_id,
|
|
|
|
+ device_id, HOLD_MUSIC_PATH)
|
|
|
|
+
|
|
def make_call_new(self, context: MakeCallContext):
|
|
def make_call_new(self, context: MakeCallContext):
|
|
called = context.get_called()
|
|
called = context.get_called()
|
|
params = {'gateway': context.route_gateway_name, 'called': called, 'realm': context.get_realm()}
|
|
params = {'gateway': context.route_gateway_name, 'called': called, 'realm': context.get_realm()}
|
|
@@ -184,7 +263,8 @@ class InboundClient:
|
|
|
|
|
|
def call_timeout(self, call_id, device_id, timeout):
|
|
def call_timeout(self, call_id, device_id, timeout):
|
|
"""呼叫超时主动挂机"""
|
|
"""呼叫超时主动挂机"""
|
|
- pass
|
|
|
|
|
|
+ delay_action = DelayAction(call_id=call_id, device_id=device_id)
|
|
|
|
+ Cache.add_delay_message(DelayActionEnum.CALL_TIMEOUT_HANGUP.code, delay_action, timeouts=timeout)
|
|
|
|
|
|
def send_args(self, device_id, name, arg):
|
|
def send_args(self, device_id, name, arg):
|
|
msg = ESL.ESLevent("sendmsg", device_id)
|
|
msg = ESL.ESLevent("sendmsg", device_id)
|
|
@@ -365,7 +445,8 @@ class InboundClient:
|
|
|
|
|
|
def play_timeout(self, call_id, timeout):
|
|
def play_timeout(self, call_id, timeout):
|
|
"""播放超时主动挂机"""
|
|
"""播放超时主动挂机"""
|
|
- pass
|
|
|
|
|
|
+ delay_action = DelayAction(call_id=call_id)
|
|
|
|
+ Cache.add_delay_message(DelayActionEnum.PLAY_TIMEOUT_HANGUP.code, delay_action, timeouts=timeout)
|
|
|
|
|
|
def listen(self, device_id1, device_id2, aleg=True, bleg=True):
|
|
def listen(self, device_id1, device_id2, aleg=True, bleg=True):
|
|
"""监听"""
|
|
"""监听"""
|