event_socket connection lib for twisted python apps

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@5828 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Traun Leyden 2007-10-07 16:47:10 +00:00
parent 01e2f20bc0
commit bf98f981e1
13 changed files with 2347 additions and 0 deletions

View File

@ -0,0 +1,4 @@
- Add /path/to/freeswitch/scripts/socket to your PYTHONPATH
- Copy/Paste the code from test1() in fshelper.py to your own test module
- Adapt code as needed and run

View File

@ -0,0 +1,3 @@
Socket library to interface w/ freeswitch mod_event_socket from Twisted python applications.

View File

@ -0,0 +1,336 @@
"""
FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
Version: MPL 1.1
The contents of this file are subject to the Mozilla Public License Version
1.1 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.
The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
The Initial Developer of the Original Code is
Anthony Minessale II <anthmct@yahoo.com>
Portions created by the Initial Developer are Copyright (C)
the Initial Developer. All Rights Reserved.
Contributor(s): Traun Leyden <tleyden@branchcut.com>
"""
import sys
from twisted.internet import reactor, defer
from twisted.protocols.basic import LineReceiver
from twisted.internet.protocol import Protocol, ClientFactory
from twisted.python import failure
import time, re
from time import strftime
from Queue import Queue
from freepy import request
"""
freepy library -- connect to freeswitch mod_socket_event via python/twisted
All commands currently use api instead of bgapi. For the networking model
used (twisted), this seems to work well and is simpler.
"""
class FreepyDispatcher(LineReceiver):
def __init__(self, conncb, discocb=None):
self.delimiter='\n' # parent class uses this
self.conncb=conncb
self.discocb=discocb
self.requestq = Queue() # queue of pending requests
self.active_request = None # the current active (de-queued) request
def connectionMade(self):
self.conncb(self)
def connectionLost(self, reason):
if self.discocb:
self.discocb(reason)
print "connectionLost: %s" % reason
def login(self, passwd):
"""
send login request
"""
msg = "auth %s" % passwd
req = request.LoginRequest()
self.requestq.put(req)
self.transport.write("%s\n\n" % msg)
return req.getDeferred()
def confdialout(self, conf_name, sofia_url, bgapi=True):
"""
Instruct conference to join a particular user via dialout
@param conf_name - the name of the conference (arbitrary)
@param party2dial - a freeswitch sofia url, eg, sofia/mydomain.com/foo@bar.com
@return - a deferred that will be called back with a string like:
Reply-Text: +OK Job-UUID: 4d410a8e-2409-11dc-99bf-a5e17fab9c65
"""
if bgapi == True:
msg = "bgapi conference %s dial %s" % (conf_name,
sofia_url)
req = request.BgDialoutRequest()
else:
msg = "api conference %s dial %s" % (conf_name,
sofia_url)
req = request.DialoutRequest()
self.requestq.put(req)
self.transport.write("%s\n\n" % msg)
return req.getDeferred()
def originate(self, party2dial, dest_ext_app, bgapi=True):
if bgapi == True:
msg = "bgapi originate %s %s" % (party2dial,
dest_ext_app)
req = request.BgDialoutRequest()
else:
msg = "api originate %s %s" % (party2dial,
dest_ext_app)
req = request.DialoutRequest()
self.requestq.put(req)
self.transport.write("%s\n\n" % msg)
return req.getDeferred()
def listconf(self, conf_name):
"""
List users in a conf
@param conf_name - the name of the conference (arbitrary)
@return - a deferred that will be called back with an array
of models.ConfMember instances
"""
msg = "api conference %s list" % (conf_name)
req = request.ListConfRequest()
self.requestq.put(req)
self.transport.write("%s\n\n" % msg)
return req.getDeferred()
def confkick(self, member_id, conf_name, bgapi=False):
"""
Kick member_id from conf
conf_name - name of conf
member_id - member id of user to kick, eg, "7"
returns - a deferred that will be called back with a result
like:
TODO: add this
"""
if bgapi == True:
msg = "bgapi conference %s kick %s" % (conf_name, member_id)
req = request.BgConfKickRequest()
else:
msg = "api conference %s kick %s" % (conf_name, member_id)
req = request.ConfKickRequest()
self.requestq.put(req)
self.transport.write("%s\n\n" % msg)
return req.getDeferred()
def confdtmf(self, member_id, conf_name, dtmf, bgapi=False):
"""
Send dtmf to member_id or to all members
conf_name - name of conf
member_id - member id of user to kick, eg, "7"
dtmf - a single dtmf or a string of dtms, eg "1" or "123"
returns - a deferred that will be called back with a result
like:
TODO: add this
"""
print "confdtmf called"
if bgapi == True:
msg = "bgapi conference %s dtmf %s %s" % \
(conf_name, member_id, dtmf)
req = request.BgApiRequest()
else:
msg = "api conference %s dtmf %s %s" % \
(conf_name, member_id, dtmf)
req = request.ApiRequest()
self.requestq.put(req)
print "sending to fs: %s" % msg
self.transport.write("%s\n\n" % msg)
return req.getDeferred()
def confsay(self, conf_name, text2speak, bgapi=False):
"""
Speak text all members
conf_name - name of conf
dtmf - text to speak
returns - a deferred that will be called back with a result
like:
TODO: add this
"""
if bgapi == True:
msg = "bgapi conference %s say %s" % \
(conf_name, text2speak)
req = request.BgApiRequest()
else:
msg = "api conference %s say %s" % \
(conf_name, text2speak)
req = request.ApiRequest()
self.requestq.put(req)
print "sending to fs: %s" % msg
self.transport.write("%s\n\n" % msg)
return req.getDeferred()
def confplay(self, conf_name, snd_url, bgapi=False):
"""
Play a file to all members
conf_name - name of conf
dtmf - text to speak
returns - a deferred that will be called back with a result
like:
TODO: add this
"""
if bgapi == True:
msg = "bgapi conference %s play %s" % \
(conf_name, snd_url)
req = request.BgApiRequest()
else:
msg = "api conference %s play %s" % \
(conf_name, snd_url)
req = request.ApiRequest()
self.requestq.put(req)
print "sending to fs: %s" % msg
self.transport.write("%s\n\n" % msg)
return req.getDeferred()
def confstop(self, conf_name, bgapi=False):
"""
Stop playback of all sound files
conf_name - name of conf
returns - a deferred that will be called back with a result
like:
TODO: add this
"""
if bgapi == True:
msg = "bgapi conference %s stop" % \
(conf_name)
req = request.BgApiRequest()
else:
msg = "api conference %s stop" % \
(conf_name)
req = request.ApiRequest()
self.requestq.put(req)
print "sending to fs: %s" % msg
self.transport.write("%s\n\n" % msg)
return req.getDeferred()
def showchannels(self, bgapi=False):
"""
Get a list of all live channels on switch
returns - a deferred that will be called back with a result
<result row_count="2">
<row row_id="1">
<uuid>21524b8c-6d19-11dc-9380-357de4a7a612</uuid>
<created>2007-09-27 11:46:01</created>
<name>sofia/test/4761</name>
<state>CS_LOOPBACK</state>
<cid_name>FreeSWITCH</cid_name>
<cid_num>0000000000</cid_num>
<ip_addr></ip_addr>
<dest>outgoing2endpoint-6207463</dest>
<application>echo</application>
<application_data></application_data>
<read_codec>PCMU</read_codec>
<read_rate>8000</read_rate>
<write_codec>PCMU</write_codec>
<write_rate>8000</write_rate>
</row>
...
</result>
"""
if bgapi == True:
msg = "bgapi show channels as xml"
req = request.BgApiRequest()
else:
msg = "api show channels as xml"
req = request.ApiRequest()
self.requestq.put(req)
self.transport.write("%s\n\n" % msg)
return req.getDeferred()
def sofia_status_profile(self, profile_name, bgapi=False):
# DO NOT USE - TOTALLY BROKEN
# FS DOES NOT RETURN XML IN THIS CASE
if bgapi == True:
msg = "bgapi sofia status profile %s as xml" % (profile_name)
req = request.BgApiRequest()
else:
msg = "api sofia status profile %s as xml" % (profile_name)
req = request.ApiRequest()
self.requestq.put(req)
print "sending to fs: %s" % msg
self.transport.write("%s\n\n" % msg)
return req.getDeferred()
def sofia_profile_restart(self, sofia_profile_name, bgapi = False):
if bgapi == True:
msg = "bgapi sofia profile %s restart" % \
(sofia_profile_name)
req = request.BgApiRequest()
else:
msg = "api sofia profile %s restart" % \
(sofia_profile_name)
req = request.ApiRequest()
self.requestq.put(req)
print "sending to fs: %s" % msg
self.transport.write("%s\n\n" % msg)
return req.getDeferred()
def killchan(self, uuid, bgapi = False):
if bgapi == True:
msg = "bgapi killchan %s" % (uuid)
req = request.BgApiRequest()
else:
msg = "api killchan %s" % (uuid)
req = request.ApiRequest()
self.requestq.put(req)
print "sending to fs: %s" % msg
self.transport.write("%s\n\n" % msg)
return req.getDeferred()
def lineReceived(self, line):
if not self.active_request:
# if no active request, dequeue a new one
if self.requestq.empty():
# we are receiving data from fs without an
# active request pending. that means that
# there is a bug in the protocol handler
# (or possibly in fs)
raise Exception("Received line: %s w/ no pending requests" % line)
self.active_request = self.requestq.get()
# tell the request to process the line, and tell us
# if its finished or not. if its finished, we remove it
# as the active request so that a new active request will
# be de-queued.
finished = self.active_request.process(line)
if finished == True:
self.active_request = None

