ruby-asterisk 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,32 +1,31 @@
1
1
  module RubyAsterisk
2
+ ##
3
+ #
4
+ # Class responsible of building commands structure
5
+ #
2
6
  class Request
3
7
  attr_accessor :action, :action_id, :parameters, :response_data
4
8
 
5
- def initialize(action,parameters={})
9
+ def initialize(action, parameters = {})
6
10
  self.action = action
7
- self.action_id = self.generate_action_id
11
+ self.action_id = Request.generate_action_id
8
12
  self.parameters = parameters
9
- self.response_data = ""
13
+ self.response_data = ''
10
14
  end
11
15
 
12
16
  def commands
13
- _commands=["Action: "+self.action+"\r\n","ActionID: "+self.action_id+"\r\n"]
14
- self.parameters.each do |key,value|
15
- _commands<<key+": "+value+"\r\n" unless value.nil?
17
+ _commands = ["Action: #{self.action}\r\n", "ActionID: #{self.action_id}\r\n"]
18
+ self.parameters.each do |key, value|
19
+ _commands<<"#{key.to_s}: #{value.to_s}\r\n" unless value.nil?
16
20
  end
17
- _commands[_commands.length-1]<<"\r\n"
21
+ _commands[_commands.length - 1] << "\r\n"
18
22
  _commands
19
- end
23
+ end
20
24
 
21
25
  protected
22
26
 
23
- def generate_action_id
24
- if RUBY_VERSION.start_with?("1.9")
25
- Random.rand(999).to_s
26
- else
27
- rand(999).to_s
28
- end
27
+ def self.generate_action_id
28
+ Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond).to_s(36)
29
29
  end
30
-
31
30
  end
32
31
  end
@@ -1,33 +1,38 @@
1
+ require 'ruby-asterisk/response_parser'
2
+
1
3
  module RubyAsterisk
4
+ ##
5
+ #
6
+ # Class for response coming from Asterisk
7
+ #
2
8
  class Response
3
- attr_accessor :type, :success, :action_id, :message, :data, :raw_response
9
+ attr_accessor :type, :action_id, :message, :data, :raw_response
4
10
 
5
11
  def initialize(type,response)
6
12
  self.raw_response = response
7
13
  self.type = type
8
- self.success = self._parse_successfull(response)
9
- self.action_id = self._parse_action_id(response)
10
- self.message = self._parse_message(response)
11
- self.data = self._parse_data(response)
14
+ self.action_id = self._parse_action_id
15
+ self.message = self._parse_message
16
+ self.data = self._parse_response
12
17
  end
13
18
 
14
- protected
15
-
16
- def _parse_successfull(response)
17
- response.include?("Response: Success")
19
+ def success
20
+ self.raw_response.include?("Response: Success")
18
21
  end
19
22
 
20
- def _parse_action_id(response)
21
- self._parse(response,"ActionID:")
23
+ protected
24
+
25
+ def _parse_action_id
26
+ self._parse("ActionID:")
22
27
  end
23
28
 
24
- def _parse_message(response)
25
- self._parse(response,"Message:")
29
+ def _parse_message
30
+ self._parse("Message:")
26
31
  end
27
32
 
28
- def _parse(response,field)
33
+ def _parse(field)
29
34
  _value = nil
30
- response.each_line do |line|
35
+ self.raw_response.each_line do |line|
31
36
  if line.start_with?(field)
32
37
  _value = line[line.rindex(":")+1..line.size].strip
33
38
  end
@@ -35,128 +40,9 @@ module RubyAsterisk
35
40
  _value
36
41
  end
37
42
 
