Commit f1b7815a authored by okhin's avatar okhin 🚴

Let's try to play with bridges and understand how they work

parent 696f9e55
Pipeline #22 skipped
......@@ -7,6 +7,7 @@ import json
import logging
import concurrent.futures
import asyncio
import re
from wsgiref.simple_server import make_server
from operator import itemgetter
......@@ -65,11 +66,11 @@ class Call(object):
if callid == None:
self.id = str(uuid.uuid4())
self.db = db
self.event_handler({'type': 'Created', 'timestamp': datetime.datetime.now().isoformat()})
self.event_handler({'type': 'Created', 'timestamp': datetime.datetime.now().isoformat(), 'channel': {'id': 'Init'}})
else:
self.id = callid
except Exception as e:
logging.debug("Exception catched: {}".format(e,))
logging.exception(e)
raise e
def url(self):
......@@ -91,7 +92,7 @@ class Call(object):
object.db = db
return object
except Exception as e:
logging.debug("Exception catched: {}".format(e,))
logging.exception(e)
raise e
def update(self, new_state):
......@@ -115,36 +116,49 @@ class Call(object):
We received a DTMF sequence
'''
try:
assert self.state() == 'Up'
assert self.state().startswith('Up')
# The only thing we want to do is to call the callee if we press 1
if event['digit'] == '1':
# Now, we're connectig the other side
# But first we should stop the playback
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])
logging.debug('Stopping the playback currently running'.format(payload,))
# We're starting a playback, with the same ID as the channel, to keep track of it
r = requests.delete('http://185.34.33.12:8088/ari/playbacks/{0}'.format(self.id), data=payload)
logging.info('Will now connect {} to {}'.format(self.caller, self.callee,))
payload = {}
payload['app'] = 'piphone'
payload['api_key'] = ':'.join([login_ari, token_ari])
payload['endpoint'] = 'SIP/forfait-kwaoo/' + sanitize_phonenumber(self.callee)
r = requests.post('http://185.34.33.12:8088/ari/channels/{}/redirect'.format(self.id), data=payload)
if event['digit'] != '1':
return
# Now, we're connectig the other side
# But first we should stop the playback
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])
logging.debug('Stopping the playback currently running'.format(payload,))
# We're stoping the playback, with the same ID as the channel, to keep track of it
r = requests.delete('http://185.34.33.12:8088/ari/playbacks/{0}'.format(event['channel']['id']), data=payload)
# Next we need to originate a call to the other side
logging.info('Will now connect {} to {}'.format(self.caller, self.callee,))
payload = {}
payload['app'] = 'piphone'
payload['api_key'] = ':'.join([login_ari, token_ari])
payload['endpoint'] = 'SIP/' + sanitize_phonenumber(self.callee) + '@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/{}-{}'.format(self.id, sanitize_phonenumber(self.callee),), data=payload)
# And now, just need to add the channel to the bridge
payload = {}
payload['app'] = 'piphone'
payload['api_key'] = ':'.join([login_ari, token_ari])
payload['channel'] = '{}-{}'.format(self.id, sanitize_phonenumber(self.callee),)
r = requests.post('http://185.34.33.12:8088/ari/bridges/{}/addChannel'.format(self.id,), data=payload)
except AssertionError as e:
logging.debug("Received a DTMF sequence out le being in a '{}' state, ignoring: {}".format(self.state(), event['digit']))
logging.error("Received a DTMF sequence out le being in a '{}' state, ignoring: {}".format(self.state(), event['digit']))
def change(self, event):
'''
Let's change the state of the call
'''
self.update((event['channel']['state'], event['timestamp'],))
self.update((':'.join([event['channel']['state'], event['channel']['id'].split('-')[-1]]), event['timestamp'],))
logging.info("New state for call {}: {}".format(event['channel']['id'], event['channel']['state']))
# We now need to take action according to our new state
if event['channel']['state'] == 'Up':
# Are we the caller orthe callee?
if event['channel']['id'].endswith(self.callee):
# Callee side, let's just move
return
# Call is being picked up, we want to play a song
payload = {}
try:
......@@ -156,29 +170,58 @@ class Call(object):
payload['lang'] = 'en_US'
logging.debug('Preparing to send a request to the ARI with payload {}'.format(payload,))
# We're starting a playback, with the same ID as the channel, to keep track of it
r = requests.post('http://185.34.33.12:8088/ari/channels/{0}/play/{0}'.format(self.id), data=payload)
r = requests.post('http://185.34.33.12:8088/ari/channels/{0}/play/{0}'.format(event['channel']['id']), data=payload)
logging.debug("Now playing a sound on channel {}".format(self.id))
except Exception as e:
logging.debug("Exception raised in change(): {} - event was {}".format(e, event,))
logging.exception(e)
raise e
def call_caller(self, event):
'''
Let's do a request on the ARI system
We want to call the caller. Which needs to be done via a bridge.
Fisrt we set-up a bridge, then we originate a channel, postfixing the bridge id
with the caller number.
And then we connect the caller to the bridge.
The bridge is a mixed one.
'''
self.update((event['type'], event['timestamp'],))
self.update((':'.join([event['type'], event['channel']['id'].split('-')[-1]]), event['timestamp'],))
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])
# Let's establish a bridge over the Kwai River
try:
payload['type'] = 'mixing'
logging.debug("Initiating a bridge for call {}".format(self.id,))
r = requests.post('http://185.34.33.12:8088/ari/bridges/{}'.format(self.id,), data=payload)
except Exception as e:
logging.exception(e)
raise e
# Now, let's create the channel
payload = {}
payload['app'] = 'piphone'
payload['api_key'] = ':'.join([login_ari, token_ari])
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/{}'.format(self.id), data=payload)
logging.debug('Requests sent, got response: {}'.format(r,))
r = requests.post('http://185.34.33.12:8088/ari/channels/{}-{}'.format(self.id, sanitize_phonenumber(self.caller),), data=payload)
except Exception as e:
logging.debug("Exception raised in call_caller(): {}".format(e,))
logging.exception(e)
raise e
# Let's connect the channel to the bridge.
payload = {}
payload['app'] = 'piphone'
payload['api_key'] = ':'.join([login_ari, token_ari])
try:
payload['channel'] = '{}-{}'.format(self.id, sanitize_phonenumber(self.caller),)
logging.debug("Connection the channel to the bridge for call {}".format(self.id,))
r = requests.post('http://185.34.33.12:8088/ari/bridges/{}/addChannel'.format(self.id,), data=payload)
except Exception as e:
logging.exception(e)
raise e
def save(self):
......@@ -192,7 +235,7 @@ class Call(object):
, (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,))
logging.exception(e)
raise e
def authenticated(f):
......@@ -225,7 +268,7 @@ def authenticated(f):
request.params[key] = auth_token[key]
except (jwt.exceptions.InvalidTokenError, AssertionError) as e:
logging.error("Access refused")
logging.debug("InvalidTokenError: {}".format(e))
logging.exception(e)
abort(403, e)
except Exception as e:
abort(500, e)
......@@ -274,11 +317,12 @@ class Server(ServerAdapter):
a dict loaded from JSON.
"""
self.logger.debug('Event received: {}'.format(event,))
# Let's get the call ID
# Let's get the call ID, the call id isthe channel id minus the last -part.
if 'channel' not in event:
self.logger.debug('Not a channel event, skip')
return
call = Call.load(event['channel']['id'], self.db)
call_id = re.sub('-\d+$', '', event['channel']['id'])
call = Call.load(call_id, self.db)
call.event_handler(event)
def run(self, handler):
......@@ -316,7 +360,7 @@ def calls(db, callid=None):
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,))
logging.exception(e)
abort(500, "Exception")
# We first need to check if we can access the callid we asked for
try:
......@@ -354,7 +398,7 @@ def originate(db, callid=None):
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,))
logging.exception(e)
abort(400, "Missing or incorrect fields, the call cannot be processed")
if __name__ == '__main__':
......@@ -365,6 +409,6 @@ if __name__ == '__main__':
try:
app.run(server=server)
except Exception as e:
logging.error(e)
logging.exception(e)
server.stop()
raise e
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