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.
- data/README +126 -0
- data/bin/mongrel_rails +254 -0
- data/bin/swiftiply +136 -0
- data/bin/swiftiply_mongrel_rails +54 -0
- data/external/package.rb +672 -0
- data/external/test_support.rb +58 -0
- data/setup.rb +40 -0
- data/src/ramaze/adapter/evented_mongrel.rb +2 -0
- data/src/ramaze/adapter/swiftiplied_mongrel.rb +2 -0
- data/src/swiftcore/Swiftiply.rb +444 -0
- data/src/swiftcore/Swiftiply.rb.orig +390 -0
- data/src/swiftcore/evented_mongrel.rb +182 -0
- data/src/swiftcore/swiftiplied_mongrel.rb +212 -0
- data/swiftiply.gemspec +41 -0
- data/test/rails/README +182 -0
- data/test/rails/Rakefile +10 -0
- data/test/rails/app/controllers/application.rb +6 -0
- data/test/rails/app/controllers/tests_controller.rb +15 -0
- data/test/rails/app/helpers/application_helper.rb +3 -0
- data/test/rails/config/boot.rb +45 -0
- data/test/rails/config/database.yml +36 -0
- data/test/rails/config/environment.rb +60 -0
- data/test/rails/config/environments/development.rb +21 -0
- data/test/rails/config/environments/production.rb +18 -0
- data/test/rails/config/environments/production_no_caching.rb +18 -0
- data/test/rails/config/environments/test.rb +19 -0
- data/test/rails/config/routes.rb +23 -0
- data/test/rails/doc/README_FOR_APP +2 -0
- data/test/rails/observe_ram.rb +10 -0
- data/test/rails/public/404.html +30 -0
- data/test/rails/public/500.html +30 -0
- data/test/rails/public/dispatch.cgi +10 -0
- data/test/rails/public/dispatch.fcgi +24 -0
- data/test/rails/public/dispatch.rb +10 -0
- data/test/rails/public/favicon.ico +0 -0
- data/test/rails/public/images/rails.png +0 -0
- data/test/rails/public/index.html +277 -0
- data/test/rails/public/javascripts/application.js +2 -0
- data/test/rails/public/javascripts/controls.js +833 -0
- data/test/rails/public/javascripts/dragdrop.js +942 -0
- data/test/rails/public/javascripts/effects.js +1088 -0
- data/test/rails/public/javascripts/prototype.js +2515 -0
- data/test/rails/public/robots.txt +1 -0
- data/test/rails/script/about +3 -0
- data/test/rails/script/breakpointer +3 -0
- data/test/rails/script/console +3 -0
- data/test/rails/script/destroy +3 -0
- data/test/rails/script/generate +3 -0
- data/test/rails/script/performance/benchmarker +3 -0
- data/test/rails/script/performance/profiler +3 -0
- data/test/rails/script/plugin +3 -0
- data/test/rails/script/process/inspector +3 -0
- data/test/rails/script/process/reaper +3 -0
- data/test/rails/script/process/spawner +3 -0
- data/test/rails/script/runner +3 -0
- data/test/rails/script/server +3 -0
- data/test/rails/test/test_helper.rb +28 -0
- data/test/ramaze/conf/benchmark.yaml +35 -0
- data/test/ramaze/conf/debug.yaml +34 -0
- data/test/ramaze/conf/live.yaml +33 -0
- data/test/ramaze/conf/silent.yaml +31 -0
- data/test/ramaze/conf/stage.yaml +33 -0
- data/test/ramaze/main.rb +18 -0
- data/test/ramaze/public/404.jpg +0 -0
- data/test/ramaze/public/css/coderay.css +105 -0
- data/test/ramaze/public/css/ramaze_error.css +42 -0
- data/test/ramaze/public/error.zmr +77 -0
- data/test/ramaze/public/favicon.ico +0 -0
- data/test/ramaze/public/js/jquery.js +1923 -0
- data/test/ramaze/public/ramaze.png +0 -0
- data/test/ramaze/src/controller/main.rb +8 -0
- data/test/ramaze/src/element/page.rb +17 -0
- data/test/ramaze/src/model.rb +6 -0
- data/test/ramaze/template/index.xhtml +6 -0
- data/test/ramaze/yaml.db +0 -0
- metadata +189 -0
@@ -0,0 +1,58 @@
|
|
1
|
+
# A support module for the test suite. This provides a win32 aware
|
2
|
+
# mechanism for doing fork/exec operations. It requires win32/process
|
3
|
+
# to be installed, however.
|
4
|
+
#
|
5
|
+
module SwiftcoreTestSupport
|
6
|
+
@run_modes = []
|
7
|
+
|
8
|
+
def self.create_process(args)
|
9
|
+
@fork_ok = true unless @fork_ok == false
|
10
|
+
pid = nil
|
11
|
+
begin
|
12
|
+
raise NotImplementedError unless @fork_ok
|
13
|
+
unless pid = fork
|
14
|
+
Dir.chdir args[:dir]
|
15
|
+
exec(*args[:cmd])
|
16
|
+
end
|
17
|
+
rescue NotImplementedError
|
18
|
+
@fork_ok = false
|
19
|
+
begin
|
20
|
+
require 'rubygems'
|
21
|
+
rescue LoadError
|
22
|
+
end
|
23
|
+
|
24
|
+
begin
|
25
|
+
require 'win32/process'
|
26
|
+
rescue LoadError
|
27
|
+
raise "Please install win32-process to run all tests on a Win32 platform. 'gem install win32-process' or http://rubyforge.org/projects/win32utils"
|
28
|
+
end
|
29
|
+
cwd = Dir.pwd
|
30
|
+
Dir.chdir args[:dir]
|
31
|
+
pid = Process.create(:app_name => args[:cmd].join(' '))
|
32
|
+
Dir.chdir cwd
|
33
|
+
end
|
34
|
+
pid
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.test_dir(dir)
|
38
|
+
File.dirname(File.expand_path(dir))
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.cd_to_test_dir(dir)
|
42
|
+
Dir.chdir(File.dirname(File.expand_path(dir)))
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.set_src_dir
|
46
|
+
$:.unshift File.expand_path(File.join(File.dirname(__FILE__),'../src'))
|
47
|
+
end
|
48
|
+
|
49
|
+
@announcements = {}
|
50
|
+
def self.announce(section,msg)
|
51
|
+
unless @announcements.has_key?(section)
|
52
|
+
puts "\n\n"
|
53
|
+
puts msg,"#{'=' * msg.length}\n\n"
|
54
|
+
@announcements[section] = true
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
data/setup.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
#!ruby
|
2
|
+
|
3
|
+
basedir = File.dirname(__FILE__)
|
4
|
+
$:.push(basedir)
|
5
|
+
require 'external/package'
|
6
|
+
require 'rbconfig'
|
7
|
+
begin
|
8
|
+
require 'rubygems'
|
9
|
+
rescue LoadError
|
10
|
+
end
|
11
|
+
|
12
|
+
Dir.chdir(basedir)
|
13
|
+
Package.setup("1.0") {
|
14
|
+
name "Swiftcore Swiftiply"
|
15
|
+
|
16
|
+
translate(:lib, 'src/' => '')
|
17
|
+
translate(:bin, 'bin/' => '')
|
18
|
+
lib(*Dir["src/swiftcore/**/*.rb"])
|
19
|
+
lib("src/swiftcore/evented_mongrel.rb")
|
20
|
+
lib("src/swiftcore/swiftiplied_mongrel.rb")
|
21
|
+
ri(*Dir["src/swiftcore/**/*.rb"])
|
22
|
+
bin "bin/swiftiply"
|
23
|
+
bin "bin/swiftiply_mongrel_rails"
|
24
|
+
#File.rename("#{Config::CONFIG["bindir"]}/mongrel_rails","#{Config::CONFIG["bindir"]}/mongrel_rails.orig")
|
25
|
+
bin "bin/mongrel_rails"
|
26
|
+
|
27
|
+
# Install Ramaze libs if Ramaze is installed.
|
28
|
+
|
29
|
+
begin
|
30
|
+
require 'ramaze'
|
31
|
+
lib("src/ramaze/adapter/evented_mongrel.rb")
|
32
|
+
lib("src/ramaze/adapter/swiftiplied_mongrel.rb")
|
33
|
+
rescue LoadError
|
34
|
+
# Ramaze not installed
|
35
|
+
end
|
36
|
+
|
37
|
+
# unit_test "test/TC_Swiftiply.rb"
|
38
|
+
|
39
|
+
true
|
40
|
+
}
|
@@ -0,0 +1,444 @@
|
|
1
|
+
begin
|
2
|
+
load_attempted ||= false
|
3
|
+
require 'digest/sha2'
|
4
|
+
require 'eventmachine'
|
5
|
+
rescue LoadError => e
|
6
|
+
unless load_attempted
|
7
|
+
load_attempted = true
|
8
|
+
require 'rubygems'
|
9
|
+
end
|
10
|
+
raise e
|
11
|
+
end
|
12
|
+
|
13
|
+
module Swiftcore
|
14
|
+
module Swiftiply
|
15
|
+
Ccluster_address = 'cluster_address'.freeze
|
16
|
+
Ccluster_port = 'cluster_port'.freeze
|
17
|
+
CBackendAddress = 'BackendAddress'.freeze
|
18
|
+
CBackendPort = 'BackendPort'.freeze
|
19
|
+
Cmap = 'map'.freeze
|
20
|
+
Cincoming = 'incoming'.freeze
|
21
|
+
Ckeepalive = 'keepalive'.freeze
|
22
|
+
Cdaemonize = 'daemonize'.freeze
|
23
|
+
Curl = 'url'.freeze
|
24
|
+
Chost = 'host'.freeze
|
25
|
+
Cport = 'port'.freeze
|
26
|
+
Coutgoing = 'outgoing'.freeze
|
27
|
+
Ctimeout = 'timeout'.freeze
|
28
|
+
Cdefault = 'default'.freeze
|
29
|
+
|
30
|
+
# The ProxyBag is a class that holds the client and the server queues,
|
31
|
+
# and that is responsible for managing them, matching them, and expiring
|
32
|
+
# them, if necessary.
|
33
|
+
|
34
|
+
class ProxyBag
|
35
|
+
@client_q = Hash.new {|h,k| h[k] = []}
|
36
|
+
@server_q = Hash.new {|h,k| h[k] = []}
|
37
|
+
@ctime = Time.now
|
38
|
+
@server_unavailable_timeout = 6
|
39
|
+
@id_map = {}
|
40
|
+
@reverse_id_map = {}
|
41
|
+
@incoming_map = {}
|
42
|
+
@demanding_clients = Hash.new {|h,k| h[k] = []}
|
43
|
+
|
44
|
+
class << self
|
45
|
+
|
46
|
+
def now
|
47
|
+
@ctime
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns the access key. If an access key is set, then all new backend
|
51
|
+
# connections must send the correct access key before being added to
|
52
|
+
# the cluster as a valid backend.
|
53
|
+
|
54
|
+
def key
|
55
|
+
@key
|
56
|
+
end
|
57
|
+
|
58
|
+
# Sets the access key.
|
59
|
+
|
60
|
+
def key=(val)
|
61
|
+
@key = val
|
62
|
+
end
|
63
|
+
|
64
|
+
def add_id(who,what)
|
65
|
+
@id_map[who] = what
|
66
|
+
@reverse_id_map[what] = who
|
67
|
+
end
|
68
|
+
|
69
|
+
def remove_id(who)
|
70
|
+
what = @id_map.delete(who)
|
71
|
+
@reverse_id_map.delete(what)
|
72
|
+
end
|
73
|
+
|
74
|
+
def add_incoming_mapping(hashcode,name)
|
75
|
+
@incoming_map[name] = hashcode
|
76
|
+
end
|
77
|
+
|
78
|
+
def default_name
|
79
|
+
@default_name
|
80
|
+
end
|
81
|
+
|
82
|
+
def default_name=(val)
|
83
|
+
@default_name = val
|
84
|
+
end
|
85
|
+
|
86
|
+
# This timeout is the amount of time a connection will sit in queue
|
87
|
+
# waiting for a backend to process it.
|
88
|
+
|
89
|
+
def server_unavailable_timeout
|
90
|
+
@server_unavailable_timeout
|
91
|
+
end
|
92
|
+
|
93
|
+
# Sets the server unavailable timeout value.
|
94
|
+
|
95
|
+
def server_unavailable_timeout=(val)
|
96
|
+
@server_unavailable_timeout = val
|
97
|
+
end
|
98
|
+
|
99
|
+
# Pushes a front end client (web browser) into the queue of clients
|
100
|
+
# waiting to be serviced if there's no server available to handle
|
101
|
+
# it right now.
|
102
|
+
|
103
|
+
def add_frontend_client clnt
|
104
|
+
clnt.create_time = @ctime
|
105
|
+
unless match_client_to_server_now(clnt)
|
106
|
+
if clnt.uri =~ /\w+-\w+-\w+\.\w+\.[\w\.]+-(\w+)?$/
|
107
|
+
@demanding_clients[$1].unshift clnt
|
108
|
+
else
|
109
|
+
@client_q[clnt.name].unshift(clnt)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Pushes a backend server into the queue of servers waiting for a
|
115
|
+
# client to service if there are no clients waiting to be serviced.
|
116
|
+
|
117
|
+
def add_server srvr
|
118
|
+
@server_q[srvr.name].unshift(srvr) unless match_server_to_client_now(srvr)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Deletes the provided server from the server queue.
|
122
|
+
|
123
|
+
def remove_server srvr
|
124
|
+
@server_q[srvr.name].delete srvr
|
125
|
+
end
|
126
|
+
|
127
|
+
# Removes the named client from the client queue.
|
128
|
+
# TODO: Try replacing this with a linked list. Performance
|
129
|
+
# here has to suck when the list is long.
|
130
|
+
|
131
|
+
def remove_client clnt
|
132
|
+
@client_q[clnt.name].delete clnt
|
133
|
+
end
|
134
|
+
|
135
|
+
# Walks through the client and server queues, matching
|
136
|
+
# waiting clients with waiting servers until the queue
|
137
|
+
# runs out of one or the other. DEPRECATED
|
138
|
+
|
139
|
+
#def match_clients_to_servers
|
140
|
+
# while @server_q.first && @client_q.first
|
141
|
+
# server = @server_q.pop
|
142
|
+
# client = @client_q.pop
|
143
|
+
# server.associate = client
|
144
|
+
# client.associate = server
|
145
|
+
# client.push
|
146
|
+
# end
|
147
|
+
#end
|
148
|
+
|
149
|
+
# Tries to match the client passed as an argument to a
|
150
|
+
# server.
|
151
|
+
|
152
|
+
def match_client_to_server_now(client)
|
153
|
+
sq = @server_q[@incoming_map[client.name]]
|
154
|
+
if client.uri =~ /\w+-\w+-\w+\.\w+\.[\w\.]+-(\w+)?$/ and sidx = sq.index(@reverse_id_map[$1])
|
155
|
+
server = sq.delete_at(sidx)
|
156
|
+
server.associate = client
|
157
|
+
client.associate = server
|
158
|
+
client.push
|
159
|
+
true
|
160
|
+
elsif server = sq.pop
|
161
|
+
server.associate = client
|
162
|
+
client.associate = server
|
163
|
+
client.push
|
164
|
+
true
|
165
|
+
else
|
166
|
+
false
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# Tries to match the server passed as an argument to a
|
171
|
+
# client.
|
172
|
+
|
173
|
+
def match_server_to_client_now(server)
|
174
|
+
if client = @demanding_clients[server.id].pop
|
175
|
+
server.associate = client
|
176
|
+
client.associate = server
|
177
|
+
client.push
|
178
|
+
true
|
179
|
+
elsif client = @client_q[server.name].pop
|
180
|
+
server.associate = client
|
181
|
+
client.associate = server
|
182
|
+
client.push
|
183
|
+
true
|
184
|
+
else
|
185
|
+
false
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# Walk through the waiting clients if there is no server
|
190
|
+
# available to process clients and expire any clients that
|
191
|
+
# have been waiting longer than @server_unavailable_timeout
|
192
|
+
# seconds. Clients which are expired will receive a 503
|
193
|
+
# response.
|
194
|
+
|
195
|
+
def expire_clients
|
196
|
+
now = Time.now
|
197
|
+
@server_q.each_key do |name|
|
198
|
+
unless @server_q[name].first
|
199
|
+
while c = @client_q[name].pop
|
200
|
+
if (now - c.create_time) >= @server_unavailable_timeout
|
201
|
+
c.send_503_response
|
202
|
+
else
|
203
|
+
@client_q[name].push c
|
204
|
+
break
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
# This is called by a periodic timer once a second to update
|
212
|
+
# the time.
|
213
|
+
|
214
|
+
def update_ctime
|
215
|
+
@ctime = Time.now
|
216
|
+
end
|
217
|
+
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# The ClusterProtocol is the subclass of EventMachine::Connection used
|
222
|
+
# to communicate between Swiftiply and the web browser clients.
|
223
|
+
|
224
|
+
class ClusterProtocol < EventMachine::Connection
|
225
|
+
|
226
|
+
attr_accessor :create_time, :associate, :name
|
227
|
+
|
228
|
+
Crn = "\r\n".freeze
|
229
|
+
Crnrn = "\r\n\r\n".freeze
|
230
|
+
Rrnrn = /\r\n\r\n/
|
231
|
+
R_colon = /:/
|
232
|
+
C_blank = ''.freeze
|
233
|
+
|
234
|
+
# Initialize the @data array, which is the temporary storage for blocks
|
235
|
+
# of data received from the web browser client, then invoke the superclass
|
236
|
+
# initialization.
|
237
|
+
|
238
|
+
def initialize *args
|
239
|
+
@data = []
|
240
|
+
@name = nil
|
241
|
+
@uri = nil
|
242
|
+
super
|
243
|
+
end
|
244
|
+
|
245
|
+
def receive_data data
|
246
|
+
@data.unshift data
|
247
|
+
if @name
|
248
|
+
push
|
249
|
+
else
|
250
|
+
data =~ /\s([^\s\?]*)/
|
251
|
+
@uri ||= $1
|
252
|
+
if data =~ /^Host:\s*([^\r\n:]*)/
|
253
|
+
@name = $1
|
254
|
+
ProxyBag.add_frontend_client self
|
255
|
+
push
|
256
|
+
elsif data.index(/\r\n\r\n/)
|
257
|
+
@name = ProxyBag.default_name
|
258
|
+
ProxyBag.add_frontend_client self
|
259
|
+
push
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
# Hardcoded 503 response that is sent if a connection is timed out while
|
265
|
+
# waiting for a backend to handle it.
|
266
|
+
|
267
|
+
def send_503_response
|
268
|
+
send_data [
|
269
|
+
"HTTP/1.0 503 Server Unavailable\r\n",
|
270
|
+
"Content-type: text/plain\r\n",
|
271
|
+
"Connection: close\r\n",
|
272
|
+
"\r\n",
|
273
|
+
"Server Unavailable"
|
274
|
+
].join
|
275
|
+
close_connection_after_writing
|
276
|
+
end
|
277
|
+
|
278
|
+
# Push data from the web browser client to the backend server process.
|
279
|
+
|
280
|
+
def push
|
281
|
+
if @associate
|
282
|
+
while data = @data.pop
|
283
|
+
@associate.send_data data
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
# The connection with the web browser client has been closed, so the
|
289
|
+
# object must be removed from the ProxyBag's queue if it is has not
|
290
|
+
# been associated with a backend. If it has already been associated
|
291
|
+
# with a backend, then it will not be in the queue and need not be
|
292
|
+
# removed.
|
293
|
+
|
294
|
+
def unbind
|
295
|
+
ProxyBag.remove_client(self) unless @associate
|
296
|
+
end
|
297
|
+
|
298
|
+
def uri
|
299
|
+
@uri
|
300
|
+
end
|
301
|
+
|
302
|
+
end
|
303
|
+
|
304
|
+
|
305
|
+
# The BackendProtocol is the EventMachine::Connection subclass that
|
306
|
+
# handles the communications between Swiftiply and the backend process
|
307
|
+
# it is proxying to.
|
308
|
+
|
309
|
+
class BackendProtocol < EventMachine::Connection
|
310
|
+
attr_accessor :associate, :id
|
311
|
+
|
312
|
+
Crnrn = "\r\n\r\n".freeze
|
313
|
+
Rrnrn = /\r\n\r\n/
|
314
|
+
|
315
|
+
def initialize *args
|
316
|
+
@name = self.class.bname
|
317
|
+
super
|
318
|
+
end
|
319
|
+
|
320
|
+
def name
|
321
|
+
@name
|
322
|
+
end
|
323
|
+
|
324
|
+
# Call setup() and add the backend to the ProxyBag queue.
|
325
|
+
|
326
|
+
def post_init
|
327
|
+
setup
|
328
|
+
@initialized = nil
|
329
|
+
ProxyBag.add_server self
|
330
|
+
end
|
331
|
+
|
332
|
+
# Setup the initial variables for receiving headers and content.
|
333
|
+
|
334
|
+
def setup
|
335
|
+
@headers = ''
|
336
|
+
@headers_completed = false
|
337
|
+
@content_length = nil
|
338
|
+
@content_sent = 0
|
339
|
+
end
|
340
|
+
|
341
|
+
# Receive data from the backend process. Headers are parsed from
|
342
|
+
# the rest of the content, and the Content-Length header used to
|
343
|
+
# determine when the complete response has been read. The proxy
|
344
|
+
# will attempt to maintain a persistent connection with the backend,
|
345
|
+
# allowing for greater throughput.
|
346
|
+
|
347
|
+
def receive_data data
|
348
|
+
unless @initialized
|
349
|
+
@id = data.slice!(0..11)
|
350
|
+
ProxyBag.add_id(self,@id)
|
351
|
+
@initialized = true
|
352
|
+
end
|
353
|
+
unless @headers_completed
|
354
|
+
if data.index(Crnrn)
|
355
|
+
@headers_completed = true
|
356
|
+
h,d = data.split(Rrnrn)
|
357
|
+
@headers << h << Crnrn
|
358
|
+
@headers =~ /Content-Length:\s*([^\r\n]+)/
|
359
|
+
@content_length = $1.to_i
|
360
|
+
@associate.send_data @headers
|
361
|
+
data = d
|
362
|
+
else
|
363
|
+
@headers << data
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
if @headers_completed
|
368
|
+
@associate.send_data data
|
369
|
+
@content_sent += data.length
|
370
|
+
if @content_sent >= @content_length
|
371
|
+
@associate.close_connection_after_writing
|
372
|
+
@associate = nil
|
373
|
+
setup
|
374
|
+
ProxyBag.add_server self
|
375
|
+
end
|
376
|
+
end
|
377
|
+
rescue
|
378
|
+
@associate.close_connection_after_writing
|
379
|
+
@associate = nil
|
380
|
+
setup
|
381
|
+
ProxyBag.add_server self
|
382
|
+
end
|
383
|
+
|
384
|
+
# This is called when the backend disconnects from the proxy.
|
385
|
+
# If the backend is currently associated with a web browser client,
|
386
|
+
# that connection will be closed. Otherwise, the backend will be
|
387
|
+
# removed from the ProxyBag's backend queue.
|
388
|
+
|
389
|
+
def unbind
|
390
|
+
if @associate
|
391
|
+
@associate.close_connection_after_writing
|
392
|
+
else
|
393
|
+
ProxyBag.remove_server(self)
|
394
|
+
end
|
395
|
+
ProxyBag.remove_id(self)
|
396
|
+
end
|
397
|
+
|
398
|
+
def self.bname=(val)
|
399
|
+
@bname = val
|
400
|
+
end
|
401
|
+
|
402
|
+
def self.bname
|
403
|
+
@bname
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
# Start the EventMachine event loop and create the front end and backend
|
408
|
+
# handlers, then create the timers that are used to expire unserviced
|
409
|
+
# clients and to update the Proxy's clock.
|
410
|
+
|
411
|
+
def self.run(config, key = nil)
|
412
|
+
existing_backends = {}
|
413
|
+
EventMachine.run do
|
414
|
+
EventMachine.start_server(config[Ccluster_address], config[Ccluster_port], ClusterProtocol)
|
415
|
+
config[Cmap].each do |m|
|
416
|
+
if m[Ckeepalive]
|
417
|
+
incoming_hash = Digest::SHA512.hexdigest(m[Cincoming].join('|'))
|
418
|
+
m[Cincoming].each do |p|
|
419
|
+
ProxyBag.add_incoming_mapping(incoming_hash,p)
|
420
|
+
m[Coutgoing].each do |o|
|
421
|
+
ProxyBag.default_name = p if m[Cdefault]
|
422
|
+
if existing_backends.has_key?(o)
|
423
|
+
# Do we need to do anything here other than skip?
|
424
|
+
next
|
425
|
+
else
|
426
|
+
existing_backends[o] = true
|
427
|
+
backend_class = Class.new(BackendProtocol)
|
428
|
+
backend_class.bname = incoming_hash
|
429
|
+
host, port = o.split(/:/,2)
|
430
|
+
EventMachine.start_server(host, port.to_i, backend_class)
|
431
|
+
end
|
432
|
+
end
|
433
|
+
end
|
434
|
+
end
|
435
|
+
end
|
436
|
+
ProxyBag.server_unavailable_timeout ||= config[Ctimeout]
|
437
|
+
ProxyBag.key = key
|
438
|
+
EventMachine.add_periodic_timer(2) { ProxyBag.expire_clients }
|
439
|
+
EventMachine.add_periodic_timer(1) { ProxyBag.update_ctime }
|
440
|
+
end
|
441
|
+
end
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|