View File

@ -0,0 +1,96 @@
%start MainMap::Startup
%class ApiRequest
%map MainMap
%%
Startup
{
ApiResponse
ApiResponseStarted
{
}
}
ApiResponseStarted
{
ContentLength
ContentPreStarted
{
}
}
ContentPreStarted
{
BlankLine
ContentStarted
{
}
}
ContentStarted
{
ProcessLine(line)
[ctxt.add_content(line) == True]
Startup
{
setRequestFinished(); callbackDeferred(ctxt.getResponse());
}
ProcessLine(line)
nil
{
// for some reason, have to add doNothing() here or
// importing smc will fail. looks like smc bug.
doNothing();
}
}
Default
{
BlankLine
nil
{
setRequestFinished();
errbackDeferred("Protocol failure");
}
ContentFinished
nil
{
setRequestFinished();
errbackDeferred("Protocol failure");
}
ContentLength
nil
{
setRequestFinished();
errbackDeferred("Protocol failure");
}
ApiResponse
nil
{
setRequestFinished();
errbackDeferred("Protocol failure");
}
ProcessLine(line)
nil
{
setRequestFinished();
errbackDeferred("Protocol failure");
}
}
%%

View File

@ -0,0 +1,206 @@
# DO NOT MODIFY THIS CODE - AUTOMATICALLY GENERATED BY SMC
import statemap
class ApiRequestState(statemap.State):
def Entry(self, fsm):
pass
def Exit(self, fsm):
pass
def ApiResponse(self, fsm):
self.Default(fsm)
def BlankLine(self, fsm):
self.Default(fsm)
def ContentFinished(self, fsm):
self.Default(fsm)
def ContentLength(self, fsm):
self.Default(fsm)
def ProcessLine(self, fsm, line):
self.Default(fsm)
def Default(self, fsm):
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write('TRANSITION : Default\n')
msg = "\n\tState: %s\n\tTransition: %s" % (
fsm.getState().getName(), fsm.getTransition())
raise TransitionUndefinedException, msg
class MainMap_Default(ApiRequestState):
def BlankLine(self, fsm):
ctxt = fsm.getOwner()
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.Default.BlankLine()\n")
endState = fsm.getState()
fsm.clearState()
try:
ctxt.setRequestFinished()
ctxt.errbackDeferred("Protocol failure")
finally:
fsm.setState(endState)
def ContentFinished(self, fsm):
ctxt = fsm.getOwner()
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.Default.ContentFinished()\n")
endState = fsm.getState()
fsm.clearState()
try:
ctxt.setRequestFinished()
ctxt.errbackDeferred("Protocol failure")
finally:
fsm.setState(endState)
def ContentLength(self, fsm):
ctxt = fsm.getOwner()
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.Default.ContentLength()\n")
endState = fsm.getState()
fsm.clearState()
try:
ctxt.setRequestFinished()
ctxt.errbackDeferred("Protocol failure")
finally:
fsm.setState(endState)
def ApiResponse(self, fsm):
ctxt = fsm.getOwner()
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.Default.ApiResponse()\n")
endState = fsm.getState()
fsm.clearState()
try:
ctxt.setRequestFinished()
ctxt.errbackDeferred("Protocol failure")
finally:
fsm.setState(endState)
def ProcessLine(self, fsm, line):
ctxt = fsm.getOwner()
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.Default.ProcessLine(line)\n")
endState = fsm.getState()
fsm.clearState()
try:
ctxt.setRequestFinished()
ctxt.errbackDeferred("Protocol failure")
finally:
fsm.setState(endState)
class MainMap_Startup(MainMap_Default):
def ApiResponse(self, fsm):
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.Startup.ApiResponse()\n")
fsm.getState().Exit(fsm)
fsm.setState(MainMap.ApiResponseStarted)
fsm.getState().Entry(fsm)
class MainMap_ApiResponseStarted(MainMap_Default):
def ContentLength(self, fsm):
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.ApiResponseStarted.ContentLength()\n")
fsm.getState().Exit(fsm)
fsm.setState(MainMap.ContentPreStarted)
fsm.getState().Entry(fsm)
class MainMap_ContentPreStarted(MainMap_Default):
def BlankLine(self, fsm):
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.ContentPreStarted.BlankLine()\n")
fsm.getState().Exit(fsm)
fsm.setState(MainMap.ContentStarted)
fsm.getState().Entry(fsm)
class MainMap_ContentStarted(MainMap_Default):
def ProcessLine(self, fsm, line):
ctxt = fsm.getOwner()
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.ContentStarted.ProcessLine(line)\n")
if ctxt.add_content(line) == True :
fsm.getState().Exit(fsm)
fsm.clearState()
try:
ctxt.setRequestFinished()
ctxt.callbackDeferred(ctxt.getResponse())
finally:
fsm.setState(MainMap.Startup)
fsm.getState().Entry(fsm)
else:
endState = fsm.getState()
fsm.clearState()
try:
ctxt.doNothing()
finally:
fsm.setState(endState)
class MainMap:
Startup = MainMap_Startup('MainMap.Startup', 0)
ApiResponseStarted = MainMap_ApiResponseStarted('MainMap.ApiResponseStarted', 1)
ContentPreStarted = MainMap_ContentPreStarted('MainMap.ContentPreStarted', 2)
ContentStarted = MainMap_ContentStarted('MainMap.ContentStarted', 3)
Default = MainMap_Default('MainMap.Default', -1)
class ApiRequest_sm(statemap.FSMContext):
def __init__(self, owner):
statemap.FSMContext.__init__(self)
self._owner = owner
self.setState(MainMap.Startup)
MainMap.Startup.Entry(self)
def ApiResponse(self):
self._transition = 'ApiResponse'
self.getState().ApiResponse(self)
self._transition = None
def BlankLine(self):
self._transition = 'BlankLine'
self.getState().BlankLine(self)
self._transition = None
def ContentFinished(self):
self._transition = 'ContentFinished'
self.getState().ContentFinished(self)
self._transition = None
def ContentLength(self):
self._transition = 'ContentLength'
self.getState().ContentLength(self)
self._transition = None
def ProcessLine(self, *arglist):
self._transition = 'ProcessLine'
self.getState().ProcessLine(self, *arglist)
self._transition = None
def getState(self):
if self._state == None:
raise statemap.StateUndefinedException
return self._state
def getOwner(self):
return self._owner

