stompserver 0.9.7 → 0.9.8

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/History.txt CHANGED
@@ -1,9 +1,11 @@
1
- == 0.9.6 / 31 Oct 2006
2
-
3
- * Added simple code to handle denial of service attacks from large headers
4
- * Fixed a multitude of bugs (and added tests) found by our small but growing
5
- community of users
6
- * more coming soom (thanks to snacktime)
1
+ == 0.9.8 / 16 Aug 2007
2
+
3
+ * Several storage backends instead of Madeleine (allow tradeoffs between
4
+ robustness with ActiveRecord and speed with memory with intermediary
5
+ solutions based on file or dbm storages).
6
+ * Better load distribution between clients acknowledging messages after
7
+ processing them.
8
+ * Monitoring support through a dedicated queue.
7
9
 
8
10
  == 0.9.5 / 18 Oct 2006
9
11
 
data/Manifest.txt CHANGED
@@ -2,15 +2,33 @@ History.txt
2
2
  Manifest.txt
3
3
  README.txt
4
4
  Rakefile
5
- setup.rb
5
+ STATUS
6
6
  bin/stompserver
7
- lib/frame_journal.rb
8
- lib/queue_manager.rb
9
- lib/stomp_frame.rb
7
+ client/README.txt
8
+ client/both.rb
9
+ client/consume.rb
10
+ client/send.rb
11
+ config/stompserver.conf
12
+ etc/passwd.example
10
13
  lib/stomp_server.rb
11
- lib/topic_manager.rb
12
- test/test_frame_journal.rb
14
+ lib/stomp_server/protocols/http.rb
15
+ lib/stomp_server/protocols/stomp.rb
16
+ lib/stomp_server/queue.rb
17
+ lib/stomp_server/queue/activerecord_queue.rb
18
+ lib/stomp_server/queue/ar_message.rb
19
+ lib/stomp_server/queue/dbm_queue.rb
20
+ lib/stomp_server/queue/file_queue.rb
21
+ lib/stomp_server/queue/memory_queue.rb
22
+ lib/stomp_server/queue_manager.rb
23
+ lib/stomp_server/stomp_auth.rb
24
+ lib/stomp_server/stomp_frame.rb
25
+ lib/stomp_server/stomp_id.rb
26
+ lib/stomp_server/stomp_user.rb
27
+ lib/stomp_server/test_server.rb
28
+ lib/stomp_server/topic_manager.rb
29
+ setup.rb
30
+ test/tesly.rb
13
31
  test/test_queue_manager.rb
14
32
  test/test_stomp_frame.rb
15
- test/test_stomp_server.rb
16
33
  test/test_topic_manager.rb
34
+ test_todo/test_stomp_server.rb
data/README.txt CHANGED
@@ -1,43 +1,160 @@
1
1
  stompserver
2
- by Patrick Hurley
2
+ by Patrick Hurley, Lionel Bouton
3
3
  http://stompserver.rubyforge.org/
4
4
 
5
5
  == DESCRIPTION:
6
6
 
7
- Don't want to install a JVM, but still want to use messaging? Me too,
8
- so I threw together this little server. All the hard work was done
9
- by Francis Cianfrocca (big thank you) in his event machine gem (which
10
- is required by this server).
7
+ Stomp messaging server with file/dbm/memory/activerecord based FIFO
8
+ queues, queue monitoring, and basic authentication.
11
9
 
12
- == FEATURES/PROBLEMS:
10
+ == SYNOPSYS:
13
11
 
14
12
  Handles basic message queue processing
15
- Does not support any server to server messaging
16
- (although you could write a client to do this)
17
- Server Id is not being well initialized
18
- Quite a bit of polish is still required to make into a daemon/service
19
- And oh yeah, I need to write some docs (see the tests for now)
20
13
 
21
- == SYNOPSYS:
14
+ == REQUIREMENTS:
22
15
 
23
- Handles basic message queue processing
16
+ * EventMachine
24
17
 
