FreeSWITCHeR 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/License.txt +20 -0
  2. data/NEWS +3 -0
  3. data/README +85 -0
  4. data/Rakefile +82 -0
  5. data/bin/cmd_demo.rb +19 -0
  6. data/bin/ies_demo.rb +19 -0
  7. data/bin/ies_demo_with_hook.rb +27 -0
  8. data/bin/oes_demo.rb +22 -0
  9. data/lib/fsr.rb +86 -0
  10. data/lib/fsr/app.rb +72 -0
  11. data/lib/fsr/app/answer.rb +21 -0
  12. data/lib/fsr/app/bridge.rb +33 -0
  13. data/lib/fsr/app/conference.rb +29 -0
  14. data/lib/fsr/app/fifo.rb +38 -0
  15. data/lib/fsr/app/fs_break.rb +21 -0
  16. data/lib/fsr/app/fs_sleep.rb +24 -0
  17. data/lib/fsr/app/hangup.rb +22 -0
  18. data/lib/fsr/app/log.rb +24 -0
  19. data/lib/fsr/app/playback.rb +23 -0
  20. data/lib/fsr/app/set.rb +22 -0
  21. data/lib/fsr/app/speak.rb +25 -0
  22. data/lib/fsr/app/transfer.rb +24 -0
  23. data/lib/fsr/cmd.rb +57 -0
  24. data/lib/fsr/cmd/fsctl.rb +41 -0
  25. data/lib/fsr/cmd/originate.rb +46 -0
  26. data/lib/fsr/cmd/sofia.rb +40 -0
  27. data/lib/fsr/cmd/sofia/profile.rb +75 -0
  28. data/lib/fsr/cmd/sofia/status.rb +39 -0
  29. data/lib/fsr/cmd/sofia_contact.rb +31 -0
  30. data/lib/fsr/cmd/status.rb +25 -0
  31. data/lib/fsr/command_socket.rb +29 -0
  32. data/lib/fsr/database.rb +7 -0
  33. data/lib/fsr/database/call_limit.rb +21 -0
  34. data/lib/fsr/database/core.rb +30 -0
  35. data/lib/fsr/database/sofia_reg_external.rb +0 -0
  36. data/lib/fsr/database/sofia_reg_internal.rb +0 -0
  37. data/lib/fsr/database/voicemail_default.rb +0 -0
  38. data/lib/fsr/event_socket.rb +41 -0
  39. data/lib/fsr/fake_socket.rb +68 -0
  40. data/lib/fsr/listener.rb +10 -0
  41. data/lib/fsr/listener/header_and_content_response.rb +21 -0
  42. data/lib/fsr/listener/inbound.rb +61 -0
  43. data/lib/fsr/listener/inbound/event.rb +42 -0
  44. data/lib/fsr/listener/outbound.rb +62 -0
  45. data/spec/fsr/app.rb +8 -0
  46. data/spec/fsr/app/bridge.rb +17 -0
  47. data/spec/fsr/app/conference.rb +12 -0
  48. data/spec/fsr/app/fifo.rb +29 -0
  49. data/spec/fsr/cmd.rb +8 -0
  50. data/spec/fsr/cmd/originate.rb +12 -0
  51. data/spec/fsr/cmd/sofia.rb +69 -0
  52. data/spec/fsr/cmd/sofia/profile.rb +58 -0
  53. data/spec/fsr/listener.rb +12 -0
  54. data/spec/fsr/listener/inbound.rb +19 -0
  55. data/spec/fsr/listener/outbound.rb +19 -0
  56. data/spec/fsr/loading.rb +27 -0
  57. data/spec/helper.rb +14 -0
  58. data/tasks/package.rake +29 -0
  59. data/tasks/spec.rake +59 -0
  60. metadata +224 -0
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 rubyists.com (TJ Vanderpoel, Jayson Vaughn, Michael Fellinger, Kevin Berry)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/NEWS ADDED
@@ -0,0 +1,3 @@
1
+ 2009-04-08 - Released new gem version, using EventMachine's HeaderAndContent protocol
2
+ in listeners now
3
+ 2009-04-01 - Added inspired to git committers
data/README ADDED
@@ -0,0 +1,85 @@
1
+ =========================================================
2
+ FreeSWITCHeR
3
+ Copyright (c) 2009 The Rubyists (Jayson Vaughn, Tj Vanderpoel, Michael Fellinger, Kevin Berry)
4
+ Distributed under the terms of the MIT License.
5
+ ==========================================================
6
+
7
+ About
8
+ -----
9
+ *** STILL UNDER HEAVY DEVELOPMENT ***
10
+
11
+ A ruby library for interacting with the "FreeSWITCH" (http://www.freeswitch.org) opensource telephony platform
12
+
13
+ *** STILL UNDER HEAVY DEVELOPMENT ***
14
+
15
+ Requirements
16
+ ------------
17
+ - ruby (>= 1.8)
18
+ - eventmachine (If you wish to use Outbound and Inbound listener)
19
+
20
+ Usage
21
+ -----
22
+
23
+ Example of originating a new call in 'irb' using FSR::CommandSocket#originate:
24
+
25
+ irb(main):001:0> require 'fsr'
26
+ => true
27
+
28
+ irb(main):002:0> FSR.load_all_commands
29
+ => [:sofia, :originate]
30
+
31
+ irb(main):003:0> sock = FSR::CommandSocket.new
32
+ => #<FSR::CommandSocket:0xb7a89104 @server="127.0.0.1", @socket=#<TCPSocket:0xb7a8908c>, @port="8021", @auth="ClueCon">
33
+
34
+ irb(main):007:0> sock.originate(:target => 'sofia/gateway/carlos/8179395222', :endpoint => FSR::App::Bridge.new("user/bougyman")).run
35
+ => {"Job-UUID"=>"732075a4-7dd5-4258-b124-6284a82a5ae7", "body"=>"", "Content-Type"=>"command/reply", "Reply-Text"=>"+OK Job-UUID: 732075a4-7dd5-4258-b124-6284a82a5ae7"}
36
+
37
+
38
+ Example of creating an Outbound Eventsocket listener:
39
+
40
+ #!/usr/bin/env ruby
41
+
42
+ require 'fsr'
43
+ require "fsr/listener/outbound"
44
+
45
+ class OesDemo < FSR::Listener::Outbound
46
+
47
+ def session_initiated(session)
48
+ number = session.headers[:caller_caller_id_number] # Grab the inbound caller id
49
+ FSR::Log.info "*** Answering incoming call from #{number}"
50
+ answer # Answer the call
51
+ set "hangup_after_bridge=true" # Set a variable
52
+ speak 'Hello, This is your phone switch. Have a great day' # use mod_flite to speak
53
+ hangup # Hangup the call
54
+ end
55
+
56
+ end
57
+
58
+ FSR.start_oes!(OesDemo, :port => 1888, :host => "localhost")
59
+
60
+
61
+
62
+ Example of creating an Inbound Eventsocket listener:
63
+
64
+ #!/usr/bin/env ruby
65
+
66
+ require 'fsr'
67
+ require "fsr/listener/inbound"
68
+
69
+ class IesDemo < FSR::Listener::Inbound
70
+
71
+ def on_event(event)
72
+ pp event.headers
73
+ pp event.content[:event_name]
74
+ end
75
+
76
+ end
77
+
78
+ FSR.start_ies!(IesDemo, :host => "localhost", :port => 8021)
79
+
80
+
81
+
82
+ Support
83
+ -------
84
+ Home page at http://code.rubyists.com/projects/fs
85
+ #rubyists on FreeNode
@@ -0,0 +1,82 @@
1
+ require 'rake/clean'
2
+ require "rubygems"
3
+
4
+ import(*Dir['tasks/*rake'])
5
+
6
+ task :default => :spec
7
+
8
+ desc 'install dependencies'
9
+ task :setup do
10
+ GemSetup.new do
11
+ github = 'http://gems.github.com'
12
+ Gem.sources << github
13
+
14
+ gem('bacon')
15
+ setup
16
+ end
17
+ end
18
+
19
+ class GemSetup
20
+ def initialize(options = {}, &block)
21
+ @gems = []
22
+ @options = options
23
+
24
+ run(&block)
25
+ end
26
+
27
+ def run(&block)
28
+ instance_eval(&block) if block_given?
29
+ end
30
+
31
+ def gem(name, version = nil, options = {})
32
+ if version.respond_to?(:merge!)
33
+ options = version
34
+ else
35
+ options[:version] = version
36
+ end
37
+
38
+ @gems << [name, options]
39
+ end
40
+
41
+ def setup
42
+ require 'rubygems'
43
+ require 'rubygems/dependency_installer'
44
+
45
+ @gems.each do |name, options|
46
+ setup_gem(name, options)
47
+ end
48
+ end
49
+
50
+ def setup_gem(name, options, try_install = true)
51
+ print "activating #{name} ... "
52
+ Gem.activate(name, *[options[:version]].compact)
53
+ require(options[:lib] || name)
54
+ puts "success."
55
+ rescue LoadError => error
56
+ puts error
57
+ install_gem(name, options) if try_install
58
+ setup_gem(name, options, try_install = false)
59
+ end
60
+
61
+ def install_gem(name, options)
62
+ installer = Gem::DependencyInstaller.new(options)
63
+
64
+ temp_argv(options[:extconf]) do
65
+ print "Installing #{name} ... "
66
+ installer.install(name, options[:version])
67
+ puts "done."
68
+ end
69
+ end
70
+
71
+ def temp_argv(extconf)
72
+ if extconf ||= @options[:extconf]
73
+ old_argv = ARGV.clone
74
+ ARGV.replace(extconf.split(' '))
75
+ end
76
+
77
+ yield
78
+
79
+ ensure
80
+ ARGV.replace(old_argv) if extconf
81
+ end
82
+ end
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pp'
4
+ require File.join(File.dirname(__FILE__), "..", 'lib', 'fsr')
5
+ require "fsr/cmd"
6
+
7
+ FSR.load_all_commands
8
+ sock = FSR::CommandSocket.new
9
+
10
+ # Check the status of our server
11
+ pp sock.status.run
12
+
13
+ # Check max sessions
14
+ pp sock.fsctl.max_sessions
15
+ # Set max sessions
16
+ pp sock.fsctl.max_sessions = 3000
17
+
18
+ # Check up a sofia user
19
+ pp sock.sofia_contact(:contact => "internal/user@domain.com").run
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pp'
4
+ require File.join(File.dirname(__FILE__), "..", 'lib', 'fsr')
5
+ puts $LOAD_PATH.inspect
6
+ $stdout.flush
7
+ require "fsr/listener/inbound"
8
+
9
+
10
+ class IesDemo < FSR::Listener::Inbound
11
+
12
+ def on_event(event)
13
+ pp event.headers
14
+ pp event.content[:event_name]
15
+ end
16
+
17
+ end
18
+
19
+ FSR.start_ies!(IesDemo, :host => "localhost", :port => 8021)
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pp'
4
+ require File.join(File.dirname(__FILE__), "..", 'lib', 'fsr')
5
+ puts $LOAD_PATH.inspect
6
+ $stdout.flush
7
+ require "fsr/listener/inbound"
8
+
9
+ # EXAMPLE 1
10
+ # This adds a hook on CHANNEL_CREATE events. You can also create a method to handle the event you're after. See the next example
11
+ FSL::Inbound.add_event_hook(:CHANNEL_CREATE) {|event| FSR::Log.info "*** [#{event.content[:unique_id]}] Channel created - greetings from the hook!" }
12
+
13
+ # EXAMPLE 2
14
+ # Define a method to handle CHANNEL_HANGUP events.
15
+ def custom_channel_hangup_handler(event)
16
+ FSR::Log.info "*** [#{event.content[:unique_id]}] Channel hangup. The event:"
17
+ pp event
18
+ end
19
+ # This adds a hook for EXAMPLE 2
20
+ FSL::Inbound.add_event_hook(:CHANNEL_HANGUP) {|event| custom_channel_hangup_handler(event) }
21
+
22
+
23
+
24
+
25
+ # Start FSR Inbound Listener
26
+ FSR.start_ies!(FSL::Inbound, :host => "localhost", :port => 8021)
27
+
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), "..", 'lib', 'fsr')
4
+ puts $LOAD_PATH.inspect
5
+ $stdout.flush
6
+ require "fsr/listener/outbound"
7
+
8
+ class OesDemo < FSR::Listener::Outbound
9
+
10
+ def session_initiated(session)
11
+ number = session.headers[:caller_caller_id_number] # Grab the inbound caller id
12
+ FSR::Log.info "*** Answering incoming call from #{number}"
13
+ answer # Answer the call
14
+ log("1", "Pong from the FSR event socket!")
15
+ set("hangup_after_bridge", "true") # Set a variable
16
+ speak 'Hello, This is your phone switch. Have a great day' # use mod_flite to speak
17
+ hangup # Hangup the call
18
+ end
19
+
20
+ end
21
+
22
+ FSR.start_oes!(OesDemo, :port => 1888, :host => "localhost")
@@ -0,0 +1,86 @@
1
+ require 'logger'
2
+ require 'socket'
3
+ require 'pathname'
4
+ require 'pp'
5
+
6
+ module FSR
7
+ # Global configuration options
8
+ #
9
+ VERSION = '0.0.8'
10
+ FS_INSTALL_PATHS = ["/usr/local/freeswitch", "/opt/freeswitch", "/usr/freeswitch"]
11
+ DEFAULT_CALLER_ID_NUMBER = '8675309'
12
+ DEFAULT_CALLER_ID_NAME = "FSR"
13
+
14
+ # Usage:
15
+ #
16
+ # Log.info('foo')
17
+ # Log.debug('bar')
18
+ # Log.warn('foobar')
19
+ # Log.error('barfoo')
20
+ Log = Logger.new($stdout)
21
+ Log.level = Logger::INFO
22
+
23
+ ROOT = Pathname(__FILE__).dirname.expand_path.freeze
24
+ $LOAD_PATH.unshift(FSR::ROOT)
25
+
26
+ # Load all FSR::Cmd classes
27
+ def self.load_all_commands(retrying = false)
28
+ require 'fsr/command_socket'
29
+ load_all_applications
30
+ Cmd.load_all
31
+ end
32
+
33
+ # Load all FSR::App classes
34
+ def self.load_all_applications
35
+ require "fsr/app"
36
+ App.load_all
37
+ end
38
+
39
+ # Method to start EM for Outbound Event Socket
40
+ def self.start_oes!(klass, args = {})
41
+ port = args[:port] || "8084"
42
+ host = args[:host] || "localhost"
43
+ EM.run do
44
+ EventMachine::start_server(host, port, klass)
45
+ FSR::Log.info "*** FreeSWITCHer Outbound EventSocket Listener on #{host}:#{port} ***"
46
+ FSR::Log.info "*** http://code.rubyists.com/projects/fs"
47
+ end
48
+ end
49
+
50
+ # Method to start EM for Inbound Event Socket
51
+ def self.start_ies!(klass, args = {})
52
+ port = args[:port] || "8021"
53
+ host = args[:host] || "localhost"
54
+ EM.run do
55
+ EventMachine::connect(host, port, klass)
56
+ FSR::Log.info "*** FreeSWITCHer Inbound EventSocket Listener connected to #{host}:#{port} ***"
57
+ FSR::Log.info "*** http://code.rubyists.com/projects/fs"
58
+ end
59
+ end
60
+
61
+ private
62
+
63
+ # Find the FreeSWITCH install path if running FSR on a local box with FreeSWITCH installed.
64
+ # This will enable sqlite db access
65
+ def self.find_freeswitch_install
66
+ good_path = FS_INSTALL_PATHS.find do |fs_path|
67
+ Log.warn("#{fs_path} is not a directory!") if File.exists?(fs_path) && !File.directory?(fs_path)
68
+ Log.warn("#{fs_path} is not readable by this user!") if File.exists?(fs_path) && !File.readable?(fs_path)
69
+ Dir["#{fs_path}/{conf,db}/"].size == 2
70
+ end
71
+ if good_path.nil?
72
+ Log.warn("No FreeSWITCH install found, database and configuration functionality disabled")
73
+ return nil
74
+ end
75
+ end
76
+
77
+ FS_ROOT = find_freeswitch_install # FreeSWITCH $${base_dir}
78
+
79
+ if FS_ROOT
80
+ FS_CONFIG_PATH = (FS_ROOT + 'conf').freeze # FreeSWITCH conf dir
81
+ FS_DB_PATH = (FS_ROOT + 'db').freeze # FreeSWITCH db dir
82
+ else
83
+ FS_CONFIG_PATH = FS_DB_PATH = nil
84
+ end
85
+ end
86
+
@@ -0,0 +1,72 @@
1
+ module FSR
2
+ module App
3
+ class Application
4
+ def to_s
5
+ sendmsg
6
+ end
7
+
8
+ def app_name
9
+ self.class.name.split("::").last.downcase
10
+ end
11
+
12
+ # This method builds the API command to send to freeswitch
13
+ def raw
14
+ "%s(%s)" % [app_name, arguments.join(" ")]
15
+ end
16
+
17
+ def sendmsg
18
+ "call-command: execute\nexecute-app-name: %s\nexecute-app-arg: %s\n\n" % [app_name, arguments.join(" ")]
19
+ end
20
+ end
21
+
22
+ APPLICATIONS = {}
23
+ LOAD_PATH = [FSR::ROOT.join("fsr/app")]
24
+ REGISTER_CODE = "def %s(*args, &block); APPLICATIONS[%p].new(*args, &block); end"
25
+
26
+ def self.register(application, obj)
27
+ APPLICATIONS[application.to_sym] = obj
28
+
29
+ code = REGISTER_CODE % [application, application]
30
+ App.module_eval(code)
31
+ end
32
+
33
+ def self.list
34
+ APPLICATIONS.keys
35
+ end
36
+
37
+ def self.load_application(application, force_reload = false)
38
+ exception = nil
39
+
40
+ if Pathname(application).absolute?
41
+ glob = application
42
+ else
43
+ glob = "{#{LOAD_PATH.join(',')}}/#{application}.{so,rb,bundle}"
44
+ end
45
+
46
+ Dir[glob].each do |file|
47
+ begin
48
+ return force_reload ? load(file) : require(file)
49
+ rescue LoadError => exception
50
+ end
51
+ end
52
+
53
+ raise("Couldn't find %s in %p" % [application, LOAD_PATH])
54
+ end
55
+
56
+ # Load all of the applications we find in App::LOAD_PATH
57
+ def self.load_all(force_reload = false)
58
+ glob = "{#{LOAD_PATH.join(',')}}/*.{so,rb,bundle}"
59
+
60
+ Dir[glob].each do |file|
61
+ force_reload ? load(file) : require(file)
62
+ end
63
+
64
+ list
65
+ end
66
+
67
+ def applications
68
+ FSR::App.list
69
+ end
70
+ end
71
+ end
72
+ FSA = FSR::App