View File

@ -0,0 +1,72 @@
%start MainMap::Startup
%class BgApiRequest
%map MainMap
%%
Startup
{
CommandReply
ApiResponseStarted
{
}
}
ApiResponseStarted
{
ReplyText
GotReplyText
{
}
}
GotReplyText
{
BlankLine
Startup
{
setRequestFinished(); callOrErrback();
}
}
Default
{
BlankLine
nil
{
setRequestFinished();
errbackDeferred("Protocol failure");
}
CommandReply
nil
{
setRequestFinished();
errbackDeferred("Protocol failure");
}
ReplyText
nil
{
setRequestFinished();
errbackDeferred("Protocol failure");
}
ProcessLine(line)
nil
{
setRequestFinished();
errbackDeferred("Protocol failure");
}
}
%%

View File

@ -0,0 +1,165 @@
# DO NOT MODIFY THIS CODE - AUTOMATICALLY GENERATED BY SMC
import statemap
class BgApiRequestState(statemap.State):
def Entry(self, fsm):
pass
def Exit(self, fsm):
pass
def BlankLine(self, fsm):
self.Default(fsm)
def CommandReply(self, fsm):
self.Default(fsm)
def ProcessLine(self, fsm, line):
self.Default(fsm)
def ReplyText(self, fsm):
self.Default(fsm)
def Default(self, fsm):
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write('TRANSITION : Default\n')
msg = "\n\tState: %s\n\tTransition: %s" % (
fsm.getState().getName(), fsm.getTransition())
raise TransitionUndefinedException, msg
class MainMap_Default(BgApiRequestState):
def BlankLine(self, fsm):
ctxt = fsm.getOwner()
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.Default.BlankLine()\n")
endState = fsm.getState()
fsm.clearState()
try:
ctxt.setRequestFinished()
ctxt.errbackDeferred("Protocol failure")
finally:
fsm.setState(endState)
def CommandReply(self, fsm):
ctxt = fsm.getOwner()
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.Default.CommandReply()\n")
endState = fsm.getState()
fsm.clearState()
try:
ctxt.setRequestFinished()
ctxt.errbackDeferred("Protocol failure")
finally:
fsm.setState(endState)
def ReplyText(self, fsm):
ctxt = fsm.getOwner()
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.Default.ReplyText()\n")
endState = fsm.getState()
fsm.clearState()
try:
ctxt.setRequestFinished()
ctxt.errbackDeferred("Protocol failure")
finally:
fsm.setState(endState)
def ProcessLine(self, fsm, line):
ctxt = fsm.getOwner()
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.Default.ProcessLine(line)\n")
endState = fsm.getState()
fsm.clearState()
try:
ctxt.setRequestFinished()
ctxt.errbackDeferred("Protocol failure")
finally:
fsm.setState(endState)
class MainMap_Startup(MainMap_Default):
def CommandReply(self, fsm):
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.Startup.CommandReply()\n")
fsm.getState().Exit(fsm)
fsm.setState(MainMap.ApiResponseStarted)
fsm.getState().Entry(fsm)
class MainMap_ApiResponseStarted(MainMap_Default):
def ReplyText(self, fsm):
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.ApiResponseStarted.ReplyText()\n")
fsm.getState().Exit(fsm)
fsm.setState(MainMap.GotReplyText)
fsm.getState().Entry(fsm)
class MainMap_GotReplyText(MainMap_Default):
def BlankLine(self, fsm):
ctxt = fsm.getOwner()
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.GotReplyText.BlankLine()\n")
fsm.getState().Exit(fsm)
fsm.clearState()
try:
ctxt.setRequestFinished()
ctxt.callOrErrback()
finally:
fsm.setState(MainMap.Startup)
fsm.getState().Entry(fsm)
class MainMap:
Startup = MainMap_Startup('MainMap.Startup', 0)
ApiResponseStarted = MainMap_ApiResponseStarted('MainMap.ApiResponseStarted', 1)
GotReplyText = MainMap_GotReplyText('MainMap.GotReplyText', 2)
Default = MainMap_Default('MainMap.Default', -1)
class BgApiRequest_sm(statemap.FSMContext):
def __init__(self, owner):
statemap.FSMContext.__init__(self)
self._owner = owner
self.setState(MainMap.Startup)
MainMap.Startup.Entry(self)
def BlankLine(self):
self._transition = 'BlankLine'
self.getState().BlankLine(self)
self._transition = None
def CommandReply(self):
self._transition = 'CommandReply'
self.getState().CommandReply(self)
self._transition = None
def ProcessLine(self, *arglist):
self._transition = 'ProcessLine'
self.getState().ProcessLine(self, *arglist)
self._transition = None
def ReplyText(self):
self._transition = 'ReplyText'
self.getState().ReplyText(self)
self._transition = None
def getState(self):
if self._state == None:
raise statemap.StateUndefinedException
return self._state
def getOwner(self):
return self._owner