25
- == REQUIREMENTS:
18
+ == FEATURES/PROBLEMS:
19
+
20
+ === Several queue storage backends
21
+
22
+ Handles basic message queue processing using memory, file, or dbm
23
+ based queues. Messages are sent and consumed in FIFO order (unless a
24
+ client error happens, this should be corrected in the future). Topics
25
+ are memory-only storage. You can select activerecord, file or dbm
26
+ storage and the queues will use that, but topics will only be stored
27
+ in memory.
28
+
29
+ memory queues are of course the fastest ones but shouldn't be used if
30
+ you want to ensure all messages are delivered.
31
+
32
+ dbm queues will use berkeleydb if available, otherwise dbm or gdbm
33
+ depending on the platform. sdbm does not work well with marshalled
34
+ data. Note that these queues have not been tested in this release.
35
+
36
+ For the file based storage, each frame is stored in a single file. The
37
+ first 8 bytes contains the header length, the next 8 bytes contains
38
+ the body length, then the headers are stored as a marshalled object
39
+ followed by the body stored as a string. This storage is currently
40
+ inefficient because queues are stored separately from messages, which
41
+ forces a double write for data safety reasons on each message stored.
42
+
43
+ The activerecord based storage expects to find a database.yml file in
44
+ the configuration directory. It should be the most robust backend, but
45
+ the slowest one. The database must have an ar_messages table which can
46
+ be created with the following code (you are responsible to do so):
47
+
48
+ ActiveRecord::Schema.define do
49
+ create_table 'ar_messages' do |t|
50
+ t.column 'stomp_id', :string, :null => false
51
+ t.column 'frame', :text, :null => false
52
+ end
53
+ end
54
+
55
+ You can read the frames with this model:
56
+
57
+ class ArMessage < ActiveRecord::Base
58
+ serialize :frame
59
+ end
60
+
61
+ The ar_message implementation will certainly change in the future.
62
+
63
+ This is meant to be easily readable by a Rails application (which
64
+ could handle the ar_messages table creation with a migration).
65
+
66
+ === Limitations
67
+
68
+ Stompserver not support any server to server messaging (although you could
69
+ write a client to do this).
70
+
71
+ === Monitoring
72
+
73
+ Queues can be monitored via the monitor queue (this will probably not
74
+ be supported this way in the future to avoid polluting the queue
75
+ namespace). If you subscribe to /queue/monitor, you will receive a
76
+ status message every 5 seconds that displays each queue, it's size,
77
+ frames enqueued, and frames dequeued. Stats are sent in the same
78
+ format of stomp headers, so they are easy to parse. Following is an
79
+ example of a status message containing stats for 2 queues:
80
+
81
+ Queue: /queue/client2
82
+ size: 0
83
+ dequeued: 400
84
+ enqueued: 400
85
+
86
+ Queue: /queue/test
87
+ size: 50
88
+ dequeued: 250
89
+ enqueued: 300
90
+
91
+ === Access control
92
+
93
+ Basic client authorization is also supported. If the -a flag is
94
+ passed to stompserver on startup, and a .passwd file exists in the run
95
+ directory, then clients will be required to provide a valid login and
96
+ passcode. See passwd.example for the password file format.
97
+
98
+ === Misc
26
99
 
27
- + EventMachine
28
- + madeleine
100
+ Whenever you stop the server, any queues with no messages will be
101
+ removed, and the stats for that queue will be reset. If the queue has
102
+ any messages remaining then the stats will be saved and available on
103
+ the next restart.
29
104
 
30
105
  == INSTALL:
31
106
 
