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.
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