Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
La Quadrature du Net
piphone
piphone-sip
Commits
696f9e55
Commit
696f9e55
authored
Apr 27, 2016
by
okhin
Browse files
Everything is working, but the redirct
parent
c187a7b6
Changes
1
Hide whitespace changes
Inline
Side-by-side
app.py
View file @
696f9e55
...
...
@@ -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
.
deb
u
g
(
"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
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment