stompserver_ng 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. data/History.txt +159 -0
  2. data/Manifest.txt +71 -0
  3. data/README.txt +172 -0
  4. data/Rakefile +38 -0
  5. data/STATUS +5 -0
  6. data/bin/stompserver_ng +63 -0
  7. data/client/README.txt +1 -0
  8. data/client/both.rb +25 -0
  9. data/client/consume.rb +14 -0
  10. data/client/send.rb +17 -0
  11. data/config/stompserver_ng.conf +11 -0
  12. data/etc/19xcompat/notes.txt +223 -0
  13. data/etc/arutils/README-activerecord.txt +78 -0
  14. data/etc/arutils/cre_mysql.rb +34 -0
  15. data/etc/arutils/cre_postgres.rb +33 -0
  16. data/etc/arutils/cre_sqlite3.rb +28 -0
  17. data/etc/arutils/mysql_boot.sql +12 -0
  18. data/etc/arutils/postgres_boot.sql +14 -0
  19. data/etc/database.mysql.yml +9 -0
  20. data/etc/database.postgres.yml +9 -0
  21. data/etc/passwd.example +3 -0
  22. data/etc/ppqinfo.rb +15 -0
  23. data/etc/runserver.sh +17 -0
  24. data/etc/stompserver_ng +50 -0
  25. data/etc/stompserver_ng.conf +13 -0
  26. data/lib/stomp_server_ng.rb +471 -0
  27. data/lib/stomp_server_ng/protocols/http.rb +128 -0
  28. data/lib/stomp_server_ng/protocols/stomp.rb +407 -0
  29. data/lib/stomp_server_ng/qmonitor.rb +58 -0
  30. data/lib/stomp_server_ng/queue.rb +248 -0
  31. data/lib/stomp_server_ng/queue/activerecord_queue.rb +118 -0
  32. data/lib/stomp_server_ng/queue/ar_message.rb +21 -0
  33. data/lib/stomp_server_ng/queue/ar_reconnect.rb +18 -0
  34. data/lib/stomp_server_ng/queue/dbm_queue.rb +72 -0
  35. data/lib/stomp_server_ng/queue/file_queue.rb +56 -0
  36. data/lib/stomp_server_ng/queue/memory_queue.rb +64 -0
  37. data/lib/stomp_server_ng/queue_manager.rb +302 -0
  38. data/lib/stomp_server_ng/stomp_auth.rb +26 -0
  39. data/lib/stomp_server_ng/stomp_frame.rb +32 -0
  40. data/lib/stomp_server_ng/stomp_frame_recognizer.rb +77 -0
  41. data/lib/stomp_server_ng/stomp_id.rb +32 -0
  42. data/lib/stomp_server_ng/stomp_user.rb +17 -0
  43. data/lib/stomp_server_ng/test_server.rb +21 -0
  44. data/lib/stomp_server_ng/topic_manager.rb +46 -0
  45. data/setup.rb +1585 -0
  46. data/stompserver_ng.gemspec +136 -0
  47. data/test/devserver/props.yaml +5 -0
  48. data/test/devserver/runserver.sh +16 -0
  49. data/test/devserver/stompserver_ng.dbm.conf +12 -0
  50. data/test/devserver/stompserver_ng.file.conf +12 -0
  51. data/test/devserver/stompserver_ng.memory.conf +12 -0
  52. data/test/noserver/mocklogger.rb +12 -0
  53. data/test/noserver/test_queue_manager.rb +134 -0
  54. data/test/noserver/test_stomp_frame.rb +138 -0
  55. data/test/noserver/test_topic_manager.rb +79 -0
  56. data/test/noserver/ts_all_no_server.rb +12 -0
  57. data/test/props.yaml +5 -0
  58. data/test/runalltests.sh +14 -0
  59. data/test/runtest.sh +4 -0
  60. data/test/test_0000_base.rb +107 -0
  61. data/test/test_0001_conn.rb +47 -0
  62. data/test/test_0002_conn_sr.rb +94 -0
  63. data/test/test_0006_client.rb +41 -0
  64. data/test/test_0011_send_recv.rb +74 -0
  65. data/test/test_0015_ack_conn.rb +78 -0
  66. data/test/test_0017_ack_client.rb +78 -0
  67. data/test/test_0019_ack_no_ack.rb +145 -0
  68. data/test/test_0022_ack_noack_conn.rb +123 -0
  69. data/test/test_0030_subscr_id.rb +44 -0
  70. data/test/test_0040_receipt_conn.rb +87 -0
  71. data/test/ts_all_server.rb +10 -0
  72. 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
+
@@ -0,0 +1,9 @@
1
+ adapter: mysql
2
+ encoding: utf8
3
+ database: ssng_dev
4
+ pool: 5
5
+ username: ssng
6
+ password: xxxxxxxx
7
+ host: localhost
8
+ port: 3306
9
+
@@ -0,0 +1,9 @@
1
+ adapter: postgresql
2
+ encoding: utf8
3
+ database: ssng_dev
4
+ pool: 5
5
+ username: ssng
6
+ password: xxxxxxxx
7
+ host: localhost
8
+ port: 5432
9
+
@@ -0,0 +1,3 @@
1
+ # Stompserver will look for a .passwd file in the directory you are running it from. One login/passcode per line, separated by a colon.
2
+ # Comment lines are ignored
3
+ testuser:testpass
@@ -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
+
@@ -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
@@ -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,13 @@
1
+ ---
2
+ :daemon: true
3
+ :working_dir: /tmp/stompserver
4
+ :storage: .queue
5
+ :queue: file
6
+ :auth: false
7
+ :debug: false
8
+ :group:
9
+ :user:
10
+ :host: localhost
11
+ :port: 61613
12
+ :log_level: debug
13
+
@@ -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
+