punchblock 0.5.1 → 0.6.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.
Files changed (64) hide show
  1. data/CHANGELOG.md +5 -0
  2. data/LICENSE.txt +3 -1
  3. data/bin/punchblock-console +19 -1
  4. data/lib/punchblock.rb +11 -4
  5. data/lib/punchblock/command/reject.rb +6 -2
  6. data/lib/punchblock/component.rb +1 -0
  7. data/lib/punchblock/component/asterisk.rb +10 -0
  8. data/lib/punchblock/component/asterisk/agi.rb +11 -0
  9. data/lib/punchblock/component/asterisk/agi/command.rb +157 -0
  10. data/lib/punchblock/component/asterisk/ami.rb +12 -0
  11. data/lib/punchblock/component/asterisk/ami/action.rb +144 -0
  12. data/lib/punchblock/component/input.rb +2 -2
  13. data/lib/punchblock/connection.rb +1 -0
  14. data/lib/punchblock/connection/asterisk.rb +31 -0
  15. data/lib/punchblock/core_ext/celluloid.rb +11 -0
  16. data/lib/punchblock/event.rb +1 -1
  17. data/lib/punchblock/event/asterisk.rb +9 -0
  18. data/lib/punchblock/event/asterisk/ami.rb +11 -0
  19. data/lib/punchblock/event/asterisk/ami/event.rb +66 -0
  20. data/lib/punchblock/event/complete.rb +20 -0
  21. data/lib/punchblock/event/dtmf.rb +19 -0
  22. data/lib/punchblock/event/end.rb +23 -0
  23. data/lib/punchblock/event/offer.rb +23 -0
  24. data/lib/punchblock/header.rb +4 -44
  25. data/lib/punchblock/key_value_pair_node.rb +50 -0
  26. data/lib/punchblock/rayo_node.rb +1 -1
  27. data/lib/punchblock/ref.rb +6 -0
  28. data/lib/punchblock/translator.rb +7 -0
  29. data/lib/punchblock/translator/asterisk.rb +74 -0
  30. data/lib/punchblock/translator/asterisk/ami_action.rb +86 -0
  31. data/lib/punchblock/translator/asterisk/call.rb +25 -0
  32. data/lib/punchblock/translator/asterisk/component.rb +11 -0
  33. data/lib/punchblock/version.rb +1 -1
  34. data/punchblock.gemspec +3 -1
  35. data/spec/punchblock/command/accept_spec.rb +8 -0
  36. data/spec/punchblock/command/answer_spec.rb +8 -0
  37. data/spec/punchblock/command/dial_spec.rb +22 -2
  38. data/spec/punchblock/command/hangup_spec.rb +8 -0
  39. data/spec/punchblock/command/join_spec.rb +21 -0
  40. data/spec/punchblock/command/mute_spec.rb +8 -0
  41. data/spec/punchblock/command/redirect_spec.rb +21 -0
  42. data/spec/punchblock/command/reject_spec.rb +19 -8
  43. data/spec/punchblock/command/unjoin_spec.rb +17 -0
  44. data/spec/punchblock/command/unmute_spec.rb +8 -0
  45. data/spec/punchblock/component/asterisk/agi/command_spec.rb +102 -0
  46. data/spec/punchblock/component/asterisk/ami/action_spec.rb +118 -0
  47. data/spec/punchblock/component/input_spec.rb +40 -0
  48. data/spec/punchblock/component/output_spec.rb +28 -0
  49. data/spec/punchblock/component/record_spec.rb +27 -0
  50. data/spec/punchblock/connection/asterisk_spec.rb +69 -0
  51. data/spec/punchblock/event/asterisk/ami/event_spec.rb +60 -0
  52. data/spec/punchblock/event/complete_spec.rb +8 -0
  53. data/spec/punchblock/event/dtmf_spec.rb +8 -0
  54. data/spec/punchblock/event/end_spec.rb +8 -0
  55. data/spec/punchblock/event/offer_spec.rb +15 -2
  56. data/spec/punchblock/ref_spec.rb +6 -0
  57. data/spec/punchblock/translator/asterisk/ami_action_spec.rb +149 -0
  58. data/spec/punchblock/translator/asterisk/call_spec.rb +18 -0
  59. data/spec/punchblock/translator/asterisk/component_spec.rb +11 -0
  60. data/spec/punchblock/translator/asterisk_spec.rb +150 -0
  61. data/spec/spec_helper.rb +42 -0
  62. metadata +92 -42
  63. data/lib/punchblock/event/info.rb +0 -15
  64. data/spec/punchblock/event/info_spec.rb +0 -30
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # develop
2
2
 
