eventmachine-mkroman 1.3.0.dev.1

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 (182) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +179 -0
  3. data/GNU +281 -0
  4. data/LICENSE +60 -0
  5. data/README.md +110 -0
  6. data/docs/DocumentationGuidesIndex.md +27 -0
  7. data/docs/GettingStarted.md +520 -0
  8. data/docs/old/ChangeLog +211 -0
  9. data/docs/old/DEFERRABLES +246 -0
  10. data/docs/old/EPOLL +141 -0
  11. data/docs/old/INSTALL +13 -0
  12. data/docs/old/KEYBOARD +42 -0
  13. data/docs/old/LEGAL +25 -0
  14. data/docs/old/LIGHTWEIGHT_CONCURRENCY +130 -0
  15. data/docs/old/PURE_RUBY +75 -0
  16. data/docs/old/RELEASE_NOTES +94 -0
  17. data/docs/old/SMTP +4 -0
  18. data/docs/old/SPAWNED_PROCESSES +148 -0
  19. data/docs/old/TODO +8 -0
  20. data/examples/guides/getting_started/01_eventmachine_echo_server.rb +18 -0
  21. data/examples/guides/getting_started/02_eventmachine_echo_server_that_recognizes_exit_command.rb +22 -0
  22. data/examples/guides/getting_started/03_simple_chat_server.rb +149 -0
  23. data/examples/guides/getting_started/04_simple_chat_server_step_one.rb +27 -0
  24. data/examples/guides/getting_started/05_simple_chat_server_step_two.rb +43 -0
  25. data/examples/guides/getting_started/06_simple_chat_server_step_three.rb +98 -0
  26. data/examples/guides/getting_started/07_simple_chat_server_step_four.rb +121 -0
  27. data/examples/guides/getting_started/08_simple_chat_server_step_five.rb +141 -0
  28. data/examples/old/ex_channel.rb +43 -0
  29. data/examples/old/ex_queue.rb +2 -0
  30. data/examples/old/ex_tick_loop_array.rb +15 -0
  31. data/examples/old/ex_tick_loop_counter.rb +32 -0
  32. data/examples/old/helper.rb +2 -0
  33. data/ext/binder.cpp +124 -0
  34. data/ext/binder.h +52 -0
  35. data/ext/cmain.cpp +1046 -0
  36. data/ext/ed.cpp +2243 -0
  37. data/ext/ed.h +463 -0
  38. data/ext/em.cpp +2378 -0
  39. data/ext/em.h +266 -0
  40. data/ext/eventmachine.h +152 -0
  41. data/ext/extconf.rb +291 -0
  42. data/ext/fastfilereader/extconf.rb +120 -0
  43. data/ext/fastfilereader/mapper.cpp +214 -0
  44. data/ext/fastfilereader/mapper.h +59 -0
  45. data/ext/fastfilereader/rubymain.cpp +126 -0
  46. data/ext/kb.cpp +79 -0
  47. data/ext/page.cpp +107 -0
  48. data/ext/page.h +51 -0
  49. data/ext/pipe.cpp +354 -0
  50. data/ext/project.h +174 -0
  51. data/ext/rubymain.cpp +1643 -0
  52. data/ext/ssl.cpp +701 -0
  53. data/ext/ssl.h +103 -0
  54. data/ext/wait_for_single_fd.h +36 -0
  55. data/java/.classpath +8 -0
  56. data/java/.project +17 -0
  57. data/java/src/com/rubyeventmachine/EmReactor.java +625 -0
  58. data/java/src/com/rubyeventmachine/EmReactorException.java +40 -0
  59. data/java/src/com/rubyeventmachine/EmReactorInterface.java +70 -0
  60. data/java/src/com/rubyeventmachine/EventableChannel.java +72 -0
  61. data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +201 -0
  62. data/java/src/com/rubyeventmachine/EventableSocketChannel.java +415 -0
  63. data/java/src/com/rubyeventmachine/NullEmReactor.java +157 -0
  64. data/java/src/com/rubyeventmachine/NullEventableChannel.java +81 -0
  65. data/lib/em/buftok.rb +59 -0
  66. data/lib/em/callback.rb +58 -0
  67. data/lib/em/channel.rb +69 -0
  68. data/lib/em/completion.rb +307 -0
  69. data/lib/em/connection.rb +802 -0
  70. data/lib/em/deferrable/pool.rb +2 -0
  71. data/lib/em/deferrable.rb +210 -0
  72. data/lib/em/file_watch.rb +73 -0
  73. data/lib/em/future.rb +61 -0
  74. data/lib/em/io_streamer.rb +68 -0
  75. data/lib/em/iterator.rb +252 -0
  76. data/lib/em/messages.rb +66 -0
  77. data/lib/em/pool.rb +151 -0
  78. data/lib/em/process_watch.rb +45 -0
  79. data/lib/em/processes.rb +123 -0
  80. data/lib/em/protocols/header_and_content.rb +138 -0
  81. data/lib/em/protocols/httpclient.rb +303 -0
  82. data/lib/em/protocols/httpclient2.rb +602 -0
  83. data/lib/em/protocols/line_and_text.rb +125 -0
  84. data/lib/em/protocols/line_protocol.rb +33 -0
  85. data/lib/em/protocols/linetext2.rb +179 -0
  86. data/lib/em/protocols/memcache.rb +331 -0
  87. data/lib/em/protocols/object_protocol.rb +46 -0
  88. data/lib/em/protocols/postgres3.rb +246 -0
  89. data/lib/em/protocols/saslauth.rb +175 -0
  90. data/lib/em/protocols/smtpclient.rb +394 -0
  91. data/lib/em/protocols/smtpserver.rb +666 -0
  92. data/lib/em/protocols/socks4.rb +66 -0
  93. data/lib/em/protocols/stomp.rb +205 -0
  94. data/lib/em/protocols/tcptest.rb +54 -0
  95. data/lib/em/protocols.rb +37 -0
  96. data/lib/em/pure_ruby.rb +1300 -0
  97. data/lib/em/queue.rb +80 -0
  98. data/lib/em/resolver.rb +232 -0
  99. data/lib/em/spawnable.rb +84 -0
  100. data/lib/em/streamer.rb +118 -0
  101. data/lib/em/threaded_resource.rb +90 -0
  102. data/lib/em/tick_loop.rb +85 -0
  103. data/lib/em/timers.rb +61 -0
  104. data/lib/em/version.rb +3 -0
  105. data/lib/eventmachine.rb +1602 -0
  106. data/lib/jeventmachine.rb +319 -0
  107. data/rakelib/package.rake +120 -0
  108. data/rakelib/test.rake +6 -0
  109. data/rakelib/test_pure.rake +11 -0
  110. data/tests/client.crt +31 -0
  111. data/tests/client.key +51 -0
  112. data/tests/dhparam.pem +13 -0
  113. data/tests/em_ssl_handlers.rb +165 -0
  114. data/tests/em_test_helper.rb +198 -0
  115. data/tests/encoded_client.key +54 -0
  116. data/tests/jruby/test_jeventmachine.rb +38 -0
  117. data/tests/test_attach.rb +199 -0
  118. data/tests/test_basic.rb +321 -0
  119. data/tests/test_channel.rb +75 -0
  120. data/tests/test_completion.rb +178 -0
  121. data/tests/test_connection_count.rb +83 -0
  122. data/tests/test_connection_write.rb +35 -0
  123. data/tests/test_defer.rb +35 -0
  124. data/tests/test_deferrable.rb +35 -0
  125. data/tests/test_epoll.rb +141 -0
  126. data/tests/test_error_handler.rb +38 -0
  127. data/tests/test_exc.rb +37 -0
  128. data/tests/test_file_watch.rb +86 -0
  129. data/tests/test_fork.rb +75 -0
  130. data/tests/test_futures.rb +170 -0
  131. data/tests/test_handler_check.rb +35 -0
  132. data/tests/test_hc.rb +155 -0
  133. data/tests/test_httpclient.rb +238 -0
  134. data/tests/test_httpclient2.rb +132 -0
  135. data/tests/test_idle_connection.rb +31 -0
  136. data/tests/test_inactivity_timeout.rb +102 -0
  137. data/tests/test_io_streamer.rb +48 -0
  138. data/tests/test_ipv4.rb +96 -0
  139. data/tests/test_ipv6.rb +107 -0
  140. data/tests/test_iterator.rb +122 -0
  141. data/tests/test_kb.rb +28 -0
  142. data/tests/test_keepalive.rb +113 -0
  143. data/tests/test_line_protocol.rb +33 -0
  144. data/tests/test_ltp.rb +155 -0
  145. data/tests/test_ltp2.rb +332 -0
  146. data/tests/test_many_fds.rb +21 -0
  147. data/tests/test_next_tick.rb +104 -0
  148. data/tests/test_object_protocol.rb +36 -0
  149. data/tests/test_pause.rb +109 -0
  150. data/tests/test_pending_connect_timeout.rb +52 -0
  151. data/tests/test_pool.rb +196 -0
  152. data/tests/test_process_watch.rb +50 -0
  153. data/tests/test_processes.rb +147 -0
  154. data/tests/test_proxy_connection.rb +180 -0
  155. data/tests/test_pure.rb +156 -0
  156. data/tests/test_queue.rb +64 -0
  157. data/tests/test_resolver.rb +129 -0
  158. data/tests/test_running.rb +14 -0
  159. data/tests/test_sasl.rb +46 -0
  160. data/tests/test_send_file.rb +217 -0
  161. data/tests/test_servers.rb +32 -0
  162. data/tests/test_shutdown_hooks.rb +23 -0
  163. data/tests/test_smtpclient.rb +75 -0
  164. data/tests/test_smtpserver.rb +90 -0
  165. data/tests/test_sock_opt.rb +53 -0
  166. data/tests/test_spawn.rb +290 -0
  167. data/tests/test_ssl_args.rb +70 -0
  168. data/tests/test_ssl_dhparam.rb +57 -0
  169. data/tests/test_ssl_ecdh_curve.rb +57 -0
  170. data/tests/test_ssl_extensions.rb +24 -0
  171. data/tests/test_ssl_inline_cert.rb +222 -0
  172. data/tests/test_ssl_methods.rb +31 -0
  173. data/tests/test_ssl_protocols.rb +190 -0
  174. data/tests/test_ssl_verify.rb +108 -0
  175. data/tests/test_stomp.rb +38 -0
  176. data/tests/test_system.rb +46 -0
  177. data/tests/test_threaded_resource.rb +68 -0
  178. data/tests/test_tick_loop.rb +58 -0
  179. data/tests/test_timers.rb +150 -0
  180. data/tests/test_ud.rb +8 -0
  181. data/tests/test_unbind_reason.rb +40 -0
  182. metadata +389 -0
