starpy.fastagi
index
/home/mcfletch/pylive/starpy/fastagi.py

Asterisk FastAGI server for use from the dialplan
 
You use an asterisk FastAGI like this from extensions.conf:
 
        exten => 1000,3,AGI(agi://127.0.0.1:4573,arg1,arg2)
 
Where 127.0.0.1 is the server and 4573 is the port on which 
the server is listening.
 
Module defines a standard Python logging module log 'FastAGI'

 
Modules
       
twisted.protocols.basic
twisted.internet.defer
starpy.error
logging
twisted.internet.protocol
socket
time

 
Classes
       
object
InSequence
Factory
FastAGIFactory
LineOnlyReceiver(Protocol)
FastAGIProtocol

 
class FastAGIFactory(Factory)
    Factory generating FastAGI server instances
 
  Methods defined here:
__init__(self, mainFunction)
Initialise the factory
 
mainFunction -- function taking a connected FastAGIProtocol instance 
        this is the function that's run when the Asterisk server connects.

Data and other attributes defined here:
protocol = <class starpy.fastagi.FastAGIProtocol>
Protocol for the interfacing with the Asterisk FastAGI application
 
Attributes:
 
        variables -- for  connected protocol, the set of variables passed 
                during initialisation, keys are all-lower-case
        
        # Internal:
        readingVariables -- whether the instance is still in initialising by
                reading the setup variables from the connection 
        messageCache -- stores incoming variables 
        pendingMessages -- set of outstanding messages for which we expect 
                replies
        delimiter -- uses bald newline instead of carriage-return-newline
 
XXX Lots of problems with data-escaping, no docs on how to escape special 
        characters that I can see...

Methods inherited from Factory:
buildProtocol(self, addr)
Create an instance of a subclass of Protocol.
 
The returned instance will handle input on an incoming server
connection, and an attribute "factory" pointing to the creating
factory.
 
Override this method to alter how Protocol instances get created.
 
@param addr: an object implementing L{twisted.internet.interfaces.IAddress}
doStart(self)
Make sure startFactory is called.
 
Users should not call this function themselves!
doStop(self)
Make sure stopFactory is called.
 
Users should not call this function themselves!
startFactory(self)
This will be called before I begin listening on a Port or Connector.
 
It will only be called once, even if the factory is connected
to multiple ports.
 
This can be used to perform 'unserialization' tasks that
are best put off until things are actually running, such
as connecting to a database, opening files, etcetera.
stopFactory(self)
This will be called before I stop listening on all Ports/Connectors.
 
This can be overridden to perform 'shutdown' tasks such as disconnecting
database connections, closing files, etc.
 
It will be called, for example, before an application shuts down,
if it was connected to a port. User code should not call this function
directly.

Data and other attributes inherited from Factory:
__implemented__ = <implementedBy twisted.internet.protocol.Factory>
__implements__ = (<MetaInterface twisted.internet.interfaces.IProtocolFactory>,)
__providedBy__ = <zope.interface.declarations.Declaration object>
noisy = True
numPorts = 0

 
class FastAGIProtocol(LineOnlyReceiver)
    Protocol for the interfacing with the Asterisk FastAGI application
 
Attributes:
 
        variables -- for  connected protocol, the set of variables passed 
                during initialisation, keys are all-lower-case
        
        # Internal:
        readingVariables -- whether the instance is still in initialising by
                reading the setup variables from the connection 
        messageCache -- stores incoming variables 
        pendingMessages -- set of outstanding messages for which we expect 
                replies
        delimiter -- uses bald newline instead of carriage-return-newline
 
XXX Lots of problems with data-escaping, no docs on how to escape special 
        characters that I can see...
 
 
Method resolution order:
FastAGIProtocol
LineOnlyReceiver
Protocol
BaseProtocol

Methods defined here:
__init__(self, *args, **named)
Initialise the AMIProtocol, arguments are ignored
answer(self)
Answer the channel (go off-hook)
 
Returns deferred integer response code
channelStatus(self, channel=None)
Retrieve the current channel's status
 
Result integers (from the wiki):
        0 Channel is down and available
        1 Channel is down, but reserved
        2 Channel is off hook
        3 Digits (or equivalent) have been dialed
        4 Line is ringing
        5 Remote end is ringing
        6 Line is up
        7 Line is busy 
 
Returns deferred integer result code
 
This could be used to decide if we can forward the channel to a given 
user, or whether we need to shunt them off somewhere else.
checkFailure(self, result, failure='-1')
(Internal) Check for a failure-code, raise error if == result
connectionLost(self, reason)
(Internal) Handle loss of the connection (remote hangup)
connectionMade(self)
(Internal) Handle incoming connection (new AGI request)
 
Initiates read of the initial attributes passed by the server
controlStreamFile(self, filename, escapeDigits, skipMS=0, ffChar='*', rewChar='#', pauseChar=None)
Playback specified file with ability to be controlled by user
 
filename -- filename to play (on the asterisk server) 
        (don't use file-type extension!)
escapeDigits -- if provided, 
skipMS -- number of milliseconds to skip on FF/REW
ffChar -- if provided, the set of chars that fast-forward
rewChar -- if provided, the set of chars that rewind
pauseChar -- if provided, the set of chars that pause playback
 
returns deferred (digit,endpos) on success, or errors on failure, 
        note that digit will be 0 if no digit was pressed AFAICS
databaseDel(self, family, key)
Delete the given key from the database
 
Returns deferred integer result code
databaseDeltree(self, family, keyTree=None)
Delete an entire family or a tree within a family from database
 
Returns deferred integer result code
databaseGet(self, family, key)
Retrieve value of the given key from database
 
Returns deferred string value for the key
databasePut = databaseSet(self, family, key, value)
databaseSet(self, family, key, value)
Set value of the given key to database
 
a.k.a databasePut on the asterisk side
 
Returns deferred integer result code
dateAsSeconds(self, date)
(Internal) Convert date to asterisk-compatible format
execute(self, application, *options)
Execute a dialplan application with given options
 
Note: asterisk calls this "exec", which is Python keyword
 
Returns deferred string result for the application, which 
may have failed, result values are application dependant.
finish(self)
Finish the AGI "script" (drop connection)
 
This command simply drops the connection to the Asterisk server,
which the FastAGI protocol interprets as a successful termination.
 
Note: There *should* be a mechanism for sending a "result" code,
but I haven't found any documentation for it.
getData(self, filename, timeout=2000, maxDigits=None)
Playback file, collecting up to maxDigits or waiting up to timeout
 
filename -- filename without extension to play
timeout -- timeout in milliseconds
maxDigits -- maximum number of digits to collect
 
returns deferred (str(digits), bool(timedOut))
getOption(self, filename, escapeDigits, timeout=None)
Playback file, collect 1 digit or timeout (return 0)
 
returns ??? XXX Wiki seems wrong about what it returns...
getVariable(self, variable)
Retrieve the given channel variable
 
Returns deferred string value for the key
hangup(self, channel=None)
Cause the server to hang up on the channel
 
Returns deferred integer response code
 
Note: This command just doesn't seem to work with Asterisk 1.2.1,
connected channels just remain connected.
lineReceived(self, line)
(Internal) Handle Twisted's report of an incoming line from the manager
noop(self)
Send a null operation to the server
 
Returns deferred integer response code
onStreamingComplete(self, resultLine, skipMS=0)
(Internal) Handle putative success, watch for failure-on-load problems
receiveChar(self, timeout=None)
Receive a single text char on text-supporting channels (rare)
 
returns deferred (char, bool(timeout))
receiveText(self, timeout=None)
Receive text until timeout
 
Returns deferred string response value (unaltered)
recordFile(self, filename, format, escapeDigits, timeout=-1, offsetSamples=None, beep=True, silence=None)
Record channel to given filename until escapeDigits or silence
 
filename -- filename on the server to which to save 
format -- encoding format in which to save data
escapeDigits -- digits which end recording 
timeout -- maximum time to record, -1 gives infinite
offsetSamples -- move into file this number of samples before recording?
        XXX check semantics here.
beep -- if true, play a Beep on channel to indicate start of recording
silence -- if specified, silence duration to trigger end of recording 
 
returns deferred (str(code/digits), typeOfExit, endpos)
 
Where known typeOfExits include:
        hangup, code='0'
        dtmf, code=digits-pressed 
        timeout, code='0'
resultAsInt(self, result)
(Internal) Convert result to an integer value
resultPlusTimeoutFlag(self, resultLine)
(Internal) Result followed by optional flag declaring timeout
sayAlpha(self, string, escapeDigits=None)
Spell out character string to the user until escapeDigits
 
returns deferred 0 or the digit pressed
sayDate(self, date, escapeDigits=None)
Spell out the date (with somewhat unnatural form)
 
See sayDateTime with format 'ABdY' for a more natural reading
 
returns deferred 0 or digit-pressed as integer
sayDateTime(self, time, escapeDigits='', format=None, timezone=None)
Say given date/time in given format until escapeDigits
 
time -- datetime or float-seconds-since-epoch
escapeDigits -- digits to cancel playback 
format -- strftime-style format for the date to be read 
        'filename' -- filename of a soundfile (single ticks around the filename required)
        A or a -- Day of week (Saturday, Sunday, ...)
        B or b or h -- Month name (January, February, ...)
        d or e -- numeric day of month (first, second, ..., thirty-first)
        Y -- Year
        I or l -- Hour, 12 hour clock
        H -- Hour, 24 hour clock (single digit hours preceded by "oh")
        k -- Hour, 24 hour clock (single digit hours NOT preceded by "oh")
        M -- Minute
        P or p -- AM or PM
        Q -- "today", "yesterday" or ABdY (*note: not standard strftime value)
        q -- "" (for today), "yesterday", weekday, or ABdY (*note: not standard strftime value)
        R -- 24 hour time, including minute
        
        Default format is "ABdY 'digits/at' IMp"
timezone -- optional timezone name from /usr/share/zoneinfo
 
returns deferred 0 or digit-pressed as integer
sayDigits(self, number, escapeDigits=None)
Spell out the number/string as a string of digits
 
returns deferred 0 or digit-pressed as integer
sayNumber(self, number, escapeDigits=None)
Say a number in natural form
 
returns deferred 0 or digit-pressed as integer
sayPhonetic(self, string, escapeDigits=None)
Say string using phonetics
 
returns deferred 0 or digit-pressed as integer
sayTime(self, time, escapeDigits=None)
Say string using phonetics
 
returns deferred 0 or digit-pressed as integer
sayXXX(self, baseCommand, value, escapeDigits='')
Underlying implementation for the common-api sayXXX functions
secondResultItem(self, result)
(Internal) Retrieve the second item on the result-line
sendCommand(self, commandString)
(Internal) Send the given command to the other side
sendImage(self, filename)
Send image on those channels which support sending images (rare)
 
returns deferred integer result code
sendText(self, text)
Send text on text-supporting channels (rare)
 
returns deferred integer result code
setAutoHangup(self, time)
Set channel to automatically hang up after time seconds
 
returns deferred integer result code
setCallerID(self, number)
Set channel's caller ID to given number
 
returns deferred integer result code
setContext(self, context)
Move channel to given context (no error checking is performed)
 
returns deferred integer result code
setExtension(self, priority)
Move channel to given priority or drop if not there
 
returns deferred integer result code
setMusic(self, on=True, musicClass=None)
Enable/disable and/or choose music class for channel's music-on-hold
 
returns deferred integer result code
setVariable(self, variable, value)
Set given channel variable to given value
 
returns deferred integer result code
streamFile(self, filename, escapeDigits='', offset=0)
Stream given file until escapeDigits starting from offset
 
returns deferred (str(digit), int(endpos)) for playback
 
Note: streamFile is apparently unstable in AGI, may want to use
execute( 'PLAYBACK', ... ) instead (according to the Wiki)
tddMode(self, on=True)
Set TDD mode on the channel if possible (ZAP only ATM)
 
on -- ON (True), OFF (False) or MATE (None)
 
returns deferred integer result code
verbose(self, message, level=None)
Send a logging message to the asterisk console for debugging etc
 
message -- text to pass 
level -- 1-4 denoting verbosity level
 
returns deferred integer result code
wait(self, duration)
Wait for X seconds (just a wrapper around callLater, doesn't talk to server)
 
returns deferred which fires some time after duration seconds have 
passed
waitForDigit(self, timeout)
Wait up to timeout seconds for single digit to be pressed 
 
timeout -- timeout in seconds or -1 for infinite timeout 
 
returns deferred 0 on timeout or digit

Data and other attributes defined here:
delimiter = '\n'
readingVariables = False

Methods inherited from LineOnlyReceiver:
dataReceived(self, data)
Translates bytes into lines, and calls lineReceived.
lineLengthExceeded(self, line)
Called when the maximum line length has been reached.
Override if it needs to be dealt with in some special way.
sendLine(self, line)
Sends a line to the other end of the connection.

Data and other attributes inherited from LineOnlyReceiver:
MAX_LENGTH = 16384

Data and other attributes inherited from Protocol:
__implemented__ = <implementedBy twisted.internet.protocol.Protocol>
__implements__ = (<MetaInterface twisted.internet.interfaces.IProtocol>,)

Methods inherited from BaseProtocol:
makeConnection(self, transport)
Make a connection to a transport and a server.
 
This sets the 'transport' attribute of this Protocol, and calls the
connectionMade() callback.

Data and other attributes inherited from BaseProtocol:
__providedBy__ = <zope.interface.declarations.Declaration object>
connected = 0
transport = None

 
class InSequence(object)
    Single-shot item creating a set of actions to run in sequence
 
  Methods defined here:
__call__(self)
Return deferred that fires when we are finished processing all items
__init__(self)
append(self, function, *args, **named)
Append an action to the set of actions to process
onActionFailure(self, reason, finalDF)
Handle individual-action failure
onActionSuccess(self, result, finalDF)
Handle individual-action success

Data and other attributes defined here:
__dict__ = <dictproxy object>
dictionary for instance variables (if defined)
__weakref__ = <attribute '__weakref__' of 'InSequence' objects>
list of weak references to the object (if defined)

 
Data
        FAILURE_CODE = -1
reactor = <twisted.internet.selectreactor.SelectReactor instance>