foxbat 0.2.4 → 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/em/connection.rb +10 -6
- data/lib/em/deferrable.rb +210 -0
- data/lib/eventmachine.rb +24 -3
- data/lib/foxbat/client.rb +29 -0
- data/lib/foxbat/future.rb +15 -0
- data/lib/foxbat/generic_connection.rb +15 -0
- data/lib/foxbat/http_server.rb +104 -0
- data/lib/foxbat/netty_connection.rb +20 -2
- data/lib/foxbat/pipeline.rb +16 -5
- data/lib/foxbat/security.rb +17 -6
- data/lib/foxbat/server.rb +12 -8
- data/lib/foxbat/version.rb +1 -1
- data/lib/foxbat.rb +33 -25
- data/lib/guava-13.0.1.jar +0 -0
- metadata +8 -2
data/lib/em/connection.rb
CHANGED
@@ -17,6 +17,14 @@ module EventMachine
|
|
17
17
|
@netty_handler.write(data)
|
18
18
|
end
|
19
19
|
|
20
|
+
def broadcast(data)
|
21
|
+
@netty_handler.write(data, true)
|
22
|
+
end
|
23
|
+
|
24
|
+
def send_file_data(path)
|
25
|
+
@netty_handler.send_file(path)
|
26
|
+
end
|
27
|
+
|
20
28
|
def post_init; end
|
21
29
|
|
22
30
|
def unbind; end
|
@@ -28,11 +36,7 @@ module EventMachine
|
|
28
36
|
end
|
29
37
|
|
30
38
|
def close_connection(after_writing=false)
|
31
|
-
|
32
|
-
@close_scheduled = true
|
33
|
-
else
|
34
|
-
@netty_handler.close
|
35
|
-
end
|
39
|
+
@netty_handler.close
|
36
40
|
end
|
37
41
|
|
38
42
|
def close_connection_after_writing
|
@@ -44,7 +48,7 @@ module EventMachine
|
|
44
48
|
end
|
45
49
|
|
46
50
|
def comm_inactivity_timeout=(seconds)
|
47
|
-
|
51
|
+
@netty_handler.set_read_timeout(seconds)
|
48
52
|
end
|
49
53
|
|
50
54
|
end
|
@@ -0,0 +1,210 @@
|
|
1
|
+
#--
|
2
|
+
#
|
3
|
+
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
4
|
+
# Homepage:: http://rubyeventmachine.com
|
5
|
+
# Date:: 16 Jul 2006
|
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
|
+
module Deferrable
|
28
|
+
autoload :Pool, 'em/deferrable/pool'
|
29
|
+
|
30
|
+
# Specify a block to be executed if and when the Deferrable object receives
|
31
|
+
# a status of :succeeded. See #set_deferred_status for more information.
|
32
|
+
#
|
33
|
+
# Calling this method on a Deferrable object whose status is not yet known
|
34
|
+
# will cause the callback block to be stored on an internal list.
|
35
|
+
# If you call this method on a Deferrable whose status is :succeeded, the
|
36
|
+
# block will be executed immediately, receiving the parameters given to the
|
37
|
+
# prior #set_deferred_status call.
|
38
|
+
#
|
39
|
+
#--
|
40
|
+
# If there is no status, add a callback to an internal list.
|
41
|
+
# If status is succeeded, execute the callback immediately.
|
42
|
+
# If status is failed, do nothing.
|
43
|
+
#
|
44
|
+
def callback &block
|
45
|
+
return unless block
|
46
|
+
@deferred_status ||= :unknown
|
47
|
+
if @deferred_status == :succeeded
|
48
|
+
block.call(*@deferred_args)
|
49
|
+
elsif @deferred_status != :failed
|
50
|
+
@callbacks ||= []
|
51
|
+
@callbacks.unshift block # << block
|
52
|
+
end
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
# Cancels an outstanding callback to &block if any. Undoes the action of #callback.
|
57
|
+
#
|
58
|
+
def cancel_callback block
|
59
|
+
@callbacks ||= []
|
60
|
+
@callbacks.delete block
|
61
|
+
end
|
62
|
+
|
63
|
+
# Specify a block to be executed if and when the Deferrable object receives
|
64
|
+
# a status of :failed. See #set_deferred_status for more information.
|
65
|
+
#--
|
66
|
+
# If there is no status, add an errback to an internal list.
|
67
|
+
# If status is failed, execute the errback immediately.
|
68
|
+
# If status is succeeded, do nothing.
|
69
|
+
#
|
70
|
+
def errback &block
|
71
|
+
return unless block
|
72
|
+
@deferred_status ||= :unknown
|
73
|
+
if @deferred_status == :failed
|
74
|
+
block.call(*@deferred_args)
|
75
|
+
elsif @deferred_status != :succeeded
|
76
|
+
@errbacks ||= []
|
77
|
+
@errbacks.unshift block # << block
|
78
|
+
end
|
79
|
+
self
|
80
|
+
end
|
81
|
+
|
82
|
+
# Cancels an outstanding errback to &block if any. Undoes the action of #errback.
|
83
|
+
#
|
84
|
+
def cancel_errback block
|
85
|
+
@errbacks ||= []
|
86
|
+
@errbacks.delete block
|
87
|
+
end
|
88
|
+
|
89
|
+
# Sets the "disposition" (status) of the Deferrable object. See also the large set of
|
90
|
+
# sugarings for this method.
|
91
|
+
# Note that if you call this method without arguments,
|
92
|
+
# no arguments will be passed to the callback/errback.
|
93
|
+
# If the user has coded these with arguments, then the
|
94
|
+
# user code will throw an argument exception.
|
95
|
+
# Implementors of deferrable classes <b>must</b>
|
96
|
+
# document the arguments they will supply to user callbacks.
|
97
|
+
#
|
98
|
+
# OBSERVE SOMETHING VERY SPECIAL here: you may call this method even
|
99
|
+
# on the INSIDE of a callback. This is very useful when a previously-registered
|
100
|
+
# callback wants to change the parameters that will be passed to subsequently-registered
|
101
|
+
# ones.
|
102
|
+
#
|
103
|
+
# You may give either :succeeded or :failed as the status argument.
|
104
|
+
#
|
105
|
+
# If you pass :succeeded, then all of the blocks passed to the object using the #callback
|
106
|
+
# method (if any) will be executed BEFORE the #set_deferred_status method returns. All of the blocks
|
107
|
+
# passed to the object using #errback will be discarded.
|
108
|
+
#
|
109
|
+
# If you pass :failed, then all of the blocks passed to the object using the #errback
|
110
|
+
# method (if any) will be executed BEFORE the #set_deferred_status method returns. All of the blocks
|
111
|
+
# passed to the object using # callback will be discarded.
|
112
|
+
#
|
113
|
+
# If you pass any arguments to #set_deferred_status in addition to the status argument,
|
114
|
+
# they will be passed as arguments to any callbacks or errbacks that are executed.
|
115
|
+
# It's your responsibility to ensure that the argument lists specified in your callbacks and
|
116
|
+
# errbacks match the arguments given in calls to #set_deferred_status, otherwise Ruby will raise
|
117
|
+
# an ArgumentError.
|
118
|
+
#
|
119
|
+
#--
|
120
|
+
# We're shifting callbacks off and discarding them as we execute them.
|
121
|
+
# This is valid because by definition callbacks are executed no more than
|
122
|
+
# once. It also has the magic effect of permitting recursive calls, which
|
123
|
+
# means that a callback can call #set_deferred_status and change the parameters
|
124
|
+
# that will be sent to subsequent callbacks down the chain.
|
125
|
+
#
|
126
|
+
# Changed @callbacks and @errbacks from push/shift to unshift/pop, per suggestion
|
127
|
+
# by Kirk Haines, to work around the memory leak bug that still exists in many Ruby
|
128
|
+
# versions.
|
129
|
+
#
|
130
|
+
# Changed 15Sep07: after processing callbacks or errbacks, CLEAR the other set of
|
131
|
+
# handlers. This gets us a little closer to the behavior of Twisted's "deferred,"
|
132
|
+
# which only allows status to be set once. Prior to making this change, it was possible
|
133
|
+
# to "succeed" a Deferrable (triggering its callbacks), and then immediately "fail" it,
|
134
|
+
# triggering its errbacks! That is clearly undesirable, but it's just as undesirable
|
135
|
+
# to raise an exception is status is set more than once on a Deferrable. The latter
|
136
|
+
# behavior would invalidate the idiom of resetting arguments by setting status from
|
137
|
+
# within a callback or errback, but more seriously it would cause spurious errors
|
138
|
+
# if a Deferrable was timed out and then an attempt was made to succeed it. See the
|
139
|
+
# comments under the new method #timeout.
|
140
|
+
#
|
141
|
+
def set_deferred_status status, *args
|
142
|
+
cancel_timeout
|
143
|
+
@errbacks ||= nil
|
144
|
+
@callbacks ||= nil
|
145
|
+
@deferred_status = status
|
146
|
+
@deferred_args = args
|
147
|
+
case @deferred_status
|
148
|
+
when :succeeded
|
149
|
+
if @callbacks
|
150
|
+
while cb = @callbacks.pop
|
151
|
+
cb.call(*@deferred_args)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
@errbacks.clear if @errbacks
|
155
|
+
when :failed
|
156
|
+
if @errbacks
|
157
|
+
while eb = @errbacks.pop
|
158
|
+
eb.call(*@deferred_args)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
@callbacks.clear if @callbacks
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
# Setting a timeout on a Deferrable causes it to go into the failed state after
|
167
|
+
# the Timeout expires (passing no arguments to the object's errbacks).
|
168
|
+
# Setting the status at any time prior to a call to the expiration of the timeout
|
169
|
+
# will cause the timer to be cancelled.
|
170
|
+
def timeout seconds, *args
|
171
|
+
cancel_timeout
|
172
|
+
me = self
|
173
|
+
@deferred_timeout = EventMachine::Timer.new(seconds) {me.fail(*args)}
|
174
|
+
self
|
175
|
+
end
|
176
|
+
|
177
|
+
# Cancels an outstanding timeout if any. Undoes the action of #timeout.
|
178
|
+
#
|
179
|
+
def cancel_timeout
|
180
|
+
@deferred_timeout ||= nil
|
181
|
+
if @deferred_timeout
|
182
|
+
@deferred_timeout.cancel
|
183
|
+
@deferred_timeout = nil
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
|
188
|
+
# Sugar for set_deferred_status(:succeeded, ...)
|
189
|
+
#
|
190
|
+
def succeed *args
|
191
|
+
set_deferred_status :succeeded, *args
|
192
|
+
end
|
193
|
+
alias set_deferred_success succeed
|
194
|
+
|
195
|
+
# Sugar for set_deferred_status(:failed, ...)
|
196
|
+
#
|
197
|
+
def fail *args
|
198
|
+
set_deferred_status :failed, *args
|
199
|
+
end
|
200
|
+
alias set_deferred_failure fail
|
201
|
+
end
|
202
|
+
|
203
|
+
|
204
|
+
# DefaultDeferrable is an otherwise empty class that includes Deferrable.
|
205
|
+
# This is very useful when you just need to return a Deferrable object
|
206
|
+
# as a way of communicating deferred status to some other part of a program.
|
207
|
+
class DefaultDeferrable
|
208
|
+
include Deferrable
|
209
|
+
end
|
210
|
+
end
|
data/lib/eventmachine.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
import java.lang.Long
|
2
2
|
import java.util.concurrent.Executors
|
3
3
|
import java.util.concurrent.TimeUnit
|
4
|
+
import org.jboss.netty.util.HashedWheelTimer
|
5
|
+
|
6
|
+
require 'foxbat/future'
|
4
7
|
|
5
8
|
module EventMachine
|
6
9
|
|
7
|
-
def self.start_server
|
10
|
+
def self.start_server(host, port=nil, handler=nil, *args, &block)
|
8
11
|
s = Foxbat::Server.new(host, port, handler, args.first || {}, &block)
|
9
12
|
|
10
13
|
@@servers ||= []
|
@@ -13,6 +16,11 @@ module EventMachine
|
|
13
16
|
s.start(@@threadpool)
|
14
17
|
end
|
15
18
|
|
19
|
+
def self.connect(host, port=nil, handler=nil, *args, &block)
|
20
|
+
c = Foxbat::Client.new(host, port, handler, args.first || {}, &block)
|
21
|
+
c.start(@@threadpool)
|
22
|
+
end
|
23
|
+
|
16
24
|
# We're on the JVM- this does nothing!
|
17
25
|
def self.epoll; end
|
18
26
|
def self.kqueue; end
|
@@ -20,24 +28,37 @@ module EventMachine
|
|
20
28
|
def self.run(blk=nil, tail=nil, &block)
|
21
29
|
@alive = true
|
22
30
|
@@threadpool = Executors.newCachedThreadPool
|
31
|
+
@@timer = HashedWheelTimer.new
|
23
32
|
|
24
33
|
block.call
|
25
34
|
|
26
35
|
@@threadpool.awaitTermination(Long::MAX_VALUE, TimeUnit::SECONDS)
|
27
36
|
end
|
28
37
|
|
38
|
+
def self.add_timer(*args, &block)
|
39
|
+
timeout = args.shift
|
40
|
+
callable = args.shift || block
|
41
|
+
task = lambda { |t| callable.call }
|
42
|
+
@@timer.newTimeout(task, timeout, TimeUnit::SECONDS)
|
43
|
+
end
|
44
|
+
|
29
45
|
def self.stop
|
30
46
|
@@servers.each { |s| s.stop }
|
31
47
|
@@threadpool.shutdown
|
48
|
+
@@timer.stop
|
32
49
|
end
|
33
50
|
|
34
|
-
def self.
|
35
|
-
@@threadpool
|
51
|
+
def self.defer(op, callback)
|
52
|
+
Foxbat::Future.schedule(op, callback, @@threadpool)
|
36
53
|
end
|
37
54
|
|
38
55
|
def self.reactor_running?
|
39
56
|
@alive
|
40
57
|
end
|
41
58
|
|
59
|
+
def self.connection_count
|
60
|
+
@@servers.map { |s| s.connection_count }.reduce(:+)
|
61
|
+
end
|
62
|
+
|
42
63
|
end
|
43
64
|
|
@@ -0,0 +1,29 @@
|
|
1
|
+
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory
|
2
|
+
import org.jboss.netty.bootstrap.ClientBootstrap
|
3
|
+
|
4
|
+
module Foxbat
|
5
|
+
|
6
|
+
class Client
|
7
|
+
|
8
|
+
def initialize(host, port, klass, options, &block)
|
9
|
+
if options[:secure]
|
10
|
+
@context = Security.setup_ssl_client_context
|
11
|
+
end
|
12
|
+
|
13
|
+
@group = DefaultChannelGroup.new
|
14
|
+
@address = InetSocketAddress.new(host, port)
|
15
|
+
@pipeline = Pipeline.new(klass, @group, true, options, @context, &block)
|
16
|
+
end
|
17
|
+
|
18
|
+
def start(threadpool)
|
19
|
+
factory = NioClientSocketChannelFactory.new(threadpool, threadpool)
|
20
|
+
@bootstrap = ClientBootstrap.new(factory)
|
21
|
+
@bootstrap.setPipelineFactory(@pipeline)
|
22
|
+
@bootstrap.setOption("child.tcpNoDelay", true)
|
23
|
+
@bootstrap.setOption("child.keepAlive", true)
|
24
|
+
@bootstrap.connect(@address)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import com.google.common.util.concurrent.ListenableFutureTask
|
2
|
+
|
3
|
+
module Foxbat
|
4
|
+
|
5
|
+
class Future
|
6
|
+
|
7
|
+
def self.schedule(op, cb, executor)
|
8
|
+
future = ListenableFutureTask.create(op)
|
9
|
+
future.addListener(cb, executor)
|
10
|
+
executor.submit(future)
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
import org.jboss.netty.handler.codec.http.HttpRequestDecoder
|
2
|
+
import org.jboss.netty.handler.codec.http.HttpResponseEncoder
|
3
|
+
import org.jboss.netty.handler.codec.http.HttpContentCompressor
|
4
|
+
import org.jboss.netty.channel.Channels
|
5
|
+
import org.jboss.netty.channel.ChannelPipelineFactory
|
6
|
+
import org.jboss.netty.buffer.ChannelBuffers
|
7
|
+
import org.jboss.netty.handler.codec.http.DefaultHttpResponse
|
8
|
+
import org.jboss.netty.handler.codec.http.HttpResponseStatus
|
9
|
+
import org.jboss.netty.handler.codec.http.HttpVersion
|
10
|
+
import org.jboss.netty.handler.codec.http.HttpHeaders
|
11
|
+
|
12
|
+
require_relative 'server'
|
13
|
+
|
14
|
+
module Foxbat
|
15
|
+
|
16
|
+
class WebPipeline
|
17
|
+
include ChannelPipelineFactory
|
18
|
+
|
19
|
+
HANDLER = "handler"
|
20
|
+
ENCODER = "encoder"
|
21
|
+
DECODER = "decoder"
|
22
|
+
DEFLATER = "deflater"
|
23
|
+
|
24
|
+
def initialize(app)
|
25
|
+
@app = app
|
26
|
+
@handler = ReadTimeoutHandler.new(EM.timer, 10)
|
27
|
+
end
|
28
|
+
|
29
|
+
def getPipeline
|
30
|
+
pipeline = Channels.pipeline
|
31
|
+
pipeline.addLast(DECODER, HttpRequestDecoder.new)
|
32
|
+
pipeline.addLast(ENCODER, HttpResponseEncoder.new)
|
33
|
+
pipeline.addLast(DEFLATER, HttpContentCompressor.new)
|
34
|
+
pipeline.addLast(HANDLER, WebHandler.new(@app))
|
35
|
+
pipeline
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class WebHandler < SimpleChannelUpstreamHandler
|
40
|
+
|
41
|
+
def initialize(app)
|
42
|
+
super()
|
43
|
+
@app = app
|
44
|
+
end
|
45
|
+
|
46
|
+
def messageReceived(ctx, e)
|
47
|
+
req = e.getMessage
|
48
|
+
env = to_rack(req)
|
49
|
+
val = @app.call(env)
|
50
|
+
|
51
|
+
resp = to_netty(val)
|
52
|
+
future = e.getChannel.write(resp)
|
53
|
+
|
54
|
+
listener = Object.new
|
55
|
+
def listener.operationComplete(f)
|
56
|
+
f.getChannel.close
|
57
|
+
end
|
58
|
+
|
59
|
+
future.addListener(listener)
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def to_rack(req)
|
65
|
+
env = {}
|
66
|
+
env['REQUEST_METHOD'] = req.getMethod.toString
|
67
|
+
|
68
|
+
req.getHeaders.each do |h|
|
69
|
+
header = "HTTP_" + h.getKey.upcase.gsub("-", "_")
|
70
|
+
env[header] = h.getValue
|
71
|
+
end
|
72
|
+
env
|
73
|
+
end
|
74
|
+
|
75
|
+
CODES = {200 => HttpResponseStatus::OK}
|
76
|
+
|
77
|
+
def to_netty(resp)
|
78
|
+
code, headers, content = resp
|
79
|
+
|
80
|
+
netty_response = DefaultHttpResponse.new(HttpVersion::HTTP_1_1, CODES[code])
|
81
|
+
headers.each do |k,v|
|
82
|
+
netty_response.setHeader(k, v)
|
83
|
+
end
|
84
|
+
|
85
|
+
content = content.to_java_bytes if content.is_a?(String)
|
86
|
+
buf = ChannelBuffers.copiedBuffer(content)
|
87
|
+
netty_response.setContent(buf)
|
88
|
+
netty_response.setHeader('Content-Length', buf.writerIndex)
|
89
|
+
netty_response.setHeader('Server', 'Foxbat')
|
90
|
+
netty_response
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class HttpServer < Server
|
95
|
+
|
96
|
+
def initialize(host, port, klass, options, &block)
|
97
|
+
super(host, port, klass, options, &block)
|
98
|
+
@pipeline.releaseExternalResources
|
99
|
+
@pipeline = WebPipeline.new(block)
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
|
+
import java.io.RandomAccessFile
|
1
2
|
import java.nio.ByteBuffer
|
2
3
|
import org.jboss.netty.buffer.ChannelBuffers
|
4
|
+
import org.jboss.netty.channel.DefaultFileRegion
|
3
5
|
import org.jboss.netty.channel.SimpleChannelUpstreamHandler
|
4
6
|
|
5
7
|
module Foxbat
|
@@ -13,21 +15,37 @@ module Foxbat
|
|
13
15
|
super()
|
14
16
|
end
|
15
17
|
|
16
|
-
def write(data)
|
18
|
+
def write(data, broadcast=false)
|
17
19
|
data = data.to_java_bytes if data.is_a?(String)
|
18
20
|
buf = ChannelBuffers.copiedBuffer(data)
|
19
|
-
|
21
|
+
|
22
|
+
recipient = broadcast ? @group : @channel
|
23
|
+
recipient.write(buf)
|
24
|
+
end
|
25
|
+
|
26
|
+
def send_file(path)
|
27
|
+
file_channel = RandomAccessFile.new(path, 'r').getChannel
|
28
|
+
region = DefaultFileRegion.new(file_channel, 0, file_channel.size, true)
|
29
|
+
@channel.write(region)
|
20
30
|
end
|
21
31
|
|
22
32
|
def close
|
23
33
|
@channel.close
|
24
34
|
end
|
25
35
|
|
36
|
+
def set_read_timeout(seconds)
|
37
|
+
|
38
|
+
end
|
39
|
+
|
26
40
|
private
|
27
41
|
|
28
42
|
def channelOpen(ctx, e)
|
29
43
|
@group.add(e.getChannel)
|
30
44
|
end
|
45
|
+
|
46
|
+
def channelClosed(ctx, e)
|
47
|
+
@group.remove(e.getChannel)
|
48
|
+
end
|
31
49
|
|
32
50
|
def channelConnected(ctx, e)
|
33
51
|
@pipeline = ctx.getPipeline
|
data/lib/foxbat/pipeline.rb
CHANGED
@@ -10,9 +10,19 @@ module Foxbat
|
|
10
10
|
class Pipeline
|
11
11
|
include ChannelPipelineFactory
|
12
12
|
|
13
|
-
|
13
|
+
HANDLER = "handler"
|
14
|
+
SSL_HANDLER = "ssl"
|
15
|
+
|
16
|
+
def initialize(handler, group, client, options={}, ssl_context=nil, &block)
|
14
17
|
@options = options
|
15
18
|
@handler = handler
|
19
|
+
@client_mode = client
|
20
|
+
|
21
|
+
if handler.class == Module
|
22
|
+
@handler = Class.new(EM::Connection)
|
23
|
+
@handler.send(:include, handler)
|
24
|
+
end
|
25
|
+
|
16
26
|
@group = group
|
17
27
|
@block = block
|
18
28
|
@context = ssl_context
|
@@ -21,18 +31,19 @@ module Foxbat
|
|
21
31
|
def getPipeline
|
22
32
|
pipeline = Channels.pipeline
|
23
33
|
if @context
|
24
|
-
engine = Security.create_ssl_engine(@context)
|
25
|
-
pipeline.addLast(
|
34
|
+
engine = Security.create_ssl_engine(@context, @client_mode)
|
35
|
+
pipeline.addLast(SSL_HANDLER, SslHandler.new(engine))
|
26
36
|
end
|
37
|
+
|
27
38
|
h = @handler.new(@options)
|
28
39
|
@block.call(h) if @block
|
29
40
|
connection = NettyConnection.new(h, @group)
|
30
|
-
pipeline.addLast(
|
41
|
+
pipeline.addLast(HANDLER, connection)
|
31
42
|
pipeline
|
32
43
|
end
|
33
44
|
|
34
45
|
def releaseExternalResources
|
35
|
-
|
46
|
+
# todo
|
36
47
|
end
|
37
48
|
end
|
38
49
|
|
data/lib/foxbat/security.rb
CHANGED
@@ -24,8 +24,9 @@ module Foxbat
|
|
24
24
|
end
|
25
25
|
fis.close
|
26
26
|
|
27
|
-
|
28
|
-
|
27
|
+
algorithm = KeyManagerFactory.getDefaultAlgorithm
|
28
|
+
kmf = KeyManagerFactory.getInstance(algorithm)
|
29
|
+
tmf = TrustManagerFactory.getInstance(algorithm)
|
29
30
|
|
30
31
|
kmf.init(keystore, password)
|
31
32
|
tmf.init(keystore)
|
@@ -43,10 +44,20 @@ module Foxbat
|
|
43
44
|
context.init(kmf.getKeyManagers, tmf.getTrustManagers, nil)
|
44
45
|
context
|
45
46
|
end
|
46
|
-
|
47
|
-
def self.
|
48
|
-
|
49
|
-
|
47
|
+
|
48
|
+
def self.setup_ssl_client_context
|
49
|
+
# keystore = KeyStore.getInstance(KeyStore.getDefaultType)
|
50
|
+
# context = SSLContext.getInstance('TLSv1')
|
51
|
+
# tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm)
|
52
|
+
# tmf.init(keystore)
|
53
|
+
# context.init(nil, nil, nil)
|
54
|
+
# context
|
55
|
+
SSLContext.getDefault
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.create_ssl_engine(context, client=false)
|
59
|
+
context.createSSLEngine
|
60
|
+
engine.setUseClientMode(client)
|
50
61
|
engine.setNeedClientAuth(false)
|
51
62
|
engine
|
52
63
|
end
|
data/lib/foxbat/server.rb
CHANGED
@@ -3,12 +3,10 @@ import org.jboss.netty.channel.group.DefaultChannelGroup
|
|
3
3
|
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory
|
4
4
|
import org.jboss.netty.bootstrap.ServerBootstrap
|
5
5
|
require_relative 'pipeline'
|
6
|
-
require_relative 'security'
|
7
6
|
|
8
7
|
module Foxbat
|
9
8
|
|
10
9
|
class Server
|
11
|
-
|
12
10
|
def initialize(host, port, klass, options, &block)
|
13
11
|
if options[:secure]
|
14
12
|
@context = Security.setup_ssl_context(options[:keystore])
|
@@ -16,15 +14,21 @@ module Foxbat
|
|
16
14
|
|
17
15
|
@group = DefaultChannelGroup.new
|
18
16
|
@address = InetSocketAddress.new(host, port)
|
19
|
-
@pipeline = Pipeline.new(klass, @group, options, @context, &block)
|
17
|
+
@pipeline = Pipeline.new(klass, @group, false, options, @context, &block)
|
20
18
|
end
|
21
|
-
|
19
|
+
|
22
20
|
def start(threadpool)
|
23
|
-
|
24
|
-
|
21
|
+
sp = java.util.concurrent.Executors.newSingleThreadExecutor
|
22
|
+
factory = NioServerSocketChannelFactory.new(sp, threadpool)
|
23
|
+
@bootstrap = ServerBootstrap.new(factory)
|
25
24
|
@bootstrap.setPipelineFactory(@pipeline)
|
26
|
-
@
|
27
|
-
@
|
25
|
+
@bootstrap.setOption("child.tcpNoDelay", true)
|
26
|
+
server_channel = @bootstrap.bind(@address)
|
27
|
+
@group.add(server_channel)
|
28
|
+
end
|
29
|
+
|
30
|
+
def connection_count
|
31
|
+
@group.size - 1 # -1 to exclude the server's channel
|
28
32
|
end
|
29
33
|
|
30
34
|
def stop
|
data/lib/foxbat/version.rb
CHANGED
data/lib/foxbat.rb
CHANGED
@@ -1,45 +1,53 @@
|
|
1
1
|
require 'java'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
unless Kernel.respond_to?(:require_relative)
|
4
|
+
module Kernel
|
5
|
+
def require_relative(path)
|
6
|
+
require File.join(File.dirname(caller[0]), path.to_str)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
7
10
|
|
8
|
-
|
9
|
-
|
11
|
+
def require_or_get(lib, version, ns)
|
12
|
+
jar = "#{lib}-#{version}.jar"
|
13
|
+
jarpath = File.dirname(__FILE__) + '/' + jar
|
14
|
+
if !File.exist?(jarpath)
|
15
|
+
puts "Couldn't find #{lib}, let's download it now."
|
10
16
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
f.write(segment)
|
17
|
+
require 'net/http'
|
18
|
+
f = open(jarpath, 'w')
|
19
|
+
|
20
|
+
Net::HTTP.start('search.maven.org') do |http|
|
21
|
+
|
22
|
+
begin
|
23
|
+
http.request_get("/remotecontent?filepath=#{ns}/#{lib}/#{version}/#{jar}") do |resp|
|
24
|
+
puts "Downloading #{jar} from maven repository..."
|
25
|
+
resp.read_body do |segment|
|
26
|
+
f.write(segment)
|
27
|
+
end
|
28
|
+
puts "Done."
|
24
29
|
end
|
25
|
-
|
30
|
+
ensure
|
31
|
+
f.close()
|
26
32
|
end
|
27
|
-
ensure
|
28
|
-
f.close()
|
29
33
|
end
|
30
34
|
end
|
35
|
+
|
36
|
+
require jar
|
31
37
|
end
|
32
38
|
|
33
|
-
|
39
|
+
require_or_get 'netty', '3.5.0.Final', 'io/netty'
|
40
|
+
require_or_get 'guava', '13.0.1', 'com/google/guava'
|
34
41
|
|
35
42
|
require 'em/connection'
|
43
|
+
require 'em/deferrable'
|
36
44
|
require 'em/periodic_timer'
|
37
45
|
require 'em/timer'
|
46
|
+
require 'foxbat/client'
|
38
47
|
require 'foxbat/server'
|
39
48
|
require 'foxbat/version'
|
40
|
-
require_relative 'eventmachine'
|
41
|
-
|
42
49
|
|
50
|
+
require_relative 'eventmachine'
|
43
51
|
|
44
52
|
module EventMachine; end
|
45
53
|
|
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foxbat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-11-12 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: A drop-in replacement for EM, providing functionality missing from the
|
15
15
|
Java port.
|
@@ -22,15 +22,21 @@ files:
|
|
22
22
|
- lib/eventmachine.rb
|
23
23
|
- lib/foxbat/barrier.rb
|
24
24
|
- lib/foxbat/version.rb
|
25
|
+
- lib/foxbat/generic_connection.rb
|
26
|
+
- lib/foxbat/client.rb
|
25
27
|
- lib/foxbat/server.rb
|
28
|
+
- lib/foxbat/http_server.rb
|
26
29
|
- lib/foxbat/pipeline.rb
|
30
|
+
- lib/foxbat/future.rb
|
27
31
|
- lib/foxbat/netty_connection.rb
|
28
32
|
- lib/foxbat/security.rb
|
29
33
|
- lib/netty-3.5.0.Final.jar
|
30
34
|
- lib/foxbat.rb
|
31
35
|
- lib/em/periodic_timer.rb
|
32
36
|
- lib/em/timer.rb
|
37
|
+
- lib/em/deferrable.rb
|
33
38
|
- lib/em/connection.rb
|
39
|
+
- lib/guava-13.0.1.jar
|
34
40
|
homepage: http://github.com/m0wfo/foxbat
|
35
41
|
licenses: []
|
36
42
|
post_install_message:
|