callback.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. #!/usr/bin/env python3
  2. # encoding:utf-8
  3. import queue
  4. import threading
  5. import concurrent.futures
  6. import mmh3
  7. import random
  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 CUSTOM, 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) 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. # self.logger.info("callback::call_type=%s, call_info=%s", call_type, call_info)
  29. if call_type is None:
  30. continue
  31. if CallType.BOT_CALL == call_type:
  32. self.choose_thread_pool_executor(event).submit(self.agent_event_service.bot_event_channel, event, call_info, device_info)
  33. else:
  34. self.choose_thread_pool_executor(event).submit(self.agent_event_service.agent_event_channel, event, call_info, device_info)
  35. except:
  36. pass
  37. def stop(self):
  38. self.is_stopping = True
  39. for k, v in self.executors.items():
  40. v.shutdown()
  41. def callback_event(self, event):
  42. event_name = EslEventUtil.getEventName(event)
  43. # CUSTOM == event_name or
  44. if not (event_name.startswith('CHANNEL_') or event_name.startswith('PLAYBACK_') or event_name == DETECTED_TONE):
  45. return
  46. call_id = EslEventUtil.getCallId(event)
  47. device_id = EslEventUtil.getDeviceId(event)
  48. if not call_id and device_id:
  49. call_id = self.cache.get_call_id_by_device_id(device_id)
  50. call_info = self.cache.get_call_info(call_id)
  51. if not call_info:
  52. # self.logger.info("callback:return::event_name=%s, call_id=%s, device_id=%s", event_name, call_id, device_id)
  53. return
  54. device_info = call_info.device_info_map.get(device_id) if call_info and call_info.device_info_map else None
  55. self.logger.info("callback::event_name=%s, call_id=%s, device_id=%s", event_name, call_id, device_id)
  56. self.event_queue.put_nowait((event, call_info, device_info))
  57. def choose_thread_pool_executor(self, e):
  58. call_id = EslEventUtil.getCallId(e)
  59. device_id = EslEventUtil.getUniqueId(e)
  60. wdh_device_id = EslEventUtil.getDeviceId(e)
  61. random_id = call_id if call_id else device_id
  62. if random_id:
  63. random_index = abs(mmh3.hash(random_id)) % len(self.executors)
  64. else:
  65. random_index = random.randint(0, len(self.executors) - 1) if self.executors else 0
  66. # self.logger.info('choose_thread_pool_executor.index %s %s %s %s', random_index, call_id, device_id, wdh_device_id)
  67. return self.executors.get(random_index)