32
- + Grab the gem
33
- and run:
34
- stompserver -p 61613 -b 0.0.0.0 -j /var/ss/journal_dir
107
+ * gem install stompserver
108
+
109
+ stompserver will create a log, etc, and storage directory on startup
110
+ in your current working directory, the value passed to as
111
+ --working_dir parameter, or if using a config file it will
112
+ use what you specified for working_dir. The configuration file is a
113
+ yaml file and can be specified on the command line with -C
114
+ <configfile>. A sample is provided in config/stompserver.conf.
115
+
116
+ Command line options will override options set in the yaml config
117
+ file.
118
+
119
+ To use the memory queue run as follows:
120
+ stompserver -p 61613 -b 0.0.0.0
121
+
122
+ To use the file or dbm queue storage, use the -q switch and specificy
123
+ either file or dbm. The file and dbm queues also take a storage
124
+ directory specified with -s. .stompserver is the default directory if
125
+ -s is not used.
126
+ stompserver -p 61613 -b 0.0.0.0 -q file -s .stompfile
127
+ Or
128
+ stompserver -p 61613 -b 0.0.0.0 -q dbm -s .stompbdb
129
+
130
+ To specify where the queue is stored on disk, use the -s flag followed
131
+ by a storage directory. To enable client authorization use -a, for
132
+ debugging use -d.
133
+ stompserver -p 61613 -b 0.0.0.0 -q file -s .stompserver -a -d
134
+
135
+ You cannot use the same storage directory for a file and dbm queue,
136
+ they must be kept separate.
137
+
138
+ To use the activerecord queue storage use -q activerecord:
139
+ stompserver -p 61613 -b 0.0.0.0 -q activerecord
140
+ It will try to read the etc/database.yml file in the working
141
+ directory. Here's an example of a database.yml for a PostgreSQL
142
+ database named stompserver on the 'dbserver' host usable by
143
+ PostgreSQL's user 'foo' with password 'bar'(see ActiveRecord's
144
+ documentation for the parameters needed by your database):
145
+
146
+ adapter: postgresql
147
+ database: stompserver
148
+ username: foo
149
+ password: bar
150
+ host: dbserver
35
151
 
36
152
  == LICENSE:
37
153
 
38
154
  (The MIT License)
39
155
 
40
156
  Copyright (c) 2006 Patrick Hurley
157
+ Copyright (c) 2007 Lionel Bouton
41
158
 
42
159
  Permission is hereby granted, free of charge, to any person obtaining
43
160
  a copy of this software and associated documentation files (the
data/Rakefile CHANGED
@@ -11,15 +11,15 @@ Hoe.new('stompserver', StompServer::VERSION) do |p|
11
11
  p.description = p.paragraphs_of('README.txt', 2..4).join("\n\n")
12
12
  p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
13
13
  p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
14
- p.email = "phurley@gmail.com"
15
- p.author = ["Patrick Hurley"]
14
+ p.email = [ "lionel-dev@bouton.name" ]
15
+ p.author = [ "Lionel Bouton" ]
16
16
  p.extra_deps = [
17
- # This depencency is real, but if you are on a Win32 box
18
- # and don't have VC6, it can be a real problem
19
- # ["eventmachine", ">= 0.5.0"],
20
- ["madeleine", ">= 0.7.3"],
21
- ["hoe", ">= 1.1.1"]
22
- ]
17
+ # This depencency is real, but if you are on a Win32 box
18
+ # and don't have VC6, it can be a real problem
19
+ ["daemons", ">= 1.0.2"],
20
+ ["hoe", ">= 1.1.1"],
21
+ ]
22
+ p.remote_rdoc_dir = ''
23
23
  end
24
24
 
25
25
  # vim: syntax=Ruby
data/STATUS ADDED
@@ -0,0 +1,5 @@
1
+
2
+ - Unit tests are broken, need to override methods that call EM
3
+ - Added http protocol handler. No pipelining or anything fancy, just PUT/GET requests which enqueue/dequeue messages from
4
+ the queue one at a time. Uses the Mongrel http parser.
5
+
data/bin/stompserver CHANGED
@@ -1,28 +1,52 @@
1
1
  require 'rubygems'
2
+ require 'etc'
3
+ require 'yaml'
4
+ require 'daemons/daemonize'
2
5
  require 'stomp_server'
3
- require 'frame_journal'
4
6
  require 'optparse'
5
7
 
6
- opts = OptionParser.new
8
+ $STOMP_SERVER = true
7
9
 
8
- port = 61613
9
- bind = "127.0.0.1"
10
- bind = "localhost"
11
- journal = ".stompserver"
12
-
13
- opts.on("-p", "--port=PORT", Integer, "Change the port (default: 61613)") {|p| port = p}
14
- opts.on("-b", "--bind=ADDR", String, "Change the binding adapter (default: localhost)") {|a| bind = a}
15
- opts.on("-j", "--journal=DIR", String, "Change the journal directory (default: ./.stompserver)") {|j| journal = j}
16
- opts.on("-d", "--debug", "Enable debug output") {$DEBUG=1}
17
- opts.on("-h", "--help", "Show this message") do
18
- puts opts
19
- exit
10
+ $HTTP_ENABLE = false
11
+ if $HTTP_ENABLE
12
+ require 'mongrel'
13
+ require 'stomp_server/protocols/http'
20
14
  end
