freeswitcher 0.4.10 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README CHANGED
@@ -56,27 +56,83 @@ An Inbound Event Socket Listener example using FreeSWITCHeR's hook system:
56
56
  --------------------------------------------------------------------------
57
57
 
58
58
  #!/usr/bin/ruby
59
- require 'pp'
60
59
  require 'fsr'
61
60
  require "fsr/listener/inbound"
62
61
 
63
- # EXAMPLE 1
64
- # 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
65
- FSL::Inbound.add_event_hook(:CHANNEL_CREATE) { FSR::Log.info "*** [#{event.content[:unique_id]}] Channel created - greetings from the hook!" }
62
+ class MyEventListener < FSR::Listener::Inbound
63
+ def before_session
64
+ # 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
65
+ add_event(:CHANNEL_CREATE) { |e| p e }
66
66
 
67
- # EXAMPLE 2
68
- # Define a method to handle CHANNEL_HANGUP events.
69
- def custom_channel_hangup_handler(event)
70
- FSR::Log.info "*** [#{event.content[:unique_id]}] Channel hangup. The event:"
71
- pp event
72
- end
67
+ # This adds a hook on CHANNEL_HANGUP events with a callback method.
68
+ add_event(:CHANNEL_HANGUP) { |e| channel_hangup(e) }
69
+ end
73
70
 
74
- # This adds a hook for EXAMPLE 2
75
- FSL::Inbound.add_event_hook(:CHANNEL_HANGUP) { custom_channel_hangup_handler(event) }
71
+ def channel_hangup(event)
72
+ p event
73
+ end
74
+
75
+ def on_event(event)
76
+ # This gets called for _every_ event that's subscribed (through add_event)
77
+ p event
78
+ end
79
+ end
76
80
 
77
81
 
78
82
  # Start FSR Inbound Listener
79
- FSR.start_ies!(FSL::Inbound, :host => "localhost", :port => 8021)
83
+ FSR.start_ies!(MyEventListener, :host => "localhost", :port => 8021)
84
+
85
+ A More Advanced Example, Publishing Events To A Web Socket:
86
+ -----------------------------------------------------------
87
+
88
+ class MyWebSocketClient < Struct.new(:reporter, :socket, :channel_id)
89
+ Channel = EM::Channel.new
90
+
91
+ def initialize(reporter, socket)
92
+ self.reporter, self.socket = reporter, socket
93
+ socket.onopen(&method(:on_open))
94
+ socket.onmessage(&method(:on_message))
95
+ socket.onclose(&method(:on_close))
96
+ end
97
+
98
+ def on_message(json)
99
+ msg = JSON.parse(json)
100
+ FSR::Log.info "Websocket got #{msg}"
101
+ end
102
+
103
+ def send(msg)
104
+ socket.send(msg.to_json)
105
+ end
106
+
107
+ def on_open
108
+ FSR::Log.info("Subscribed listener")
109
+ self.channel_id = Channel.subscribe { |message| send(message) }
110
+ end
111
+
112
+ def on_close
113
+ Channel.unsubscribe(channel_id)
114
+ FSR::Log.info("Unsubscribed listener")
115
+ end
116
+ end
117
+
118
+ # Add the Channel to your event listener
119
+ class MyEventListener
120
+ def on_event(event)
121
+ MyWebSocketClient::Channel << event.content
122
+ end
123
+ end
124
+
125
+ # Start Listener within and EM.run
126
+ EM.epoll
127
+ EM.run do
128
+ server, port = '127.0.0.1', 8021
129
+ EventMachine.connect(server, port, MyEventListener, auth: 'MyPassword') do |listener|
130
+ FSR::Log.info "MyEventListener connected to #{server} on #{port}"
131
+ EventMachine.start_server('0.0.0.0'), 8080, EventSocket::WebSocket::Connection, {}) do |websocket|
132
+ MyWebSocketClient.new(reporter, websocket)
133
+ end
134
+ end
135
+ end
80
136
 
81
137
 
82
138
  An Inbound Event Socket Listener example using the on_event callback method instead of hooks:
data/Rakefile CHANGED
@@ -15,7 +15,7 @@ GEM_FILES << "spec/fsr_listener_helper.rb" if Pathname("spec/helper.rb").file?
15
15
 
16
16
  GEMSPEC = Gem::Specification.new do |spec|
17
17
  spec.name = "freeswitcher"
18
- spec.version = ENV["FSR_VERSION"] || FSR::VERSION
18
+ spec.version = (ENV["FSR_VERSION"] || FSR::VERSION).dup
19
19
  spec.summary = 'A library for interacting with the "FreeSWITCH":http://freeswitch.org telephony platform'