3
+ # v0.6.0
4
+ * API change: Punchblock consumers now need to instantiate both a Connection and a Client (see the punchblock-console gem for an example)
5
+ * Feature: Added a Connection for Asterisk, utilising RubyAMI to open an AMI connection to Asterisk, and allowing AMI actions to be executed. AMI events are handled by the client event handler.
6
+ * Deprecation: The punchblock-console and the associated DSL are now deprecated and the punchblock-console gem should be used instead
7
+
3
8
  # v0.5.1
4
9
  API change: Connections now raise a Punchblock::Connection::Connected instance as an event, rather than the class itself
5
10
 
data/LICENSE.txt CHANGED
@@ -1,4 +1,6 @@
1
- Copyright (c) 2011 Jason Goecke
1
+ Copyright (C) 2011 Ben Klang
2
+ Copyright (C) 2011 Ben Langfeld
3
+ Copyright (C) 2011 Jason Goecke
2
4
 
3
5
  Permission is hereby granted, free of charge, to any person obtaining
4
6
  a copy of this software and associated documentation files (the
@@ -7,12 +7,20 @@ require 'pry'
7
7
  require 'logger'
8
8
  require 'optparse'
9
9
 
10
+ puts <<-DEPRECATION
11
+ ********************
12
+ WARNING: This utility is deprecated and will be removed from a future version of Punchblock without further notice. You should use the punchblock-console gem instead.
13
+ ********************
14
+ DEPRECATION
15
+
10
16
  include Punchblock
11
17
 
12
18
  Thread.abort_on_exception = true
13
19
 
14
20
  options = { :username => 'usera@127.0.0.1', :password => '1', :wire_log_file => 'log/rayo-wire.log', :transport_log_file => 'log/rayo-transport.log', :auto_reconnect => false }
15
21
 
22
+ connection_class = Connection::XMPP
23
+
16
24
  option_parser = OptionParser.new do |opts|
17
25
  opts.banner = "Usage: punchblock-console [-u usera@127.0.0.1] [-p abc123]"
18
26
  opts.on("-u", "--username USERNAME", String, "Specify the XMPP JID to connect to") do |u|
@@ -30,6 +38,11 @@ option_parser = OptionParser.new do |opts|
30
38
  opts.on("--transport-log-file log/transportlog.log", String, "Specify the file to which the transport log should be written") do |tlf|
31
39
  options[:transport_log_file] = tlf
32
40
  end
41
+ opts.on("--asterisk", "Use Asterisk") do |tlf|
42
+ connection_class = Connection::Asterisk
43
+ options[:host] = '127.0.0.1'
44
+ options[:port] = 5038
45
+ end
33
46
  opts.on_tail("-h", "--help", "Show this message") do
34
47
  puts opts
35
48
  exit
@@ -53,8 +66,9 @@ options[:wire_logger].debug "Starting up..."
53
66
  options[:transport_logger] = Logger.new options.delete(:transport_log_file)
54
67
  options[:transport_logger].level = Logger::DEBUG
55
68
  options[:transport_logger].debug "Starting up..."
69
+ options[:logger] = options[:wire_logger]
56
70
 
57
- connection = Connection::XMPP.new options
71
+ connection = connection_class.new options
58
72
  client = Client.new :connection => connection
59
73
 
60
74
  [:INT, :TERM].each do |signal|
@@ -87,6 +101,10 @@ Thread.new do
87
101
  puts "Waiting for a call..."
88
102
  next
89
103
  end
104
+ unless event.call_id
105
+ puts "Ad-hoc event: #{event.inspect}"
106
+ next
107
+ end
90
108
  puts "#{event.class} event for call: #{event.call_id}"
91
109
  case event
92
110
  when Event::Offer
data/lib/punchblock.rb CHANGED
@@ -34,15 +34,17 @@ module Punchblock
34
34
  autoload :MediaNode
35
35
  autoload :ProtocolError
36
36
  autoload :RayoNode
37
+ autoload :Translator
37
38
 
38
39
  ##
39
40
  # This exception may be raised if a transport error is detected.
40
41
  TransportError = Class.new StandardError
41
42
 
42
- BASE_RAYO_NAMESPACE = 'urn:xmpp:rayo'
43
- BASE_TROPO_NAMESPACE = 'urn:xmpp:tropo'
44
- RAYO_VERSION = '1'
45
- RAYO_NAMESPACES = {:core => [BASE_RAYO_NAMESPACE, RAYO_VERSION].compact.join(':')}
43
+ BASE_RAYO_NAMESPACE = 'urn:xmpp:rayo'
44
+ BASE_TROPO_NAMESPACE = 'urn:xmpp:tropo'
45
+ BASE_ASTERISK_NAMESPACE = 'urn:xmpp:rayo:asterisk'
46
+ RAYO_VERSION = '1'
47
+ RAYO_NAMESPACES = {:core => [BASE_RAYO_NAMESPACE, RAYO_VERSION].compact.join(':')}
46
48
 
47
49
  [:ext, :record, :output, :input].each do |ns|
48
50
  RAYO_NAMESPACES[ns] = [BASE_RAYO_NAMESPACE, ns.to_s, RAYO_VERSION].compact.join(':')
@@ -53,6 +55,11 @@ module Punchblock
53
55
  RAYO_NAMESPACES[ns] = [BASE_TROPO_NAMESPACE, ns.to_s, RAYO_VERSION].compact.join(':')
54
56
  RAYO_NAMESPACES[:"#{ns}_complete"] = [BASE_TROPO_NAMESPACE, ns.to_s, 'complete', RAYO_VERSION].compact.join(':')
55
57
  end
58
+
59
+ [:agi, :ami].each do |ns|
60
+ RAYO_NAMESPACES[ns] = [BASE_ASTERISK_NAMESPACE, ns.to_s, RAYO_VERSION].compact.join(':')
61
+ RAYO_NAMESPACES[:"#{ns}_complete"] = [BASE_ASTERISK_NAMESPACE, ns.to_s, 'complete', RAYO_VERSION].compact.join(':')
62
+ end
56
63
  end
57
64
 
58
65
  require 'punchblock/event'
@@ -26,8 +26,12 @@ module Punchblock
26
26
  #
27
27
  def self.new(options = {})
28
28
  super().tap do |new_node|
29
- new_node.reason = options[:reason] || :decline
30
- new_node.headers = options[:headers]
29
+ case options
30
+ when Nokogiri::XML::Node
31
+ new_node.inherit options
32
+ when Hash
33
+ options.each_pair { |k,v| new_node.send :"#{k}=", v }
34
+ end
31
35
  end
32
36
  end
33
37
 
@@ -2,6 +2,7 @@ module Punchblock
2
2
  module Component
3
3
  extend ActiveSupport::Autoload
4
4
 
5
+ autoload :Asterisk
5
6
  autoload :Input
6
7
  autoload :Output
7
8
  autoload :Record
@@ -0,0 +1,10 @@
1
+ module Punchblock
2
+ module Component
3
+ module Asterisk
4
+ extend ActiveSupport::Autoload
5
+
6
+ autoload :AGI
7
+ autoload :AMI
8
+ end
9
+ end # Command
10
+ end # Punchblock
@@ -0,0 +1,11 @@
1
+ module Punchblock
2
+ module Component
3
+ module Asterisk
4
+ module AGI
5
+ extend ActiveSupport::Autoload
6
+
7
+ autoload :Command
8
+ end # AGI
9
+ end # Asterisk
10
+ end # Component
11
+ end # Punchblock
@@ -0,0 +1,157 @@
1
+ module Punchblock
2
+ module Component
3
+ module Asterisk
4
+ module AGI
5
+ class Command < ComponentNode
6
+ register :command, :agi
7
+
8
+ def self.new(options = {})
9
+ super().tap do |new_node|
10
+ options.each_pair { |k,v| new_node.send :"#{k}=", v }
11
+ end
12
+ end
13
+
14
+ def name
15
+ read_attr :name
16
+ end
17
+
18
+ def name=(other)
19
+ write_attr :name, other
20
+ end
21
+
22
+ ##
23
+ # @return [Array[String]] array of values of params
24
+ #
25
+ def params_array
26
+ params.map &:value
27
+ end
28
+
29
+ ##
30
+ # @return [Array[Param]] params
31
+ #
32
+ def params
33
+ find('//ns:param', :ns => self.class.registered_ns).map do |i|
34
+ Param.new i
35
+ end
36
+ end
37
+
38
+ ##
39
+ # @param [Hash, Array] params A hash of key-value param pairs, or an array of Param objects
40
+ #
41
+ def params=(params)
42
+ find('//ns:param', :ns => self.class.registered_ns).each &:remove
43
+ [params].flatten.each { |i| self << Param.new(i) } if params.is_a? Array
44
+ end
45
+
46
+ def inspect_attributes # :nodoc:
47
+ [:name, :params_array] + super
48
+ end
49
+
50
+ class Param < RayoNode
51
+ ##
52
+ # @param [String] name
53
+ # @param [String] value
54
+ #
55
+ def self.new(value)
56
+ super(:param).tap do |new_node|
57
+ case value
58
+ when Nokogiri::XML::Node
59
+ new_node.inherit value
60
+ else
61
+ new_node.value = value
62
+ end
63
+ end
64
+ end
65
+
66
+ # The Header's value
67
+ # @return [String]
68
+ def value
69
+ read_attr :value
70
+ end
71
+
72
+ # Set the Header's value
73
+ # @param [String] value the new value for the param
74
+ def value=(value)
75
+ write_attr :value, value
76
+ end
77
+
78
+ def inspect_attributes # :nodoc:
79
+ [:value] + super
80
+ end
81
+ end
82
+
83
+ class Complete
84
+ class Success < Event::Complete::Reason
85
+ register :success, :agi_complete
86
+
87
+ def self.new(options = {})
88
+ super().tap do |new_node|
89
+ case options
90
+ when Nokogiri::XML::Node
91
+ new_node.inherit options
92
+ else
93
+ options.each_pair { |k,v| new_node.send :"#{k}=", v }
94
+ end
95
+ end
96
+ end
97
+
98
+ def node_with_name(name)
99
+ n = if self.class.registered_ns
100
+ find_first "ns:#{name}", :ns => self.class.registered_ns
101
+ else
102
+ find_first name
103
+ end
104
+
105
+ unless n
106
+ self << (n = RayoNode.new(name, self.document))
107
+ n.namespace = self.class.registered_ns
108
+ end
109
+ n
110
+ end
111
+
112
+ def code_node
113
+ node_with_name 'code'
114
+ end
115
+
116
+ def result_node
117
+ node_with_name 'result'
118
+ end
119
+
120
+ def data_node
121
+ node_with_name 'data'
122
+ end
123
+
124
+ def code
125
+ code_node.text.to_i
126
+ end
127
+
128
+ def code=(other)
129
+ code_node.content = other
130
+ end
131
+
132
+ def result
133
+ result_node.text.to_i
134
+ end
135
+
136
+ def result=(other)
137
+ result_node.content = other
138
+ end
139
+
140
+ def data
141
+ data_node.text
142
+ end
143
+
144
+ def data=(other)
145
+ data_node.content = other
146
+ end
147
+
148
+ def inspect_attributes
149
+ [:code, :result, :data]
150
+ end
151
+ end
152
+ end # Complete
153
+ end # Command
154
+ end # AGI
155
+ end # Asterisk
156
+ end # Component
157
+ end # Punchblock
@@ -0,0 +1,12 @@
1
+ module Punchblock
2
+ module Component
3
+ module Asterisk
4
+ module AMI
5
+ extend ActiveSupport::Autoload
6
+
7
+ autoload :Action
8
+ end
9
+ end
10
+ end # Command
11
+ end # Punchblock
12
+
@@ -0,0 +1,144 @@
1
+ require 'punchblock/key_value_pair_node'
2
+
3
+ module Punchblock
4
+ module Component
5
+ module Asterisk
6
+ module AMI
7
+ class Action < ComponentNode
8
+ register :action, :ami
9
+
10
+ def self.new(options = {})
11
+ super().tap do |new_node|
12
+ options.each_pair { |k,v| new_node.send :"#{k}=", v }
13
+ end
14
+ end
15
+
16
+ def name
17
+ read_attr :name
18
+ end
19
+
20
+ def name=(other)
21
+ write_attr :name, other
22
+ end
23
+
24
+ ##
25
+ # @return [Hash] hash of key-value pairs of params
26
+ #
27
+ def params_hash
28
+ params.inject({}) do |hash, param|
29
+ hash[param.name] = param.value
30
+ hash
31
+ end
32
+ end
33
+
34
+ ##
35
+ # @return [Array[Param]] params
36
+ #
37
+ def params
38
+ find('//ns:param', :ns => self.class.registered_ns).map do |i|
39
+ Param.new i
40
+ end
41
+ end
42
+
43
+ ##
44
+ # @param [Hash, Array] params A hash of key-value param pairs, or an array of Param objects
45
+ #
46
+ def params=(params)
47
+ find('//ns:param', :ns => self.class.registered_ns).each &:remove
48
+ if params.is_a? Hash
49
+ params.each_pair { |k,v| self << Param.new(k, v) }
50
+ elsif params.is_a? Array
51
+ [params].flatten.each { |i| self << Param.new(i) }
52
+ end
53
+ end
54
+
55
+ def inspect_attributes # :nodoc:
56
+ [:name] + super
57
+ end
58
+
59
+ class Param < RayoNode
60
+ include KeyValuePairNode
61
+ end
62
+
63
+ class Complete
64
+ class Success < Event::Complete::Reason
65
+ register :success, :ami_complete
66
+
67
+ def self.new(options = {})
68
+ super().tap do |new_node|
69
+ case options
70
+ when Nokogiri::XML::Node
71
+ new_node.inherit options
72
+ else
73
+ options.each_pair { |k,v| new_node.send :"#{k}=", v }
74
+ end
75
+ end
76
+ end
77
+
78
+ def message_node
79
+ mn = if self.class.registered_ns
80
+ find_first 'ns:message', :ns => self.class.registered_ns
81
+ else
82
+ find_first 'message'
83
+ end
84
+
85
+ unless mn
86
+ self << (mn = RayoNode.new('message', self.document))
87
+ mn.namespace = self.class.registered_ns
88
+ end
89
+ mn
90
+ end
91
+
92
+ def message
93
+ message_node.text
94
+ end
95
+
96
+ def message=(other)
97
+ message_node.content = other
98
+ end
99
+
100
+ ##
101
+ # @return [Hash] hash of key-value pairs of attributes
102
+ #
103
+ def attributes_hash
104
+ attributes.inject({}) do |hash, attribute|
105
+ hash[attribute.name] = attribute.value
106
+ hash
107
+ end
108
+ end
109
+
110
+ ##
111
+ # @return [Array[Attribute]] attributes
112
+ #
113
+ def attributes
114
+ find('//ns:attribute', :ns => self.class.registered_ns).map do |i|
115
+ Attribute.new i
116
+ end
117
+ end
118
+
119
+ ##
120
+ # @param [Hash, Array] attributes A hash of key-value attribute pairs, or an array of Attribute objects
121
+ #
122
+ def attributes=(attributes)
123
+ find('//ns:attribute', :ns => self.class.registered_ns).each &:remove
124
+ if attributes.is_a? Hash
125
+ attributes.each_pair { |k,v| self << Attribute.new(k, v) }
126
+ elsif attributes.is_a? Array
127
+ [attributes].flatten.each { |i| self << Attribute.new(i) }
128
+ end
129
+ end
130
+
131
+ def inspect_attributes
132
+ [:message, :attributes_hash]
133
+ end
134
+ end
135
+
136
+ class Attribute < RayoNode
137
+ include KeyValuePairNode
138
+ end
139
+ end # Complete
140
+ end # Action
141
+ end # AMI
142
+ end # Asterisk
143
+ end # Component
144
+ end # Punchblock