stompserver 0.9.7 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
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
+