Skip to content

Commit

Permalink
Merge branch 'master' of github.com:miglu/plivo
Browse files Browse the repository at this point in the history
  • Loading branch information
bevenky committed May 16, 2011
2 parents 7018529 + f0c1bfe commit 061317d
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 35 deletions.
1 change: 1 addition & 0 deletions src/config/default.conf
Expand Up @@ -27,6 +27,7 @@ FS_INBOUND_ADDRESS = 127.0.0.1:8021
FS_PASSWORD = ClueCon
FS_OUTBOUND_ADDRESS = 127.0.0.1:8084
DEFAULT_ANSWER_URL = http://127.0.0.1:5000/answered/
DEFAULT_HANGUP_URL = http://127.0.0.1:5000/hangup/

# to set different user/group when running in daemon mode :
#FS_OUTBOUND_USER = root
Expand Down
13 changes: 9 additions & 4 deletions src/plivo/rest/freeswitch/inbound_socket.py
Expand Up @@ -127,9 +127,15 @@ def on_channel_state(self, ev):
def hangup_complete(self, request_uuid, call_uuid, reason, ev, hangup_url):
self.log.debug("Call: %s hungup, Reason %s, Request uuid %s"
% (call_uuid, reason, request_uuid))
del self.call_request[request_uuid]
try:
del self.call_request[request_uuid]
except KeyError:
pass
# Check if call cleans up if no user
del self.calls_ring_complete[call_uuid]
try:
del self.calls_ring_complete[call_uuid]
except KeyError:
pass
self.log.debug("Call Cleaned up")
if hangup_url:
params = {'request_uuid': request_uuid, 'call_uuid': call_uuid,
Expand Down Expand Up @@ -170,7 +176,6 @@ def spawn_originate(self, request_uuid):
originate_str = "%s,originate_timeout=%s" \
% (originate_str, gw_timeout_list[0])

answer_url = request_params[7]
outbound_str = "'socket:%s async full' inline" \
% (self.fs_outbound_address)
dial_str = "%s}%s/%s %s" \
Expand All @@ -180,7 +185,7 @@ def spawn_originate(self, request_uuid):
self.bk_jobs[job_uuid] = request_uuid
if not job_uuid:
self.log.error("Calls Failed -- JobUUID not received"
% dial_str)
% dial_str)
# Reduce one from the call request param lists each time
if gw_retry_list:
gw_tries_done += 1
Expand Down
18 changes: 12 additions & 6 deletions src/plivo/rest/freeswitch/outbound_server.py
Expand Up @@ -50,10 +50,12 @@ def __init__(self, configfile, daemon=False,
'rest_server', 'AUTH_ID')
self.auth_token = helpers.get_conf_value(self._config,
'rest_server', 'AUTH_TOKEN')
#This is where we define the connection with the
#Plivo XML grammar Processor
self.default_hangup_url = helpers.get_conf_value(self._config,
'freeswitch', 'DEFAULT_HANGUP_URL')
# This is where we define the connection with the
# Plivo XML grammar Processor
OutboundServer.__init__(self, (fs_host, fs_port),
PlivoOutboundEventSocket, filter)
PlivoOutboundEventSocket, filter)

def _get_request_id(self):
try:
Expand All @@ -65,9 +67,13 @@ def _get_request_id(self):
def do_handle(self, socket, address):
request_id = self._get_request_id()
self.log.info("(%d) New request from %s" % (request_id, str(address)))
self._handle_class(socket, address, self.log, self.default_answer_url,
filter=self._filter, request_id=request_id,
auth_id=self.auth_id, auth_token= self.auth_token)
self._handle_class(socket, address, self.log,
default_answer_url=self.default_answer_url,
default_hangup_url=self.default_hangup_url,
auth_id=self.auth_id,
auth_token=self.auth_token,
request_id=request_id,
filter=self._filter)
self.log.info("(%d) End request from %s" % (request_id, str(address)))

