Hal De преди 4 години
родител
ревизия
b4f7378bbb
променени са 2 файла, в които са добавени 103 реда и са изтрити 23 реда
  1. 24 23
      app/app.py
  2. 79 0
      app/cel.py

+ 24 - 23
app/app.py

@@ -10,12 +10,28 @@ from datetime import timedelta as td
 from typing import Any, Optional
 from databases import Database
 from quart import jsonify, request, render_template_string, abort
+from quart.json import JSONEncoder
 from quart_openapi import Pint, Resource
 from http import HTTPStatus
 from panoramisk import Manager, Message
 from utils import *
+from cel import *
 from logging.config import dictConfig
 
+class ApiJsonEncoder(JSONEncoder):
+  def default(self, o):
+    if isinstance(o, dt):
+      return o.isoformat()
+    if isinstance(o, CELEventChannel):
+      return str(o)
+    if isinstance(o, CELEvent):
+      return o.__dict__
+    if isinstance(o, CELEvents):
+      return o.all
+    if isinstance(o, CELCall):
+      return o.__dict__
+    return JSONEncoder.default(self, o)
+
 class PintDB:
   def __init__(self, app: Optional[Pint] = None) -> None:
     self.init_app(app)
@@ -38,7 +54,7 @@ class PintDB:
 main_loop = asyncio.get_event_loop()
 
 app = Pint(__name__, title=os.getenv('APP_TITLE', 'PBX API'), no_openapi=True)
-
+app.json_encoder = ApiJsonEncoder
 app.config.update({
   'TITLE':                  os.getenv('APP_TITLE', 'PBX API'),
   'APPLICATION_ROOT':       os.getenv('APP_APPLICATION_ROOT', None),
@@ -192,37 +208,22 @@ async def getCEL(start=None, end=None, **kwargs):
     end = dt.now()
   if start is None:
     start=(end - td(hours=24))
-  async for row in db.iterate(query='''SELECT linkedid,
-                                              uniqueid,
-                                              eventtime,
-                                              eventtype,
-                                              cid_name,
-                                              cid_num,
-                                              cid_ani,
-                                              cid_rdnis,
-                                              cid_dnid,
-                                              exten,
-                                              context,
-                                              channame,
-                                              appname,
-                                              uniqueid,
-                                              linkedid
+  async for row in db.iterate(query='''SELECT *
                                        FROM cel
                                        WHERE linkedid
                                        IN (SELECT DISTINCT(linkedid)
                                        FROM cel
                                        WHERE eventtime
-                                       BETWEEN :start AND :end)
-                                       ORDER BY linkedid,
-                                                uniqueid,
-                                                eventtime;''',
+                                       BETWEEN :start AND :end);''',
                               values={'start':start,
                                       'end':end}):
-    event = {_k: str(_v) for _k, _v in row.items() if _k != 'linkedid' and _v != ''}
-    _cel.setdefault(row['linkedid'],[]).append(event)
+    if row['linkedid'] in _cel:
+      _cel[row['linkedid']].events.add(row)
+    else:
+      _cel[row['linkedid']]=CELCall(row)
   cel = []
   for _id in sorted(_cel.keys()):
-    cel.append({'id':_id,'events':_cel[_id]})
+    cel.append(_cel[_id])
   return cel
 
 @app.before_first_request

+ 79 - 0
app/cel.py

@@ -0,0 +1,79 @@
+#!/usr/bin/env python3
+import json
+import re
+from datetime import datetime
+
+fieldsFilter = ('id', 'linkedid', 'appdata')
+
+class CELEventChannel:
+  def __init__(self, chanData):
+    self._str = chanData
+    (self.tech,
+     self.peer,
+     self.context,
+     self.id,
+     self.leg) = re.match(r'(\w+)/(\w+)(?:@([\w-]+))?-([0-9a-f]{8})(?:;([0-9]+))?', chanData).groups()
+  def __repr__(self):
+    return self._str
+
+class CELEvent:
+  def __init__(self, eventData):
+    for key, value in eventData.items():
+      if ((key not in fieldsFilter) and (value is not None) and (str(value) != '')):
+        if key == 'extra':
+          setattr(self, key, json.loads(value))
+        elif key == 'channame':
+          setattr(self, key, CELEventChannel(value))
+        else:
+          setattr(self, key, value)
+
+class CELEvents:
+  def __init__(self):
+    self._events = []
+  def add(self, event):
+    if isinstance(event, CELEvent):
+      self._events.append(event)
+    else:
+      self._events.append(CELEvent(event))
+  @property
+  def all(self):
+    return self._events
+  @property
+  def first(self):
+    return self._events[0] if len(self._events) > 0 else None
+  @property
+  def second(self):
+    return self._events[1] if len(self._events) > 1 else None
+  @property
+  def last(self):
+    return self._events[-1] if len(self._events) > 0 else None
+  def filter(self, key, value, func='__eq__'):
+    ''' events.filter('channame','PJSIP/','startswith')
+    '''
+    result = CELEvents()
+    for event in self._events:
+      if getattr(str(getattr(event, key)), func)(value):
+        result.add(event)
+    return result
+  def has(self, value, key='eventtype'):
+    for event in self._events:
+      if getattr(event, key) == value:
+        return True
+    return False
+  def __len__(self):
+    return len(self._events)
+
+class CELCall:
+  def __init__(self, event=None):
+    self.events = CELEvents()
+    if event is not None:
+      self.events.add(event)
+      self.linkedid = event['linkedid']
+    else:
+      self.linkedid = None
+  @property
+  def start(self):
+    return self.events.first.eventtime
+  @property
+  def isAnswered(self):
+    return self.events.has('BRIDGE_ENTER');