ruby-asterisk 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,3 @@
1
+ ## v0.0.1
2
+
3
+ * Initial release
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in rami.gemspec
4
+ gemspec
@@ -0,0 +1,87 @@
1
+ # RUBY-ASTERISK
2
+
3
+ This gem add support to your Ruby or RubyOnRails projects to Asterisk Manager Interface
4
+
5
+ There was a project with the same name, but it appears to be discontinued so I decided to start a new project
6
+
7
+ ## Installation
8
+
9
+ ### Rails3
10
+
11
+ Add to your Gemfile and run the `bundle` command to install it.
12
+
13
+ ```ruby
14
+ gem "ruby-asterisk"
15
+ ```
16
+
17
+ ### Rails2
18
+
19
+ Simply run in your terminal
20
+
21
+ ```ruby
22
+ gem install ruby-asterisk
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ### INITIALIZE
28
+
29
+ To create a new AMI session, just call the following command
30
+
31
+ ```ruby
32
+ @ami = RubyAsterisk::AMI.new("192.168.1.1",5038)
33
+ ```
34
+
35
+ ### LOGIN
36
+
37
+ To log in, provide to the created sessions a valid username and password
38
+
39
+ ```ruby
40
+ @ami.login("mark","mysecret")
41
+ ```
42
+
43
+ Like all commands, it will return a Response command that could be parsed accordingly
44
+
45
+ ### CORE SHOW CHANNELS
46
+
47
+ To get a list of all channels currently active on your Asterisk installation, use the following command
48
+
49
+ ```ruby
50
+ @ami.core_show_channels
51
+ ```
52
+
53
+ ### PARKED CALLS
54
+
55
+ To get a list of all parked calls on your Asterisk PBX, use the following command
56
+
57
+ ```ruby
58
+ @ami.parked_calls
59
+ ```
60
+
61
+ ### ORIGINATE
62
+
63
+ To start a new call use the following command
64
+
65
+ ```ruby
66
+ @ami.originate("SIP/9100","OUTGOING","123456","1") # CALLER, CONTEXT, CALLEE, PRIORITY
67
+ ```
68
+
69
+
70
+ ### THE RESPONSE OBJECT
71
+
72
+ The response object contains all information about all data received from Asterisk. Here follows a list of all object's properties:
73
+
74
+ - type
75
+ - success
76
+ - action_id
77
+ - message
78
+ - data
79
+
80
+ The data property contains all additional information obtained from Asterisk, like for example the list of active channels after a "core show channels" command.
81
+
82
+ ## Development
83
+
84
+ Questions or problems? Please post them on the [issue tracker](https://github.com/emilianodellacasa/ruby-asterisk/issues). You can contribute changes by forking the project and submitting a pull request. You can ensure the tests passing by running `bundle` and `rake`.
85
+
86
+ This gem is created by Emiliano Della Casa and is under the MIT License and it is distributed by courtesy of [Engim srl](http://www.engim.eu/en).
87
+
@@ -0,0 +1,8 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec'
5
+ require 'rspec/core/rake_task'
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
@@ -0,0 +1,84 @@
1
+ require "ruby-asterisk/version"
2
+ require "ruby-asterisk/request"
3
+ require "ruby-asterisk/response"
4
+
5
+ require 'net/telnet'
6
+
7
+ module RubyAsterisk
8
+ class AMI
9
+ attr_accessor :host, :port, :connected
10
+
11
+ def initialize(host,port)
12
+ self.host = host.to_s
13
+ self.port = port.to_i
14
+ self.connected = false
15
+ @session = nil
16
+ end
17
+
18
+ def connect
19
+ begin
20
+ @session = Net::Telnet::new("Host" => self.host,"Port" => self.port)
21
+ self.connected = true
22
+ rescue Exception => ex
23
+ false
24
+ end
25
+ end
26
+
27
+ def disconnect
28
+ begin
29
+ @session.close if self.connected
30
+ @session = nil
31
+ self.connected = false
32
+ true
33
+ rescue Exception => ex
34
+ puts ex
35
+ false
36
+ end
37
+ end
38
+
39
+ def login(username,password)
40
+ self.connect unless self.connected
41
+ request = Request.new("Login",{"Username" => username, "Secret" => password})
42
+ request.commands.each do |command|
43
+ @session.write(command)
44
+ end
45
+ @session.waitfor("String" => "ActionID: "+request.action_id, "Timeout" => 3) do |data|
46
+ request.response_data << data
47
+ end
48
+ Response.new("Login",request.response_data)
49
+ end
50
+
51
+ def core_show_channels
52
+ request = Request.new("CoreShowChannels")
53
+ request.commands.each do |command|
54
+ @session.write(command)
55
+ end
56
+ @session.waitfor("String" => "ActionID: "+request.action_id, "Timeout" => 3) do |data|
57
+ request.response_data << data
58
+ end
59
+ Response.new("CoreShowChannels",request.response_data)
60
+ end
61
+
62
+ def parked_calls
63
+ request = Request.new("ParkedCalls")
64
+ request.commands.each do |command|
65
+ @session.write(command)
66
+ end
67
+ @session.waitfor("String" => "ActionID: "+request.action_id, "Timeout" => 3) do |data|
68
+ request.response_data << data
69
+ end
70
+ Response.new("ParkedCalls",request.response_data)
71
+ end
72
+
73
+ def originate(caller,context,callee,priority)
74
+ request = Request.new("Originate",{"Channel" => caller, "Context" => context, "Exten" => callee, "Priority" => priority, "Callerid" => caller, "Timeout" => "30000" })
75
+ request.commands.each do |command|
76
+ @session.write(command)
77
+ end
78
+ @session.waitfor("String" => "ActionID: "+request.action_id, "Timeout" => 30) do |data|
79
+ request.response_data << data
80
+ end
81
+ Response.new("Originate",request.response_data)
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,28 @@
1
+ module RubyAsterisk
2
+ class Request
3
+ attr_accessor :action, :action_id, :parameters, :response_data
4
+
5
+ def initialize(action,parameters={})
6
+ self.action = action
7
+ self.action_id = self.generate_action_id
8
+ self.parameters = parameters
9
+ self.response_data = ""
10
+ end
11
+
12
+ 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"
16
+ end
17
+ _commands[_commands.length-1]<<"\r\n"
18
+ _commands
19
+ end
20
+
21
+ protected
22
+
23
+ def generate_action_id
24
+ Random.rand(999).to_s
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,79 @@
1
+ module RubyAsterisk
2
+ class Response
3
+ attr_accessor :type, :success, :action_id, :message, :data
4
+
5
+ def initialize(type,response)
6
+ self.type = type
7
+ self.success = self._parse_successfull(response)
8
+ self.action_id = self._parse_action_id(response)
9
+ self.message = self._parse_message(response)
10
+ self.data = self._parse_data(response)
11
+ end
12
+
13
+ protected
14
+
15
+ def _parse_successfull(response)
16
+ response.include?("Response: Success")
17
+ end
18
+
19
+ def _parse_action_id(response)
20
+ _action_id = self._parse(response,"ActionID:")
21
+ end
22
+
23
+ def _parse_message(response)
24
+ _message = self._parse(response,"Message:")
25
+ end
26
+
27
+ def _parse(response,field)
28
+ _value = nil
29
+ response.each_line do |line|
30
+ if line.start_with?(field)
31
+ _value = line[line.rindex(":")+1..line.size].strip
32
+ end
33
+ end
34
+ _value
35
+ end
36
+
37
+ def _parse_data(response)
38
+ case self.type
39
+ when "CoreShowChannels"
40
+ self._parse_data_core_show_channels(response)
41
+ when "ParkedCalls"
42
+ self._parse_data_parked_calls(response)
43
+ when "Originate"
44
+ self._parse_originate_calls(response)
45
+ end
46
+ end
47
+
48
+ def _parse_originate_calls(response)
49
+ self._parse_objects(response,:dial,"Event: Dial")
50
+ end
51
+
52
+ def _parse_data_parked_calls(response)
53
+ self._parse_objects(response,:calls,"Event: ParkedCall")
54
+ end
55
+
56
+ def _parse_data_core_show_channels(response)
57
+ self._parse_objects(response,:channels,"Event: CoreShowChannel")
58
+ end
59
+
60
+ def _parse_objects(response,symbol_name,search_for)
61
+ _data = { symbol_name => [] }
62
+ parsing = false
63
+ object = nil
64
+ response.each_line do |line|
65
+ if line.start_with?(search_for)
66
+ _data[symbol_name] << object unless object.nil?
67
+ object = {}
68
+ parsing = true
69
+ elsif line.strip.empty?
70
+ parsing = false
71
+ elsif parsing
72
+ object[line.split(':')[0].strip]=line.split(':')[1].strip unless line.split(':')[1].nil?
73
+ end
74
+ end
75
+ _data[symbol_name] << object unless object.nil?
76
+ _data
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,3 @@
1
+ module Rami
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "ruby-asterisk/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "ruby-asterisk"
7
+ s.version = Rami::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Emiliano Della Casa"]
10
+ s.email = ["e.dellacasa@engim.eu"]
11
+ s.homepage = "http://github.com/emilianodellacasa/ruby-asterisk"
12
+ s.summary = %q{Asterisk Manager Interface in Ruby}
13
+ s.description = %q{Add support to your ruby or rails projects to Asterisk Manager Interface (AMI)}
14
+
15
+ s.rubyforge_project = "ruby-asterisk"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_development_dependency "rake"
23
+ s.add_development_dependency 'rspec'
24
+ end
@@ -0,0 +1,88 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ describe RubyAsterisk::Response do
4
+
5
+ def core_show_channels_response
6
+ "Event: CoreShowChannel
7
+ ActionID: 839
8
+ Channel: SIP/195.62.226.4-00000025
9
+ UniqueID: 1335448133.61
10
+ Context: incoming
11
+ Extension: s
12
+ Priority: 1
13
+ ChannelState: 6
14
+ ChannelStateDesc: Up
15
+ Application: Parked Call
16
+ ApplicationData:
17
+ CallerIDnum: 3335313510
18
+ CallerIDname:
19
+ ConnectedLineNum:
20
+ ConnectedLineName:
21
+ Duration: 00:00:05
22
+ AccountCode:
23
+ BridgedChannel:
24
+ BridgedUniqueID:"
25
+ end
26
+
27
+ def parked_calls_response
28
+ "Event: ParkedCall
29
+ Parkinglot: default
30
+ Exten: 701
31
+ Channel: SIP/195.62.226.2-00000026
32
+ From: SIP/195.62.226.2-00000026
33
+ Timeout: 3
34
+ CallerIDNum: 3335313510
35
+ CallerIDName:
36
+ ConnectedLineNum:
37
+ ConnectedLineName:
38
+ ActionID: 899"
39
+ end
40
+
41
+ def originate_response
42
+ "Event: Dial
43
+ Privilege: call,all
44
+ SubEvent: End
45
+ Channel: SIP/9100-0000002b
46
+ UniqueID: 1335457364.68
47
+ DialStatus: CHANUNAVAIL"
48
+ end
49
+
50
+ describe ".new" do
51
+
52
+ describe "receiving a Core Show Channels request" do
53
+ it "should parse correctly data coming from Asterisk about channels" do
54
+ @response = RubyAsterisk::Response.new("CoreShowChannels",core_show_channels_response)
55
+ @response.data[:channels].should_not be_empty
56
+ end
57
+
58
+ it "should correctly fill the fields" do
59
+ @response = RubyAsterisk::Response.new("CoreShowChannels",core_show_channels_response)
60
+ @response.data[:channels][0]["CallerIDnum"].should eq("3335313510")
61
+ end
62
+ end
63
+
64
+ describe "receiving a Parked Calls request" do
65
+ it "should parse correctly data coming from Asterisk about calls" do
66
+ @response = RubyAsterisk::Response.new("ParkedCalls",parked_calls_response)
67
+ @response.data[:calls].should_not be_empty
68
+ end
69
+
70
+ it "should correctly fill the fields" do
71
+ @response = RubyAsterisk::Response.new("ParkedCalls",parked_calls_response)
72
+ @response.data[:calls][0]["Exten"].should eq("701")
73
+ end
74
+ end
75
+
76
+ describe "resceiving a Originate request" do
77
+ it "should parse correctly data coming from Asterisk about the call" do
78
+ @response = RubyAsterisk::Response.new("Originate",originate_response)
79
+ @response.data[:dial].should_not be_empty
80
+ end
81
+
82
+ it "should correctly fill the fields" do
83
+ @response = RubyAsterisk::Response.new("Originate",originate_response)
84
+ @response.data[:dial][0]["UniqueID"].should eq("1335457364.68")
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,143 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ describe RubyAsterisk do
4
+
5
+ def core_show_channels_response
6
+ "Event: CoreShowChannel
7
+ ActionID: 839
8
+ Channel: SIP/195.62.226.4-00000025
9
+ UniqueID: 1335448133.61
10
+ Context: incoming
11
+ Extension: s
12
+ Priority: 1
13
+ ChannelState: 6
14
+ ChannelStateDesc: Up
15
+ Application: Parked Call
16
+ ApplicationData:
17
+ CallerIDnum: 3335313510
18
+ CallerIDname:
19
+ ConnectedLineNum:
20
+ ConnectedLineName:
21
+ Duration: 00:00:05
22
+ AccountCode:
23
+ BridgedChannel:
24
+ BridgedUniqueID:"
25
+ end
26
+
27
+ def mock_request(stubs={})
28
+ (@mock_request ||= mock_model(RubyAsterisk::Request).as_null_object).tap do |request|
29
+ request.stub(stubs) unless stubs.empty?
30
+ end
31
+ end
32
+
33
+ before :each do
34
+ @session = RubyAsterisk::AMI.new("127.0.0.1",5038)
35
+ end
36
+
37
+ after :each do
38
+ @session.disconnect
39
+ end
40
+
41
+ describe ".new" do
42
+ it "initialize session with host" do
43
+ @session.host.should eq("127.0.0.1")
44
+ end
45
+
46
+ it "initialize session with host" do
47
+ @session.port.should eq(5038)
48
+ end
49
+
50
+ it "should start the session as disconnected" do
51
+ @session.connected.should_not be_true
52
+ end
53
+ end
54
+
55
+ describe ".connect" do
56
+ it "should return true if everything is ok" do
57
+ @session.connect.should be_true
58
+ end
59
+
60
+ it "should return false if everything if something went wrong" do
61
+ @session.port = 666
62
+ @session.connect.should_not be_true
63
+ @session.port = 5038
64
+ end
65
+
66
+ it "should change state to session as connected" do
67
+ @session.connect
68
+ @session.connected.should be_true
69
+ end
70
+ end
71
+
72
+ describe ".disconnect" do
73
+ it "should return true if everything is ok" do
74
+ @session.disconnect.should be_true
75
+ end
76
+
77
+ it "should change state to session as disconnected" do
78
+ @session.disconnect
79
+ @session.connected.should_not be_true
80
+ end
81
+ end
82
+
83
+ describe ".login" do
84
+ it "should return a response object" do
85
+ @session.login("mark","mysecret").should be_kind_of(RubyAsterisk::Response)
86
+ end
87
+
88
+ it "should return a response with type Login" do
89
+ @session.login("mark","mysecret").type.should eq("Login")
90
+ end
91
+
92
+ describe "if everything is ok" do
93
+ it "should return a successfull response" do
94
+ @session.login("mark","mysecret").success.should be_true
95
+ end
96
+
97
+ it "should fill the ActionID" do
98
+ @session.login("mark","mysecret").action_id.should_not be_nil
99
+ end
100
+
101
+ it "should fill the Message" do
102
+ @session.login("mark","mysecret").message.should_not be_nil
103
+ end
104
+ end
105
+
106
+ describe "if credentials are wrong" do
107
+ it "should not return a successfull response" do
108
+ @session.login("mark","wrong").success.should be_false
109
+ end
110
+ end
111
+ end
112
+
113
+ describe ".core_show_channels" do
114
+ it "should return a response object" do
115
+ @session.login("mark","mysecret")
116
+ @session.core_show_channels.should be_kind_of(RubyAsterisk::Response)
117
+ end
118
+
119
+ it "should contain additional data about channels" do
120
+ @session.login("mark","mysecret")
121
+ @session.core_show_channels.data[:channels].should_not be_nil
122
+ end
123
+ end
124
+
125
+ describe ".parked_calls" do
126
+ it "should return a response object" do
127
+ @session.login("mark","mysecret")
128
+ @session.parked_calls.should be_kind_of(RubyAsterisk::Response)
129
+ end
130
+
131
+ it "should contain additional data about parked calls" do
132
+ @session.login("mark","mysecret")
133
+ @session.parked_calls.data[:calls].should_not be_nil
134
+ end
135
+ end
136
+
137
+ describe ".originate" do
138
+ it "should return a response object" do
139
+ @session.login("mark","mysecret")
140
+ @session.originate("SIP/9100","OUTGOING","123456","1").should be_kind_of(RubyAsterisk::Response)
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,4 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ require 'ruby-asterisk'
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-asterisk
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Emiliano Della Casa
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2012-04-27 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rake
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ type: :development
25
+ version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: rspec
28
+ prerelease: false
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: "0"
35
+ type: :development
36
+ version_requirements: *id002
37
+ description: Add support to your ruby or rails projects to Asterisk Manager Interface (AMI)
38
+ email:
39
+ - e.dellacasa@engim.eu
40
+ executables: []
41
+
42
+ extensions: []
43
+
44
+ extra_rdoc_files: []
45
+
46
+ files:
47
+ - .gitignore
48
+ - .rspec
49
+ - CHANGELOG
50
+ - Gemfile
51
+ - README.md
52
+ - Rakefile
53
+ - lib/ruby-asterisk.rb
54
+ - lib/ruby-asterisk/request.rb
55
+ - lib/ruby-asterisk/response.rb
56
+ - lib/ruby-asterisk/version.rb
57
+ - ruby-asterisk.gemspec
58
+ - spec/ruby-asterisk/response_spec.rb
59
+ - spec/ruby-asterisk/ruby_asterisk_spec.rb
60
+ - spec/spec_helper.rb
61
+ homepage: http://github.com/emilianodellacasa/ruby-asterisk
62
+ licenses: []
63
+
64
+ post_install_message:
65
+ rdoc_options: []
66
+
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: "0"
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: "0"
81
+ requirements: []
82
+
83
+ rubyforge_project: ruby-asterisk
84
+ rubygems_version: 1.8.17
85
+ signing_key:
86
+ specification_version: 3
87
+ summary: Asterisk Manager Interface in Ruby
88
+ test_files: []
89
+