View File

@ -0,0 +1,258 @@
"""
FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
Version: MPL 1.1
The contents of this file are subject to the Mozilla Public License Version
1.1 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.
The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
The Initial Developer of the Original Code is
Anthony Minessale II <anthmct@yahoo.com>
Portions created by the Initial Developer are Copyright (C)
the Initial Developer. All Rights Reserved.
Contributor(s): Traun Leyden <tleyden@branchcut.com>
"""
import sys
from twisted.internet import reactor, defer
from twisted.protocols.basic import LineReceiver
from twisted.internet.protocol import Protocol, ClientFactory
from twisted.python import failure
import time, re
from time import strftime
from Queue import Queue
from freepy import request
"""
This class connects to freeswitch and listens for
events and calls callback with the events.
Example messages
=================
Content-Length: 675
Content-Type: text/event-xml
<event>
<header name="force-contact" value="nat-connectile-dysfunction"></header>
etc..
</event>
Content-Length: 875
Content-Type: text/event-xml
<event>
...
</event>
"""
class FreeswitchEventListener(LineReceiver):
def __init__(self, conncb, discocb=None):
self.delimiter='\n' # parent class uses this
self.conncb=conncb
self.discocb=discocb
self.bufferlines = []
self.receiving_event = False # state to track if in <event>..</event>
self.requestq = Queue() # queue of pending requests
self.active_request = None # the current active (de-queued) request
def connectionMade(self):
self.conncb(self)
def connectionLost(self, reason):
if self.discocb:
self.discocb(reason)
print "connectionLost: %s" % reason
def login(self, passwd):
"""
send login request
"""
msg = "auth %s" % passwd
req = request.LoginRequest()
self.active_request = req
self.transport.write("%s\n\n" % msg)
return req.getDeferred()
def sniff_events(self, output_type, events):
"""
@param output_type - eg, xml or plain
@param events - list of events, eg ['all']
"""
event_list = " ".join(events)
msg = "event %s %s" % (output_type, event_list)
self.transport.write("%s\n\n" % msg)
def sniff_custom_events(self, output_type, events):
"""
when sniffing custom events, the CUSTOM keyword
must be present in message
http://wiki.freeswitch.org/wiki/Event_Socket#event
@param output_type - eg, xml or plain
@param events - list of events, eg ['all']
"""
event_list = " ".join(events)
msg = "event %s CUSTOM %s" % (output_type, event_list)
self.transport.write("%s\n\n" % msg)
def sniff_all_events(self, output_type):
"""
@param output_type - eg, xml or plain
"""
msg = "event %s all" % output_type
self.transport.write("%s\n\n" % msg)
def lineReceived(self, line):
if not self.active_request:
if line.find("<event>") != -1:
self.receiving_event = True
if self.receiving_event:
self.bufferlines.append(line)
if line.find("</event>") != -1:
event_xml_str = "\n".join(self.bufferlines)
self.eventReceived(event_xml_str)
self.bufferlines = []
self.receiving_event = False
else:
# we have an active request (seperate state machine)
# tell the request to process the line, and tell us
# if its finished or not. if its finished, we remove it
# as the active request so that a new active request will
# be de-queued.
finished = self.active_request.process(line)
if finished == True:
self.active_request = None
def eventReceived(self, event_xml_str):
"""
should be overridden by subclasses
"""
raise Exception("This is an abstract class, should be overridden "
"in a subclass")
class FreeswitchEventListenerFactory(ClientFactory):
def __init__(self, protoclass, host=None, passwd=None, port=None):
"""
@param protoclass - a class (not instance) of the protocol
should be a subclass of a FreeswitchEventListener
"""
self.protoclass=protoclass
if host:
self.host = host
if passwd:
self.passwd = passwd
if port:
self.port = port
self.protocol = None
self.connection_deferred = None
self.num_attempts = 0
def reset(self):
self.protocol = None
self.connection_deferred = None
def connect(self):
if self.protocol:
# if we have a protocol object, we are connected (since we always
# null it upon any disconnection)
return defer.succeed(self.protocol)
#if self.connection_deferred:
# we are already connecting, return existing dfrd
# return self.connection_deferred
# connect and automatically login after connection
if not self.connection_deferred:
self.connection_deferred = defer.Deferred()
self.connection_deferred.addCallback(self.dologin)
self.connection_deferred.addErrback(self.generalError)
reactor.connectTCP(self.host, self.port, self)
return self.connection_deferred
def conncb(self, protocol):
self.protocol = protocol
deferred2callback = self.connection_deferred
self.connection_deferred = None
deferred2callback.callback(self.protocol)
def generalError(self, failure):
print "General error: %s" % failure
return failure
def startedConnecting(self, connector):
pass
def buildProtocol(self, addr):
return self.protoclass(self.conncb, self.discocb)
def clientConnectionLost(self, connector, reason):
print "clientConnectionLost! conn=%s, reason=%s" % (connector,
reason)
self.connection_deferred = None
self.protocol = None
def clientConnectionFailed(self, connector, reason):
print "clientConnectionFailed! conn=%s, reason=%s" % (connector,
reason)
#self.protocol = None
if self.num_attempts < 100:
self.num_attempts += 1
return reactor.callLater(5, self.connect)
else:
deferred2callback = self.connection_deferred
deferred2callback.errback(reason)
def discocb(self, reason):
print "disconnected. reason: %s" % reason
self.protocol = None
def dologin(self, connectmsg):
return self.protocol.login(self.passwd)
def test1():
fel = FreeswitchEventListener
factory = FreeswitchEventListenerFactory(protoclass=fel,
host="127.0.0.1",
port=8021,
passwd="ClueCon")
def connected(result):
print "We connected, result: %s" % result
events=['sofia::register','sofia::expire']
factory.protocol.sniff_custom_events(output_type="xml", events=events)
#factory.protocol.sniff_all_events(output_type="xml")
def failure(failure):
print "Failed to connect: %s" % failure
d = factory.connect()
d.addCallbacks(connected, failure)
d.addErrback(failure)
reactor.run()
if __name__=="__main__":
test1()

View File