38
- def _parse_data(response)
39
- case self.type
40
- when "CoreShowChannels"
41
- self._parse_data_core_show_channels(response)
42
- when "ParkedCalls"
43
- self._parse_data_parked_calls(response)
44
- when "Originate"
45
- self._parse_originate(response)
46
- when "MeetMeList"
47
- self._parse_meet_me_list(response)
48
- when "Status"
49
- self._parse_status(response)
50
- when "ExtensionState"
51
- self._parse_extension_state(response)
52
- when "SKINNYdevices"
53
- self._parse_skinny_devices(response)
54
- when "SKINNYlines"
55
- self._parse_skinny_lines(response)
56
- when "Command"
57
- response
58
- when "QueuePause"
59
- self._parse_queue_pause(response)
60
- when "Pong"
61
- self._parse_pong(response)
62
- when "Events"
63
- self._parse_event_mask(response)
64
- when "SIPpeers"
65
- self._parse_sip_peers(response)
66
- end
67
-
68
- end
69
-
70
- def _parse_sip_peers(response)
71
- self._parse_objects(response, :peers, "Event: PeerEntry")
72
- end
73
-
74
- def _parse_meet_me_list(response)
75
- self._parse_objects(response,:rooms,"Event: MeetmeList")
76
- end
77
-
78
- def _parse_originate(response)
79
- self._parse_objects(response,:dial,"Event: Dial")
80
- end
81
-
82
- def _parse_data_parked_calls(response)
83
- self._parse_objects(response,:calls,"Event: ParkedCall")
84
- end
85
-
86
- def _parse_data_core_show_channels(response)
87
- self._parse_objects(response,:channels,"Event: CoreShowChannel","Event: CoreShowChannelsComplete")
43
+ def _parse_response
44
+ ResponseParser.parse(self.raw_response, self.type)
88
45
  end
89
46
 
90
- def _parse_extension_state(response)
91
- _data = self._parse_objects(response,:hints,"Response:")
92
- self._convert_status(_data)
93
- end
94
-
95
- def _parse_skinny_devices(response)
96
- self._parse_objects(response,:skinnydevs,"Event: DeviceEntry")
97
- end
98
-
99
- def _parse_skinny_lines(response)
100
- self._parse_objects(response,:skinnylines,"Event: LineEntry")
101
- end
102
-
103
- def _parse_queue_pause(response)
104
- _data = self._parse_objects(response,:queue_pause,"Response:")
105
- end
106
-
107
- def _parse_pong(response)
108
- _data = self._parse_objects(response,:pong, "Response:")
109
- end
110
-
111
- def _parse_event_mask(response)
112
- _data = self._parse_objects(response, :event_mask, "Ping:")
113
- end
114
-
115
- def _parse_status(response)
116
- self._parse_objects(response, :status, "Event: Status")
117
- end
118
-
119
- def _convert_status(_data)
120
- _data[:hints].each do |hint|
121
- case hint["Status"]
122
- when "-1"
123
- hint["DescriptiveStatus"] = "Extension not found"
124
- when "0"
125
- hint["DescriptiveStatus"] = "Idle"
126
- when "1"
127
- hint["DescriptiveStatus"] = "In Use"
128
- when "2"
129
- hint["DescriptiveStatus"] = "Busy"
130
- when "4"
131
- hint["DescriptiveStatus"] = "Unavailable"
132
- when "8"
133
- hint["DescriptiveStatus"] = "Ringing"
134
- when "16"
135
- hint["DescriptiveStatus"] = "On Hold"
136
- end
137
- end
138
- _data
139
- end
140
-
141
- def _parse_objects(response,symbol_name,search_for,stop_with=nil)
142
- _data = { symbol_name => [] }
143
- parsing = false
144
- object = nil
145
- response.each_line do |line|
146
- line.strip!
147
- if line.strip.empty? or (!stop_with.nil? and line.start_with?(stop_with))
148
- parsing = false
149
- elsif line.start_with?(search_for)
150
- _data[symbol_name] << object unless object.nil?
151
- object = {}
152
- parsing = true
153
- elsif parsing
154
- tokens = line.split(':', 2)
155
- object[tokens[0].strip]=tokens[1].strip unless tokens[1].nil?
156
- end
157
- end
158
- _data[symbol_name] << object unless object.nil?
159
- _data
160
- end
161
47
  end
162
48
  end
