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 +8 -6
- data/Manifest.txt +25 -7
- data/README.txt +136 -19
- data/Rakefile +8 -8
- data/STATUS +5 -0
- data/bin/stompserver +43 -19
- 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.conf +11 -0
- data/etc/passwd.example +3 -0
- data/lib/stomp_server.rb +132 -157
- data/lib/stomp_server/protocols/http.rb +128 -0
- data/lib/stomp_server/protocols/stomp.rb +186 -0
- data/lib/stomp_server/queue.rb +140 -0
- data/lib/stomp_server/queue/activerecord_queue.rb +104 -0
- data/lib/stomp_server/queue/ar_message.rb +5 -0
- data/lib/stomp_server/queue/dbm_queue.rb +68 -0
- data/lib/stomp_server/queue/file_queue.rb +47 -0
- data/lib/stomp_server/queue/memory_queue.rb +58 -0
- data/lib/stomp_server/queue_manager.rb +209 -0
- data/lib/stomp_server/stomp_auth.rb +22 -0
- data/lib/{stomp_frame.rb → stomp_server/stomp_frame.rb} +7 -7
- data/lib/stomp_server/stomp_id.rb +21 -0
- data/lib/stomp_server/stomp_user.rb +17 -0
- data/lib/stomp_server/test_server.rb +21 -0
- data/lib/{topic_manager.rb → stomp_server/topic_manager.rb} +14 -2
- data/test/tesly.rb +15 -0
- data/test/test_queue_manager.rb +39 -32
- data/test/test_stomp_frame.rb +3 -16
- data/test/test_topic_manager.rb +3 -4
- data/{test → test_todo}/test_stomp_server.rb +0 -27
- metadata +56 -23
- data/lib/frame_journal.rb +0 -135
- data/lib/queue_manager.rb +0 -81
- data/test/test_frame_journal.rb +0 -14
data/History.txt
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
-
== 0.9.
|
2
|
-
|
3
|
-
*
|
4
|
-
|
5
|
-
|
6
|
-
*
|
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
|
-
|
5
|
+
STATUS
|
6
6
|
bin/stompserver
|
7
|
-
|
8
|
-
|
9
|
-
|
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/
|
12
|
-
|
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
|
-
|
8
|
-
|
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
|
-
==
|
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
|
-
==
|
14
|
+
== REQUIREMENTS:
|
22
15
|
|
23
|
-
|
16
|
+
* EventMachine
|
24
17
|
|
25
|
-
==
|
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
|
-
|
28
|
-
|
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
|
-
|
33
|
-
|
34
|
-
|
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 = "
|
15
|
-
p.author = ["
|
14
|
+
p.email = [ "lionel-dev@bouton.name" ]
|
15
|
+
p.author = [ "Lionel Bouton" ]
|
16
16
|
p.extra_deps = [
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
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
|
-
|
8
|
+
$STOMP_SERVER = true
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
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
|
-
|
23
|
-
|
24
|
-
StompServer.setup(FrameJournal.new(journal))
|
16
|
+
|
25
17
|
EventMachine::run do
|
26
|
-
|
27
|
-
|
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
|
data/etc/passwd.example
ADDED
data/lib/stomp_server.rb
CHANGED
@@ -1,172 +1,147 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'eventmachine'
|
3
|
-
require 'stomp_frame'
|
4
|
-
require '
|
5
|
-
require '
|
6
|
-
require '
|
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.
|
10
|
-
VALID_COMMANDS = [:connect, :send, :subscribe, :unsubscribe, :begin, :commit, :abort, :ack, :disconnect]
|
15
|
+
VERSION = '0.9.8'
|
11
16
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
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
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
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
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
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
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
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
|
168
|
-
|
169
|
-
|
170
|
-
|
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
|
+
|