@ -0,0 +1,400 @@
#!/usr/bin/env python
"""
FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
Version: MPL 1.1
The contents of this file are subject to the Mozilla Public License Version
1.1 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.
The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
The Initial Developer of the Original Code is
Anthony Minessale II <anthmct@yahoo.com>
Portions created by the Initial Developer are Copyright (C)
the Initial Developer. All Rights Reserved.
Contributor(s): Traun Leyden <tleyden@branchcut.com>
"""
from twisted.internet import reactor, defer
from twisted.internet.protocol import ClientFactory
import freepy
class FsHelper(ClientFactory):
def __init__(self, host=None, passwd=None, port=None):
if host:
self.host = host
if passwd:
self.passwd = passwd
if port:
self.port = port
self.freepyd = None
self.connection_deferred = None
def reset(self):
self.freepyd = None
self.connection_deferred = None
def connect(self):
if self.freepyd:
# if we have a protocol object, we are connected (since we always
# null it upon any disconnection)
return defer.succeed("Connected")
if self.connection_deferred:
# we are already connecting, return existing dfrd
return self.connection_deferred
self.connection_deferred = defer.Deferred()
self.connection_deferred.addCallback(self.dologin)
self.connection_deferred.addErrback(self.generalError)
print "freepy connecting to %s:%s" % (self.host, self.port)
reactor.connectTCP(self.host, self.port, self)
return self.connection_deferred
def conncb(self, freepyd):
self.freepyd = freepyd
deferred2callback = self.connection_deferred
self.connection_deferred = None
deferred2callback.callback("Connected")
def generalError(self, failure):
print "General error: %s" % failure
return failure
def startedConnecting(self, connector):
pass
def buildProtocol(self, addr):
return freepy.FreepyDispatcher(self.conncb, self.discocb)
def clientConnectionLost(self, connector, reason):
print "clientConnectionLost! conn=%s, reason=%s" % (connector,
reason)
self.connection_deferred = None
self.freepyd = None
def clientConnectionFailed(self, connector, reason):
print "clientConnectionFailed! conn=%s, reason=%s" % (connector,
reason)
self.freepyd = None
deferred2callback = self.connection_deferred
self.connection_deferred = None
deferred2callback.errback(reason)
def discocb(self, reason):
print "disconnected. reason: %s" % reason
self.freepyd = None
def dologin(self, connectmsg):
return self.freepyd.login(self.passwd)
def originate(self, party2dial, dest_ext_app, bgapi=True):
"""
party2dial - the first argument to the originate command,
eg, sofia/profile_name/1234@domain.com
dest_ext_app - the second argument to the originate command,
eg, &park() or 4761
returns - a deferred that will be called back with a result
like:
([(True, 'Reply-Text: +OK Job-UUID: d07ad7de-2406-11dc-aea3-e3b2e56b7a2c')],)
"""
def originate_inner(ignored):
deferreds = []
deferred = self.freepyd.originate(party2dial,
dest_ext_app,
bgapi)
return deferred
d = self.connect()
d.addCallback(originate_inner)
return d
def dialconf(self, people2dial, conf_name, bgapi=True):
"""
conf_name - name of conf TODO: change to match db
people2dial - an array of dictionaries:
'name': name
'number': number
returns - a deferred that will be called back with a result
like:
([(True, 'Reply-Text: +OK Job-UUID: d07ad7de-2406-11dc-aea3-e3b2e56b7a2c')],)
Its a bit ugly because its a deferred list callback.
"""
def dialconf_inner(ignored):
deferreds = []
for person2dial in people2dial:
sofia_url = person2dial['number']
deferred = self.freepyd.confdialout(conf_name,
sofia_url,
bgapi)
deferreds.append(deferred)
return defer.DeferredList(deferreds)
d = self.connect()
d.addCallback(dialconf_inner)
return d
def listconf(self, conf_name):
"""
conf_name - name of conf
returns - a deferred that will be called back with a result
like:
TODO: add this
"""
def listconf_inner(ignored):
deferred = self.freepyd.listconf(conf_name)
return deferred
d = self.connect()
d.addCallback(listconf_inner)
return d
def confkick(self, member_id, conf_name, bgapi=True):
"""
conf_name - name of conf
member_id - member id of user to kick, eg, "7"
returns - a deferred that will be called back with a result
like:
TODO: add this
"""
def confkick_inner(ignored):
#if type(member_id) == type(""):
# member_id = int(member_id)
deferred = self.freepyd.confkick(member_id, conf_name, bgapi)
return deferred
d = self.connect()
d.addCallback(confkick_inner)
return d
def confdtmf(self, member_id, conf_name, dtmf, bgapi=True):
"""
Send dtmf(s) to a conference
conf_name - name of conf
member_id - member id of user to kick, eg, "7", or "all"
dtmf - a single dtmf or a string of dtms, eg "1" or "123"
returns - a deferred that will be called back with a result
like:
TODO: add this
"""
def confdtmf_inner(ignored):
print "confdtmf_inner called"
deferred = self.freepyd.confdtmf(member_id, conf_name, dtmf, bgapi)
return deferred
d = self.connect()
d.addCallback(confdtmf_inner)
return d
def confsay(self, conf_name, text2speak, bgapi=True):
"""
conf_name - name of conf
text2speak - text to speak
returns - a deferred that will be called back with a result
like:
TODO: add this
"""
def confsay_inner(ignored):
deferred = self.freepyd.confsay(conf_name, text2speak, bgapi)
return deferred
d = self.connect()
d.addCallback(confsay_inner)
return d
def confplay(self, conf_name, snd_url, bgapi=True):
"""
conf_name - name of conf
snd_url - url to sound file
returns - a deferred that will be called back with a result
like:
TODO: add this
"""
def confplay_inner(ignored):
deferred = self.freepyd.confplay(conf_name, snd_url, bgapi)
return deferred
d = self.connect()
d.addCallback(confplay_inner)
return d
def confstop(self, conf_name, bgapi=True):
"""
stop playback of all sounds
conf_name - name of conf
returns - a deferred that will be called back with a result
like:
TODO: add this
"""
def confstop_inner(ignored):
deferred = self.freepyd.confstop(conf_name, bgapi)
return deferred
d = self.connect()
d.addCallback(confstop_inner)
return d
def showchannels(self, bgapi=True):
def showchannels_inner(ignored):
df = self.freepyd.showchannels(bgapi)
return df
d = self.connect()
d.addCallback(showchannels_inner)
return d
def killchan(self, uuid, bgapi=True):
def killchan_inner(ignored):
df = self.freepyd.killchan(uuid, bgapi)
return df
d = self.connect()
d.addCallback(killchan_inner)
return d
def sofia_profile_restart(self, profile_name, bgapi=True):
def sofia_profile_restart_inner(ignored):
df = self.freepyd.sofia_profile_restart(profile_name,
bgapi)
return df
d = self.connect()
d.addCallback(sofia_profile_restart_inner)
return d
def sofia_status_profile(self, profile_name, bgapi=True):
def sofia_status_profile_inner(ignored):
df = self.freepyd.sofia_status_profile(profile_name,
bgapi)
return df
d = self.connect()
d.addCallback(sofia_status_profile_inner)
return d
class FsHelperTest:
def __init__(self, fshelper):
self.fshelper=fshelper
pass
def test_dialconf(self):
people2dial = [{'name':'freeswitch',
'number':'888@conference.freeswitch.org'},
{'name':'mouselike',
'number':'904@mouselike.org'}]
d = self.fshelper.dialconf(people2dial, "freeswitch", bgapi=False)
def failed(error):
print "Failed to dial users!"
reactor.stop()
return error
d.addErrback(failed)
def worked(*args):
print "Worked! Dialed user result: %s" % str(args)
#reactor.stop()
d.addCallback(worked)
return d
def test_listconf(self):
d = self.fshelper.listconf("freeswitch")
def failed(failure):
print "Failed to list users!"
reactor.stop()
return failure
d.addErrback(failed)
def worked(*args):
print "List of users in conf: %s" % str(args)
return args[0]
d.addCallback(worked)
return d
def test_confkick(self, member_id="6", conf_name="freeswitch"):
d = self.fshelper.confkick(member_id, conf_name)
def failed(failure):
print "Failed to kick user!"
reactor.stop()
return failure
d.addErrback(failed)
def worked(*args):
print "Kicked user from conf, result: %s" % str(args)
d.addCallback(worked)
def test1():
kick_everyone = False
fshelper = FsHelper("mydomain.com")
fsht = FsHelperTest(fshelper)
fsht.test_dialconf()
d = fsht.test_listconf()
def kickeveryone(members):
print "Kickeveryone called w/ %s (type: %s)" % (members,
type(members))
for member in members:
fsht.test_confkick(member.member_id)
def failed(failure):
print "failed: %s" % str(failure)
reactor.stop()
if kick_everyone:
d.addCallback(kickeveryone)
d.addErrback(failed)
#fsht.test_confkick()
#d = fshelper.connect()
#def connected(*args):
# fsht.test_dialconf()
# fsht.test_listconf()
#d.addCallback(connected)
reactor.run()
def test2():
fshelper = FsHelper("mydomain.com")
fshelper.sofia_profile_restart("mydomain.com")
reactor.run()
if __name__=="__main__":
#test1()
test2()