20
20
  spec.authors = ["Jayson Vaughn", "Michael Fellinger", "Kevin Berry", "TJ Vanderpoel"]
21
21
  spec.email = "FreeSWITCHeR@rubyists.com"
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), "..", 'lib', 'fsr')
4
+ require "fsr/listener/outbound"
5
+ $stdout.flush
6
+
7
+ class PlayAndGetDigitsDemo < FSR::Listener::Outbound
8
+
9
+ def session_initiated
10
+ exten = @session.headers[:caller_caller_id_number]
11
+ FSR::Log.info "*** Answering incoming call from #{exten}"
12
+
13
+ answer do
14
+ FSR::Log.info "***Reading DTMF from #{exten}"
15
+ #######################################################
16
+ ## NOTE YOU MUST MAKE SURE YOU PASS A VALID WAV FILE ##
17
+ #######################################################
18
+ play_and_get_digits("/usr/local/freeswitch/sounds/music/8000/sweet.wav","/usr/local/freeswitch/sounds/music/8000/not.wav", :chan_var => rand(10000).to_s) do |read_var|
19
+ FSR::Log.info "***Success, grabbed #{read_var.to_s.strip} from #{exten}"
20
+ # Tell the caller what they entered
21
+ # If you have mod_flite installed you should hear speech
22
+ speak("Got the DTMF of: #{read_var.to_s.strip}") { hangup }
23
+ end
24
+ end
25
+
26
+ def receive_reply(reply)
27
+ FSR::Log.info "Received #{reply.inspect}"
28
+ end
29
+
30
+ end
31
+
32
+ end
33
+
34
+ FSR.start_oes! PlayAndGetDigitsDemo, :port => 8084, :host => "0.0.0.0"
data/lib/fsr.rb CHANGED
@@ -34,7 +34,10 @@ module FSR
34
34
  end
35
35
 
36
36
  ROOT = Pathname(__FILE__).dirname.expand_path.freeze
37
- $LOAD_PATH.unshift(FSR::ROOT)
37
+ $LOAD_PATH.unshift(FSR::ROOT.to_s)
38
+
39
+ FSR_ROOT = Pathname(__FILE__).join("..").dirname.expand_path.freeze
40
+ $LOAD_PATH.unshift(FSR::FSR_ROOT.to_s)
38
41
 
39
42
  # Load all FSR::Cmd classes
40
43
  def self.load_all_commands(retrying = false)
@@ -1,8 +1,13 @@
1
1
  require "fsr/app"
2
+ require 'fsr/file_methods'
3
+
2
4
  module FSR
3
5
  #http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_play_and_get_digits
4
6
  module App
5
7
  class PlayAndGetDigits < Application
8
+
9
+ include ::FSR::App::FileMethods
10
+
6
11
  attr_reader :chan_var
7
12
  DEFAULT_ARGS = {:min => 0, :max => 10, :tries => 3, :timeout => 7000, :terminators => ["#"], :chan_var => "fsr_read_dtmf", :regexp => '\d'}
8
13
 
@@ -30,6 +35,9 @@ module FSR
30
35
  @chan_var = arg_hash[:chan_var]
31
36
  @terminators = arg_hash[:terminators]
32
37
  @regexp = arg_hash[:regexp]
38
+
39
+ raise unless test_files(@sound_file, @invalid_file)
40
+
33
41
  end
34
42
 
35
43
  def arguments
@@ -1,19 +1,25 @@
1
1
  require "fsr/app"
2
+ require 'fsr/file_methods'
2
3
  module FSR
3
4
  module App
4
5
  class Playback < Application
6
+
7
+ include ::FSR::App::FileMethods
8
+
5
9
  attr_reader :wavfile
6
10
 
7
11
  def initialize(wavfile)
8
- # wav file you wish to play, full path
12
+ # wav file you wish to play, full path
13
+ test_files wavfile
9
14
  @wavfile = wavfile
10
15
  end
16
+
11
17
  def arguments
12
18
  @wavfile
13
19
  end
14
20
 
15
21
  def sendmsg
16
- "call-command: execute\nexecute-app-name: %s\nexecute-app-arg: %s\nevent-lock:true\n\n" % [app_name, arguments]
22
+ "call-command: execute\nexecute-app-name: %s\nexecute-app-arg: %s\nevent-lock:true\n\n" % [app_name, arguments]
17
23
  end
18
24
  end
19
25
 