@@ -0,0 +1,42 @@
1
+ require 'ruby-asterisk/parsing_constants'
2
+
3
+ module RubyAsterisk
4
+ ##
5
+ #
6
+ # Class for parsing response coming from Asterisk
7
+ #
8
+ class ResponseParser
9
+
10
+ def self.parse(raw_response, type)
11
+ if PARSE_DATA.include?(type)
12
+ self._parse_objects(raw_response, PARSE_DATA[type])
13
+ else
14
+ raw_response
15
+ end
16
+ end
17
+
18
+ protected
19
+
20
+ def self._add_status(exten_array)
21
+ exten_array.each do |hint|
22
+ hint["DescriptiveStatus"] = DESCRIPTIVE_STATUS[hint["Status"]]
23
+ end
24
+ exten_array
25
+ end
26
+
27
+ def self._parse_objects(response, parse_params)
28
+ object_array = []
29
+ object_regex = Regexp.new(/#{parse_params[:search_for]}\n(.*?)\n\n/m)
30
+ response.scan(object_regex) do |match|
31
+ object = {}
32
+ match[0].split(/\n/).each do |line|
33
+ tokens = line.split(':', 2)
34
+ object[tokens[0].strip]=tokens[1].strip unless tokens[1].nil?
35
+ end
36
+ object_array << object unless object.empty?
37
+ end
38
+ object_array = _add_status(object_array) if parse_params[:symbol].eql?(:hints)
39
+ { parse_params[:symbol] => object_array }
40
+ end
41
+ end
42
+ end
@@ -1,3 +1,3 @@
1
1
  module Rami
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -7,10 +7,11 @@ Gem::Specification.new do |s|
7
7
  s.version = Rami::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
9
  s.authors = ["Emiliano Della Casa"]
10
- s.email = ["e.dellacasa@engim.eu"]
10
+ s.email = ["emiliano.dellacasa@gmail.com"]
11
11
  s.homepage = "http://github.com/emilianodellacasa/ruby-asterisk"
12
12
  s.summary = %q{Asterisk Manager Interface in Ruby}
13
13
  s.description = %q{Add support to your ruby or rails projects to Asterisk Manager Interface (AMI)}
14
+ s.licenses = ['MIT']
14
15
 
15
16
  s.rubyforge_project = "ruby-asterisk"
16
17
 
@@ -19,6 +20,8 @@ Gem::Specification.new do |s|
19
20
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
21
  s.require_paths = ["lib"]
21
22
 
22
- s.add_development_dependency "rake"
23
- s.add_development_dependency 'rspec'
23
+ s.add_development_dependency "rake"
24
+ s.add_development_dependency 'rspec'
25
+ s.add_development_dependency 'simplecov'
26
+ s.add_development_dependency 'quality'
24
27
  end
@@ -8,7 +8,7 @@ describe RubyAsterisk::Request do
8
8
  request.commands.include?("Variable: var1=15\r\n").should_not be_nil
9
9
  end
10
10
 
11
- it "should not set a Variable option if not set" do
11
+ it "should not set a Variable option if not set" do
12
12
  request = RubyAsterisk::Request.new("Originate",{"Channel" => "1234", "Context" => "test", "Exten" => "1", "Priority" => "1", "Callerid" => "1234", "Timeout" => "30000", "Variable" => nil })
13
13
  request.commands.include?("Variable: var=15").should==false
14
14
  end
@@ -5,130 +5,130 @@ describe RubyAsterisk::Response do
5
5
  def sip_peers_response
6
6
  "Response: Success
7
7
  Message: Peer status list will follow
8
-
8
+
9
9
  Event: PeerEntry
10
10
  Channeltype: SIP
11
11
  ObjectName: 9915057
12
- IPport: 5060"
12
+ IPport: 5060\n\n"
13
+ end
14
+
15
+ def empty_core_show_channels_response
16
+ "Event: CoreShowChannelsComplete
17
+ EventList: Complete
18
+ ListItems: 1
19
+ ActionID: 839\n\n"
13
20
  end
14
21
 
15
- def empty_core_show_channels_response
16
- "Event: CoreShowChannelsComplete
17
- EventList: Complete
22
+ def core_show_channels_response
23
+ "Event: CoreShowChannel
24
+ ActionID: 839
25
+ Channel: SIP/195.62.226.4-00000025
26
+ UniqueID: 1335448133.61
27
+ Context: incoming
28
+ Extension: s
29
+ Priority: 1
30
+ ChannelState: 6
31
+ ChannelStateDesc: Up
32
+ Application: Parked Call
33
+ ApplicationData:
34
+ CallerIDnum: 123456
35
+ CallerIDname:
36
+ ConnectedLineNum:
37
+ ConnectedLineName:
38
+ Duration: 00:00:05
39
+ AccountCode:
40
+ BridgedChannel:
41
+ BridgedUniqueID:
42
+
43
+ Event: CoreShowChannelsComplete
44
+ EventList: Complete
18
45
  ListItems: 1
19
- ActionID: 839"
20
- end
21
-
22
- def core_show_channels_response
23
- "Event: CoreShowChannel
24
- ActionID: 839
25
- Channel: SIP/195.62.226.4-00000025
26
- UniqueID: 1335448133.61
27
- Context: incoming
28
- Extension: s
29
- Priority: 1
30
- ChannelState: 6
31
- ChannelStateDesc: Up
32
- Application: Parked Call
33
- ApplicationData:
34
- CallerIDnum: 123456
35
- CallerIDname:
36
- ConnectedLineNum:
37
- ConnectedLineName:
38
- Duration: 00:00:05
39
- AccountCode:
40
- BridgedChannel:
41
- BridgedUniqueID:
42
-
43
- Event: CoreShowChannelsComplete
44
- EventList: Complete
45
- ListItems: 1
46
- ActionID: 839"
47
- end
48
-
49
- def parked_calls_response
50
- "Event: ParkedCall
51
- Parkinglot: default
52
- Exten: 701
53
- Channel: SIP/195.62.226.2-00000026
54
- From: SIP/195.62.226.2-00000026
55
- Timeout: 3
56
- CallerIDNum: 123456
57
- CallerIDName:
58
- ConnectedLineNum:
59
- ConnectedLineName:
60
- ActionID: 899"
61
- end
62
-
63
- def originate_response
64
- "Event: Dial
65
- Privilege: call,all
66
- SubEvent: End
67
- Channel: SIP/9100-0000002b
68
- UniqueID: 1335457364.68
69
- DialStatus: CHANUNAVAIL"
70
- end
71
-
72
- def meet_me_list_response
73
- "Event: MeetmeList
74
- ActionID: 921
75
- Conference: 1234
76
- UserNumber: 1
77
- CallerIDNum: 123456
78
- CallerIDName: <no name>
79
- ConnectedLineNum: <unknown>
80
- ConnectedLineName: <no name>
81
- Channel: SIP/195.62.226.18-0000000e
82
- Admin: No
83
- Role: Talk and listen
84
- MarkedUser: No
85
- Muted: No
86
- Talking: Not monitored"
87
- end
88
-
89
- def extension_state_response
90
- "Response: Success
91
- ActionID: 180
92
- Message: Extension Status
93
- Exten: 9100
94
- Context: HINT
95
- Hint: SIP/9100
96
- Status: 0"
97
- end
98
-
99
- describe ".new" do
100
-
101
- describe "receiving a Core Show Channels request" do
102
- it "should parse correctly data coming from Asterisk about channels" do
103
- @response = RubyAsterisk::Response.new("CoreShowChannels",core_show_channels_response)
104
- @response.data[:channels].should_not be_empty
105
- end
106
-
107
- it "should correctly fill the fields" do
46
+ ActionID: 839\n\n"
47
+ end
48
+
49
+ def parked_calls_response
50
+ "Event: ParkedCall
51
+ Parkinglot: default
52
+ Exten: 701
53
+ Channel: SIP/195.62.226.2-00000026
54
+ From: SIP/195.62.226.2-00000026
55
+ Timeout: 3
56
+ CallerIDNum: 123456
57
+ CallerIDName:
58
+ ConnectedLineNum:
59
+ ConnectedLineName:
60
+ ActionID: 899\n\n"
61
+ end
62
+
63
+ def originate_response
64
+ "Event: Dial
65
+ Privilege: call,all
66
+ SubEvent: End
67
+ Channel: SIP/9100-0000002b
68
+ UniqueID: 1335457364.68
69
+ DialStatus: CHANUNAVAIL\n\n"
70
+ end
71
+
72
+ def meet_me_list_response
73
+ "Event: MeetmeList
74
+ ActionID: 921
75
+ Conference: 1234
76
+ UserNumber: 1
77
+ CallerIDNum: 123456
78
+ CallerIDName: <no name>
79
+ ConnectedLineNum: <unknown>
80
+ ConnectedLineName: <no name>
81
+ Channel: SIP/195.62.226.18-0000000e
82
+ Admin: No
83
+ Role: Talk and listen
84
+ MarkedUser: No
85
+ Muted: No
86
+ Talking: Not monitored\n\n"
87
+ end
88
+
89
+ def extension_state_response
90
+ "Response: Success
91
+ ActionID: 180
92
+ Message: Extension Status
93
+ Exten: 9100
94
+ Context: HINT
95
+ Hint: SIP/9100
96
+ Status: 0\n\n"
97
+ end
98
+
99
+ describe ".new" do
100
+
101
+ describe "receiving a Core Show Channels request" do
102
+ it "should parse correctly data coming from Asterisk about channels" do
103
+ @response = RubyAsterisk::Response.new("CoreShowChannels",core_show_channels_response)
104
+ @response.data[:channels].should_not be_empty
105
+ end
106
+
107
+ it "should correctly fill the fields" do
108
108
  @response = RubyAsterisk::Response.new("CoreShowChannels",core_show_channels_response)
109
109
  @response.data[:channels][0]["CallerIDnum"].should eq("123456")
110
110
  end
111
111
 
112
- it "should have no channels if answer is empty" do
113
- @response = RubyAsterisk::Response.new("CoreShowChannels",empty_core_show_channels_response)
114
- @response.data[:channels].count.should eq(0)
115
- end
116
- end
117
-
118
- describe "receiving a Parked Calls request" do
119
- it "should parse correctly data coming from Asterisk about calls" do
120
- @response = RubyAsterisk::Response.new("ParkedCalls",parked_calls_response)
121
- @response.data[:calls].should_not be_empty
122
- end
123
-
124
- it "should correctly fill the fields" do
125
- @response = RubyAsterisk::Response.new("ParkedCalls",parked_calls_response)
126
- @response.data[:calls][0]["Exten"].should eq("701")
127
- end
128
- end
129
-
130
- describe "receiving a Originate request" do
131
- it "should parse correctly data coming from Asterisk about the call" do
112
+ it "should have no channels if answer is empty" do
113
+ @response = RubyAsterisk::Response.new("CoreShowChannels",empty_core_show_channels_response)
114
+ @response.data[:channels].count.should eq(0)
115
+ end
116
+ end
117
+
118
+ describe "receiving a Parked Calls request" do
119
+ it "should parse correctly data coming from Asterisk about calls" do
120
+ @response = RubyAsterisk::Response.new("ParkedCalls",parked_calls_response)
121
+ @response.data[:calls].should_not be_empty
122
+ end
123
+
124
+ it "should correctly fill the fields" do
125
+ @response = RubyAsterisk::Response.new("ParkedCalls",parked_calls_response)
126
+ @response.data[:calls][0]["Exten"].should eq("701")
127
+ end
128
+ end
129
+
130
+ describe "receiving a Originate request" do
131
+ it "should parse correctly data coming from Asterisk about the call" do
132
132
  @response = RubyAsterisk::Response.new("Originate",originate_response)
133
133
  @response.data[:dial].should_not be_empty
134
134
  end
@@ -143,8 +143,8 @@ describe RubyAsterisk::Response do
143
143
  @response.raw_response.should eq(originate_response)
144
144
  end
145
145
  end
146
-
147
- describe "receiving a MeetMeList request" do
146
+
147
+ describe "receiving a MeetMeList request" do
148
148
  it "should parse correctly data coming from Asterisk about the conference room" do
149
149
  @response = RubyAsterisk::Response.new("MeetMeList",meet_me_list_response)
150
150
  @response.data[:rooms].should_not be_empty
@@ -156,7 +156,7 @@ describe RubyAsterisk::Response do
156
156
  end
157
157
  end
158
158
 
159
- describe "receiving a ExtensionState request" do
159
+ describe "receiving a ExtensionState request" do
160
160
  it "should parse correctly data coming from Asterisk about the state of the extension" do
161
161
  @response = RubyAsterisk::Response.new("ExtensionState",extension_state_response)
162
162
  @response.data[:hints].should_not be_empty
@@ -165,17 +165,17 @@ describe RubyAsterisk::Response do
165
165
  it "should correctly fill the fields" do
166
166
  @response = RubyAsterisk::Response.new("ExtensionState",extension_state_response)
167
167
  @response.data[:hints][0]["Status"].should eq("0")
168
- @response.data[:hints][0]["DescriptiveStatus"].should eq("Idle")
168
+ @response.data[:hints][0]["DescriptiveStatus"].should eq("Idle")
169
169
  end
170
170
  end
171
- end
171
+ end
172
172
 
173
173
  describe "receiving a SIPPeers request" do
174
174
  it "should parse correctly data coming from Asterisk abous sip peers" do
175
175
  @response = RubyAsterisk::Response.new("SIPpeers",sip_peers_response)
176
176
  @response.data[:peers].should_not be_empty
177
177
  end
178
-
178
+
179
179
  it "should correctly fill the fields" do
180
180
  @response = RubyAsterisk::Response.new("SIPpeers",sip_peers_response)
181
181
  @response.data[:peers][0]["ObjectName"].should eq("9915057")