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 +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
|
+
|