[sip/asterisk] Une classe pour écrire des applications AGI

This commit is contained in:
Valentin Samir 2013-12-21 03:31:27 +01:00
parent 8b724825bc
commit 8ce6d5d4e8

View file

@ -10,7 +10,9 @@ import shutil
import syslog import syslog
import socket import socket
import base64 import base64
import syslog
import psycopg2 import psycopg2
import threading
import psycopg2.extras import psycopg2.extras
from datetime import datetime from datetime import datetime
@ -202,7 +204,7 @@ class History(object):
class Manager(object): class Manager(object):
def __init__(self, username, password, timeout=10, server='asterisk.adm.crans.org', port=5038, debug=False, event=False, auto_connect=True): def __init__(self, username, password, timeout=10, server='asterisk.adm.crans.org', port=5038, debug=False, event=False, auto_connect=True, agi=None):
self.timeout = timeout self.timeout = timeout
self.server = server self.server = server
self.port = port self.port = port
@ -214,6 +216,7 @@ class Manager(object):
self._event=[] self._event=[]
self._event_callback = {} self._event_callback = {}
self._toread = "" self._toread = ""
self._agi = agi
self.fullybooted = False self.fullybooted = False
self.username = username self.username = username
@ -223,6 +226,11 @@ class Manager(object):
if auto_connect: if auto_connect:
self.connect() self.connect()
def agi(self, *args, **kwargs):
if not self._agi:
self._agi = AGI(*args, manager=self, **kwargs)
return self._agi
def _FullyBooted(self, manager, params): def _FullyBooted(self, manager, params):
manager.fullybooted = True manager.fullybooted = True
@ -246,7 +254,7 @@ class Manager(object):
def _parse_msg(self, msg): def _parse_msg(self, msg):
msg = msg.strip().split('\r\n') msg = msg.strip().split('\r\n')
type, value = msg[0].split(': ', 1) type, value = msg[0].split(': ', 1)
params = dict([line.split(': ', 1) for line in msg[1:]]) params = dict([line.split(': ', 1) if len(line.split(': ', 1))==2 else (line.split(': ', 1)[0], '') for line in msg[1:]])
handler = getattr(self, "_do_"+type, None) handler = getattr(self, "_do_"+type, None)
handler(value, params) handler(value, params)
@ -339,6 +347,10 @@ class Manager(object):
raise EnvironmentError("%r should be a list or a bool" % param) raise EnvironmentError("%r should be a list or a bool" % param)
return self.action('events', eventmask=eventmask) return self.action('events', eventmask=eventmask)
def hangup(self, channel):
"""Hangup a channel"""
return self.action('hangup', channel=channel)
def reload(self, module): def reload(self, module):
"""Synopsis: Send a reload event """Synopsis: Send a reload event
Privilege: system,config,all""" Privilege: system,config,all"""
@ -351,3 +363,103 @@ class Manager(object):
if body_type == "str": if body_type == "str":
body = base64.b64encode(body).strip() body = base64.b64encode(body).strip()
return self._action('messageSend', {'to':dst, 'from':src, 'base64body':body}) return self._action('messageSend', {'to':dst, 'from':src, 'base64body':body})
class AGI(object):
"""voir http://www.voip-info.org/wiki/view/Asterisk+AGI"""
def __init__(self, read=sys.stdin, write=sys.stdout, manager=None, **params):
self.debug = True
self.read=read
self.write=write
self.params=params
self._manager=manager
self._lock=False
self._locklock = threading.Lock()
self._read_params()
def manager(self, *args, **kwargs):
if not self._manager:
self._manager=Manager(*args, agi=self, **kwargs)
return self._manager
def __getitem__(self, key):
try:
return self.params[key]
except KeyError:
(result, data) = self.command("GET VARIABLE", key)
if int(result) != 1:
raise KeyError(key)
return data[1:-2]
def __setitem__(self, key, value):
if key in self.params.keys():
raise ValueError("ReadOnly value")
else:
(result, data) = self.command("SET VARIABLE", key, value)
return result
def _read_params(self):
line=self.read.readline()
while line.strip():
syslog.syslog(line)
if line.startswith('agi_'):
(key, data) = line[4:].split(':',1)
self.params[key.strip()]=data.strip()
line = self.read.readline()
def command(self, name, *params):
with self._locklock:
if self._lock:
raise AsteriskError("Cannot lauch AGI command %s, an other command is processing" % name, name, params)
else:
self._lock = True
cmd=' '.join([name] + ["%s" % p for p in params])
if self.debug:
syslog.syslog("%s\n" % cmd)
self.write.write("%s\n" % cmd)
self.write.flush()
line=self.read.readline()
if self.debug:
syslog.syslog(line)
lines=[line]
code=int(line[0:3])
type=line[3]
if type == '-':
while not "%s End of " % code not in line:
line=self.read.readline()
if self.debug:
syslog.syslog("%s\n" % cmd)
lines.append(line)
self._lock=False
if code != 200:
raise AsteriskError((code, '\n'.join(lines)), name, params)
try:
(result, data) = lines[0][4:].split(' ', 1)
except ValueError:
result = lines[0][4:]
data=""
result=result.split('=',1)[1].strip()
return (int(result), data)
def hangup(self):
self.command("hangup")
def set_callerid(self, callerid):
self.command("set_callerid", callerid)
def noop(self, str):
self.command("noop", str)
def launch_app(self, app, *params):
self.command("exec", app, *params)
def dial(self, to):
self.launch_app("dial", to)
def goto(self, arg):
self.launch_app("goto", arg)
### TODO
class FastAGI(object):
def __init__(self, bind, port, *args,**kwargs):
pass