123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- """
- FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
- Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
- 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 <anthm@freeswitch.org>
- 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
- from twisted.python.failure import Failure
- import time, re
- from time import strftime
- from Queue import Queue
- from freepy import models
- import freepy.globals
- from freepy.globals import debug
- """
- 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):
- debug("setRequestFinished called. response_content: %s " %
- self.response_content)
- self.finished = True
- def getDeferred(self):
- return self.deferred
- def callbackDeferred(self, cbval):
- self.deferred.callback(cbval)
- def errbackDeferred(self, result):
- self.deferred.errback(Exception(str(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.strip() or len(line.strip()) == 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):
- debug("FREEPY: got Reply-Text")
- 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("Job-UUID", re.I)
- result = matchstr.search(line)
- if (result != None):
- fields = line.split(":") # eg, ['Job-UUID','c9eee07e-508-..']
- endfields = fields[1:]
- # ignore job uuid given on this line, take the one sent
- # in Reply-Text response line
- # self.response_content = "".join(endfields)
- self._fsm.JobUuid()
- 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(Failure(Exception(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 callOrErrback(self):
- matchstr = re.compile("OK", re.I)
- result = matchstr.search(self.response_content)
- if (result != None):
- self.callbackDeferred(self.response_content)
- return
- msg = "Login failed, most likely a bad password"
- self.errbackDeferred(Failure(Exception(msg)))
- 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 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 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
|