Commit 696f9e55 authored by okhin's avatar okhin 🚴

Everything is working, but the redirct

parent c187a7b6
......@@ -8,6 +8,7 @@ import logging
import concurrent.futures
import asyncio
from wsgiref.simple_server import make_server
from operator import itemgetter
from bottle import request, abort, Bottle, ServerAdapter, JSONPlugin
from bottle_sqlite import SQLitePlugin
......@@ -53,7 +54,9 @@ class Call(object):
"""
history = []
actions = {'Created': 'call_caller'
, 'ChannelStateChange': 'change'}
, 'ChannelStateChange': 'change'
, 'ChannelDtmfReceived': 'dtmf'}
def __init__(self, caller, callee, owner, callid=None, db=None):
try:
self.caller = caller
......@@ -72,6 +75,10 @@ class Call(object):
def url(self):
return ''.join(['/calls/', self.id])
def state(self):
sort = sorted(self.history, reverse=True, key=itemgetter(1))
return sort[0][0]
@classmethod
def load(cls, callid, db):
logging.debug("Loading call {}".format(callid,))
......@@ -103,11 +110,57 @@ class Call(object):
if state in self.actions:
getattr(self, self.actions[state])(event=event)
def dtmf(self, event):
'''
We received a DTMF sequence
'''
try:
assert self.state() == '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)
except AssertionError as e:
logging.debug("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'],))
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':
# Call is being picked up, we want to play a song
payload = {}
try:
results = self.db.execute('SELECT login_ari, pass_ari FROM users WHERE api = ?', (self.owner,))
login_ari, token_ari = results.fetchone()
payload['app'] = 'piphone'
payload['api_key'] = ':'.join([login_ari, token_ari])
payload['media'] = 'sound:mario'
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)
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,))
raise e
def call_caller(self, event):
'''
......@@ -125,6 +178,7 @@ class Call(object):
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:
logging.debug("Exception raised in call_caller(): {}".format(e,))
raise e
def save(self):
......@@ -141,19 +195,24 @@ class Call(object):
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
# needs to have both of them.
# He must then send us a JWT token with an API claim in the payload.
# The JWT token must be encoded and signed with the SECRET. If the
# token is bad, we return a 403.
def authenticated(f):
'''
We need a decorator to check if our query is authenticated.
We will store an API key and SECRET in ur database, the client
needs to have both of them.
He must then send us a JWT token with an API claim in the payload.
The JWT token must be encoded and signed with the SECRET. If the
token is bad, we return a 403.
'''
def wrapped(db, *args, **kwargs):
# Let's get the JWT token. It should be a params (from get or post or whatev')
logging.debug("Authetication: {}".format([':'.join([key, request.params[key]]) for key in request.params],))
if 'token' not in request.params:
logging.error("No token found in the params")
abort(401, "No token found in the query")
# We want the api id in the params to.
if 'api' not in request.params:
logging.error("No api id found in the params")
abort(401, "No api id found in the params")
# Now, let's get the token on our side
try:
......@@ -165,6 +224,8 @@ def authenticated(f):
for key in auth_token:
request.params[key] = auth_token[key]
except (jwt.exceptions.InvalidTokenError, AssertionError) as e:
logging.error("Access refused")
logging.debug("InvalidTokenError: {}".format(e))
abort(403, e)
except Exception as e:
abort(500, e)
......@@ -185,11 +246,10 @@ class Server(ServerAdapter):
"""
We're starting the logger subsytem, create the Thread Pool and stuff
"""
self.logger = logging.getLogger(__name__)
self.logger = logging.getLogger('server')
if debug:
self.logger.setLevel(logging.DEBUG)
self.log_handler = logging.FileHandler('app.log')
self.logger.addHandler(self.log_handler)
self.logger.addHandler(logging.FileHandler('app.log'))
self.threads = concurrent.futures.ThreadPoolExecutor()
self.loop = asyncio.get_event_loop()
self.db = sqlite3.connect('call.db')
......@@ -197,12 +257,12 @@ class Server(ServerAdapter):
super(Server, self).__init__(*args, **kwargs)
async def __listen(self):
logger = logging.getLogger('websockets')
logger.setLevel(logging.DEBUG)
logger.addHandler(self.log_handler)
ws_logger = logging.getLogger('websockets')
ws_logger.setLevel(logging.DEBUG)
ws_logger.addHandler(logging.FileHandler('app.log'))
async with websockets.connect('ws://185.34.33.12:8088/ari/events?app=piphone&api_key=piphone:passpiphone') as websocket:
while self.running == True:
logger.debug("Waiting for events")
ws_logger.info("Waiting for events on websocket")
event = await websocket.recv()
# Let's call the applications function
await self.dispatch(json.loads(event))
......@@ -269,7 +329,7 @@ def calls(db, callid=None):
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.debug("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:
......@@ -305,7 +365,6 @@ if __name__ == '__main__':
try:
app.run(server=server)
except Exception as e:
print(e)
logging.error(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