Skip to content

Instantly share code, notes, and snippets.

@karthicraghupathi
Last active October 3, 2020 18:23
Show Gist options
  • Save karthicraghupathi/9666ff29407301e3e2a5630402bc6f37 to your computer and use it in GitHub Desktop.
Save karthicraghupathi/9666ff29407301e3e2a5630402bc6f37 to your computer and use it in GitHub Desktop.
Asterisk AMI over TCP - Dialer & OriginateResponse Listener with pystrix
import pystrix
CHANNEL_DRIVER_SIP = 'SIP'
CHANNEL_DRIVER_PJIP = 'PJSIP'
class Dialer(object):
_host = _username = _password = _manager = _channel_driver = None
def __init__(
self, host, username, password, channel_driver=CHANNEL_DRIVER_PJIP
):
self._host = host
self._username = username
self._password = password
self._channel_driver = channel_driver
self._manager = pystrix.ami.Manager()
self._connect()
challenge_response = self._challenge()
if not challenge_response or not challenge_response.success:
raise ConnectionError(
"Asterisk did not provide an MD5 challenge token"
+ (challenge_response is None and ": timed out" or "")
)
login_response = self._login(challenge_response)
if not login_response or not login_response.success:
raise ConnectionError(
"Attempt to login to Asterisk server failed"
+ (login_response is None and ": timed out" or "")
)
def _connect(self):
self._manager.connect(self._host)
def _challenge(self):
return self._manager.send_action(pystrix.ami.core.Challenge())
def _login(self, challenge_response):
return self._manager.send_action(pystrix.ami.core.Login(
self._username,
self._password,
events=False,
challenge=challenge_response.result["Challenge"]
))
def originate(
self, action_id, callerid, phone=None,
channel=None, context='default', priority=1, extension=None,
timeout_secs=60, variables=None, account=None, async_=True,
carrier_context='Outbound'
):
if not phone and not channel:
raise Exception('Either phone or channel should be provided.')
if phone:
channel = '{}/{}@{}'.format(
self._channel_driver, phone, carrier_context
)
if not extension:
extension = callerid
if not variables:
variables = dict()
return self._manager.send_action(
pystrix.ami.core.Originate_Context(
channel,
context,
extension,
priority,
timeout=timeout_secs * 1000,
callerid=callerid,
variables=variables,
account=account,
async_=async_
),
action_id=action_id
)
if __name__ == "__main__":
host = ""
username = ""
password = ""
busy_action_id = '5f78b020b7326f279dde3ce1'
busy_phone = '8005559939'
good_action_id = '5f78b020b7326f279dde3ce2'
good_phone = ''
callerid = ''
dialer = Dialer(host, username, password)
result = dialer.originate(busy_action_id, callerid, phone=busy_phone)
print(result)
result = dialer.originate(good_action_id, callerid, phone=good_phone)
print(result)
import time
import pystrix
_HOST = ""
_USERNAME = ""
_PASSWORD = ""
class AMICore(object):
_manager = None
_kill_flag = False
def __init__(self):
self._manager = pystrix.ami.Manager()
self._register_callbacks()
try:
self._manager.connect(_HOST)
challenge_response = self._manager.send_action(pystrix.ami.core.Challenge())
if challenge_response and challenge_response.success:
action = pystrix.ami.core.Login(
_USERNAME,
_PASSWORD,
challenge=challenge_response.result["Challenge"],
)
self._manager.send_action(action)
else:
self._kill_flag = True
raise ConnectionError(
"Asterisk did not provide an MD5 challenge token"
+ (challenge_response is None and ": timed out" or "")
)
except pystrix.ami.ManagerSocketError as e:
self._kill_flag = True
raise ConnectionError(
"Unable to connect to Asterisk server: %(error)s"
% {
"error": str(e),
}
)
except pystrix.ami.core.ManagerAuthError as reason:
self._kill_flag = True
raise ConnectionError(
"Unable to authenticate to Asterisk server: %(reason)s"
% {
"reason": reason,
}
)
except pystrix.ami.ManagerError as reason:
self._kill_flag = True
raise ConnectionError(
"An unexpected Asterisk error occurred: %(reason)s"
% {
"reason": reason,
}
)
self._manager.monitor_connection()
def _register_callbacks(self):
self._manager.register_callback(
pystrix.ami.core_events.FullyBooted, self._handle_event
)
self._manager.register_callback(
pystrix.ami.core_events.OriginateResponse, self._handle_event
)
self._manager.register_callback(None, self._handle_event)
self._manager.register_callback("Shutdown", self._handle_shutdown)
def _handle_shutdown(self, event, manager):
self._kill_flag = True
def _handle_event(self, event, manager):
if 'OriginateResponse' == event['Event']:
headers, data = event.process()
headers['Reason'] = pystrix.ami.core.ORIGINATE_RESULT_MAP.get(
headers['Reason'], headers['Reason']
)
print(headers)
def is_alive(self):
return not self._kill_flag
def kill(self):
self._manager.close()
class Error(Exception):
pass
class ConnectionError(Error):
pass
if __name__ == "__main__":
ami_core = AMICore()
while ami_core.is_alive():
time.sleep(1)
ami_core.kill()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment