123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530 |
- #!/usr/bin/env python
- """
- 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>
- """
- 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 broadcast(self, uuid, path, legs="both", bgapi=True):
- """
- @legs - one of the following strings: aleg|bleg|both
- """
- def broadcast_inner(ignored):
- df = self.freepyd.broadcast(uuid, path, legs, bgapi)
- return df
- d = self.connect()
- d.addCallback(broadcast_inner)
- return d
- def transfer(self, uuid, dest_ext, legs="-both", bgapi=True):
- """
- @legs -bleg|-both
- """
- def transfer_inner(ignored):
- df = self.freepyd.transfer(uuid, dest_ext, legs, bgapi)
- return df
- d = self.connect()
- d.addCallback(transfer_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):
- # the following parties will be dialed out from the conference
- # called "freeswitch" on the local freeswitch instance.
- # one party is actually another conference, just to make
- # the example more confusing.
- 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)
- 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(host="127.0.0.1",
- passwd="ClueCon",
- port=8021)
- 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(host="127.0.0.1",
- passwd="ClueCon",
- port=8021)
- fshelper.sofia_profile_restart("mydomain.com")
- reactor.run()
- def test3():
- fshelper = FsHelper(host="127.0.0.1",
- passwd="ClueCon",
- port=8021)
- print "Calling originate.."
- party2dial="sofia/foo/600@192.168.1.202:5080"
- d = fshelper.originate(party2dial=party2dial,
- dest_ext_app="101",
- bgapi=True)
- def worked(result):
- print "Originate succeeded: %s" % result
- reactor.stop()
- def failed(failure):
- print "failed: %s" % str(failure)
- reactor.stop()
- d.addCallback(worked)
- d.addErrback(failed)
- reactor.run()
- def test4():
- fshelper = FsHelper(host="127.0.0.1",
- passwd="ClueCon",
- port=8021)
- def worked(result):
- print "Originate succeeded: %s" % result
- #reactor.stop()
- def failed(failure):
- print "failed: %s" % str(failure)
- #reactor.stop()
- dest_ext_app = "101"
- party2dial="sofia/foo/600@192.168.1.202:5080"
- d = fshelper.originate(party2dial=party2dial,
- dest_ext_app=dest_ext_app,
- bgapi=True)
- d.addCallback(worked)
- d.addErrback(failed)
- party2dial="sofia/foo/someone@bar.com"
- d2 = fshelper.originate(party2dial=party2dial,
- dest_ext_app=dest_ext_app,
- bgapi=True)
- d2.addCallback(worked)
- d2.addErrback(failed)
- reactor.run()
- def test5():
- fshelper = FsHelper(host="127.0.0.1",
- passwd="ClueCon",
- port=8021)
- def worked(result):
- print "Originate succeeded: %s" % result
- #reactor.stop()
- def failed(failure):
- print "failed: %s" % str(failure)
- #reactor.stop()
- for i in xrange(20):
- party2dial = "sofia/foo/600@192.168.1.202:5080"
- d = fshelper.originate(party2dial=party2dial,
- dest_ext_app="700",
- bgapi=True)
- d.addCallback(worked)
- d.addErrback(failed)
- reactor.run()
- def test6():
- """
- show channels for a given sofia profile
- """
- fshelper = FsHelper(host="127.0.0.1",
- passwd="ClueCon",
- port=8021)
- from wikipbx import channelsutil
- def show_chanels(raw_xml):
- print raw_xml
- def failure(failure):
- print failure
- d = fshelper.showchannels(bgapi=False)
- d.addCallback(show_chanels)
- d.addErrback(failure)
- reactor.run()
- if __name__ == "__main__":
- #test1()
- #test2()
- #test3()
- test4()
- #test5()
|