juggernaut_rails 0.5.9
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.rdoc +95 -0
- data/Rakefile +27 -0
- data/VERSION +1 -0
- data/bin/juggernaut +4 -0
- data/lib/juggernaut.rb +158 -0
- data/lib/juggernaut/client.rb +263 -0
- data/lib/juggernaut/message.rb +19 -0
- data/lib/juggernaut/miscel.rb +27 -0
- data/lib/juggernaut/rails.rb +25 -0
- data/lib/juggernaut/rails/convenience_methods.rb +137 -0
- data/lib/juggernaut/rails/helpers.rb +27 -0
- data/lib/juggernaut/rails/render_extension.rb +77 -0
- data/lib/juggernaut/rails/tasks.rb +66 -0
- data/lib/juggernaut/runner.rb +221 -0
- data/lib/juggernaut/server.rb +368 -0
- data/lib/juggernaut/utils.rb +11 -0
- data/lib/juggernaut_rails.rb +4 -0
- data/media/expressinstall.swf +0 -0
- data/media/jquery.js +3549 -0
- data/media/jquerynaut.js +57 -0
- data/media/json.js +97 -0
- data/media/juggernaut.as +79 -0
- data/media/juggernaut.js +204 -0
- data/media/juggernaut.swf +0 -0
- data/media/juggernaut.yml +121 -0
- data/media/juggernaut_hosts.yml +18 -0
- data/media/log/juggernaut.log +0 -0
- data/media/swfobject.js +5 -0
- data/rails/init.rb +21 -0
- data/test/test_client.rb +176 -0
- data/test/test_juggernaut.rb +34 -0
- data/test/test_message.rb +26 -0
- data/test/test_runner.rb +26 -0
- data/test/test_server.rb +573 -0
- data/test/test_utils.rb +26 -0
- metadata +114 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
module Juggernaut
|
2
|
+
class Message
|
3
|
+
attr_accessor :id
|
4
|
+
attr_accessor :signature
|
5
|
+
attr_accessor :body
|
6
|
+
attr_reader :created_at
|
7
|
+
|
8
|
+
def initialize(id, body, signature)
|
9
|
+
@id = id
|
10
|
+
@body = body
|
11
|
+
@signature = signature
|
12
|
+
@created_at = Time.now
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
{ :id => @id.to_s, :body => @body, :signature => @signature }.to_json
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Juggernaut
|
2
|
+
module Miscel
|
3
|
+
def options
|
4
|
+
Juggernaut.options
|
5
|
+
end
|
6
|
+
|
7
|
+
def options=(ob)
|
8
|
+
Juggernaut.options = ob
|
9
|
+
end
|
10
|
+
|
11
|
+
def log_path
|
12
|
+
Juggernaut.log_path
|
13
|
+
end
|
14
|
+
|
15
|
+
def pid_path
|
16
|
+
Juggernaut.pid_path
|
17
|
+
end
|
18
|
+
|
19
|
+
def config_path
|
20
|
+
Juggernaut.config_path
|
21
|
+
end
|
22
|
+
|
23
|
+
def logger
|
24
|
+
Juggernaut.logger
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "yaml"
|
2
|
+
|
3
|
+
module Juggernaut
|
4
|
+
module Rails
|
5
|
+
class <<self
|
6
|
+
attr_writer :hosts
|
7
|
+
|
8
|
+
def default_options
|
9
|
+
@default_options ||= {
|
10
|
+
:config_path => File.join(::Rails.root, 'config', 'juggernaut.yml'),
|
11
|
+
:log_path => File.join(::Rails.root, 'log', 'juggernaut.log'),
|
12
|
+
:pid_path => File.join(::Rails.root, 'tmp', 'pids', 'juggernaut.5001.pid')
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
def hosts
|
17
|
+
@hosts ||= YAML::load(ERB.new(IO.read("#{::Rails.root}/config/juggernaut_hosts.yml")).result)[:hosts].select {|h| !h[:environment] or h[:environment] == ::Rails.env.to_sym }
|
18
|
+
end
|
19
|
+
|
20
|
+
def random_host
|
21
|
+
hosts[rand(hosts.length)]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require "socket"
|
2
|
+
|
3
|
+
module Juggernaut::Rails
|
4
|
+
module ConvenienceMethods
|
5
|
+
|
6
|
+
def self.included(base) #:nodoc:
|
7
|
+
#raise "included jugs"
|
8
|
+
base.class_eval do
|
9
|
+
extend ClassMethods
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
|
15
|
+
def send_to_all(data)
|
16
|
+
fc = {
|
17
|
+
:command => :broadcast,
|
18
|
+
:body => data,
|
19
|
+
:type => :to_channels,
|
20
|
+
:channels => []
|
21
|
+
}
|
22
|
+
send_data(fc)
|
23
|
+
end
|
24
|
+
|
25
|
+
def send_to_channels(data, channels)
|
26
|
+
fc = {
|
27
|
+
:command => :broadcast,
|
28
|
+
:body => data,
|
29
|
+
:type => :to_channels,
|
30
|
+
:channels => channels
|
31
|
+
}
|
32
|
+
send_data(fc)
|
33
|
+
end
|
34
|
+
alias send_to_channel send_to_channels
|
35
|
+
|
36
|
+
def send_to_clients(data, client_ids)
|
37
|
+
fc = {
|
38
|
+
:command => :broadcast,
|
39
|
+
:body => data,
|
40
|
+
:type => :to_clients,
|
41
|
+
:client_ids => client_ids
|
42
|
+
}
|
43
|
+
send_data(fc)
|
44
|
+
end
|
45
|
+
alias send_to_client send_to_clients
|
46
|
+
|
47
|
+
def send_to_clients_on_channels(data, client_ids, channels)
|
48
|
+
fc = {
|
49
|
+
:command => :broadcast,
|
50
|
+
:body => data,
|
51
|
+
:type => :to_clients,
|
52
|
+
:client_ids => client_ids,
|
53
|
+
:channels => channels
|
54
|
+
}
|
55
|
+
send_data(fc)
|
56
|
+
end
|
57
|
+
alias send_to_clients_on_channel send_to_clients_on_channels
|
58
|
+
alias send_to_client_on_channels send_to_clients_on_channels
|
59
|
+
|
60
|
+
def remove_channels_from_clients(client_ids, channels)
|
61
|
+
fc = {
|
62
|
+
:command => :query,
|
63
|
+
:type => :remove_channels_from_client,
|
64
|
+
:client_ids => client_ids,
|
65
|
+
:channels => channels
|
66
|
+
}
|
67
|
+
send_data(fc)
|
68
|
+
end
|
69
|
+
alias remove_channel_from_client remove_channels_from_clients
|
70
|
+
alias remove_channels_from_client remove_channels_from_clients
|
71
|
+
|
72
|
+
def remove_all_channels(channels)
|
73
|
+
fc = {
|
74
|
+
:command => :query,
|
75
|
+
:type => :remove_all_channels,
|
76
|
+
:channels => channels
|
77
|
+
}
|
78
|
+
send_data(fc)
|
79
|
+
end
|
80
|
+
|
81
|
+
def show_clients
|
82
|
+
fc = {
|
83
|
+
:command => :query,
|
84
|
+
:type => :show_clients
|
85
|
+
}
|
86
|
+
send_data(fc, true).flatten
|
87
|
+
end
|
88
|
+
|
89
|
+
def show_client(client_id)
|
90
|
+
fc = {
|
91
|
+
:command => :query,
|
92
|
+
:type => :show_client,
|
93
|
+
:client_id => client_id
|
94
|
+
}
|
95
|
+
send_data(fc, true).flatten[0]
|
96
|
+
end
|
97
|
+
|
98
|
+
def show_clients_for_channels(channels)
|
99
|
+
fc = {
|
100
|
+
:command => :query,
|
101
|
+
:type => :show_clients_for_channels,
|
102
|
+
:channels => channels
|
103
|
+
}
|
104
|
+
send_data(fc, true).flatten
|
105
|
+
end
|
106
|
+
alias show_clients_for_channel show_clients_for_channels
|
107
|
+
|
108
|
+
def send_data(hash, response = false)
|
109
|
+
hash[:channels] = Array(hash[:channels]) if hash[:channels]
|
110
|
+
hash[:client_ids] = Array(hash[:client_ids]) if hash[:client_ids]
|
111
|
+
|
112
|
+
res = []
|
113
|
+
hosts.each do |address|
|
114
|
+
begin
|
115
|
+
hash[:secret_key] = address[:secret_key] if address[:secret_key]
|
116
|
+
|
117
|
+
@socket = TCPSocket.new(address[:host], address[:port])
|
118
|
+
# the \0 is to mirror flash
|
119
|
+
@socket.print(hash.to_json + Juggernaut::Server::CR)
|
120
|
+
@socket.flush
|
121
|
+
res << @socket.readline(Juggernaut::Server::CR) if response
|
122
|
+
ensure
|
123
|
+
@socket.close if @socket and !@socket.closed?
|
124
|
+
end
|
125
|
+
end
|
126
|
+
res.collect {|r| ActiveSupport::JSON.decode(r.chomp!(Juggernaut::Server::CR)) } if response
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
def hosts
|
132
|
+
Juggernaut::Rails.hosts
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Juggernaut # :nodoc:
|
2
|
+
module Rails
|
3
|
+
module Helpers
|
4
|
+
|
5
|
+
def juggernaut(options = {})
|
6
|
+
random_host = Juggernaut::Rails.random_host
|
7
|
+
options = {
|
8
|
+
:host => (random_host[:public_host] || random_host[:host]),
|
9
|
+
:port => (random_host[:public_port] || random_host[:port]),
|
10
|
+
:width => '0px',
|
11
|
+
:height => '0px',
|
12
|
+
:session_id => request.session_options[:id],
|
13
|
+
:swf_address => "/juggernaut/juggernaut.swf",
|
14
|
+
:ei_swf_address => "/juggernaut/expressinstall.swf",
|
15
|
+
:flash_version => 8,
|
16
|
+
:flash_color => "#fff",
|
17
|
+
:swf_name => "juggernaut_flash",
|
18
|
+
:bridge_name => "juggernaut",
|
19
|
+
:debug => (RAILS_ENV == 'development'),
|
20
|
+
:reconnect_attempts => 3,
|
21
|
+
:reconnect_intervals => 3
|
22
|
+
}.merge(options)
|
23
|
+
javascript_tag "new Juggernaut(#{options.to_json});"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Juggernaut::Rails
|
2
|
+
module RenderExtension
|
3
|
+
def self.included(base)
|
4
|
+
base.send :include, InstanceMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module InstanceMethods
|
8
|
+
# We can't protect these as ActionMailer complains
|
9
|
+
|
10
|
+
def render_with_juggernaut(options = nil, extra_options = {}, &block)
|
11
|
+
if options == :juggernaut or (options.is_a?(Hash) and options[:juggernaut])
|
12
|
+
begin
|
13
|
+
if @template.respond_to?(:_evaluate_assigns_and_ivars, true)
|
14
|
+
@template.send(:_evaluate_assigns_and_ivars)
|
15
|
+
else
|
16
|
+
@template.send(:evaluate_assigns)
|
17
|
+
end
|
18
|
+
|
19
|
+
generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(@template, &block)
|
20
|
+
render_for_juggernaut(generator.to_s, options.is_a?(Hash) ? options[:juggernaut] : nil)
|
21
|
+
ensure
|
22
|
+
erase_render_results
|
23
|
+
reset_variables_added_to_assigns
|
24
|
+
end
|
25
|
+
else
|
26
|
+
render_without_juggernaut(options, extra_options, &block)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def render_juggernaut(*args)
|
31
|
+
juggernaut_options = args.last.is_a?(Hash) ? args.pop : {}
|
32
|
+
render_for_juggernaut(render_to_string(*args), juggernaut_options)
|
33
|
+
end
|
34
|
+
|
35
|
+
def render_for_juggernaut(data, options = {})
|
36
|
+
if !options or !options.is_a?(Hash)
|
37
|
+
return Juggernaut.send_to_all(data)
|
38
|
+
end
|
39
|
+
|
40
|
+
case options[:type]
|
41
|
+
when :send_to_all
|
42
|
+
Juggernaut.send_to_all(data)
|
43
|
+
when :send_to_channels
|
44
|
+
juggernaut_needs options, :channels
|
45
|
+
Juggernaut.send_to_channels(data, options[:channels])
|
46
|
+
when :send_to_channel
|
47
|
+
juggernaut_needs options, :channel
|
48
|
+
Juggernaut.send_to_channel(data, options[:channel])
|
49
|
+
when :send_to_client
|
50
|
+
juggernaut_needs options, :client_id
|
51
|
+
Juggernaut.send_to_client(data, options[:client_id])
|
52
|
+
when :send_to_clients
|
53
|
+
juggernaut_needs options, :client_ids
|
54
|
+
Juggernaut.send_to_clients(data, options[:client_ids])
|
55
|
+
when :send_to_client_on_channel
|
56
|
+
juggernaut_needs options, :client_id, :channel
|
57
|
+
Juggernaut.send_to_clients_on_channel(data, options[:client_id], options[:channel])
|
58
|
+
when :send_to_clients_on_channel
|
59
|
+
juggernaut_needs options, :client_ids, :channel
|
60
|
+
Juggernaut.send_to_clients_on_channel(data, options[:client_ids], options[:channel])
|
61
|
+
when :send_to_client_on_channels
|
62
|
+
juggernaut_needs options, :client_ids, :channels
|
63
|
+
Juggernaut.send_to_clients_on_channel(data, options[:client_id], options[:channels])
|
64
|
+
when :send_to_clients_on_channels
|
65
|
+
juggernaut_needs options, :client_ids, :channels
|
66
|
+
Juggernaut.send_to_clients_on_channel(data, options[:client_ids], options[:channels])
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def juggernaut_needs(options, *args)
|
71
|
+
args.each do |a|
|
72
|
+
raise "You must specify #{a}" unless options[a]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'escape'
|
2
|
+
|
3
|
+
namespace :juggernaut do
|
4
|
+
desc "Install the Juggernaut js and swf files into your Rails application."
|
5
|
+
task :install => :environment do
|
6
|
+
require 'fileutils'
|
7
|
+
|
8
|
+
here = File.join(File.dirname(__FILE__), '../../../')
|
9
|
+
there = ::Rails.root
|
10
|
+
|
11
|
+
FileUtils.mkdir_p("#{there}/public/javascripts/juggernaut/")
|
12
|
+
FileUtils.mkdir_p("#{there}/public/juggernaut/")
|
13
|
+
|
14
|
+
puts "Installing Juggernaut..."
|
15
|
+
FileUtils.cp("#{here}/media/swfobject.js", "#{there}/public/javascripts/juggernaut/")
|
16
|
+
FileUtils.cp("#{here}/media/juggernaut.js", "#{there}/public/javascripts/juggernaut/")
|
17
|
+
FileUtils.cp("#{here}/media/juggernaut.swf", "#{there}/public/juggernaut/")
|
18
|
+
FileUtils.cp("#{here}/media/expressinstall.swf", "#{there}/public/juggernaut/")
|
19
|
+
|
20
|
+
FileUtils.cp("#{here}/media/juggernaut.yml", "#{there}/config/") unless File.exist?("#{there}/config/juggernaut.yml")
|
21
|
+
FileUtils.cp("#{here}/media/juggernaut_hosts.yml", "#{there}/config/") unless File.exist?("#{there}/config/juggernaut_hosts.yml")
|
22
|
+
puts "Juggernaut has been successfully installed."
|
23
|
+
puts
|
24
|
+
puts "Please refer to the readme file #{File.expand_path(here)}/README"
|
25
|
+
end
|
26
|
+
|
27
|
+
namespace :install do
|
28
|
+
desc "Install the Juggernaut jQuery JavaScript files into your Rails application."
|
29
|
+
task :jquery => :environment do
|
30
|
+
require 'fileutils'
|
31
|
+
|
32
|
+
here = File.join(File.dirname(__FILE__), '../../../')
|
33
|
+
there = ::Rails.root
|
34
|
+
|
35
|
+
FileUtils.cp("#{here}/media/jquerynaut.js", "#{there}/public/javascripts/juggernaut/")
|
36
|
+
FileUtils.cp("#{here}/media/json.js", "#{there}/public/javascripts/juggernaut/")
|
37
|
+
puts "Installed the Juggernaut jQuery JavaScript files to public/javascripts/juggernaut/"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
desc 'Compile the juggernaut flash file'
|
42
|
+
task :compile_flash do
|
43
|
+
`mtasc -version 8 -header 1:1:1 -main -swf media/juggernaut.swf media/juggernaut.as`
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "Start the Juggernaut server"
|
47
|
+
task 'start' => :environment do
|
48
|
+
run_juggernaut('-d')
|
49
|
+
end
|
50
|
+
|
51
|
+
desc "Stop the Juggernaut server"
|
52
|
+
task 'stop' => :environment do
|
53
|
+
run_juggernaut('-k')
|
54
|
+
end
|
55
|
+
|
56
|
+
def run_juggernaut(extra_options=[])
|
57
|
+
defaults = Juggernaut::Rails.default_options
|
58
|
+
extra_options = [extra_options] unless extra_options.is_a?(Array)
|
59
|
+
extra_options << '-e' if Rails.env.development?
|
60
|
+
FileUtils.cd(Rails.root) do
|
61
|
+
command = ['juggernaut', '-c', defaults[:config_path], '-P', defaults[:pid_path], '-l', defaults[:log_path]] + extra_options
|
62
|
+
ENV['RAILS_ENV'] = Rails.env.to_s
|
63
|
+
system(Escape.shell_command(command))
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,221 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'yaml'
|
3
|
+
require 'erb'
|
4
|
+
|
5
|
+
module Juggernaut
|
6
|
+
class Runner
|
7
|
+
include Juggernaut::Miscel
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def run(argv = ARGV)
|
11
|
+
self.new(argv)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(argv = ARGV)
|
16
|
+
self.options = {
|
17
|
+
:host => "0.0.0.0",
|
18
|
+
:port => 5001,
|
19
|
+
:debug => false,
|
20
|
+
:cleanup_timer => 2,
|
21
|
+
:timeout => 10,
|
22
|
+
:store_messages => false
|
23
|
+
}
|
24
|
+
|
25
|
+
self.options.merge!({
|
26
|
+
:pid_path => pid_path,
|
27
|
+
:log_path => log_path,
|
28
|
+
:config_path => config_path
|
29
|
+
})
|
30
|
+
|
31
|
+
parse_options(argv)
|
32
|
+
|
33
|
+
if !File.exists?(config_path)
|
34
|
+
puts "You must generate a config file (juggernaut -g filename.yml or rake juggernaut:install)"
|
35
|
+
exit
|
36
|
+
end
|
37
|
+
|
38
|
+
config_options = YAML::load(ERB.new(IO.read(config_path)).result)
|
39
|
+
config_options = config_options[ENV['RAILS_ENV']] if config_options.has_key?(ENV['RAILS_ENV'])
|
40
|
+
options.merge!(config_options)
|
41
|
+
|
42
|
+
if options.include?(:kill)
|
43
|
+
kill_pid(options[:kill] || '*')
|
44
|
+
end
|
45
|
+
|
46
|
+
Process.euid = options[:user] if options[:user]
|
47
|
+
Process.egid = options[:group] if options[:group]
|
48
|
+
|
49
|
+
if !options[:daemonize]
|
50
|
+
start
|
51
|
+
else
|
52
|
+
daemonize
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def start
|
57
|
+
puts "Starting Juggernaut server #{Juggernaut::VERSION} on port: #{options[:port]}..."
|
58
|
+
|
59
|
+
trap("INT") {
|
60
|
+
stop
|
61
|
+
exit
|
62
|
+
}
|
63
|
+
trap("TERM"){
|
64
|
+
stop
|
65
|
+
exit
|
66
|
+
}
|
67
|
+
|
68
|
+
if options[:descriptor_table_size]
|
69
|
+
EM.epoll
|
70
|
+
new_size = EM.set_descriptor_table_size( options[:descriptor_table_size] )
|
71
|
+
logger.debug "New descriptor-table size is #{new_size}"
|
72
|
+
end
|
73
|
+
|
74
|
+
EventMachine::run {
|
75
|
+
EventMachine::add_periodic_timer( options[:cleanup_timer] || 2 ) { Juggernaut::Client.send_logouts_after_timeout }
|
76
|
+
EventMachine::start_server(options[:host], options[:port].to_i, Juggernaut::Server)
|
77
|
+
EM.set_effective_user( options[:user] ) if options[:user]
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
def stop
|
82
|
+
puts "Stopping Juggernaut server"
|
83
|
+
Juggernaut::Client.send_logouts_to_all_clients
|
84
|
+
EventMachine::stop
|
85
|
+
end
|
86
|
+
|
87
|
+
def parse_options(argv)
|
88
|
+
OptionParser.new do |opts|
|
89
|
+
opts.summary_width = 25
|
90
|
+
opts.banner = "Juggernaut (#{VERSION})\n\n",
|
91
|
+
"Usage: juggernaut [-h host] [-p port] [-P file]\n",
|
92
|
+
" [-d] [-k port] [-l file] [-e]\n",
|
93
|
+
" juggernaut --help\n",
|
94
|
+
" juggernaut --version\n"
|
95
|
+
|
96
|
+
opts.separator ""
|
97
|
+
opts.separator ""; opts.separator "Configuration:"
|
98
|
+
|
99
|
+
opts.on("-g", "--generate FILE", String, "Generate config file", "(default: #{options[:config_path]})") do |v|
|
100
|
+
options[:config_path] = File.expand_path(v) if v
|
101
|
+
generate_config_file
|
102
|
+
end
|
103
|
+
|
104
|
+
opts.on("-c", "--config FILE", String, "Path to configuration file.", "(default: #{options[:config_path]})") do |v|
|
105
|
+
options[:config_path] = File.expand_path(v)
|
106
|
+
end
|
107
|
+
|
108
|
+
opts.separator ""; opts.separator "Network:"
|
109
|
+
|
110
|
+
opts.on("-h", "--host HOST", String, "Specify host", "(default: #{options[:host]})") do |v|
|
111
|
+
options[:host] = v
|
112
|
+
end
|
113
|
+
|
114
|
+
opts.on("-p", "--port PORT", Integer, "Specify port", "(default: #{options[:port]})") do |v|
|
115
|
+
options[:port] = v
|
116
|
+
end
|
117
|
+
|
118
|
+
opts.on("-s", "--fdsize SIZE", Integer, "Set the file descriptor size an user epoll() on Linux", "(default: use select() which is limited to 1024 clients)") do |v|
|
119
|
+
options[:descriptor_table_size] = v
|
120
|
+
end
|
121
|
+
|
122
|
+
opts.separator ""; opts.separator "Daemonization:"
|
123
|
+
|
124
|
+
opts.on("-P", "--pid FILE", String, "save PID in FILE when using -d option.", "(default: #{options[:pid_path]})") do |v|
|
125
|
+
options[:pid_path] = File.expand_path(v)
|
126
|
+
end
|
127
|
+
|
128
|
+
opts.on("-d", "--daemon", "Daemonize mode") do |v|
|
129
|
+
options[:daemonize] = v
|
130
|
+
end
|
131
|
+
|
132
|
+
opts.on("-k", "--kill PORT", String, :OPTIONAL, "Kill specified running daemons - leave blank to kill all.") do |v|
|
133
|
+
options[:kill] = v
|
134
|
+
end
|
135
|
+
|
136
|
+
opts.separator ""; opts.separator "Logging:"
|
137
|
+
|
138
|
+
opts.on("-l", "--log [FILE]", String, "Path to print debugging information.", "(default: #{options[:log_path]})") do |v|
|
139
|
+
options[:log_path] = File.expand_path(v)
|
140
|
+
end
|
141
|
+
|
142
|
+
opts.on("-e", "--debug", "Run in debug mode", "(default: #{options[:debug]})") do |v|
|
143
|
+
options[:debug] = v
|
144
|
+
end
|
145
|
+
|
146
|
+
opts.separator ""; opts.separator "Permissions:"
|
147
|
+
|
148
|
+
opts.on("-u", "--user USER", Integer, "User to run as") do |user|
|
149
|
+
options[:user] = user
|
150
|
+
end
|
151
|
+
|
152
|
+
opts.on("-G", "--group GROUP", String, "Group to run as") do |group|
|
153
|
+
options[:group] = group
|
154
|
+
end
|
155
|
+
|
156
|
+
opts.separator ""; opts.separator "Miscellaneous:"
|
157
|
+
|
158
|
+
opts.on_tail("-?", "--help", "Display this usage information.") do
|
159
|
+
puts "#{opts}\n"
|
160
|
+
exit
|
161
|
+
end
|
162
|
+
|
163
|
+
opts.on_tail("-v", "--version", "Display version") do |v|
|
164
|
+
puts "Juggernaut #{VERSION}"
|
165
|
+
exit
|
166
|
+
end
|
167
|
+
end.parse!(argv)
|
168
|
+
options
|
169
|
+
end
|
170
|
+
|
171
|
+
private
|
172
|
+
|
173
|
+
def generate_config_file
|
174
|
+
if File.exists?(config_path)
|
175
|
+
puts "Config file already exists. You must remove it before generating a new one."
|
176
|
+
exit
|
177
|
+
end
|
178
|
+
puts "Generating config file...."
|
179
|
+
File.open(config_path, 'w+') do |file|
|
180
|
+
file.write DEFAULT_CONFIG_FILE.gsub('your_secret_key_here', Digest::SHA1.hexdigest("--#{Time.now.to_s.split(//).sort_by {rand}.join}--"))
|
181
|
+
end
|
182
|
+
puts "Config file generated at #{config_path}"
|
183
|
+
exit
|
184
|
+
end
|
185
|
+
|
186
|
+
def store_pid(pid)
|
187
|
+
FileUtils.mkdir_p(File.dirname(pid_path))
|
188
|
+
File.open(pid_path, 'w'){|f| f.write("#{pid}\n")}
|
189
|
+
end
|
190
|
+
|
191
|
+
def kill_pid(k)
|
192
|
+
Dir[options[:pid_path]||File.join(File.dirname(pid_dir), "juggernaut.#{k}.pid")].each do |f|
|
193
|
+
begin
|
194
|
+
puts f
|
195
|
+
pid = IO.read(f).chomp.to_i
|
196
|
+
FileUtils.rm f
|
197
|
+
Process.kill(9, pid)
|
198
|
+
puts "killed PID: #{pid}"
|
199
|
+
rescue => e
|
200
|
+
puts "Failed to kill! #{k}: #{e}"
|
201
|
+
end
|
202
|
+
end
|
203
|
+
exit
|
204
|
+
end
|
205
|
+
|
206
|
+
def daemonize
|
207
|
+
fork do
|
208
|
+
Process.setsid
|
209
|
+
exit if fork
|
210
|
+
store_pid(Process.pid)
|
211
|
+
# Dir.chdir "/" # Mucks up logs
|
212
|
+
File.umask 0000
|
213
|
+
STDIN.reopen "/dev/null"
|
214
|
+
STDOUT.reopen "/dev/null", "a"
|
215
|
+
STDERR.reopen STDOUT
|
216
|
+
start
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
end
|
221
|
+
end
|