View File

@ -0,0 +1,92 @@
%start MainMap::Startup
%class LoginRequest
%map MainMap
%%
Startup
{
AuthRequest
AuthRequestStarted
{
}
}
AuthRequestStarted
{
BlankLine
AuthRequestFinished
{
}
}
AuthRequestFinished
{
CommandReply
CommandReplyStarted
{
}
}
CommandReplyStarted
{
ReplyText
GotReplyText
{
}
}
GotReplyText
{
BlankLine
Startup
{
setRequestFinished(); callOrErrback();
}
}
Default
{
BlankLine
nil
{
setRequestFinished();
errbackDeferred("Protocol failure");
}
AuthRequest
nil
{
setRequestFinished();
errbackDeferred("Protocol failure");
}
CommandReply
nil
{
setRequestFinished();
errbackDeferred("Protocol failure");
}
ReplyText
nil
{
setRequestFinished();
errbackDeferred("Protocol failure");
}
ProcessLine(line)
nil
{
setRequestFinished();
errbackDeferred("Protocol failure");
}
}
%%

View File

@ -0,0 +1,209 @@
# DO NOT MODIFY THIS CODE - AUTOMATICALLY GENERATED BY SMC
import statemap
class LoginRequestState(statemap.State):
def Entry(self, fsm):
pass
def Exit(self, fsm):
pass
def AuthRequest(self, fsm):
self.Default(fsm)
def BlankLine(self, fsm):
self.Default(fsm)
def CommandReply(self, fsm):
self.Default(fsm)
def ProcessLine(self, fsm, line):
self.Default(fsm)
def ReplyText(self, fsm):
self.Default(fsm)
def Default(self, fsm):
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write('TRANSITION : Default\n')
msg = "\n\tState: %s\n\tTransition: %s" % (
fsm.getState().getName(), fsm.getTransition())
raise TransitionUndefinedException, msg
class MainMap_Default(LoginRequestState):
def BlankLine(self, fsm):
ctxt = fsm.getOwner()
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.Default.BlankLine()\n")
endState = fsm.getState()
fsm.clearState()
try:
ctxt.setRequestFinished()
ctxt.errbackDeferred("Protocol failure")
finally:
fsm.setState(endState)
def AuthRequest(self, fsm):
ctxt = fsm.getOwner()
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.Default.AuthRequest()\n")
endState = fsm.getState()
fsm.clearState()
try:
ctxt.setRequestFinished()
ctxt.errbackDeferred("Protocol failure")
finally:
fsm.setState(endState)
def CommandReply(self, fsm):
ctxt = fsm.getOwner()
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.Default.CommandReply()\n")
endState = fsm.getState()
fsm.clearState()
try:
ctxt.setRequestFinished()
ctxt.errbackDeferred("Protocol failure")
finally:
fsm.setState(endState)
def ReplyText(self, fsm):
ctxt = fsm.getOwner()
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.Default.ReplyText()\n")
endState = fsm.getState()
fsm.clearState()
try:
ctxt.setRequestFinished()
ctxt.errbackDeferred("Protocol failure")
finally:
fsm.setState(endState)
def ProcessLine(self, fsm, line):
ctxt = fsm.getOwner()
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.Default.ProcessLine(line)\n")
endState = fsm.getState()
fsm.clearState()
try:
ctxt.setRequestFinished()
ctxt.errbackDeferred("Protocol failure")
finally:
fsm.setState(endState)
class MainMap_Startup(MainMap_Default):
def AuthRequest(self, fsm):
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.Startup.AuthRequest()\n")
fsm.getState().Exit(fsm)
fsm.setState(MainMap.AuthRequestStarted)
fsm.getState().Entry(fsm)
class MainMap_AuthRequestStarted(MainMap_Default):
def BlankLine(self, fsm):
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.AuthRequestStarted.BlankLine()\n")
fsm.getState().Exit(fsm)
fsm.setState(MainMap.AuthRequestFinished)
fsm.getState().Entry(fsm)
class MainMap_AuthRequestFinished(MainMap_Default):
def CommandReply(self, fsm):
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.AuthRequestFinished.CommandReply()\n")
fsm.getState().Exit(fsm)
fsm.setState(MainMap.CommandReplyStarted)
fsm.getState().Entry(fsm)
class MainMap_CommandReplyStarted(MainMap_Default):
def ReplyText(self, fsm):
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.CommandReplyStarted.ReplyText()\n")
fsm.getState().Exit(fsm)
fsm.setState(MainMap.GotReplyText)
fsm.getState().Entry(fsm)
class MainMap_GotReplyText(MainMap_Default):
def BlankLine(self, fsm):
ctxt = fsm.getOwner()
if fsm.getDebugFlag() == True:
fsm.getDebugStream().write("TRANSITION : MainMap.GotReplyText.BlankLine()\n")
fsm.getState().Exit(fsm)
fsm.clearState()
try:
ctxt.setRequestFinished()
ctxt.callOrErrback()
finally:
fsm.setState(MainMap.Startup)
fsm.getState().Entry(fsm)
class MainMap:
Startup = MainMap_Startup('MainMap.Startup', 0)
AuthRequestStarted = MainMap_AuthRequestStarted('MainMap.AuthRequestStarted', 1)
AuthRequestFinished = MainMap_AuthRequestFinished('MainMap.AuthRequestFinished', 2)
CommandReplyStarted = MainMap_CommandReplyStarted('MainMap.CommandReplyStarted', 3)
GotReplyText = MainMap_GotReplyText('MainMap.GotReplyText', 4)
Default = MainMap_Default('MainMap.Default', -1)
class LoginRequest_sm(statemap.FSMContext):
def __init__(self, owner):
statemap.FSMContext.__init__(self)
self._owner = owner
self.setState(MainMap.Startup)
MainMap.Startup.Entry(self)
def AuthRequest(self):
self._transition = 'AuthRequest'
self.getState().AuthRequest(self)
self._transition = None
def BlankLine(self):
self._transition = 'BlankLine'
self.getState().BlankLine(self)
self._transition = None
def CommandReply(self):
self._transition = 'CommandReply'
self.getState().CommandReply(self)
self._transition = None
def ProcessLine(self, *arglist):
self._transition = 'ProcessLine'
self.getState().ProcessLine(self, *arglist)
self._transition = None
def ReplyText(self):
self._transition = 'ReplyText'
self.getState().ReplyText(self)
self._transition = None
def getState(self):
if self._state == None:
raise statemap.StateUndefinedException
return self._state
def getOwner(self):
return self._owner