@@ -0,0 +1,58 @@
1
+ module EventMachine
2
+ # Utility method for coercing arguments to an object that responds to :call.
3
+ # Accepts an object and a method name to send to, or a block, or an object
4
+ # that responds to :call.
5
+ #
6
+ # @example EventMachine.Callback used with a block. Returns that block.
7
+ #
8
+ # cb = EventMachine.Callback do |msg|
9
+ # puts(msg)
10
+ # end
11
+ # # returned object is a callable
12
+ # cb.call('hello world')
13
+ #
14
+ #
15
+ # @example EventMachine.Callback used with an object (to be more specific, class object) and a method name, returns an object that responds to #call
16
+ #
17
+ # cb = EventMachine.Callback(Object, :puts)
18
+ # # returned object is a callable that delegates to Kernel#puts (in this case Object.puts)
19
+ # cb.call('hello world')
20
+ #
21
+ #
22
+ # @example EventMachine.Callback used with an object that responds to #call. Returns the argument.
23
+ #
24
+ # cb = EventMachine.Callback(proc{ |msg| puts(msg) })
25
+ # # returned object is a callable
26
+ # cb.call('hello world')
27
+ #
28
+ #
29
+ # @overload Callback(object, method)
30
+ # Wraps `method` invocation on `object` into an object that responds to #call that proxies all the arguments to that method
31
+ # @param [Object] Object to invoke method on
32
+ # @param [Symbol] Method name
33
+ # @return [<#call>] An object that responds to #call that takes any number of arguments and invokes method on object with those arguments
34
+ #
35
+ # @overload Callback(object)
36
+ # Returns callable object as is, without any coercion
37
+ # @param [<#call>] An object that responds to #call
38
+ # @return [<#call>] Its argument
39
+ #
40
+ # @overload Callback(&block)
41
+ # Returns block passed to it without any coercion
42
+ # @return [<#call>] Block passed to this method
43
+ #
44
+ # @raise [ArgumentError] When argument doesn't respond to #call, method name is missing or when invoked without arguments and block isn't given
45
+ #
46
+ # @return [<#call>]
47
+ def self.Callback(object = nil, method = nil, &blk)
48
+ if object && method
49
+ lambda { |*args| object.__send__ method, *args }
50
+ else
51
+ if object.respond_to? :call
52
+ object
53
+ else
54
+ blk || raise(ArgumentError)
55
+ end # if
56
+ end # if
57
+ end # self.Callback
58
+ end # EventMachine
data/lib/em/channel.rb ADDED
@@ -0,0 +1,69 @@
1
+ module EventMachine
2
+ # Provides a simple thread-safe way to transfer data between (typically) long running
3
+ # tasks in {EventMachine.defer} and event loop thread.
4
+ #
5
+ # @example
6
+ #
7
+ # channel = EventMachine::Channel.new
8
+ # sid = channel.subscribe { |msg| p [:got, msg] }
9
+ #
10
+ # channel.push('hello world')
11
+ # channel.unsubscribe(sid)
12
+ #
13
+ #
14
+ class Channel
15
+ def initialize
16
+ @subs = {}
17
+ @uid = 0
18
+ end
19
+
20
+ # Return the number of current subscribers.
21
+ def num_subscribers
22
+ return @subs.size
23
+ end
24
+
25
+ # Takes any arguments suitable for EM::Callback() and returns a subscriber
26
+ # id for use when unsubscribing.
27
+ #
28
+ # @return [Integer] Subscribe identifier
29
+ # @see #unsubscribe
30
+ def subscribe(*a, &b)
31
+ name = gen_id
32
+ EM.schedule { @subs[name] = EM::Callback(*a, &b) }
33
+
34
+ name
35
+ end
36
+
37
+ # Removes subscriber from the list.
38
+ #
39
+ # @param [Integer] Subscriber identifier
40
+ # @see #subscribe
41
+ def unsubscribe(name)
42
+ EM.schedule { @subs.delete name }
43
+ end
44
+
45
+ # Add items to the channel, which are pushed out to all subscribers.
46
+ def push(*items)
47
+ items = items.dup
48
+ EM.schedule { items.each { |i| @subs.values.each { |s| s.call i } } }
49
+ end
50
+ alias << push
51
+
52
+ # Fetches one message from the channel.
53
+ def pop(*a, &b)
54
+ EM.schedule {
55
+ name = subscribe do |*args|
56
+ unsubscribe(name)
57
+ EM::Callback(*a, &b).call(*args)
58
+ end
59
+ }
60
+ end
61
+
62
+ private
63
+
64
+ # @private
65
+ def gen_id
66
+ @uid += 1
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,307 @@
1
+ module EventMachine
2
+
3
+ ##
4
+ # An EM::Completion instance is a callback container for various states of
5
+ # completion. In its most basic form it has a start state and a finish state.
6
+ #
7
+ # This implementation includes some hold-back from the EM::Deferrable
8
+ # interface in order to be compatible - but it has a much cleaner
9
+ # implementation.
10
+ #
11
+ # In general it is preferred that this implementation be used as a state
12
+ # callback container than EM::DefaultDeferrable or other classes including
13
+ # EM::Deferrable. This is because it is generally more sane to keep this level
14
+ # of state in a dedicated state-back container. This generally leads to more
15
+ # malleable interfaces and software designs, as well as eradicating nasty bugs
16
+ # that result from abstraction leakage.
17
+ #
18
+ # == Basic Usage
19
+ #
20
+ # As already mentioned, the basic usage of a Completion is simply for its two
21
+ # final states, :succeeded and :failed.
22
+ #
23
+ # An asynchronous operation will complete at some future point in time, and
24
+ # users often want to react to this event. API authors will want to expose
25
+ # some common interface to react to these events.
26
+ #
27
+ # In the following example, the user wants to know when a short lived
28
+ # connection has completed its exchange with the remote server. The simple
29
+ # protocol just waits for an ack to its message.
30
+ #
31
+ # ```ruby
32
+ # class Protocol < EM::Connection
33
+ # include EM::P::LineText2
34
+ #
35
+ # def initialize(message, completion)
36
+ # @message, @completion = message, completion
37
+ # @completion.completion { close_connection }
38
+ # @completion.timeout(1, :timeout)
39
+ # end
40
+ #
41
+ # def post_init
42
+ # send_data(@message)
43
+ # end
44
+ #
45
+ # def receive_line(line)
46
+ # case line
47
+ # when /ACK/i
48
+ # @completion.succeed line
49
+ # when /ERR/i
50
+ # @completion.fail :error, line
51
+ # else
52
+ # @completion.fail :unknown, line
53
+ # end
54
+ # end
55
+ #
56
+ # def unbind
57
+ # @completion.fail :disconnected unless @completion.completed?
58
+ # end
59
+ # end
60
+ #
61
+ # class API
62
+ # attr_reader :host, :port
63
+ #
64
+ # def initialize(host = 'example.org', port = 8000)
65
+ # @host, @port = host, port
66
+ # end
67
+ #
68
+ # def request(message)
69
+ # completion = EM::Deferrable::Completion.new
70
+ # EM.connect(host, port, Protocol, message, completion)
71
+ # completion
72
+ # end
73
+ # end
74
+ #
75
+ # api = API.new
76
+ # completion = api.request('stuff')
77
+ # completion.callback do |line|
78
+ # puts "API responded with: #{line}"
79
+ # end
80
+ # completion.errback do |type, line|
81
+ # case type
82
+ # when :error
83
+ # puts "API error: #{line}"
84
+ # when :unknown
85
+ # puts "API returned unknown response: #{line}"
86
+ # when :disconnected
87
+ # puts "API server disconnected prematurely"
88
+ # when :timeout
89
+ # puts "API server did not respond in a timely fashion"
90
+ # end
91
+ # end
92
+ # ```
93
+ #
94
+ # == Advanced Usage
95
+ #
96
+ # This completion implementation also supports more state callbacks and
97
+ # arbitrary states (unlike the original Deferrable API). This allows for basic
98
+ # stateful process encapsulation. One might use this to setup state callbacks
99
+ # for various states in an exchange like in the basic usage example, except
100
+ # where the applicaiton could be made to react to "connected" and
101
+ # "disconnected" states additionally.
102
+ #
103
+ # ```ruby
104
+ # class Protocol < EM::Connection
105
+ # def initialize(completion)
106
+ # @response = []
107
+ # @completion = completion
108
+ # @completion.stateback(:disconnected) do
109
+ # @completion.succeed @response.join
110
+ # end
111
+ # end
112
+ #
113
+ # def connection_completed
114
+ # @host, @port = Socket.unpack_sockaddr_in get_peername
115
+ # @completion.change_state(:connected, @host, @port)
116
+ # send_data("GET http://example.org/ HTTP/1.0\r\n\r\n")
117
+ # end
118
+ #
119
+ # def receive_data(data)
120
+ # @response << data
121
+ # end
122
+ #
123
+ # def unbind
124
+ # @completion.change_state(:disconnected, @host, @port)
125
+ # end
126
+ # end
127
+ #
128
+ # completion = EM::Deferrable::Completion.new
129
+ # completion.stateback(:connected) do |host, port|
130
+ # puts "Connected to #{host}:#{port}"
131
+ # end
132
+ # completion.stateback(:disconnected) do |host, port|
133
+ # puts "Disconnected from #{host}:#{port}"
134
+ # end
135
+ # completion.callback do |response|
136
+ # puts response
137
+ # end
138
+ #
139
+ # EM.connect('example.org', 80, Protocol, completion)
140
+ # ```
141
+ #
142
+ # == Timeout
143
+ #
144
+ # The Completion also has a timeout. The timeout is global and is not aware of
145
+ # states apart from completion states. The timeout is only engaged if #timeout
146
+ # is called, and it will call fail if it is reached.
147
+ #
148
+ # == Completion states
149
+ #
150
+ # By default there are two completion states, :succeeded and :failed. These
151
+ # states can be modified by subclassing and overrding the #completion_states
152
+ # method. Completion states are special, in that callbacks for all completion
153
+ # states are explcitly cleared when a completion state is entered. This
154
+ # prevents errors that could arise from accidental unterminated timeouts, and
155
+ # other such user errors.
156
+ #
157
+ # == Other notes
158
+ #
159
+ # Several APIs have been carried over from EM::Deferrable for compatibility
160
+ # reasons during a transitionary period. Specifically cancel_errback and
161
+ # cancel_callback are implemented, but their usage is to be strongly
162
+ # discouraged. Due to the already complex nature of reaction systems, dynamic
163
+ # callback deletion only makes the problem much worse. It is always better to
164
+ # add correct conditionals to the callback code, or use more states, than to
165
+ # address such implementaiton issues with conditional callbacks.
166
+
167
+ class Completion
168
+ # This is totally not used (re-implemented), it's here in case people check
169
+ # for kind_of?
170
+ include EventMachine::Deferrable
171
+
172
+ attr_reader :state, :value
173
+
174
+ def initialize
175
+ @state = :unknown
176
+ @callbacks = Hash.new { |h,k| h[k] = [] }
177
+ @value = []
178
+ @timeout_timer = nil
179
+ end
180
+
181
+ # Enter the :succeeded state, setting the result value if given.
182
+ def succeed(*args)
183
+ change_state(:succeeded, *args)
184
+ end
185
+ # The old EM method:
186
+ alias set_deferred_success succeed
187
+
188
+ # Enter the :failed state, setting the result value if given.
189
+ def fail(*args)
190
+ change_state(:failed, *args)
191
+ end
192
+ # The old EM method:
193
+ alias set_deferred_failure fail
194
+
195
+ # Statebacks are called when you enter (or are in) the named state.
196
+ def stateback(state, *a, &b)
197
+ # The following is quite unfortunate special casing for :completed
198
+ # statebacks, but it's a necessary evil for latent completion
199
+ # definitions.
200
+
201
+ if :completed == state || !completed? || @state == state
202
+ @callbacks[state] << EM::Callback(*a, &b)
203
+ end
204
+ execute_callbacks
205
+ self
206
+ end
207
+
208
+ # Callbacks are called when you enter (or are in) a :succeeded state.
209
+ def callback(*a, &b)
210
+ stateback(:succeeded, *a, &b)
211
+ end
212
+
213
+ # Errbacks are called when you enter (or are in) a :failed state.
214
+ def errback(*a, &b)
215
+ stateback(:failed, *a, &b)
216
+ end
217
+
218
+ # Completions are called when you enter (or are in) either a :failed or a
219
+ # :succeeded state. They are stored as a special (reserved) state called
220
+ # :completed.
221
+ def completion(*a, &b)
222
+ stateback(:completed, *a, &b)
223
+ end
224
+
225
+ # Enter a new state, setting the result value if given. If the state is one
226
+ # of :succeeded or :failed, then :completed callbacks will also be called.
227
+ def change_state(state, *args)
228
+ @value = args
229
+ @state = state
230
+
231
+ EM.schedule { execute_callbacks }
232
+ end
233
+
234
+ # The old EM method:
235
+ alias set_deferred_status change_state
236
+
237
+ # Indicates that we've reached some kind of completion state, by default
238
+ # this is :succeeded or :failed. Due to these semantics, the :completed
239
+ # state is reserved for internal use.
240
+ def completed?
241
+ completion_states.any? { |s| state == s }
242
+ end
243
+
244
+ # Completion states simply returns a list of completion states, by default
245
+ # this is :succeeded and :failed.
246
+ def completion_states
247
+ [:succeeded, :failed]
248
+ end
249
+
250
+ # Schedule a time which if passes before we enter a completion state, this
251
+ # deferrable will be failed with the given arguments.
252
+ def timeout(time, *args)
253
+ cancel_timeout
254
+ @timeout_timer = EM::Timer.new(time) do
255
+ fail(*args) unless completed?
256
+ end
257
+ end
258
+
259
+ # Disable the timeout
260
+ def cancel_timeout
261
+ if @timeout_timer
262
+ @timeout_timer.cancel
263
+ @timeout_timer = nil
264
+ end
265
+ end
266
+
267
+ # Remove an errback. N.B. Some errbacks cannot be deleted. Usage is NOT
268
+ # recommended, this is an anti-pattern.
269
+ def cancel_errback(*a, &b)
270
+ @callbacks[:failed].delete(EM::Callback(*a, &b))
271
+ end
272
+
273
+ # Remove a callback. N.B. Some callbacks cannot be deleted. Usage is NOT
274
+ # recommended, this is an anti-pattern.
275
+ def cancel_callback(*a, &b)
276
+ @callbacks[:succeeded].delete(EM::Callback(*a, &b))
277
+ end
278
+
279
+ private
280
+ # Execute all callbacks for the current state. If in a completed state, then
281
+ # call any statebacks associated with the completed state.
282
+ def execute_callbacks
283
+ execute_state_callbacks(state)
284
+ if completed?
285
+ execute_state_callbacks(:completed)
286
+ clear_dead_callbacks
287
+ cancel_timeout
288
+ end
289
+ end
290
+
291
+ # Iterate all callbacks for a given state, and remove then call them.
292
+ def execute_state_callbacks(state)
293
+ while callback = @callbacks[state].shift
294
+ callback.call(*value)
295
+ end
296
+ end
297
+
298
+ # If we enter a completion state, clear other completion states after all
299
+ # callback chains are completed. This means that operation specific
300
+ # callbacks can't be dual-called, which is most common user error.
301
+ def clear_dead_callbacks
302
+ completion_states.each do |state|
303
+ @callbacks[state].clear
304
+ end
305
+ end
306
+ end
307
+ end