sant0sk1-adhearsion 0.7.999
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +456 -0
- data/README.txt +5 -0
- data/Rakefile +75 -0
- data/adhearsion.gemspec +136 -0
- data/app_generators/ahn/USAGE +5 -0
- data/app_generators/ahn/ahn_generator.rb +77 -0
- data/app_generators/ahn/templates/.ahnrc +36 -0
- data/app_generators/ahn/templates/README +8 -0
- data/app_generators/ahn/templates/Rakefile +18 -0
- data/app_generators/ahn/templates/components/simon_game/configuration.rb +0 -0
- data/app_generators/ahn/templates/components/simon_game/lib/simon_game.rb +61 -0
- data/app_generators/ahn/templates/components/simon_game/test/test_helper.rb +14 -0
- data/app_generators/ahn/templates/components/simon_game/test/test_simon_game.rb +31 -0
- data/app_generators/ahn/templates/config/startup.rb +53 -0
- data/app_generators/ahn/templates/dialplan.rb +4 -0
- data/bin/ahn +28 -0
- data/bin/ahnctl +68 -0
- data/bin/jahn +32 -0
- data/lib/adhearsion.rb +32 -0
- data/lib/adhearsion/blank_slate.rb +5 -0
- data/lib/adhearsion/cli.rb +106 -0
- data/lib/adhearsion/component_manager.rb +277 -0
- data/lib/adhearsion/core_extensions/all.rb +9 -0
- data/lib/adhearsion/core_extensions/array.rb +0 -0
- data/lib/adhearsion/core_extensions/custom_daemonizer.rb +45 -0
- data/lib/adhearsion/core_extensions/global.rb +1 -0
- data/lib/adhearsion/core_extensions/hash.rb +0 -0
- data/lib/adhearsion/core_extensions/metaprogramming.rb +17 -0
- data/lib/adhearsion/core_extensions/numeric.rb +4 -0
- data/lib/adhearsion/core_extensions/proc.rb +0 -0
- data/lib/adhearsion/core_extensions/publishable.rb +73 -0
- data/lib/adhearsion/core_extensions/relationship_properties.rb +40 -0
- data/lib/adhearsion/core_extensions/string.rb +26 -0
- data/lib/adhearsion/core_extensions/thread.rb +13 -0
- data/lib/adhearsion/core_extensions/thread_safety.rb +7 -0
- data/lib/adhearsion/core_extensions/time.rb +0 -0
- data/lib/adhearsion/distributed/gateways/dbus_gateway.rb +0 -0
- data/lib/adhearsion/distributed/gateways/osa_gateway.rb +0 -0
- data/lib/adhearsion/distributed/gateways/rest_gateway.rb +9 -0
- data/lib/adhearsion/distributed/gateways/soap_gateway.rb +9 -0
- data/lib/adhearsion/distributed/gateways/xmlrpc_gateway.rb +9 -0
- data/lib/adhearsion/distributed/peer_finder.rb +0 -0
- data/lib/adhearsion/distributed/remote_cli.rb +0 -0
- data/lib/adhearsion/events_support.rb +26 -0
- data/lib/adhearsion/hooks.rb +57 -0
- data/lib/adhearsion/host_definitions.rb +63 -0
- data/lib/adhearsion/initializer.rb +246 -0
- data/lib/adhearsion/initializer/asterisk.rb +59 -0
- data/lib/adhearsion/initializer/configuration.rb +236 -0
- data/lib/adhearsion/initializer/database.rb +49 -0
- data/lib/adhearsion/initializer/drb.rb +25 -0
- data/lib/adhearsion/initializer/freeswitch.rb +22 -0
- data/lib/adhearsion/initializer/rails.rb +40 -0
- data/lib/adhearsion/logging.rb +92 -0
- data/lib/adhearsion/tasks.rb +15 -0
- data/lib/adhearsion/tasks/database.rb +5 -0
- data/lib/adhearsion/tasks/generating.rb +20 -0
- data/lib/adhearsion/tasks/lint.rb +4 -0
- data/lib/adhearsion/tasks/testing.rb +37 -0
- data/lib/adhearsion/version.rb +9 -0
- data/lib/adhearsion/voip/asterisk.rb +10 -0
- data/lib/adhearsion/voip/asterisk/agi_server.rb +81 -0
- data/lib/adhearsion/voip/asterisk/ami.rb +147 -0
- data/lib/adhearsion/voip/asterisk/ami/actions.rb +238 -0
- data/lib/adhearsion/voip/asterisk/ami/machine.rb +871 -0
- data/lib/adhearsion/voip/asterisk/ami/machine.rl +109 -0
- data/lib/adhearsion/voip/asterisk/ami/parser.rb +262 -0
- data/lib/adhearsion/voip/asterisk/commands.rb +1284 -0
- data/lib/adhearsion/voip/asterisk/config_generators/agents.conf.rb +140 -0
- data/lib/adhearsion/voip/asterisk/config_generators/config_generator.rb +101 -0
- data/lib/adhearsion/voip/asterisk/config_generators/queues.conf.rb +250 -0
- data/lib/adhearsion/voip/asterisk/config_generators/voicemail.conf.rb +240 -0
- data/lib/adhearsion/voip/asterisk/config_manager.rb +71 -0
- data/lib/adhearsion/voip/asterisk/special_dial_plan_managers.rb +80 -0
- data/lib/adhearsion/voip/call.rb +436 -0
- data/lib/adhearsion/voip/call_routing.rb +64 -0
- data/lib/adhearsion/voip/commands.rb +9 -0
- data/lib/adhearsion/voip/constants.rb +39 -0
- data/lib/adhearsion/voip/conveniences.rb +18 -0
- data/lib/adhearsion/voip/dial_plan.rb +207 -0
- data/lib/adhearsion/voip/dsl/dialing_dsl.rb +151 -0
- data/lib/adhearsion/voip/dsl/dialing_dsl/dialing_dsl_monkey_patches.rb +37 -0
- data/lib/adhearsion/voip/dsl/dialplan/control_passing_exception.rb +27 -0
- data/lib/adhearsion/voip/dsl/dialplan/dispatcher.rb +124 -0
- data/lib/adhearsion/voip/dsl/dialplan/parser.rb +71 -0
- data/lib/adhearsion/voip/dsl/dialplan/thread_mixin.rb +16 -0
- data/lib/adhearsion/voip/dsl/numerical_string.rb +117 -0
- data/lib/adhearsion/voip/freeswitch/basic_connection_manager.rb +48 -0
- data/lib/adhearsion/voip/freeswitch/event_handler.rb +58 -0
- data/lib/adhearsion/voip/freeswitch/freeswitch_dialplan_command_factory.rb +129 -0
- data/lib/adhearsion/voip/freeswitch/inbound_connection_manager.rb +38 -0
- data/lib/adhearsion/voip/freeswitch/oes_server.rb +195 -0
- data/lib/adhearsion/voip/menu_state_machine/calculated_match.rb +80 -0
- data/lib/adhearsion/voip/menu_state_machine/matchers.rb +123 -0
- data/lib/adhearsion/voip/menu_state_machine/menu_builder.rb +58 -0
- data/lib/adhearsion/voip/menu_state_machine/menu_class.rb +149 -0
- metadata +167 -0
File without changes
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# This is largely based on the Daemonize library by Travis Whitton and
|
2
|
+
# Judson Lester. http://grub.ath.cx/daemonize. I cleaned it up a bit to
|
3
|
+
# meet Adhearsion's quality standards.
|
4
|
+
module Adhearsion
|
5
|
+
module CustomDaemonizer
|
6
|
+
|
7
|
+
# Try to fork if at all possible retrying every 5 sec if the
|
8
|
+
# maximum process limit for the system has been reached
|
9
|
+
def safefork
|
10
|
+
begin
|
11
|
+
pid = fork
|
12
|
+
return pid if pid
|
13
|
+
rescue Errno::EWOULDBLOCK
|
14
|
+
sleep 5
|
15
|
+
retry
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# This method causes the current running process to become a daemon
|
20
|
+
def daemonize(log_file='/dev/null')
|
21
|
+
oldmode = 0
|
22
|
+
srand # Split rand streams between spawning and daemonized process
|
23
|
+
safefork and exit # Fork and exit from the parent
|
24
|
+
|
25
|
+
# Detach from the controlling terminal
|
26
|
+
unless sess_id = Process.setsid
|
27
|
+
raise 'Cannot detach from controlled terminal'
|
28
|
+
end
|
29
|
+
|
30
|
+
# Prevent the possibility of acquiring a controlling terminal
|
31
|
+
if oldmode.zero?
|
32
|
+
trap 'SIGHUP', 'IGNORE'
|
33
|
+
exit if pid = safefork
|
34
|
+
end
|
35
|
+
|
36
|
+
Dir.chdir "/" # Release old working directory
|
37
|
+
File.umask 0000 # Ensure sensible umask
|
38
|
+
|
39
|
+
STDIN.reopen "/dev/null"
|
40
|
+
STDOUT.reopen '/dev/null', "a"
|
41
|
+
STDERR.reopen log_file
|
42
|
+
return oldmode ? sess_id : 0
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Infinity = 1.0/0.0
|
File without changes
|
File without changes
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Adhearsion
|
2
|
+
class DrbDoor
|
3
|
+
|
4
|
+
include Singleton
|
5
|
+
|
6
|
+
def add(interface, name, meth)
|
7
|
+
@interfaces ||= {}
|
8
|
+
@interfaces[interface] ||= returning(Object.new) { |obj| obj.metaclass.send(:attr_accessor, :__methods) }
|
9
|
+
obj = @interfaces[interface]
|
10
|
+
obj.__methods ||= {}
|
11
|
+
obj.__methods[name] = meth
|
12
|
+
obj.instance_eval(<<-STR, __FILE__, __LINE__)
|
13
|
+
def #{name}(*args, &block)
|
14
|
+
begin
|
15
|
+
__methods["#{name}"].call(*args, &block)
|
16
|
+
rescue => exception
|
17
|
+
raise RuntimeError, exception.message, exception.backtrace
|
18
|
+
end
|
19
|
+
end
|
20
|
+
STR
|
21
|
+
end
|
22
|
+
|
23
|
+
def method_missing(name, *args, &block)
|
24
|
+
return Module.const_get(name) if name.to_s =~ /^[A-Z]/
|
25
|
+
super unless @interfaces && @interfaces.has_key?(name.to_s)
|
26
|
+
@interfaces[name.to_s]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module Publishable
|
31
|
+
def self.included(base)
|
32
|
+
base.send(:alias_method_chain, :initialize, :publishable)
|
33
|
+
base.extend(ClassMethods)
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize_with_publishable(*args, &block)
|
37
|
+
initialize_without_publishable(*args, &block)
|
38
|
+
self.class.published_instance_methods.each do |(sym, interface)|
|
39
|
+
DrbDoor.instance.add(interface, sym.to_s, self.method(sym))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module ClassMethods
|
44
|
+
attr_reader :interface
|
45
|
+
attr_reader :published_instance_methods
|
46
|
+
|
47
|
+
def publish(options={}, &block)
|
48
|
+
@interface = options.delete(:through).to_s || self.to_s
|
49
|
+
begin
|
50
|
+
@capture = true
|
51
|
+
yield
|
52
|
+
ensure
|
53
|
+
@capture = false
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def method_added(sym)
|
58
|
+
return if not @capture
|
59
|
+
if sym.to_s !~ /method_added/
|
60
|
+
@published_instance_methods ||= []
|
61
|
+
@published_instance_methods << [sym, @interface]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def singleton_method_added(sym)
|
66
|
+
return if not @capture
|
67
|
+
if sym.to_s !~ /method_added/
|
68
|
+
DrbDoor.instance.add(@interface, sym.to_s, method(sym.to_s))
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class Module
|
2
|
+
|
3
|
+
# In OOP, relationships between classes should be treated as *properties* of those classes. Often, in a complex OO
|
4
|
+
# architecture, you'll end up with many relationships that intermingle in monolithic ways, blunting the effectiveness of
|
5
|
+
# subclassing.
|
6
|
+
#
|
7
|
+
# For example, say you have an Automobile class which, in its constructor, instantiates a new Battery class and performs
|
8
|
+
# some operations on it such as calling an install() method. Let's also assume the Automobile class exposes a repair()
|
9
|
+
# method which uses a class-level method of Battery to diagnose your own instance of Battery. If the result of the
|
10
|
+
# diagnosis shows that the Battery is bad, the Automobile will instantiate a new Battery object and replace the old battery
|
11
|
+
# with the new one.
|
12
|
+
#
|
13
|
+
# Now, what if you wish to create a new Automobile derived from existing technology: a HybridAutomobile subclass. For this
|
14
|
+
# particular HybridAutomobile class, let's simply say the only difference between it and its parent is which kind of
|
15
|
+
# Battery it uses -- it requires its own special subclass of Battery. With Automobile's current implementation, its
|
16
|
+
# references to which Battery it instantiates and uses are embedded in the immutable method defintions. This
|
17
|
+
# HybridAutomobile needs to override which Battery its superclass' methods use and nothing else.
|
18
|
+
#
|
19
|
+
# For this reason, the Battery class which Automobile uses is semantically a property which others may want to override.
|
20
|
+
# In OOP theory, we define overridable properties in the form of methods and override those methods in the subclasses.
|
21
|
+
#
|
22
|
+
# This method exposes one method which creates human-readable semantics to defining these relationships as properties. It's
|
23
|
+
# used as follows:
|
24
|
+
#
|
25
|
+
# class Automobile
|
26
|
+
# relationship :battery => Battery
|
27
|
+
# relationship :chassis => Chassis
|
28
|
+
# # Other properties and instance methods here....
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# class HybridAutomobile < Automobile
|
32
|
+
# relationship :battery => HybridBattery
|
33
|
+
# end
|
34
|
+
def relationships(relationship_mapping)
|
35
|
+
relationship_mapping.each_pair do |class_name, class_object|
|
36
|
+
define_method(class_name) { class_object }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
def unindent
|
4
|
+
gsub(/^\s*/,'')
|
5
|
+
end
|
6
|
+
|
7
|
+
def unindent!
|
8
|
+
gsub!(/^\s*/,'')
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.random_char
|
12
|
+
case random_digit = rand(62)
|
13
|
+
when 0...10 : random_digit.to_s
|
14
|
+
when 10...36 : (random_digit + 55).chr
|
15
|
+
when 36...62 : (random_digit + 61).chr
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.random(length_of_string=8)
|
20
|
+
Array.new(length_of_string) { random_char }.join
|
21
|
+
end
|
22
|
+
|
23
|
+
def nameify() downcase.gsub(/[^\w]/, '') end
|
24
|
+
def nameify!() replace nameify end
|
25
|
+
|
26
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# gem 'theatre', '>= 0.8.0'
|
2
|
+
# require 'theatre'
|
3
|
+
|
4
|
+
module Adhearsion
|
5
|
+
module Events
|
6
|
+
|
7
|
+
class << self
|
8
|
+
|
9
|
+
def framework_theatre
|
10
|
+
defined?(@@framework_theatre) ? @@framework_theatre : reinitialize_theatre!
|
11
|
+
end
|
12
|
+
|
13
|
+
def reinitialize_theatre!
|
14
|
+
@@framework_theatre.gracefully_stop! if defined? @@framework_theatre
|
15
|
+
rescue
|
16
|
+
# Recover and reinitalize
|
17
|
+
ensure
|
18
|
+
# TODO: Extract number of threads to use from AHN_CONFIG
|
19
|
+
@@framework_theatre = Theatre::Theatre.new
|
20
|
+
return @@framework_theatre
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Adhearsion
|
2
|
+
|
3
|
+
|
4
|
+
module Hooks
|
5
|
+
|
6
|
+
class GenericHook
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@hooks = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_hook(&block)
|
13
|
+
@hooks.synchronize do
|
14
|
+
@hooks << block
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# TODO: This is hardly thread safe!
|
19
|
+
def trigger_hooks
|
20
|
+
@hooks.each &:call
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
class HookWithArguments < GenericHook
|
26
|
+
def trigger_hooks(*args)
|
27
|
+
@hooks.each { |hook| hook.call(*args) }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
ThreadsJoinedAfterInitialized = GenericHook.new
|
32
|
+
|
33
|
+
OnFailedCall = HookWithArguments.new
|
34
|
+
OnHungupCall = HookWithArguments.new
|
35
|
+
AfterInitialized = GenericHook.new
|
36
|
+
BeforeCall = GenericHook.new
|
37
|
+
AfterCall = GenericHook.new
|
38
|
+
TearDown = GenericHook.new
|
39
|
+
|
40
|
+
class << TearDown
|
41
|
+
def aliases
|
42
|
+
[:before_shutdown]
|
43
|
+
end
|
44
|
+
|
45
|
+
def catch_termination_signals
|
46
|
+
%w'INT TERM'.each do |sig|
|
47
|
+
trap sig do
|
48
|
+
ahn_log "Shutting down gracefully at #{Time.now}."
|
49
|
+
Adhearsion::Hooks::TearDown.trigger_hooks
|
50
|
+
exit
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Adhearsion
|
4
|
+
class HostDefinition
|
5
|
+
|
6
|
+
SUPPORTED_KEYS = [:host, :username, :password, :key, :name]
|
7
|
+
|
8
|
+
cattr_reader :definitions
|
9
|
+
@@definitions ||= []
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def import_from_data_structure(local_definitions)
|
13
|
+
case local_definitions
|
14
|
+
when Array
|
15
|
+
local_definitions.each do |definition|
|
16
|
+
raise HostDefinitionException, "Unrecognized definition: #{definition}" unless definition.is_a?(Hash)
|
17
|
+
end
|
18
|
+
local_definitions.map { |definition| new definition }
|
19
|
+
when Hash
|
20
|
+
local_definitions.map do |(name,definition)|
|
21
|
+
new definition.merge(:name => name)
|
22
|
+
end
|
23
|
+
else
|
24
|
+
raise HostDefinitionException, "Unrecognized definition #{local_definitions}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def import_from_yaml(yaml_string)
|
29
|
+
import_from_data_structure YAML.load(yaml_string)
|
30
|
+
end
|
31
|
+
|
32
|
+
def import_from_yaml_file(file)
|
33
|
+
import_from_yaml YAML.load_file(file)
|
34
|
+
end
|
35
|
+
|
36
|
+
def clear_definitions!
|
37
|
+
definitions.clear
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
attr_reader :name, :host, :username, :password, :key
|
42
|
+
def initialize(hash)
|
43
|
+
@host, @username, @password, @key, @name = hash.values_at(*SUPPORTED_KEYS)
|
44
|
+
@name ||= new_guid
|
45
|
+
|
46
|
+
unrecognized_keys = hash.keys - SUPPORTED_KEYS
|
47
|
+
raise HostDefinitionException, "Unrecognized key(s): #{unrecognized_keys.map(&:inspect).to_sentence}" if unrecognized_keys.any?
|
48
|
+
raise HostDefinitionException, "You must supply a password or key!" if username && !(password || key)
|
49
|
+
raise HostDefinitionException, "You must supply a username!" unless username
|
50
|
+
raise HostDefinitionException, 'You cannot supply both a password and key!' if password && key
|
51
|
+
raise HostDefinitionException, 'You must supply a host!' unless host
|
52
|
+
|
53
|
+
self.class.definitions << self
|
54
|
+
end
|
55
|
+
|
56
|
+
class HostDefinitionException < Exception
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
end
|