stompserver_ng 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +159 -0
- data/Manifest.txt +71 -0
- data/README.txt +172 -0
- data/Rakefile +38 -0
- data/STATUS +5 -0
- data/bin/stompserver_ng +63 -0
- data/client/README.txt +1 -0
- data/client/both.rb +25 -0
- data/client/consume.rb +14 -0
- data/client/send.rb +17 -0
- data/config/stompserver_ng.conf +11 -0
- data/etc/19xcompat/notes.txt +223 -0
- data/etc/arutils/README-activerecord.txt +78 -0
- data/etc/arutils/cre_mysql.rb +34 -0
- data/etc/arutils/cre_postgres.rb +33 -0
- data/etc/arutils/cre_sqlite3.rb +28 -0
- data/etc/arutils/mysql_boot.sql +12 -0
- data/etc/arutils/postgres_boot.sql +14 -0
- data/etc/database.mysql.yml +9 -0
- data/etc/database.postgres.yml +9 -0
- data/etc/passwd.example +3 -0
- data/etc/ppqinfo.rb +15 -0
- data/etc/runserver.sh +17 -0
- data/etc/stompserver_ng +50 -0
- data/etc/stompserver_ng.conf +13 -0
- data/lib/stomp_server_ng.rb +471 -0
- data/lib/stomp_server_ng/protocols/http.rb +128 -0
- data/lib/stomp_server_ng/protocols/stomp.rb +407 -0
- data/lib/stomp_server_ng/qmonitor.rb +58 -0
- data/lib/stomp_server_ng/queue.rb +248 -0
- data/lib/stomp_server_ng/queue/activerecord_queue.rb +118 -0
- data/lib/stomp_server_ng/queue/ar_message.rb +21 -0
- data/lib/stomp_server_ng/queue/ar_reconnect.rb +18 -0
- data/lib/stomp_server_ng/queue/dbm_queue.rb +72 -0
- data/lib/stomp_server_ng/queue/file_queue.rb +56 -0
- data/lib/stomp_server_ng/queue/memory_queue.rb +64 -0
- data/lib/stomp_server_ng/queue_manager.rb +302 -0
- data/lib/stomp_server_ng/stomp_auth.rb +26 -0
- data/lib/stomp_server_ng/stomp_frame.rb +32 -0
- data/lib/stomp_server_ng/stomp_frame_recognizer.rb +77 -0
- data/lib/stomp_server_ng/stomp_id.rb +32 -0
- data/lib/stomp_server_ng/stomp_user.rb +17 -0
- data/lib/stomp_server_ng/test_server.rb +21 -0
- data/lib/stomp_server_ng/topic_manager.rb +46 -0
- data/setup.rb +1585 -0
- data/stompserver_ng.gemspec +136 -0
- data/test/devserver/props.yaml +5 -0
- data/test/devserver/runserver.sh +16 -0
- data/test/devserver/stompserver_ng.dbm.conf +12 -0
- data/test/devserver/stompserver_ng.file.conf +12 -0
- data/test/devserver/stompserver_ng.memory.conf +12 -0
- data/test/noserver/mocklogger.rb +12 -0
- data/test/noserver/test_queue_manager.rb +134 -0
- data/test/noserver/test_stomp_frame.rb +138 -0
- data/test/noserver/test_topic_manager.rb +79 -0
- data/test/noserver/ts_all_no_server.rb +12 -0
- data/test/props.yaml +5 -0
- data/test/runalltests.sh +14 -0
- data/test/runtest.sh +4 -0
- data/test/test_0000_base.rb +107 -0
- data/test/test_0001_conn.rb +47 -0
- data/test/test_0002_conn_sr.rb +94 -0
- data/test/test_0006_client.rb +41 -0
- data/test/test_0011_send_recv.rb +74 -0
- data/test/test_0015_ack_conn.rb +78 -0
- data/test/test_0017_ack_client.rb +78 -0
- data/test/test_0019_ack_no_ack.rb +145 -0
- data/test/test_0022_ack_noack_conn.rb +123 -0
- data/test/test_0030_subscr_id.rb +44 -0
- data/test/test_0040_receipt_conn.rb +87 -0
- data/test/ts_all_server.rb +10 -0
- metadata +196 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rubygems' if RUBY_VERSION =~ /1.8/
|
2
|
+
require 'active_record'
|
3
|
+
#
|
4
|
+
# = cre_postgres - create a postgres data base for use by stompserver_ng
|
5
|
+
#
|
6
|
+
# For now, the db parameters are hard coded. Change as required.
|
7
|
+
#
|
8
|
+
db_params = {
|
9
|
+
'adapter' => 'postgresql',
|
10
|
+
'encoding' => 'utf8',
|
11
|
+
'database' => 'ssng_dev',
|
12
|
+
'pool' => 5,
|
13
|
+
'username' => 'ssng',
|
14
|
+
'password' => 'xxxxxxxx',
|
15
|
+
'host' => 'localhost',
|
16
|
+
'port' => 5432
|
17
|
+
}
|
18
|
+
#
|
19
|
+
# Connect.
|
20
|
+
#
|
21
|
+
ActiveRecord::Base.establish_connection(db_params)
|
22
|
+
puts "postgres Connection complete."
|
23
|
+
#
|
24
|
+
# Define the ar_messages table.
|
25
|
+
#
|
26
|
+
ActiveRecord::Schema.define do
|
27
|
+
create_table 'ar_messages' do |t|
|
28
|
+
t.column 'stomp_id', :string, :null => false
|
29
|
+
t.column 'frame', :text, :null => false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
puts "postgres table create complete."
|
33
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rubygems' if RUBY_VERSION =~ /1.8/
|
2
|
+
require 'active_record'
|
3
|
+
#
|
4
|
+
# = cre_sqlite3 - create an sqlite3 data base for use by stompserver_ng
|
5
|
+
#
|
6
|
+
# For now, the db parameters are hard coded. Change as required.
|
7
|
+
# Note: directory structure should already exist.
|
8
|
+
#
|
9
|
+
db_params = {
|
10
|
+
'adapter' => 'sqlite3',
|
11
|
+
'database' => "/tmp/stompserver/etc/stompserver_development"
|
12
|
+
}
|
13
|
+
#
|
14
|
+
# Connect.
|
15
|
+
#
|
16
|
+
ActiveRecord::Base.establish_connection(db_params)
|
17
|
+
puts "sqlite3 Connection complete."
|
18
|
+
#
|
19
|
+
# Define the ar_messages table.
|
20
|
+
#
|
21
|
+
ActiveRecord::Schema.define do
|
22
|
+
create_table 'ar_messages' do |t|
|
23
|
+
t.column 'stomp_id', :string, :null => false
|
24
|
+
t.column 'frame', :text, :null => false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
puts "sqlite3 table create complete."
|
28
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
--
|
2
|
+
--
|
3
|
+
-- This might depend on your mysql set up:
|
4
|
+
--
|
5
|
+
-- * mysql -u root -p mysql < mysql_boot.sql
|
6
|
+
--
|
7
|
+
CREATE USER 'ssng'@'localhost' IDENTIFIED BY 'xxxxxxxx';
|
8
|
+
GRANT ALL PRIVILEGES ON ssng_dev.* TO 'ssng'@'localhost' WITH GRANT OPTION;
|
9
|
+
GRANT ALL PRIVILEGES ON ssng_dev.* TO 'ssng'@'%' WITH GRANT OPTION;
|
10
|
+
--
|
11
|
+
CREATE DATABASE ssng_dev;
|
12
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
--
|
2
|
+
-- This probably depends on your postgres setup:
|
3
|
+
-- * su - postgres
|
4
|
+
-- * (enter password if necessary)
|
5
|
+
-- * psql < postgres_boot.sql
|
6
|
+
--
|
7
|
+
-- Create the user/role.
|
8
|
+
--
|
9
|
+
CREATE ROLE ssng LOGIN PASSWORD 'xxxxxxxx';
|
10
|
+
--
|
11
|
+
-- And the data base.
|
12
|
+
--
|
13
|
+
CREATE DATABASE ssng_dev OWNER ssng;
|
14
|
+
|
data/etc/passwd.example
ADDED
data/etc/ppqinfo.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'pp'
|
2
|
+
#
|
3
|
+
# Pretty print the queue information file.
|
4
|
+
#
|
5
|
+
# Sample Use:
|
6
|
+
#
|
7
|
+
# ruby etc/ppqinfo.rb /ad3/tmp/stompserver/.queue/qinfo
|
8
|
+
#
|
9
|
+
qfile = ARGV[0]
|
10
|
+
qinfo = nil
|
11
|
+
File.open(qfile) do |f|
|
12
|
+
qinfo = Marshal.load(f)
|
13
|
+
end
|
14
|
+
pp qinfo
|
15
|
+
|
data/etc/runserver.sh
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
cd /home/stompserver_ng
|
3
|
+
>stompserver.log
|
4
|
+
echo Start >>stompserver.log
|
5
|
+
x=$(ruby -v)
|
6
|
+
echo $x >>stompserver.log
|
7
|
+
#
|
8
|
+
# Set command line options.
|
9
|
+
#
|
10
|
+
sopts="$*"
|
11
|
+
#
|
12
|
+
# Start the server.
|
13
|
+
#
|
14
|
+
echo Start server >>stompserver.log
|
15
|
+
stompserver_ng $sopts
|
16
|
+
set +x
|
17
|
+
exit 0
|
data/etc/stompserver_ng
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
### BEGIN INIT INFO
|
3
|
+
# Provides: stompserver_ng
|
4
|
+
# Required-Start: $syslog
|
5
|
+
# Required-Stop: $syslog
|
6
|
+
# Default-Start: 2 3 4 5
|
7
|
+
# Default-Stop: 0 1 6
|
8
|
+
# Short-Description: Start/stop the stompserver_ng gem
|
9
|
+
### END INIT INFO
|
10
|
+
#
|
11
|
+
NAME=stompserver_ng
|
12
|
+
DESC="stompserver_ng ruby gem"
|
13
|
+
#
|
14
|
+
NAMEHOME=/home/$NAME
|
15
|
+
#
|
16
|
+
CONFIGFILE="$NAMEHOME/$NAME.conf"
|
17
|
+
STOMPCMD="$NAMEHOME/bin/runserver.sh"
|
18
|
+
#
|
19
|
+
WORKDIR=$(grep "working_dir" $CONFIGFILE | cut -d" " -f2)
|
20
|
+
PIDFILE="$WORKDIR/$NAME.pid"
|
21
|
+
#
|
22
|
+
EXTRA_OPTS="--daemon --session_cache=25 -C $CONFIGFILE"
|
23
|
+
EXTRA_OPTS="${EXTRA_OPTS} ${STOMP_OPTS}"
|
24
|
+
#
|
25
|
+
set -e
|
26
|
+
# set -x
|
27
|
+
#
|
28
|
+
case "$1" in
|
29
|
+
start)
|
30
|
+
echo -n "Starting $DESC: "
|
31
|
+
test -f /var/tmp/ruby-uuid && rm /var/tmp/ruby-uuid
|
32
|
+
test -d $WORKDIR && rm -rf $WORKDIR
|
33
|
+
su -l $NAME -c "$STOMPCMD $EXTRA_OPTS"
|
34
|
+
echo "$NAME."
|
35
|
+
;;
|
36
|
+
stop)
|
37
|
+
echo -n "Stopping $DESC: "
|
38
|
+
pid=$(ps -ef | grep -i stompserver | grep -i ruby |awk '{print $2}')
|
39
|
+
kill $pid
|
40
|
+
echo "$NAME."
|
41
|
+
;;
|
42
|
+
*)
|
43
|
+
echo "Usage: $0 { start | stop }" >&2
|
44
|
+
exit 1
|
45
|
+
;;
|
46
|
+
esac
|
47
|
+
#
|
48
|
+
# set +x
|
49
|
+
exit 0
|
50
|
+
|
@@ -0,0 +1,471 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'eventmachine'
|
3
|
+
require 'uuid'
|
4
|
+
require 'stomp_server_ng/stomp_frame'
|
5
|
+
require 'stomp_server_ng/stomp_frame_recognizer'
|
6
|
+
require 'stomp_server_ng/stomp_id'
|
7
|
+
require 'stomp_server_ng/stomp_auth'
|
8
|
+
require 'stomp_server_ng/topic_manager'
|
9
|
+
require 'stomp_server_ng/queue_manager'
|
10
|
+
require 'stomp_server_ng/qmonitor'
|
11
|
+
require 'stomp_server_ng/queue'
|
12
|
+
require 'stomp_server_ng/queue/memory_queue'
|
13
|
+
require 'stomp_server_ng/queue/file_queue'
|
14
|
+
require 'stomp_server_ng/queue/dbm_queue'
|
15
|
+
require 'stomp_server_ng/protocols/stomp'
|
16
|
+
require 'logger'
|
17
|
+
|
18
|
+
module StompServer
|
19
|
+
VERSION = '1.0.6'
|
20
|
+
#
|
21
|
+
# session ID cache manager
|
22
|
+
#
|
23
|
+
class SessionIDManager
|
24
|
+
#
|
25
|
+
@@session_cache = nil
|
26
|
+
#
|
27
|
+
@@generator = nil
|
28
|
+
#
|
29
|
+
def self.initialize_cache(requested_size)
|
30
|
+
#
|
31
|
+
return [] if requested_size <= 0
|
32
|
+
#
|
33
|
+
@@session_cache = @@session_cache || []
|
34
|
+
#
|
35
|
+
if not @@generator
|
36
|
+
UUID::state_file = "./.temp_uuid_state"
|
37
|
+
@@generator = UUID::new()
|
38
|
+
end
|
39
|
+
#
|
40
|
+
return @@session_cache if @@session_cache.size > requested_size
|
41
|
+
#
|
42
|
+
(requested_size - @@session_cache.size).times do
|
43
|
+
@@session_cache << @@generator.generate
|
44
|
+
end
|
45
|
+
end
|
46
|
+
#
|
47
|
+
def self.get_cache_id(requested_size)
|
48
|
+
session_id = @@session_cache.pop
|
49
|
+
initialize_cache(requested_size) if @@session_cache.size == 0
|
50
|
+
session_id
|
51
|
+
end
|
52
|
+
#
|
53
|
+
def self.dump_cache(logger)
|
54
|
+
logger.debug("Session ID Dump:")
|
55
|
+
@@session_cache.each do |sessid|
|
56
|
+
logger.debug("#{sessid}")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
#
|
61
|
+
# Ruby Logger Level Handler.
|
62
|
+
#
|
63
|
+
class LogHelper
|
64
|
+
#
|
65
|
+
# Set the desired logger level.
|
66
|
+
#
|
67
|
+
def self.set_loglevel(opts)
|
68
|
+
@@loglevel = nil
|
69
|
+
case opts[:log_level].downcase
|
70
|
+
when 'debug' then @@loglevel = Logger::DEBUG
|
71
|
+
when 'info' then @@loglevel = Logger::INFO
|
72
|
+
when 'warn' then @@loglevel = Logger::WARN
|
73
|
+
when 'error' then @@loglevel = Logger::ERROR
|
74
|
+
else
|
75
|
+
@@loglevel = Logger::ERROR
|
76
|
+
end
|
77
|
+
end
|
78
|
+
#
|
79
|
+
# Return the desired logging level.
|
80
|
+
#
|
81
|
+
def self.get_loglevel
|
82
|
+
@@loglevel
|
83
|
+
end
|
84
|
+
#
|
85
|
+
# Display ruby version information on a defined logger output
|
86
|
+
# destination.
|
87
|
+
#
|
88
|
+
def self.showversion(logger)
|
89
|
+
# stompserver version
|
90
|
+
logger.debug "stomp_server version: #{StompServer::VERSION}"
|
91
|
+
# ruby version for all versions
|
92
|
+
logger.debug "ruby: ver=#{RUBY_VERSION}p#{RUBY_PATCHLEVEL} (reldate=#{RUBY_RELEASE_DATE})"
|
93
|
+
# more ruby version information for 1.9+
|
94
|
+
if RUBY_VERSION =~ /1.9/
|
95
|
+
logger.debug "ruby: rev=#{RUBY_REVISION} engine=#{RUBY_ENGINE}"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
#
|
99
|
+
# Clean logging of all options values.
|
100
|
+
#
|
101
|
+
def self.showoptions(logger, opts)
|
102
|
+
logger.debug("Options Display Starts")
|
103
|
+
# This is ugly, but it should only happen once at startup ......
|
104
|
+
if RUBY_VERSION =~ /1.8/
|
105
|
+
opts.keys.map {|key| key.to_s}.sort.each do |str_opt|
|
106
|
+
optname = str_opt.to_sym
|
107
|
+
logger.debug("Option: #{optname}=#{opts[optname]}")
|
108
|
+
end
|
109
|
+
else # 1.9 version
|
110
|
+
opts.keys.sort.each do |optname|
|
111
|
+
logger.debug("Option: #{optname}=#{opts[optname]}")
|
112
|
+
end
|
113
|
+
end
|
114
|
+
logger.debug("Options Display Ends")
|
115
|
+
end
|
116
|
+
#
|
117
|
+
# Show load path
|
118
|
+
#
|
119
|
+
def self.showloadpath(logger)
|
120
|
+
return unless @@loglevel == Logger::DEBUG
|
121
|
+
pos = 1
|
122
|
+
$:.each do |lp|
|
123
|
+
logger.debug("#{pos} #{lp}")
|
124
|
+
pos += 1
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end # of class LogHelper
|
128
|
+
#
|
129
|
+
# Module level configuration
|
130
|
+
#
|
131
|
+
class Configurator
|
132
|
+
|
133
|
+
# The final options, merged from the defaults, the config file, and the
|
134
|
+
# command line.
|
135
|
+
#--
|
136
|
+
# Should this be 'read' only after construction ????
|
137
|
+
attr_accessor :opts
|
138
|
+
|
139
|
+
def initialize
|
140
|
+
|
141
|
+
@opts = nil
|
142
|
+
@defaults = {
|
143
|
+
#
|
144
|
+
# For clarity maintain the same order here as below in the 'getopts'
|
145
|
+
# method!!!!
|
146
|
+
#
|
147
|
+
:auth => false, # -a
|
148
|
+
:host => "127.0.0.1", # -b
|
149
|
+
:checkpoint => 0, # -c
|
150
|
+
:config => 'stompserver.conf', # -C
|
151
|
+
:debug => false, # -d
|
152
|
+
:logdir => 'log', # -D
|
153
|
+
:log_level => 'error', # -l
|
154
|
+
:logfile => 'stompserver.log', # -L
|
155
|
+
:port => 61613, # -p
|
156
|
+
:pidfile => 'stompserver.pid', # -P
|
157
|
+
:queue => 'memory', # -q
|
158
|
+
:storage => ".stompserver", # -s
|
159
|
+
:session_cache => 0, # -S
|
160
|
+
:working_dir => Dir.getwd, # -w
|
161
|
+
:dbyml => 'database.yml', # -y
|
162
|
+
:daemon => false # -z
|
163
|
+
}
|
164
|
+
# Get a crude logger
|
165
|
+
@@log = Logger.new(STDOUT)
|
166
|
+
|
167
|
+
# Show version numbers regardless
|
168
|
+
StompServer::LogHelper.showversion(@@log)
|
169
|
+
|
170
|
+
# Options handling
|
171
|
+
@opts = getopts() # get and merge the options
|
172
|
+
|
173
|
+
# Finalize logger level handling
|
174
|
+
@@log.debug "Logger Level Requested: #{@opts[:log_level].upcase}"
|
175
|
+
StompServer::LogHelper.set_loglevel(@opts)
|
176
|
+
|
177
|
+
# Show Load Path
|
178
|
+
StompServer::LogHelper.showloadpath(@@log)
|
179
|
+
|
180
|
+
@@log.level = StompServer::LogHelper.get_loglevel()
|
181
|
+
|
182
|
+
# Turn on $DEBUG for extra debugging info if requested
|
183
|
+
if opts[:debug]
|
184
|
+
$DEBUG=true
|
185
|
+
@@log.debug "-d / --debug set, $DEBUG is true"
|
186
|
+
end
|
187
|
+
|
188
|
+
# Configuration is complete!
|
189
|
+
@@log.debug("#{self.class} Configuration complete")
|
190
|
+
end
|
191
|
+
|
192
|
+
def getopts()
|
193
|
+
|
194
|
+
# New Options Parser
|
195
|
+
opts_parser = OptionParser.new
|
196
|
+
|
197
|
+
# Empty Hash for parser values
|
198
|
+
hopts = {}
|
199
|
+
|
200
|
+
# :auth
|
201
|
+
opts_parser.on("-a", "--auth", String,
|
202
|
+
"Require client authorization") {|a|
|
203
|
+
hopts[:auth] = true}
|
204
|
+
|
205
|
+
# :host
|
206
|
+
opts_parser.on("-b", "--host=ADDR", String,
|
207
|
+
"Change the host (default: localhost)") {|a|
|
208
|
+
hopts[:host] = a}
|
209
|
+
|
210
|
+
# :checkpoint
|
211
|
+
opts_parser.on("-c", "--checkpoint=SECONDS", Integer,
|
212
|
+
"Time between checkpointing the queues in seconds (default: 0)") {|c|
|
213
|
+
hopts[:checkpoint] = c}
|
214
|
+
|
215
|
+
# :config
|
216
|
+
opts_parser.on("-C", "--config=CONFIGFILE", String,
|
217
|
+
"Configuration File (default: stompserver.conf)") {|c|
|
218
|
+
hopts[:config] = c}
|
219
|
+
|
220
|
+
# :debug
|
221
|
+
opts_parser.on("-d", "--debug", String,
|
222
|
+
"Turn on debug messages") {|d|
|
223
|
+
hopts[:debug] = true}
|
224
|
+
|
225
|
+
# :logdir
|
226
|
+
opts_parser.on("-D", "--logdir=LOGDIR", String,
|
227
|
+
"Log file directory (default: log)") {|d|
|
228
|
+
hopts[:logdir] = d} # new
|
229
|
+
|
230
|
+
# :log_level
|
231
|
+
opts_parser.on("-l", "--log_level=LEVEL", String,
|
232
|
+
"Logger Level (default: ERROR)") {|l|
|
233
|
+
hopts[:log_level] = l}
|
234
|
+
|
235
|
+
# :logfile
|
236
|
+
opts_parser.on("-L", "--logfile=LOGFILE", String,
|
237
|
+
"Log file name (default: stompserver.log") {|l|
|
238
|
+
hopts[:logfile] = l} # new
|
239
|
+
|
240
|
+
# :port
|
241
|
+
opts_parser.on("-p", "--port=PORT", Integer,
|
242
|
+
"Change the port (default: 61613)") {|p|
|
243
|
+
hopts[:port] = p}
|
244
|
+
|
245
|
+
# :pidfile
|
246
|
+
opts_parser.on("-P", "--pidfile=PIDFILE", Integer,
|
247
|
+
"PID file name (default: stompserver.pid)") {|p|
|
248
|
+
hopts[:pidfile] = p} # new
|
249
|
+
|
250
|
+
# :queue
|
251
|
+
opts_parser.on("-q", "--queuetype=QUEUETYPE", String,
|
252
|
+
"Queue type (memory|dbm|activerecord|file) (default: memory)") {|q|
|
253
|
+
hopts[:queue] = q}
|
254
|
+
|
255
|
+
# :storage
|
256
|
+
opts_parser.on("-s", "--storage=DIR", String,
|
257
|
+
"Change the storage directory (default: .stompserver, relative to working_dir)") {|s|
|
258
|
+
hopts[:storage] = s}
|
259
|
+
|
260
|
+
# :session_cache
|
261
|
+
opts_parser.on("-S", "--session_cache=SIZE", Integer,
|
262
|
+
"session ID cache size (default: 0, disable session ID cache)") {|s|
|
263
|
+
hopts[:session_cache] = s}
|
264
|
+
|
265
|
+
# :working_dir
|
266
|
+
opts_parser.on("-w", "--working_dir=DIR", String,
|
267
|
+
"Change the working directory (default: current directory)") {|s|
|
268
|
+
hopts[:working_dir] = s}
|
269
|
+
|
270
|
+
# :dbyml
|
271
|
+
opts_parser.on("-y", "--dbyml=YMLFILE", String,
|
272
|
+
"Database .yml file name (default: database.yml)") {|y|
|
273
|
+
hopts[:dbyml] = y}
|
274
|
+
|
275
|
+
# :daemon
|
276
|
+
opts_parser.on("-z", "--daemon", String,
|
277
|
+
"Daemonize server process") {|d|
|
278
|
+
hopts[:daemon] = true}
|
279
|
+
|
280
|
+
# Handle help if required
|
281
|
+
opts_parser.on("-h", "--help", "Show this message") do
|
282
|
+
puts opts_parser
|
283
|
+
exit
|
284
|
+
end
|
285
|
+
|
286
|
+
opts_parser.parse(ARGV)
|
287
|
+
|
288
|
+
# Handle the config file
|
289
|
+
config_found = false
|
290
|
+
# Load a default config file first if it exists.
|
291
|
+
loaded_opts = {}
|
292
|
+
full_path_default = File.expand_path(@defaults[:config])
|
293
|
+
if File.exists?(full_path_default)
|
294
|
+
@@log.debug("Loading config file defaults from: #{full_path_default}")
|
295
|
+
loaded_opts.merge!(YAML.load_file(full_path_default))
|
296
|
+
@defaults[:config] = full_path_default
|
297
|
+
config_found = true
|
298
|
+
end
|
299
|
+
# If a command line specified config file exists, overlay any new
|
300
|
+
# parameters in that file.
|
301
|
+
if hopts[:config]
|
302
|
+
full_path_cl = File.expand_path(hopts[:config])
|
303
|
+
if File.exists?(full_path_cl)
|
304
|
+
@@log.debug("Loading config file overrides from: #{full_path_cl}")
|
305
|
+
loaded_opts.merge!(YAML.load_file(full_path_cl))
|
306
|
+
hopts[:config] = full_path_cl
|
307
|
+
config_found = true
|
308
|
+
end
|
309
|
+
end
|
310
|
+
@@log.warn("No configuration file found.") unless config_found
|
311
|
+
|
312
|
+
# Run basic required merges on all the options
|
313
|
+
opts = {} # set to empty
|
314
|
+
opts = opts.merge(@defaults) # 01 = merge in defaults
|
315
|
+
opts = opts.merge(loaded_opts) # 02 = merge in loaded from config file
|
316
|
+
opts = opts.merge(hopts) # 03 = merge in command line options
|
317
|
+
|
318
|
+
# Last but not least: Miscellaneous file definitions
|
319
|
+
opts[:etcdir] = File.join(opts[:working_dir],'etc') # Define ':etcdir'
|
320
|
+
opts[:storage] = File.join(opts[:working_dir],opts[:storage]) # Override! ':storage'
|
321
|
+
opts[:logdir] = File.join(opts[:working_dir],opts[:logdir]) # Override! ':logdir'
|
322
|
+
opts[:logfile] = File.join(opts[:logdir],opts[:logfile]) # Override! ':logfile'
|
323
|
+
opts[:pidfile] = File.join(opts[:logdir],opts[:pidfile]) # Override! ':pidfile'
|
324
|
+
# :dbyml will be a full path and file name
|
325
|
+
unless File.exists?(File.expand_path(opts[:dbyml]))
|
326
|
+
opts[:dbyml] = File.join(opts[:etcdir],opts[:dbyml]) # Override! ':dbyml'
|
327
|
+
else
|
328
|
+
opts[:dbyml] = File.expand_path(opts[:dbyml])
|
329
|
+
end
|
330
|
+
|
331
|
+
# Authorization - working file
|
332
|
+
if opts[:auth]
|
333
|
+
opts[:passwd] = File.join(opts[:etcdir],'.passwd')
|
334
|
+
end
|
335
|
+
|
336
|
+
# Return merged values (in Hash)
|
337
|
+
return opts
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
#
|
342
|
+
# Run server start up.
|
343
|
+
#
|
344
|
+
class Run
|
345
|
+
#
|
346
|
+
attr_accessor :queue_manager, :auth_required, :stompauth, :topic_manager
|
347
|
+
|
348
|
+
#
|
349
|
+
attr_accessor :session_cache
|
350
|
+
|
351
|
+
# Intiialize
|
352
|
+
def initialize(opts)
|
353
|
+
@@log = Logger.new(STDOUT)
|
354
|
+
@@log.level = StompServer::LogHelper.get_loglevel()
|
355
|
+
|
356
|
+
@opts = opts
|
357
|
+
@queue_manager = nil
|
358
|
+
@auth_required = nil
|
359
|
+
@stompauth = nil
|
360
|
+
@topic_manager = nil
|
361
|
+
@session_cache = nil
|
362
|
+
@@log.debug("#{self.class} Run class initialize method complete")
|
363
|
+
end
|
364
|
+
|
365
|
+
# Server stop on SIGINT or SIGTERM
|
366
|
+
def stop(pidfile)
|
367
|
+
@queue_manager.stop("KILL_ISSUED")
|
368
|
+
@@log.debug "Stompserver #{StompServer::VERSION} shutting down"
|
369
|
+
STDOUT.flush
|
370
|
+
EventMachine::stop_event_loop
|
371
|
+
File.delete(pidfile)
|
372
|
+
end
|
373
|
+
|
374
|
+
# Startup
|
375
|
+
def start
|
376
|
+
@@log.debug("#{self.class}.start begins")
|
377
|
+
|
378
|
+
# Handle group priviliges!
|
379
|
+
# N.B.: Handle these options from the command line ?????????
|
380
|
+
begin
|
381
|
+
if @opts[:group]
|
382
|
+
@@log.debug "Changing group to #{@opts[:group]}."
|
383
|
+
Process::GID.change_privilege(Etc.getgrnam(@opts[:group]).gid)
|
384
|
+
end
|
385
|
+
|
386
|
+
if @opts[:user]
|
387
|
+
@@log.debug "Changing user to #{@opts[:user]}."
|
388
|
+
Process::UID.change_privilege(Etc.getpwnam(@opts[:user]).uid)
|
389
|
+
end
|
390
|
+
rescue Errno::EPERM
|
391
|
+
@@log.error "FAILED to change user:group #{@opts[:user]}:#{@opts[:group]}: #$!"
|
392
|
+
exit 1
|
393
|
+
end
|
394
|
+
|
395
|
+
# Make required directories unless they already exist
|
396
|
+
Dir.mkdir(@opts[:working_dir]) unless File.directory?(@opts[:working_dir])
|
397
|
+
Dir.mkdir(@opts[:logdir]) unless File.directory?(@opts[:logdir])
|
398
|
+
Dir.mkdir(@opts[:etcdir]) unless File.directory?(@opts[:etcdir])
|
399
|
+
|
400
|
+
# Determine qstore type
|
401
|
+
if @opts[:queue] == 'dbm'
|
402
|
+
qstore=StompServer::DBMQueue.new(@opts[:storage])
|
403
|
+
@@log.debug "Queue storage is DBM"
|
404
|
+
elsif @opts[:queue] == 'file'
|
405
|
+
qstore=StompServer::FileQueue.new(@opts[:storage])
|
406
|
+
@@log.debug "Queue storage is FILE"
|
407
|
+
elsif @opts[:queue] == 'activerecord'
|
408
|
+
require 'stomp_server_ng/queue/activerecord_queue'
|
409
|
+
qstore=StompServer::ActiveRecordQueue.new(@opts[:etcdir], @opts[:storage], @opts[:dbyml])
|
410
|
+
@@log.debug "Queue storage is ActiveRecord"
|
411
|
+
else
|
412
|
+
qstore=StompServer::MemoryQueue.new
|
413
|
+
@@log.debug "Queue storage is MEMORY"
|
414
|
+
end
|
415
|
+
|
416
|
+
# Set checkpoint interval
|
417
|
+
qstore.checkpoint_interval = @opts[:checkpoint]
|
418
|
+
@@log.debug "Checkpoint interval is #{qstore.checkpoint_interval}" if $DEBUG
|
419
|
+
|
420
|
+
#
|
421
|
+
@topic_manager = StompServer::TopicManager.new
|
422
|
+
@queue_manager = StompServer::QueueManager.new(qstore)
|
423
|
+
@@log.debug("Managers are initialized.")
|
424
|
+
@@log.debug("Topic Manager: #{@topic_manager}")
|
425
|
+
@@log.debug("Queue Manager: #{@queue_manager}")
|
426
|
+
|
427
|
+
# Authorization: requirement
|
428
|
+
@auth_required = @opts[:auth]
|
429
|
+
if @auth_required
|
430
|
+
@stompauth = StompServer::StompAuth.new(@opts[:passwd])
|
431
|
+
end
|
432
|
+
|
433
|
+
# Initialize session ID cache
|
434
|
+
if @opts[:session_cache] > 0
|
435
|
+
StompServer::SessionIDManager.initialize_cache(@opts[:session_cache])
|
436
|
+
StompServer::SessionIDManager.dump_cache(@@log);
|
437
|
+
end
|
438
|
+
|
439
|
+
# If we are going to daemonize, it should be almost the last
|
440
|
+
# thing we do here.
|
441
|
+
@@log.debug("#{self.class}.start Daemonize: #{@opts[:daemon]}")
|
442
|
+
if @opts[:daemon]
|
443
|
+
@@log.debug("#{self.class}.start going to background")
|
444
|
+
@@log.debug("#{self.class}.start check #{@opts[:logfile]}")
|
445
|
+
|
446
|
+
StompServer::LogHelper.showversion(@@log)
|
447
|
+
|
448
|
+
STDOUT.flush # clear the decks
|
449
|
+
Daemonize.daemonize(log_file=@opts[:logfile])
|
450
|
+
# change back to the original starting directory
|
451
|
+
Dir.chdir(@opts[:working_dir])
|
452
|
+
end
|
453
|
+
|
454
|
+
# But write pidfile only after possible daemonization
|
455
|
+
curr_pid = Process.pid
|
456
|
+
open(@opts[:pidfile],"w") {|f| f.write(curr_pid) }
|
457
|
+
@@log.debug("Pid File Contents: #{curr_pid}")
|
458
|
+
|
459
|
+
# OK, log and set the SIGINT signal handler.
|
460
|
+
@@log.debug("#{self.class}.start setting trap at completion")
|
461
|
+
StompServer::LogHelper.showversion(@@log) # one more time at startup
|
462
|
+
# Show Load Path
|
463
|
+
StompServer::LogHelper.showloadpath(@@log)
|
464
|
+
StompServer::LogHelper.showoptions(@@log, @opts) # Dump runtime options
|
465
|
+
trap("INT") { @@log.debug "INT signal received.";stop(@opts[:pidfile]) }
|
466
|
+
trap("TERM") { @@log.debug "TERM signal received.";stop(@opts[:pidfile]) }
|
467
|
+
end
|
468
|
+
end # of class Run
|
469
|
+
#
|
470
|
+
end # of module StompServer
|
471
|
+
|