adhearsion 0.8.3 → 0.8.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +11 -2
- data/EVENTS +1 -1
- data/Rakefile +4 -4
- data/adhearsion.gemspec +8 -4
- data/app_generators/ahn/USAGE +3 -3
- data/app_generators/ahn/ahn_generator.rb +11 -11
- data/app_generators/ahn/templates/components/ami_remote/ami_remote.rb +3 -3
- data/app_generators/ahn/templates/components/disabled/restful_rpc/example-client.rb +6 -6
- data/app_generators/ahn/templates/components/disabled/restful_rpc/restful_rpc.rb +16 -16
- data/app_generators/ahn/templates/components/disabled/restful_rpc/spec/restful_rpc_spec.rb +42 -42
- data/app_generators/ahn/templates/components/disabled/sandbox/sandbox.rb +11 -11
- data/app_generators/ahn/templates/components/disabled/stomp_gateway/README.markdown +1 -1
- data/app_generators/ahn/templates/components/disabled/stomp_gateway/stomp_gateway.rb +6 -6
- data/app_generators/ahn/templates/components/simon_game/simon_game.rb +4 -4
- data/app_generators/ahn/templates/config/startup.rb +31 -16
- data/bin/ahn +3 -3
- data/bin/ahnctl +8 -8
- data/bin/jahn +3 -3
- data/examples/asterisk_manager_interface/standalone.rb +2 -2
- data/lib/adhearsion.rb +4 -2
- data/lib/adhearsion/cli.rb +31 -31
- data/lib/adhearsion/component_manager.rb +39 -39
- data/lib/adhearsion/component_manager/component_tester.rb +14 -14
- data/lib/adhearsion/component_manager/spec_framework.rb +1 -1
- data/lib/adhearsion/events_support.rb +12 -12
- data/lib/adhearsion/foundation/blank_slate.rb +1 -1
- data/lib/adhearsion/foundation/custom_daemonizer.rb +2 -2
- data/lib/adhearsion/foundation/event_socket.rb +26 -26
- data/lib/adhearsion/foundation/future_resource.rb +6 -6
- data/lib/adhearsion/foundation/metaprogramming.rb +2 -2
- data/lib/adhearsion/foundation/numeric.rb +3 -3
- data/lib/adhearsion/foundation/relationship_properties.rb +7 -7
- data/lib/adhearsion/foundation/string.rb +8 -8
- data/lib/adhearsion/foundation/synchronized_hash.rb +8 -8
- data/lib/adhearsion/host_definitions.rb +16 -16
- data/lib/adhearsion/initializer.rb +74 -65
- data/lib/adhearsion/initializer/asterisk.rb +15 -9
- data/lib/adhearsion/initializer/configuration.rb +54 -39
- data/lib/adhearsion/initializer/database.rb +4 -4
- data/lib/adhearsion/initializer/drb.rb +6 -6
- data/lib/adhearsion/initializer/freeswitch.rb +1 -1
- data/lib/adhearsion/initializer/ldap.rb +51 -0
- data/lib/adhearsion/initializer/rails.rb +8 -8
- data/lib/adhearsion/logging.rb +16 -16
- data/lib/adhearsion/tasks/deprecations.rb +12 -12
- data/lib/adhearsion/tasks/generating.rb +2 -2
- data/lib/adhearsion/tasks/testing.rb +7 -7
- data/lib/adhearsion/version.rb +1 -1
- data/lib/adhearsion/voip/asterisk/agi_server.rb +44 -14
- data/lib/adhearsion/voip/asterisk/commands.rb +281 -237
- data/lib/adhearsion/voip/asterisk/config_generators/agents.conf.rb +8 -8
- data/lib/adhearsion/voip/asterisk/config_generators/config_generator.rb +14 -14
- data/lib/adhearsion/voip/asterisk/config_generators/queues.conf.rb +16 -16
- data/lib/adhearsion/voip/asterisk/config_generators/voicemail.conf.rb +39 -39
- data/lib/adhearsion/voip/asterisk/config_manager.rb +13 -13
- data/lib/adhearsion/voip/asterisk/manager_interface.rb +91 -87
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rb +739 -739
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rl.rb +60 -60
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_messages.rb +16 -16
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_protocol_lexer_machine.rl +1 -1
- data/lib/adhearsion/voip/asterisk/special_dial_plan_managers.rb +13 -13
- data/lib/adhearsion/voip/asterisk/super_manager.rb +3 -3
- data/lib/adhearsion/voip/call.rb +101 -64
- data/lib/adhearsion/voip/call_routing.rb +9 -9
- data/lib/adhearsion/voip/constants.rb +7 -7
- data/lib/adhearsion/voip/conveniences.rb +1 -1
- data/lib/adhearsion/voip/dial_plan.rb +42 -40
- data/lib/adhearsion/voip/dsl/dialing_dsl.rb +27 -27
- data/lib/adhearsion/voip/dsl/dialing_dsl/dialing_dsl_monkey_patches.rb +1 -1
- data/lib/adhearsion/voip/dsl/dialplan/control_passing_exception.rb +6 -6
- data/lib/adhearsion/voip/dsl/dialplan/dispatcher.rb +17 -17
- data/lib/adhearsion/voip/dsl/dialplan/parser.rb +7 -7
- data/lib/adhearsion/voip/dsl/dialplan/thread_mixin.rb +2 -2
- data/lib/adhearsion/voip/dsl/numerical_string.rb +3 -3
- data/lib/adhearsion/voip/freeswitch/basic_connection_manager.rb +7 -7
- data/lib/adhearsion/voip/freeswitch/event_handler.rb +1 -1
- data/lib/adhearsion/voip/freeswitch/freeswitch_dialplan_command_factory.rb +20 -20
- data/lib/adhearsion/voip/freeswitch/inbound_connection_manager.rb +5 -5
- data/lib/adhearsion/voip/freeswitch/oes_server.rb +33 -33
- data/lib/adhearsion/voip/menu_state_machine/calculated_match.rb +1 -1
- data/lib/adhearsion/voip/menu_state_machine/matchers.rb +2 -2
- data/lib/adhearsion/voip/menu_state_machine/menu_class.rb +9 -9
- data/lib/theatre.rb +18 -18
- data/lib/theatre/callback_definition_loader.rb +17 -17
- data/lib/theatre/guid.rb +6 -6
- data/lib/theatre/invocation.rb +19 -19
- data/lib/theatre/namespace_manager.rb +28 -28
- metadata +55 -14
@@ -1,24 +1,24 @@
|
|
1
1
|
module Adhearsion
|
2
2
|
module Components
|
3
|
-
|
3
|
+
|
4
4
|
mattr_accessor :component_manager
|
5
|
-
|
5
|
+
|
6
6
|
class ConfigurationError < Exception; end
|
7
|
-
|
7
|
+
|
8
8
|
class ComponentManager
|
9
|
-
|
9
|
+
|
10
10
|
class << self
|
11
|
-
|
11
|
+
|
12
12
|
def scopes_valid?(*scopes)
|
13
13
|
unrecognized_scopes = (scopes.flatten - SCOPE_NAMES).map(&:inspect)
|
14
14
|
raise ArgumentError, "Unrecognized scopes #{unrecognized_scopes.to_sentence}" if unrecognized_scopes.any?
|
15
15
|
true
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
SCOPE_NAMES = [:dialplan, :events, :generators, :rpc, :global]
|
21
|
-
|
21
|
+
|
22
22
|
attr_reader :scopes, :lazy_config_loader
|
23
23
|
def initialize(path_to_container_directory)
|
24
24
|
@path_to_container_directory = path_to_container_directory
|
@@ -28,14 +28,14 @@ module Adhearsion
|
|
28
28
|
end
|
29
29
|
@lazy_config_loader = LazyConfigLoader.new(self)
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
##
|
33
33
|
# Includes the anonymous Module created for the :global scope in Object, making its methods globally accessible.
|
34
34
|
#
|
35
35
|
def globalize_global_scope!
|
36
36
|
Object.send :include, @scopes[:global]
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
def load_components
|
40
40
|
components = Dir.glob(File.join(@path_to_container_directory + "/*")).select do |path|
|
41
41
|
File.directory?(path)
|
@@ -50,9 +50,9 @@ module Adhearsion
|
|
50
50
|
ahn_log.warn "Component directory does not contain a matching .rb file! Was expecting #{component_file.inspect}"
|
51
51
|
end
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
54
|
end
|
55
|
-
|
55
|
+
|
56
56
|
##
|
57
57
|
# Loads the configuration file for a given component name.
|
58
58
|
#
|
@@ -67,12 +67,12 @@ module Adhearsion
|
|
67
67
|
return {}
|
68
68
|
end
|
69
69
|
end
|
70
|
-
|
70
|
+
|
71
71
|
def extend_object_with(object, *scopes)
|
72
72
|
raise ArgumentError, "Must supply at least one scope!" if scopes.empty?
|
73
|
-
|
73
|
+
|
74
74
|
self.class.scopes_valid? scopes
|
75
|
-
|
75
|
+
|
76
76
|
scopes.each do |scope|
|
77
77
|
methods = @scopes[scope]
|
78
78
|
if object.kind_of?(Module)
|
@@ -83,7 +83,7 @@ module Adhearsion
|
|
83
83
|
end
|
84
84
|
object
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
def load_code(code)
|
88
88
|
load_container ComponentDefinitionContainer.load_code(code)
|
89
89
|
end
|
@@ -91,9 +91,9 @@ module Adhearsion
|
|
91
91
|
def load_file(filename)
|
92
92
|
load_container ComponentDefinitionContainer.load_file(filename)
|
93
93
|
end
|
94
|
-
|
94
|
+
|
95
95
|
protected
|
96
|
-
|
96
|
+
|
97
97
|
def load_container(container)
|
98
98
|
container.constants.each do |constant_name|
|
99
99
|
constant_value = container.const_get(constant_name)
|
@@ -101,9 +101,9 @@ module Adhearsion
|
|
101
101
|
end
|
102
102
|
metadata = container.metaclass.send(:instance_variable_get, :@metadata)
|
103
103
|
metadata[:initialization_block].call if metadata[:initialization_block]
|
104
|
-
|
104
|
+
|
105
105
|
self.class.scopes_valid? metadata[:scopes].keys
|
106
|
-
|
106
|
+
|
107
107
|
metadata[:scopes].each_pair do |scope, method_definition_blocks|
|
108
108
|
method_definition_blocks.each do |method_definition_block|
|
109
109
|
@scopes[scope].module_eval(&method_definition_block)
|
@@ -113,45 +113,45 @@ module Adhearsion
|
|
113
113
|
end
|
114
114
|
|
115
115
|
class ComponentDefinitionContainer < Module
|
116
|
-
|
116
|
+
|
117
117
|
class << self
|
118
118
|
def load_code(code)
|
119
119
|
returning(new) do |instance|
|
120
120
|
instance.module_eval code
|
121
121
|
end
|
122
122
|
end
|
123
|
-
|
123
|
+
|
124
124
|
def load_file(filename)
|
125
125
|
returning(new) do |instance|
|
126
126
|
instance.module_eval File.read(filename), filename
|
127
127
|
end
|
128
128
|
end
|
129
129
|
end
|
130
|
-
|
130
|
+
|
131
131
|
def initialize(&block)
|
132
132
|
# Hide our instance variables in the singleton class
|
133
133
|
metadata = {}
|
134
134
|
metaclass.send(:instance_variable_set, :@metadata, metadata)
|
135
|
-
|
135
|
+
|
136
136
|
metadata[:scopes] = ComponentManager::SCOPE_NAMES.inject({}) do |scopes, name|
|
137
137
|
scopes[name] = []
|
138
138
|
scopes
|
139
139
|
end
|
140
|
-
|
140
|
+
|
141
141
|
super
|
142
|
-
|
142
|
+
|
143
143
|
meta_def(:initialize) { raise "This object has already been instantiated. Are you sure you didn't mean initialization()?" }
|
144
144
|
end
|
145
|
-
|
145
|
+
|
146
146
|
def methods_for(*scopes, &block)
|
147
147
|
raise ArgumentError if scopes.empty?
|
148
|
-
|
148
|
+
|
149
149
|
ComponentManager.scopes_valid? scopes
|
150
|
-
|
150
|
+
|
151
151
|
metadata = metaclass.send(:instance_variable_get, :@metadata)
|
152
152
|
scopes.each { |scope| metadata[:scopes][scope] << block }
|
153
153
|
end
|
154
|
-
|
154
|
+
|
155
155
|
def initialization(&block)
|
156
156
|
# Raise an exception if the initialization block has already been set
|
157
157
|
metadata = metaclass.send(:instance_variable_get, :@metadata)
|
@@ -162,18 +162,18 @@ module Adhearsion
|
|
162
162
|
end
|
163
163
|
end
|
164
164
|
alias initialisation initialization
|
165
|
-
|
165
|
+
|
166
166
|
protected
|
167
|
-
|
167
|
+
|
168
168
|
class << self
|
169
169
|
def self.method_added(method_name)
|
170
170
|
@methods ||= []
|
171
171
|
@methods << method_name
|
172
172
|
end
|
173
173
|
end
|
174
|
-
|
174
|
+
|
175
175
|
end
|
176
|
-
|
176
|
+
|
177
177
|
class ComponentMethodDefinitionContainer < Module
|
178
178
|
class << self
|
179
179
|
def method_added(method_name)
|
@@ -181,27 +181,27 @@ module Adhearsion
|
|
181
181
|
@methods << method_name
|
182
182
|
end
|
183
183
|
end
|
184
|
-
|
184
|
+
|
185
185
|
attr_reader :scopes
|
186
186
|
def initialize(*scopes, &block)
|
187
187
|
@scopes = []
|
188
188
|
super(&block)
|
189
189
|
end
|
190
|
-
|
190
|
+
|
191
191
|
end
|
192
|
-
|
192
|
+
|
193
193
|
class LazyConfigLoader
|
194
194
|
def initialize(component_manager)
|
195
195
|
@component_manager = component_manager
|
196
196
|
end
|
197
|
-
|
197
|
+
|
198
198
|
def method_missing(component_name)
|
199
199
|
config = @component_manager.configuration_for_component_named(component_name.to_s)
|
200
200
|
(class << self; self; end).send(:define_method, component_name) { config }
|
201
201
|
config
|
202
202
|
end
|
203
203
|
end
|
204
|
-
|
204
|
+
|
205
205
|
end
|
206
206
|
end
|
207
207
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module ComponentTester
|
2
|
-
|
2
|
+
|
3
3
|
class << self
|
4
|
-
|
4
|
+
|
5
5
|
##
|
6
6
|
#
|
7
7
|
#
|
@@ -10,46 +10,46 @@ module ComponentTester
|
|
10
10
|
def new(component_name, component_directory)
|
11
11
|
component_directory = File.expand_path component_directory
|
12
12
|
main_file = component_directory + "/#{component_name}/#{component_name}.rb"
|
13
|
-
|
13
|
+
|
14
14
|
component_manager = Adhearsion::Components::ComponentManager.new(component_directory)
|
15
15
|
component_module = Adhearsion::Components::ComponentManager::ComponentDefinitionContainer.load_file main_file
|
16
|
-
|
16
|
+
|
17
17
|
Module.new do
|
18
|
-
|
18
|
+
|
19
19
|
extend ComponentTester
|
20
|
-
|
20
|
+
|
21
21
|
(class << self; self; end).send(:define_method, :component_manager) { component_manager }
|
22
22
|
(class << self; self; end).send(:define_method, :component_name) { component_name }
|
23
23
|
(class << self; self; end).send(:define_method, :component_module) { component_module }
|
24
24
|
(class << self; self; end).send(:define_method, :component_directory) { component_directory }
|
25
|
-
|
26
|
-
|
25
|
+
|
26
|
+
|
27
27
|
define_method(:component_manager) { component_manager }
|
28
28
|
define_method(:component_name) { component_name }
|
29
29
|
define_method(:component_module) { component_module }
|
30
30
|
define_method(:component_directory) { component_directory }
|
31
|
-
|
31
|
+
|
32
32
|
def self.const_missing(name)
|
33
33
|
component_module.const_get name
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
def helper_method(name)
|
41
41
|
Object.new.extend(component_module).method(name)
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
def config
|
45
45
|
component_manager.configuration_for_component_named component_name
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
def initialize!
|
49
49
|
metadata = component_module.metaclass.send(:instance_variable_get, :@metadata)
|
50
50
|
if metadata && metadata[:initialization_block].kind_of?(Proc)
|
51
51
|
metadata[:initialization_block].call
|
52
52
|
end
|
53
53
|
end
|
54
|
-
|
54
|
+
|
55
55
|
end
|
@@ -8,7 +8,7 @@ end
|
|
8
8
|
begin
|
9
9
|
require 'rr'
|
10
10
|
rescue LoadError
|
11
|
-
abort 'You do not have the "rr" gem installed! You must install it to continue.\n\nsudo gem install rr\n\n'
|
11
|
+
abort 'You do not have the "rr" gem installed! You must install it to continue.\n\nsudo gem install rr\n\n'
|
12
12
|
end
|
13
13
|
|
14
14
|
module ComponentConfigurationSpecHelper
|
@@ -22,7 +22,7 @@ require 'theatre'
|
|
22
22
|
|
23
23
|
module Adhearsion
|
24
24
|
module Events
|
25
|
-
|
25
|
+
|
26
26
|
DEFAULT_FRAMEWORK_EVENT_NAMESPACES = %w[
|
27
27
|
/after_initialized
|
28
28
|
/shutdown
|
@@ -32,21 +32,21 @@ module Adhearsion
|
|
32
32
|
/asterisk/hungup_call
|
33
33
|
/asterisk/failed_call
|
34
34
|
]
|
35
|
-
|
35
|
+
|
36
36
|
class << self
|
37
|
-
|
37
|
+
|
38
38
|
def framework_theatre
|
39
39
|
defined?(@@framework_theatre) ? @@framework_theatre : reinitialize_theatre!
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
def trigger(*args)
|
43
43
|
framework_theatre.trigger(*args)
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
def trigger_immediately(*args)
|
47
47
|
framework_theatre.trigger_immediately(*args)
|
48
48
|
end
|
49
|
-
|
49
|
+
|
50
50
|
def reinitialize_theatre!
|
51
51
|
@@framework_theatre.gracefully_stop! if defined? @@framework_theatre
|
52
52
|
rescue
|
@@ -59,26 +59,26 @@ module Adhearsion
|
|
59
59
|
end
|
60
60
|
return @@framework_theatre
|
61
61
|
end
|
62
|
-
|
62
|
+
|
63
63
|
def register_namespace_name(name)
|
64
64
|
framework_theatre.register_namespace_name name
|
65
65
|
end
|
66
|
-
|
66
|
+
|
67
67
|
def stop!
|
68
68
|
Events.trigger :shutdown
|
69
69
|
framework_theatre.graceful_stop!
|
70
70
|
framework_theatre.join
|
71
71
|
end
|
72
|
-
|
72
|
+
|
73
73
|
def register_callback(namespace, block_arg=nil, &method_block)
|
74
74
|
raise ArgumentError, "Cannot supply two blocks!" if block_arg && block_given?
|
75
75
|
block = method_block || block_arg
|
76
76
|
raise ArgumentError, "Must supply a callback!" unless block
|
77
|
-
|
77
|
+
|
78
78
|
framework_theatre.register_callback_at_namespace(namespace, block)
|
79
79
|
end
|
80
|
-
|
80
|
+
|
81
81
|
end
|
82
|
-
|
82
|
+
|
83
83
|
end
|
84
84
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
# meet Adhearsion's quality standards.
|
4
4
|
module Adhearsion
|
5
5
|
module CustomDaemonizer
|
6
|
-
|
6
|
+
|
7
7
|
# Try to fork if at all possible retrying every 5 sec if the
|
8
8
|
# maximum process limit for the system has been reached
|
9
9
|
def safefork
|
@@ -38,7 +38,7 @@ module Adhearsion
|
|
38
38
|
|
39
39
|
STDIN.reopen "/dev/null"
|
40
40
|
STDOUT.reopen '/dev/null', "a"
|
41
|
-
STDERR.reopen log_file
|
41
|
+
STDERR.reopen log_file, "a"
|
42
42
|
return oldmode ? sess_id : 0
|
43
43
|
end
|
44
44
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
##
|
2
2
|
# EventSocket is a small abstraction of TCPSocket which causes it to behave much like an EventMachine Connection object for
|
3
|
-
# the sake of better testability. The EventMachine Connection paradigm (as well as other networking libraries such as the
|
4
|
-
# Objective-C HTTP library) uses callbacks to signal different stages of a socket's lifecycle.
|
3
|
+
# the sake of better testability. The EventMachine Connection paradigm (as well as other networking libraries such as the
|
4
|
+
# Objective-C HTTP library) uses callbacks to signal different stages of a socket's lifecycle.
|
5
5
|
#
|
6
|
-
# A handler can be registered in one of two ways: through registrations on an object yielded by the constructor or
|
6
|
+
# A handler can be registered in one of two ways: through registrations on an object yielded by the constructor or
|
7
7
|
# pre-defined on the object given as a constructor parameter. Below is an example definition which uses the block way:
|
8
8
|
#
|
9
9
|
# EventSocket.new do |handler|
|
@@ -35,7 +35,7 @@
|
|
35
35
|
# end
|
36
36
|
# EventSocket.new(MyCallbackHandler.new)
|
37
37
|
#
|
38
|
-
# If you wish to ask the EventSocket what state it is in, you can call the Thread-safe EventSocket#state method. The
|
38
|
+
# If you wish to ask the EventSocket what state it is in, you can call the Thread-safe EventSocket#state method. The
|
39
39
|
# supported states are:
|
40
40
|
#
|
41
41
|
# - :new
|
@@ -43,10 +43,10 @@
|
|
43
43
|
# - :stopped
|
44
44
|
# - :connection_dropped
|
45
45
|
#
|
46
|
-
# Note: the EventSocket's state will be changed before these callbacks are executed. For example, if your "connected"
|
46
|
+
# Note: the EventSocket's state will be changed before these callbacks are executed. For example, if your "connected"
|
47
47
|
# callback queried its own EventSocket for its state, it will have already transitioned to the connected() state.
|
48
48
|
#
|
49
|
-
# Warning: If an exception occurs in your EventSocket callbacks, they will be "eaten" and never bubbled up the call stack.
|
49
|
+
# Warning: If an exception occurs in your EventSocket callbacks, they will be "eaten" and never bubbled up the call stack.
|
50
50
|
# You should always wrap your callbacks in a begin/rescue clause and handle exceptions explicitly.
|
51
51
|
#
|
52
52
|
require "thread"
|
@@ -55,7 +55,7 @@ require "socket"
|
|
55
55
|
class EventSocket
|
56
56
|
|
57
57
|
class << self
|
58
|
-
|
58
|
+
|
59
59
|
##
|
60
60
|
# Creates and returns a connected EventSocket instance.
|
61
61
|
#
|
@@ -67,23 +67,23 @@ class EventSocket
|
|
67
67
|
end
|
68
68
|
|
69
69
|
MAX_CHUNK_SIZE = 256 * 1024
|
70
|
-
|
70
|
+
|
71
71
|
def initialize(host, port, handler=nil, &block)
|
72
72
|
raise ArgumentError, "Cannot supply both a handler object and a block" if handler && block_given?
|
73
73
|
raise ArgumentError, "Must supply either a handler object or a block" if !handler && !block_given?
|
74
|
-
|
74
|
+
|
75
75
|
@state_lock = Mutex.new
|
76
76
|
@host = host
|
77
77
|
@port = port
|
78
|
-
|
78
|
+
|
79
79
|
@state = :new
|
80
80
|
@handler = handler || new_handler_from_block(&block)
|
81
81
|
end
|
82
|
-
|
82
|
+
|
83
83
|
def state
|
84
84
|
@state_lock.synchronize { @state }
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
def connect!
|
88
88
|
@state_lock.synchronize do
|
89
89
|
if @state.equal? :connected
|
@@ -100,7 +100,7 @@ class EventSocket
|
|
100
100
|
@state = :failed
|
101
101
|
raise error
|
102
102
|
end
|
103
|
-
|
103
|
+
|
104
104
|
##
|
105
105
|
# Thread-safe implementation of write.
|
106
106
|
#
|
@@ -121,7 +121,7 @@ class EventSocket
|
|
121
121
|
@state = :stopped
|
122
122
|
end
|
123
123
|
end
|
124
|
-
|
124
|
+
|
125
125
|
##
|
126
126
|
# Joins the Thread which reads data off the socket.
|
127
127
|
#
|
@@ -134,13 +134,13 @@ class EventSocket
|
|
134
134
|
end
|
135
135
|
end
|
136
136
|
end
|
137
|
-
|
137
|
+
|
138
138
|
def receive_data(data)
|
139
139
|
@handler.receive_data(data)
|
140
140
|
end
|
141
|
-
|
141
|
+
|
142
142
|
protected
|
143
|
-
|
143
|
+
|
144
144
|
def connection_dropped!
|
145
145
|
@state_lock.synchronize do
|
146
146
|
unless @state.equal? :connection_dropped
|
@@ -149,11 +149,11 @@ class EventSocket
|
|
149
149
|
end
|
150
150
|
end
|
151
151
|
end
|
152
|
-
|
152
|
+
|
153
153
|
def spawn_reader_thread
|
154
154
|
Thread.new(&method(:reader_loop))
|
155
155
|
end
|
156
|
-
|
156
|
+
|
157
157
|
def reader_loop
|
158
158
|
until state.equal? :stopped
|
159
159
|
data = @socket.readpartial(MAX_CHUNK_SIZE)
|
@@ -167,7 +167,7 @@ class EventSocket
|
|
167
167
|
handler = Object.new
|
168
168
|
handler.metaclass.send :attr_accessor, :set_callbacks
|
169
169
|
handler.set_callbacks = {:receive_data => false, :disconnected => false, :connected => false }
|
170
|
-
|
170
|
+
|
171
171
|
def handler.receive_data(&block)
|
172
172
|
self.metaclass.send(:remove_method, :receive_data)
|
173
173
|
self.metaclass.send(:define_method, :receive_data) { |data| block.call data }
|
@@ -183,21 +183,21 @@ class EventSocket
|
|
183
183
|
self.metaclass.send(:define_method, :disconnected) { block.call }
|
184
184
|
set_callbacks[:disconnected] = true
|
185
185
|
end
|
186
|
-
|
186
|
+
|
187
187
|
def handler.singleton_method_added(name)
|
188
188
|
set_callbacks[name.to_sym] = true
|
189
189
|
end
|
190
|
-
|
190
|
+
|
191
191
|
yield handler
|
192
|
-
|
192
|
+
|
193
193
|
handler.set_callbacks.each_pair do |callback_name,was_set|
|
194
194
|
handler.send(callback_name) {} unless was_set
|
195
195
|
end
|
196
|
-
|
196
|
+
|
197
197
|
handler
|
198
|
-
|
198
|
+
|
199
199
|
end
|
200
200
|
|
201
201
|
class ConnectionError < Exception; end
|
202
|
-
|
202
|
+
|
203
203
|
end
|