View File

@ -0,0 +1,81 @@
"""
FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
Version: MPL 1.1
The contents of this file are subject to the Mozilla Public License Version
1.1 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.
The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
The Initial Developer of the Original Code is
Anthony Minessale II <anthmct@yahoo.com>
Portions created by the Initial Developer are Copyright (C)
the Initial Developer. All Rights Reserved.
Contributor(s): Traun Leyden <tleyden@branchcut.com>
"""
"""
Data models for objects inside freeswitch
"""
import re
class ConfMember:
def __init__(self, rawstring):
self.rawstring = rawstring
self.member_id = None
self.member_uri = None
self.uuid = None
self.caller_id_name = None
self.caller_id_number = None
self.flags = None
self.volume_in = None
self.volume_out = None
self.energy_level = None
self.parse(self.rawstring)
def parse(self, rawstring):
"""
1;sofia/mydomain.com/user@somewhere.com;898e6552-24ab-11dc-9df7-9fccd4095451;FreeSWITCH;0000000000;hear|speak;0;0;300
"""
fields = rawstring.split(";")
self.member_id = fields[0]
self.member_uri = fields[1]
self.uuid = fields[2]
self.caller_id_name = fields[3]
self.caller_id_number = fields[4]
self.flags = fields[5]
self.volume_in = fields[6]
self.volume_out = fields[7]
self.energy_level = fields[8]
def brief_member_uri(self):
"""
if self.member_uri is sofia/mydomain.com/foo@bar.com
return foo@bar.com
"""
if not self.member_uri:
return None
if self.member_uri.find("/") == -1:
return self.member_uri
r = self.member_uri.split("/")[-1] # tokenize on "/" and return last item
return r
def __repr__(self):
return self.__str__()
def __str__(self):
return "%s (%s)" % (self.member_id, self.member_uri)

View File

