swiftiply 0.6.1.1 → 1.0.0

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 (75) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTORS +2 -0
  3. data/README.md +62 -0
  4. data/bin/{mongrel_rails → evented_mongrel_rails} +6 -14
  5. data/bin/swiftiplied_mongrel_rails +246 -0
  6. data/bin/swiftiply +136 -116
  7. data/bin/swiftiply_mongrel_rails +2 -2
  8. data/bin/swiftiplyctl +283 -0
  9. data/cleanup.sh +5 -0
  10. data/ext/deque/extconf.rb +162 -0
  11. data/ext/deque/swiftcore/rubymain.cpp +435 -0
  12. data/ext/fastfilereader/extconf.rb +2 -2
  13. data/ext/fastfilereader/mapper.cpp +2 -0
  14. data/ext/map/extconf.rb +161 -0
  15. data/ext/map/rubymain.cpp +500 -0
  16. data/ext/splaytree/extconf.rb +161 -0
  17. data/ext/splaytree/swiftcore/rubymain.cpp +580 -0
  18. data/ext/splaytree/swiftcore/splay_map.h +635 -0
  19. data/ext/splaytree/swiftcore/splay_set.h +575 -0
  20. data/ext/splaytree/swiftcore/splay_tree.h +1127 -0
  21. data/external/httpclient.rb +231 -0
  22. data/external/package.rb +13 -13
  23. data/setup.rb +18 -2
  24. data/src/swiftcore/Swiftiply.rb +417 -773
  25. data/src/swiftcore/Swiftiply/backend_protocol.rb +213 -0
  26. data/src/swiftcore/Swiftiply/cache_base.rb +49 -0
  27. data/src/swiftcore/Swiftiply/cache_base_mixin.rb +52 -0
  28. data/src/swiftcore/Swiftiply/cluster_managers/rest_based_cluster_manager.rb +9 -0
  29. data/src/swiftcore/Swiftiply/cluster_protocol.rb +70 -0
  30. data/src/swiftcore/Swiftiply/config.rb +370 -0
  31. data/src/swiftcore/Swiftiply/config/rest_updater.rb +26 -0
  32. data/src/swiftcore/Swiftiply/constants.rb +101 -0
  33. data/src/swiftcore/Swiftiply/content_cache_entry.rb +44 -0
  34. data/src/swiftcore/Swiftiply/content_response.rb +45 -0
  35. data/src/swiftcore/Swiftiply/control_protocol.rb +49 -0
  36. data/src/swiftcore/Swiftiply/dynamic_request_cache.rb +41 -0
  37. data/src/swiftcore/Swiftiply/etag_cache.rb +64 -0
  38. data/src/swiftcore/Swiftiply/file_cache.rb +46 -0
  39. data/src/swiftcore/Swiftiply/hash_cache_base.rb +22 -0
  40. data/src/swiftcore/Swiftiply/http_recognizer.rb +267 -0
  41. data/src/swiftcore/Swiftiply/loggers/Analogger.rb +21 -0
  42. data/src/swiftcore/Swiftiply/loggers/stderror.rb +13 -0
  43. data/src/swiftcore/Swiftiply/mocklog.rb +10 -0
  44. data/src/swiftcore/Swiftiply/proxy.rb +15 -0
  45. data/src/swiftcore/Swiftiply/proxy_backends/keepalive.rb +286 -0
  46. data/src/swiftcore/Swiftiply/proxy_backends/traditional.rb +286 -0
  47. data/src/swiftcore/Swiftiply/proxy_backends/traditional/redis_directory.rb +87 -0
  48. data/src/swiftcore/Swiftiply/proxy_backends/traditional/static_directory.rb +69 -0
  49. data/src/swiftcore/Swiftiply/proxy_bag.rb +716 -0
  50. data/src/swiftcore/Swiftiply/rest_based_cluster_manager.rb +15 -0
  51. data/src/swiftcore/Swiftiply/splay_cache_base.rb +21 -0
  52. data/src/swiftcore/Swiftiply/support_pagecache.rb +6 -3
  53. data/src/swiftcore/Swiftiply/swiftiply_2_http_proxy.rb +7 -0
  54. data/src/swiftcore/Swiftiply/swiftiply_client.rb +20 -5
  55. data/src/swiftcore/Swiftiply/version.rb +5 -0
  56. data/src/swiftcore/evented_mongrel.rb +26 -8
  57. data/src/swiftcore/hash.rb +43 -0
  58. data/src/swiftcore/method_builder.rb +28 -0
  59. data/src/swiftcore/streamer.rb +46 -0
  60. data/src/swiftcore/swiftiplied_mongrel.rb +91 -23
  61. data/src/swiftcore/types.rb +20 -3
  62. data/swiftiply.gemspec +14 -8
  63. data/test/TC_Deque.rb +152 -0
  64. data/test/TC_ProxyBag.rb +147 -166
  65. data/test/TC_Swiftiply.rb +576 -169
  66. data/test/TC_Swiftiply/mongrel/evented_hello.rb +1 -1
  67. data/test/TC_Swiftiply/mongrel/swiftiplied_hello.rb +1 -1
  68. data/test/TC_Swiftiply/test_serve_static_file_xsendfile/sendfile_client.rb +27 -0
  69. data/test/TC_Swiftiply/test_ssl/bin/validate_ssl_capability.rb +21 -0
  70. data/test/TC_Swiftiply/test_ssl/test.cert +16 -0
  71. data/test/TC_Swiftiply/test_ssl/test.key +15 -0
  72. data/{bin → test/bin}/echo_client +0 -0
  73. metadata +136 -94
  74. data/README +0 -126
  75. 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
