swiftiply 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/README +126 -0
  2. data/bin/mongrel_rails +254 -0
  3. data/bin/swiftiply +136 -0
  4. data/bin/swiftiply_mongrel_rails +54 -0
  5. data/external/package.rb +672 -0
  6. data/external/test_support.rb +58 -0
  7. data/setup.rb +40 -0
  8. data/src/ramaze/adapter/evented_mongrel.rb +2 -0
  9. data/src/ramaze/adapter/swiftiplied_mongrel.rb +2 -0
  10. data/src/swiftcore/Swiftiply.rb +444 -0
  11. data/src/swiftcore/Swiftiply.rb.orig +390 -0
  12. data/src/swiftcore/evented_mongrel.rb +182 -0
  13. data/src/swiftcore/swiftiplied_mongrel.rb +212 -0
  14. data/swiftiply.gemspec +41 -0
  15. data/test/rails/README +182 -0
  16. data/test/rails/Rakefile +10 -0
  17. data/test/rails/app/controllers/application.rb +6 -0
  18. data/test/rails/app/controllers/tests_controller.rb +15 -0
  19. data/test/rails/app/helpers/application_helper.rb +3 -0
  20. data/test/rails/config/boot.rb +45 -0
  21. data/test/rails/config/database.yml +36 -0
  22. data/test/rails/config/environment.rb +60 -0
  23. data/test/rails/config/environments/development.rb +21 -0
  24. data/test/rails/config/environments/production.rb +18 -0
  25. data/test/rails/config/environments/production_no_caching.rb +18 -0
  26. data/test/rails/config/environments/test.rb +19 -0
  27. data/test/rails/config/routes.rb +23 -0
  28. data/test/rails/doc/README_FOR_APP +2 -0
  29. data/test/rails/observe_ram.rb +10 -0
  30. data/test/rails/public/404.html +30 -0
  31. data/test/rails/public/500.html +30 -0
  32. data/test/rails/public/dispatch.cgi +10 -0
  33. data/test/rails/public/dispatch.fcgi +24 -0
  34. data/test/rails/public/dispatch.rb +10 -0
  35. data/test/rails/public/favicon.ico +0 -0
  36. data/test/rails/public/images/rails.png +0 -0
  37. data/test/rails/public/index.html +277 -0
  38. data/test/rails/public/javascripts/application.js +2 -0
  39. data/test/rails/public/javascripts/controls.js +833 -0
  40. data/test/rails/public/javascripts/dragdrop.js +942 -0
  41. data/test/rails/public/javascripts/effects.js +1088 -0
  42. data/test/rails/public/javascripts/prototype.js +2515 -0
  43. data/test/rails/public/robots.txt +1 -0
  44. data/test/rails/script/about +3 -0
  45. data/test/rails/script/breakpointer +3 -0
  46. data/test/rails/script/console +3 -0
  47. data/test/rails/script/destroy +3 -0
  48. data/test/rails/script/generate +3 -0
  49. data/test/rails/script/performance/benchmarker +3 -0
  50. data/test/rails/script/performance/profiler +3 -0
  51. data/test/rails/script/plugin +3 -0
  52. data/test/rails/script/process/inspector +3 -0
  53. data/test/rails/script/process/reaper +3 -0
  54. data/test/rails/script/process/spawner +3 -0
  55. data/test/rails/script/runner +3 -0
  56. data/test/rails/script/server +3 -0
  57. data/test/rails/test/test_helper.rb +28 -0
  58. data/test/ramaze/conf/benchmark.yaml +35 -0
  59. data/test/ramaze/conf/debug.yaml +34 -0
  60. data/test/ramaze/conf/live.yaml +33 -0
  61. data/test/ramaze/conf/silent.yaml +31 -0
  62. data/test/ramaze/conf/stage.yaml +33 -0
  63. data/test/ramaze/main.rb +18 -0
  64. data/test/ramaze/public/404.jpg +0 -0
  65. data/test/ramaze/public/css/coderay.css +105 -0
  66. data/test/ramaze/public/css/ramaze_error.css +42 -0
  67. data/test/ramaze/public/error.zmr +77 -0
  68. data/test/ramaze/public/favicon.ico +0 -0
  69. data/test/ramaze/public/js/jquery.js +1923 -0
  70. data/test/ramaze/public/ramaze.png +0 -0
  71. data/test/ramaze/src/controller/main.rb +8 -0
  72. data/test/ramaze/src/element/page.rb +17 -0
  73. data/test/ramaze/src/model.rb +6 -0
  74. data/test/ramaze/template/index.xhtml +6 -0
  75. data/test/ramaze/yaml.db +0 -0
  76. metadata +189 -0
