cel.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. #!/usr/bin/env python3
  2. import json
  3. import re
  4. from datetime import datetime
  5. fieldsFilter = ('id', 'linkedid', 'appdata', 'lastdata')
  6. class CdrChannel:
  7. def __init__(self, chanData):
  8. self._str = chanData
  9. (self.tech,
  10. self.peer,
  11. self.context,
  12. self.id,
  13. self.leg) = re.match(r'(\w+)/(\w+)(?:@([\w-]+))?-([0-9a-f]{8})(?:;([0-9]+))?', chanData).groups()
  14. def __repr__(self):
  15. return self._str
  16. class CdrEvent:
  17. def __init__(self, eventData):
  18. for key, value in eventData.items():
  19. if ((key not in fieldsFilter) and (value is not None) and (str(value) != '')):
  20. if key == 'extra':
  21. setattr(self, key, json.loads(value))
  22. elif key in ('channame','channel','dstchannel'):
  23. setattr(self, key, CdrChannel(value))
  24. else:
  25. setattr(self, key, value)
  26. def __getattr__(self, attr):
  27. return None
  28. class CdrEvents:
  29. def __init__(self):
  30. self._events = []
  31. def add(self, event):
  32. if isinstance(event, CdrEvent):
  33. self._events.append(event)
  34. else:
  35. self._events.append(CdrEvent(event))
  36. @property
  37. def all(self):
  38. return self._events
  39. @property
  40. def first(self):
  41. return self._events[0] if len(self._events) > 0 else None
  42. @property
  43. def second(self):
  44. return self._events[1] if len(self._events) > 1 else None
  45. @property
  46. def last(self):
  47. return self._events[-1] if len(self._events) > 0 else None
  48. def filter(self, key, value, func='__eq__'):
  49. result = CdrEvents()
  50. for event in self._events:
  51. if getattr(str(getattr(event, key)), func)(value):
  52. result.add(event)
  53. return result
  54. def has(self, value, key='disposition'):
  55. for event in self._events:
  56. if getattr(event, key) == value:
  57. return True
  58. return False
  59. def __len__(self):
  60. return len(self._events)
  61. class CelEvents(CdrEvents):
  62. def has(self, value, key='eventtype'):
  63. return super().has(value, key)
  64. class CdrCall:
  65. def __init__(self, event=None):
  66. self.events = CdrEvents()
  67. if event is not None:
  68. self.events.add(event)
  69. self.linkedid = event['linkedid']
  70. else:
  71. self.linkedid = None
  72. @property
  73. def start(self):
  74. return self.events.first.calldate
  75. @property
  76. def disposition(self):
  77. return self.events.first.disposition
  78. @property
  79. def file(self):
  80. return self.events.first.recordingfile
  81. @property
  82. def src(self):
  83. return self.events.first.cnum
  84. @property
  85. def direction(self):
  86. if self.events.first.dcontext == 'from-internal':
  87. if self.events.first.outbound_cnum is not None:
  88. return 'outbound'
  89. else:
  90. return 'local'
  91. else:
  92. return 'inbound'
  93. @property
  94. def dst(self):
  95. # placeholder
  96. # TODO: determine last dst based on disposition
  97. return self.events.filter(src, self.src).last.dst
  98. @property
  99. def did(self):
  100. if self.direction == 'inbound':
  101. return self.events.first.did
  102. else:
  103. return None
  104. @property
  105. def duration(self):
  106. if not self.isAnswered:
  107. return 0
  108. else:
  109. _t = 0
  110. if len(self.events) > 1:
  111. for event in self.events.all[1:]:
  112. if event.disposition == 'ANSWERED':
  113. _t = _t + event.billsec
  114. else:
  115. _t = self.events.first.billsec
  116. return _t
  117. @property
  118. def waiting(self):
  119. if not self.isAnswered:
  120. return self.events.first.duration
  121. else:
  122. # TODO: exclude time on ivr
  123. return self.events.first.duration - self.duration
  124. @property
  125. def isAnswered(self):
  126. return self.disposition == 'ANSWERED';
  127. class CelCall:
  128. def __init__(self, event=None):
  129. self.events = CelEvents()
  130. if event is not None:
  131. self.events.add(event)
  132. self.linkedid = event['linkedid']
  133. else:
  134. self.linkedid = None
  135. @property
  136. def start(self):
  137. return self.events.first.eventtime