swiftiply 0.5.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 (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