21
15
 
22
- puts opts.parse(ARGV)
23
-
24
- StompServer.setup(FrameJournal.new(journal))
16
+
25
17
  EventMachine::run do
26
- puts "Stomp Server starting on port #{port}"
27
- EventMachine.start_server bind, port, StompServer
18
+
19
+ ## Get the configuration and initialize the stomp engine
20
+ config = StompServer::Configurator.new
21
+ stomp = StompServer::Run.new(config.opts)
22
+ stomp.start
23
+
24
+
25
+ # Might want to uncomment this if you are sending large files
26
+ #EventMachine::add_periodic_timer 10, proc {GC.start}
27
+
28
+ puts "Client authorization enabled" if config.opts[:auth]
29
+ puts "Debug enabled" if config.opts[:debug]
30
+
31
+ ## Start protocol handlers
32
+
33
+ puts "Stomp protocol handler starting on #{config.opts[:host]} port #{config.opts[:port]}"
34
+ EventMachine.start_server(config.opts[:host], config.opts[:port], StompServer::Protocols::Stomp) {|s| s.instance_eval {
35
+ @@auth_required=stomp.auth_required
36
+ @@queue_manager=stomp.queue_manager
37
+ @@topic_manager=stomp.topic_manager
38
+ @@stompauth = stomp.stompauth
39
+ }
40
+ }
41
+
42
+ if $HTTP_ENABLE
43
+ puts "Http protocol handler starting on #{config.opts[:host]} port 8080"
44
+ EventMachine.start_server(config.opts[:host], 8080, StompServer::Protocols::Http) {|s| s.instance_eval {
45
+ @@auth_required=stomp.auth_required
46
+ @@queue_manager=stomp.queue_manager
47
+ @@topic_manager=stomp.topic_manager
48
+ @@stompauth = stomp.stompauth
49
+ }
50
+ }
51
+ end
28
52
  end
data/client/README.txt ADDED
@@ -0,0 +1 @@
1
+ Samples of how to use the ruby stomp client with stompserver
data/client/both.rb ADDED
@@ -0,0 +1,25 @@
1
+ require 'rubygems'
2
+ require 'stomp'
3
+ client = Stomp::Client.open "login", "passcode", "localhost", 61613
4
+
5
+ client.subscribe("/queue/client2", {
6
+ "persistent" => true,
7
+ "ack" => 'client',
8
+ "client-id" => "rubyClient",
9
+ } ) do |message|
10
+ puts "Got Reply: #{message.headers['message-id']} - #{message.body} on #{message.headers['destination']}"
11
+ end
12
+
13
+ for i in 1..5 do
14
+ m = "Go Sox #{i}!"
15
+ puts m
16
+ client.send("/queue/client2", m, {
17
+ "persistent" => true,
18
+ "priority" => 4,
19
+ "reply-to" => "/queue/client2",
20
+ }
21
+ )
22
+ end
23
+
24
+ gets
25
+ client.close
data/client/consume.rb ADDED
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ require 'stomp'
3
+ client = Stomp::Client.open "login", "passcode", "localhost", 61613
4
+
5
+ client.subscribe("/queue/test", {
6
+ "persistent" => true,
7
+ "client-id" => "rubyClient",
8
+ } ) do |message|
9
+ puts "Got Reply: ID=#{message.headers['message-id']} BODY=#{message.body} on #{message.headers['destination']}"
10
+ end
11
+
12
+
13
+ gets
14
+ client.close
data/client/send.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'rubygems'
2
+ require 'stomp'
3
+ client = Stomp::Client.open "login", "passcode", "localhost", 61613
4
+
5
+ # sending 5 messages at once
6
+ for i in 1..5 do
7
+ m = "Go Sox #{i}!"
8
+ puts m
9
+ client.send("/queue/test", m, {
10
+ "persistent" => true,
11
+ "client-id" => "Client1",
12
+ "reply-to" => "/queue/test",
13
+ }
14
+ )
15
+ end
16
+
17
+ client.close
@@ -0,0 +1,11 @@
1
+ ---
2
+ :daemon: false
3
+ :working_dir: /tmp/stompserver
4
+ :storage: .queue
5
+ :queue: file
6
+ :auth: false
7
+ :debug: false
8
+ :group:
9
+ :user:
10
+ :host: 127.0.0.1
11
+ :port: 61613
@@ -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
data/lib/stomp_server.rb CHANGED
@@ -1,172 +1,147 @@
1
1
  require 'rubygems'
