callback.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. #!/usr/bin/env python3
  2. # encoding:utf-8
  3. import concurrent.futures
  4. import queue
  5. import random
  6. import threading
  7. import mmh3
  8. import src.core.callcenter.esl.utils.esl_event_util as EslEventUtil
  9. from src.core.callcenter.agent import AgentEventService
  10. from src.core.callcenter.cache import Cache
  11. from src.core.callcenter.enumeration import CallType
  12. from src.core.callcenter.esl.constant.event_names import DETECTED_TONE
  13. class Callback(object):
  14. def __init__(self, app, thread_num):
  15. self.app = app
  16. self.is_stopping = False
  17. self.logger = app.logger
  18. self.cache = Cache(app)
  19. self.event_queue = queue.Queue()
  20. self.executors = {x: concurrent.futures.ThreadPoolExecutor(max_workers=1, thread_name_prefix="callback-event-pool") for x in range(thread_num)}
  21. self.agent_event_service = AgentEventService(app)
  22. threading.Thread(target=self.start).start()
  23. def start(self):
  24. while not self.is_stopping:
  25. try:
  26. event, call_info, device_info = self.event_queue.get(timeout=1)
  27. call_type = CallType.get_by_code(call_info.call_type) if call_info else None
  28. if call_type is None:
  29. event_name = EslEventUtil.getEventName(event)
  30. self.logger.info("callback:call_type_none:return::event_name=%s, call_info=%s, device_info=%s", event_name, call_info, device_info)
  31. continue
  32. if CallType.BOT_CALL == call_type or CallType.INCOMING_BOT_CALL == call_type:
  33. self.choose_thread_pool_executor(event).submit(self.agent_event_service.bot_event_channel, event, call_info, device_info)
  34. else:
  35. self.choose_thread_pool_executor(event).submit(self.agent_event_service.agent_event_channel, event, call_info, device_info)
  36. except:
  37. pass
  38. def stop(self):
  39. self.is_stopping = True
  40. for k, v in self.executors.items():
  41. v.shutdown()
  42. def callback_event(self, event):
  43. event_name = EslEventUtil.getEventName(event)
  44. # CUSTOM == event_name or
  45. if not (event_name.startswith('CHANNEL_') or event_name.startswith('PLAYBACK_') or event_name == DETECTED_TONE):
  46. return
  47. call_id = EslEventUtil.getCallId(event)
  48. device_id = EslEventUtil.getDeviceId(event)
  49. if not call_id and device_id:
  50. call_id = self.cache.get_call_id_by_device_id(device_id)
  51. call_info = self.cache.get_call_info(call_id)
  52. if not call_info:
  53. self.logger.info("callback:return::event_name=%s, call_id=%s, device_id=%s", event_name, call_id, device_id)
  54. return
  55. device_info = call_info.device_info_map.get(device_id) if call_info and call_info.device_info_map else None
  56. self.logger.info("callback::event_name=%s, call_id=%s, device_id=%s", event_name, call_id, device_id)
  57. self.event_queue.put_nowait((event, call_info, device_info))
  58. def choose_thread_pool_executor(self, e):
  59. call_id = EslEventUtil.getCallId(e)
  60. device_id = EslEventUtil.getUniqueId(e)
  61. wdh_device_id = EslEventUtil.getDeviceId(e)
  62. random_id = call_id if call_id else device_id
  63. if random_id:
  64. random_index = abs(mmh3.hash(random_id)) % len(self.executors)
  65. else:
  66. random_index = random.randint(0, len(self.executors) - 1) if self.executors else 0
  67. # self.logger.info('choose_thread_pool_executor.index %s %s %s %s', random_index, call_id, device_id, wdh_device_id)
  68. return self.executors.get(random_index)