jicksta-adhearsion 0.7.999

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 (107) hide show
  1. data/CHANGELOG +6 -0
  2. data/EVENTS +11 -0
  3. data/LICENSE +456 -0
  4. data/README.txt +5 -0
  5. data/Rakefile +120 -0
  6. data/adhearsion.gemspec +146 -0
  7. data/app_generators/ahn/USAGE +5 -0
  8. data/app_generators/ahn/ahn_generator.rb +87 -0
  9. data/app_generators/ahn/templates/.ahnrc +34 -0
  10. data/app_generators/ahn/templates/README +8 -0
  11. data/app_generators/ahn/templates/Rakefile +23 -0
  12. data/app_generators/ahn/templates/components/ami_remote/ami_remote.rb +15 -0
  13. data/app_generators/ahn/templates/components/disabled/HOW_TO_ENABLE +7 -0
  14. data/app_generators/ahn/templates/components/disabled/stomp_gateway/README.markdown +47 -0
  15. data/app_generators/ahn/templates/components/disabled/stomp_gateway/config.yml +12 -0
  16. data/app_generators/ahn/templates/components/disabled/stomp_gateway/stomp_gateway.rb +34 -0
  17. data/app_generators/ahn/templates/components/restful_rpc/README.markdown +11 -0
  18. data/app_generators/ahn/templates/components/restful_rpc/config.yml +34 -0
  19. data/app_generators/ahn/templates/components/restful_rpc/example-client.rb +48 -0
  20. data/app_generators/ahn/templates/components/restful_rpc/restful_rpc.rb +87 -0
  21. data/app_generators/ahn/templates/components/simon_game/simon_game.rb +56 -0
  22. data/app_generators/ahn/templates/config/startup.rb +53 -0
  23. data/app_generators/ahn/templates/dialplan.rb +3 -0
  24. data/app_generators/ahn/templates/events.rb +32 -0
  25. data/bin/ahn +28 -0
  26. data/bin/ahnctl +68 -0
  27. data/bin/jahn +42 -0
  28. data/examples/asterisk_manager_interface/standalone.rb +51 -0
  29. data/lib/adhearsion/cli.rb +223 -0
  30. data/lib/adhearsion/component_manager/spec_framework.rb +24 -0
  31. data/lib/adhearsion/component_manager.rb +208 -0
  32. data/lib/adhearsion/events_support.rb +84 -0
  33. data/lib/adhearsion/foundation/all.rb +9 -0
  34. data/lib/adhearsion/foundation/blank_slate.rb +5 -0
  35. data/lib/adhearsion/foundation/custom_daemonizer.rb +45 -0
  36. data/lib/adhearsion/foundation/event_socket.rb +203 -0
  37. data/lib/adhearsion/foundation/future_resource.rb +36 -0
  38. data/lib/adhearsion/foundation/global.rb +1 -0
  39. data/lib/adhearsion/foundation/metaprogramming.rb +17 -0
  40. data/lib/adhearsion/foundation/numeric.rb +13 -0
  41. data/lib/adhearsion/foundation/pseudo_guid.rb +10 -0
  42. data/lib/adhearsion/foundation/relationship_properties.rb +42 -0
  43. data/lib/adhearsion/foundation/string.rb +26 -0
  44. data/lib/adhearsion/foundation/synchronized_hash.rb +96 -0
  45. data/lib/adhearsion/foundation/thread_safety.rb +7 -0
  46. data/lib/adhearsion/host_definitions.rb +67 -0
  47. data/lib/adhearsion/initializer/asterisk.rb +81 -0
  48. data/lib/adhearsion/initializer/configuration.rb +254 -0
  49. data/lib/adhearsion/initializer/database.rb +49 -0
  50. data/lib/adhearsion/initializer/drb.rb +31 -0
  51. data/lib/adhearsion/initializer/freeswitch.rb +22 -0
  52. data/lib/adhearsion/initializer/rails.rb +40 -0
  53. data/lib/adhearsion/initializer.rb +373 -0
  54. data/lib/adhearsion/logging.rb +92 -0
  55. data/lib/adhearsion/tasks/database.rb +5 -0
  56. data/lib/adhearsion/tasks/deprecations.rb +59 -0
  57. data/lib/adhearsion/tasks/generating.rb +20 -0
  58. data/lib/adhearsion/tasks/lint.rb +4 -0
  59. data/lib/adhearsion/tasks/testing.rb +37 -0
  60. data/lib/adhearsion/tasks.rb +16 -0
  61. data/lib/adhearsion/version.rb +9 -0
  62. data/lib/adhearsion/voip/asterisk/agi_server.rb +81 -0
  63. data/lib/adhearsion/voip/asterisk/commands.rb +1284 -0
  64. data/lib/adhearsion/voip/asterisk/config_generators/agents.conf.rb +140 -0
  65. data/lib/adhearsion/voip/asterisk/config_generators/config_generator.rb +101 -0
  66. data/lib/adhearsion/voip/asterisk/config_generators/queues.conf.rb +250 -0
  67. data/lib/adhearsion/voip/asterisk/config_generators/voicemail.conf.rb +240 -0
  68. data/lib/adhearsion/voip/asterisk/config_manager.rb +71 -0
  69. data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rb +1754 -0
  70. data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rl.rb +286 -0
  71. data/lib/adhearsion/voip/asterisk/manager_interface/ami_messages.rb +78 -0
  72. data/lib/adhearsion/voip/asterisk/manager_interface/ami_protocol_lexer_machine.rl +87 -0
  73. data/lib/adhearsion/voip/asterisk/manager_interface.rb +562 -0
  74. data/lib/adhearsion/voip/asterisk/special_dial_plan_managers.rb +80 -0
  75. data/lib/adhearsion/voip/asterisk/super_manager.rb +19 -0
  76. data/lib/adhearsion/voip/asterisk.rb +4 -0
  77. data/lib/adhearsion/voip/call.rb +440 -0
  78. data/lib/adhearsion/voip/call_routing.rb +64 -0
  79. data/lib/adhearsion/voip/commands.rb +9 -0
  80. data/lib/adhearsion/voip/constants.rb +39 -0
  81. data/lib/adhearsion/voip/conveniences.rb +18 -0
  82. data/lib/adhearsion/voip/dial_plan.rb +218 -0
  83. data/lib/adhearsion/voip/dsl/dialing_dsl/dialing_dsl_monkey_patches.rb +37 -0
  84. data/lib/adhearsion/voip/dsl/dialing_dsl.rb +151 -0
  85. data/lib/adhearsion/voip/dsl/dialplan/control_passing_exception.rb +27 -0
  86. data/lib/adhearsion/voip/dsl/dialplan/dispatcher.rb +124 -0
  87. data/lib/adhearsion/voip/dsl/dialplan/parser.rb +71 -0
  88. data/lib/adhearsion/voip/dsl/dialplan/thread_mixin.rb +16 -0
  89. data/lib/adhearsion/voip/dsl/numerical_string.rb +117 -0
  90. data/lib/adhearsion/voip/freeswitch/basic_connection_manager.rb +48 -0
  91. data/lib/adhearsion/voip/freeswitch/event_handler.rb +58 -0
  92. data/lib/adhearsion/voip/freeswitch/freeswitch_dialplan_command_factory.rb +129 -0
  93. data/lib/adhearsion/voip/freeswitch/inbound_connection_manager.rb +38 -0
  94. data/lib/adhearsion/voip/freeswitch/oes_server.rb +195 -0
  95. data/lib/adhearsion/voip/menu_state_machine/calculated_match.rb +80 -0
  96. data/lib/adhearsion/voip/menu_state_machine/matchers.rb +123 -0
  97. data/lib/adhearsion/voip/menu_state_machine/menu_builder.rb +58 -0
  98. data/lib/adhearsion/voip/menu_state_machine/menu_class.rb +149 -0
  99. data/lib/adhearsion.rb +37 -0
  100. data/lib/theatre/README.markdown +64 -0
  101. data/lib/theatre/callback_definition_loader.rb +84 -0
  102. data/lib/theatre/guid.rb +23 -0
  103. data/lib/theatre/invocation.rb +121 -0
  104. data/lib/theatre/namespace_manager.rb +153 -0
  105. data/lib/theatre/version.rb +2 -0
  106. data/lib/theatre.rb +151 -0
  107. metadata +177 -0