@@ -0,0 +1,156 @@
1
+ require "fsr/app"
2
+ module FSR
3
+ module Cmd
4
+ class CallCenter < Command
5
+ attr_accessor :cmd
6
+ def initialize(fs_socket = nil, config_type = :agent)
7
+ @fs_socket = fs_socket # FSR::CommandSocket obj
8
+ @config_type = config_type
9
+ @last_repsonse = nil
10
+ @cmd = []
11
+ end
12
+
13
+ def list_agent
14
+ ["list"]
15
+ end
16
+
17
+ def last_response
18
+ responses.last
19
+ end
20
+
21
+ def responses
22
+ @responses ||= []
23
+ end
24
+
25
+ def list_tier(queue)
26
+ ["list", queue]
27
+ end
28
+
29
+ def list_queue(queue=nil)
30
+ ["list", queue].compact
31
+ end
32
+
33
+ def list(*args)
34
+ @listing = true
35
+ @cmd = case @config_type
36
+ when :agent
37
+ list_agent(*args)
38
+ when :tier
39
+ list_tier(*args)
40
+ when :queue
41
+ list_queue(*args)
42
+ else
43
+ raise "no such config_type #{@config_type}"
44
+ end
45
+ self
46
+ end
47
+
48
+
49
+ def set_agent(agent, field, value)
50
+ value = value.respond_to?(:each_char) ? "'#{value}'" : value
51
+ ["set", field.to_s, "'#{agent}'", value].compact
52
+ end
53
+
54
+ def set_tier(agent, queue, field, value)
55
+ ["set", field.to_s, queue, agent, "'#{value}'"].compact
56
+ end
57
+
58
+ def set(agent, *args)
59
+ @listing = false
60
+ @cmd = case @config_type
61
+ when :agent
62
+ set_agent(agent, *args)
63
+ when :tier
64
+ set_tier(agent, *args)
65
+ else
66
+ raise "Cannot run set on #{@config_type}"
67
+ end
68
+ self
69
+ end
70
+
71
+ def add_tier(agent, queue, level = 1, position = nil)
72
+ ["add", queue, agent, level, position].compact
73
+ end
74
+
75
+ def add_agent(agent, callback = nil)
76
+ callback ||= 'callback'
77
+ ["add", "'#{agent}'", callback].compact
78
+ end
79
+
80
+ def add(agent, *args)
81
+ @listing = false
82
+ @cmd = case @config_type
83
+ when :agent
84
+ add_agent(agent, *args)
85
+ when :tier
86
+ add_tier(agent, *args)
87
+ else
88
+ raise "Cannot add to #{@config_type}"
89
+ end
90
+ self
91
+ end
92
+
93
+ protected :list_agent, :list_tier, :list_queue, :set_agent, :set_tier, :add_tier, :add_agent
94
+ def del(agent, queue = nil)
95
+ @listing = false
96
+ @cmd = ["del", queue, agent].compact
97
+ self
98
+ end
99
+
100
+ def run(api_method = :api)
101
+ orig_command = "%s %s" % [api_method, raw]
102
+ resp = @fs_socket.say(orig_command)
103
+ responses << resp
104
+ if @listing
105
+ if resp["body"].match(/^([^|]*\|[^|]*)+/)
106
+ require "csv"
107
+ csv = CSV.parse(resp["body"], :col_sep => '|', :headers => true)
108
+ case @config_type
109
+ when :tier
110
+ require "fsr/model/tier"
111
+ csv.to_a[1 .. -2].map { |c| FSR::Model::Tier.new(csv.headers, *c) }
112
+ when :queue
113
+ require "fsr/model/queue"
114
+ csv.to_a[1 .. -2].map { |c| FSR::Model::Queue.new(csv.headers, *c) }
115
+ when :agent
116
+ require "fsr/model/agent"
117
+ csv.to_a[1 .. -2].map { |c| FSR::Model::Agent.new(csv.headers, *c) }
118
+ end
119
+ else
120
+ []
121
+ end
122
+ else
123
+ resp["body"].to_s =~ /\+OK$/
124
+ end
125
+ end
126
+ =begin
127
+ # Send the command to the event socket, using bgapi by default.
128
+ def run(api_method = :api)
129
+ orig_command = "%s %s" % [api_method, raw]
130
+ Log.debug "saying #{orig_command}"
131
+ resp = @fs_socket.say(orig_command)
132
+ unless resp["body"] == "0 total."
133
+ call_info, count = resp["body"].split("\n\n")
134
+ require "fsr/model/call"
135
+ begin
136
+ require "fastercsv"
137
+ @calls = FCSV.parse(call_info)
138
+ rescue LoadError
139
+ require "csv"
140
+ @calls = CSV.parse(call_info)
141
+ end
142
+ return @calls[1 .. -1].map { |c| FSR::Model::Call.new(@calls[0],*c) }
143
+ end
144
+ []
145
+ end
146
+ =end
147
+
148
+ # This method builds the API command to send to the freeswitch event socket
149
+ def raw
150
+ ["callcenter_config", @config_type, *@cmd].join(" ")
151
+ end
152
+ end
153
+
154
+ register(:call_center, CallCenter)
155
+ end
156
+ end
data/lib/fsr/cmd/calls.rb CHANGED
@@ -25,14 +25,14 @@ module FSR
25
25
  require "fsr/model/call"
