Commit f1b7815a authored by okhin's avatar okhin
Browse files

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

parent 696f9e55
Pipeline #22 skipped
...@@ -7,6 +7,7 @@ import json ...@@ -7,6 +7,7 @@ import json
import logging import logging
import concurrent.futures import concurrent.futures
import asyncio import asyncio
import re
from wsgiref.simple_server import make_server from wsgiref.simple_server import make_server
from operator import itemgetter from operator import itemgetter
...@@ -65,11 +66,11 @@ class Call(object): ...@@ -65,11 +66,11 @@ class Call(object):
if callid == None: if callid == None:
self.id = str(uuid.uuid4()) self.id = str(uuid.uuid4())
self.db = db 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: else:
self.id = callid self.id = callid
except Exception as e: except Exception as e:
logging.debug("Exception catched: {}".format(e,)) logging.exception(e)
raise e raise e
def url(self): def url(self):
...@@ -91,7 +92,7 @@ class Call(object): ...@@ -91,7 +92,7 @@ class Call(object):
object.db = db object.db = db
return object return object
except Exception as e: except Exception as e:
logging.debug("Exception catched: {}".format(e,)) logging.exception(e)
raise e raise e
def update(self, new_state): def update(self, new_state):
...@@ -115,36 +116,49 @@ class Call(object): ...@@ -115,36 +116,49 @@ class Call(object):
We received a DTMF sequence We received a DTMF sequence
''' '''
try: 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 # The only thing we want to do is to call the callee if we press 1
if event['digit'] == '1': if event['digit'] != '1':
# Now, we're connectig the other side return
# But first we should stop the playback # Now, we're connectig the other side
results = self.db.execute('SELECT login_ari, pass_ari FROM users WHERE api = ?', (self.owner,)) # But first we should stop the playback
login_ari, token_ari = results.fetchone() results = self.db.execute('SELECT login_ari, pass_ari FROM users WHERE api = ?', (self.owner,))
payload = {} login_ari, token_ari = results.fetchone()
payload['app'] = 'piphone' payload = {}
payload['api_key'] = ':'.join([login_ari, token_ari]) payload['app'] = 'piphone'
logging.debug('Stopping the playback currently running'.format(payload,)) payload['api_key'] = ':'.join([login_ari, token_ari])
# We're starting a playback, with the same ID as the channel, to keep track of it logging.debug('Stopping the playback currently running'.format(payload,))
r = requests.delete('http://185.34.33.12:8088/ari/playbacks/{0}'.format(self.id), data=payload) # We're stoping the playback, with the same ID as the channel, to keep track of it
logging.info('Will now connect {} to {}'.format(self.caller, self.callee,)) r = requests.delete('http://185.34.33.12:8088/ari/playbacks/{0}'.format(event['channel']['id']), data=payload)
payload = {} # Next we need to originate a call to the other side
payload['app'] = 'piphone' logging.info('Will now connect {} to {}'.format(self.caller, self.callee,))
payload['api_key'] = ':'.join([login_ari, token_ari]) payload = {}
payload['endpoint'] = 'SIP/forfait-kwaoo/' + sanitize_phonenumber(self.callee) payload['app'] = 'piphone'
r = requests.post('http://185.34.33.12:8088/ari/channels/{}/redirect'.format(self.id), data=payload) 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: 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): def change(self, event):
''' '''
Let's change the state of the call 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'])) logging.info("New state for call {}: {}".format(event['channel']['id'], event['channel']['state']))
# We now need to take action according to our new state # We now need to take action according to our new state
if event['channel']['state'] == 'Up': 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 # Call is being picked up, we want to play a song
payload = {} payload = {}
try: try:
...@@ -156,29 +170,58 @@ class Call(object): ...@@ -156,29 +170,58 @@ class Call(object):
payload['lang'] = 'en_US' payload['lang'] = 'en_US'
logging.debug('Preparing to send a request to the ARI with payload {}'.format(payload,)) 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 # 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)) logging.debug("Now playing a sound on channel {}".format(self.id))
except Exception as e: except Exception as e:
logging.debug("Exception raised in change(): {} - event was {}".format(e, event,)) logging.exception(e)
raise e raise e
def call_caller(self, event): 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: 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' payload['endpoint'] = 'SIP/' + sanitize_phonenumber(self.caller) + '@forfait-kwaoo'
logging.debug('Preparing to send a request to the ARI with payload {}'.format(payload,)) 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) r = requests.post('http://185.34.33.12:8088/ari/channels/{}-{}'.format(self.id, sanitize_phonenumber(self.caller),), data=payload)
logging.debug('Requests sent, got response: {}'.format(r,))
except Exception as e: 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 raise e
def save(self): def save(self):
...@@ -192,7 +235,7 @@ class Call(object): ...@@ -192,7 +235,7 @@ class Call(object):
, (self.caller, self.callee, self.owner, self.id, json.dumps(self.history))) , (self.caller, self.callee, self.owner, self.id, json.dumps(self.history)))
self.db.commit() self.db.commit()
except Exception as e: except Exception as e:
logging.debug("Got Exception: {}".format(e,)) logging.exception(e)
raise e raise e
def authenticated(f): def authenticated(f):
...@@ -225,7 +268,7 @@ def authenticated(f): ...@@ -225,7 +268,7 @@ def authenticated(f):
request.params[key] = auth_token[key] request.params[key] = auth_token[key]
except (jwt.exceptions.InvalidTokenError, AssertionError) as e: except (jwt.exceptions.InvalidTokenError, AssertionError) as e:
logging.error("Access refused") logging.error("Access refused")
logging.debug("InvalidTokenError: {}".format(e)) logging.exception(e)
abort(403, e) abort(403, e)
except Exception as e: except Exception as e:
abort(500, e) abort(500, e)
...@@ -274,11 +317,12 @@ class Server(ServerAdapter): ...@@ -274,11 +317,12 @@ class Server(ServerAdapter):
a dict loaded from JSON. a dict loaded from JSON.
""" """
self.logger.debug('Event received: {}'.format(event,)) 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: if 'channel' not in event:
self.logger.debug('Not a channel event, skip') self.logger.debug('Not a channel event, skip')
return 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) call.event_handler(event)
def run(self, handler): def run(self, handler):
...@@ -316,7 +360,7 @@ def calls(db, callid=None): ...@@ -316,7 +360,7 @@ def calls(db, callid=None):
head = {'call': request.fullpath, 'user': request.params['api'], 'hits': len(calls)} head = {'call': request.fullpath, 'user': request.params['api'], 'hits': len(calls)}
return {'head': head, 'data': calls} return {'head': head, 'data': calls}
except Exception as e: except Exception as e:
logging.error("Got exception: {}".format(e,)) logging.exception(e)
abort(500, "Exception") abort(500, "Exception")
# We first need to check if we can access the callid we asked for # We first need to check if we can access the callid we asked for
try: try:
...@@ -354,7 +398,7 @@ def originate(db, callid=None): ...@@ -354,7 +398,7 @@ def originate(db, callid=None):
return {'header': head, 'data': call} return {'header': head, 'data': call}
except Exception as e: except Exception as e:
logging.debug("Missing params : {}".format([p for p in request.params],)) 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") abort(400, "Missing or incorrect fields, the call cannot be processed")
if __name__ == '__main__': if __name__ == '__main__':
...@@ -365,6 +409,6 @@ if __name__ == '__main__': ...@@ -365,6 +409,6 @@ if __name__ == '__main__':
try: try:
app.run(server=server) app.run(server=server)
except Exception as e: except Exception as e:
logging.error(e) logging.exception(e)
server.stop() server.stop()
raise e 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