Skip to content
GitLab
Menu
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
f1b7815a
Commit
f1b7815a
authored
Apr 27, 2016
by
okhin
Browse files
Let's try to play with bridges and understand how they work
parent
696f9e55
Pipeline
#22
skipped
Changes
1
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
app.py
View file @
f1b7815a
...
...
@@ -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
.
e
rror
(
"Got exception: {}"
.
format
(
e
,)
)
logging
.
e
xception
(
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
.
e
rror
(
e
)
logging
.
e
xception
(
e
)
server
.
stop
()
raise
e
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a 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