26
26
  begin
27
27
  require "fastercsv"
28
- calls = FCSV.parse(call_info)
28
+ @calls = FCSV.parse(call_info)
29
29
  rescue LoadError
30
30
  require "csv"
31
- calls = CSV.parse(call_info)
31
+ @calls = CSV.parse(call_info)
32
32
  end
33
- return calls[1 .. -1].map { |c| FSR::Model::Call.new(*c) }
33
+ return @calls[1 .. -1].map { |c| FSR::Model::Call.new(@calls[0],*c) }
34
34
  end
35
- nil
35
+ []
36
36
  end
37
37
 
38
38
  # This method builds the API command to send to the freeswitch event socket
@@ -0,0 +1,47 @@
1
+ require "fsr/app"
2
+ module FSR
3
+ module Cmd
4
+ class Channels < Command
5
+
6
+ include Enumerable
7
+ def each(&block)
8
+ @channels ||= run
9
+ if @channels
10
+ @channels.each { |call| yield call }
11
+ end
12
+ end
13
+
14
+ def initialize(fs_socket = nil, distinct = true)
15
+ @distinct = distinct
16
+ @fs_socket = fs_socket # FSR::CommandSocket obj
17
+ end
18
+
19
+ # Send the command to the event socket, using bgapi by default.
20
+ def run(api_method = :api)
21
+ orig_command = "%s %s" % [api_method, raw]
22
+ Log.debug "saying #{orig_command}"
23
+ resp = @fs_socket.say(orig_command)
24
+ unless resp["body"] == "0 total."
25
+ call_info, count = resp["body"].split("\n\n")
26
+ require "fsr/model/channel"
27
+ begin
28
+ require "fastercsv"
29
+ @channels = FCSV.parse(call_info)
30
+ rescue LoadError
31
+ require "csv"
32
+ @channels = CSV.parse(call_info)
33
+ end
34
+ return @channels[1 .. -1].map { |c| FSR::Model::Channel.new(@channels[0],*c) }
35
+ end
36
+ []
37
+ end
38
+
39
+ # This method builds the API command to send to the freeswitch event socket
40
+ def raw
41
+ orig_command = @distinct ? "show distinct_channels" : "show channels"
42
+ end
43
+ end
44
+
45
+ register(:channels, Channels)
46
+ end
47
+ end
@@ -0,0 +1,40 @@
1
+ require "fsr/app"
2
+ module FSR
3
+ module Cmd
4
+ class Enum < Command
5
+ attr_reader :ph_nbr
6
+
7
+ def initialize(fs_socket = nil, phone_number = nil)
8
+ @fs_socket = fs_socket # FSR::CommandSocket obj
9
+ @ph_nbr = phone_number # phone number to look up, up to 15 digits
10
+ end
11
+
12
+ # Send the command to the event socket, using api by default.
13
+ def run(api_method = :api)
14
+ orig_command = "%s %s" % [api_method, raw]
15
+ Log.debug "saying #{orig_command}"
16
+ resp = @fs_socket.say(orig_command)
17
+ parse(resp)
18
+ end
19
+
20
+ # This method builds the API command to send to the freeswitch event socket
21
+ def raw
22
+ orig_command = "enum #{ph_nbr}"
23
+ end
24
+
25
+ def parse(response)
26
+ body = response["body"]
27
+ offered_routes,supported_routes = body.match(/Offered\ Routes:(.*?)Supported\ Routes:(.*?)/mx)[1 .. 2]
28
+ order, pref, service, route = offered_routes.match(/==+\n(.*)/m)[1].split
29
+ unless body == "No Match!"
30
+ require "fsr/model/enum"
31
+ return FSR::Model::Enum.new(offered_routes, supported_routes, order, pref, service, route)
32
+ end
33
+ nil
34
+ end
35
+
36
+ end
37
+
38
+ register(:enum, Enum)
39
+ end
40
+ end