swiftiply 0.6.1.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CONTRIBUTORS +2 -0
- data/README.md +62 -0
- data/bin/{mongrel_rails → evented_mongrel_rails} +6 -14
- data/bin/swiftiplied_mongrel_rails +246 -0
- data/bin/swiftiply +136 -116
- data/bin/swiftiply_mongrel_rails +2 -2
- data/bin/swiftiplyctl +283 -0
- data/cleanup.sh +5 -0
- data/ext/deque/extconf.rb +162 -0
- data/ext/deque/swiftcore/rubymain.cpp +435 -0
- data/ext/fastfilereader/extconf.rb +2 -2
- data/ext/fastfilereader/mapper.cpp +2 -0
- data/ext/map/extconf.rb +161 -0
- data/ext/map/rubymain.cpp +500 -0
- data/ext/splaytree/extconf.rb +161 -0
- data/ext/splaytree/swiftcore/rubymain.cpp +580 -0
- data/ext/splaytree/swiftcore/splay_map.h +635 -0
- data/ext/splaytree/swiftcore/splay_set.h +575 -0
- data/ext/splaytree/swiftcore/splay_tree.h +1127 -0
- data/external/httpclient.rb +231 -0
- data/external/package.rb +13 -13
- data/setup.rb +18 -2
- data/src/swiftcore/Swiftiply.rb +417 -773
- data/src/swiftcore/Swiftiply/backend_protocol.rb +213 -0
- data/src/swiftcore/Swiftiply/cache_base.rb +49 -0
- data/src/swiftcore/Swiftiply/cache_base_mixin.rb +52 -0
- data/src/swiftcore/Swiftiply/cluster_managers/rest_based_cluster_manager.rb +9 -0
- data/src/swiftcore/Swiftiply/cluster_protocol.rb +70 -0
- data/src/swiftcore/Swiftiply/config.rb +370 -0
- data/src/swiftcore/Swiftiply/config/rest_updater.rb +26 -0
- data/src/swiftcore/Swiftiply/constants.rb +101 -0
- data/src/swiftcore/Swiftiply/content_cache_entry.rb +44 -0
- data/src/swiftcore/Swiftiply/content_response.rb +45 -0
- data/src/swiftcore/Swiftiply/control_protocol.rb +49 -0
- data/src/swiftcore/Swiftiply/dynamic_request_cache.rb +41 -0
- data/src/swiftcore/Swiftiply/etag_cache.rb +64 -0
- data/src/swiftcore/Swiftiply/file_cache.rb +46 -0
- data/src/swiftcore/Swiftiply/hash_cache_base.rb +22 -0
- data/src/swiftcore/Swiftiply/http_recognizer.rb +267 -0
- data/src/swiftcore/Swiftiply/loggers/Analogger.rb +21 -0
- data/src/swiftcore/Swiftiply/loggers/stderror.rb +13 -0
- data/src/swiftcore/Swiftiply/mocklog.rb +10 -0
- data/src/swiftcore/Swiftiply/proxy.rb +15 -0
- data/src/swiftcore/Swiftiply/proxy_backends/keepalive.rb +286 -0
- data/src/swiftcore/Swiftiply/proxy_backends/traditional.rb +286 -0
- data/src/swiftcore/Swiftiply/proxy_backends/traditional/redis_directory.rb +87 -0
- data/src/swiftcore/Swiftiply/proxy_backends/traditional/static_directory.rb +69 -0
- data/src/swiftcore/Swiftiply/proxy_bag.rb +716 -0
- data/src/swiftcore/Swiftiply/rest_based_cluster_manager.rb +15 -0
- data/src/swiftcore/Swiftiply/splay_cache_base.rb +21 -0
- data/src/swiftcore/Swiftiply/support_pagecache.rb +6 -3
- data/src/swiftcore/Swiftiply/swiftiply_2_http_proxy.rb +7 -0
- data/src/swiftcore/Swiftiply/swiftiply_client.rb +20 -5
- data/src/swiftcore/Swiftiply/version.rb +5 -0
- data/src/swiftcore/evented_mongrel.rb +26 -8
- data/src/swiftcore/hash.rb +43 -0
- data/src/swiftcore/method_builder.rb +28 -0
- data/src/swiftcore/streamer.rb +46 -0
- data/src/swiftcore/swiftiplied_mongrel.rb +91 -23
- data/src/swiftcore/types.rb +20 -3
- data/swiftiply.gemspec +14 -8
- data/test/TC_Deque.rb +152 -0
- data/test/TC_ProxyBag.rb +147 -166
- data/test/TC_Swiftiply.rb +576 -169
- data/test/TC_Swiftiply/mongrel/evented_hello.rb +1 -1
- data/test/TC_Swiftiply/mongrel/swiftiplied_hello.rb +1 -1
- data/test/TC_Swiftiply/test_serve_static_file_xsendfile/sendfile_client.rb +27 -0
- data/test/TC_Swiftiply/test_ssl/bin/validate_ssl_capability.rb +21 -0
- data/test/TC_Swiftiply/test_ssl/test.cert +16 -0
- data/test/TC_Swiftiply/test_ssl/test.key +15 -0
- data/{bin → test/bin}/echo_client +0 -0
- metadata +136 -94
- data/README +0 -126
- data/ext/swiftiply_parse/parse.rl +0 -90
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 41ffdd88a623bd6b34c2cb105d8e34286a4f226a
|
4
|
+
data.tar.gz: 2fe4a945f3b6008882f52e6e16174fd77603182f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fdbe79598ec795b05ed861a7fe446da09a7c00f510d468f62c2e1473980f964acaaee63c26919509da5fad293de5bc2f19348ccad22e79d58f4b9c5948d8b1ed
|
7
|
+
data.tar.gz: efe8bf53cf9756435a9924cc08eb5b8eef01d4ea5e69b899648be187ed26bfb5dbdbf2fab3edd4daf9702398d4cb74affc5cc0eb7d4df8b63ad20bd4d5d032ed
|
data/CONTRIBUTORS
CHANGED
data/README.md
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# Swiftiply v1.0.0 (http://github.com/wyhaines/swiftiply)
|
2
|
+
|
3
|
+
Swiftiply is a backend agnostic clustering proxy for web applications that is
|
4
|
+
specifically designed to support HTTP traffic from web frameworks. It is a targeted
|
5
|
+
proxy, intended specifically for use in front of web frameworks, and is not a
|
6
|
+
general purpose proxy.
|
7
|
+
|
8
|
+
What it is, though, is a very fast, narrowly targeted clustering proxy, with the
|
9
|
+
current implementation being written in Ruby.
|
10
|
+
|
11
|
+
Swiftiply works differently from a traditional proxy. In Swiftiply, the
|
12
|
+
backend processes are clients of the Swiftiply server -- they make persistent
|
13
|
+
socket connections to Swiftiply. One of the major advantages to this
|
14
|
+
architecture is that it allows one to start or stop backend processes at will,
|
15
|
+
with no configuration of the proxy. The proxy always knows exactly what resources
|
16
|
+
it has available to handle a given request. The obvious disadvantage is that this is
|
17
|
+
not behavior that web applications typically expect.
|
18
|
+
|
19
|
+
Swiftiply was originally written in an era when Mongrel was the preferred deployment
|
20
|
+
method for most Ruby frameworks. Swiftiply includes a version of Mongrel(found in
|
21
|
+
swiftcore/swiftiplied_mongrel.rb) that has been modified to work as a swiftiply client.
|
22
|
+
This should be transparent to any existing Mongrel handlers, allowing them all to with
|
23
|
+
Swiftiply.
|
24
|
+
|
25
|
+
Swiftiply also provides a traditional proxy model, allowing it to be used as a proxy
|
26
|
+
in front of any web application.
|
27
|
+
|
28
|
+
TODO: Provide an implementation of a swiftiply access proxy. This is a Swiftiply
|
29
|
+
TODO: "client" that maintains N connections into Swiftiply, but that operates as
|
30
|
+
TODO: a traditional proxy on the web application facing side. This lets an individual
|
31
|
+
TODO: server modulate the total number of connections that it is willing to handle
|
32
|
+
TODO: simultaneously, while not requiring the applications themselves to know anything
|
33
|
+
TODO: about it.
|
34
|
+
|
35
|
+
CONFIGURATION
|
36
|
+
|
37
|
+
Swiftiply takes a single configuration file which defines for it where it
|
38
|
+
should listen for incoming connections, whether it should daemonize itself,
|
39
|
+
and then provides a map of incoming domain names and the address/port to
|
40
|
+
proxy that traffic to. That outgoing address/port is where the backends for
|
41
|
+
that site will connect to.
|
42
|
+
|
43
|
+
Here's an example:
|
44
|
+
|
45
|
+
cluster_address: swiftcore.org
|
46
|
+
cluster_port: 80
|
47
|
+
daemonize: true
|
48
|
+
map:
|
49
|
+
- incoming:
|
50
|
+
- swiftcore.org
|
51
|
+
- www.swiftcore.org
|
52
|
+
outgoing: 127.0.0.1:30000
|
53
|
+
default: true
|
54
|
+
- incoming: iowa.swiftcore.org
|
55
|
+
outgoing: 127.0.0.1:30010
|
56
|
+
- incoming: analogger.swiftcore.org
|
57
|
+
outgoing: 127.0.0.1:30020
|
58
|
+
- incoming:
|
59
|
+
- swiftiply.com
|
60
|
+
- www.swiftiply.com
|
61
|
+
- swiftiply.swiftcore.org
|
62
|
+
outgoing: 127.0.0.1:30030
|
@@ -1,21 +1,13 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html
|
6
|
-
# for more information.
|
2
|
+
|
3
|
+
# No more mucking with event variables. Run swiftiplied_mongrel_rails to run
|
4
|
+
# a mongrel_rails setup for Swiftiply.
|
7
5
|
|
8
6
|
require 'rubygems'
|
9
7
|
require 'yaml'
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
elsif ENV['SWIFT']
|
14
|
-
require 'swiftcore/swiftiplied_mongrel'
|
15
|
-
puts "Using Evented Mongrel"
|
16
|
-
else
|
17
|
-
require 'mongrel'
|
18
|
-
end
|
8
|
+
|
9
|
+
require 'swiftcore/evented_mongrel'
|
10
|
+
|
19
11
|
require 'mongrel/rails'
|
20
12
|
require 'etc'
|
21
13
|
require 'cgi_multipart_eof_fix' rescue nil
|
@@ -0,0 +1,246 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# No more mucking with event variables. Run swiftiplied_mongrel_rails to run
|
4
|
+
# a mongrel_rails setup for Swiftiply.
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require 'yaml'
|
8
|
+
|
9
|
+
require 'swiftcore/swiftiplied_mongrel'
|
10
|
+
|
11
|
+
require 'mongrel/rails'
|
12
|
+
require 'etc'
|
13
|
+
require 'cgi_multipart_eof_fix' rescue nil
|
14
|
+
|
15
|
+
module Mongrel
|
16
|
+
class Start < GemPlugin::Plugin "/commands"
|
17
|
+
include Mongrel::Command::Base
|
18
|
+
|
19
|
+
def configure
|
20
|
+
options [
|
21
|
+
["-e", "--environment ENV", "Rails environment to run as", :@environment, ENV['RAILS_ENV'] || "development"],
|
22
|
+
["-d", "--daemonize", "Run daemonized in the background", :@daemon, false],
|
23
|
+
['-p', '--port PORT', "Which port to bind to", :@port, 3000],
|
24
|
+
['-a', '--address ADDR', "Address to bind to", :@address, "0.0.0.0"],
|
25
|
+
['-l', '--log FILE', "Where to write log messages", :@log_file, "log/mongrel.log"],
|
26
|
+
['-P', '--pid FILE', "Where to write the PID", :@pid_file, "log/mongrel.pid"],
|
27
|
+
['-n', '--num-procs INT', "Number of processors active before clients denied", :@num_procs, 1024],
|
28
|
+
['-t', '--timeout TIME', "Timeout all requests after 100th seconds time", :@timeout, 0],
|
29
|
+
['-m', '--mime PATH', "A YAML file that lists additional MIME types", :@mime_map, nil],
|
30
|
+
['-c', '--chdir PATH', "Change to dir before starting (will be expanded)", :@cwd, Dir.pwd],
|
31
|
+
['-r', '--root PATH', "Set the document root (default 'public')", :@docroot, "public"],
|
32
|
+
['-B', '--debug', "Enable debugging mode", :@debug, false],
|
33
|
+
['-C', '--config PATH', "Use a config file", :@config_file, nil],
|
34
|
+
['-S', '--script PATH', "Load the given file as an extra config script", :@config_script, nil],
|
35
|
+
['-G', '--generate PATH', "Generate a config file for use with -C", :@generate, nil],
|
36
|
+
['', '--user USER', "User to run as", :@user, nil],
|
37
|
+
['', '--group GROUP', "Group to run as", :@group, nil],
|
38
|
+
['', '--prefix PATH', "URL prefix for Rails app", :@prefix, nil]
|
39
|
+
]
|
40
|
+
end
|
41
|
+
|
42
|
+
def validate
|
43
|
+
@cwd = File.expand_path(@cwd)
|
44
|
+
valid_dir? @cwd, "Invalid path to change to during daemon mode: #@cwd"
|
45
|
+
|
46
|
+
# Change there to start, then we'll have to come back after daemonize
|
47
|
+
Dir.chdir(@cwd)
|
48
|
+
|
49
|
+
valid?(@prefix[0].chr == "/" && @prefix[-1].chr != "/", "Prefix must begin with / and not end in /") if @prefix
|
50
|
+
valid_dir? File.dirname(@log_file), "Path to log file not valid: #@log_file"
|
51
|
+
valid_dir? File.dirname(@pid_file), "Path to pid file not valid: #@pid_file"
|
52
|
+
valid_dir? @docroot, "Path to docroot not valid: #@docroot"
|
53
|
+
valid_exists? @mime_map, "MIME mapping file does not exist: #@mime_map" if @mime_map
|
54
|
+
valid_exists? @config_file, "Config file not there: #@config_file" if @config_file
|
55
|
+
valid_dir? File.dirname(@generate), "Problem accessing directory to #@generate" if @generate
|
56
|
+
valid_user? @user if @user
|
57
|
+
valid_group? @group if @group
|
58
|
+
|
59
|
+
return @valid
|
60
|
+
end
|
61
|
+
|
62
|
+
def run
|
63
|
+
# Config file settings will override command line settings
|
64
|
+
settings = { :host => @address, :port => @port, :cwd => @cwd,
|
65
|
+
:log_file => @log_file, :pid_file => @pid_file, :environment => @environment,
|
66
|
+
:docroot => @docroot, :mime_map => @mime_map, :daemon => @daemon,
|
67
|
+
:debug => @debug, :includes => ["mongrel"], :config_script => @config_script,
|
68
|
+
:num_processors => @num_procs, :timeout => @timeout,
|
69
|
+
:user => @user, :group => @group, :prefix => @prefix, :config_file => @config_file
|
70
|
+
}
|
71
|
+
|
72
|
+
if @generate
|
73
|
+
STDERR.puts "** Writing config to \"#@generate\"."
|
74
|
+
open(@generate, "w") {|f| f.write(settings.to_yaml) }
|
75
|
+
STDERR.puts "** Finished. Run \"mongrel_rails -C #@generate\" to use the config file."
|
76
|
+
exit 0
|
77
|
+
end
|
78
|
+
|
79
|
+
if @config_file
|
80
|
+
settings.merge! YAML.load_file(@config_file)
|
81
|
+
STDERR.puts "** Loading settings from #{@config_file} (they override command line)." unless settings[:daemon]
|
82
|
+
end
|
83
|
+
|
84
|
+
config = Mongrel::Rails::RailsConfigurator.new(settings) do
|
85
|
+
if defaults[:daemon]
|
86
|
+
if File.exist? defaults[:pid_file]
|
87
|
+
log "!!! PID file #{defaults[:pid_file]} already exists. Mongrel could be running already. Check your #{defaults[:log_file]} for errors."
|
88
|
+
log "!!! Exiting with error. You must stop mongrel and clear the .pid before I'll attempt a start."
|
89
|
+
exit 1
|
90
|
+
end
|
91
|
+
|
92
|
+
daemonize
|
93
|
+
log "Daemonized, any open files are closed. Look at #{defaults[:pid_file]} and #{defaults[:log_file]} for info."
|
94
|
+
log "Settings loaded from #{@config_file} (they override command line)." if @config_file
|
95
|
+
end
|
96
|
+
|
97
|
+
log "Starting Mongrel listening at #{defaults[:host]}:#{defaults[:port]}"
|
98
|
+
|
99
|
+
listener do
|
100
|
+
mime = {}
|
101
|
+
if defaults[:mime_map]
|
102
|
+
log "Loading additional MIME types from #{defaults[:mime_map]}"
|
103
|
+
mime = load_mime_map(defaults[:mime_map], mime)
|
104
|
+
end
|
105
|
+
|
106
|
+
if defaults[:debug]
|
107
|
+
log "Installing debugging prefixed filters. Look in log/mongrel_debug for the files."
|
108
|
+
debug "/"
|
109
|
+
end
|
110
|
+
|
111
|
+
log "Starting Rails with #{defaults[:environment]} environment..."
|
112
|
+
log "Mounting Rails at #{defaults[:prefix]}..." if defaults[:prefix]
|
113
|
+
uri defaults[:prefix] || "/", :handler => rails(:mime => mime, :prefix => defaults[:prefix])
|
114
|
+
log "Rails loaded."
|
115
|
+
|
116
|
+
log "Loading any Rails specific GemPlugins"
|
117
|
+
load_plugins
|
118
|
+
|
119
|
+
if defaults[:config_script]
|
120
|
+
log "Loading #{defaults[:config_script]} external config script"
|
121
|
+
run_config(defaults[:config_script])
|
122
|
+
end
|
123
|
+
|
124
|
+
setup_rails_signals
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
config.run
|
129
|
+
config.log "Mongrel available at #{settings[:host]}:#{settings[:port]}"
|
130
|
+
|
131
|
+
if config.defaults[:daemon]
|
132
|
+
config.write_pid_file
|
133
|
+
else
|
134
|
+
config.log "Use CTRL-C to stop."
|
135
|
+
end
|
136
|
+
|
137
|
+
config.join
|
138
|
+
|
139
|
+
if config.needs_restart
|
140
|
+
if RUBY_PLATFORM !~ /mswin/
|
141
|
+
cmd = "ruby #{__FILE__} start #{original_args.join(' ')}"
|
142
|
+
config.log "Restarting with arguments: #{cmd}"
|
143
|
+
config.stop
|
144
|
+
config.remove_pid_file
|
145
|
+
|
146
|
+
if config.defaults[:daemon]
|
147
|
+
system cmd
|
148
|
+
else
|
149
|
+
STDERR.puts "Can't restart unless in daemon mode."
|
150
|
+
exit 1
|
151
|
+
end
|
152
|
+
else
|
153
|
+
config.log "Win32 does not support restarts. Exiting."
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def Mongrel::send_signal(signal, pid_file)
|
160
|
+
pid = open(pid_file).read.to_i
|
161
|
+
print "Sending #{signal} to Mongrel at PID #{pid}..."
|
162
|
+
begin
|
163
|
+
Process.kill(signal, pid)
|
164
|
+
rescue Errno::ESRCH
|
165
|
+
puts "Process does not exist. Not running."
|
166
|
+
end
|
167
|
+
|
168
|
+
puts "Done."
|
169
|
+
end
|
170
|
+
|
171
|
+
|
172
|
+
class Stop < GemPlugin::Plugin "/commands"
|
173
|
+
include Mongrel::Command::Base
|
174
|
+
|
175
|
+
def configure
|
176
|
+
options [
|
177
|
+
['-c', '--chdir PATH', "Change to dir before starting (will be expanded).", :@cwd, "."],
|
178
|
+
['-f', '--force', "Force the shutdown (kill -9).", :@force, false],
|
179
|
+
['-w', '--wait SECONDS', "Wait SECONDS before forcing shutdown", :@wait, "0"],
|
180
|
+
['-P', '--pid FILE', "Where the PID file is located.", :@pid_file, "log/mongrel.pid"]
|
181
|
+
]
|
182
|
+
end
|
183
|
+
|
184
|
+
def validate
|
185
|
+
@cwd = File.expand_path(@cwd)
|
186
|
+
valid_dir? @cwd, "Invalid path to change to during daemon mode: #@cwd"
|
187
|
+
|
188
|
+
Dir.chdir @cwd
|
189
|
+
|
190
|
+
valid_exists? @pid_file, "PID file #@pid_file does not exist. Not running?"
|
191
|
+
return @valid
|
192
|
+
end
|
193
|
+
|
194
|
+
def run
|
195
|
+
if @force
|
196
|
+
@wait.to_i.times do |waiting|
|
197
|
+
exit(0) if not File.exist? @pid_file
|
198
|
+
sleep 1
|
199
|
+
end
|
200
|
+
|
201
|
+
Mongrel::send_signal("KILL", @pid_file) if File.exist? @pid_file
|
202
|
+
else
|
203
|
+
Mongrel::send_signal("TERM", @pid_file)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
|
209
|
+
class Restart < GemPlugin::Plugin "/commands"
|
210
|
+
include Mongrel::Command::Base
|
211
|
+
|
212
|
+
def configure
|
213
|
+
options [
|
214
|
+
['-c', '--chdir PATH', "Change to dir before starting (will be expanded)", :@cwd, '.'],
|
215
|
+
['-s', '--soft', "Do a soft restart rather than a process exit restart", :@soft, false],
|
216
|
+
['-P', '--pid FILE', "Where the PID file is located", :@pid_file, "log/mongrel.pid"]
|
217
|
+
]
|
218
|
+
end
|
219
|
+
|
220
|
+
def validate
|
221
|
+
@cwd = File.expand_path(@cwd)
|
222
|
+
valid_dir? @cwd, "Invalid path to change to during daemon mode: #@cwd"
|
223
|
+
|
224
|
+
Dir.chdir @cwd
|
225
|
+
|
226
|
+
valid_exists? @pid_file, "PID file #@pid_file does not exist. Not running?"
|
227
|
+
return @valid
|
228
|
+
end
|
229
|
+
|
230
|
+
def run
|
231
|
+
if @soft
|
232
|
+
Mongrel::send_signal("HUP", @pid_file)
|
233
|
+
else
|
234
|
+
Mongrel::send_signal("USR2", @pid_file)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
|
241
|
+
GemPlugin::Manager.instance.load "mongrel" => GemPlugin::INCLUDE, "rails" => GemPlugin::EXCLUDE
|
242
|
+
|
243
|
+
|
244
|
+
if not Mongrel::Command::Registry.instance.run ARGV
|
245
|
+
exit 1
|
246
|
+
end
|
data/bin/swiftiply
CHANGED
@@ -4,33 +4,33 @@ require 'optparse'
|
|
4
4
|
require 'yaml'
|
5
5
|
|
6
6
|
begin
|
7
|
-
|
8
|
-
|
7
|
+
load_attempted ||= false
|
8
|
+
require 'swiftcore/Swiftiply'
|
9
9
|
rescue LoadError => e
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
10
|
+
unless load_attempted
|
11
|
+
load_attempted = true
|
12
|
+
require 'rubygems'
|
13
|
+
retry
|
14
|
+
end
|
15
|
+
raise e
|
16
16
|
end
|
17
17
|
|
18
18
|
module Swiftcore
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
19
|
+
class SwiftiplyExec
|
20
|
+
Ccluster_address = 'cluster_address'.freeze
|
21
|
+
Ccluster_port = 'cluster_port'.freeze
|
22
|
+
Cconfig_file = 'config_file'.freeze
|
23
|
+
Cbackend_address = 'backend_address'.freeze
|
24
|
+
Cbackend_port = 'backend_port'.freeze
|
25
|
+
Cmap = 'map'.freeze
|
26
|
+
Cincoming = 'incoming'.freeze
|
27
|
+
Coutgoing = 'outgoing'.freeze
|
28
|
+
Ckeepalive = 'keepalive'.freeze
|
29
|
+
Cdaemonize = 'daemonize'.freeze
|
30
|
+
Curl = 'url'.freeze
|
31
|
+
Chost = 'host'.freeze
|
32
|
+
Cport = 'port'.freeze
|
33
|
+
Ctimeout = 'timeout'.freeze
|
34
34
|
|
35
35
|
#####
|
36
36
|
#
|
@@ -49,101 +49,121 @@ module Swiftcore
|
|
49
49
|
# - 127.0.0.1:8080
|
50
50
|
# - foo.bar.com:8090
|
51
51
|
# url:
|
52
|
-
#
|
53
|
-
#
|
52
|
+
# keepalive:
|
53
|
+
# outgoing:
|
54
54
|
#
|
55
55
|
#####
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
56
|
+
def self.parse_options
|
57
|
+
config = @cliconfig || {}
|
58
|
+
@print = false
|
59
|
+
|
60
|
+
OptionParser.new do |opts|
|
61
|
+
opts.banner = 'Usage: swiftiply.rb [options]'
|
62
|
+
opts.separator ''
|
63
|
+
opts.on('-c','--config CONFFILE',"The configuration file to read.") do |conf|
|
64
|
+
config[Cconfig_file] = conf
|
65
|
+
end
|
66
|
+
opts.on('--cluster-address [ADDRESS]',String,'The hostname/IP address that swiftiply will listen for connections on.') do |address|
|
67
|
+
config[Ccluster_address] = address
|
68
|
+
end
|
69
|
+
opts.on('--cluster-port [PORT]',Integer,'The port that swiftiply will listen for connections on.') do |port|
|
70
|
+
config[Ccluster_port] = port
|
71
|
+
end
|
72
|
+
opts.on('--backend-address [ADDRESS]',String,'The hostname/IP address that swiftiply will listen for backend connections on.') do |address|
|
73
|
+
config[Cbackend_address] = address
|
74
|
+
end
|
75
|
+
opts.on('--backend-port [PORT]',Integer,'The port that swiftiply will listen for backend connections on.') do |port|
|
76
|
+
config[Cbackend_port] = port
|
77
|
+
end
|
78
|
+
opts.on('-d','--daemonize [YN]',[:y,:yes,:n,:no],'Whether swiftiply should put itself into the background.') do |yn|
|
79
|
+
config[Cdaemonize] = yn.to_s =~ /^y/i
|
80
|
+
end
|
81
|
+
opts.on('-t','--timeout [SECONDS]',Integer,'The server unavailable timeout. Defaults to 3 seconds.') do |timeout|
|
82
|
+
config[Ctimeout] = timeout
|
83
|
+
end
|
84
|
+
opts.on('-p','--print-config','Print the full configuration.') do
|
85
|
+
@print = true
|
86
|
+
end
|
87
|
+
opts.on('-v','--version','Show the version number, then exit.') do
|
88
|
+
puts "Swiftiply v. #{Swiftcore::Swiftiply::VERSION}"
|
89
|
+
exit 0
|
90
|
+
end
|
91
|
+
opts.on('-f','--pid PIDFILE',"Path of the pid file to write.") do |pidfile|
|
92
|
+
config['pidfile'] = pidfile
|
93
|
+
end
|
94
|
+
|
95
|
+
end.parse!
|
96
|
+
@cliconfig ||= config
|
97
|
+
|
98
|
+
fileconfig = {}
|
99
|
+
fileconfig = YAML.load(File.open(config['config_file'])) if config['config_file']
|
100
|
+
config = fileconfig.merge(@cliconfig)
|
101
|
+
postprocess_config_load(config)
|
102
|
+
(puts("Configuration failed validation; exiting.") && exit(1)) unless verify_config(config)
|
103
|
+
|
104
|
+
if @print
|
105
|
+
require 'pp'
|
106
|
+
pp config
|
107
|
+
exit 0
|
108
|
+
end
|
109
|
+
|
110
|
+
config
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.daemonize(pidfile = nil)
|
114
|
+
if (child_pid = fork)
|
115
|
+
if pidfile
|
116
|
+
begin
|
117
|
+
File.open(pidfile,"w+") {|fh| fh.puts "#{child_pid}"}
|
118
|
+
rescue Exception => e
|
119
|
+
puts "Failed to write PID file #{pidfile}\n#{e}\n\nPID #{child_pid}"
|
120
|
+
end
|
121
|
+
else
|
122
|
+
puts "PID #{child_pid}"
|
123
|
+
end
|
124
|
+
|
125
|
+
exit! 0
|
126
|
+
end
|
127
|
+
|
128
|
+
Process.setsid
|
129
|
+
|
130
|
+
rescue Exception
|
131
|
+
puts "Platform (#{RUBY_PLATFORM}) does not appear to support fork/setsid; skipping"
|
132
|
+
end
|
133
|
+
|
134
|
+
def self.postprocess_config_load(config)
|
135
|
+
config[Cmap] = [] unless Array === config[Cmap]
|
136
|
+
config[Ctimeout] ||= 3
|
137
|
+
config[Cmap].each do |m|
|
138
|
+
m[Ckeepalive] = true unless m.has_key?(Ckeepalive)
|
139
|
+
m[Ckeepalive] = !!m[Ckeepalive]
|
140
|
+
m[Coutgoing] = [m[Coutgoing]] unless Array === m[Coutgoing]
|
141
|
+
m[Cincoming] = [m[Cincoming]] unless Array === m[Cincoming]
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def self.verify_config(config)
|
146
|
+
return nil if config[Ccluster_address].nil?
|
147
|
+
return nil if config[Ccluster_port].nil?
|
148
|
+
|
149
|
+
if config[Cbackend_address] and config[Cbackend_port]
|
150
|
+
config[Cmap] << {Cincoming => nil, Curl => nil, Coutgoing => "#{config[Cbackend_address]}:#{config[Cbackend_port]}", Ckeepalive => true}
|
151
|
+
end
|
152
|
+
true
|
153
|
+
end
|
154
|
+
|
155
|
+
def self.run
|
156
|
+
config = parse_options
|
157
|
+
daemonize(config['pidfile']) if config[Cdaemonize]
|
158
|
+
Swiftcore::Swiftiply.run(config)
|
159
|
+
end
|
160
|
+
|
161
|
+
def self.on_windows?
|
162
|
+
return @on_windows unless @on_windows.nil?
|
163
|
+
@on_windows = !![/mswin/i, /cygwin/i, /mingw/i, /bccwin/i, /wince/i].find {|p| RUBY_PLATFORM =~ p}
|
164
|
+
end
|
165
|
+
end
|
147
166
|
end
|
148
167
|
|
149
168
|
Swiftcore::SwiftiplyExec.run
|
169
|
+
exit 0
|