@@ -0,0 +1,218 @@
1
+ # Hardcoding require for now since for some reason it's not being loaded
2
+ require 'adhearsion/voip/dsl/dialplan/control_passing_exception'
3
+
4
+ module Adhearsion
5
+ class DialPlan
6
+ attr_accessor :loader, :entry_points
7
+ def initialize(loader = Loader)
8
+ @loader = loader
9
+ @entry_points = @loader.load_dialplans.contexts
10
+ end
11
+
12
+ ##
13
+ # Lookup and return an entry point by context name
14
+ #
15
+ def lookup(context_name)
16
+ entry_points[context_name]
17
+ end
18
+
19
+ ##
20
+ # Executable environment for a dial plan in the scope of a call. This class has all the dialplan methods mixed into it.
21
+ #
22
+ class ExecutionEnvironment
23
+
24
+ class << self
25
+ def create(*args)
26
+ returning(new(*args)) { |instance| instance.stage! }
27
+ end
28
+ end
29
+
30
+ attr_reader :call
31
+ def initialize(call, entry_point)
32
+ @call, @entry_point = call, entry_point
33
+ end
34
+
35
+ ##
36
+ # Adds the methods to this ExecutionEnvironment which make it useful. e.g. dialplan-related methods, call variables,
37
+ # and component methods.
38
+ #
39
+ def stage!
40
+ extend_with_voip_commands!
41
+ extend_with_call_variables!
42
+ extend_with_dialplan_component_methods!
43
+ end
44
+
45
+ def run
46
+ raise "Cannot run ExecutionEnvironment without an entry point!" unless entry_point
47
+ current_context = entry_point
48
+ answer if AHN_CONFIG.automatically_answer_incoming_calls
49
+ begin
50
+ instance_eval(&current_context)
51
+ rescue Adhearsion::VoIP::DSL::Dialplan::ControlPassingException => exception
52
+ current_context = exception.target
53
+ retry
54
+ end
55
+ end
56
+
57
+ protected
58
+
59
+ attr_reader :entry_point
60
+ def extend_with_voip_commands!
61
+ extend Adhearsion::VoIP::Conveniences
62
+ extend Adhearsion::VoIP::Commands.for(call.originating_voip_platform)
63
+ end
64
+
65
+ def extend_with_call_variables!
66
+ call.define_variable_accessors self
67
+ end
68
+
69
+ def extend_with_dialplan_component_methods!
70
+ Components.component_manager.extend_object_with(self, :dialplan) if Components.component_manager
71
+ end
72
+
73
+ end
74
+
75
+ class Manager
76
+
77
+ class NoContextError < Exception; end
78
+
79
+ class << self
80
+ def handle(call)
81
+ new.handle(call)
82
+ end
83
+ end
84
+
85
+ attr_accessor :dial_plan, :context
86
+ def initialize
87
+ @dial_plan = DialPlan.new
88
+ end
89
+
90
+ def handle(call)
91
+ if call.failed_call?
92
+ environment = ExecutionEnvironment.create(call, nil)
93
+ call.extract_failed_reason_from environment
94
+ raise FailedExtensionCallException.new(environment)
95
+ end
96
+
97
+ if call.hungup_call?
98
+ raise HungupExtensionCallException.new(ExecutionEnvironment.new(call, nil))
99
+ end
100
+
101
+ starting_entry_point = entry_point_for call
102
+ raise NoContextError, "No dialplan entry point for call context '#{call.context}' -- Ignoring call!" unless starting_entry_point
103
+ @context = ExecutionEnvironment.create(call, starting_entry_point)
104
+ inject_context_names_into_environment @context
105
+ @context.run
106
+ end
107
+
108
+ # Find the dialplan by the context name from the call or from the
109
+ # first path entry in the AGI URL
110
+ def entry_point_for(call)
111
+ if entry_point = dial_plan.lookup(call.context.to_sym)
112
+ entry_point
113
+ elsif call.respond_to?(:request) && m = call.request.path.match(%r{/([^/]+)})
114
+ dial_plan.lookup(m[1].to_sym)
115
+ end
116
+ end
117
+
118
+ protected
119
+
120
+ def inject_context_names_into_environment(environment)
121
+ return unless dial_plan.entry_points
122
+ dial_plan.entry_points.each do |name, context|
123
+ environment.meta_def(name) { context }
124
+ end
125
+ end
126
+
127
+ end
128
+
129
+ class Loader
130
+ class << self
131
+ attr_accessor :default_dial_plan_file_name
132
+
133
+ def load(dial_plan_as_string)
134
+ string_io = StringIO.new dial_plan_as_string
135
+ def string_io.path
136
+ "(eval)"
137
+ end
138
+ load_dialplans string_io
139
+ end
140
+
141
+ def load_dialplans(*files)
142
+ files = Adhearsion::AHN_CONFIG.files_from_setting("paths", "dialplan") if files.empty?
143
+ files = Array files
144
+ files.map! do |file|
145
+ case file
146
+ when File, StringIO
147
+ file
148
+ when String
149
+ File.new file
150
+ else
151
+ raise ArgumentError, "Unrecognized type of file #{file.inspect}"
152
+ end
153
+ end
154
+ returning new do |loader|
155
+ files.each do |file|
156
+ loader.load file
157
+ end
158
+ end
159
+ end
160
+
161
+ end
162
+
163
+ self.default_dial_plan_file_name ||= 'dialplan.rb'
164
+
165
+ def initialize
166
+ @context_collector = ContextNameCollector.new
167
+ end
168
+
169
+ def contexts
170
+ @context_collector.contexts
171
+ end
172
+
173
+ def load(dialplan_file)
174
+ dialplan_code = dialplan_file.read
175
+ @context_collector.instance_eval(dialplan_code, dialplan_file.path)
176
+ nil
177
+ end
178
+
179
+ class ContextNameCollector# < ::BlankSlate
180
+
181
+ class << self
182
+
183
+ def const_missing(name)
184
+ super
185
+ rescue ArgumentError
186
+ raise NameError, %(undefined constant "#{name}")
187
+ end
188
+
189
+ end
190
+
191
+ attr_reader :contexts
192
+ def initialize
193
+ @contexts = {}
194
+ end
195
+
196
+ def method_missing(name, *args, &block)
197
+ super if !block_given? || args.any?
198
+ contexts[name] = DialplanContextProc.new(name, &block)
199
+ end
200
+
201
+ end
202
+ end
203
+ class DialplanContextProc < Proc
204
+
205
+ attr_reader :name
206
+
207
+ def initialize(name, &block)
208
+ super(&block)
209
+ @name = name
210
+ end
211
+
212
+ def +@
213
+ raise Adhearsion::VoIP::DSL::Dialplan::ControlPassingException.new(self)
214
+ end
215
+
216
+ end
217
+ end
218
+ end
@@ -0,0 +1,37 @@
1
+ module Adhearsion
2
+ module VoIP
3
+ module DSL
4
+ class DialingDSL
5
+ module MonkeyPatches
6
+ module RegexpMonkeyPatch
7
+
8
+ def |(other)
9
+ case other
10
+ when RouteRule
11
+ other.unshift_pattern self
12
+ other
13
+ when Regexp
14
+ RouteRule.new :patterns => [self, other]
15
+ else
16
+ raise ArgumentError, "Unsupported pattern type #{other.inspect}"
17
+ end
18
+ end
19
+
20
+ def >>(other)
21
+ case other
22
+ when ProviderDefinition
23
+ RouteRule.new :patterns => self, :providers => other
24
+ when RouteRule
25
+ returning other do |route|
26
+ route.unshift_pattern self
27
+ end
28
+ else raise ArgumentError, "Unsupported route definition #{other.inspect}"
29
+ end
30
+ end
31
+
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,151 @@
1
+ # Adhearsion, open source collaboration framework
2
+ # Copyright (C) 2006,2007,2008 Jay Phillips
3
+ #
4
+ # This library is free software; you can redistribute it and/or
5
+ # modify it under the terms of the GNU Lesser General Public
6
+ # License as published by the Free Software Foundation; either
7
+ # version 2.1 of the License, or (at your option) any later version.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+ require 'adhearsion/foundation/metaprogramming'
19
+ require 'adhearsion/voip/conveniences'
20
+ require 'adhearsion/voip/constants'
21
+ require 'adhearsion/voip/dsl/dialing_dsl/dialing_dsl_monkey_patches'
22
+
23
+ module Adhearsion
24
+ module VoIP
25
+ module DSL
26
+ class DialingDSL
27
+
28
+ extend Conveniences
29
+ include Constants
30
+
31
+ Regexp.class_eval do
32
+ include Adhearsion::VoIP::DSL::DialingDSL::MonkeyPatches::RegexpMonkeyPatch
33
+ end
34
+
35
+ def self.inherited(klass)
36
+ klass.class_eval do
37
+ [:@@providers, :@@routes].each do |var|
38
+ class_variable_set(var, [])
39
+ cattr_reader var.to_s.gsub('@@', '')
40
+ end
41
+ end
42
+ end
43
+
44
+ def self.calculate_routes_for(destination)
45
+ destination = destination.to_s
46
+ routes.select { |defined_route| defined_route === destination }.map &:providers
47
+ end
48
+
49
+ class ProviderDefinition < OpenStruct
50
+
51
+ def initialize(name)
52
+ super()
53
+ self.name = name.to_s.to_sym
54
+ end
55
+
56
+ def >>(other)
57
+ RouteRule.new :providers => [self, other]
58
+ end
59
+
60
+ def format_number_for_platform(number, platform=:asterisk)
61
+ case platform
62
+ when :asterisk
63
+ [protocol || "SIP", name || "default", number].join '/'
64
+ else
65
+ raise "Unsupported platform #{platform}!"
66
+ end
67
+ end
68
+
69
+ def format_number_for_platform(number, platform=:asterisk)
70
+ case platform
71
+ when :asterisk
72
+ [protocol || "SIP", name || "default", number].join '/'
73
+ else
74
+ raise "Unsupported platform #{platform}!"
75
+ end
76
+ end
77
+
78
+ def defined_properties_without_name
79
+ returning @table.clone do |copy|
80
+ copy.delete :name
81
+ end
82
+ end
83
+
84
+ end
85
+
86
+ protected
87
+
88
+ def self.provider(name, &block)
89
+ raise ArgumentError, "no block given" unless block_given?
90
+
91
+ options = ProviderDefinition.new name
92
+ yield options
93
+
94
+ providers << options
95
+ meta_def(name) { options }
96
+ end
97
+
98
+ def self.route(route)
99
+ routes << route
100
+ end
101
+
102
+ class RouteRule
103
+
104
+ attr_reader :patterns, :providers
105
+
106
+ def initialize(hash={})
107
+ @patterns = Array hash[:patterns]
108
+ @providers = Array hash[:providers]
109
+ end
110
+
111
+ def merge!(other)
112
+ providers.concat other.providers
113
+ patterns.concat other.patterns
114
+ self
115
+ end
116
+
117
+ def >>(other)
118
+ case other
119
+ when RouteRule: merge! other
120
+ when ProviderDefinition: providers << other
121
+ else raise RouteException, "Unrecognized object in route definition: #{other.inspect}"
122
+ end
123
+ self
124
+ end
125
+
126
+ def |(other)
127
+ case other
128
+ when RouteRule: merge! other
129
+ when Regexp
130
+ patterns << other
131
+ self
132
+ else raise other.inspect
133
+ end
134
+ end
135
+
136
+ def ===(other)
137
+ patterns.each { |pattern| return true if pattern === other }
138
+ false
139
+ end
140
+
141
+ def unshift_pattern(pattern)
142
+ patterns.unshift pattern
143
+ end
144
+
145
+ class RouteException < Exception; end
146
+
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,27 @@
1
+ module Adhearsion
2
+ module VoIP
3
+ module DSL
4
+ module Dialplan
5
+ # A ControlPassingException is used internally to stop execution of one
6
+ # dialplan context and begin execution of another proc instead. It is
7
+ # most notably used by the ~@ unary operator that can be called on a
8
+ # context name within a dialplan to transfer control entirely to that
9
+ # particular context. The serve() method in the servlet_container actually
10
+ # rescues these exceptions specifically and then does +e.target to execute
11
+ # that code.
12
+ class ControlPassingException < Exception
13
+
14
+ attr_reader :target
15
+
16
+ def initialize(target)
17
+ super()
18
+ @target = target
19
+ end
20
+
21
+ end
22
+
23
+ class ContextNotFoundException < Exception; end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,124 @@
1
+ module Adhearsion
2
+ module VoIP
3
+ module DSL
4
+ module Dialplan
5
+
6
+ class ReturnValue < Exception
7
+ attr_reader :obj
8
+ def initialize(obj)
9
+ @obj = obj
10
+ super
11
+ end
12
+ end
13
+
14
+ class Hangup < Exception; end
15
+
16
+ # Instantiated and returned in every dialplan command
17
+ class EventCommand
18
+
19
+ attr_accessor :app, :args, :response_block, :returns, :on_keypress
20
+
21
+ def initialize(app, *args, &block)
22
+ @hash = args.pop if args.last.kind_of?(Hash)
23
+ @app, @args = app, args
24
+
25
+ if @hash
26
+ @returns = @hash[:returns] || :raw
27
+ @on_keypress = @hash[:on_keypress]
28
+ end
29
+
30
+ @response_block = block if block_given?
31
+ end
32
+
33
+ def on_keypress(&block)
34
+ block_given? ? @on_keypress = block : @on_keypress
35
+ end
36
+
37
+ def on_break(&block)
38
+ block_given? ? @on_break = block : @on_break
39
+ end
40
+
41
+ end
42
+
43
+ class NoOpEventCommand < EventCommand
44
+ attr_reader :timeout, :on_keypress
45
+ def initialize(timeout=nil, hash={})
46
+ @timeout = timeout
47
+ @on_keypress = hash[:on_keypress]
48
+ end
49
+ end
50
+
51
+ class ExitingEventCommand < EventCommand; end
52
+
53
+ # Serves as a EventCommand proxy for handling EventCommands. Useful
54
+ # if doing any pre-processing.
55
+ #
56
+ # For example, when sending commands over the event socket to FreeSwitch,
57
+ # every command must start with "api", but, when doing an originate, it
58
+ # must begin with an ampersand. These two pre-processors would be developed
59
+ # as separate CommandDispatchers.
60
+ class CommandDispatcher
61
+
62
+ attr_reader :factory, :context
63
+
64
+ def initialize(factory, context=nil)
65
+ @context = context
66
+ @factory = factory.new context
67
+ end
68
+
69
+ def dispatch!(event_command)
70
+ raise NotImplementedError, "Must subclass #{self.class} and override this!"
71
+ end
72
+
73
+ def method_missing(name, *args, &block)
74
+ *commands = *@factory.send(name, *args, &block)
75
+ commands.map do |command|
76
+ if command.kind_of? Proc
77
+ instance_eval(&command)
78
+ elsif command.kind_of? EventCommand
79
+ dispatched_command = dispatch! command
80
+ if command.response_block
81
+ while (new_cmd = command.response_block.call(dispatched_command)).kind_of? EventCommand
82
+ dispatched_command = dispatch! new_cmd
83
+ end
84
+ end
85
+ dispatched_command
86
+ else
87
+ command
88
+ end
89
+ end.last
90
+ rescue ReturnValue => r
91
+ return r.obj
92
+ end
93
+
94
+ def return!(obj)
95
+ raise DSL::Dialplan::ReturnValue.new(obj)
96
+ end
97
+
98
+ def break!(uuid=@context)
99
+ raise NotImplementedError, "Must subclass #{self.class} and override this!"
100
+ end
101
+
102
+ # Takes a Hash and meta_def()'s a method for each key that returns
103
+ # the key's value in the Hash.
104
+ def def_keys!(hash)
105
+ hash.each_pair do |k,v|
106
+ meta_def(k) { v } rescue nil
107
+ end
108
+ end
109
+
110
+ def clone
111
+ returning super do |nemesis|
112
+ instance_variables.each do |iv|
113
+ value = instance_variable_get(iv)
114
+ nemesis.instance_variable_set iv, value.clone if value
115
+ end
116
+ end
117
+ end
118
+
119
+ end
120
+
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,71 @@
1
+ require 'ostruct'
2
+
3
+ module Adhearsion
4
+ module VoIP
5
+ module DSL
6
+ module Dialplan
7
+ #TODO: This is obsolete, but we still need it for Freeswitch until we port that to the new 0.8.0 APIs
8
+ module DialplanParser
9
+
10
+ # Create a container and then clone that. when the container is created
11
+ # it should have all the contexts meta_def'd into it. for each call coming
12
+ # in, the cloned copy has the variables meta_def'd and set as instance
13
+ # variables
14
+
15
+ #TODO: separate into smaller pieces
16
+ def self.get_contexts
17
+ envelope = ContextsEnvelope.new
18
+
19
+ dialplans = AHN_CONFIG.files_from_setting "paths", "dialplan"
20
+ ahn_log.dialplan.warn "No dialplan files were found!" if dialplans.empty?
21
+
22
+ returning({}) do |contexts|
23
+ dialplans.each do |file|
24
+ raise "Dialplan file #{file} does not exist!" unless File.exists? file
25
+ envelope.instance_eval do
26
+ eval File.read(file)
27
+ end
28
+ current_contexts = envelope.parsed_contexts
29
+ current_contexts.each_pair do |name, block|
30
+ if contexts.has_key? name
31
+ warn %'Dialplan context "#{name}" exists in both #{contexts[name].file} and #{file}.' +
32
+ %' Using the "#{name}" context from #{contexts[name].file}.'
33
+ else
34
+ contexts[name] = returning OpenStruct.new do |metadata|
35
+ metadata.file = file
36
+ metadata.name = name
37
+ metadata.block = block
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ class ContextsEnvelope
47
+
48
+ keep = %w"__send__ __id__ define_method instance_eval meta_def meta_eval metaclass"
49
+ (instance_methods - keep).each do |m|
50
+ undef_method m
51
+ end
52
+
53
+ def initialize
54
+ @parsed_contexts = {}
55
+ end
56
+
57
+ attr_reader :parsed_contexts
58
+
59
+ def method_missing(name, *args, &block)
60
+ super unless block_given?
61
+ @parsed_contexts[name] = block
62
+ meta_def(name) { block }
63
+ end
64
+
65
+ end
66
+
67
+ end
68
+
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,16 @@
1
+ require 'ostruct'
2
+ module Adhearsion
3
+ module VoIP
4
+ module DSL
5
+ module Dialplan
6
+ module ThreadMixin
7
+
8
+ def call
9
+ @thread_call_struct ||= OpenStruct.new
10
+ end
11
+
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end