def create_logger(self):
Expand Down
81 changes: 59 additions & 22 deletions src/plivo/rest/freeswitch/outbound_socket.py
Expand Up @@ -61,20 +61,26 @@ class PlivoOutboundEventSocket(OutboundEventSocket):
The instance requests for a XML grammar set to execute the call and acts as a
bridge between Event_Socket and the web application
"""

def __init__(self, socket, address, log, default_answer_url, filter=None,
request_id=0, auth_id="", auth_token=""):
def __init__(self, socket, address, log,
default_answer_url=None,
default_hangup_url=None,
auth_id="",
auth_token="",
request_id=0,
filter=None):
self._request_id = request_id
self._log = log
self.log = RequestLogger(logger=self._log, request_id=self._request_id)
self.xml_response = ""
self.parsed_grammar = []
self.lexed_xml_response = []
self.answer_url = ""
self.hangup_url = ""
self.direction = ""
self.params = None
self._action_queue = gevent.queue.Queue()
self.default_answer_url = default_answer_url
self.default_hangup_url = default_hangup_url
self.answered = False
self._hangup_cause = ''
self.no_answer_grammar = ['Wait', 'Reject', 'Preanswer', 'Dial']
Expand Down Expand Up @@ -126,11 +132,29 @@ def on_channel_hangup(self, event):
self._hangup_cause = event['Hangup-Cause']
self.log.info('Event: channel %s has hung up (%s)' %
(self.get_channel_unique_id(), self._hangup_cause))
if self.hangup_url:
hangup_url = self.hangup_url
elif self.default_hangup_url:
hangup_url = self.default_hangup_url
if hangup_url:
params = {
'call_uuid': self.call_uuid,
'reason': self._hangup_cause
}
encoded_params = urllib.urlencode(params)
request = urllib2.Request(hangup_url, encoded_params)
try:
self.xml_response = urllib2.urlopen(request).read()
self.log.info("Posted to %s with %s" % (hangup_url,
params))
except Exception, e:
self.log.error("Post to %s with %s --Error: %s" \
% (hangup_url, params, e))

def on_channel_hangup_complete(self, event):
if not self._hangup_cause:
self._hangup_cause = event['Hangup-Cause']
self.log.info('Event: channel %s hangup complete (%s)' %
self.log.info('Event: channel %s hangup completed (%s)' %
(self.get_channel_unique_id(), self._hangup_cause))

def has_hangup(self):
Expand All @@ -142,11 +166,11 @@ def get_hangup_cause(self):
return self._hangup_cause

def disconnect(self):
self.log.debug("Releasing connection ...")
self.log.debug("Releasing Connection ...")
super(PlivoOutboundEventSocket, self).disconnect()
# prevent command to be stuck while waiting response
# Prevent command to be stuck while waiting response
self._action_queue.put_nowait(Event())
self.log.debug("Releasing connection done")
self.log.debug("Releasing Connection Done")

def run(self):
self.resume()
Expand All @@ -162,13 +186,18 @@ def run(self):
called_no = channel.get_header('Caller-Destination-Number')
from_no = channel.get_header('Caller-Caller-ID-Number')
self.direction = channel.get_header('Call-Direction')

aleg_uuid = ""
aleg_request_uuid = ""

if self.direction == 'outbound':
# Look for variables in channel headers
aleg_uuid = channel.get_header('Caller-Unique-ID')
aleg_request_uuid = channel.get_header('variable_request_uuid')
self.answer_url = channel.get_header('variable_answer_url')
sched_hangup_id = channel.get_header('variable_sched_hangup_id')
# Don't post hangup in outbound direction
self.default_hangup_url = None
self.hangup_url = None
else:
# Look for an answer url in order below :
# get transfer_url from channel variable
Expand All @@ -179,6 +208,13 @@ def run(self):
self.answer_url = self.get_var('answer_url')
if not self.answer_url:
self.answer_url = self.default_answer_url
# Look for a sched_hangup_id
sched_hangup_id = self.get_var('sched_hangup_id')
# Look for hangup_url
self.hangup_url = self.get_var('hangup_url')

if not sched_hangup_id:
sched_hangup_id = ""

# Post to ANSWER URL and get XML Response
self.params = {
Expand All @@ -187,14 +223,12 @@ def run(self):
'from_no': from_no,
'direction': self.direction,
'aleg_uuid': aleg_uuid,
'aleg_request_uuid': aleg_request_uuid
'aleg_request_uuid': aleg_request_uuid,
'sched_hangup_id': sched_hangup_id
}
# Look for a sched_hangup_id and add it to params if found
self.sched_hangup_id = self.get_var('sched_hangup_id')
if self.sched_hangup_id:
self.params['sched_hangup_id'] = self.sched_hangup_id
# Remove sched_hangup_id from channel vars
self.unset("sched_hangup_id")
if sched_hangup_id:
self.unset("sched_hangup_id")
# Run application
self.log.debug("Processing Call")
self.process_call()
Expand All @@ -206,9 +240,11 @@ def process_call(self):
Parse the XML and Execute it
"""
for x in range(MAX_REDIRECT):
fetch_method = 'POST'
try:
self.fetch_xml(fetch_method)
if self.has_hangup():
self.log.warn("Channel has hung up, breaking Processing Call")
return
self.fetch_xml(method='POST')
if not self.xml_response:
self.log.warn("No XML Response")
return
Expand All @@ -225,15 +261,17 @@ def process_call(self):
self.lexed_xml_response = []
self.log.info("Redirecting to %s to fetch RESTXML" \
% self.answer_url)
gevent.sleep(0.010)
continue
except Exception, e:
# if error occurs during xml parsing
# If error occurs during xml parsing
# log exception and break
self.log.error(str(e))
[ self.log.error(line) for line in \
traceback.format_exc().splitlines() ]
self.log.error("XML error")
return
self.log.warn("Max Redirect reached !")