2
2
  require 'eventmachine'
3
- require 'stomp_frame'
4
- require 'topic_manager'
5
- require 'queue_manager'
6
- require 'frame_journal'
3
+ require 'stomp_server/stomp_frame'
4
+ require 'stomp_server/stomp_id'
5
+ require 'stomp_server/stomp_auth'
6
+ require 'stomp_server/topic_manager'
7
+ require 'stomp_server/queue_manager'
8
+ require 'stomp_server/queue'
9
+ require 'stomp_server/queue/memory_queue'
10
+ require 'stomp_server/queue/file_queue'
11
+ require 'stomp_server/queue/dbm_queue'
12
+ require 'stomp_server/protocols/stomp'
7
13
 
8
14
  module StompServer
9
- VERSION = '0.9.7'
10
- VALID_COMMANDS = [:connect, :send, :subscribe, :unsubscribe, :begin, :commit, :abort, :ack, :disconnect]
15
+ VERSION = '0.9.8'
11
16
 
12
- def self.setup(j = FrameJournal.new, tm = TopicManager.new, qm = QueueManager.new(j))
13
- @@journal = j
14
- @@topic_manager = tm
15
- @@queue_manager = qm
16
- end
17
-
18
- def post_init
19
- @sfr = StompFrameRecognizer.new
20
- @transactions = {}
21
- @connected = false
22
- end
23
-
24
- def receive_data(data)
25
- begin
26
- puts "receive_data: #{data.inspect}" if $DEBUG
27
- @sfr << data
28
- process_frames
29
- rescue Exception => e
30
- puts "err: #{e} #{e.backtrace.join("\n")}" if $DEBUG
31
- send_error(e.to_s)
32
- close_connection_after_writing
33
- end
34
- end
35
-
36
- def process_frames
37
- frame = nil
38
- process_frame(frame) while frame = @sfr.frames.shift
39
- end
40
-
41
- def process_frame(frame)
42
- cmd = frame.command.downcase.to_sym
43
- raise "Unhandled frame: #{cmd}" unless VALID_COMMANDS.include?(cmd)
44
- raise "Not connected" if !@connected && cmd != :connect
45
-
46
- puts "process_frame #{cmd}" if $DEBUG
47
-
48
- # I really like this code, but my needs are a little trickier
49
- #
50
-
51
- if trans = frame.headers['transaction']
52
- handle_transaction(frame, trans, cmd)
53
- else
54
- cmd = :sendmsg if cmd == :send
55
- puts "Execute #{cmd}" if $DEBUG
56
- send(cmd, frame)
57
- end
58
-
59
- send_receipt(frame.headers['receipt']) if frame.headers['receipt']
60
- end
17
+ class Configurator
18
+ attr_accessor :opts
19
+
20
+ def initialize
21
+ @opts = nil
22
+ @defaults = {
23
+ :port => 61613,
24
+ :host => "127.0.0.1",
25
+ :debug => false,
26
+ :queue => 'memory',
27
+ :auth => false,
28
+ :working_dir => Dir.getwd,
29
+ :storage => ".stompserver",
30
+ :logdir => 'log',
31
+ :configfile => 'stompserver.conf',
32
+ :logfile => 'stompserver.log',
33
+ :pidfile => 'stompserver.pid'
34
+ }
35
+ @opts = getopts
36
+ if opts[:debug]
37
+ $DEBUG=true
38
+ end
61
39
 
