Commit c187a7b6 authored by okhin's avatar okhin 🚴

Lot of code, the event_handling looks better. Committing transatcion in SQLite...

Lot of code, the event_handling looks better. Committing transatcion in SQLite is - obviously - a good thing
parent c796e765
Pipeline #19 skipped
......@@ -31,7 +31,7 @@ class PiphoneJSONEncoder(json.JSONEncoder):
, 'history': obj.history
, 'owner': obj.owner }
else:
return json.JSONEncoder.default(self, o)
return json.JSONEncoder.default(self, obj)
def sanitize_phonenumber(number):
"""
......@@ -52,19 +52,21 @@ class Call(object):
This Class is used to manage operatiosn on a call, to print it and dump it.
"""
history = []
actions = {'Created': 'call_caller'}
actions = {'Created': 'call_caller'
, 'ChannelStateChange': 'change'}
def __init__(self, caller, callee, owner, callid=None, db=None):
try:
self.caller = caller
self.callee = callee
self.owner = owner
if callid == None:
self.id = uuid.uuid4()
self.id = str(uuid.uuid4())
self.db = db
self.event_handler({'type': 'Created', 'timestamp': datetime.datetime.now().isoformat()})
else:
self.id = callid
self.db = db
self.change(('Created', datetime.datetime.now().isoformat(),))
except Exception as e:
logging.debug("Exception catched: {}".format(e,))
raise e
def url(self):
......@@ -72,41 +74,55 @@ class Call(object):
@classmethod
def load(cls, callid, db):
results = db.execute('SELECT caller, callee, owner, callid, history FROM calls WHERE callid = ?;', (callid,))
logging.debug("Loading call {}".format(callid,))
try:
results = db.execute('SELECT caller, callee, owner, callid, history FROM calls WHERE callid = ?;', (callid,))
result = results.fetchone()
object = cls(result[0], result[1], result[2])
object.id = result[3]
object.db = db
assert len(result) == 5
object = cls(result[0], result[1], result[2], result[3])
object.history = json.loads(result[4])
object.db = db
return object
except:
return None
except Exception as e:
logging.debug("Exception catched: {}".format(e,))
raise e
def change(self, new_state):
def update(self, new_state):
'''
Let's change the state of the call. new_state is a tuple in the form (newstate, timestamp,)
Let's update the state of the call. new_state is a tuple in the form (newstate, timestamp,)
'''
logging.debug("Got a new state: {}".format(new_state,))
self.history.append(new_state)
self.save()
state = new_state[0]
def event_handler(self, event):
'''
There's a new event related to our call
'''
state = event['type']
if state in self.actions:
getattr(self, self.actions[state])()
getattr(self, self.actions[state])(event=event)
def call_caller(self):
def change(self, event):
'''
Let's change the state of the call
'''
self.update((event['channel']['state'], event['timestamp'],))
def call_caller(self, event):
'''
Let's do a request on the ARI system
'''
results = self.db.execute('SELECT login_ari, pass_ari FROM users WHERE api = ?', (self.owner,))
self.update((event['type'], event['timestamp'],))
try:
results = self.db.execute('SELECT login_ari, pass_ari FROM users WHERE api = ?', (self.owner,))
login_ari, token_ari = results.fetchone()
payload = {}
payload['app'] = 'piphone'
payload['api_key'] = ':'.join([login_ari, token_ari])
payload['endpoint'] = 'SIP/' + sanitize_phonenumber(self.caller) + '@forfait-kwaoo'
logging.debug('Preparing to send a request to the ARI with payload {}'.format(payload,))
r = requests.post('http://185.34.33.12:8088/ari/channels', data=payload)
r = requests.post('http://185.34.33.12:8088/ari/channels/{}'.format(self.id), data=payload)
logging.debug('Requests sent, got response: {}'.format(r,))
except Exception as e:
raise e
......@@ -115,9 +131,15 @@ class Call(object):
'''
Save the Call to database.
'''
self.db.execute('''INSERT OR REPLACE INTO calls (caller, callee, owner, callid, history)
VALUES (?, ?, ?, ?, ?)
''', (self.caller, self.callee, self.owner, self.id, json.dumps(self.history)))
logging.debug("Saving call {}: {}".format(self.id, json.dumps(self, cls=PiphoneJSONEncoder)))
try:
self.db.execute('''INSERT OR REPLACE INTO calls (caller, callee, owner, callid, history)
VALUES (?, ?, ?, ?, ?) '''
, (self.caller, self.callee, self.owner, self.id, json.dumps(self.history)))
self.db.commit()
except Exception as e:
logging.debug("Got Exception: {}".format(e,))
raise e
# We need a decorator to check if our query is authenticated.
# We will store an API key and SECRET in ur database, the client
......@@ -197,7 +219,7 @@ class Server(ServerAdapter):
self.logger.debug('Not a channel event, skip')
return
call = Call.load(event['channel']['id'], self.db)
await call.change((event['channel']['state'], event['channel']['creationtime'],))
call.event_handler(event)
def run(self, handler):
"""
......@@ -214,30 +236,66 @@ class Server(ServerAdapter):
self.server.shutdown()
self.threads.shutdown(wait=False)
@app.get('/calls/<callid>')
@app.get('/calls/')
@authenticated
def calls(db):
def calls(db, callid=None):
"""
Return the list of calls associated to the connected user.
The call has a status, caller, callee and history (status change+timestamp)
"""
logging.debug("/calls/ called")
results = db.execute('SELECT callid FROM calls WHERE owner = ?;', (request.params['api'],))
calls = []
for call in results.fetchall():
calls.append(Call.load(call[0], db))
head = {'call': request.fullpath, 'user': request.params['api'], 'hits': len(calls)}
return {'head': head, 'data': calls}
@app.post('/calls/<callid>/caller/<caller>/callee/<callee>/')
logging.debug("GET {}".format(request.fullpath))
if callid == None:
try:
results = db.execute('SELECT callid FROM calls WHERE owner = ?;', (request.params['api'],))
calls = []
for row in results.fetchall():
call = Call.load(row[0], db)
logging.debug("Call fetched: {}".format(json.dumps(call, cls=PiphoneJSONEncoder)))
calls.append(call)
head = {'call': request.fullpath, 'user': request.params['api'], 'hits': len(calls)}
return {'head': head, 'data': calls}
except Exception as e:
logging.error("Got exception: {}".format(e,))
abort(500, "Exception")
# We first need to check if we can access the callid we asked for
try:
results = db.execute('SELECT callid FROM calls WHERE owner = ? AND callid = ? ;'
, (request.params['api'], callid,))
rows = results.fetchall()
logging.debug("Found {} results: {}".format(len(rows), rows))
assert len(rows) == 1
call = Call.load(callid, db)
head = {'call': call.url(), 'user': request.params['api'], 'hits': 1}
return {'head': head, 'data': call}
except AssertionError as e:
logging.debg("Not exactly one results found, this is an issue")
logging.error("Unauthorized access to call {} from user {}".format(callid, request.params['api']))
abort(403, "You do not have the authorization to get this call")
except Exception as e:
logging.debug("Exception catched: {}".format(e,))
logging.error("Call not found {}".format(callid,))
abort(404, "This call does not exist")
@app.post('/calls/')
@app.post('/calls/<callid>')
@authenticated
def originate(db, callid, caller, callee):
call = Call(caller, callee, request.params['api'], callid, db)
logging.debug("Originate a call: {}".format(json.dumps(call, cls=PiphoneJSONEncoder)))
head = {'call': call.url()
def originate(db, callid=None):
logging.debug("POST {}".format(request.fullpath))
try:
if callid is not None:
call = Call(request.params['caller'], request.params['callee'], request.params['api'], callid=request.params['callid'], db=db)
else:
call = Call(request.params['caller'], request.params['callee'], request.params['api'], db=db)
logging.debug("Originate a call: {}".format(json.dumps(call, cls=PiphoneJSONEncoder)))
head = {'call': call.url()
, 'user': request.params['api']
, 'hits': 1}
return {'header': head, 'data': call}
return {'header': head, 'data': call}
except Exception as e:
logging.debug("Missing params : {}".format([p for p in request.params],))
logging.debug("Exception catched: {}".format(e,))
abort(400, "Missing or incorrect fields, the call cannot be processed")
if __name__ == '__main__':
app.install(SQLitePlugin(dbfile='call.db'))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment