sensu-em 2.0.0-java

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 (177) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.travis.yml +12 -0
  4. data/.yardopts +7 -0
  5. data/CHANGELOG.md +33 -0
  6. data/GNU +281 -0
  7. data/Gemfile +2 -0
  8. data/LICENSE +60 -0
  9. data/README.md +109 -0
  10. data/Rakefile +20 -0
  11. data/docs/DocumentationGuidesIndex.md +27 -0
  12. data/docs/GettingStarted.md +521 -0
  13. data/docs/old/ChangeLog +211 -0
  14. data/docs/old/DEFERRABLES +246 -0
  15. data/docs/old/EPOLL +141 -0
  16. data/docs/old/INSTALL +13 -0
  17. data/docs/old/KEYBOARD +42 -0
  18. data/docs/old/LEGAL +25 -0
  19. data/docs/old/LIGHTWEIGHT_CONCURRENCY +130 -0
  20. data/docs/old/PURE_RUBY +75 -0
  21. data/docs/old/RELEASE_NOTES +94 -0
  22. data/docs/old/SMTP +4 -0
  23. data/docs/old/SPAWNED_PROCESSES +148 -0
  24. data/docs/old/TODO +8 -0
  25. data/eventmachine.gemspec +38 -0
  26. data/examples/guides/getting_started/01_eventmachine_echo_server.rb +18 -0
  27. data/examples/guides/getting_started/02_eventmachine_echo_server_that_recognizes_exit_command.rb +22 -0
  28. data/examples/guides/getting_started/03_simple_chat_server.rb +149 -0
  29. data/examples/guides/getting_started/04_simple_chat_server_step_one.rb +27 -0
  30. data/examples/guides/getting_started/05_simple_chat_server_step_two.rb +43 -0
  31. data/examples/guides/getting_started/06_simple_chat_server_step_three.rb +98 -0
  32. data/examples/guides/getting_started/07_simple_chat_server_step_four.rb +121 -0
  33. data/examples/guides/getting_started/08_simple_chat_server_step_five.rb +141 -0
  34. data/examples/old/ex_channel.rb +43 -0
  35. data/examples/old/ex_queue.rb +2 -0
  36. data/examples/old/ex_tick_loop_array.rb +15 -0
  37. data/examples/old/ex_tick_loop_counter.rb +32 -0
  38. data/examples/old/helper.rb +2 -0
  39. data/ext/binder.cpp +124 -0
  40. data/ext/binder.h +46 -0
  41. data/ext/cmain.cpp +887 -0
  42. data/ext/ed.cpp +1988 -0
  43. data/ext/ed.h +422 -0
  44. data/ext/em.cpp +2352 -0
  45. data/ext/em.h +253 -0
  46. data/ext/eventmachine.h +128 -0
  47. data/ext/extconf.rb +179 -0
  48. data/ext/fastfilereader/extconf.rb +103 -0
  49. data/ext/fastfilereader/mapper.cpp +214 -0
  50. data/ext/fastfilereader/mapper.h +59 -0
  51. data/ext/fastfilereader/rubymain.cpp +127 -0
  52. data/ext/kb.cpp +79 -0
  53. data/ext/page.cpp +107 -0
  54. data/ext/page.h +51 -0
  55. data/ext/pipe.cpp +347 -0
  56. data/ext/project.h +161 -0
  57. data/ext/rubymain.cpp +1318 -0
  58. data/ext/ssl.cpp +468 -0
  59. data/ext/ssl.h +94 -0
  60. data/java/.classpath +6 -0
  61. data/java/.gitignore +1 -0
  62. data/java/.project +17 -0
  63. data/java/src/com/rubyeventmachine/DatagramPacket.java +13 -0
  64. data/java/src/com/rubyeventmachine/EmReactor.java +529 -0
  65. data/java/src/com/rubyeventmachine/EmReactorException.java +40 -0
  66. data/java/src/com/rubyeventmachine/EventCallback.java +7 -0
  67. data/java/src/com/rubyeventmachine/EventCode.java +26 -0
  68. data/java/src/com/rubyeventmachine/EventableChannel.java +130 -0
  69. data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +180 -0
  70. data/java/src/com/rubyeventmachine/EventableSocketChannel.java +405 -0
  71. data/java/src/com/rubyeventmachine/SslBox.java +310 -0
  72. data/lib/em/buftok.rb +110 -0
  73. data/lib/em/callback.rb +58 -0
  74. data/lib/em/channel.rb +64 -0
  75. data/lib/em/completion.rb +304 -0
  76. data/lib/em/connection.rb +712 -0
  77. data/lib/em/deferrable/pool.rb +2 -0
  78. data/lib/em/deferrable.rb +210 -0
  79. data/lib/em/file_watch.rb +73 -0
  80. data/lib/em/future.rb +61 -0
  81. data/lib/em/iterator.rb +231 -0
  82. data/lib/em/messages.rb +66 -0
  83. data/lib/em/pool.rb +151 -0
  84. data/lib/em/process_watch.rb +45 -0
  85. data/lib/em/processes.rb +123 -0
  86. data/lib/em/protocols/header_and_content.rb +138 -0
  87. data/lib/em/protocols/httpclient.rb +279 -0
  88. data/lib/em/protocols/httpclient2.rb +600 -0
  89. data/lib/em/protocols/line_and_text.rb +125 -0
  90. data/lib/em/protocols/line_protocol.rb +29 -0
  91. data/lib/em/protocols/linetext2.rb +161 -0
  92. data/lib/em/protocols/memcache.rb +331 -0
  93. data/lib/em/protocols/object_protocol.rb +46 -0
  94. data/lib/em/protocols/postgres3.rb +246 -0
  95. data/lib/em/protocols/saslauth.rb +175 -0
  96. data/lib/em/protocols/smtpclient.rb +365 -0
  97. data/lib/em/protocols/smtpserver.rb +643 -0
  98. data/lib/em/protocols/socks4.rb +66 -0
  99. data/lib/em/protocols/stomp.rb +205 -0
  100. data/lib/em/protocols/tcptest.rb +54 -0
  101. data/lib/em/protocols.rb +37 -0
  102. data/lib/em/pure_ruby.rb +1017 -0
  103. data/lib/em/queue.rb +71 -0
  104. data/lib/em/resolver.rb +209 -0
  105. data/lib/em/spawnable.rb +84 -0
  106. data/lib/em/streamer.rb +118 -0
  107. data/lib/em/threaded_resource.rb +90 -0
  108. data/lib/em/tick_loop.rb +85 -0
  109. data/lib/em/timers.rb +61 -0
  110. data/lib/em/version.rb +3 -0
  111. data/lib/eventmachine.rb +1553 -0
  112. data/lib/jeventmachine.rb +321 -0
  113. data/lib/rubyeventmachine.jar +0 -0
  114. data/rakelib/cpp.rake_example +77 -0
  115. data/rakelib/package.rake +98 -0
  116. data/rakelib/test.rake +8 -0
  117. data/tests/client.crt +31 -0
  118. data/tests/client.key +51 -0
  119. data/tests/em_test_helper.rb +64 -0
  120. data/tests/server.crt +36 -0
  121. data/tests/server.key +51 -0
  122. data/tests/test_attach.rb +150 -0
  123. data/tests/test_basic.rb +294 -0
  124. data/tests/test_channel.rb +62 -0
  125. data/tests/test_completion.rb +177 -0
  126. data/tests/test_connection_count.rb +53 -0
  127. data/tests/test_defer.rb +18 -0
  128. data/tests/test_deferrable.rb +35 -0
  129. data/tests/test_epoll.rb +145 -0
  130. data/tests/test_error_handler.rb +38 -0
  131. data/tests/test_exc.rb +28 -0
  132. data/tests/test_file_watch.rb +65 -0
  133. data/tests/test_futures.rb +170 -0
  134. data/tests/test_get_sock_opt.rb +37 -0
  135. data/tests/test_handler_check.rb +35 -0
  136. data/tests/test_hc.rb +155 -0
  137. data/tests/test_httpclient.rb +190 -0
  138. data/tests/test_httpclient2.rb +133 -0
  139. data/tests/test_idle_connection.rb +25 -0
  140. data/tests/test_inactivity_timeout.rb +54 -0
  141. data/tests/test_iterator.rb +97 -0
  142. data/tests/test_kb.rb +34 -0
  143. data/tests/test_line_protocol.rb +33 -0
  144. data/tests/test_ltp.rb +138 -0
  145. data/tests/test_ltp2.rb +288 -0
  146. data/tests/test_next_tick.rb +104 -0
  147. data/tests/test_object_protocol.rb +36 -0
  148. data/tests/test_pause.rb +102 -0
  149. data/tests/test_pending_connect_timeout.rb +52 -0
  150. data/tests/test_pool.rb +194 -0
  151. data/tests/test_process_watch.rb +48 -0
  152. data/tests/test_processes.rb +128 -0
  153. data/tests/test_proxy_connection.rb +180 -0
  154. data/tests/test_pure.rb +88 -0
  155. data/tests/test_queue.rb +50 -0
  156. data/tests/test_resolver.rb +55 -0
  157. data/tests/test_running.rb +14 -0
  158. data/tests/test_sasl.rb +47 -0
  159. data/tests/test_send_file.rb +217 -0
  160. data/tests/test_servers.rb +33 -0
  161. data/tests/test_set_sock_opt.rb +37 -0
  162. data/tests/test_shutdown_hooks.rb +23 -0
  163. data/tests/test_smtpclient.rb +55 -0
  164. data/tests/test_smtpserver.rb +57 -0
  165. data/tests/test_spawn.rb +293 -0
  166. data/tests/test_ssl_args.rb +78 -0
  167. data/tests/test_ssl_echo_data.rb +60 -0
  168. data/tests/test_ssl_methods.rb +56 -0
  169. data/tests/test_ssl_verify.rb +82 -0
  170. data/tests/test_stomp.rb +37 -0
  171. data/tests/test_system.rb +42 -0
  172. data/tests/test_threaded_resource.rb +53 -0
  173. data/tests/test_tick_loop.rb +59 -0
  174. data/tests/test_timers.rb +123 -0
  175. data/tests/test_ud.rb +8 -0
  176. data/tests/test_unbind_reason.rb +48 -0
  177. metadata +297 -0
