jubilee 1.1.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.
- checksums.yaml +7 -0
- data/.ruby-version +1 -0
- data/.travis.yml +5 -0
- data/CHANGELOG +32 -0
- data/Gemfile +35 -0
- data/Gemfile.lock +244 -0
- data/Guardfile +24 -0
- data/KNOWN_ISSUES +6 -0
- data/LICENSE.txt +20 -0
- data/README.md +147 -0
- data/ROADMAP +5 -0
- data/Rakefile +98 -0
- data/bin/jubilee +6 -0
- data/bin/jubilee_d +13 -0
- data/examples/chatapp/Gemfile +5 -0
- data/examples/chatapp/Gemfile.lock +27 -0
- data/examples/chatapp/README.md +17 -0
- data/examples/chatapp/app.rb +57 -0
- data/examples/chatapp/config.ru +3 -0
- data/examples/chatapp/public/assets/javascripts/application.js +67 -0
- data/examples/chatapp/public/assets/javascripts/jquery.js +5 -0
- data/examples/chatapp/public/assets/javascripts/sockjs-0.3.4.min.js +27 -0
- data/examples/chatapp/public/assets/javascripts/vertxbus.js +216 -0
- data/examples/chatapp/public/assets/stylesheets/application.css +29 -0
- data/examples/client/sockjs-0.3.4.min.js +27 -0
- data/examples/client/vertxbus.js +216 -0
- data/examples/jubilee.conf.rb +12 -0
- data/examples/jubilee/keystore.jks +0 -0
- data/examples/jubilee/server-keystore.jks +0 -0
- data/jars/hazelcast-2.6.3.jar +0 -0
- data/jars/jackson-annotations-2.2.2.jar +0 -0
- data/jars/jackson-core-2.2.2.jar +0 -0
- data/jars/jackson-databind-2.2.2.jar +0 -0
- data/jars/netty-all-4.0.13.Final.jar +0 -0
- data/jars/vertx-core-2.1M3-SNAPSHOT.jar +0 -0
- data/jars/vertx-hazelcast-2.1M3-SNAPSHOT.jar +0 -0
- data/java/src/jubilee/JubileeService.java +20 -0
- data/java/src/org/jruby/jubilee/Const.java +32 -0
- data/java/src/org/jruby/jubilee/RackApplication.java +103 -0
- data/java/src/org/jruby/jubilee/RackEnvironment.java +150 -0
- data/java/src/org/jruby/jubilee/RackEnvironmentHash.java +449 -0
- data/java/src/org/jruby/jubilee/RackInput.java +62 -0
- data/java/src/org/jruby/jubilee/RackResponse.java +11 -0
- data/java/src/org/jruby/jubilee/RubyHttpServerResponse.java +88 -0
- data/java/src/org/jruby/jubilee/RubyServer.java +171 -0
- data/java/src/org/jruby/jubilee/deploy/Starter.java +26 -0
- data/java/src/org/jruby/jubilee/impl/RubyIORackInput.java +201 -0
- data/java/src/org/jruby/jubilee/impl/RubyNullIO.java +107 -0
- data/java/src/org/jruby/jubilee/utils/RubyHelper.java +37 -0
- data/java/src/org/jruby/jubilee/vertx/JubileeVertx.java +38 -0
- data/jubilee.gemspec +201 -0
- data/lib/jubilee.rb +17 -0
- data/lib/jubilee/application.rb +13 -0
- data/lib/jubilee/cli.rb +127 -0
- data/lib/jubilee/configuration.rb +177 -0
- data/lib/jubilee/const.rb +40 -0
- data/lib/jubilee/jubilee.jar +0 -0
- data/lib/jubilee/response.rb +69 -0
- data/lib/jubilee/server.rb +12 -0
- data/lib/jubilee/version.rb +10 -0
- data/lib/rack/chunked.rb +38 -0
- data/lib/rack/handler/jubilee.rb +44 -0
- data/lib/vertx.rb +26 -0
- data/lib/vertx/README.md +7 -0
- data/lib/vertx/buffer.rb +251 -0
- data/lib/vertx/event_bus.rb +206 -0
- data/lib/vertx/shared_data.rb +214 -0
- data/spec/apps/rack/basic/config.ru +50 -0
- data/spec/apps/rails4/basic/.gitignore +16 -0
- data/spec/apps/rails4/basic/Gemfile +41 -0
- data/spec/apps/rails4/basic/Gemfile.lock +127 -0
- data/spec/apps/rails4/basic/README.rdoc +28 -0
- data/spec/apps/rails4/basic/Rakefile +6 -0
- data/spec/apps/rails4/basic/app/assets/images/.keep +0 -0
- data/spec/apps/rails4/basic/app/assets/images/rails.png +0 -0
- data/spec/apps/rails4/basic/app/assets/javascripts/application.js +12 -0
- data/spec/apps/rails4/basic/app/assets/stylesheets/application.css +13 -0
- data/spec/apps/rails4/basic/app/controllers/application_controller.rb +5 -0
- data/spec/apps/rails4/basic/app/controllers/concerns/.keep +0 -0
- data/spec/apps/rails4/basic/app/controllers/reloader_controller.rb +11 -0
- data/spec/apps/rails4/basic/app/controllers/reloader_controller.rb.erb +11 -0
- data/spec/apps/rails4/basic/app/controllers/root_controller.rb +14 -0
- data/spec/apps/rails4/basic/app/helpers/application_helper.rb +2 -0
- data/spec/apps/rails4/basic/app/mailers/.keep +0 -0
- data/spec/apps/rails4/basic/app/models/.keep +0 -0
- data/spec/apps/rails4/basic/app/models/concerns/.keep +0 -0
- data/spec/apps/rails4/basic/app/views/layouts/application.html.erb +14 -0
- data/spec/apps/rails4/basic/app/views/reloader/index.html.erb +1 -0
- data/spec/apps/rails4/basic/app/views/root/index.html.erb +8 -0
- data/spec/apps/rails4/basic/app/views/root/streaming.html.erb +6 -0
- data/spec/apps/rails4/basic/bin/bundle +3 -0
- data/spec/apps/rails4/basic/bin/rails +4 -0
- data/spec/apps/rails4/basic/bin/rake +4 -0
- data/spec/apps/rails4/basic/config.ru +4 -0
- data/spec/apps/rails4/basic/config/application.rb +23 -0
- data/spec/apps/rails4/basic/config/boot.rb +4 -0
- data/spec/apps/rails4/basic/config/database.yml +20 -0
- data/spec/apps/rails4/basic/config/environment.rb +5 -0
- data/spec/apps/rails4/basic/config/environments/development.rb +29 -0
- data/spec/apps/rails4/basic/config/environments/production.rb +80 -0
- data/spec/apps/rails4/basic/config/environments/test.rb +36 -0
- data/spec/apps/rails4/basic/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/apps/rails4/basic/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/apps/rails4/basic/config/initializers/inflections.rb +16 -0
- data/spec/apps/rails4/basic/config/initializers/mime_types.rb +5 -0
- data/spec/apps/rails4/basic/config/initializers/secret_token.rb +12 -0
- data/spec/apps/rails4/basic/config/initializers/session_store.rb +2 -0
- data/spec/apps/rails4/basic/config/initializers/wrap_parameters.rb +14 -0
- data/spec/apps/rails4/basic/config/locales/en.yml +23 -0
- data/spec/apps/rails4/basic/config/routes.rb +5 -0
- data/spec/apps/rails4/basic/db/seeds.rb +7 -0
- data/spec/apps/rails4/basic/lib/assets/.keep +0 -0
- data/spec/apps/rails4/basic/lib/tasks/.keep +0 -0
- data/spec/apps/rails4/basic/public/404.html +58 -0
- data/spec/apps/rails4/basic/public/422.html +58 -0
- data/spec/apps/rails4/basic/public/500.html +57 -0
- data/spec/apps/rails4/basic/public/favicon.ico +0 -0
- data/spec/apps/rails4/basic/public/robots.txt +5 -0
- data/spec/apps/rails4/basic/public/some_page.html +7 -0
- data/spec/apps/rails4/basic/test/controllers/.keep +0 -0
- data/spec/apps/rails4/basic/test/fixtures/.keep +0 -0
- data/spec/apps/rails4/basic/test/helpers/.keep +0 -0
- data/spec/apps/rails4/basic/test/integration/.keep +0 -0
- data/spec/apps/rails4/basic/test/mailers/.keep +0 -0
- data/spec/apps/rails4/basic/test/models/.keep +0 -0
- data/spec/apps/rails4/basic/test/test_helper.rb +15 -0
- data/spec/apps/rails4/basic/vendor/assets/javascripts/.keep +0 -0
- data/spec/apps/rails4/basic/vendor/assets/stylesheets/.keep +0 -0
- data/spec/apps/sinatra/basic/Gemfile +4 -0
- data/spec/apps/sinatra/basic/Gemfile.lock +20 -0
- data/spec/apps/sinatra/basic/basic.rb +27 -0
- data/spec/apps/sinatra/basic/config.ru +7 -0
- data/spec/apps/sinatra/basic/public/some_page.html +7 -0
- data/spec/apps/sinatra/basic/views/index.erb +4 -0
- data/spec/apps/sinatra/basic/views/posted.haml +2 -0
- data/spec/apps/sinatra/basic/views/poster.haml +4 -0
- data/spec/apps/sinatra/basic/views/request_mapping.haml +4 -0
- data/spec/integration/basic_rack_spec.rb +89 -0
- data/spec/integration/basic_rails4_spec.rb +64 -0
- data/spec/integration/basic_sinatra_spec.rb +80 -0
- data/spec/spec_helper.rb +13 -0
- data/test/.ruby-version +1 -0
- data/test/config/app.rb +5 -0
- data/test/jubilee/test_cli.rb +11 -0
- data/test/jubilee/test_configuration.rb +31 -0
- data/test/jubilee/test_rack_server.rb +137 -0
- data/test/jubilee/test_response.rb +272 -0
- data/test/jubilee/test_server.rb +72 -0
- data/test/jubilee/test_upload.rb +301 -0
- data/test/sinatra_app/app.rb +31 -0
- data/test/sinatra_app/config.ru +6 -0
- data/test/sinatra_app/public/test.html +10 -0
- data/test/sinatra_app/unicorn.conf.rb +29 -0
- data/test/test_helper.rb +93 -0
- metadata +242 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
package org.jruby.jubilee;
|
|
2
|
+
|
|
3
|
+
import org.jruby.runtime.Block;
|
|
4
|
+
import org.jruby.runtime.ThreadContext;
|
|
5
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @author isaiah
|
|
9
|
+
* @since Nov 26, 2012
|
|
10
|
+
*
|
|
11
|
+
* Specification for Rack input, translated to a Java interface.
|
|
12
|
+
* @author nicksieger
|
|
13
|
+
*/
|
|
14
|
+
public interface RackInput
|
|
15
|
+
{
|
|
16
|
+
/**
|
|
17
|
+
* gets must be called without arguments and return a string, or nil on EOF.
|
|
18
|
+
* @param context it's a JRuby thing
|
|
19
|
+
* @return a string, or nil on EOF
|
|
20
|
+
*/
|
|
21
|
+
IRubyObject gets( ThreadContext context );
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* read behaves like IO#read. Its signature is read([length, [buffer]]). If given,
|
|
25
|
+
* length must be an non-negative Integer (>= 0) or nil, and buffer must be a
|
|
26
|
+
* String and may not be nil. If length is given and not nil, then this method
|
|
27
|
+
* reads at most length bytes from the input stream. If length is not given or
|
|
28
|
+
* nil, then this method reads all data until EOF. When EOF is reached, this
|
|
29
|
+
* method returns nil if length is given and not nil, or "" if length is not
|
|
30
|
+
* given or is nil. If buffer is given, then the read data will be placed into
|
|
31
|
+
* buffer instead of a newly created String object.
|
|
32
|
+
* @param context it's a JRuby thing
|
|
33
|
+
* @param args [length, [buffer]]
|
|
34
|
+
* @return nil if length is given and not nil, or "" if length is not given or nil
|
|
35
|
+
*/
|
|
36
|
+
IRubyObject read( ThreadContext context, IRubyObject[] args );
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* each must be called without arguments and only yield Strings.
|
|
40
|
+
* @param context it's a JRuby thing
|
|
41
|
+
* @param block that receives yield of Strings
|
|
42
|
+
* @return pretty much nil
|
|
43
|
+
*/
|
|
44
|
+
public IRubyObject each( ThreadContext context, Block block );
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* rewind must be called without arguments. It rewinds the input stream back
|
|
48
|
+
* to the beginning. It must not raise Errno::ESPIPE: that is, it may not be
|
|
49
|
+
* a pipe or a socket. Therefore, handler developers must buffer the input
|
|
50
|
+
* data into some rewindable object if the underlying input stream is not rewindable.
|
|
51
|
+
* @param context it's a JRuby thing
|
|
52
|
+
* @return pretty much nil
|
|
53
|
+
*/
|
|
54
|
+
public IRubyObject rewind( ThreadContext context );
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Close the input. Exposed only to the Java side because the Rack spec says
|
|
58
|
+
* that application code must not call close, so we don't expose a close method to Ruby.
|
|
59
|
+
*/
|
|
60
|
+
public IRubyObject close(ThreadContext context);
|
|
61
|
+
}
|
|
62
|
+
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
package org.jruby.jubilee;
|
|
2
|
+
|
|
3
|
+
import org.jruby.*;
|
|
4
|
+
import org.jruby.anno.JRubyClass;
|
|
5
|
+
import org.jruby.anno.JRubyMethod;
|
|
6
|
+
import org.jruby.runtime.ObjectAllocator;
|
|
7
|
+
import org.jruby.runtime.ThreadContext;
|
|
8
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
|
9
|
+
import org.vertx.java.core.http.HttpServerResponse;
|
|
10
|
+
|
|
11
|
+
import java.util.Arrays;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Created by isaiah on 21/12/2013.
|
|
15
|
+
*/
|
|
16
|
+
@JRubyClass(name = "HttpServerResponse")
|
|
17
|
+
public class RubyHttpServerResponse extends RubyObject {
|
|
18
|
+
private HttpServerResponse resp;
|
|
19
|
+
private String lineSeparator;
|
|
20
|
+
|
|
21
|
+
public static RubyClass createHttpServerResponseClass(final Ruby runtime) {
|
|
22
|
+
RubyModule mJubilee = runtime.getOrCreateModule("Jubilee");
|
|
23
|
+
RubyClass klazz = mJubilee.defineClassUnder("HttpServerResponse", runtime.getObject(), new ObjectAllocator() {
|
|
24
|
+
@Override
|
|
25
|
+
public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
|
|
26
|
+
return new RubyHttpServerResponse(ruby, rubyClass);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
klazz.defineAnnotatedMethods(RubyHttpServerResponse.class);
|
|
30
|
+
return klazz;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public RubyHttpServerResponse(Ruby ruby, RubyClass rubyClass) {
|
|
34
|
+
super(ruby, rubyClass);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public RubyHttpServerResponse(Ruby ruby, RubyClass rubyClass, HttpServerResponse resp) {
|
|
38
|
+
super(ruby, rubyClass);
|
|
39
|
+
this.resp = resp;
|
|
40
|
+
this.lineSeparator = System.getProperty("line.separator");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@JRubyMethod
|
|
44
|
+
public IRubyObject write(ThreadContext context, IRubyObject string) {
|
|
45
|
+
this.resp.write(string.asJavaString());
|
|
46
|
+
return context.runtime.getNil();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@JRubyMethod(name = "status_code=")
|
|
50
|
+
public IRubyObject setStatusCode(ThreadContext context, IRubyObject statusCode) {
|
|
51
|
+
this.resp.setStatusCode(RubyNumeric.num2int(statusCode));
|
|
52
|
+
return context.runtime.getNil();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@JRubyMethod(name = "chunked=")
|
|
56
|
+
public IRubyObject setChunked(ThreadContext context, IRubyObject chunked) {
|
|
57
|
+
this.resp.setChunked(chunked.isTrue());
|
|
58
|
+
return context.runtime.getNil();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@JRubyMethod(name = "put_header")
|
|
62
|
+
public IRubyObject putHeader(ThreadContext context, IRubyObject key, IRubyObject val) {
|
|
63
|
+
String cookie = val.asJavaString();
|
|
64
|
+
if (cookie.indexOf(this.lineSeparator) != -1)
|
|
65
|
+
this.resp.putHeader(key.asJavaString(),
|
|
66
|
+
Arrays.asList(val.asJavaString().split(this.lineSeparator)));
|
|
67
|
+
else this.resp.putHeader(key.asJavaString(), val.asJavaString());
|
|
68
|
+
return context.runtime.getNil();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@JRubyMethod(name = "send_file")
|
|
72
|
+
public IRubyObject sendFile(ThreadContext context, IRubyObject filePath) {
|
|
73
|
+
this.resp.sendFile(filePath.asJavaString());
|
|
74
|
+
return context.runtime.getNil();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@JRubyMethod
|
|
78
|
+
public IRubyObject end(ThreadContext context) {
|
|
79
|
+
this.resp.end();
|
|
80
|
+
return context.runtime.getNil();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@JRubyMethod(name = "put_default_headers")
|
|
84
|
+
public IRubyObject putDefaultHeaders(ThreadContext context) {
|
|
85
|
+
this.resp.putHeader("Server", Const.JUBILEE_VERSION);
|
|
86
|
+
return context.runtime.getNil();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
package org.jruby.jubilee;
|
|
2
|
+
|
|
3
|
+
import org.jruby.*;
|
|
4
|
+
import org.jruby.anno.JRubyMethod;
|
|
5
|
+
import org.jruby.jubilee.vertx.JubileeVertx;
|
|
6
|
+
import org.jruby.runtime.Block;
|
|
7
|
+
import org.jruby.runtime.ObjectAllocator;
|
|
8
|
+
import org.jruby.runtime.ThreadContext;
|
|
9
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
|
10
|
+
import org.vertx.java.core.Handler;
|
|
11
|
+
import org.vertx.java.core.Vertx;
|
|
12
|
+
import org.vertx.java.core.http.HttpServer;
|
|
13
|
+
import org.vertx.java.core.http.HttpServerRequest;
|
|
14
|
+
import org.vertx.java.core.json.JsonArray;
|
|
15
|
+
import org.vertx.java.core.json.JsonObject;
|
|
16
|
+
|
|
17
|
+
import java.io.IOException;
|
|
18
|
+
|
|
19
|
+
public class RubyServer extends RubyObject {
|
|
20
|
+
private Vertx vertx;
|
|
21
|
+
private HttpServer httpServer;
|
|
22
|
+
private RackApplication app;
|
|
23
|
+
private boolean running = false;
|
|
24
|
+
private boolean ssl = false;
|
|
25
|
+
private String keyStorePath;
|
|
26
|
+
private String keyStorePassword;
|
|
27
|
+
private String eventBusPrefix;
|
|
28
|
+
private int port;
|
|
29
|
+
private String host;
|
|
30
|
+
private int clusterPort;
|
|
31
|
+
private String clusterHost;
|
|
32
|
+
|
|
33
|
+
public static void createServerClass(Ruby runtime) {
|
|
34
|
+
RubyModule mJubilee = runtime.defineModule("Jubilee");
|
|
35
|
+
RubyClass serverClass = mJubilee.defineClassUnder("VertxServer", runtime.getObject(), ALLOCATOR);
|
|
36
|
+
serverClass.defineAnnotatedMethods(RubyServer.class);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
|
|
40
|
+
public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
|
|
41
|
+
return new RubyServer(ruby, rubyClass);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
public RubyServer(Ruby ruby, RubyClass rubyClass) {
|
|
46
|
+
super(ruby, rubyClass);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Initialize jubilee server, take a rack application and a configuration hash as parameter
|
|
51
|
+
*
|
|
52
|
+
* @param context
|
|
53
|
+
* @param app
|
|
54
|
+
* @param config
|
|
55
|
+
* @param block
|
|
56
|
+
* @return
|
|
57
|
+
*/
|
|
58
|
+
@JRubyMethod(name = "initialize")
|
|
59
|
+
public IRubyObject initialize(ThreadContext context, IRubyObject app, IRubyObject config, Block block) {
|
|
60
|
+
Ruby runtime = getRuntime();
|
|
61
|
+
/* configuration keys */
|
|
62
|
+
RubyHash options = config.convertToHash();
|
|
63
|
+
RubySymbol port_k = runtime.newSymbol("Port");
|
|
64
|
+
RubySymbol host_k = runtime.newSymbol("Host");
|
|
65
|
+
RubySymbol cluster_port_k = runtime.newSymbol("cluster_port");
|
|
66
|
+
RubySymbol cluster_host_k = runtime.newSymbol("cluster_host");
|
|
67
|
+
RubySymbol ssl_k = runtime.newSymbol("ssl");
|
|
68
|
+
RubySymbol keystore_path_k = runtime.newSymbol("keystore_path");
|
|
69
|
+
RubySymbol keystore_password_k = runtime.newSymbol("keystore_password");
|
|
70
|
+
RubySymbol eventbus_prefix_k = runtime.newSymbol("eventbus_prefix");
|
|
71
|
+
|
|
72
|
+
/* retrieve from passed in options */
|
|
73
|
+
this.port = Integer.parseInt(options.op_aref(context, port_k).toString());
|
|
74
|
+
this.host = options.op_aref(context, host_k).toString();
|
|
75
|
+
|
|
76
|
+
this.ssl = options.op_aref(context, ssl_k).isTrue();
|
|
77
|
+
if (options.has_key_p(keystore_path_k).isTrue()) {
|
|
78
|
+
this.keyStorePath = options.op_aref(context, keystore_path_k).toString();
|
|
79
|
+
this.keyStorePassword = options.op_aref(context, keystore_password_k).toString();
|
|
80
|
+
}
|
|
81
|
+
if (options.has_key_p(eventbus_prefix_k).isTrue())
|
|
82
|
+
this.eventBusPrefix = options.op_aref(context, eventbus_prefix_k).toString();
|
|
83
|
+
|
|
84
|
+
/* init vertx */
|
|
85
|
+
if (options.has_key_p(cluster_host_k).isTrue()) {
|
|
86
|
+
this.clusterHost = options.op_aref(context, cluster_host_k).toString();
|
|
87
|
+
if (options.has_key_p(cluster_port_k).isTrue()) {
|
|
88
|
+
this.clusterPort = Integer.parseInt(options.op_aref(context, cluster_port_k).toString());
|
|
89
|
+
this.vertx = JubileeVertx.init(clusterPort, clusterHost);
|
|
90
|
+
}
|
|
91
|
+
this.vertx = JubileeVertx.init(clusterHost);
|
|
92
|
+
} else {
|
|
93
|
+
this.vertx = JubileeVertx.init();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
httpServer = vertx.createHttpServer();
|
|
97
|
+
try {
|
|
98
|
+
this.app = new RackApplication(vertx, context, app, this.ssl);
|
|
99
|
+
if (block.isGiven()) block.yieldSpecific(context, this);
|
|
100
|
+
} catch (IOException e) {
|
|
101
|
+
// noop
|
|
102
|
+
}
|
|
103
|
+
return this;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Start http server, initialize states
|
|
108
|
+
*
|
|
109
|
+
* @param context
|
|
110
|
+
* @param block
|
|
111
|
+
* @return
|
|
112
|
+
*/
|
|
113
|
+
@JRubyMethod(name = "start")
|
|
114
|
+
public IRubyObject start(final ThreadContext context, final Block block) {
|
|
115
|
+
httpServer.setAcceptBacklog(10000);
|
|
116
|
+
httpServer.requestHandler(new Handler<HttpServerRequest>() {
|
|
117
|
+
public void handle(final HttpServerRequest req) {
|
|
118
|
+
app.call(req);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
if (eventBusPrefix != null) {
|
|
122
|
+
JsonObject config = new JsonObject().putString("prefix", eventBusPrefix);
|
|
123
|
+
JsonArray allowAll = new JsonArray();
|
|
124
|
+
allowAll.add(new JsonObject());
|
|
125
|
+
// TODO read inbounds and outbounds from config file
|
|
126
|
+
vertx.createSockJSServer(httpServer).bridge(config, allowAll, allowAll);
|
|
127
|
+
}
|
|
128
|
+
if (ssl) httpServer.setSSL(true).setKeyStorePath(this.keyStorePath)
|
|
129
|
+
.setKeyStorePassword(this.keyStorePassword);
|
|
130
|
+
httpServer.listen(this.port, this.host);
|
|
131
|
+
this.running = true;
|
|
132
|
+
if (block.isGiven()) block.yieldSpecific(context, this);
|
|
133
|
+
return this;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Set timeout for keep alive connection
|
|
138
|
+
*
|
|
139
|
+
* @param context
|
|
140
|
+
* @param timeout (in TimeUnit.SECONDS)
|
|
141
|
+
* @return this
|
|
142
|
+
*/
|
|
143
|
+
@JRubyMethod(name = "persistent_timeout=")
|
|
144
|
+
public IRubyObject setPersistentTimeout(final ThreadContext context, final IRubyObject timeout) {
|
|
145
|
+
// FIXME
|
|
146
|
+
//httpServer.setPersistentTimeout(RubyInteger.fix2long(timeout) * 1000);
|
|
147
|
+
return this;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Stop the HttpServer
|
|
152
|
+
*
|
|
153
|
+
* @param context
|
|
154
|
+
* @param args if shutdown abruptly
|
|
155
|
+
* @param block callback on close
|
|
156
|
+
* @return
|
|
157
|
+
*/
|
|
158
|
+
@JRubyMethod(name = {"stop", "close"}, optional = 1)
|
|
159
|
+
public IRubyObject close(ThreadContext context, IRubyObject[] args, Block block) {
|
|
160
|
+
if (running) {
|
|
161
|
+
this.running = false;
|
|
162
|
+
httpServer.close();
|
|
163
|
+
// DO I need to stop?
|
|
164
|
+
//vertx.stop();
|
|
165
|
+
if (block.isGiven()) block.yieldSpecific(context);
|
|
166
|
+
} else {
|
|
167
|
+
getRuntime().getOutputStream().println("jubilee server not running?");
|
|
168
|
+
}
|
|
169
|
+
return getRuntime().getNil();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
package org.jruby.jubilee.deploy;
|
|
2
|
+
|
|
3
|
+
import java.util.concurrent.CountDownLatch;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Created with IntelliJ IDEA.
|
|
7
|
+
* User: isaiah
|
|
8
|
+
* Date: 12/3/12
|
|
9
|
+
* Time: 7:37 PM
|
|
10
|
+
*/
|
|
11
|
+
public class Starter {
|
|
12
|
+
private CountDownLatch stopLatch = new CountDownLatch(1);
|
|
13
|
+
|
|
14
|
+
public void block() {
|
|
15
|
+
while(true) {
|
|
16
|
+
try {
|
|
17
|
+
stopLatch.await();
|
|
18
|
+
break;
|
|
19
|
+
} catch (InterruptedException ignore) {}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public void unblock() {
|
|
24
|
+
stopLatch.countDown();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
package org.jruby.jubilee.impl;
|
|
2
|
+
|
|
3
|
+
import io.netty.buffer.ByteBuf;
|
|
4
|
+
import org.jcodings.specific.ASCIIEncoding;
|
|
5
|
+
import org.jcodings.Encoding;
|
|
6
|
+
import org.jruby.*;
|
|
7
|
+
import org.jruby.anno.JRubyMethod;
|
|
8
|
+
import org.jruby.jubilee.Const;
|
|
9
|
+
import org.jruby.jubilee.RackInput;
|
|
10
|
+
import org.jruby.runtime.Block;
|
|
11
|
+
import org.jruby.runtime.ObjectAllocator;
|
|
12
|
+
import org.jruby.runtime.ThreadContext;
|
|
13
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
|
14
|
+
import org.jruby.util.ByteList;
|
|
15
|
+
import org.jruby.util.StringSupport;
|
|
16
|
+
import org.vertx.java.core.http.HttpServerRequest;
|
|
17
|
+
|
|
18
|
+
import java.util.concurrent.atomic.AtomicBoolean;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Created with IntelliJ IDEA.
|
|
22
|
+
* User: isaiah
|
|
23
|
+
* Date: 11/26/12
|
|
24
|
+
* Time: 10:12 PM
|
|
25
|
+
*/
|
|
26
|
+
public class RubyIORackInput extends RubyObject implements RackInput {
|
|
27
|
+
private Encoding BINARY = ASCIIEncoding.INSTANCE;
|
|
28
|
+
private int len;
|
|
29
|
+
private boolean chunked;
|
|
30
|
+
private ByteBuf buf;
|
|
31
|
+
private AtomicBoolean eof;
|
|
32
|
+
|
|
33
|
+
public static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
|
|
34
|
+
@Override
|
|
35
|
+
public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
|
|
36
|
+
return new RubyIORackInput(ruby, rubyClass);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
public static RubyClass createIORackInputClass(Ruby runtime) {
|
|
41
|
+
RubyModule jModule = runtime.getOrCreateModule("Jubilee");
|
|
42
|
+
RubyClass rackIOInputClass = jModule.defineClassUnder("IORackInput", runtime.getObject(), ALLOCATOR);
|
|
43
|
+
rackIOInputClass.defineAnnotatedMethods(RubyIORackInput.class);
|
|
44
|
+
return rackIOInputClass;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public RubyIORackInput(Ruby runtime, RubyClass metaClass) {
|
|
48
|
+
super(runtime, metaClass);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public RubyIORackInput(Ruby runtime, RubyClass rubyClass, HttpServerRequest request, ByteBuf buf, AtomicBoolean eof) {
|
|
52
|
+
this(runtime, rubyClass);
|
|
53
|
+
String hdr = request.headers().get(Const.Vertx.CONTENT_LENGTH);
|
|
54
|
+
this.chunked = hdr == null;
|
|
55
|
+
this.len = this.chunked ? 0 : Integer.parseInt(hdr);
|
|
56
|
+
this.buf = buf;
|
|
57
|
+
this.eof = eof;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* gets must be called without arguments and return a string, or nil on EOF.
|
|
62
|
+
* <p/>
|
|
63
|
+
* this method return one line a time.
|
|
64
|
+
*
|
|
65
|
+
* @param context it's a JRuby thing
|
|
66
|
+
* @return a string, or nil on EOF
|
|
67
|
+
*/
|
|
68
|
+
@Override
|
|
69
|
+
@JRubyMethod
|
|
70
|
+
public IRubyObject gets(ThreadContext context) {
|
|
71
|
+
Ruby runtime = context.runtime;
|
|
72
|
+
RubyString line = RubyString.newEmptyString(context.runtime, BINARY);
|
|
73
|
+
|
|
74
|
+
if (isEOF()) return runtime.getNil();
|
|
75
|
+
|
|
76
|
+
int lineEnd = -1;
|
|
77
|
+
while (lineEnd == -1 && !eof.get()) {
|
|
78
|
+
lineEnd = buf.indexOf(buf.readerIndex(), buf.writerIndex(), Const.EOL);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// No line break found, read all
|
|
82
|
+
if (lineEnd == -1)
|
|
83
|
+
return readAll(runtime, line);
|
|
84
|
+
|
|
85
|
+
int readLength = lineEnd - buf.readerIndex();
|
|
86
|
+
byte[] dst = new byte[readLength + 1];
|
|
87
|
+
buf.readBytes(dst);
|
|
88
|
+
return line.cat(dst);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* read behaves like IO#read. Its signature is read([length, [buffer]]). If given,
|
|
93
|
+
* length must be an non-negative Integer (>= 0) or nil, and buffer must be a
|
|
94
|
+
* String and may not be nil. If length is given and not nil, then this method
|
|
95
|
+
* reads at most length bytes from the input stream. If length is not given or
|
|
96
|
+
* nil, then this method reads all data until EOF. When EOF is reached, this
|
|
97
|
+
* method returns nil if length is given and not nil, or "" if) length is not
|
|
98
|
+
* given or is nil. If buffer is given, then the read data will be placed into
|
|
99
|
+
* buffer instead of a newly created String object.
|
|
100
|
+
*
|
|
101
|
+
* @param context it's a JRuby thing
|
|
102
|
+
* @param args [length, [buffer]]
|
|
103
|
+
* @return nil if length is given and not nil, or "" if length is not given or nil
|
|
104
|
+
*/
|
|
105
|
+
@Override
|
|
106
|
+
@JRubyMethod(optional = 2)
|
|
107
|
+
public IRubyObject read(ThreadContext context, IRubyObject[] args) {
|
|
108
|
+
Ruby runtime = context.runtime;
|
|
109
|
+
RubyString dst = RubyString.newStringNoCopy(context.runtime, new ByteList(), BINARY, StringSupport.CR_VALID);
|
|
110
|
+
if (isEOF())
|
|
111
|
+
return runtime.getNil();
|
|
112
|
+
int length;
|
|
113
|
+
switch (args.length) {
|
|
114
|
+
case 0:
|
|
115
|
+
return readAll(runtime, dst);
|
|
116
|
+
case 1:
|
|
117
|
+
length = RubyNumeric.num2int(args[0]);
|
|
118
|
+
break;
|
|
119
|
+
default:
|
|
120
|
+
length = RubyNumeric.num2int(args[0]);
|
|
121
|
+
dst = (RubyString) args[1];
|
|
122
|
+
}
|
|
123
|
+
if (length < 0)
|
|
124
|
+
runtime.newArgumentError("Negative length " + length + " given");
|
|
125
|
+
byte[] buffer = new byte[length];
|
|
126
|
+
int toRead = length;
|
|
127
|
+
while (toRead > 0 && !isEOF()) {
|
|
128
|
+
int len = Math.min(toRead, readableBytes());
|
|
129
|
+
buf.readBytes(buffer, length - toRead, len);
|
|
130
|
+
toRead = toRead - len;
|
|
131
|
+
}
|
|
132
|
+
if (toRead > 0) length -= toRead;
|
|
133
|
+
return dst.cat(buffer, 0, length);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* each must be called without arguments and only yield Strings.
|
|
138
|
+
*
|
|
139
|
+
* @param context it's a JRuby thing
|
|
140
|
+
* @param block that receives yield of Strings
|
|
141
|
+
* @return pretty much nil
|
|
142
|
+
*/
|
|
143
|
+
@Override
|
|
144
|
+
@JRubyMethod
|
|
145
|
+
public IRubyObject each(ThreadContext context, Block block) {
|
|
146
|
+
IRubyObject str;
|
|
147
|
+
while (!(str = gets(context)).isNil()) {
|
|
148
|
+
block.yield(context, str);
|
|
149
|
+
}
|
|
150
|
+
return context.runtime.getNil();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* rewind must be called without arguments. It rewinds the input stream back
|
|
155
|
+
* to the beginning. It must not raise Errno::ESPIPE: that is, it may not be
|
|
156
|
+
* a pipe or a socket. Therefore, handler developers must buffer the input
|
|
157
|
+
* data into some rewindable object if the underlying input stream is not rewindable.
|
|
158
|
+
*
|
|
159
|
+
* @param context it's a JRuby thing
|
|
160
|
+
* @return pretty much nil
|
|
161
|
+
*/
|
|
162
|
+
@Override
|
|
163
|
+
@JRubyMethod
|
|
164
|
+
public IRubyObject rewind(ThreadContext context) {
|
|
165
|
+
buf.readerIndex(0);
|
|
166
|
+
return context.runtime.getNil();
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Close the input. Exposed only to the Java side because the Rack spec says
|
|
171
|
+
* that application code must not call close, so we don't expose a close method to Ruby.
|
|
172
|
+
*/
|
|
173
|
+
@JRubyMethod
|
|
174
|
+
public IRubyObject close(ThreadContext context) {
|
|
175
|
+
buf.clear();
|
|
176
|
+
return context.runtime.getNil();
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
private int readableBytes() {
|
|
180
|
+
if (! this.chunked) {
|
|
181
|
+
return Math.min(buf.readableBytes(), this.len - buf.readerIndex());
|
|
182
|
+
}
|
|
183
|
+
return buf.readableBytes();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
private boolean isEOF() {
|
|
187
|
+
while (buf.readableBytes() == 0 && !eof.get())
|
|
188
|
+
; // wait while there is nothing to read
|
|
189
|
+
return buf.readableBytes() == 0 && eof.get();
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
private IRubyObject readAll(Ruby runtime, RubyString dst) {
|
|
193
|
+
while(!eof.get())
|
|
194
|
+
; // wait until all data received
|
|
195
|
+
int length = this.chunked ? buf.readableBytes() : Math.min(this.len, buf.readableBytes());
|
|
196
|
+
byte[] data = new byte[length];
|
|
197
|
+
buf.readBytes(data);
|
|
198
|
+
dst.cat(data);
|
|
199
|
+
return dst.isEmpty() ? runtime.getNil() : dst;
|
|
200
|
+
}
|
|
201
|
+
}
|