def fetch_xml(self, method='POST'):
"""
Expand All @@ -247,12 +285,11 @@ def fetch_xml(self, method='POST'):
self.log.info("Requested to %s with %s" % (self.answer_url,
self.params))


def lex_xml(self):
"""
Validate the XML document and make sure we recognize all Grammar
"""
#1. Parse XML into a doctring
# Parse XML into a doctring
xml_str = ' '.join(self.xml_response.split())
try:
#convert the string into an Element instance
Expand All @@ -261,11 +298,11 @@ def lex_xml(self):
raise RESTSyntaxException("Invalid RESTXML Response Syntax: %s"
% str(e))

# 2. Make sure the document has a <Response> root
# Make sure the document has a <Response> root
if doc.tag != "Response":
raise RESTFormatException("No Response Tag Present")

# 3. Make sure we recognize all the Grammar in the xml
# Make sure we recognize all the Grammar in the xml
for element in doc:
invalid_grammar = []
if not hasattr(grammar, element.tag):
Expand Down Expand Up @@ -311,7 +348,7 @@ def parse_children(self, child_element, parent_instance):
def execute_xml(self):
for grammar_element in self.parsed_grammar:
if hasattr(grammar, "prepare"):
# :TODO Prepare grammar concurrently
# TODO Prepare grammar concurrently
grammar_element.prepare()
# Check if it's an inbound call
if self.direction == 'inbound':
Expand Down
7 changes: 4 additions & 3 deletions src/plivo/rest/freeswitch/rest_api.py
Expand Up @@ -223,8 +223,9 @@ def call(self):
msg = "Call Request Executed"
result = True

return flask.jsonify(Success=result, Message=msg,
RequestUUID=request_uuid)
return flask.jsonify(Success=result,
Message=msg,
RequestUUID=request_uuid)

@auth_protect
def bulk_calls(self):
Expand Down Expand Up @@ -362,7 +363,7 @@ def bulk_calls(self):
result = True

return flask.jsonify(Success=result, Message=msg,
RequestUUID=str(request_uuid_list))
RequestUUID=str(request_uuid_list))

@auth_protect
def hangup_call(self):
Expand Down

0 comments on commit 061317d

Please sign in to comment.