@ -0,0 +1,425 @@
"""
FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
Version: MPL 1.1
The contents of this file are subject to the Mozilla Public License Version
1.1 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.
The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
The Initial Developer of the Original Code is
Anthony Minessale II <anthmct@yahoo.com>
Portions created by the Initial Developer are Copyright (C)
the Initial Developer. All Rights Reserved.
Contributor(s): Traun Leyden <tleyden@branchcut.com>
"""
import sys
from twisted.internet import reactor, defer
from twisted.protocols.basic import LineReceiver
from twisted.internet.protocol import Protocol, ClientFactory
from twisted.python import failure
import time, re
from time import strftime
from Queue import Queue
from freepy import models
"""
These are response handlers for different types of requests.
It reads the response from freeswitch, and calls back
self.deferred with the result.
The naming could be improved, but here is the translation:
LoginRequest - Response handler for a login request
"""
class FreepyRequest(object):
def __init__(self):
self.deferred = defer.Deferred()
self.response_content = ""
self.finished = False
def isRequestFinished(self):
return self.finished
def setRequestFinished(self):
self.finished = True
def getDeferred(self):
return self.deferred
def callbackDeferred(self, cbval):
self.deferred.callback(cbval)
def errbackDeferred(self, result):
self.deferred.errback(result)
def process(self, line):
"""
processs a line from the fs response. if the fs response has been
detected to be finished, then:
* create an appropriate response based on request type
* callback deferred with response
* rturn True to indicate we are finished
otherwise, if the fs response is incomplete, just buffer the data
"""
if not line or len(line) == 0:
self._fsm.BlankLine()
return self.isRequestFinished()
matchstr = re.compile("auth/request", re.I)
result = matchstr.search(line)
if (result != None):
self._fsm.AuthRequest()
return self.isRequestFinished()
matchstr = re.compile("command/reply", re.I)
result = matchstr.search(line)
if (result != None):
self._fsm.CommandReply()
return self.isRequestFinished()
matchstr = re.compile("Reply-Text", re.I)
result = matchstr.search(line)
if (result != None):
fields = line.split(":") # eg, ['Reply-Text','+OK Job-UUID', '882']
endfields = fields[1:]
self.response_content = "".join(endfields)
self._fsm.ReplyText()
return self.isRequestFinished()
matchstr = re.compile("api/response", re.I)
result = matchstr.search(line)
if (result != None):
self._fsm.ApiResponse()
return self.isRequestFinished()
matchstr = re.compile("Content-Length", re.I)
result = matchstr.search(line)
if (result != None):
# line: Content-Length: 34
self.content_length = int(line.split(":")[1].strip())
self._fsm.ContentLength()
return self.isRequestFinished()
self._fsm.ProcessLine(line)
return self.isRequestFinished()
def callOrErrback(self):
matchstr = re.compile("OK", re.I)
result = matchstr.search(self.response_content)
if (result != None):
self.callbackDeferred(self.response_content)
return
self.errbackDeferred(self.response_content)
def doNothing(self):
# weird smc issue workaround attempt
pass
class LoginRequest(FreepyRequest):
"""
Example success response
========================
lineReceived: Content-Type: auth/request
lineReceived:
lineReceived: Content-Type: command/reply
lineReceived: Reply-Text: +OK accepted
lineReceived:
Example failure response
========================
lineReceived: Content-Type: auth/request
lineReceived:
lineReceived: Content-Type: command/reply
lineReceived: Reply-Text: -ERR invalid
lineReceived:
"""
def __init__(self):
super(LoginRequest, self).__init__()
import loginrequest_sm
self._fsm = loginrequest_sm.LoginRequest_sm(self)
def processOLD(self, line):
if not line or len(line) == 0:
self._fsm.BlankLine()
return self.isRequestFinished()
matchstr = re.compile("auth/request", re.I)
result = matchstr.search(line)
if (result != None):
self._fsm.AuthRequest()
return self.isRequestFinished()
matchstr = re.compile("command/reply", re.I)
result = matchstr.search(line)
if (result != None):
self._fsm.CommandReply()
return self.isRequestFinished()
matchstr = re.compile("Reply-Text", re.I)
result = matchstr.search(line)
if (result != None):
fields = line.split(":") # eg, ['Reply-Text','+OK Job-UUID', '882']
endfields = fields[1:]
self.response_content = "".join(endfields)
self._fsm.ReplyText()
return self.isRequestFinished()
self._fsm.ProcessLine(line)
return self.isRequestFinished()
def getReplyText(self):
self.response_content
class BgApiRequest(FreepyRequest):
"""
Here is one of the 'bgapi requests' this class
supports:
linereceived: Content-Type: command/reply
linereceived: Reply-Text: +OK Job-UUID: 788da080-24e0-11dc-85f6-3d7b12..
linereceived:
"""
def __init__(self):
super(BgApiRequest, self).__init__()
import bgapirequest_sm
self._fsm = bgapirequest_sm.BgApiRequest_sm(self)
def processOLD(self, line):
if not line or len(line) == 0:
self._fsm.BlankLine()
return self.isRequestFinished()
matchstr = re.compile("command/reply", re.I)
result = matchstr.search(line)
if (result != None):
self._fsm.CommandReply()
return self.isRequestFinished()
matchstr = re.compile("Reply-Text", re.I)
result = matchstr.search(line)
if (result != None):
self.response_content = line.split(":")[1]
self._fsm.ReplyText()
return self.isRequestFinished()
self._fsm.ProcessLine(line)
return self.isRequestFinished()
def getResponse(self):
# subclasses may want to parse this into a meaningful
# object or set of objects (eg, see ListConfRequest)
# By default, just return accumulated string
return self.response_content
class ApiRequest(FreepyRequest):
"""
Here is one of the 'api requests' this class
supports:
lineReceived: Content-Type: api/response
lineReceived: Content-Length: 34
lineReceived:
lineReceived: Call Requested: result: [SUCCESS]
"""
def __init__(self):
super(ApiRequest, self).__init__()
import apirequest_sm
self._fsm = apirequest_sm.ApiRequest_sm(self)
self.response_content = ""
def processOLD(self, line):
if not line or len(line) == 0:
self._fsm.BlankLine()
return self.isRequestFinished()
matchstr = re.compile("api/response", re.I)
result = matchstr.search(line)
if (result != None):
self._fsm.ApiResponse()
return self.isRequestFinished()
matchstr = re.compile("Content-Length", re.I)
result = matchstr.search(line)
if (result != None):
# line: Content-Length: 34
self.content_length = int(line.split(":")[1].strip())
self._fsm.ContentLength()
return self.isRequestFinished()
self._fsm.ProcessLine(line)
return self.isRequestFinished()
def doNothing(self):
# weird smc issue workaround attempt
pass
def add_content(self, line):
"""
Add content to local buffer
return - True if finished adding content, False otherwise
"""
# since the twisted LineReceiver strips off the newline,
# we need to add it back .. otherwise the Content-length
# will be off by one
line += "\n"
self.response_content += line
if len(self.response_content) == self.content_length:
return True
elif len(self.response_content) > self.content_length:
return True
else:
return False
def getResponse(self):
# subclasses may want to parse this into a meaningful
# object or set of objects (eg, see ListConfRequest)
# By default, just return accumulated string
return self.response_content
class DialoutRequest(ApiRequest):
"""
Example raw dialout response
============================
lineReceived: Content-Type: api/response
lineReceived: Content-Length: 34
lineReceived:
lineReceived: Call Requested: result: [SUCCESS]
"""
def __init__(self):
super(DialoutRequest, self).__init__()
class BgDialoutRequest(BgApiRequest):
def __init__(self):
super(BgDialoutRequest, self).__init__()
class ConfKickRequest(ApiRequest):
"""
Example response
================
"""
def __init__(self):
super(ConfKickRequest, self).__init__()
class BgConfKickRequest(BgApiRequest):
"""
Example response
================
"""
def __init__(self):
super(BgConfKickRequest, self).__init__()
class ListConfRequest(ApiRequest):
"""
Response to request to list conferences:
========================================
lineReceived: Content-Type: api/response
lineReceived: Content-Length: 233
lineReceived:
lineReceived: 2;sofia/mydomain.com/foo@bar.com;e9be6e72-2410-11dc-8daf-7bcec6dda2ae;FreeSWITCH;0000000000;hear|speak;0;0;300
lineReceived: 1;sofia/mydomain.com/foo2@bar.com;e9be5fcc-2410-11dc-8daf-7bcec6dda2ae;FreeSWITCH;0000000000;hear|speak;0;0;300
"""
def __init__(self):
super(ListConfRequest, self).__init__()
self.conf_members = []
def add_content(self, line):
"""
conf not empty example
======================
1;sofia/mydomain.com/888@conference.freeswitch.org;898e6552-24ab-11dc-9df7-9fccd4095451;FreeSWITCH;0000000000;hear|speak;0;0;300
conf empty example
==================
Conference foo not found
"""
matchstr = re.compile("not found", re.I)
result = matchstr.search(line)
if (result != None):
# no conf found..
pass
else:
confmember = models.ConfMember(line)
self.conf_members.append(confmember)
return super(ListConfRequest, self).add_content(line)
def getResponse(self):
# TODO: parse this content into a meaningful
# 'object' .. though, not sure this is really
# necessary. wait till there's a need
return self.conf_members