62
- # here is how we can stop, of course there is currently no
63
- # way to get here
64
- def shutdown(msg)
65
- EventMachine::stop_event_loop
66
- end
67
-
68
- def handle_transaction(frame, trans, cmd)
69
- if [:begin, :commit, :abort].include?(cmd)
70
- send(cmd, frame, trans)
71
- else
72
- raise "transaction does not exist" unless @transactions.has_key?(trans)
73
- @transactions[trans] << frame
74
- end
75
- end
76
-
77
- def connect(frame)
78
- puts "Connecting" if $DEBUG
79
- response = StompFrame.new("CONNECTED", {'session' => 'wow'})
80
- send_data(response.to_s)
81
- @connected = true
82
- end
83
-
84
- def sendmsg(frame)
85
- # set message id
86
- frame.headers['message-id'] = "msg-#{@@journal.system_id}-#{@@journal.next_index}"
87
- if frame.dest.match(%r|^/queue|)
88
- @@queue_manager.sendmsg(frame)
89
- else
90
- @@topic_manager.sendmsg(frame)
91
40
  end
92
- end
93
-
94
- def subscribe(frame)
95
- if frame.dest =~ %r|^/queue|
96
- ack = frame.headers['ack'] == 'client'
97
- @@queue_manager.subscribe(frame.dest, self, ack)
98
- else
99
- @@topic_manager.subscribe(frame.dest, self)
41
+
42
+ def getopts
43
+ copts = OptionParser.new
44
+ copts.on("-C", "--config=CONFIGFILE", String, "Configuration File (default: stompserver.conf)") {|c| @defaults[:configfile] = c}
45
+ copts.on("-p", "--port=PORT", Integer, "Change the port (default: 61613)") {|p| @defaults[:port] = p}
46
+ copts.on("-b", "--host=ADDR", String, "Change the host (default: localhost)") {|a| @defaults[:host] = a}
47
+ copts.on("-q", "--queuetype=QUEUETYPE", String, "Queue type (memory|dbm|activerecord|file) (default: memory)") {|q| @defaults[:queue] = q}
48
+ copts.on("-w", "--working_dir=DIR", String, "Change the working directory (default: current directory)") {|s| @defaults[:working_dir] = s}
49
+ copts.on("-s", "--storage=DIR", String, "Change the storage directory (default: .stompserver, relative to working_dir)") {|s| @defaults[:storage] = s}
50
+ copts.on("-d", "--debug", String, "Turn on debug messages") {|d| @defaults[:debug] = true}
51
+ copts.on("-a", "--auth", String, "Require client authorization") {|a| @defaults[:auth] = true}
52
+ copts.on("-h", "--help", "Show this message") do
53
+ puts copts
54
+ exit
55
+ end
56
+ puts copts.parse(ARGV)
57
+
58
+ if File.exists?(@defaults[:configfile])
59
+ opts = @defaults.merge(YAML.load_file(@defaults[:configfile]))
60
+ else
61
+ opts = @defaults
62
+ end
63
+
64
+ opts[:etcdir] = File.join(opts[:working_dir],'etc')
65
+ opts[:storage] = File.join(opts[:working_dir],opts[:storage])
66
+ opts[:logdir] = File.join(opts[:working_dir],opts[:logdir])
67
+ opts[:logfile] = File.join(opts[:logdir],opts[:logfile])
68
+ opts[:pidfile] = File.join(opts[:logdir],opts[:pidfile])
69
+ if opts[:auth]
70
+ opts[:passwd] = File.join(opts[:etcdir],'.passwd')
71
+ end
72
+
73
+ return opts
100
74
  end
101
75
  end
102
-
103
- def unsubscribe(frame)
104
- if frame.dest =~ %r|^/queue|
105
- @@queue_manager.unsubscribe(frame.dest, self)
106
- else
107
- @@topic_manager.unsubscribe(frame.dest, self)
76
+
77
+
78
+ class Run
79
+ attr_accessor :queue_manager, :auth_required, :stompauth, :topic_manager
80
+
81
+ def initialize(opts)
82
+ @opts = opts
83
+ @queue_manager = nil
84
+ @auth_required = nil
85
+ @stompauth = nil
86
+ @topic_manager = nil
108
87
  end