data/README ADDED
@@ -0,0 +1,126 @@
1
+ Swiftiply v. 0.5.0 (http://swiftiply.swiftcore.org)
2
+
3
+ Swiftiply is a backend agnostic clustering proxy for web applications that is
4
+ specifically designed to support HTTP traffic from web frameworks. Unlike Pen
5
+ (http://siag.nu/pen/), Swiftiply is not intended as a general purpose load
6
+ balancer for tcp protocols and unlike HAProxy (http://haproxy.1wt.eu/), it is
7
+ not a highly configurable general purpose proxy overflowing with features.
8
+
9
+ What it is, though, is a very fast, narrowly targetted clustering proxy.
10
+ In back to back comparisons of Swiftiply to HAProxy, Swiftiply reliably
11
+ outperforms HAProxy (tested using IOWA, Rails, Merb, and Ramaze backend
12
+ processes running Mongrel).
13
+
14
+ Swiftiply works differently from a traditional proxy. In Swiftiply, the
15
+ backend processes are clients of the Swiftiply server -- they make persistent
16
+ socket connections to Swiftiply. One of the major advantages to this
17
+ architecture is that it allows one to start or stop backend processes at will,
18
+ with no configuration of the proxy. The obvious disadvantage is that this is
19
+ not behavior that backends typically expect.
20
+
21
+ Because Mongrel is the preferred deployment method for most Ruby frameworks,
22
+ Swiftiply includes a version of Mongrel (found in swiftcore/swiftiplied_mongrel.rb)
23
+ that has been modified to work as a swiftiply client. This should be
24
+ transparent to any existing Mongrel handlers, allowing them all to with
25
+ Swiftiply.
26
+
27
+ In addition, as an offshoot of the swiftiplied_mongrel, there is a second
28
+ version that is available. This other version is found in
29
+ swiftcore/evented_mongrel.rb; it is a version of Mongrel that has its network
30
+ traffic handled by EventMachine, creating a Mongrel that runs in an event
31
+ based mode instead of a threaded mode. For many applications, running in an
32
+ event based mode will give better throughput than running in a threaded mode,
33
+ especially when there are concurrent requests coming in.
34
+
35
+ This is because the event based operation handles requests efficiently, on
36
+ a first come, first served basis, without the overhead of threads. For the
37
+ typical Rails application, this means that request handling may be slightly
38
+ faster than the threaded Mongrel for single, non-concurrent requests. When
39
+ there are concurrent requests, though, the differential increases quickly.
40
+
41
+
42
+ FRAMEWORK SUPPORT
43
+
44
+
45
+ Swiftcore IOWA
46
+
47
+ IOWA has built in support for running in evented and clustered modes.
48
+
49
+
50
+ Rails
51
+
52
+ Swiftiply provides a _REPLACEMENT_ to mongrel_rails that, throught the use
53
+ of an environment variable, can be told to run in either the evented mode or
54
+ the swiftiplied mode.
55
+
56
+ To run a Rails app in evented mode, set the EVENT environment variable. On
57
+ a unixlike system:
58
+
59
+ env EVENT=1 mongrel_rails
60
+
61
+ will do it.
62
+
63
+ To run in swiftiplied mode:
64
+
65
+ env SWIFTIPLY=1 mongrel_rails
66
+
67
+ Because Swiftiply backends connect to the Swiftiply server, they all connect
68
+ on the same port. This is important. Each of the backends runs against the
69
+ same port. To make it easier to start multiple Rails backends, a helper
70
+ script, swiftiply_mongrel_rails, is provided. It is just a light wrapper
71
+ around mongrel_rails that will let one start N backends, with proper pid
72
+ files, and stop them.
73
+
74
+
75
+ Merb
76
+
77
+ The merb source (trunk only, at this point), has Swiftiply support that works
78
+ just like the Rails support, built in.
79
+
80
+
81
+ Ramaze
82
+
83
+ A couple adapters for Ramaze are included, to allow Ramaze to run with either
84
+ the evented or the swiftiplied mongrels. They are installed into
85
+
86
+ ramaze/adapter/evented_mongrel.rb
87
+ ramaze/adapter/swiftiplied_mongrel.rb
88
+
89
+
90
+ Other Frameworks
91
+
92
+ Swiftiply has been tested with Camping and Nitro, as well. Direct support for
93
+ them is not yet bundled, but will be in an upcoming release.
94
+
95
+
96
+ CONFIGURATION
97
+
98
+ Swiftiply takes a single configuration file which defines for it where it
99
+ should listen for incoming connections, whether it should daemonize itself,
100
+ and then provides a map of incoming domain names and the address/port to
101
+ proxy that traffic to. That outgoing address/port is where the backends for
102
+ that site will connect to.
103
+
104
+ Here's an example:
105
+
106
+ cluster_address: swiftcore.org
107
+ cluster_port: 80
108
+ daemonize: true
109
+ map:
110
+ - incoming:
111
+ - swiftcore.org
112
+ - www.swiftcore.org
113
+ outgoing: 127.0.0.1:30000
114
+ default: true
115
+ - incoming: iowa.swiftcore.org
116
+ outgoing: 127.0.0.1:30010
117
+ - incoming: analogger.swiftcore.org
118
+ outgoing: 127.0.0.1:30020
119
+ - incoming:
120
+ - swiftiply.com
121
+ - www.swiftiply.com
122
+ - swiftiply.swiftcore.org
123
+ outgoing: 127.0.0.1:30030
124
+
125
+
126
+
data/bin/mongrel_rails ADDED
@@ -0,0 +1,254 @@
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.
7
+
8
+ require 'rubygems'
9
+ 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
19
+ require 'mongrel/rails'
20
+ require 'etc'
21
+ require 'cgi_multipart_eof_fix' rescue nil
22
+
23
+ module Mongrel
24
+ class Start < GemPlugin::Plugin "/commands"
25
+ include Mongrel::Command::Base
26
+
27
+ def configure
28
+ options [
29
+ ["-e", "--environment ENV", "Rails environment to run as", :@environment, ENV['RAILS_ENV'] || "development"],
30
+ ["-d", "--daemonize", "Run daemonized in the background", :@daemon, false],
31
+ ['-p', '--port PORT', "Which port to bind to", :@port, 3000],
32
+ ['-a', '--address ADDR', "Address to bind to", :@address, "0.0.0.0"],
33
+ ['-l', '--log FILE', "Where to write log messages", :@log_file, "log/mongrel.log"],
34
+ ['-P', '--pid FILE', "Where to write the PID", :@pid_file, "log/mongrel.pid"],
35
+ ['-n', '--num-procs INT', "Number of processors active before clients denied", :@num_procs, 1024],
36
+ ['-t', '--timeout TIME', "Timeout all requests after 100th seconds time", :@timeout, 0],
37
+ ['-m', '--mime PATH', "A YAML file that lists additional MIME types", :@mime_map, nil],
38
+ ['-c', '--chdir PATH', "Change to dir before starting (will be expanded)", :@cwd, Dir.pwd],
39
+ ['-r', '--root PATH', "Set the document root (default 'public')", :@docroot, "public"],
40
+ ['-B', '--debug', "Enable debugging mode", :@debug, false],
41
+ ['-C', '--config PATH', "Use a config file", :@config_file, nil],
42
+ ['-S', '--script PATH', "Load the given file as an extra config script", :@config_script, nil],
43
+ ['-G', '--generate PATH', "Generate a config file for use with -C", :@generate, nil],
44
+ ['', '--user USER', "User to run as", :@user, nil],
45
+ ['', '--group GROUP', "Group to run as", :@group, nil],
46
+ ['', '--prefix PATH', "URL prefix for Rails app", :@prefix, nil]
47
+ ]
48
+ end
49
+
50
+ def validate
51
+ @cwd = File.expand_path(@cwd)
52
+ valid_dir? @cwd, "Invalid path to change to during daemon mode: #@cwd"
53
+
54
+ # Change there to start, then we'll have to come back after daemonize
55
+ Dir.chdir(@cwd)
56
+
57
+ valid?(@prefix[0].chr == "/" && @prefix[-1].chr != "/", "Prefix must begin with / and not end in /") if @prefix
58
+ valid_dir? File.dirname(@log_file), "Path to log file not valid: #@log_file"
59
+ valid_dir? File.dirname(@pid_file), "Path to pid file not valid: #@pid_file"
60
+ valid_dir? @docroot, "Path to docroot not valid: #@docroot"
61
+ valid_exists? @mime_map, "MIME mapping file does not exist: #@mime_map" if @mime_map
62
+ valid_exists? @config_file, "Config file not there: #@config_file" if @config_file
63
+ valid_dir? File.dirname(@generate), "Problem accessing directory to #@generate" if @generate
64
+ valid_user? @user if @user
65
+ valid_group? @group if @group
66
+
67
+ return @valid
68
+ end
69
+
70
+ def run
71
+ # Config file settings will override command line settings
72
+ settings = { :host => @address, :port => @port, :cwd => @cwd,
73
+ :log_file => @log_file, :pid_file => @pid_file, :environment => @environment,
74
+ :docroot => @docroot, :mime_map => @mime_map, :daemon => @daemon,
75
+ :debug => @debug, :includes => ["mongrel"], :config_script => @config_script,
76
+ :num_processors => @num_procs, :timeout => @timeout,
77
+ :user => @user, :group => @group, :prefix => @prefix, :config_file => @config_file
78
+ }
79
+
80
+ if @generate
81
+ STDERR.puts "** Writing config to \"#@generate\"."
82
+ open(@generate, "w") {|f| f.write(settings.to_yaml) }
83
+ STDERR.puts "** Finished. Run \"mongrel_rails -C #@generate\" to use the config file."
84
+ exit 0
85
+ end
86
+
87
+ if @config_file
88
+ settings.merge! YAML.load_file(@config_file)
89
+ STDERR.puts "** Loading settings from #{@config_file} (they override command line)." unless settings[:daemon]
90
+ end
91
+
92
+ config = Mongrel::Rails::RailsConfigurator.new(settings) do
93
+ if defaults[:daemon]
94
+ if File.exist? defaults[:pid_file]
95
+ log "!!! PID file #{defaults[:pid_file]} already exists. Mongrel could be running already. Check your #{defaults[:log_file]} for errors."
96
+ log "!!! Exiting with error. You must stop mongrel and clear the .pid before I'll attempt a start."
97
+ exit 1
98
+ end
99
+
100
+ daemonize
101
+ log "Daemonized, any open files are closed. Look at #{defaults[:pid_file]} and #{defaults[:log_file]} for info."
102
+ log "Settings loaded from #{@config_file} (they override command line)." if @config_file
103
+ end
104
+
105
+ log "Starting Mongrel listening at #{defaults[:host]}:#{defaults[:port]}"
106
+
107
+ listener do
108
+ mime = {}
109
+ if defaults[:mime_map]
110
+ log "Loading additional MIME types from #{defaults[:mime_map]}"
111
+ mime = load_mime_map(defaults[:mime_map], mime)
112
+ end
113
+
114
+ if defaults[:debug]
115
+ log "Installing debugging prefixed filters. Look in log/mongrel_debug for the files."
116
+ debug "/"
117
+ end
118
+
119
+ log "Starting Rails with #{defaults[:environment]} environment..."
120
+ log "Mounting Rails at #{defaults[:prefix]}..." if defaults[:prefix]
121
+ uri defaults[:prefix] || "/", :handler => rails(:mime => mime, :prefix => defaults[:prefix])
122
+ log "Rails loaded."
123
+
124
+ log "Loading any Rails specific GemPlugins"
125
+ load_plugins
126
+
127
+ if defaults[:config_script]
128
+ log "Loading #{defaults[:config_script]} external config script"
129
+ run_config(defaults[:config_script])
130
+ end
131
+
132
+ setup_rails_signals
133
+ end
134
+ end
135
+
136
+ config.run
137
+ config.log "Mongrel available at #{settings[:host]}:#{settings[:port]}"
138
+
139
+ if config.defaults[:daemon]
140
+ config.write_pid_file
141
+ else
142
+ config.log "Use CTRL-C to stop."
143
+ end
144
+
145
+ config.join
146
+
147
+ if config.needs_restart
148
+ if RUBY_PLATFORM !~ /mswin/
149
+ cmd = "ruby #{__FILE__} start #{original_args.join(' ')}"
150
+ config.log "Restarting with arguments: #{cmd}"
151
+ config.stop
152
+ config.remove_pid_file
153
+
154
+ if config.defaults[:daemon]
155
+ system cmd
156
+ else
157
+ STDERR.puts "Can't restart unless in daemon mode."
158
+ exit 1
159
+ end
160
+ else
161
+ config.log "Win32 does not support restarts. Exiting."
162
+ end
163
+ end
164
+ end
165
+ end
166
+
167
+ def Mongrel::send_signal(signal, pid_file)
168
+ pid = open(pid_file).read.to_i
169
+ print "Sending #{signal} to Mongrel at PID #{pid}..."
170
+ begin
171
+ Process.kill(signal, pid)
172
+ rescue Errno::ESRCH
173
+ puts "Process does not exist. Not running."
174
+ end
175
+
176
+ puts "Done."
177
+ end
178
+
179
+
180
+ class Stop < GemPlugin::Plugin "/commands"
181
+ include Mongrel::Command::Base
182
+
183
+ def configure
184
+ options [
185
+ ['-c', '--chdir PATH', "Change to dir before starting (will be expanded).", :@cwd, "."],
186
+ ['-f', '--force', "Force the shutdown (kill -9).", :@force, false],
187
+ ['-w', '--wait SECONDS', "Wait SECONDS before forcing shutdown", :@wait, "0"],
188
+ ['-P', '--pid FILE', "Where the PID file is located.", :@pid_file, "log/mongrel.pid"]
189
+ ]
190
+ end
191
+
192
+ def validate
193
+ @cwd = File.expand_path(@cwd)
194
+ valid_dir? @cwd, "Invalid path to change to during daemon mode: #@cwd"
195
+
196
+ Dir.chdir @cwd
197
+
198
+ valid_exists? @pid_file, "PID file #@pid_file does not exist. Not running?"
199
+ return @valid
200
+ end
201
+
202
+ def run
203
+ if @force
204
+ @wait.to_i.times do |waiting|
205
+ exit(0) if not File.exist? @pid_file
206
+ sleep 1
207
+ end
208
+
209
+ Mongrel::send_signal("KILL", @pid_file) if File.exist? @pid_file
210
+ else
211
+ Mongrel::send_signal("TERM", @pid_file)
212
+ end
213
+ end
214
+ end
215
+
216
+
217
+ class Restart < GemPlugin::Plugin "/commands"
218
+ include Mongrel::Command::Base
219
+
220
+ def configure
221
+ options [
222
+ ['-c', '--chdir PATH', "Change to dir before starting (will be expanded)", :@cwd, '.'],
223
+ ['-s', '--soft', "Do a soft restart rather than a process exit restart", :@soft, false],
224
+ ['-P', '--pid FILE', "Where the PID file is located", :@pid_file, "log/mongrel.pid"]
225
+ ]
226
+ end
227
+
228
+ def validate
229
+ @cwd = File.expand_path(@cwd)
230
+ valid_dir? @cwd, "Invalid path to change to during daemon mode: #@cwd"
231
+
232
+ Dir.chdir @cwd
233
+
234
+ valid_exists? @pid_file, "PID file #@pid_file does not exist. Not running?"
235
+ return @valid
236
+ end
237
+
238
+ def run
239
+ if @soft
240
+ Mongrel::send_signal("HUP", @pid_file)
241
+ else
242
+ Mongrel::send_signal("USR2", @pid_file)
243
+ end
244
+ end
245
+ end
246
+ end
247
+
248
+
249
+ GemPlugin::Manager.instance.load "mongrel" => GemPlugin::INCLUDE, "rails" => GemPlugin::EXCLUDE
250
+
251
+
252
+ if not Mongrel::Command::Registry.instance.run ARGV
253
+ exit 1
254
+ end
data/bin/swiftiply ADDED
@@ -0,0 +1,136 @@
1
+ #!ruby
2
+
3
+ require 'optparse'
4
+ require 'yaml'
5
+
6
+ begin
7
+ load_attempted ||= false
8
+ require 'swiftcore/Swiftiply'
9
+ rescue LoadError => e
10
+ unless load_attempted
11
+ load_attempted = true
12
+ require 'rubygems'
13
+ retry
14
+ end
15
+ raise e
16
+ end
17
+
18
+ module Swiftcore
19
+ class SwiftiplyExec
20
+ Ccluster_address = 'cluster_address'.freeze
21
+ Ccluster_port = 'cluster_port'.freeze
22
+ Cbackend_address = 'backend_address'.freeze
23
+ Cbackend_port = 'backend_port'.freeze
24
+ Cmap = 'map'.freeze
25
+ Cincoming = 'incoming'.freeze
26
+ Coutgoing = 'outgoing'.freeze
27
+ Ckeepalive = 'keepalive'.freeze
28
+ Cdaemonize = 'daemonize'.freeze
29
+ Curl = 'url'.freeze
30
+ Chost = 'host'.freeze
31
+ Cport = 'port'.freeze
32
+ Ctimeout = 'timeout'.freeze
33
+
34
+ #####
35
+ #
36
+ # --cluster-address
37
+ # --cluster-port
38
+ # --config-file -c (default swiftiply.cnf)
39
+ # --daemonize -d
40
+ #
41
+ # Config file format (YAML):
42
+ #
43
+ # cluster_address:
44
+ # cluster_port:
45
+ # daemonize:
46
+ # map:
47
+ # - incoming:
48
+ # - 127.0.0.1:8080
49
+ # - foo.bar.com:8090
50
+ # url:
51
+ # keepalive:
52
+ # outgoing:
53
+ #
54
+ #####
55
+ def self.parse_options(config = {})
56
+ OptionParser.new do |opts|
57
+ opts.banner = 'Usage: swiftiply.rb [options]'
58
+ opts.separator ''
59
+ opts.on('-c','--config CONFFILE',"The configuration file to read.") do |conf|
60
+ config = YAML.load(File.open(conf))
61
+ postprocess_config_load(config)
62
+ end
63
+ opts.on('--cluster-address [ADDRESS]',String,'The hostname/IP address that swiftiply will listen for connections on.') do |address|
64
+ config[Ccluster_address] = address
65
+ end
66
+ opts.on('--cluster-port [PORT]',Integer,'The port that swiftiply will listen for connections on.') do |port|
67
+ config[Ccluster_port] = port
68
+ end
69
+ opts.on('--backend-address [ADDRESS]',String,'The hostname/IP address that swiftiply will listen for backend connections on.') do |address|
70
+ config[Cbackend_address] = address
71
+ end
72
+ opts.on('--backend-port [PORT]',Integer,'The port that swiftiply will listen for backend connections on.') do |port|
73
+ config[Cbackend_port] = port
74
+ end
75
+ opts.on('-d','--daemonize [YN]',[:y,:yes,:n,:no],'Whether swiftiply should put itself into the background.') do |yn|
76
+ config[Cdaemonize] = yn.to_s =~ /^y/i
77
+ end
78
+ opts.on('-t','--timeout [SECONDS]',Integer,'The server unavailable timeout. Defaults to 3 seconds.') do |timeout|
79
+ config[Ctimeout] = timeout
80
+ end
81
+ opts.on('-p','--print-config','Print the full configuration.') do
82
+ verify_config(config)
83
+ require 'pp'
84
+ pp config
85
+ exit
86
+ end
87
+
88
+ end.parse!
89
+ puts("Configuration failed validation; exiting.") && exit unless verify_config(config)
90
+ config
91
+ end
92
+
93
+ def self.daemonize
94
+ if (child_pid = fork)
95
+ puts "PID #{child_pid}"
96
+ exit!
97
+ end
98
+
99
+ Process.setsid
100
+
101
+ rescue Exception
102
+ puts "Platform (#{RUBY_PLATFORM}) does not appear to support fork/setsid; skipping"
103
+ end
104
+
105
+ def self.postprocess_config_load(config)
106
+ config[Cmap] = [] unless Array === config[Cmap]
107
+ config[Ctimeout] ||= 3
108
+ config[Cmap].each do |m|
109
+ m[Ckeepalive] = true unless m.has_key?(Ckeepalive)
110
+ m[Ckeepalive] = !!m[Ckeepalive]
111
+ m[Coutgoing] = [m[Coutgoing]] unless Array === m[Coutgoing]
112
+ m[Cincoming] = [m[Cincoming]] unless Array === m[Cincoming]
113
+ end
114
+ end
115
+
116
+ def self.verify_config(config)
117
+ if config[Cbackend_address] and config[Cbackend_port]
118
+ config[Cmap] << {Cincoming => nil, Curl => nil, Coutgoing => "#{config[Cbackend_address]}:#{config[Cbackend_port]}", Ckeepalive => true}
119
+ end
120
+ true
121
+ end
122
+
123
+ def self.run
124
+ config = parse_options
125
+ daemonize if config[Cdaemonize]
126
+ Swiftcore::Swiftiply.run(config)
127
+ end
128
+
129
+ def self.on_windows?
130
+ return @on_windows unless @on_windows.nil?
131
+ @on_windows = !![/mswin/i, /cygwin/i, /mingw/i, /bccwin/i, /wince/i].find {|p| RUBY_PLATFORM =~ p}
132
+ end
133
+ end
134
+ end
135
+
136
+ Swiftcore::SwiftiplyExec.run