freeswitcher 0.4.10 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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