@@ -4,3 +4,5 @@ The fastfilereader extension was contributed by Francis Cianfrocca.
4
4
 
5
5
  Ezra Zygmuntowicz contributed swiftiply_mongrel_rails and edits to
6
6
  mongrel_rails.
7
+
8
+ Flip Sasser contributed the original version of the swiftiplyctl.
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
- # Copyright (c) 2005 Zed A. Shaw
3
- # You can redistribute it and/or modify it under the same terms as Ruby.
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
- if ENV['EVENT']
11
- require 'swiftcore/evented_mongrel'
12
- puts "Using Evented Mongrel"
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
- load_attempted ||= false
8
- require 'swiftcore/Swiftiply'
7
+ load_attempted ||= false
8
+ require 'swiftcore/Swiftiply'
9
9
  rescue LoadError => e
10
- unless load_attempted
11
- load_attempted = true
12
- require 'rubygems'
13
- retry
14
- end
15
- raise e
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
- 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
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
- # keepalive:
53
- # outgoing:
52
+ # keepalive:
53
+ # outgoing:
54
54
  #
55
55
  #####
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
-
88
- end.parse!
89
- @cliconfig ||= config
90
-
91
- fileconfig = {}
92
- fileconfig = YAML.load(File.open(config['config_file'])) if config['config_file']
93
- config = fileconfig.merge(@cliconfig)
94
- postprocess_config_load(config)
95
- puts("Configuration failed validation; exiting.") && exit unless verify_config(config)
96
-
97
- if @print
98
- require 'pp'
99
- pp config
100
- exit
101
- end
102
-
103
- config
104
- end
105
-
106
- def self.daemonize
107
- if (child_pid = fork)
108
- puts "PID #{child_pid}"
109
- exit!
110
- end
111
-
112
- Process.setsid
113
-
114
- rescue Exception
115
- puts "Platform (#{RUBY_PLATFORM}) does not appear to support fork/setsid; skipping"
116
- end
117
-
118
- def self.postprocess_config_load(config)
119
- config[Cmap] = [] unless Array === config[Cmap]
120
- config[Ctimeout] ||= 3
121
- config[Cmap].each do |m|
122
- m[Ckeepalive] = true unless m.has_key?(Ckeepalive)
123
- m[Ckeepalive] = !!m[Ckeepalive]
124
- m[Coutgoing] = [m[Coutgoing]] unless Array === m[Coutgoing]
125
- m[Cincoming] = [m[Cincoming]] unless Array === m[Cincoming]
126
- end
127
- end
128
-
129
- def self.verify_config(config)
130
- if config[Cbackend_address] and config[Cbackend_port]
131
- config[Cmap] << {Cincoming => nil, Curl => nil, Coutgoing => "#{config[Cbackend_address]}:#{config[Cbackend_port]}", Ckeepalive => true}
132
- end
133
- true
134
- end
135
-
136
- def self.run
137
- config = parse_options
138
- daemonize if config[Cdaemonize]
139
- Swiftcore::Swiftiply.run(config)
140
- end
141
-
142
- def self.on_windows?
143
- return @on_windows unless @on_windows.nil?
144
- @on_windows = !![/mswin/i, /cygwin/i, /mingw/i, /bccwin/i, /wince/i].find {|p| RUBY_PLATFORM =~ p}
145
- end
146
- end
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