109
- end
110
-
111
- def begin(frame, trans=nil)
112
- raise "Missing transaction" unless trans
113
- raise "transaction exists" if @transactions.has_key?(trans)
114
- @transactions[trans] = []
115
- end
116
-
117
- def commit(frame, trans=nil)
118
- raise "Missing transaction" unless trans
119
- raise "transaction does not exist" unless @transactions.has_key?(trans)
120
-
121
- (@transactions[trans]).each do |frame|
122
- frame.headers.delete('transaction')
123
- process_frame(frame)
88
+
89
+ def stop(pidfile)
90
+ @queue_manager.stop
91
+ puts "Stompserver shutting down" if $DEBUG
92
+ EventMachine::stop_event_loop
93
+ File.delete(pidfile)
124
94
  end
125
- @transactions.delete(trans)
126
- end
127
-
128
- def abort(frame, trans=nil)
129
- raise "Missing transaction" unless trans
130
- raise "transaction does not exist" unless @transactions.has_key?(trans)
131
- @transactions.delete(trans)
132
- end
133
-
134
- def ack(frame)
135
- @@queue_manager.ack(self, frame)
136
- end
137
-
138
- def disconnect(frame)
139
- puts "Polite disconnect" if $DEBUG
140
- close_connection_after_writing
141
- end
142
95
 
143
- def unbind
144
- @@queue_manager.disconnect(self)
145
- @@topic_manager.disconnect(self)
146
- end
147
-
148
- def send_message(msg)
149
- msg.command = "MESSAGE"
150
- send_data(msg.to_s)
151
- end
152
-
153
- def send_receipt(id)
154
- send_frame("RECEIPT", { 'receipt-id' => id})
155
- end
156
-
157
- def send_error(msg)
158
- send_frame("ERROR",{},msg)
159
- end
160
-
161
- def send_frame(command, headers={}, body='')
162
- response = StompFrame.new(command, headers, body)
163
- send_data(response.to_s)
164
- end
165
- end
96
+ def start
97
+ begin
98
+ if @opts[:group]
99
+ puts "Changing group to #{@opts[:group]}."
100
+ Process::GID.change_privilege(Etc.getgrnam(@opts[:group]).gid)
101
+ end
102
+
103
+ if @opts[:user]
104
+ puts "Changing user to #{@opts[:user]}."
105
+ Process::UID.change_privilege(Etc.getpwnam(@opts[:user]).uid)
106
+ end
107
+ rescue Errno::EPERM
108
+ puts "FAILED to change user:group #{@opts[:user]}:#{@opts[:group]}: #$!"
109
+ exit 1
110
+ end
111
+
112
+ Dir.mkdir(@opts[:working_dir]) unless File.directory?(@opts[:working_dir])
113
+ Dir.mkdir(@opts[:logdir]) unless File.directory?(@opts[:logdir])
114
+ Dir.mkdir(@opts[:etcdir]) unless File.directory?(@opts[:etcdir])
115
+
116
+ if @opts[:daemon]
117
+ Daemonize.daemonize(log_file=@opts[:logfile])
118
+ # change back to the original starting directory
119
+ Dir.chdir(@opts[:working_dir])
120
+ end
121
+
122
+ # Write pidfile
123
+ open(@opts[:pidfile],"w") {|f| f.write(Process.pid) }
166
124
 
167
- if $0 == __FILE__
168
- StompServer.setup
169
- EventMachine::run do
170
- EventMachine.start_server "0.0.0.0", 61613, StompServer
125
+ if @opts[:queue] == 'dbm'
126
+ qstore=StompServer::DBMQueue.new(@opts[:storage])
127
+ elsif @opts[:queue] == 'file'
128
+ qstore=StompServer::FileQueue.new(@opts[:storage])
129
+ elsif @opts[:queue] == 'activerecord'
130
+ require 'stomp_server/queue/activerecord_queue'
131
+ qstore=StompServer::ActiveRecordQueue.new(@opts[:etcdir], @opts[:storage])
132
+ else
133
+ qstore=StompServer::MemoryQueue.new
134
+ end
135
+ @topic_manager = StompServer::TopicManager.new
136
+ @queue_manager = StompServer::QueueManager.new(qstore)
137
+ @auth_required = @opts[:auth]
138
+
139
+ if @auth_required
140
+ @stompauth = StompServer::StompAuth.new(@opts[:passwd])
141
+ end
142
+
143
+ trap("INT") { puts "INT signal received.";stop(@opts[:pidfile]) }
144
+ end
171
145
  end
172
146
  end
147
+