data/lib/em/queue.rb ADDED
@@ -0,0 +1,71 @@
1
+ module EventMachine
2
+ # A cross thread, reactor scheduled, linear queue.
3
+ #
4
+ # This class provides a simple queue abstraction on top of the reactor
5
+ # scheduler. It services two primary purposes:
6
+ #
7
+ # * API sugar for stateful protocols
8
+ # * Pushing processing onto the reactor thread
9
+ #
10
+ # @example
11
+ #
12
+ # q = EM::Queue.new
13
+ # q.push('one', 'two', 'three')
14
+ # 3.times do
15
+ # q.pop { |msg| puts(msg) }
16
+ # end
17
+ #
18
+ class Queue
19
+ def initialize
20
+ @items = []
21
+ @popq = []
22
+ end
23
+
24
+ # Pop items off the queue, running the block on the reactor thread. The pop
25
+ # will not happen immediately, but at some point in the future, either in
26
+ # the next tick, if the queue has data, or when the queue is populated.
27
+ #
28
+ # @return [NilClass] nil
29
+ def pop(*a, &b)
30
+ cb = EM::Callback(*a, &b)
31
+ EM.schedule do
32
+ if @items.empty?
33
+ @popq << cb
34
+ else
35
+ cb.call @items.shift
36
+ end
37
+ end
38
+ nil # Always returns nil
39
+ end
40
+
41
+ # Push items onto the queue in the reactor thread. The items will not appear
42
+ # in the queue immediately, but will be scheduled for addition during the
43
+ # next reactor tick.
44
+ def push(*items)
45
+ EM.schedule do
46
+ @items.push(*items)
47
+ @popq.shift.call @items.shift until @items.empty? || @popq.empty?
48
+ end
49
+ end
50
+ alias :<< :push
51
+
52
+ # @return [Boolean]
53
+ # @note This is a peek, it's not thread safe, and may only tend toward accuracy.
54
+ def empty?
55
+ @items.empty?
56
+ end
57
+
58
+ # @return [Integer] Queue size
59
+ # @note This is a peek, it's not thread safe, and may only tend toward accuracy.
60
+ def size
61
+ @items.size
62
+ end
63
+
64
+ # @return [Integer] Waiting size
65
+ # @note This is a peek at the number of jobs that are currently waiting on the Queue
66
+ def num_waiting
67
+ @popq.size
68
+ end
69
+
70
+ end # Queue
71
+ end # EventMachine
@@ -0,0 +1,209 @@
1
+ module EventMachine
2
+ module DNS
3
+ class Resolver
4
+
5
+ def self.resolve(hostname)
6
+ Request.new(socket, hostname)
7
+ end
8
+
9
+ @socket = @nameservers = nil
10
+
11
+ def self.socket
12
+ if !@socket || (@socket && @socket.error?)
13
+ @socket = Socket.open
14
+
15
+ @hosts = {}
16
+ IO.readlines('/etc/hosts').each do |line|
17
+ next if line =~ /^#/
18
+ addr, host = line.split(/\s+/)
19
+
20
+ if @hosts[host]
21
+ @hosts[host] << addr
22
+ else
23
+ @hosts[host] = [addr]
24
+ end
25
+ end
26
+ end
27
+
28
+ @socket
29
+ end
30
+
31
+ def self.nameservers=(ns)
32
+ @nameservers = ns
33
+ end
34
+
35
+ def self.nameservers
36
+ if !@nameservers
37
+ @nameservers = []
38
+ IO.readlines('/etc/resolv.conf').each do |line|
39
+ if line =~ /^nameserver (.+)$/
40
+ @nameservers << $1.split(/\s+/).first
41
+ end
42
+ end
43
+ end
44
+ @nameservers
45
+ end
46
+
47
+ def self.nameserver
48
+ nameservers.shuffle.first
49
+ end
50
+
51
+ def self.hosts
52
+ @hosts
53
+ end
54
+ end
55
+
56
+ class RequestIdAlreadyUsed < RuntimeError; end
57
+
58
+ class Socket < EventMachine::Connection
59
+ def self.open
60
+ EventMachine::open_datagram_socket('0.0.0.0', 0, self)
61
+ end
62
+
63
+ def initialize
64
+ @nameserver = nil
65
+ end
66
+
67
+ def post_init
68
+ @requests = {}
69
+ end
70
+
71
+ def start_timer
72
+ @timer ||= EM.add_periodic_timer(0.1, &method(:tick))
73
+ end
74
+
75
+ def stop_timer
76
+ EM.cancel_timer(@timer)
77
+ @timer = nil
78
+ end
79
+
80
+ def unbind
81
+ end
82
+
83
+ def tick
84
+ @requests.each do |id,req|
85
+ req.tick
86
+ end
87
+ end
88
+
89
+ def register_request(id, req)
90
+ if @requests.has_key?(id)
91
+ raise RequestIdAlreadyUsed
92
+ else
93
+ @requests[id] = req
94
+ end
95
+
96
+ start_timer
97
+ end
98
+
99
+ def deregister_request(id, req)
100
+ @requests.delete(id)
101
+ stop_timer if @requests.length == 0
102
+ end
103
+
104
+ def send_packet(pkt)
105
+ send_datagram(pkt, nameserver, 53)
106
+ end
107
+
108
+ def nameserver=(ns)
109
+ @nameserver = ns
110
+ end
111
+
112
+ def nameserver
113
+ @nameserver || Resolver.nameserver
114
+ end
115
+
116
+ # Decodes the packet, looks for the request and passes the
117
+ # response over to the requester
118
+ def receive_data(data)
119
+ msg = nil
120
+ begin
121
+ msg = Resolv::DNS::Message.decode data
122
+ rescue
123
+ else
124
+ req = @requests[msg.id]
125
+ if req
126
+ @requests.delete(msg.id)
127
+ stop_timer if @requests.length == 0
128
+ req.receive_answer(msg)
129
+ end
130
+ end
131
+ end
132
+ end
133
+
134
+ class Request
135
+ include Deferrable
136
+ attr_accessor :retry_interval, :max_tries
137
+
138
+ def initialize(socket, hostname)
139
+ @socket = socket
140
+ @hostname = hostname
141
+ @tries = 0
142
+ @last_send = Time.at(0)
143
+ @retry_interval = 3
144
+ @max_tries = 5
145
+
146
+ if addrs = Resolver.hosts[hostname]
147
+ succeed addrs
148
+ else
149
+ EM.next_tick { tick }
150
+ end
151
+ end
152
+
153
+ def tick
154
+ # Break early if nothing to do
155
+ return if @last_send + @retry_interval > Time.now
156
+ if @tries < @max_tries
157
+ send
158
+ else
159
+ @socket.deregister_request(@id, self)
160
+ fail 'retries exceeded'
161
+ end
162
+ end
163
+
164
+ def receive_answer(msg)
165
+ addrs = []
166
+ msg.each_answer do |name,ttl,data|
167
+ if data.kind_of?(Resolv::DNS::Resource::IN::A) ||
168
+ data.kind_of?(Resolv::DNS::Resource::IN::AAAA)
169
+ addrs << data.address.to_s
170
+ end
171
+ end
172
+
173
+ if addrs.empty?
174
+ fail "rcode=#{msg.rcode}"
175
+ else
176
+ succeed addrs
177
+ end
178
+ end
179
+
180
+ private
181
+
182
+ def send
183
+ @tries += 1
184
+ @last_send = Time.now
185
+ @socket.send_packet(packet.encode)
186
+ end
187
+
188
+ def id
189
+ begin
190
+ @id = rand(65535)
191
+ @socket.register_request(@id, self)
192
+ rescue RequestIdAlreadyUsed
193
+ retry
194
+ end unless defined?(@id)
195
+
196
+ @id
197
+ end
198
+
199
+ def packet
200
+ msg = Resolv::DNS::Message.new
201
+ msg.id = id
202
+ msg.rd = 1
203
+ msg.add_question @hostname, Resolv::DNS::Resource::IN::A
204
+ msg
205
+ end
206
+
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,84 @@
1
+ #--
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 25 Aug 2007
6
+ #
7
+ # See EventMachine and EventMachine::Connection for documentation and
8
+ # usage examples.
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
13
+ # Gmail: blackhedd
14
+ #
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either: 1) the GNU General Public License
17
+ # as published by the Free Software Foundation; either version 2 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's License.
19
+ #
20
+ # See the file COPYING for complete licensing information.
21
+ #
22
+ #---------------------------------------------------------------------------
23
+ #
24
+ #
25
+
26
+ module EventMachine
27
+ # Support for Erlang-style processes.
28
+ #
29
+ class SpawnedProcess
30
+ # Send a message to the spawned process
31
+ def notify *x
32
+ me = self
33
+ EM.next_tick {
34
+ # A notification executes in the context of this
35
+ # SpawnedProcess object. That makes self and notify
36
+ # work as one would expect.
37
+ #
38
+ y = me.call(*x)
39
+ if y and y.respond_to?(:pull_out_yield_block)
40
+ a,b = y.pull_out_yield_block
41
+ set_receiver a
42
+ self.notify if b
43
+ end
44
+ }
45
+ end
46
+ alias_method :resume, :notify
47
+ alias_method :run, :notify # for formulations like (EM.spawn {xxx}).run
48
+
49
+ def set_receiver blk
50
+ (class << self ; self ; end).class_eval do
51
+ remove_method :call if method_defined? :call
52
+ define_method :call, blk
53
+ end
54
+ end
55
+
56
+ end
57
+
58
+ # @private
59
+ class YieldBlockFromSpawnedProcess
60
+ def initialize block, notify
61
+ @block = [block,notify]
62
+ end
63
+ def pull_out_yield_block
64
+ @block
65
+ end
66
+ end
67
+
68
+ # Spawn an erlang-style process
69
+ def self.spawn &block
70
+ s = SpawnedProcess.new
71
+ s.set_receiver block
72
+ s
73
+ end
74
+
75
+ # @private
76
+ def self.yield &block
77
+ return YieldBlockFromSpawnedProcess.new( block, false )
78
+ end
79
+
80
+ # @private
81
+ def self.yield_and_notify &block
82
+ return YieldBlockFromSpawnedProcess.new( block, true )
83
+ end
84
+ end
@@ -0,0 +1,118 @@
1
+ module EventMachine
2
+ # Streams a file over a given connection. Streaming begins once the object is
3
+ # instantiated. Typically FileStreamer instances are not reused.
4
+ #
5
+ # Streaming uses buffering for files larger than 16K and uses so-called fast file reader (a C++ extension)
6
+ # if available (it is part of eventmachine gem itself).
7
+ #
8
+ # @example
9
+ #
10
+ # module FileSender
11
+ # def post_init
12
+ # streamer = EventMachine::FileStreamer.new(self, '/tmp/bigfile.tar')
13
+ # streamer.callback{
14
+ # # file was sent successfully
15
+ # close_connection_after_writing
16
+ # }
17
+ # end
18
+ # end
19
+ #
20
+ #
21
+ # @author Francis Cianfrocca
22
+ class FileStreamer
23
+ include Deferrable
24
+
25
+ # Use mapped streamer for files bigger than 16k
26
+ MappingThreshold = 16384
27
+ # Wait until next tick to send more data when 50k is still in the outgoing buffer
28
+ BackpressureLevel = 50000
29
+ # Send 16k chunks at a time
30
+ ChunkSize = 16384
31
+
32
+ # @param [EventMachine::Connection] connection
33
+ # @param [String] filename File path
34
+ #
35
+ # @option args [Boolean] :http_chunks (false) Use HTTP 1.1 style chunked-encoding semantics.
36
+ def initialize connection, filename, args = {}
37
+ @connection = connection
38
+ @http_chunks = args[:http_chunks]
39
+
40
+ if File.exist?(filename)
41
+ @size = File.size(filename)
42
+ if @size <= MappingThreshold
43
+ stream_without_mapping filename
44
+ else
45
+ stream_with_mapping filename
46
+ end
47
+ else
48
+ fail "file not found"
49
+ end
50
+ end
51
+
52
+ # @private
53
+ def stream_without_mapping filename
54
+ if @http_chunks
55
+ @connection.send_data "#{@size.to_s(16)}\r\n"
56
+ @connection.send_file_data filename
57
+ @connection.send_data "\r\n0\r\n\r\n"
58
+ else
59
+ @connection.send_file_data filename
60
+ end
61
+ succeed
62
+ end
63
+ private :stream_without_mapping
64
+
65
+ # @private
66
+ def stream_with_mapping filename
67
+ ensure_mapping_extension_is_present
68
+
69
+ @position = 0
70
+ @mapping = EventMachine::FastFileReader::Mapper.new filename
71
+ stream_one_chunk
72
+ end
73
+ private :stream_with_mapping
74
+
75
+ # Used internally to stream one chunk at a time over multiple reactor ticks
76
+ # @private
77
+ def stream_one_chunk
78
+ loop {
79
+ if @position < @size
80
+ if @connection.get_outbound_data_size > BackpressureLevel
81
+ EventMachine::next_tick {stream_one_chunk}
82
+ break
83
+ else
84
+ len = @size - @position
85
+ len = ChunkSize if (len > ChunkSize)
86
+
87
+ @connection.send_data( "#{len.to_s(16)}\r\n" ) if @http_chunks
88
+ @connection.send_data( @mapping.get_chunk( @position, len ))
89
+ @connection.send_data("\r\n") if @http_chunks
90
+
91
+ @position += len
92
+ end
93
+ else
94
+ @connection.send_data "0\r\n\r\n" if @http_chunks
95
+ @mapping.close
96
+ succeed
97
+ break
98
+ end
99
+ }
100
+ end
101
+
102
+ #
103
+ # We use an outboard extension class to get memory-mapped files.
104
+ # It's outboard to avoid polluting the core distro, but that means
105
+ # there's a "hidden" dependency on it. The first time we get here in
106
+ # any run, try to load up the dependency extension. User code will see
107
+ # a LoadError if it's not available, but code that doesn't require
108
+ # mapped files will work fine without it. This is a somewhat difficult
109
+ # compromise between usability and proper modularization.
110
+ #
111
+ # @private
112
+ def ensure_mapping_extension_is_present
113
+ @@fastfilereader ||= (require 'fastfilereaderext')
114
+ end
115
+ private :ensure_mapping_extension_is_present
116
+
117
+ end # FileStreamer
118
+ end # EventMachine
@@ -0,0 +1,90 @@
1
+ module EventMachine
2
+ # = EventMachine::ThreadedResource
3
+ #
4
+ # A threaded resource is a "quick and dirty" wrapper around the concept of
5
+ # wiring up synchronous code into a standard EM::Pool. This is useful to keep
6
+ # interfaces coherent and provide a simple approach at "making an interface
7
+ # async-ish".
8
+ #
9
+ # General usage is to wrap libraries that do not support EventMachine, or to
10
+ # have a specific number of dedicated high-cpu worker resources.
11
+ #
12
+ # == Basic Usage example
13
+ #
14
+ # This example requires the cassandra gem. The cassandra gem contains an
15
+ # EventMachine interface, but it's sadly Fiber based and thus only works on
16
+ # 1.9. It also requires (potentially) complex stack switching logic to reach
17
+ # completion of nested operations. By contrast this approach provides a block
18
+ # in which normal synchronous code can occur, but makes no attempt to wire the
19
+ # IO into EventMachines C++ IO implementations, instead relying on the reactor
20
+ # pattern in rb_thread_select.
21
+ #
22
+ # cassandra_dispatcher = ThreadedResource.new do
23
+ # Cassandra.new('allthethings', '127.0.0.1:9160')
24
+ # end
25
+ #
26
+ # pool = EM::Pool.new
27
+ #
28
+ # pool.add cassandra_dispatcher
29
+ #
30
+ # # If we don't care about the result:
31
+ # pool.perform do |dispatcher|
32
+ # # The following block executes inside a dedicated thread, and should not
33
+ # # access EventMachine things:
34
+ # dispatcher.dispatch do |cassandra|
35
+ # cassandra.insert(:Things, '10', 'stuff' => 'things')
36
+ # end
37
+ # end
38
+ #
39
+ # # Example where we care about the result:
40
+ # pool.perform do |dispatcher|
41
+ # # The dispatch block is executed in the resources thread.
42
+ # completion = dispatcher.dispatch do |cassandra|
43
+ # cassandra.get(:Things, '10', 'stuff')
44
+ # end
45
+ #
46
+ # # This block will be yielded on the EM thread:
47
+ # completion.callback do |result|
48
+ # EM.do_something_with(result)
49
+ # end
50
+ #
51
+ # completion
52
+ # end
53
+ class ThreadedResource
54
+
55
+ # The block should return the resource that will be yielded in a dispatch.
56
+ def initialize
57
+ @resource = yield
58
+
59
+ @running = true
60
+ @queue = ::Queue.new
61
+ @thread = Thread.new do
62
+ @queue.pop.call while @running
63
+ end
64
+ end
65
+
66
+ # Called on the EM thread, generally in a perform block to return a
67
+ # completion for the work.
68
+ def dispatch
69
+ completion = EM::Completion.new
70
+ @queue << lambda do
71
+ begin
72
+ result = yield @resource
73
+ completion.succeed result
74
+ rescue Exception => e
75
+ completion.fail e
76
+ end
77
+ end
78
+ completion
79
+ end
80
+
81
+ # Kill the internal thread. should only be used to cleanup - generally
82
+ # only required for tests.
83
+ def shutdown
84
+ @running = false
85
+ @queue << lambda {}
86
+ @thread.join
87
+ end
88
+
89
+ end
90
+ end
@@ -0,0 +1,85 @@
1
+ module EventMachine
2
+ # Creates and immediately starts an EventMachine::TickLoop
3
+ def self.tick_loop(*a, &b)
4
+ TickLoop.new(*a, &b).start
5
+ end
6
+
7
+ # A TickLoop is useful when one needs to distribute amounts of work
8
+ # throughout ticks in order to maintain response times. It is also useful for
9
+ # simple repeated checks and metrics.
10
+ #
11
+ # # Here we run through an array one item per tick until it is empty,
12
+ # # printing each element.
13
+ # # When the array is empty, we return :stop from the callback, and the
14
+ # # loop will terminate.
15
+ # # When the loop terminates, the on_stop callbacks will be called.
16
+ # EM.run do
17
+ # array = (1..100).to_a
18
+ #
19
+ # tickloop = EM.tick_loop do
20
+ # if array.empty?
21
+ # :stop
22
+ # else
23
+ # puts array.shift
24
+ # end
25
+ # end
26
+ #
27
+ # tickloop.on_stop { EM.stop }
28
+ # end
29
+ #
30
+ class TickLoop
31
+
32
+ # Arguments: A callback (EM::Callback) to call each tick. If the call
33
+ # returns +:stop+ then the loop will be stopped. Any other value is
34
+ # ignored.
35
+ def initialize(*a, &b)
36
+ @work = EM::Callback(*a, &b)
37
+ @stops = []
38
+ @stopped = true
39
+ end
40
+
41
+ # Arguments: A callback (EM::Callback) to call once on the next stop (or
42
+ # immediately if already stopped).
43
+ def on_stop(*a, &b)
44
+ if @stopped
45
+ EM::Callback(*a, &b).call
46
+ else
47
+ @stops << EM::Callback(*a, &b)
48
+ end
49
+ end
50
+
51
+ # Stop the tick loop immediately, and call it's on_stop callbacks.
52
+ def stop
53
+ @stopped = true
54
+ until @stops.empty?
55
+ @stops.shift.call
56
+ end
57
+ end
58
+
59
+ # Query if the loop is stopped.
60
+ def stopped?
61
+ @stopped
62
+ end
63
+
64
+ # Start the tick loop, will raise argument error if the loop is already
65
+ # running.
66
+ def start
67
+ raise ArgumentError, "double start" unless @stopped
68
+ @stopped = false
69
+ schedule
70
+ end
71
+
72
+ private
73
+ def schedule
74
+ EM.next_tick do
75
+ next if @stopped
76
+ if @work.call == :stop
77
+ stop
78
+ else
79
+ schedule
80
+ end
81
+ end
82
+ self
83
+ end
84
+ end
85
+ end
data/lib/em/timers.rb ADDED
@@ -0,0 +1,61 @@
1
+ module EventMachine
2
+ # Creates a one-time timer
3
+ #
4
+ # timer = EventMachine::Timer.new(5) do
5
+ # # this will never fire because we cancel it
6
+ # end
7
+ # timer.cancel
8
+ #
9
+ class Timer
10
+ # Create a new timer that fires after a given number of seconds
11
+ def initialize interval, callback=nil, &block
12
+ @signature = EventMachine::add_timer(interval, callback || block)
13
+ end
14
+
15
+ # Cancel the timer
16
+ def cancel
17
+ EventMachine.send :cancel_timer, @signature
18
+ end
19
+ end
20
+
21
+ # Creates a periodic timer
22
+ #
23
+ # @example
24
+ # n = 0
25
+ # timer = EventMachine::PeriodicTimer.new(5) do
26
+ # puts "the time is #{Time.now}"
27
+ # timer.cancel if (n+=1) > 5
28
+ # end
29
+ #
30
+ class PeriodicTimer
31
+ # Create a new periodic timer that executes every interval seconds
32
+ def initialize interval, callback=nil, &block
33
+ @interval = interval
34
+ @code = callback || block
35
+ @cancelled = false
36
+ @work = method(:fire)
37
+ schedule
38
+ end
39
+
40
+ # Cancel the periodic timer
41
+ def cancel
42
+ @cancelled = true
43
+ end
44
+
45
+ # Fire the timer every interval seconds
46
+ attr_accessor :interval
47
+
48
+ # @private
49
+ def schedule
50
+ EventMachine::add_timer @interval, @work
51
+ end
52
+
53
+ # @private
54
+ def fire
55
+ unless @cancelled
56
+ @code.call
57
+ schedule
58
+ end
59
+ end
60
+ end
61
+ end