asterisk-ami 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3eb66f2410e0015663bbbb1a8c4b0b3634bea943
4
+ data.tar.gz: 2d9c4156b2c46e7bb96207d0442495492b4c116d
5
+ SHA512:
6
+ metadata.gz: 65aa25c87e102d4db1340e899c712b545f0320fb8b66e774e3b7fc6d3487cd9dca2910fc2d8c3c31b6072bdb0b6c86dfeb841e3660bac19ed060255c8d5bcfd1
7
+ data.tar.gz: b8b51aa1f3ef5d63e4f3dec088b9b995f68b26603916388379e2b88f79986ec1dea5db1b8a0ecc2298324e3d8af0f9e4dead438bd790ed18eeae622f18baa4fe
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ asterisk-ami
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.1.0
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in asterisk-ami.gemspec
4
+ gemspec
5
+
6
+ gem 'em-websocket', :git => "https://github.com/igrigorik/em-websocket.git"
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Stewart McKee
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Asterisk::Ami
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'asterisk-ami'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install asterisk-ami
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'asterisk/ami/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "asterisk-ami"
8
+ spec.version = Asterisk::Ami::VERSION
9
+ spec.authors = ["Stewart McKee"]
10
+ spec.email = ["stewart@theizone.co.uk"]
11
+ spec.description = %q{Asterisk AMI integration gem}
12
+ spec.summary = %q{Asterisk AMI integration gem}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib", "lib/asterisk"]
20
+
21
+ spec.add_dependency "titleize"
22
+ spec.add_dependency "json"
23
+ spec.add_dependency "em-websocket", "> 0.5.0"
24
+ spec.add_development_dependency "bundler", "~> 1.3"
25
+ spec.add_development_dependency "rake"
26
+ end
data/bin/asterisk-ami ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path(File.dirname(__FILE__)) + '/../lib/asterisk/server/socket.rb'
data/lib/ami.rb ADDED
@@ -0,0 +1,99 @@
1
+
2
+
3
+ Dir[File.dirname(__FILE__) + '/*.rb'].each {|file| require file }
4
+ Dir[File.dirname(__FILE__) + '/asterisk/*.rb'].each {|file| require file }
5
+ require "titleize"
6
+
7
+ module Asterisk
8
+ class AMI
9
+
10
+ def initialize(username, password, host="localhost", port=5038)
11
+ @connection = Asterisk::Connection.new(username, password, host, port)
12
+ end
13
+
14
+ def connect
15
+ begin
16
+ @connection.connect
17
+ self.connected = true
18
+ rescue Exception => ex
19
+ false
20
+ end
21
+ end
22
+
23
+ def disconnect
24
+ begin
25
+ @connection.disconnect if self.connected
26
+ self.connected = false
27
+ true
28
+ rescue Exception => ex
29
+ puts ex
30
+ false
31
+ end
32
+ end
33
+
34
+ def command(command)
35
+ Asterisk::Action.new("Command", {"Command" => command}).send(@connection)
36
+ end
37
+
38
+ def core_show_channels
39
+ Asterisk::Action.new("CoreShowChannels").send(@connection)
40
+ end
41
+
42
+ def meet_me_list
43
+ Asterisk::Action.new("MeetMeList").send(@connection)
44
+ end
45
+
46
+ def parked_calls
47
+ Asterisk::Action.new("ParkedCalls").send(@connection)
48
+ end
49
+
50
+ def extension_state(exten,context)
51
+ Asterisk::Action.new("ExtensionState", {"Exten" => exten, "Context" => context}).send(@connection)
52
+ end
53
+
54
+ def originate(caller,context,callee,priority,variable=nil)
55
+ Asterisk::Action.new("Originate", {"Channel" => caller, "Context" => context, "Exten" => callee, "Priority" => priority, "Callerid" => caller, "Timeout" => "30000", "Variable" => variable }).send(@connection)
56
+ end
57
+
58
+ def channels
59
+ Asterisk::Action.new("Command", { "Command" => "show channels" }).send(@connection)
60
+ end
61
+
62
+ def redirect(caller,context,callee,priority,variable=nil)
63
+ Asterisk::Action.new("Redirect", {"Channel" => caller, "Context" => context, "Exten" => callee, "Priority" => priority, "Callerid" => caller, "Timeout" => "30000", "Variable" => variable}).send(@connection)
64
+ end
65
+
66
+ def queues
67
+ Asterisk::Action.new("Queues").send(@connection)
68
+ end
69
+
70
+ def queue_add(queue, exten, penalty=2, paused=false, member_name)
71
+ Asterisk::Action.new("QueueAdd", {"Queue" => queue, "Interface" => exten, "Penalty" => penalty, "Paused" => paused, "MemberName" => member_name}).send(@connection)
72
+ end
73
+
74
+ def queue_pause(queue, exten)
75
+ Asterisk::Action.new("QueuePause", {"Interface" => exten, "Paused" => paused}).send(@connection)
76
+ end
77
+
78
+ def queue_remove(queue, exten)
79
+ Asterisk::Action.new("QueueRemove", {"Queue" => queue, "Interface" => exten}).send(@connection)
80
+ end
81
+
82
+ def queue_status
83
+ Asterisk::Action.new("QueueStatus").send(@connection)
84
+ end
85
+
86
+ def queue_summary(queue)
87
+ Asterisk::Action.new("QueueSummary", {"Queue" => queue}).send(@connection)
88
+ end
89
+
90
+ def mailbox_status(exten, context="default")
91
+ Asterisk::Action.new("MailboxStatus", {"Mailbox" => "#{exten}@#{context}"}).send(@connection)
92
+ end
93
+
94
+ def mailbox_count(exten, context="default")
95
+ Asterisk::Action.new("MailboxCount", {"Mailbox" => "#{exten}@#{context}"}).send(@connection)
96
+ end
97
+
98
+ end
99
+ end
@@ -0,0 +1,37 @@
1
+ require File.expand_path(File.dirname(__FILE__)) + "/message_helper"
2
+
3
+ module Asterisk
4
+ class Action
5
+ include Asterisk::MessageHelper
6
+
7
+ def initialize(command, options={})
8
+ @command = command
9
+ @options = options
10
+ @options[:action_id] = Random.rand(9999) unless @options.has_key?(:action_id)
11
+ end
12
+
13
+ def self.parse(str)
14
+ hash = self.parse_lines(str)
15
+ Asterisk::Action.new(hash.delete(:action), hash)
16
+ end
17
+
18
+ # send the ami action
19
+ def send(connection)
20
+ #puts self.to_ami
21
+ connection.write(self.to_ami + "\r\n\r\n")
22
+ #connection.waitfor("Match" => /\r\n\r\n/) do |received_data|
23
+ #puts received_data
24
+ #end
25
+ end
26
+
27
+ # convert the action to ami string to send down wire
28
+ def to_ami
29
+ ami_lines(@command, @options)
30
+ end
31
+
32
+ def to_hash
33
+ {:action => @command}.merge(@options)
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,5 @@
1
+ module Asterisk
2
+ module Ami
3
+ VERSION = "0.0.2"
4
+ end
5
+ end
@@ -0,0 +1,83 @@
1
+ module Asterisk
2
+ class Connection
3
+
4
+ require "net/telnet"
5
+ require "json"
6
+
7
+ def initialize(username, password, server="localhost", port=5038)
8
+ @server = server
9
+ @port = port
10
+ @username = username
11
+ @password = password
12
+
13
+ @events = []
14
+ end
15
+
16
+ def connect(force = false)
17
+ if force || @connection.nil?
18
+ puts "Connecting to #{@server}:#{@port} with user #{@username}"
19
+ @connection = Net::Telnet::new("Host" => @server, "Port" => @port, "Timeout" => false, "Telnetmode" => false)
20
+ puts "connected"
21
+ @connection.waitfor(/Asterisk Call Manager\/\d+\.\d+/) {|response| puts response }
22
+ puts "Logging in.."
23
+ Asterisk::Action.new(:login, :username => @username, :secret => @password).send(@connection)
24
+ puts "Done."
25
+ end
26
+ end
27
+
28
+ def write(str)
29
+ @connection.write(str + "\r\n\r\n")
30
+ end
31
+
32
+ def events(&block)
33
+ force_connection = false
34
+ if block_given?
35
+ while true
36
+ connect(true)
37
+ t = Thread.new do |thread|
38
+ while true
39
+ puts "Waiting for data.."
40
+ @connection.waitfor("Match" => /\r\n\r\n/) do |received_data|
41
+ if received_data
42
+ received_data.split("\r\n\r\n").each do |message|
43
+ begin
44
+ if message.include?("Event")
45
+ yield Asterisk::Event.parse(message) if block_given?
46
+ end
47
+ rescue Errno::EPIPE => e
48
+ puts "Error in connection to Asterisk: #{e.message}"
49
+ puts e.backtrace.join("\n")
50
+ sleep(4)
51
+ t.kill
52
+ rescue => e
53
+ puts "Exception in Loop: #{e.message}"
54
+ end
55
+ end
56
+ else
57
+ @connection.close
58
+ puts "Reconnecting..."
59
+ force_connection = true
60
+ connect(true)
61
+ break
62
+ end
63
+ end
64
+ puts "outside waitfor loop"
65
+ end
66
+ puts "Exited AMI loop!"
67
+ end
68
+ t.join
69
+ puts "after thread join"
70
+ end
71
+ end
72
+ end
73
+
74
+ def disconnect
75
+ @connection.close()
76
+ end
77
+
78
+ def connection
79
+ @connection
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,9 @@
1
+ module Asterisk
2
+
3
+ class Event
4
+ include Asterisk::MessageHelper
5
+ def self.parse(str)
6
+ parse_lines(str)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,50 @@
1
+ module Asterisk
2
+ module MessageHelper
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ module ClassMethods
8
+ def parse_lines(str)
9
+ hash = {}
10
+ lines = str.gsub("\r", "").split("\n").select{|line| line.include?(":")}
11
+ lines = lines.map{|line| [line.split(":")[0], line.split(":")[1..-1].join(":")]}
12
+ lines = lines.map{|element| element.map{|e| e.strip}}
13
+ lines = lines.flatten
14
+ if lines.count > 0
15
+ hash = Hash[*lines]
16
+ hash.keys.each do |key|
17
+ hash[(underscore(key).to_sym) || key] = hash.delete(key)
18
+ end
19
+ end
20
+ hash
21
+ end
22
+
23
+ def underscore(str)
24
+ str.gsub(/::/, '/').
25
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
26
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
27
+ tr("-", "_").
28
+ downcase
29
+ end
30
+ end
31
+
32
+ def ami_lines(command, options)
33
+ messages = []
34
+ messages << add_line("Action", camelize(command, :upcase_ids => true))
35
+ options.map{|k,v| messages << add_line(camelize(k, :upcase_ids => true),v) }
36
+ messages.join("\r\n")
37
+ end
38
+
39
+ def add_line(key, value)
40
+ "#{key}: #{value}"
41
+ end
42
+
43
+ def camelize(term, options={})
44
+ options[:upcase_ids] = false unless options.has_key?(:upcase_ids)
45
+
46
+ string = term.to_s
47
+ string.split(/[\s|_]/).map{|s| s[0].upcase + s[1..-1].downcase}.join("")
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,9 @@
1
+ module Asterisk
2
+ class Response
3
+
4
+ include Asterisk::MessageHelper
5
+ def self.parse(str)
6
+ parse_lines(str)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,96 @@
1
+ # Copyright: Hiroshi Ichikawa <http://gimite.net/en/>
2
+ # Lincense: New BSD Lincense
3
+
4
+ $LOAD_PATH << File.expand_path(File.dirname(__FILE__)) + "/../lib"
5
+ require File.expand_path(File.dirname(__FILE__)) + "/../../ami"
6
+
7
+ require 'em-websocket'
8
+
9
+ Thread.abort_on_exception = true
10
+ # WebSocket.debug = true
11
+
12
+ if ARGV.size != 5
13
+ $stderr.puts("Usage: asterisk-ami ACCEPTED_DOMAIN PORT AMI_USERNAME AMI_PASSWORD AMI_HOSTNAME")
14
+ exit(1)
15
+ end
16
+
17
+ # server = WebSocketServer.new(
18
+ # :accepted_domains => [ARGV[0], "localhost"],
19
+ # :port => ARGV[1].to_i())
20
+
21
+ port = ARGV[1].to_i
22
+
23
+ ami_username = ARGV[2]
24
+ ami_password = ARGV[3]
25
+ ami_host = ARGV[4]
26
+
27
+ puts "Starting Server on port #{port}"
28
+ EM.run {
29
+ EM::WebSocket.run(:host => "0.0.0.0", :port => port) do |ws|
30
+ ws.onopen { |handshake|
31
+
32
+ puts "Websocket connection request received"
33
+
34
+ # Access properties on the EM::WebSocket::Handshake object, e.g.
35
+ # path, query_string, origin, headers
36
+
37
+ # Publish message to the client
38
+ ws.send "Connected."
39
+ }
40
+
41
+ ws.onclose { puts "Connection closed" }
42
+
43
+ ws.onmessage { |msg|
44
+ puts "Recieved message: #{msg}"
45
+
46
+ if msg.is_json?
47
+ puts "its json"
48
+ data = JSON.parse(msg)
49
+ puts data
50
+ if data["command"]
51
+ puts "its a command"
52
+ case data["command"]
53
+ when "initiate-call"
54
+ puts "initiate call!"
55
+ ami_command = Asterisk::Action.new("Originate", :channel => "SIP/#{data["from"]}", :exten => data["to"], :priority => 1, :context => "default")
56
+ puts ami_command.to_ami
57
+ end
58
+ ami_command.send(@connection)
59
+ else
60
+ ws.send ("No action found to execute, you must supply a command")
61
+ end
62
+ else
63
+ ws.send "Pong: #{msg}"
64
+ end
65
+ }
66
+
67
+ @connection = Asterisk::Connection.new(ARGV[2], ARGV[3], ARGV[4])
68
+ t = Thread.new do
69
+ @connection.events do |data|
70
+ puts data.to_json
71
+ ws.send(data.to_json)
72
+ end
73
+ end
74
+
75
+ end
76
+ }
77
+
78
+ # puts("Server is running at port %d" % server.port)
79
+ # server.run() do |ws|
80
+ # puts("Connection accepted")
81
+ # puts("Path: #{ws.path}, Origin: #{ws.origin}")
82
+ # if ws.path == "/"
83
+ # puts "Received connection from browser"
84
+ # ws.handshake()
85
+ # ws.send("Connected.")
86
+ # connection = Asterisk::Connection.new(ARGV[2], ARGV[3], ARGV[4])
87
+ # connection.events do |data|
88
+ # puts data.to_json
89
+ # ws.send(data.to_json)
90
+ # end
91
+ # puts "out of loop, finished thread."
92
+ # else
93
+ # ws.handshake("404 Not Found")
94
+ # end
95
+ # puts("Connection closed")
96
+ # end
metadata ADDED
@@ -0,0 +1,133 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: asterisk-ami
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Stewart McKee
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: titleize
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: json
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: em-websocket
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.5.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.5.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.3'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Asterisk AMI integration gem
84
+ email:
85
+ - stewart@theizone.co.uk
86
+ executables:
87
+ - asterisk-ami
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - ".gitignore"
92
+ - ".ruby-gemset"
93
+ - ".ruby-version"
94
+ - Gemfile
95
+ - LICENSE.txt
96
+ - README.md
97
+ - Rakefile
98
+ - asterisk-ami.gemspec
99
+ - bin/asterisk-ami
100
+ - lib/ami.rb
101
+ - lib/asterisk/action.rb
102
+ - lib/asterisk/ami/version.rb
103
+ - lib/asterisk/connection.rb
104
+ - lib/asterisk/event.rb
105
+ - lib/asterisk/message_helper.rb
106
+ - lib/asterisk/response.rb
107
+ - lib/asterisk/server/socket.rb
108
+ homepage: ''
109
+ licenses:
110
+ - MIT
111
+ metadata: {}
112
+ post_install_message:
113
+ rdoc_options: []
114
+ require_paths:
115
+ - lib
116
+ - lib/asterisk
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ requirements: []
128
+ rubyforge_project:
129
+ rubygems_version: 2.2.0.rc.1
130
+ signing_key:
131
+ specification_version: 4
132
+ summary: Asterisk AMI integration gem
133
+ test_files: []