stomp-1.4.4/ 0000755 0000041 0000041 00000000000 13120662775 012723 5 ustar www-data www-data stomp-1.4.4/adhoc/ 0000755 0000041 0000041 00000000000 13120662775 014001 5 ustar www-data www-data stomp-1.4.4/adhoc/stomp_adhoc_common.rb 0000644 0000041 0000041 00000004636 13120662775 020207 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
# Common Stomp 1.1 code.
#
require "rubygems" if RUBY_VERSION < "1.9"
require "stomp"
#
module Stomp11Common
# Port Constants locally
STOMP_AMQ_PORT = ENV['STOMP_AMQ_PORT'] ? ENV['STOMP_AMQ_PORT'].to_i : 61613
STOMP_APOLLO_PORT = ENV['STOMP_APOLLO_PORT'] ? ENV['STOMP_APOLLO_PORT'].to_i : 62613
STOMP_ARTEMIS_PORT = ENV['STOMP_ARTEMIS_PORT'] ? ENV['STOMP_ARTEMIS_PORT'].to_i : 31613
STOMP_SSNG_PORT = ENV['STOMP_SSNG_PORT'] ? ENV['STOMP_SSNG_PORT'].to_i : 51613
STOMP_RMQ_PORT = ENV['STOMP_RMQ_PORT'] ? ENV['STOMP_RMQ_PORT'].to_i : 41613
# Vhost Constants
STOMP_RMQ_VHOST = ENV['STOMP_RMQ_VHOST'] || '/'
STOMP_VHOST = ENV['STOMP_VHOST'] || 'localhost'
# Client Protocol List
STOMP_PROTOCOL = ENV['STOMP_PROTOCOL'] || "1.2"
# User id
def login()
ENV['STOMP_USER'] || 'guest'
end
# Password
def passcode()
ENV['STOMP_PASSCODE'] || 'guest'
end
# Server host
def host()
ENV['STOMP_HOST'] || "localhost" # The connect host name
end
# Server port
def port()
if ENV['STOMP_AMQ']
STOMP_AMQ_PORT
elsif ENV['STOMP_APOLLO']
STOMP_APOLLO_PORT
elsif ENV['STOMP_RMQ']
STOMP_RMQ_PORT
elsif ENV['STOMP_SSNG']
STOMP_SSNG_PORT
elsif ENV['STOMP_PORT']
ENV['STOMP_PORT'].to_i
else
61613 # The default ActiveMQ stomp listener port
end
end
# Required vhost name
def virt_host()
if ENV['STOMP_RMQ']
STOMP_RMQ_VHOST
else
STOMP_VHOST
end
end
# Create a 1.1 commection
def get_connection()
conn_hdrs = {"accept-version" => STOMP_PROTOCOL,
"host" => virt_host(), # the vhost
}
conn_hash = { :hosts => [
{:login => login(), :passcode => passcode(), :host => host(), :port => port()},
],
:connect_headers => conn_hdrs,
}
conn = Stomp::Connection.new(conn_hash)
end
# Number of messages
def nmsgs()
(ENV['STOMP_NMSGS'] || 1).to_i # Number of messages
end
# Queue / Topic Name
def make_destination(right_part = nil, topic = false)
if ENV['STOMP_DOTQUEUE']
right_part.gsub!('/', '.')
end
if topic
"/topic/#{right_part}"
else
"/queue/#{right_part}"
end
end
# True if client should supply a receipt block on 'publish'
def cli_block()
ENV['STOMP_CLI_BLOCK']
end
# True if connection should ask for a receipt
def conn_receipt()
ENV['STOMP_RECEIPT']
end
end # module
stomp-1.4.4/adhoc/issue121_03.rb 0000644 0000041 0000041 00000007514 13120662775 016213 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'stomp'
require 'tmpdir'
# Focus on this gem's capabilities.
require 'memory_profiler'
# require 'memory-profiler'
if Kernel.respond_to?(:require_relative)
require_relative("stomp_adhoc_common")
require_relative("payload_generator")
else
$LOAD_PATH << File.dirname(__FILE__)
require "stomp_adhoc_common"
require("payload_generator")
end
include Stomp11Common
# Round 3 of testing around issue #121.
# Different memory profiler gem.
class Issue121Examp03
attr_reader :client, :session
# Initialize.
def initialize(topic = false)
@client, @session, @topic = nil, nil, topic
@nmsgs = nmsgs()
@queue = make_destination("issue121/test_03")
@id = "issue121_03"
@block = cli_block()
#
@cmin, @cmax = 1292, 67782 # From the issue discussion
PayloadGenerator::initialize(min= @cmin, max= @cmax)
@ffmts = "%16.6f"
#
mps = 5.6 # see issue discussion
@to, @nmts, @nts, @umps = 0.0, Time.now.to_f, @nmsgs, mps
@tslt = 1.0 / @umps
end # initialize
# Startup
def start
#
client_hdrs = {"accept-version" => "1.1,1.2",
"host" => virt_host,
}
#
client_hash = { :hosts => [
{:login => login(), :passcode => passcode(), :host => host(), :port => port()},
],
:connect_headers => client_hdrs,
}
#
@client = Stomp::Client.new(client_hash)
puts "START: Client Connect complete"
raise "START: Connection failed!!" unless @client.open?
raise "START: Unexpected protocol level!!" if @client.protocol() == Stomp::SPL_10
cf = @client.connection_frame()
puts "START: Connection frame\n#{cf}"
raise "START: Connect error!!: #{cf.body}" if @client.connection_frame().command == Stomp::CMD_ERROR
@session = @client.connection_frame().headers['session']
puts "START: Queue/Topic Name: #{@queue}"
puts "START: Session: #{@session}"
puts "START: NMSGS: #{@nmsgs}"
puts "START: Block: #{@block}"
puts "START: Wanted Messages Per Second: #{@umps}"
puts "START: Sleep Time: #{@tslt}"
$stdout.flush
end # start
#
def shutdown
@client.close
#
te = Time.now.to_f
et = te - @nmts
avgsz = @to / @nts
mps = @nts.to_f / et
#
fet = sprintf(@ffmts, et)
favgsz = sprintf(@ffmts, avgsz)
fmps = sprintf(@ffmts, mps)
#
sep = "=" * 72
puts sep
puts "\tNumber of payloads generated: #{@nts}"
puts "\tMin Length: #{@cmin}, Max Length: #{@cmax}"
puts "\tAVG_SIZE: #{favgsz}, ELAPS_SEC: #{fet}(seconds)"
puts "\tNMSGS_PER_SEC: #{fmps}"
puts sep
#
puts "SHUT: Shutdown complete"
$stdout.flush
end # shutdown
# pub
def publish
m = "Message: "
nm = 0
@nmsgs.times do |n|
nm += 1
puts "PUB: NEXT MESSAGE NUMBER: #{nm}"; $stdout.flush
mo = PayloadGenerator::payload()
@to += mo.bytesize()
hs = {:session => @session}
if @block
ip = false
@client.publish(@queue,
mo,
hs) {|m|
puts "PUB: HAVE_RECEIPT:\nID: #{m.headers['receipt-id']}"
$stdout.flush
ip = m
}
sleep 0.01 until ip
else
@client.publish(@queue, mo, hs)
end # if @block
if nm < @nmsgs
puts "PUB: start user sleep"
sleep @tslt # see issue discussion
puts "PUB: end user sleep"
end
$stdout.flush
end # @nmsgs.times do
puts "PUB: end of publish"
$stdout.flush
end # publish
end # class
#
1.times do |i|
rpt = MemoryProfiler.report do
e = Issue121Examp03.new
e.start
e.publish
# No subscribes here, just publish
# See discussion in issue #121
e.shutdown
end
n = Time.now
nf = "memory_profiler-ng"
nf << n.strftime("%Y%m%dT%H%M%S.%N%Z")
where_name = File::join(Dir::tmpdir(), nf)
rpt.pretty_print(to_file: where_name )
# sleep 1
end
#
stomp-1.4.4/adhoc/payload_generator_adhoctest.rb 0000644 0000041 0000041 00000001656 13120662775 022073 0 ustar www-data www-data # -*- encoding: utf-8 -*-
if Kernel.respond_to?(:require_relative)
require_relative("payload_generator")
else
$LOAD_PATH << File.dirname(__FILE__)
require "payload_generator"
end
#
cmin, cmax = 1292, 67782
ffmts = "%16.6f"
#
PayloadGenerator::initialize(min= cmin, max= cmax)
to, nmts, nts, umps = 0.0, Time.now.to_f, 100, 5.6
# p [ "nmts", nmts ]
tslt = 1.0 / umps
# p [ "tslt", tslt ]
nts.times do |i|
ns = PayloadGenerator::payload()
to += ns.bytesize
# puts "t: #{i+1}, len: #{ns.bytesize}, tslt: #{tslt}"
sleep(tslt)
# puts "Done sleep!"
end
#
te = Time.now.to_f
# p [ "te", te ]
et = te - nmts
avgsz = to / nts
mps = nts.to_f / et
#
fet = sprintf(ffmts, et)
favgsz = sprintf(ffmts, avgsz)
fmps = sprintf(ffmts, mps)
#
puts "=" * 48
puts "\tNumber of payloads generated: #{nts}"
puts "\tMin Length: #{cmin}, Max Length: #{cmax}"
puts "\tAVG_SIZE: #{favgsz}, ELAPS_SEC: #{fet}(seconds)"
puts "\tNMSGS_PER_SEC: #{fmps}"
#
stomp-1.4.4/adhoc/payload_generator.rb 0000644 0000041 0000041 00000000772 13120662775 020033 0 ustar www-data www-data # -*- encoding: utf-8 -*-
class PayloadGenerator
private
@@BSTRING = ""
public
def self.initialize(min = 1, max = 4096)
srand()
#
@@min, @@max = min, max
if @@min > @@max
@@min, @@max = @@max, @@min
warn "Swapping min and max values"
end
#
@@BSTRING = "9" * @@max
nil
end # of initialize
def self.payload
i = rand(@@max - @@min)
i = 1 if i == 0
i += @@min
# puts "DBI: #{i}"
@@BSTRING.byteslice(0, i)
end
end # of class
stomp-1.4.4/adhoc/.gitignore 0000644 0000041 0000041 00000000112 13120662775 015763 0 ustar www-data www-data # No html in this directory
*.html
*.htm
# Typical backup files
*~
*.bak
stomp-1.4.4/adhoc/issue121_01_conn.rb 0000644 0000041 0000041 00000010044 13120662775 017216 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'stomp'
require 'tmpdir'
# Focus on this gem's capabilities.
require 'memory_profiler'
# require 'memory-profiler'
if Kernel.respond_to?(:require_relative)
require_relative("stomp_adhoc_common")
require_relative("payload_generator")
else
$LOAD_PATH << File.dirname(__FILE__)
require "stomp_adhoc_common"
require("payload_generator")
end
include Stomp11Common
# Next of testing around issue #121.
# Different memory profiler gem.
# Use Stomp#connection to merely send
class Issue121Examp01Conn
attr_reader :connection, :session
# Initialize.
def initialize(topic = false)
@connection, @session, @topic = nil, nil, topic
@nmsgs = nmsgs()
@queue = make_destination("issue121/test_01_conn")
@id = "issue121_01_conn"
@getreceipt = conn_receipt()
#
@cmin, @cmax = 1292, 67782 # From the issue discussion
PayloadGenerator::initialize(min= @cmin, max= @cmax)
@ffmts = "%16.6f"
#
mps = 5.6 # see issue discussion
@to, @nmts, @nts, @umps = 0.0, Time.now.to_f, @nmsgs, mps
@tslt = 1.0 / @umps
end # initialize
# Startup
def start
#
connect_hdrs = {"accept-version" => "1.1,1.2",
"host" => virt_host,
}
#
connect_hash = { :hosts => [
{:login => login(), :passcode => passcode(), :host => host(), :port => port()},
],
:connect_headers => connect_hdrs,
}
#
@connection = Stomp::Connection.new(connect_hash)
puts "START: Connection Connect complete"
raise "START: Connection failed!!" unless @connection.open?
raise "START: Unexpected protocol level!!" if @connection.protocol == Stomp::SPL_10
cf = @connection.connection_frame
puts "START: Connection frame\n#{cf}"
raise "START: Connect error!!: #{cf.body}" if @connection.connection_frame.command == Stomp::CMD_ERROR
@session = @connection.connection_frame.headers['session']
puts "START: Queue/Topic Name: #{@queue}"
puts "START: Session: #{@session}"
puts "START: NMSGS: #{@nmsgs}"
puts "START: Receipt: #{@getreceipt}"
puts "START: Wanted Messages Per Second: #{@umps}"
puts "START: Sleep Time: #{@tslt}"
$stdout.flush
end # start
#
def shutdown
@connection.disconnect()
#
te = Time.now.to_f
et = te - @nmts
avgsz = @to / @nts
mps = @nts.to_f / et
#
fet = sprintf(@ffmts, et)
favgsz = sprintf(@ffmts, avgsz)
fmps = sprintf(@ffmts, mps)
#
sep = "=" * 72
puts sep
puts "\tNumber of payloads generated: #{@nts}"
puts "\tMin Length: #{@cmin}, Max Length: #{@cmax}"
puts "\tAVG_SIZE: #{favgsz}, ELAPS_SEC: #{fet}(seconds)"
puts "\tNMSGS_PER_SEC: #{fmps}"
puts sep
#
puts "SHUT: Shutdown complete"
$stdout.flush
end # shutdown
#
def msg_handler
m = "Message: "
nm = 0
@nmsgs.times do |n|
nm += 1
puts "MSH: NEXT MESSAGE NUMBER: #{nm}"; $stdout.flush
mo = PayloadGenerator::payload()
@to += mo.bytesize()
if @getreceipt
uuid = @connection.uuid()
puts "MSH: Receipt id wanted is #{uuid}"
hs = {:session => @session, :receipt => uuid}
else
hs = {:session => @session}
end
# Move data out the door
@connection.publish(@queue, mo, hs)
if @getreceipt
r = @connection.receive()
puts "MSH: received receipt, id is #{r.headers['receipt-id']}"
raise if uuid != r.headers['receipt-id']
end
#
puts "MSH: start user sleep"
sleep @tslt # see issue discussion
puts "MSH: end user sleep"
$stdout.flush
end # @nmsgs.times do
puts "MSH: end of msg_handler"
$stdout.flush
end # msg_handler
end # class
#
1.times do |i|
rpt = MemoryProfiler.report do
e = Issue121Examp01Conn.new
e.start
e.msg_handler
# No subscribes here, just msg_handler
# See discussion in issue #121
e.shutdown
end
n = Time.now
nf = "memory_profiler-ng"
nf << n.strftime("%Y%m%dT%H%M%S.%N%Z")
where_name = File::join(Dir::tmpdir(), nf)
rpt.pretty_print(to_file: where_name )
# sleep 1
end
#
stomp-1.4.4/adhoc/issue121_02.rb 0000644 0000041 0000041 00000007450 13120662775 016211 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'stomp'
# Focus on this gem's capabilities.
# require 'memory_profiler'
require 'memory-profiler'
if Kernel.respond_to?(:require_relative)
require_relative("stomp_adhoc_common")
require_relative("payload_generator")
else
$LOAD_PATH << File.dirname(__FILE__)
require "stomp_adhoc_common"
require("payload_generator")
end
include Stomp11Common
# Round 2 of testing around issue #121.
class Issue121Examp02
attr_reader :client, :session
# Initialize.
def initialize(topic = false)
@client, @session, @topic = nil, nil, topic
@nmsgs = nmsgs()
@queue = make_destination("issue121/test_02")
@id = "issue121_02"
@block = cli_block()
#
@cmin, @cmax = 1292, 67782 # From the issue discussion
PayloadGenerator::initialize(min= @cmin, max= @cmax)
@ffmts = "%16.6f"
#
mps = 5.6 # see issue discussion
@to, @nmts, @nts, @umps = 0.0, Time.now.to_f, @nmsgs, mps
@tslt = 1.0 / @umps
end # initialize
# Startup
def start
#
client_hdrs = {"accept-version" => "1.1,1.2",
"host" => virt_host,
}
#
client_hash = { :hosts => [
{:login => login(), :passcode => passcode(), :host => host(), :port => port()},
],
:connect_headers => client_hdrs,
}
#
@client = Stomp::Client.new(client_hash)
puts "START: Client Connect complete"
raise "START: Connection failed!!" unless @client.open?
raise "START: Unexpected protocol level!!" if @client.protocol() == Stomp::SPL_10
cf = @client.connection_frame()
puts "START: Connection frame\n#{cf}"
raise "START: Connect error!!: #{cf.body}" if @client.connection_frame().command == Stomp::CMD_ERROR
@session = @client.connection_frame().headers['session']
puts "START: Queue/Topic Name: #{@queue}"
puts "START: Session: #{@session}"
puts "START: NMSGS: #{@nmsgs}"
puts "START: Block: #{@block}"
puts "START: Wanted Messages Per Second: #{@umps}"
puts "START: Sleep Time: #{@tslt}"
$stdout.flush
end # start
#
def shutdown
@client.close
#
te = Time.now.to_f
et = te - @nmts
avgsz = @to / @nts
mps = @nts.to_f / et
#
fet = sprintf(@ffmts, et)
favgsz = sprintf(@ffmts, avgsz)
fmps = sprintf(@ffmts, mps)
#
sep = "=" * 72
puts sep
puts "\tNumber of payloads generated: #{@nts}"
puts "\tMin Length: #{@cmin}, Max Length: #{@cmax}"
puts "\tAVG_SIZE: #{favgsz}, ELAPS_SEC: #{fet}(seconds)"
puts "\tNMSGS_PER_SEC: #{fmps}"
puts sep
#
puts "SHUT: Shutdown complete"
$stdout.flush
end # shutdown
# pub
def publish
m = "Message: "
nm = 0
@nmsgs.times do |n|
nm += 1
puts "PUB: NEXT MESSAGE NUMBER: #{nm}"; $stdout.flush
mo = PayloadGenerator::payload()
@to += mo.bytesize()
hs = {:session => @session}
if @block
ip = false
@client.publish(@queue,
mo,
hs) {|m|
puts "PUB: HAVE_RECEIPT:\nID: #{m.headers['receipt-id']}"
$stdout.flush
ip = m
}
sleep 0.01 until ip
else
@client.publish(@queue, mo, hs)
end # if @block
puts "PUB: start user sleep"
sleep @tslt # see issue discussion
puts "PUB: end user sleep"
$stdout.flush
end # @nmsgs.times do
puts "PUB: end of publish"
$stdout.flush
end # publish
end # class
#
# :limit => is max number of classes to report on
MemoryProfiler::start_daemon( :limit=>25, :delay=>10, :marshal_size=>true, :sort_by=>:absdelta )
#
1.times do |i|
rpt = MemoryProfiler.start( :limit=> 25 ) do
e = Issue121Examp02.new
e.start
e.publish
# No subscribes here, just publish
# See discussion in issue #121
e.shutdown
end
puts MemoryProfiler.format(rpt)
sleep 1
end
#
MemoryProfiler::stop_daemon
stomp-1.4.4/adhoc/README.md 0000644 0000041 0000041 00000001063 13120662775 015260 0 ustar www-data www-data
# The Ruby stomp Gem - Adhoc Items #
This directory will contain a variety of artifacts.
It is envisioned that content will mostly be of interest to gem developers.
However gem clients may find items of interest here as well.
## Issue 121 ##
Much of the initial work in this directory has focused on
recreating / confirming the high memory use described in
[issue 121](https://github.com/stompgem/stomp/issues/121).
Resolution of that issue is TDB (2016.05.25).
stomp-1.4.4/adhoc/issue121_01.rb 0000644 0000041 0000041 00000006060 13120662775 016204 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'stomp'
# Focus on this gem's capabilities.
# require 'memory_profiler'
require 'memory-profiler'
if Kernel.respond_to?(:require_relative)
require_relative("stomp_adhoc_common")
else
$LOAD_PATH << File.dirname(__FILE__)
require "stomp_adhoc_common"
end
include Stomp11Common
# Initial testing around issue #121.
class Issue121Examp01
attr_reader :client, :session
# Initialize.
def initialize(topic = false)
@client, @session, @topic = nil, nil, topic
@nmsgs = nmsgs()
@queue = make_destination("issue121/test_01")
@id = "issue121_01"
@block = cli_block()
end # initialize
# Startup
def start
#
client_hdrs = {"accept-version" => "1.1,1.2",
"host" => virt_host,
}
#
client_hash = { :hosts => [
{:login => login(), :passcode => passcode(), :host => host(), :port => port()},
],
:connect_headers => client_hdrs,
}
#
@client = Stomp::Client.new(client_hash)
puts "START: Client Connect complete"
raise "START: Connection failed!!" unless @client.open?
raise "START: Unexpected protocol level!!" if @client.protocol() == Stomp::SPL_10
cf = @client.connection_frame()
puts "START: Connection frame\n#{cf}"
raise "START: Connect error!!: #{cf.body}" if @client.connection_frame().command == Stomp::CMD_ERROR
@session = @client.connection_frame().headers['session']
puts "START: Queue/Topic Name: #{@queue}"
puts "START: Session: #{@session}"
puts "START: Block: #{@block}"
$stdout.flush
end # start
#
def shutdown
@client.close
puts "SHUT: Shutdown complete"
end # shutdown
# pub
def publish
m = "Message: "
nm = 0
@nmsgs.times do |n|
nm += 1
puts "PUB: NEXT MESSAGE NUMBER: #{nm}"
mo = "#{m} #{n}"
puts "PUB: PAYLOAD: #{mo}"
hs = {:session => @session}
if @block
ip = false
@client.publish(@queue,
mo,
hs) {|m|
puts "PUB: HAVE_RECEIPT:\nID: #{m.headers['receipt-id']}"
ip = m
}
sleep 0.01 until ip
else
@client.publish(@queue, mo, hs)
end # if @block
end # @nmsgs.times do
end # publish
# sub
def subscribe
puts "SUB: Subscribe starts For: #{@queue}"
rmc, done = 0, false
sh = {:id => "#{@id}", :ack => "auto"}
@client.subscribe(@queue, sh) {|m|
rmc += 1
rm = m
puts "SUB: HAVE_MESSAGE:\n#{rm}"
if rmc >= @nmsgs
puts "SUB: Subscribe is ending for #{@queue}"
done = true
Thread.done
end
}
sleep 0.01 until done
puts "SUB: Receives Done For: #{@queue}"
end # subscribe
end # class
#
# puts "BEG: Memory Profiler Version is: #{MemoryProfiler::VERSION}"
MemoryProfiler::start_daemon( :limit=>5, :delay=>10, :marshal_size=>true, :sort_by=>:absdelta )
#
5.times do |i|
rpt = MemoryProfiler.start( :limit=>10 ) do
e = Issue121Examp01.new
e.start
e.publish
e.subscribe
e.shutdown
end
puts MemoryProfiler.format(rpt)
sleep 1
end
#
MemoryProfiler::stop_daemon
stomp-1.4.4/Rakefile 0000644 0000041 0000041 00000004645 13120662775 014401 0 ustar www-data www-data # Copyright 2005-2006 Brian McCallister
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
$:.unshift(File.dirname(__FILE__) + "/lib")
require 'rubygems'
require 'rake'
require 'rake/testtask'
require 'rspec/core/rake_task'
require "stomp/version"
begin
require "hanna-nouveau"
have_hanna = true
rescue LoadError => e
have_hanna = false
end
require "rdoc/task"
begin
require 'jeweler'
Jeweler::Tasks.new do |gem|
gem.name = "stomp"
gem.version = Stomp::Version::STRING
gem.summary = %Q{Ruby client for the Stomp messaging protocol}
gem.license = "Apache-2.0"
gem.description = %Q{Ruby client for the Stomp messaging protocol. Note that this gem is no longer supported on rubyforge.}
gem.email = ["brianm@apache.org", 'marius@stones.com', 'morellon@gmail.com',
'allard.guy.m@gmail.com' ]
gem.homepage = "https://github.com/stompgem/stomp"
gem.authors = ["Brian McCallister", 'Marius Mathiesen', 'Thiago Morello',
'Guy M. Allard']
gem.add_development_dependency 'rspec', '~> 2.14', '>= 2.14.1'
end
Jeweler::GemcutterTasks.new
rescue LoadError
puts "Jeweler not available. Install it with: gem install jeweler"
end
desc 'Run the specs'
RSpec::Core::RakeTask.new(:spec) do |t|
t.rspec_opts = ['--colour']
t.pattern = 'spec/**/*_spec.rb'
end
desc "Rspec : run all with RCov"
RSpec::Core::RakeTask.new('spec:rcov') do |t|
t.pattern = 'spec/**/*_spec.rb'
t.rcov = true
t.rcov_opts = ['--exclude', 'gems', '--exclude', 'spec']
end
Rake::RDocTask.new do |rdoc|
rdoc.main = "README.md"
rdoc.rdoc_dir = "doc"
rdoc.title = "Stomp"
rdoc.options += %w[ --line-numbers --inline-source --charset utf-8 ]
if have_hanna
rdoc.options += %w[ --format hanna ]
end
rdoc.rdoc_files.include("README.md", "CHANGELOG.md", "lib/**/*.rb")
end
Rake::TestTask.new do |t|
t.libs << "test"
t.test_files = FileList['test/test*.rb']
t.verbose = true
end
task :default => :spec
stomp-1.4.4/bin/ 0000755 0000041 0000041 00000000000 13120662775 013473 5 ustar www-data www-data stomp-1.4.4/bin/catstomp 0000755 0000041 0000041 00000004355 13120662775 015262 0 ustar www-data www-data #!/usr/bin/env ruby
#
# Copyright 2006 LogicBlaze Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
begin; require 'rubygems'; rescue; end
require 'stomp'
#
# This simple script is inspired by the netcat utility. It allows you to publish
# input into this process to stomp destination.
#
# Usage: catstomp (destination-name)
#
# Example: ls | catstomp /topic/foo
# Would publish the output of the ls command to the stomp destination /topic/foo
#
begin
if ARGV[0] == '-h' || ARGV[0] == '--help'
$stdout.puts
$stdout.puts 'Usage: catstomp DESTINATION'
$stdout.puts
$stdout.puts 'Publishes STDIN to the desired stomp destination'
$stdout.puts
$stdout.puts 'Example: ls | catstomp /topic/foo'
$stdout.puts
$stdout.puts 'Defaults:'
$stdout.puts "DESTINATION\t/topic/default"
$stdout.puts "STOMP_HOST\tlocalhost"
$stdout.puts "STOMP_PORT\t61613"
$stdout.puts "STOMP_USER"
$stdout.puts "STOMP_PASSWORD"
$stdout.puts
$stdout.puts 'You can override the stomp host, port, user, or password through environment variables'
exit 0
end
@port = 61613
@host = "localhost"
@user = ENV["STOMP_USER"];
@password = ENV["STOMP_PASSWORD"]
@host = ENV["STOMP_HOST"] if ENV["STOMP_HOST"] != nil
@port = ENV["STOMP_PORT"] if ENV["STOMP_PORT"] != nil
@destination = "/topic/default"
@destination = $*[0] if $*[0] != nil
$stderr.print "Connecting to stomp://#{@host}:#{@port} as #{@user}\n"
@conn = Stomp::Connection.open(@user, @password, @host, @port, true)
$stderr.print "Sending input to #{@destination}\n"
@headers = {'persistent'=>'false'}
@headers['reply-to'] = $*[1] if $*[1] != nil
STDIN.each_line { |line|
@conn.publish @destination, line, @headers
}
rescue
end
stomp-1.4.4/bin/stompcat 0000755 0000041 0000041 00000004403 13120662775 015254 0 ustar www-data www-data #!/usr/bin/env ruby
#
# Copyright 2006 LogicBlaze Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
begin; require 'rubygems'; rescue; end
require 'stomp'
#
# This simple script is inspired by the netcat utility. It allows you to receive
# data from a stomp destination and output it.
#
# Usage: stompcat (destination-name)
#
# Example: stompcat /topic/foo
# Would display output that arrives at the /topic/foo stomp destination
#
begin
if ARGV[0] == '-h' || ARGV[0] == '--help'
$stdout.puts
$stdout.puts 'Usage: stompcat DESTINATION'
$stdout.puts
$stdout.puts 'Receives data from a stomp destination and outputs it to STDOUT'
$stdout.puts
$stdout.puts 'Example: stompcat /topic/foo'
$stdout.puts
$stdout.puts 'Defaults:'
$stdout.puts "DESTINATION\t/topic/default"
$stdout.puts "STOMP_HOST\tlocalhost"
$stdout.puts "STOMP_PORT\t61613"
$stdout.puts "STOMP_USER\t"
$stdout.puts "STOMP_PASSWORD\t"
$stdout.puts
$stdout.puts 'You can override the host, port, user, or password through environment variables'
exit 0
end
@port = 61613
@host = "localhost"
@user = ENV["STOMP_USER"];
@password = ENV["STOMP_PASSWORD"]
@host = ENV["STOMP_HOST"] if ENV["STOMP_HOST"] != nil
@port = ENV["STOMP_PORT"] if ENV["STOMP_PORT"] != nil
@destination = "/topic/default"
@destination = $*[0] if $*[0] != nil
$stderr.print "Connecting to stomp://#{@host}:#{@port} as #{@user}\n"
@conn = Stomp::Connection.open(@user, @password, @host, @port, true)
$stderr.print "Getting output from #{@destination}\n"
@conn.subscribe(@destination, { :ack =>"client" })
while true
@msg = @conn.receive
$stdout.print @msg.body
$stdout.flush
@conn.ack @msg.headers["message-id"]
end
rescue
end
stomp-1.4.4/examples/ 0000755 0000041 0000041 00000000000 13120662775 014541 5 ustar www-data www-data stomp-1.4.4/examples/ssl_ctxoptions.rb 0000644 0000041 0000041 00000006167 13120662775 020173 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
require "rubygems"
require "stomp"
#
# == Demo User Control of SSLContext options contents
#
# Roughly based on example ssl_uc1.rb.
# See comments in that example for more detail.
#
# Not tested with jruby. YMMV.
#
class ExampleSSLCtxOptions
# Initialize.
def initialize
end
# Run example 1
def run1
require 'openssl' unless defined?(OpenSSL)
puts "run method ...."
# Define SSL Options to be used. This code is copied from the defaults
# in later versions of Ruby V2.x (which has been backported to 1.9.3).
#
# Connection / Example 1 of 2, user supplied options.
#
# Build SSL Options per user requirements: this is just one
# particular/possible example of setting SSL context options.
opts = OpenSSL::SSL::OP_ALL
# Perhaps. If you need/want any of these you will know it.
# This is exactly what is done in later versions of Ruby 2.x (also has
# been backported by Ruby team to later versions of 1.9.3).
opts &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS if defined?(OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS)
opts |= OpenSSL::SSL::OP_NO_COMPRESSION if defined?(OpenSSL::SSL::OP_NO_COMPRESSION)
opts |= OpenSSL::SSL::OP_NO_SSLv2 if defined?(OpenSSL::SSL::OP_NO_SSLv2)
opts |= OpenSSL::SSL::OP_NO_SSLv3 if defined?(OpenSSL::SSL::OP_NO_SSLv3)
urc = defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/ ? true : false
# Pass options to SSLParams constructor.
ssl_opts = Stomp::SSLParams.new(:ssl_ctxopts => opts, # SSLContext options to set
:use_ruby_ciphers => urc,
:fsck => true)
sport = ENV["STOMP_PORT"].to_i
hash = { :hosts => [
{:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => sport, :ssl => ssl_opts},
],
:reliable => false, # YMMV, to test this in a sane manner
}
#
puts "Connect starts, SSLContext Options Set: #{opts}"
c = Stomp::Connection.new(hash)
puts "Connect completed"
puts "SSL Verify Result: #{ssl_opts.verify_result}"
# puts "SSL Peer Certificate:\n#{ssl_opts.peer_cert}"
#
c.disconnect
end
# Run example 2
def run2
puts "run2 method ...."
#
# Connection / Example 2 of 2, gem supplied options.
#
urc = defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/ ? true : false
# Use gem method to define SSL options. Exactly the same as the
# options used in Example 1 above.
ssl_opts = Stomp::SSLParams.new(:ssl_ctxopts => Stomp::Connection::ssl_v2xoptions(),
:use_ruby_ciphers => urc,
:fsck => true)
sport = ENV["STOMP_PORT"].to_i
hash = { :hosts => [
{:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => sport, :ssl => ssl_opts},
],
:reliable => false, # YMMV, to test this in a sane manner
}
#
puts "Connect starts, SSLContext Options Set: #{Stomp::Connection::ssl_v2xoptions()}"
c = Stomp::Connection.new(hash)
puts "Connect completed"
puts "SSL Verify Result: #{ssl_opts.verify_result}"
# puts "SSL Peer Certificate:\n#{ssl_opts.peer_cert}"
#
c.disconnect
end
end
#
e = ExampleSSLCtxOptions.new
e.run1
e.run2
stomp-1.4.4/examples/examplogger.rb 0000644 0000041 0000041 00000016510 13120662775 017403 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'logger' # use the standard Ruby logger .....
# == Example STOMP call back logger class.
#
# Optional callback methods:
#
# * on_connecting: connection starting
# * on_connected: successful connect
# * on_connectfail: unsuccessful connect (will usually be retried)
# * on_disconnect: successful disconnect
#
# * on_miscerr: on miscellaneous xmit/recv errors
#
# * on_publish: publish called
# * on_subscribe: subscribe called
# * on_unsubscribe: unsubscribe called
#
# * on_begin: begin called
# * on_ack: ack called
# * on_nack: nack called
# * on_commit: commit called
# * on_abort: abort called
#
# * on_receive: receive called and successful
#
# * on_ssl_connecting: SSL connection starting
# * on_ssl_connected: successful SSL connect
# * on_ssl_connectfail: unsuccessful SSL connect (will usually be retried)
#
# * on_hbread_fail: unsuccessful Heartbeat read
# * on_hbwrite_fail: unsuccessful Heartbeat write
# * on_hbfire: on any send or receive heartbeat
#
# All methods are optional, at the user's requirements.
#
# If a method is not provided, it is not called (of course.)
#
# IMPORTANT NOTE: in general, call back logging methods *SHOULD* not raise exceptions,
# otherwise the underlying STOMP connection may fail in mysterious ways.
#
# There are two useful exceptions to this rule for:
#
# * on_connectfail
# * on_ssl_connectfail
#
# These two methods can raise a Stomp::Errors::LoggerConnectionError. If this
# exception is raised, it is passed up the chain to the caller.
#
# Callback parameters: are a copy of the @parameters instance variable for
# the Stomp::Connection.
#
# A logger class may optionally inherit from the provided NullLogger
#
# # class Slogger < Stomp::NullLogger
#
class Slogger
# Initialize a new callback logger instance.
def initialize(init_parms = nil)
_init
@log.info("Logger initialization complete.")
end
def _init
@log = Logger::new(STDOUT) # User preference
@log.level = Logger::DEBUG # User preference
end
def marshal_dump
[]
end
def marshal_load(array)
_init
end
# Log connecting events
def on_connecting(parms)
begin
@log.debug "Connecting: #{info(parms)}"
rescue
@log.debug "Connecting oops"
end
end
# Log connected events
def on_connected(parms)
begin
@log.debug "Connected: #{info(parms)}"
rescue
@log.debug "Connected oops"
end
end
# Log connectfail events
def on_connectfail(parms)
begin
@log.debug "Connect Fail #{info(parms)}"
rescue
@log.debug "Connect Fail oops"
end
=begin
rescue
# An example LoggerConnectionError raise
@log.debug "Connect Fail, will raise"
raise Stomp::Error::LoggerConnectionError.new("quit from connect fail")
end
=end
end
# Log disconnect events
def on_disconnect(parms)
begin
@log.debug "Disconnected #{info(parms)}"
rescue
@log.debug "Disconnected oops"
end
end
# Log miscellaneous errors
def on_miscerr(parms, errstr)
begin
@log.debug "Miscellaneous Error #{info(parms)}"
@log.debug "Miscellaneous Error String #{errstr}"
rescue
@log.debug "Miscellaneous Error oops"
end
end
# Log Subscribe
def on_subscribe(parms, headers)
begin
@log.debug "Subscribe Parms #{info(parms)}"
@log.debug "Subscribe Headers #{headers}"
rescue
@log.debug "Subscribe oops"
end
end
# Log UnSubscribe
def on_unsubscribe(parms, headers)
begin
@log.debug "UnSubscribe Parms #{info(parms)}"
@log.debug "UnSubscribe Headers #{headers}"
rescue
@log.debug "UnSubscribe oops"
end
end
# Log Publish
def on_publish(parms, message, headers)
begin
@log.debug "Publish Parms #{info(parms)}"
@log.debug "Publish Message #{message}"
@log.debug "Publish Headers #{headers}"
rescue
@log.debug "Publish oops"
end
end
# Log Receive
def on_receive(parms, result)
begin
@log.debug "Receive Parms #{info(parms)}"
@log.debug "Receive Result #{result}"
rescue
@log.debug "Receive oops"
end
end
# Log Begin
def on_begin(parms, headers)
begin
@log.debug "Begin Parms #{info(parms)}"
@log.debug "Begin Result #{headers}"
rescue
@log.debug "Begin oops"
end
end
# Log Ack
def on_ack(parms, headers)
begin
@log.debug "Ack Parms #{info(parms)}"
@log.debug "Ack Result #{headers}"
rescue
@log.debug "Ack oops"
end
end
# Log NAck
def on_nack(parms, headers)
begin
@log.debug "NAck Parms #{info(parms)}"
@log.debug "NAck Result #{headers}"
rescue
@log.debug "NAck oops"
end
end
# Log Commit
def on_commit(parms, headers)
begin
@log.debug "Commit Parms #{info(parms)}"
@log.debug "Commit Result #{headers}"
rescue
@log.debug "Commit oops"
end
end
# Log Abort
def on_abort(parms, headers)
begin
@log.debug "Abort Parms #{info(parms)}"
@log.debug "Abort Result #{headers}"
rescue
@log.debug "Abort oops"
end
end
# Stomp 1.1+ - heart beat read (receive) failed.
def on_hbread_fail(parms, ticker_data = {})
begin
@log.debug "Hbreadf Parms #{info(parms)}"
@log.debug "Hbreadf Result #{ticker_data.inspect}"
rescue
@log.debug "Hbreadf oops"
end
end
# Stomp 1.1+ - heart beat send (transmit) failed.
def on_hbwrite_fail(parms, ticker_data = {})
begin
@log.debug "Hbwritef Parms #{info(parms)}"
@log.debug "Hbwritef Result #{ticker_data.inspect}"
rescue
@log.debug "Hbwritef oops"
end
end
# Log SSL connection start.
def on_ssl_connecting(parms)
begin
@log.debug "SSL Connecting Parms #{info(parms)}"
rescue
@log.debug "SSL Connecting oops"
end
end
# Log a successful SSL connect.
def on_ssl_connected(parms)
begin
@log.debug "SSL Connected Parms #{info(parms)}"
rescue
@log.debug "SSL Connected oops"
end
end
# Log an unsuccessful SSL connect.
def on_ssl_connectfail(parms)
begin
@log.debug "SSL Connect Fail Parms #{info(parms)}"
@log.debug "SSL Connect Fail Exception #{parms[:ssl_exception]}, #{parms[:ssl_exception].message}"
rescue
@log.debug "SSL Connect Fail oops"
end
=begin
# An example LoggerConnectionError raise
@log.debug "SSL Connect Fail, will raise"
raise Stomp::Error::LoggerConnectionError.new("quit from SSL connect")
=end
end
# Log heart beat fires
def on_hbfire(parms, srind, firedata = {})
begin
@log.debug "HeartBeat Fire Parms #{info(parms)}"
@log.debug "HeartBeat Fire Send/Receive #{srind}"
rescue
@log.debug "HeartBeat Fire oops"
end
end
private
# Example information extract.
def info(parms)
#
# Available in the parms Hash:
# parms[:cur_host]
# parms[:cur_port]
# parms[:cur_login]
# parms[:cur_passcode]
# parms[:cur_ssl]
# parms[:cur_recondelay]
# parms[:cur_parseto]
# parms[:cur_conattempts]
# parms[:openstat]
#
# For the on_ssl_connectfail callback these are also available:
# parms[:ssl_exception]
#
"Host: #{parms[:cur_host]}, Port: #{parms[:cur_port]}, Login: #{parms[:cur_login]}, Passcode: #{parms[:cur_passcode]}, ssl: #{parms[:cur_ssl]}"
end
end # of class
stomp-1.4.4/examples/ssl_uc2.rb 0000644 0000041 0000041 00000003315 13120662775 016442 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
# Reference: https://github.com/stompgem/stomp/wiki/extended-ssl-overview
#
if Kernel.respond_to?(:require_relative)
require_relative("./ssl_common")
else
$LOAD_PATH << File.dirname(__FILE__)
require "ssl_common"
end
include SSLCommon
#
# == SSL Use Case 2 - server does *not* authenticate client, client *does* authenticate server
#
# Subcase 2.A - Message broker configuration does *not* require client authentication
#
# - Expect connection success
# - Expect a verify result of 0 becuase the client did authenticate the
# server's certificate.
#
# Subcase 2.B - Message broker configuration *does* require client authentication
#
# - Expect connection failure (broker must be sent a valid client certificate)
#
class ExampleSSL2
# Initialize.
def initialize
# Change the following as needed.
@host = ENV['STOMP_HOST'] ? ENV['STOMP_HOST'] : "localhost"
@port = ENV['STOMP_PORT'] ? ENV['STOMP_PORT'].to_i : 61612
end
# Run example.
def run
puts "Connect host: #{@host}, port: #{@port}"
ts_flist = []
# Possibly change/override the cert data here.
ts_flist << "#{ca_loc()}/#{ca_cert()}"
ssl_opts = Stomp::SSLParams.new(:ts_files => ts_flist.join(","),
:fsck => true)
#
hash = { :hosts => [
{:login => 'guest', :passcode => 'guest', :host => @host, :port => @port, :ssl => ssl_opts},
],
:reliable => false, # YMMV, to test this in a sane manner
}
#
puts "Connect starts, SSL Use Case 2"
c = Stomp::Connection.new(hash)
puts "Connect completed"
puts "SSL Verify Result: #{ssl_opts.verify_result}"
# puts "SSL Peer Certificate:\n#{ssl_opts.peer_cert}"
c.disconnect
end
end
#
e = ExampleSSL2.new
e.run
stomp-1.4.4/examples/ssl_ucx_default_ciphers.rb 0000644 0000041 0000041 00000001643 13120662775 021773 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
# Reference: https://github.com/stompgem/stomp/wiki/extended-ssl-overview
#
require "rubygems"
require "stomp"
#
# == Example: Use Ruby Supplied Ciphers
#
# If you use SSLParams, and need the _default_ Ruby ciphers, this is how.
#
# NOTE: JRuby users may find that this is a *required* action. YMMV.
#
class ExampleRubyCiphers
# Initialize.
def initialize
end
# Run example.
def run
ssl_opts = Stomp::SSLParams.new(:use_ruby_ciphers => true) # Plus other parameters as needed
#
# SSL Use Case: Using default Stomp ciphers
#
hash = { :hosts => [
{:login => 'guest', :passcode => 'guest', :host => 'localhost',
:port => 61612, :ssl => ssl_opts},
]
}
#
puts "Connect starts, SSL , Use Default Ruby Ciphers"
c = Stomp::Connection.new(hash)
puts "Connect completed"
#
c.disconnect
end
end
#
e = ExampleRubyCiphers.new
e.run
stomp-1.4.4/examples/ssl_newparm.rb 0000644 0000041 0000041 00000002047 13120662775 017423 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
# Reference: https://github.com/stompgem/stomp/wiki/extended-ssl-overview
#
require "rubygems"
require "stomp"
#
# == Demo override of SSLContext.new parameters.
#
# Based roughly on example ssl_uc1.rb.
#
#
class ExampleSSLNewParm
# Initialize.
def initialize
end
# Run example.
def run
ssl_opts = Stomp::SSLParams.new
hash = { :hosts => [
{:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
],
:reliable => false, # YMMV, to test this in a sane manner
:sslctx_newparm => :SSLv2, # An example should you:
# a) Actually want SSLv2 *AND*
# b) Your Ruby version supports SSLv2 *AND*
# c) Your broker supports and allows SSLv2
}
#
puts "Connect starts, SSL Use Case 1"
c = Stomp::Connection.new(hash)
puts "Connect completed"
puts "SSL Verify Result: #{ssl_opts.verify_result}"
# puts "SSL Peer Certificate:\n#{ssl_opts.peer_cert}"
#
c.disconnect
end
end
#
e = ExampleSSLNewParm.new
e.run
stomp-1.4.4/examples/get11conn_ex1.rb 0000644 0000041 0000041 00000006407 13120662775 017451 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
# The current require dance for different Ruby versions.
# Change this to suit your requirements.
#
if Kernel.respond_to?(:require_relative)
require_relative("./stomp11_common")
else
$LOAD_PATH << File.dirname(__FILE__)
require "stomp11_common"
end
include Stomp11Common
#
# == Stomp 1.1 Receive Example 1
#
# Purpose: to demonstrate receiving messages using Stomp 1.1.
#
class Receive11Example1
# Initialize.
def initialize
end
# Run example.
def run
conn = get_connection() # Use helper method to obtain a Stomp#connection
raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
#
# To start receiving messages, you must first subscribe. This is similar
# to using Stomp 1.0.
#
# However, with Stomp 1.1:
#
# * for subscribe, the 'id' header is now _required_
# * for unsubscribe, the 'id' header is now _required_
#
# The 'id' header specifies a 'subscription id' that _must_ be unique for
# the current session.
#
qname = "/queue/nodea.nodeb.nodec"
#
# Here is an example of allowed functionality in 1.0 that is not allowed in 1.1:
#
begin
conn.subscribe qname
rescue RuntimeError => sre
puts "Rescue: #{sre}, #{sre.message}"
end
#
# So, you must specify an 'id' header. And it must be unique within the
# current session.
#
# You can build your own unique ids of course. That is a valid option.
# In order to provide you with some assistance in generating unique ids,
# two convenience methods are provided with the connection:
#
# * sha1 - generate a sha1 hash of some data you supply. This may be sufficient for many purposes.
# * uuid - generate a type 4 UUID. This would be sufficient in all cases.
#
# Get a sha1:
#
sha1 = conn.sha1(qname) # sha1 of the queue name perhaps
puts "Queue name: #{qname}, sha1: #{sha1}"
#
# Or perhaps a different sha1:
#
tn = Time.now.to_f.to_s # Maybe unique itself.
sha1 = conn.sha1(tn)
puts "Time now: #{tn}, sha1: #{sha1}"
#
# Or a Type 4 UUID:
#
uuid = conn.uuid()
puts "Type 4 UUID: #{uuid}"
#
# You can specify the 'id' in the subscribe call in one of two ways:
#
# a) In the headers parameter
# b) In the third positional parameter, the subId
#
# So, using the 'uuid', either:
#
# a) conn.subscribe qname, {'id' => uuid}
# b) conn.subscribe qname, {}, uuid
#
conn.subscribe qname, {'id' => uuid} # First style
#
# Within a session, you may not subscribe to the same subscription id.
#
begin
conn.subscribe qname, {'id' => uuid} # Second time
rescue RuntimeError => sre
puts "Rescue: #{sre}, #{sre.message}"
end
#
# Once you have subscribed, you may receive as usual
#
1.upto(nmsgs()) do
received = conn.receive
puts "Received data: #{received.body}"
end
#
# For unsubscribe, you must use the 'id' you used on subscribe.
#
# You have the same options for placing this id in the headers or in the 3rd
# positional parameter.
#
conn.unsubscribe qname, {}, uuid # Second style
#
# And finally, disconnect.
#
conn.disconnect
end
end
#
e = Receive11Example1.new
e.run
stomp-1.4.4/examples/client11_ex1.rb 0000644 0000041 0000041 00000005560 13120662775 017271 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
# The current require dance for different Ruby versions.
# Change this to suit your requirements.
#
if Kernel.respond_to?(:require_relative)
require_relative("./stomp11_common")
else
$LOAD_PATH << File.dirname(__FILE__)
require "stomp11_common"
end
include Stomp11Common
#
# == Stomp 1.1 Client Example 1
#
# Purpose: to demonstrate a connect and disconnect sequence using Stomp 1.1
# with the Stomp#Client interface.
#
class Client11Example1
# Initialize.
def initialize
end
# Run example.
def run
# Note: Stomp#Client does not provide a positional set of parameters that
# contain a 'connect_headers' parameter. To use the Stomp#Client interface
# you _must_ use a 'hashed' set of parameters.
#
# Create connection headers
# =========================
#
# The two headers used here are _required_ by the specification.
#
client_hdrs = {"accept-version" => "1.1", # Demand a 1.1 connection (use a CSV list if you will consider multiple versions)
"host" => virt_host, # The 1.1 vhost (could be different than connection host)
} # No heartbeats here: there will be none for this connection
#
# Create the connect hash.
# ========================
#
client_hash = { :hosts => [
{:login => login, :passcode => passcode, :host => host, :port => port},
],
:connect_headers => client_hdrs,
}
#
# Get a connection
# ================
#
client = Stomp::Client.new(client_hash)
puts "Client Connect complete"
#
# Let's just do some sanity checks, and look around.
#
raise "Connection failed!!" unless client.open?
#
# Is this really a 1.1 conection? (For clients, 'protocol' is a public method.
# The value will be '1.0' for those types of connections.)
#
raise "Unexpected protocol level" if client.protocol() != Stomp::SPL_11
#
# The broker _could_ have returned an ERROR frame (unlikely).
# For clients, 'connection_frame' is a public method.
#
raise "Connect error: #{client.connection_frame().body}" if client.connection_frame().command == Stomp::CMD_ERROR
#
# Examine the CONNECT response (the connection_frame()).
#
puts "Connected Headers required to be present:"
puts "Connect version - \t#{client.connection_frame().headers['version']}"
puts
puts "Connected Headers that are optional:"
puts "Connect server - \t\t#{client.connection_frame().headers['server']}"
puts "Session ID - \t\t\t#{client.connection_frame().headers['session']}"
puts "Server requested heartbeats - \t#{client.connection_frame().headers['heart-beat']}"
#
# Finally close
# =============
#
client.close # Business as usual, just like 1.0
puts "Client close complete"
end
end
#
e = Client11Example1.new
e.run
stomp-1.4.4/examples/logexamp_ssl.rb 0000644 0000041 0000041 00000005571 13120662775 017573 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'rubygems'
require 'stomp'
require 'logger' # for the 'local' logger
#
if Kernel.respond_to?(:require_relative)
require_relative("./examplogger")
else
$LOAD_PATH << File.dirname(__FILE__)
require "examplogger"
end
#
# == A STOMP::Connection program which uses the callback logging facility.
#
class SSLLoggerExample
# Initialize.
def initialize
end
# Run example.
def run
llog = Logger::new(STDOUT)
llog.level = Logger::DEBUG
llog.debug "LESSL Starting"
# //////////////////////////////////////////////////////////////////////////////
mylog = Slogger::new # The client provided STOMP callback logger
# //////////////////////////////////////////////////////////////////////////////
user = ENV['STOMP_USER'] ? ENV['STOMP_USER'] : 'guest'
password = ENV['STOMP_PASSWORD'] ? ENV['STOMP_PASSWORD'] : 'guest'
host = ENV['STOMP_HOST'] ? ENV['STOMP_HOST'] : 'localhost'
port = ENV['STOMP_PORT'] ? ENV['STOMP_PORT'].to_i : 61612
# //////////////////////////////////////////////////////////////////////////////
# A hash type connect *MUST* be used to enable callback logging.
# //////////////////////////////////////////////////////////////////////////////
hash = { :hosts => [
{:login => user, :passcode => password, :host => host, :port => port,
:ssl => true}, # Or provide your insance of SSLParams instead
],
:logger => mylog, # This enables callback logging!
:max_reconnect_attempts => 2,
}
# //////////////////////////////////////////////////////////////////////////////
# For a Connection:
llog.debug "LESSL Connection processing starts"
conn = Stomp::Connection.new(hash)
conn.disconnect
# //////////////////////////////////////////////////////////////////////////////
llog.debug "LESSL Connection processing complete"
# //////////////////////////////////////////////////////////////////////////////
# For a Client:
llog.debug "LESSL Client processing starts"
conn = Stomp::Client.new(hash)
conn.close
# //////////////////////////////////////////////////////////////////////////////
llog.debug "LESSL Client processing complete"
# //////////////////////////////////////////////////////////////////////////////
# For a Connection with other calls:
llog.debug "LESSL Connection Enhanced processing starts"
conn = Stomp::Connection.new(hash)
#
dest = "/queue/loggerq1"
conn.publish dest, "a logger message"
conn.subscribe dest
msg = conn.receive
conn.disconnect
# //////////////////////////////////////////////////////////////////////////////
llog.debug "LESSL Connection Enhanced processing complete"
# //////////////////////////////////////////////////////////////////////////////
llog.debug "LESSL Ending"
end
end
#
e = SSLLoggerExample.new
e.run
stomp-1.4.4/examples/conn11_hb1.rb 0000644 0000041 0000041 00000003032 13120662775 016715 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
# The current require dance for different Ruby versions.
# Change this to suit your requirements.
#
if Kernel.respond_to?(:require_relative)
require_relative("./stomp11_common")
require_relative("./examplogger")
else
$LOAD_PATH << File.dirname(__FILE__)
require "stomp11_common"
require "examplogger"
end
include Stomp11Common
#
# == Stomp 1.1 Heartbeat Example 1
#
# Purpose: to demonstrate that heart beats can work.
#
class HeartBeatExample1
# Initialize.
def initialize
end
# Run example.
def run
# Create connection headers
# =========================
#
conn_hdrs = {"accept-version" => "1.1", # 1.1
"host" => virt_host, # vhost
"heart-beat" => "5000,10000", # heartbeats
}
# Create a logger for demonstration purposes
logger = Slogger.new
# Connect - a paramaterized request.
conn = Stomp::Connection.new(login, passcode, host, port, # Normal connect parms
false, # Not reliable, the default for a paramaterized connection
5, # Connect redelay, the default for a paramaterized connection
conn_hdrs) # The 1.1 connection parameters / headers
puts "Connection connect complete"
#
raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
#
conn.set_logger(logger) # Connection uses a logger
sleep 65
conn.set_logger(nil) # No logging
#
conn.disconnect # Get out
puts "Connection disconnect complete"
end
end
#
e = HeartBeatExample1.new
e.run
stomp-1.4.4/examples/ssl_uc1.rb 0000644 0000041 0000041 00000003246 13120662775 016444 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
# Reference: https://github.com/stompgem/stomp/wiki/extended-ssl-overview
#
#
if Kernel.respond_to?(:require_relative)
require_relative("./ssl_common")
else
$LOAD_PATH << File.dirname(__FILE__)
require "ssl_common"
end
include SSLCommon
#
# == SSL Use Case 1 - server does *not* authenticate client, client does *not* authenticate server
#
# Subcase 1.A - Message broker configuration does *not* require client authentication
#
# - Expect connection success
# - Expect a verify result of 20 becuase the client did not authenticate the
# server's certificate.
#
# Subcase 1.B - Message broker configuration *does* require client authentication
#
# - Expect connection failure (broker must be sent a valid client certificate)
#
class ExampleSSL1
# Initialize.
def initialize # Change the following as needed.
@host = ENV['STOMP_HOST'] ? ENV['STOMP_HOST'] : "localhost"
@port = ENV['STOMP_PORT'] ? ENV['STOMP_PORT'].to_i : 61612
end
# Run example.
def run
puts "Connect host: #{@host}, port: #{@port}"
ssl_opts = Stomp::SSLParams.new # or ssl_opts = true (for this use case)
#### ssl_opts = false # for testing HandShakeDetectedError exception
hash = { :hosts => [
{:login => 'guest', :passcode => 'guest', :host => @host, :port => @port, :ssl => ssl_opts},
],
:reliable => false, # YMMV, to test this in a sane manner
}
#
puts "Connect starts, SSL Use Case 1"
c = Stomp::Connection.new(hash)
puts "Connect completed"
puts "SSL Verify Result: #{ssl_opts.verify_result}"
# puts "SSL Peer Certificate:\n#{ssl_opts.peer_cert}"
#
c.disconnect
end
end
#
e = ExampleSSL1.new
e.run
stomp-1.4.4/examples/topic_consumer.rb 0000644 0000041 0000041 00000001137 13120662775 020121 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'rubygems'
require 'stomp'
#
# == Example topic consumer.
#
class ExampleTopicConsumer
# Initialize.
def initialize
end
# Run example.
def run
client = Stomp::Client.new("failover://(stomp://:@localhost:61613,stomp://:@remotehost:61613)?initialReconnectDelay=5000&randomize=false&useExponentialBackOff=false")
puts "Subscribing to /topic/ronaldo"
client.subscribe("/topic/ronaldo") do |msg|
puts msg.to_s
puts "----------------"
end
loop do
sleep(1)
puts "."
end
end
end
#
e = ExampleTopicConsumer.new
e.run
stomp-1.4.4/examples/topic_publisher.rb 0000644 0000041 0000041 00000001161 13120662775 020260 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'rubygems'
require 'stomp'
#
# == Example topic publisher.
#
class ExampleTopicPublisher
# Initialize.
def initialize
end
# Run example.
def run
client = Stomp::Client.new("failover://(stomp://:@localhost:61613,stomp://:@remotehost:61613)?initialReconnectDelay=5000&randomize=false&useExponentialBackOff=false")
message = "ronaldo #{ARGV[0]}"
for i in (1..50)
puts "Sending message"
client.publish("/topic/ronaldo", "#{i}: #{message}")
puts "(#{Time.now})Message sent: #{i}"
sleep 0.2
end
end
end
#
e = ExampleTopicPublisher.new
e.run
stomp-1.4.4/examples/ssl_uc4_ciphers.rb 0000644 0000041 0000041 00000005164 13120662775 020165 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
# Reference: https://github.com/stompgem/stomp/wiki/extended-ssl-overview
#
if Kernel.respond_to?(:require_relative)
require_relative("./ssl_common")
else
$LOAD_PATH << File.dirname(__FILE__)
require "ssl_common"
end
include SSLCommon
#
# == SSL Use Case 4 - User Supplied Ciphers
#
# If you need your own ciphers list, this is how.
# Stomp's default list will work in many cases. If you need to use this, you
# will know it because SSL connect will fail. In that case, determining
# _what_ should be in the list is your responsibility.
#
class ExampleSSL4C
# Initialize.
def initialize # Change the following as needed.
@host = ENV['STOMP_HOST'] ? ENV['STOMP_HOST'] : "localhost"
@port = ENV['STOMP_PORT'] ? ENV['STOMP_PORT'].to_i : 61612
end
# Run example.
def run
ciphers_list = [["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["AES256-SHA", "TLSv1/SSLv3", 256, 256], ["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["AES128-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-MD5", "TLSv1/SSLv3", 128, 128], ["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EXP-EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-RC2-CBC-MD5", "TLSv1/SSLv3", 40, 128], ["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128]]
#
# SSL Use Case 4
#
# Possibly change the cert file(s) name(s) here.
ssl_opts = Stomp::SSLParams.new(
:key_file => "#{cli_loc()}/#{pck()}", # the client's private key, private data
:cert_file => "#{cli_loc()}/#{cli_cert()}", # the client's signed certificate
:ts_files => "#{ca_loc()}/#{ca_cert()}", # The CA's signed sertificate
:fsck => true # Check that files exist first
)
#
hash = { :hosts => [
{:login => 'guest', :passcode => 'guest', :host => @host, :port => @port, :ssl => ssl_opts},
],
:reliable => false, # YMMV, to test this in a sane manner
}
#
puts "Connect starts, SSL Use Case 4"
c = Stomp::Connection.new(hash)
puts "Connect completed"
puts "SSL Verify Result: #{ssl_opts.verify_result}"
# puts "SSL Peer Certificate:\n#{ssl_opts.peer_cert}"
c.disconnect
end
private
def pck()
"client.key"
end
end
#
e = ExampleSSL4C.new
e.run
stomp-1.4.4/examples/artemis/ 0000755 0000041 0000041 00000000000 13120662775 016205 5 ustar www-data www-data stomp-1.4.4/examples/artemis/cliwaiter_reliable.rb 0000644 0000041 0000041 00000003032 13120662775 022352 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
require 'stomp'
#
if Kernel.respond_to?(:require_relative)
require_relative("artlogger")
else
$LOAD_PATH << File.dirname(__FILE__)
require "artlogger"
end
#
class CliWaiter
# Initialize.
def initialize # Change the following as needed.
#
mylog = Slogger::new # a stomp callback logger
#
@gem_retries = true
@host = ENV['STOMP_HOST'] ? ENV['STOMP_HOST'] : "localhost"
@port = ENV['STOMP_PORT'] ? ENV['STOMP_PORT'].to_i : 31613 # Artemis here
@slt = 75
@ver = ENV['STOMP_PROTOCOL'] ? ENV['STOMP_PROTOCOL'] : "1.2"
@hbdata = ENV['STOMP_HEARTBEATS'] ? ENV['STOMP_HEARTBEATS'] : "0,0"
@conn_hdrs = {"accept-version" => @ver, # version
"host" => "localhost", # vhost
"heart-beat" => @hbdata, # heartbeats
}
@hash = { :hosts => [
{:login => 'guest', :passcode => 'guest', :host => @host, :port => @port},
],
:reliable => @gem_retries, # reliable controls retries by the gem
:logger => mylog, # This enables callback logging!
:autoflush => true,
:connect_headers => @conn_hdrs,
:initial_reconnect_delay => 1.0, # initial delay before reconnect (secs)
:use_exponential_back_off => false, # don't backoff
:max_reconnect_attempts => 3, # retry 3 times
}
end
# Run example.
def run
puts "Connect host: #{@host}, port: #{@port}"
puts "Connect hash: #{@hash}"
#
puts "CliWaiter Starts"
c = Stomp::Client.new(@hash)
#
while true
puts "CliWaiter Sleeps: #{@slt} seconds"
sleep @slt
end
#
c.close
end
end
#
#
e = CliWaiter.new
e.run
stomp-1.4.4/examples/artemis/artlogger.rb 0000644 0000041 0000041 00000001464 13120662775 020525 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'logger' # use the standard Ruby logger .....
#
class Slogger
# Initialize a new callback logger instance.
def initialize(init_parms = nil)
_init
@log.info("Logger initialization complete.")
end
def _init
@log = Logger::new(STDERR) # User preference
@log.level = Logger::DEBUG # User preference
end
# Log connecting events
def on_connecting(parms)
begin
@log.debug "Connecting: #{parms}"
rescue Exception => ex
@log.debug "Connecting oops"
print ex.backtrace.join("\n")
end
end
# Log connected events
def on_connected(parms)
begin
@log.debug "Connected: #{parms}"
rescue Exception => ex
@log.debug "Connected oops"
print ex.backtrace.join("\n")
end
end
private
end # of class
stomp-1.4.4/examples/artemis/cliwaiter_not_reliable.rb 0000644 0000041 0000041 00000003140 13120662775 023232 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
require 'stomp'
#
class CliWaiter
@@retry_num = 0
@@max_retries = 3
# Initialize.
def initialize # Change the following as needed.
@gem_retries = false
@host = ENV['STOMP_HOST'] ? ENV['STOMP_HOST'] : "localhost"
@port = ENV['STOMP_PORT'] ? ENV['STOMP_PORT'].to_i : 31613 # Artemis here
@slt = 75
@ver = ENV['STOMP_PROTOCOL'] ? ENV['STOMP_PROTOCOL'] : "1.2"
@hbdata = ENV['STOMP_HEARTBEATS'] ? ENV['STOMP_HEARTBEATS'] : "0,0"
@conn_hdrs = {"accept-version" => @ver, # version
"host" => "localhost", # vhost
"heart-beat" => @hbdata, # heartbeats
}
@hash = { :hosts => [
{:login => 'guest', :passcode => 'guest', :host => @host, :port => @port},
],
:reliable => @gem_retries, # reliable controls retries by the gem
:autoflush => true,
:connect_headers => @conn_hdrs,
}
p [ "DB1", @hash ]
@do_retry=true # Retry ourself, gem code will not because of :reliable =>
end
# Run example.
def run
begin
@@retry_num += 1
puts "Try Number: #{@@retry_num}"
puts "Connect host: #{@host}, port: #{@port}"
puts "Connect hash: #{@hash.inspect}"
#
puts "CliWaiter Starts"
c = Stomp::Client.new(@hash)
#
puts "CliWaiter Sleeps: #{@slt} seconds"
sleep @slt
#
c.close
puts "CliWaiter Ends"
rescue Exception => ex
puts "Kaboom, we are in trouble"
puts "Exception Message: #{ex.message}"
puts "Exception Class: #{ex.class}"
puts "The gory details:"
print ex.backtrace.join("\n")
if @do_retry && @@retry_num < @@max_retries
retry
else
raise
end
end
end
end
#
#
e = CliWaiter.new
e.run
stomp-1.4.4/examples/ssl_uc3.rb 0000644 0000041 0000041 00000003743 13120662775 016450 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
# Reference: https://github.com/stompgem/stomp/wiki/extended-ssl-overview
#
if Kernel.respond_to?(:require_relative)
require_relative("./ssl_common")
else
$LOAD_PATH << File.dirname(__FILE__)
require "ssl_common"
end
include SSLCommon
#
# == SSL Use Case 3 - server *does* authenticate client, client does *not* authenticate server
#
# Subcase 3.A - Message broker configuration does *not* require client authentication
#
# - Expect connection success
# - Expect a verify result of 20 becuase the client did not authenticate the
# server's certificate.
#
# Subcase 3.B - Message broker configuration *does* require client authentication
#
# - Expect connection success if the server can authenticate the client certificate
# - Expect a verify result of 20 because the client did not authenticate the
# server's certificate.
#
class ExampleSSL3
# Initialize.
def initialize
# Change the following as needed.
@host = ENV['STOMP_HOST'] ? ENV['STOMP_HOST'] : "localhost"
@port = ENV['STOMP_PORT'] ? ENV['STOMP_PORT'].to_i : 61612
end
# Run example.
def run
puts "Connect host: #{@host}, port: #{@port}"
# Possibly change the cert file(s) name(s) here.
ssl_opts = Stomp::SSLParams.new(
:key_file => "#{cli_loc()}/#{pck()}", # the client's private key, private data
:cert_file => "#{cli_loc()}/#{cli_cert()}", # the client's signed certificate
:fsck => true # Check that the files exist first
)
#
hash = { :hosts => [
{:login => 'guest', :passcode => 'guest', :host => @host, :port => @port, :ssl => ssl_opts},
],
:reliable => false, # YMMV, to test this in a sane manner
}
#
puts "Connect starts, SSL Use Case 3"
c = Stomp::Connection.new(hash)
puts "Connect completed"
puts "SSL Verify Result: #{ssl_opts.verify_result}"
# puts "SSL Peer Certificate:\n#{ssl_opts.peer_cert}"
c.disconnect
end
private
def pck()
"client.key"
end
end
#
e = ExampleSSL3.new
e.run
stomp-1.4.4/examples/ssl_common.rb 0000644 0000041 0000041 00000003734 13120662775 017246 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
# Common Stomp 1.1 code.
#
require "rubygems" if RUBY_VERSION < "1.9"
require "stomp"
#
module SSLCommon
# CA Data.
# CA file location/directory. Change or specify.
# This is the author's default.
def ca_loc()
ENV['CA_FLOC'] || "/ad3/gma/sslwork/2013-extended-02" # The CA cert location
end
# CA file. Change or specify.
# This is the author's default.
def ca_cert()
ENV['CA_FILE'] || "TestCA.crt" # The CA cert File
end
# CA private key file. Change or specify.
# This is the author's default.
# This file should not be exposed to the outside world.
# Not currently used in stomp examples.
def ca_key()
ENV['CA_KEY'] || nil # The CA private key File
end
# Client Data.
# Client file location/directory. Change or specify.
# This is the author's default.
def cli_loc()
ENV['CLI_FLOC'] || "/ad3/gma/sslwork/2013-extended-02" # The client cert location
end
# Client cert file. Change or specify.
# This is the author's default.
def cli_cert()
ENV['CLI_FILE'] || "client.crt" # The client cert File
end
# Client private keyfile. Change or specify.
# This is the author's default.
# This file should not be exposed to the outside world.
def cli_key()
ENV['CLI_KEY'] || nil # The client private key File
end
# Server Data.
# Server file location/directory. Change or specify.
# This is the author's default.
# Not currently used in stomp examples.
def svr_loc()
ENV['SVR_FLOC'] || "/ad3/gma/sslwork/2013-extended-02" # The server cert location
end
# Server cert file. Change or specify.
# This is the author's default.
# Not currently used in stomp examples.
def svr_cert()
ENV['SVR_FILE'] || "server.crt" # The server cert File
end
# Server private keyfile. Change or specify.
# This is the author's default.
# This file should not be exposed to the outside world.
# Not currently used in stomp examples.
def svr_key()
ENV['SVR_KEY'] || nil # The server private key File
end
end
stomp-1.4.4/examples/publish_file.rb 0000644 0000041 0000041 00000004017 13120662775 017535 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'rubygems'
require 'stomp'
if Kernel.respond_to?(:require_relative)
require_relative("./stomp11_common")
require_relative("./lflogger")
else
$LOAD_PATH << File.dirname(__FILE__)
require "stomp11_common"
require "./lflogger"
end
include Stomp11Common
#
# Used primarily for testing performance when sending "large" messages.
# "large" => YMMV
#
class FileSender
# Initialize.
def initialize
end
# Run example.
def run
p [ "pub001", Thread.current ]
publogger = Slogger::new
start_time = Time.now.to_f
fname = ARGV[0]
puts "PUBF: File Name: #{fname}"
file = open(fname, "r")
rs = Time.now.to_f
buff = file.read
re = Time.now.to_f
ppt = sprintf("%20.6f", re - rs)
puts "PUBF: File size: #{buff.respond_to?(:bytesize) ? buff.bytesize : buff.length}"
puts "PUBF: File read: #{ppt} seconds"
file.close
#
client_hdrs = {"accept-version" => "1.1",
"host" => virt_host(),
}
client_hash = { :hosts => [
{:login => login(), :passcode => passcode(),
:host => host(), :port => port()},
],
:connect_headers => client_hdrs,
:logger => publogger,
:reliable => false, ### *NOTE*
}
#
# p [ "ch", client_hash ]
client = Stomp::Client.new(client_hash)
qname = ENV['STOMP_DEST'] ? ENV['STOMP_DEST'] : "/queue/a.big.file"
puts "PUBF: Qname is: #{qname}"
# Try to gracefully handle files that exceed broker size limits.
ph = {:presistent => true}
ph['suppress_content_length'] = 'yes' if suppresscl()
puts "PUBF: Headers are: #{ph.inspect}"
begin
client.publish(qname, buff, ph)
rescue
puts "PUBF: exception on publish: #{$!}"
end
sleep 0.1
e = client.poll() # Check for unsolicited messages from broker
puts "PUBF: unexpected broker message: #{e}" if e
client.close
end_time = Time.now.to_f
ppt = sprintf("%20.6f", end_time - start_time)
puts "PUBF: File published: #{ppt} seconds"
end
end
#
e = FileSender.new
e.run
stomp-1.4.4/examples/client11_putget1.rb 0000644 0000041 0000041 00000004207 13120662775 020162 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
# The current require dance for different Ruby versions.
# Change this to suit your requirements.
#
if Kernel.respond_to?(:require_relative)
require_relative("./stomp11_common")
else
$LOAD_PATH << File.dirname(__FILE__)
require "stomp11_common"
end
include Stomp11Common
#
# == Stomp 1.1 Client Putter/Getter Example 1
#
# This is much like sending and receiving with a Stomp::Connection.
#
class Client11PutGet1
# Initialize.
def initialize
end
# Run example.
def run
#
client_hdrs = {"accept-version" => "1.1", # Demand a 1.1 connection (use a CSV list if you will consider multiple versions)
"host" => virt_host, # The 1.1 vhost (could be different than connection host)
} # No heartbeats here: there will be none for this connection
#
client_hash = { :hosts => [
{:login => login, :passcode => passcode, :host => host, :port => port},
],
:connect_headers => client_hdrs,
}
#
client = Stomp::Client.new(client_hash)
puts "Client Connect complete"
#
raise "Unexpected protocol level" if client.protocol() != Stomp::SPL_11
#
qname = "/queue/client.nodea.nodeb.nodec"
data = "message payload: #{Time.now.to_f}"
headers = {}
# Send it
client.publish qname, data
puts "Publish complete"
# Receive
uuid = client.uuid() # uuid for Stomp::Client is a public method
message = nil
# Clients must pass a receive block. This is business as usual, required for 1.0.
# For 1.1, a unique subscription id is required.
client.subscribe(qname, {'id' => uuid}) {|m|
message = m
}
sleep 0.1 until message # Wait for completion
puts "Subscribe and receive complete"
# Unsubscribe, with the unique id
client.unsubscribe qname, {'id' => uuid}
# Sanity checks for this example ....
raise "Unexpected data" if data != message.body
raise "Bad subscription header" if uuid != message.headers['subscription']
#
client.close # Business as usual, just like 1.0
puts "Client close complete"
end
end
#
e = Client11PutGet1.new
e.run
stomp-1.4.4/examples/ssl_uc2_ciphers.rb 0000644 0000041 0000041 00000004657 13120662775 020171 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
# Reference: https://github.com/stompgem/stomp/wiki/extended-ssl-overview
#
if Kernel.respond_to?(:require_relative)
require_relative("./ssl_common")
else
$LOAD_PATH << File.dirname(__FILE__)
require "ssl_common"
end
include SSLCommon
#
# == SSL Use Case 2 - User Supplied Ciphers
#
# If you need your own ciphers list, this is how.
# Stomp's default list will work in many cases. If you need to use this, you
# will know it because SSL connect will fail. In that case, determining
# _what_ should be in the list is your responsibility.
#
class ExampleSSL2C
# Initialize.
def initialize # Change the following as needed.
@host = ENV['STOMP_HOST'] ? ENV['STOMP_HOST'] : "localhost"
@port = ENV['STOMP_PORT'] ? ENV['STOMP_PORT'].to_i : 61612
end
# Run example.
def run
ciphers_list = [["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["AES256-SHA", "TLSv1/SSLv3", 256, 256], ["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["AES128-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-MD5", "TLSv1/SSLv3", 128, 128], ["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EXP-EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-RC2-CBC-MD5", "TLSv1/SSLv3", 40, 128], ["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128]]
#
# SSL Use Case 2
#
ts_flist = []
# Possibly change/override the cert data here.
ts_flist << "#{ca_loc()}/#{ca_cert()}"
ssl_opts = Stomp::SSLParams.new(:ts_files => ts_flist.join(","),
:ciphers => ciphers_list,
:fsck => true
)
#
hash = { :hosts => [
{:login => 'guest', :passcode => 'guest', :host => @host, :port => @port, :ssl => ssl_opts},
],
:reliable => false, # YMMV, to test this in a sane manner
}
#
puts "Connect starts, SSL Use Case 2"
c = Stomp::Connection.new(hash)
puts "Connect completed"
puts "SSL Verify Result: #{ssl_opts.verify_result}"
# puts "SSL Peer Certificate:\n#{ssl_opts.peer_cert}"
c.disconnect
end
end
#
e = ExampleSSL2C.new
e.run
stomp-1.4.4/examples/get11conn_ex2.rb 0000644 0000041 0000041 00000003455 13120662775 017452 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
# The current require dance for different Ruby versions.
# Change this to suit your requirements.
#
if Kernel.respond_to?(:require_relative)
require_relative("./stomp11_common")
else
$LOAD_PATH << File.dirname(__FILE__)
require "stomp11_common"
end
include Stomp11Common
#
# == Stomp 1.1 Receive Example 2
#
# Purpose: to demonstrate receiving messages using Stomp 1.1, and using
# 'ack => client'.
#
class Receive11Example2
# Initialize.
def initialize
end
# Run example.
def run
conn = get_connection() # Use helper method to obtain a Stomp#connection
raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
#
qname = "/queue/nodea.nodeb.nodec"
#
uuid = conn.uuid()
puts "Subscribe id: #{uuid}"
#
# Subscribe with client ack mode
#
conn.subscribe qname, {'id' => uuid, 'ack' => 'client'} #
#
# Once you have subscribed, you may receive as usual
#
1.upto(nmsgs()) do
received = conn.receive
puts "Received data: #{received.body}"
#
# We want now to ACK this message. In Stomp 1.0, a 'message-id' header was
# required for the ACK. In Stomp 1.1, and additional header is required:
#
# * 'subscription' => id
#
msgid = received.headers['message-id']
#
# What you cannot do:
#
begin
conn.ack msgid
rescue RuntimeError => sre
puts "Rescue: #{sre}, #{sre.message}"
end
#
# Try a valid 1.1 ACK
#
conn.ack msgid, {'subscription' => uuid}
puts "ACK - msgid: #{msgid}, subscription: #{uuid}"
end
#
# Unsubscribe
#
conn.unsubscribe qname, {}, uuid # Second style
#
# And finally, disconnect.
#
conn.disconnect
end
end
#
e = Receive11Example2.new
e.run
stomp-1.4.4/examples/conn11_ex2.rb 0000644 0000041 0000041 00000005306 13120662775 016747 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
# The current require dance for different Ruby versions.
# Change this to suit your requirements.
#
if Kernel.respond_to?(:require_relative)
require_relative("./stomp11_common")
else
$LOAD_PATH << File.dirname(__FILE__)
require "stomp11_common"
end
include Stomp11Common
#
# == Stomp 1.1 Connection Example 2
#
# Purpose: to demonstrate a connect and disconnect sequence using Stomp 1.1.
#
# This example is like the 'conn11_ex1.rb' example except that a 'hashed'
# connect request is made.
#
class Connection11Example2
# Initialize.
def initialize
end
# Run example.
def run
# Create connection headers
# =========================
#
# The two headers used here are _required_ by the specification.
#
conn_hdrs = {"accept-version" => "1.1", # Demand a 1.1 connection (use a CSV list if you will consider multiple versions)
"host" => virt_host, # The 1.1 vhost (could be different than connection host)
} # No heartbeats here: there will be none for this connection
#
# Create the connect hash.
# ========================
#
conn_hash = { :hosts => [
{:login => login, :passcode => passcode, :host => host, :port => port},
],
:reliable => false, # Override default
:connect_headers => conn_hdrs,
}
#
# Get a connection
# ================
#
conn = Stomp::Connection.new(conn_hash)
puts "Connection complete"
#
# Let's just do some sanity checks, and look around.
#
raise "Connection failed!!" unless conn.open?
#
# Is this really a 1.1 conection? ('protocol' is a read only connection
# instance variable. The value will be '1.0' for those types of connections.)
#
raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
#
# The broker _could_ have returned an ERROR frame (unlikely).
#
raise "Connect error: #{conn.connection_frame.body}" if conn.connection_frame.command == Stomp::CMD_ERROR
#
# Examine the CONNECT response (the connection_frame).
#
puts "Connected Headers required to be present:"
puts "Connect version - \t#{conn.connection_frame.headers['version']}"
puts
puts "Connected Headers that are optional:"
puts "Connect server - \t\t#{conn.connection_frame.headers['server']}"
puts "Session ID - \t\t\t#{conn.connection_frame.headers['session']}"
puts "Server requested heartbeats - \t#{conn.connection_frame.headers['heart-beat']}"
#
# Finally disconnect
# ==================
#
conn.disconnect # Business as usual, just like 1.0
puts "Disconnect complete"
end
end
#
e = Connection11Example2.new
e.run
stomp-1.4.4/examples/contributors.rb 0000755 0000041 0000041 00000003264 13120662775 017633 0 ustar www-data www-data #!/usr/bin/env ruby
#
class UserData
public
attr_accessor :count
attr_reader :ad, :cd
#
def initialize(ad = nil, cd = nil)
@count, @ad, @cd = 1, ad, cd
end
#
def to_s
"UserData: AuthorDate=>#{@ad}, CommitDate=>#{@cd}, CommitCount =>#{@count}"
end
end
# tABLE Data
ttab_s = "
\n"
#
puts ttab_s # table start
#
userList = {}
while s = gets do
s.chomp!
ad, cd, n, e = s.split(";")
hk = "#{n}|#{e}"
if userList.has_key?(hk)
userList[hk].count += 1
else
userList[hk] = UserData.new(ad, cd)
=begin
if ad != cd
puts "NE: #{ad}, #{cd}, #{n}, #{e}"
end
=end
end
end
#
puts trow_s
#
puts th_s
puts th_c1
puts th_e
#
=begin
puts th_s
puts th_c1b
puts th_e
=end
#
puts th_s
puts th_c2
puts th_e
#
puts th_s
puts th_c3
puts th_e
#
puts trow_e
#
userList.each do |k, v|
n, e = k.split("|")
oc = "(" + sprintf("%04d", v.count) + ")"
# puts "# #{v.time} (#{oc}) #{n} #{e}"
puts trow_s
#
puts td_s
puts "#{v.ad}"
puts td_e
=begin
#
puts td_s
puts "#{v.cd}"
puts td_e
=end
#
puts td_s
puts oc
puts td_e
#
puts td_s
puts "\n"
puts "#{n}\n"
puts "\n"
puts " / #{e}"
puts td_e
#
puts trow_e
end
#
puts ttab_e # table end
stomp-1.4.4/examples/ssl_uc3_ciphers.rb 0000644 0000041 0000041 00000005053 13120662775 020161 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
# Reference: https://github.com/stompgem/stomp/wiki/extended-ssl-overview
#
if Kernel.respond_to?(:require_relative)
require_relative("./ssl_common")
else
$LOAD_PATH << File.dirname(__FILE__)
require "ssl_common"
end
include SSLCommon
#
# == SSL Use Case 3 - User Supplied Ciphers
#
# If you need your own ciphers list, this is how.
# Stomp's default list will work in many cases. If you need to use this, you
# will know it because SSL connect will fail. In that case, determining
# _what_ should be in the list is your responsibility.
#
class ExampleSSL3C
# Initialize.
def initialize # Change the following as needed.
@host = ENV['STOMP_HOST'] ? ENV['STOMP_HOST'] : "localhost"
@port = ENV['STOMP_PORT'] ? ENV['STOMP_PORT'].to_i : 61612
end
# Run example.
def run
ciphers_list = [["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["AES256-SHA", "TLSv1/SSLv3", 256, 256], ["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["AES128-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-MD5", "TLSv1/SSLv3", 128, 128], ["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EXP-EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-RC2-CBC-MD5", "TLSv1/SSLv3", 40, 128], ["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128]]
#
# SSL Use Case 3
#
# Possibly change the cert file(s) name(s) here.
ssl_opts = Stomp::SSLParams.new(
:key_file => "#{cli_loc()}/#{pck()}", # the client's private key, private data
:cert_file => "#{cli_loc()}/#{cli_cert()}", # the client's signed certificate
:fsck => true # Check that the files exist first
)
#
hash = { :hosts => [
{:login => 'guest', :passcode => 'guest', :host => @host, :port => @port, :ssl => ssl_opts},
],
:reliable => false, # YMMV, to test this in a sane manner
}
#
puts "Connect starts, SSL Use Case 3"
c = Stomp::Connection.new(hash)
puts "Connect completed"
puts "SSL Verify Result: #{ssl_opts.verify_result}"
# puts "SSL Peer Certificate:\n#{ssl_opts.peer_cert}"
c.disconnect
end
private
def pck()
"client.key"
end
end
#
e = ExampleSSL3C.new
e.run
stomp-1.4.4/examples/publish_file_conn.rb 0000644 0000041 0000041 00000004076 13120662775 020557 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'rubygems'
require 'stomp'
if Kernel.respond_to?(:require_relative)
require_relative("./stomp11_common")
require_relative("./lflogger")
else
$LOAD_PATH << File.dirname(__FILE__)
require "stomp11_common"
require "./lflogger"
end
include Stomp11Common
#
# Used primarily for testing performance when sending "large" messages.
# "large" => YMMV
#
class FileSenderConn
# Initialize.
def initialize
end
# Run example.
def run
p [ "pubc001", Thread.current ]
publogger = Slogger::new
start_time = Time.now.to_f
fname = ARGV[0]
puts "PUBFC: File Name: #{fname}"
file = open(fname, "r")
rs = Time.now.to_f
buff = file.read
re = Time.now.to_f
ppt = sprintf("%20.6f", re - rs)
puts "PUBFC: File size: #{buff.respond_to?(:bytesize) ? buff.bytesize : buff.length}"
puts "PUBFC: File read: #{ppt} seconds"
file.close
#
connection_hdrs = {"accept-version" => "1.1",
"host" => virt_host(),
}
connection_hash = { :hosts => [
{:login => login(), :passcode => passcode(),
:host => host(), :port => port()},
],
:connect_headers => connection_hdrs,
:logger => publogger,
:reliable => false, ### *NOTE*
}
#
# p [ "ch", connection_hash ]
connection = Stomp::Connection.new(connection_hash)
qname = ENV['STOMP_DEST'] ? ENV['STOMP_DEST'] : "/queue/a.big.file"
puts "PUBFC: Qname is: #{qname}"
ph = {:presistent => true}
ph['suppress_content_length'] = 'yes' if suppresscl()
puts "PUBF: Headers are: #{ph.inspect}"
# Try to gracefully handle files that exceed broker size limits.
begin
connection.publish(qname, buff, ph)
rescue
puts "PUBFC: exception on publish: #{$!}"
end
e = connection.poll() # Check for unsolicited messages from broker
puts "PUBFC: unexpected broker message: #{e}" if e
connection.disconnect
end_time = Time.now.to_f
ppt = sprintf("%20.6f", end_time - start_time)
puts "PUBFC: File published: #{ppt} seconds"
end
end
#
e = FileSenderConn.new
e.run
stomp-1.4.4/examples/consumer.rb 0000644 0000041 0000041 00000001337 13120662775 016725 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'rubygems'
require 'stomp'
#
# == Example message consumer.
#
class ExampleConsumer
# Initialize.
def initialize
end
# Run example.
def run
client = Stomp::Client.new("failover://(stomp://:@localhost:61613,stomp://:@remotehost:61613)?initialReconnectDelay=5000&randomize=false&useExponentialBackOff=false")
puts "Subscribing ronaldo"
client.subscribe("/queue/ronaldo", {:ack => "client", "activemq.prefetchSize" => 1, "activemq.exclusive" => true }) do |msg|
File.open("file", "a") do |f|
f.write(msg.body)
f.write("\n----------------\n")
end
client.acknowledge(msg)
end
loop do
sleep(1)
puts "."
end
end
end
#
e = ExampleConsumer.new
e.run
stomp-1.4.4/examples/consume_file.rb 0000644 0000041 0000041 00000003464 13120662775 017545 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'rubygems'
require 'stomp'
if Kernel.respond_to?(:require_relative)
require_relative("./stomp11_common")
require_relative("./lflogger")
else
$LOAD_PATH << File.dirname(__FILE__)
require "stomp11_common"
require "./lflogger"
end
include Stomp11Common
#
# Used primarily for testing performance when receiving "large" messages.
# "large" => YMMV
#
class FileReader
# Initialize.
def initialize(pto)
@parse_timeout = pto
end
# Run example.
def run
conlogger = Slogger::new
start_time = Time.now.to_f
#
connection_hdrs = {"accept-version" => "1.1",
"host" => virt_host(),
}
connection_hash = { :hosts => [
{:login => login(), :passcode => passcode(),
:host => host(), :port => port()},
],
:connect_headers => connection_hdrs,
:logger => conlogger,
:reliable => false,
:parse_timeout => @parse_timeout,
}
#
# p [ "ch", connection_hash ]
connection = Stomp::Connection.new(connection_hash)
qname = ENV['STOMP_DEST'] ? ENV['STOMP_DEST'] : "/queue/a.big.file"
puts "CONF: Qname is: #{qname}"
## connection.subscribe(qname, {:destination => qname}, "bigFileSubscriptionID")
connection.subscribe(qname, {:destination => qname}, connection.uuid())
## connection.subscribe(qname, {:destination => qname}, "0")
msg = connection.receive()
puts "CONF: Message Command: #{msg.command}"
puts "CONF: Message Headers: #{msg.headers}"
body_length_bytes = msg.body.respond_to?(:bytesize) ? msg.body.bytesize : msg.body.length
puts "CONF: Received: #{body_length_bytes} bytes"
connection.disconnect
end_time = Time.now.to_f
ppt = sprintf("%20.6f", end_time - start_time)
puts "CONF: File consumed: #{ppt} seconds"
end
end
#
e = FileReader.new(60)
e.run
stomp-1.4.4/examples/amqdurasub.rb 0000644 0000041 0000041 00000004415 13120662775 017236 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
# The current require dance for different Ruby versions.
# Change this to suit your requirements.
#
if Kernel.respond_to?(:require_relative)
require_relative("./stomp11_common")
else
$LOAD_PATH << File.dirname(__FILE__)
require "stomp11_common"
end
=begin
A recent experience suggested that we might provide an example of how
to establish a "durable" topic subscription using ActiveMQ.
This code attempts to do that.
References:
http://activemq.apache.org/stomp.html
http://activemq.apache.org/how-does-a-queue-compare-to-a-topic.html
http://activemq.apache.org/how-do-durable-queues-and-topics-work.html
Specifically, locate the section titled: ActiveMQ extensions to Stomp.
There are two programmatic requirements:
1) On CONNECT, indicate to AMQ the code will be using durable topic
subscription(s).
Done by providing a "cilent-id" CONNECT header.
2) On SUBSCRIBE, indicate an AMQ specific (uniqie) subscription ID. Done
by providing a "activemq.subscriptionName" header to SUBSCRIBE.
=end
# login hash
hash = { :hosts => [
{:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61613, :ssl => false}, # AMQ
],
:reliable => true,
:closed_check => false,
:connect_headers => {:host => "localhost", :"accept-version" => "1.0",
# Requirement 1, name should be unique.
:"client-id" => "dursubcli01", # REF the 1st AMQ link above
}
}
# The topic
topic = "/topic/topicName"
# Establish the client connection
cli = Stomp::Client.open(hash)
# SUBSCRIBE Headers
sh = { "activemq.subscriptionName" => "subname01" } # REF the 1st AMQ link above
# And the client subscribe
cli.subscribe(topic, sh) do |msg|
puts "msg: #{msg}"
end
# Wait for a very long time, usually exit via ^C
puts "Press ^C to exit"
sleep 1000000
puts "Done yet?"
=begin
At this point open your AMQ admin console (port 8161 usually), and examine
the 'subscribers' section. You should see an instance of this client
displayed in the "Active Durable Topic Subscribers" section.
When you press ^C to exit this program, return to the AMQ console and
refresh the display. (Do not restart AMQ). You should see this client in the
"Offline Durable Topic Subscribers" section.
=end
stomp-1.4.4/examples/conn11_ex1.rb 0000644 0000041 0000041 00000007130 13120662775 016743 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
# The current require dance for different Ruby versions.
# Change this to suit your requirements.
#
if Kernel.respond_to?(:require_relative)
require_relative("./stomp11_common")
else
$LOAD_PATH << File.dirname(__FILE__)
require "stomp11_common"
end
include Stomp11Common
#
# == Stomp 1.1 Connection Example 1
#
# Purpose: to demonstrate a connect and disconnect sequence using Stomp 1.1.
#
# Note: this example assumes that you have at least the 1.2.0 gem release
# installed.
#
# When you:
#
# * Use a Stomp 1.1 compliant broker
# * Want a Stomp 1.1 level connection and functionality
#
# then your code *must* specifically request that environment.
#
# You need to supply all of the normal values expected of course:
#
# * login - the user name
# * passcode - the password
# * host - the host to connect to
# * port - the port to connect to
#
# Additionaly you are required to supply the 1.1 connection data as documented
# in the Stomp 1.1 specification: http://stomp.github.com/stomp-specification-1.1.html
# You are urged to become familiar with the spec. It is a short document.
#
# This includes:
#
# * The Stomp version(s) you wish the broker to consider
# * The broker vhost to connect to
#
# You may optionally specify other 1.1 data:
#
# * heartbeat request
#
# Using the stomp gem, you can specify this data in the "connect_headers" Hash
# parameter or a paramaterized connection request. This example uses a
# parameterized request.
#
class Connection11Example1
# Initialize
def initialize
end
# Run example
def run
#
# Create connection headers
# =========================
#
# The two headers used here are _required_ by the specification.
#
conn_hdrs = {"accept-version" => "1.1", # Demand a 1.1 connection (use a CSV list if you will consider multiple versions)
"host" => virt_host, # The 1.1 vhost (could be different than connection host)
} # No heartbeats here: there will be none for this connection
#
# Get a connection
# ================
#
conn = Stomp::Connection.new(login, passcode, host, port, # Normal connect parms
false, # Not reliable, the default for a parameter connection
5, # Connect redelay, the default
conn_hdrs) # The 1.1 connection parameters
puts "Connection connect complete"
#
# Let's just do some sanity checks, and look around.
#
raise "Connection failed!!" unless conn.open?
#
# Is this really a 1.1 conection? ('protocol' is a read only connection
# instance variable. The value will be '1.0' for those types of connections.)
#
raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
#
# The broker _could_ have returned an ERROR frame (unlikely).
#
raise "Connect error: #{conn.connection_frame.body}" if conn.connection_frame.command == Stomp::CMD_ERROR
#
# Examine the CONNECT response (the connection_frame).
#
puts "Connected Headers required to be present:"
puts "Connect version - \t#{conn.connection_frame.headers['version']}"
puts
puts "Connected Headers that are optional:"
puts "Connect server - \t\t#{conn.connection_frame.headers['server']}"
puts "Session ID - \t\t\t#{conn.connection_frame.headers['session']}"
puts "Server requested heartbeats - \t#{conn.connection_frame.headers['heart-beat']}"
#
# Finally disconnect
# ==================
#
conn.disconnect # Business as usual, just like 1.0
puts "Connection disconnect complete"
end
end
#
e = Connection11Example1.new
e.run
stomp-1.4.4/examples/publisher.rb 0000644 0000041 0000041 00000001200 13120662775 017054 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'rubygems'
require 'stomp'
#
# == Example message publisher
#
class ExamplePublisher
# Initialize.
def initialize
end
# Run example.
def run
client = Stomp::Client.new("failover://(stomp://:@localhost:61613,stomp://:@remotehost:61613)?initialReconnectDelay=5000&randomize=false&useExponentialBackOff=false")
message = "ronaldo #{ARGV[0]}"
for i in (1..50)
puts "Sending message"
client.publish("/queue/ronaldo", "#{i}: #{message}", {:persistent => true})
puts "(#{Time.now})Message sent: #{i}"
sleep 0.2
end
end
end
#
e = ExamplePublisher.new
e.run
stomp-1.4.4/examples/ssl_uc4.rb 0000644 0000041 0000041 00000004035 13120662775 016444 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
# Reference: https://github.com/stompgem/stomp/wiki/extended-ssl-overview
#
if Kernel.respond_to?(:require_relative)
require_relative("./ssl_common")
else
$LOAD_PATH << File.dirname(__FILE__)
require "ssl_common"
end
include SSLCommon
#
# == SSL Use Case 4 - server *does* authenticate client, client *does* authenticate server
#
# Subcase 4.A - Message broker configuration does *not* require client authentication
#
# - Expect connection success
# - Expect a verify result of 0 becuase the client did authenticate the
# server's certificate.
#
# Subcase 4.B - Message broker configuration *does* require client authentication
#
# - Expect connection success if the server can authenticate the client certificate
# - Expect a verify result of 0 because the client did authenticate the
# server's certificate.
#
class ExampleSSL4
# Initialize.
def initialize
# Change the following as needed.
@host = ENV['STOMP_HOST'] ? ENV['STOMP_HOST'] : "localhost"
@port = ENV['STOMP_PORT'] ? ENV['STOMP_PORT'].to_i : 61612
end
# Run example.
def run
puts "Connect host: #{@host}, port: #{@port}"
# Possibly change the cert file(s) name(s) here.
ssl_opts = Stomp::SSLParams.new(
:key_file => "#{cli_loc()}/#{pck()}", # the client's private key, private data
:cert_file => "#{cli_loc()}/#{cli_cert()}", # the client's signed certificate
:ts_files => "#{ca_loc()}/#{ca_cert()}", # The CA's signed sertificate
:fsck => true # Check that files exist first
)
#
hash = { :hosts => [
{:login => 'guest', :passcode => 'guest', :host => @host, :port => @port, :ssl => ssl_opts},
],
:reliable => false, # YMMV, to test this in a sane manner
}
#
puts "Connect starts, SSL Use Case 4"
c = Stomp::Connection.new(hash)
puts "Connect completed"
puts "SSL Verify Result: #{ssl_opts.verify_result}"
# puts "SSL Peer Certificate:\n#{ssl_opts.peer_cert}"
c.disconnect
end
private
def pck()
"client.key"
end
end
#
e = ExampleSSL4.new
e.run
stomp-1.4.4/examples/logexamp.rb 0000644 0000041 0000041 00000005553 13120662775 016712 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'rubygems'
require 'stomp'
require 'logger' # for the 'local' logger
#
if Kernel.respond_to?(:require_relative)
require_relative("./examplogger")
else
$LOAD_PATH << File.dirname(__FILE__)
require "examplogger"
end
#
# == A STOMP::Connection program which uses the callback logging facility.
#
class LoggerExample
# Initialize.
def initialize
end
# Run example.
def run
llog = Logger::new(STDOUT)
llog.level = Logger::DEBUG
llog.debug "LE Starting"
# //////////////////////////////////////////////////////////////////////////////
mylog = Slogger::new # The client provided STOMP callback logger
# //////////////////////////////////////////////////////////////////////////////
user = ENV['STOMP_USER'] ? ENV['STOMP_USER'] : 'guest'
password = ENV['STOMP_PASSWORD'] ? ENV['STOMP_PASSWORD'] : 'guest'
host = ENV['STOMP_HOST'] ? ENV['STOMP_HOST'] : 'localhost'
port = ENV['STOMP_PORT'] ? ENV['STOMP_PORT'].to_i : 61613
# //////////////////////////////////////////////////////////////////////////////
# A hash type connect *MUST* be used to enable callback logging.
# //////////////////////////////////////////////////////////////////////////////
hash = { :hosts => [
{:login => user, :passcode => password, :host => 'noonehome', :port => 2525},
{:login => user, :passcode => password, :host => host, :port => port},
],
:logger => mylog, # This enables callback logging!
:max_reconnect_attempts => 5,
}
# //////////////////////////////////////////////////////////////////////////////
# For a Connection:
llog.debug "LE Connection processing starts"
conn = Stomp::Connection.new(hash)
conn.disconnect
# //////////////////////////////////////////////////////////////////////////////
llog.debug "LE Connection processing complete"
# //////////////////////////////////////////////////////////////////////////////
# For a Client:
llog.debug "LE Client processing starts"
conn = Stomp::Client.new(hash)
conn.close
# //////////////////////////////////////////////////////////////////////////////
llog.debug "LE Client processing complete"
# //////////////////////////////////////////////////////////////////////////////
# For a Connection with other calls:
llog.debug "LE Connection Enhanced processing starts"
conn = Stomp::Connection.new(hash)
#
dest = "/queue/loggerq1"
conn.publish dest, "a logger message"
conn.subscribe dest
msg = conn.receive
conn.disconnect
# //////////////////////////////////////////////////////////////////////////////
llog.debug "LE Connection Enhanced processing complete"
# //////////////////////////////////////////////////////////////////////////////
llog.debug "LE Ending"
end
end
e = LoggerExample.new
e.run
stomp-1.4.4/examples/ssl_uc1_ciphers.rb 0000644 0000041 0000041 00000004302 13120662775 020153 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
# Reference: https://github.com/stompgem/stomp/wiki/extended-ssl-overview
#
if Kernel.respond_to?(:require_relative)
require_relative("./ssl_common")
else
$LOAD_PATH << File.dirname(__FILE__)
require "ssl_common"
end
include SSLCommon
#
# == SSL Use Case 1 - User Supplied Ciphers
#
# If you need your own ciphers list, this is how.
# Stomp's default list will work in many cases. If you need to use this, you
# will know it because SSL connect will fail. In that case, determining
# _what_ should be in the list is your responsibility.
#
class ExampleSSL1C
# Initialize.
def initialize # Change the following as needed.
@host = ENV['STOMP_HOST'] ? ENV['STOMP_HOST'] : "localhost"
@port = ENV['STOMP_PORT'] ? ENV['STOMP_PORT'].to_i : 61612
end
# Run example.
def run
ciphers_list = [["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["AES256-SHA", "TLSv1/SSLv3", 256, 256], ["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["AES128-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-MD5", "TLSv1/SSLv3", 128, 128], ["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EXP-EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-RC2-CBC-MD5", "TLSv1/SSLv3", 40, 128], ["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128]]
ssl_opts = Stomp::SSLParams.new(:ciphers => ciphers_list)
#
# SSL Use Case 1
#
hash = { :hosts => [
{:login => 'guest', :passcode => 'guest', :host => @host, :port => @port, :ssl => ssl_opts},
],
:reliable => false, # YMMV, to test this in a sane manner
}
#
puts "Connect starts, SSL Use Case 1"
c = Stomp::Connection.new(hash)
puts "Connect completed"
puts "SSL Verify Result: #{ssl_opts.verify_result}"
#
c.disconnect
end
end
#
e = ExampleSSL1C.new
e.run
stomp-1.4.4/examples/put11conn_ex1.rb 0000644 0000041 0000041 00000002416 13120662775 017476 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
# The current require dance for different Ruby versions.
# Change this to suit your requirements.
#
if Kernel.respond_to?(:require_relative)
require_relative("./stomp11_common")
else
$LOAD_PATH << File.dirname(__FILE__)
require "stomp11_common"
end
include Stomp11Common
#
# == Stomp 1.1 Publish Example
#
# Purpose: to demonstrate sending messages using Stomp 1.1.
#
class Publish11Example1
# Initialize.
def initialize
end
# Run example.
def run
conn = get_connection() # Use helper method to obtain a Stomp#connection
raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
#
# Publishing simple data is as it was with Stomp 1.0.
#
# Note: Stomp 1.1 brokers seem to prefer using '.' as delimiters in queue
# name spaces. Hence, the queue name used here.
#
qname = "/queue/nodea.nodeb.nodec"
data = "message payload"
headers = {}
#
# The 'data' and 'headers' may be omitted, as with Stomp 1.0
#
puts "Writing #{nmsgs()} messages."
1.upto(nmsgs()) do |i|
msg = "#{data}: #{i}"
conn.publish qname, msg , headers
puts "Sent data: #{msg}"
end
#
# And finally, disconnect.
#
conn.disconnect
end
end
#
e = Publish11Example1.new
e.run
stomp-1.4.4/examples/putget11_rh1.rb 0000644 0000041 0000041 00000005540 13120662775 017316 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
# The current require dance for different Ruby versions.
# Change this to suit your requirements.
#
if Kernel.respond_to?(:require_relative)
require_relative("./stomp11_common")
else
$LOAD_PATH << File.dirname(__FILE__)
require "stomp11_common"
end
include Stomp11Common
#
# == Stomp 1.1 Send/Receive Example - Repeated Headers
#
# Purpose: to demonstrate sending and receiving using Stomp 1.1, and an unusual
# aspect of the specification. What is demonstrated here is the use of
# 'repeated headers'. Note that brokers MAY support repeated headers as
# demonstrated, but are not required to provide this support. This example
# should run against the Apollo broker. It will *not* currently run against
# RabbitMQ. YMMV depending on your broker.
#
# See: http://stomp.github.com/stomp-specification-1.1.html#Repeated_Header_Entries
#
class RepeatedHeadersExample
# Initialize.
def initialize
end
# Run example.
def run
conn = get_connection() # Use helper method to obtain a Stomp#connection
raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
#
# The gem supports repeated headers by allowing the 'value' part of a header
# to be an Array instance.
#
# On 'publish', all values in the Array are placed on the wire and sent to the
# broker in order.
#
# On 'receive', if repeated headers are detected, an Array instance is created
# to hold the repeated values. This is presented the the calling client to
# be processed per client requirements.
#
qname = "/queue/nodea.nodeb.nodec"
data = "message payload: #{Time.now.to_f}"
key2_repeats = ["key2val3", "key2val2", "key2val1" ]
headers = {"key1" => "value1", # A normal header
"key2" => key2_repeats, # A repeated header
"key3" => "value3", # Another normal header
}
#
# Ship it.
#
conn.publish qname, data , headers
puts "Sent data: #{data}"
#
# Receive phase.
#
uuid = conn.uuid()
conn.subscribe qname, {"id" => uuid}
received = conn.receive
conn.unsubscribe qname, {"id" => uuid}
#
# Check that we received what we sent.
#
raise "Unexpected payload" unless data == received.body
raise "Missing key" unless received.headers["key2"]
raise "Repeats not present" unless received.headers.has_value?(key2_repeats)
raise "Unexpected repeat values" unless key2_repeats == received.headers["key2"]
#
# Demonstrate how to process repeated headers received by display of those
# received headers for a visual check.
#
received.headers.each_pair do |k,v|
if v.is_a?(Array)
v.each do |e|
puts "#{k}:#{e}"
end
else
puts "#{k}:#{v}"
end
end
#
# And finally, disconnect.
#
conn.disconnect
end
end
#
e = RepeatedHeadersExample.new
e.run
stomp-1.4.4/examples/lflogger.rb 0000644 0000041 0000041 00000017543 13120662775 016701 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'logger' # use the standard Ruby logger .....
# == Example STOMP call back logger class.
#
# Optional callback methods:
#
# * on_connecting: connection starting
# * on_connected: successful connect
# * on_connectfail: unsuccessful connect (will usually be retried)
# * on_disconnect: successful disconnect
#
# * on_miscerr: on miscellaneous xmit/recv errors
#
# * on_publish: publish called
# * on_subscribe: subscribe called
# * on_unsubscribe: unsubscribe called
#
# * on_begin: begin called
# * on_ack: ack called
# * on_nack: nack called
# * on_commit: commit called
# * on_abort: abort called
#
# * on_receive: receive called and successful
#
# * on_ssl_connecting: SSL connection starting
# * on_ssl_connected: successful SSL connect
# * on_ssl_connectfail: unsuccessful SSL connect (will usually be retried)
#
# * on_hbread_fail: unsuccessful Heartbeat read
# * on_hbwrite_fail: unsuccessful Heartbeat write
# * on_hbfire: on any send or receive heartbeat
#
# All methods are optional, at the user's requirements.
#
# If a method is not provided, it is not called (of course.)
#
# IMPORTANT NOTE: in general, call back logging methods *SHOULD* not raise exceptions,
# otherwise the underlying STOMP connection may fail in mysterious ways.
# There are, however, exceptions to this 'rule'.
#
# Useful exceptions to this rule are:
#
# * on_connectfail
# * on_ssl_connectfail
#
# These two methods can raise a Stomp::Errors::LoggerConnectionError. If this
# exception is raised, it is passed up the chain to the caller.
#
# Callback parameters: are a copy of the @parameters instance variable for
# the Stomp::Connection.
#
# A logger class may optionally inherit from the provided NullLogger
#
# # class Slogger < Stomp::NullLogger
#
class Slogger
MAX_BODY_LEN = 1024 # Arbitrary
# Initialize a new callback logger instance.
def initialize(init_parms = nil)
_init
@log.info("Logger initialization complete.")
end
def _init
@log = Logger::new(STDOUT) # User preference
@log.level = Logger::DEBUG # User preference
end
def marshal_dump
[]
end
def marshal_load(array)
_init
end
# Log connecting events
def on_connecting(parms)
begin
@log.debug "Connecting: #{info(parms)}"
rescue
@log.debug "Connecting oops #{$!}"
end
end
# Log connected events
def on_connected(parms)
begin
@log.debug "Connected Info: #{info(parms)}"
@log.debug "Connected Parms: #{parms}"
rescue
@log.debug "Connected oops #{$!}"
end
end
# Log connectfail events
def on_connectfail(parms)
begin
@log.debug "Connect Fail #{info(parms)}"
rescue
@log.debug "Connect Fail oops #{$!}"
end
=begin
# An example LoggerConnectionError raise
@log.debug "Connect Fail, will raise"
raise Stomp::Error::LoggerConnectionError.new("quit from connect fail")
=end
end
# Log disconnect events
def on_disconnect(parms)
begin
@log.debug "Disconnected #{info(parms)}"
rescue
@log.debug "Disconnected oops #{$!}"
end
end
# Log miscellaneous errors
def on_miscerr(parms, errstr)
begin
@log.debug "Miscellaneous Error Info: #{info(parms)}"
@log.debug "Miscellaneous Error String: #{errstr}"
@log.debug "Miscellaneous Error Parms: #{parms}"
rescue
@log.debug "Miscellaneous Error oops #{$!}"
# Most clients will want to know about this. YMMV
raise
end
end
# Log Subscribe
def on_subscribe(parms, headers)
begin
@log.debug "Subscribe Parms #{info(parms)}"
@log.debug "Subscribe Headers #{headers}"
rescue
@log.debug "Subscribe oops #{$!}"
end
end
# Log UnSubscribe
def on_unsubscribe(parms, headers)
begin
@log.debug "UnSubscribe Parms #{info(parms)}"
@log.debug "UnSubscribe Headers #{headers}"
rescue
@log.debug "UnSubscribe oops #{$!}"
end
end
# Log Publish
def on_publish(parms, body, headers)
begin
@log.debug "Publish Parms #{info(parms)}"
body_length_bytes = body.respond_to?(:bytesize) ? body.bytesize : body.length
@log.debug "Publish Message Body #{body}" if body_length_bytes <= MAX_BODY_LEN
@log.debug "Publish Headers #{headers}"
rescue
@log.debug "Publish oops #{$!}"
end
end
# Log Receive
def on_receive(parms, result)
begin
@log.debug "Receive Parms #{info(parms)}"
@log.debug result.is_a? Stomp::Message
## @log.debug "Receive Result #{result}"
rescue
@log.debug "Receive oops #{$!}"
end
end
# Log Begin
def on_begin(parms, headers)
begin
@log.debug "Begin Parms #{info(parms)}"
@log.debug "Begin Result #{headers}"
rescue
@log.debug "Begin oops #{$!}"
end
end
# Log Ack
def on_ack(parms, headers)
begin
@log.debug "Ack Parms #{info(parms)}"
@log.debug "Ack Result #{headers}"
rescue
@log.debug "Ack oops #{$!}"
end
end
# Log NAck
def on_nack(parms, headers)
begin
@log.debug "NAck Parms #{info(parms)}"
@log.debug "NAck Result #{headers}"
rescue
@log.debug "NAck oops #{$!}"
end
end
# Log Commit
def on_commit(parms, headers)
begin
@log.debug "Commit Parms #{info(parms)}"
@log.debug "Commit Result #{headers}"
rescue
@log.debug "Commit oops #{$!}"
end
end
# Log Abort
def on_abort(parms, headers)
begin
@log.debug "Abort Parms #{info(parms)}"
@log.debug "Abort Result #{headers}"
rescue
@log.debug "Abort oops #{$!}"
end
end
# Stomp 1.1+ - heart beat read (receive) failed.
def on_hbread_fail(parms, ticker_data = {})
begin
@log.debug "Hbreadf Parms #{info(parms)}"
@log.debug "Hbreadf Result #{ticker_data.inspect}"
rescue
@log.debug "Hbreadf oops #{$!}"
end
end
# Stomp 1.1+ - heart beat send (transmit) failed.
def on_hbwrite_fail(parms, ticker_data = {})
begin
@log.debug "Hbwritef Parms #{info(parms)}"
@log.debug "Hbwritef Result #{ticker_data.inspect}"
rescue
@log.debug "Hbwritef oops #{$!}"
end
end
# Log SSL connection start.
def on_ssl_connecting(parms)
begin
@log.debug "SSL Connecting Parms #{info(parms)}"
rescue
@log.debug "SSL Connecting oops #{$!}"
end
end
# Log a successful SSL connect.
def on_ssl_connected(parms)
begin
@log.debug "SSL Connected Parms #{info(parms)}"
rescue
@log.debug "SSL Connected oops #{$!}"
end
end
# Log an unsuccessful SSL connect.
def on_ssl_connectfail(parms)
begin
@log.debug "SSL Connect Fail Parms #{info(parms)}"
@log.debug "SSL Connect Fail Exception #{parms[:ssl_exception]}, #{parms[:ssl_exception].message}"
rescue
@log.debug "SSL Connect Fail oops #{$!}"
end
=begin
# An example LoggerConnectionError raise
@log.debug "SSL Connect Fail, will raise"
raise Stomp::Error::LoggerConnectionError.new("quit from SSL connect")
=end
end
# Log heart beat fires
def on_hbfire(parms, srind, firedata = {})
begin
@log.debug "HeartBeat Fire Parms #{info(parms)}"
@log.debug "HeartBeat Fire Send/Receive #{srind}"
rescue
@log.debug "HeartBeat Fire oops #{$!}"
end
end
private
# Example information extract.
def info(parms)
#
# Available in the parms Hash:
# parms[:cur_host]
# parms[:cur_port]
# parms[:cur_login]
# parms[:cur_passcode]
# parms[:cur_ssl]
# parms[:cur_recondelay]
# parms[:cur_parseto]
# parms[:cur_conattempts]
# parms[:cur_failure]
# parms[:openstat]
#
# For the on_ssl_connectfail callback these are also available:
# parms[:ssl_exception]
#
"Host: #{parms[:cur_host]}, Port: #{parms[:cur_port]}, Login: #{parms[:cur_login]}, Passcode: #{parms[:cur_passcode]}, ssl: #{parms[:cur_ssl]}"
end
end # of class
stomp-1.4.4/examples/contrib.sh 0000755 0000041 0000041 00000000316 13120662775 016540 0 ustar www-data www-data #!/bin/bash
#
# git log --reverse --all --date=short --pretty --format='%aI;%cI;%cn;%ce' | \
git log --reverse --all --date=short --pretty --format='%ad;%cd;%cn;%ce' | \
ruby $HOME/bin/contributors.rb
stomp-1.4.4/examples/stomp11_common.rb 0000644 0000041 0000041 00000002245 13120662775 017745 0 ustar www-data www-data # -*- encoding: utf-8 -*-
#
# Common Stomp 1.1 code.
#
require "rubygems" if RUBY_VERSION < "1.9"
require "stomp"
#
module Stomp11Common
# User id
def login()
ENV['STOMP_USER'] || 'guest'
end
# Password
def passcode()
ENV['STOMP_PASSCODE'] || 'guest'
end
# Server host
def host()
ENV['STOMP_HOST'] || "localhost" # The connect host name
end
# Server port
def port()
(ENV['STOMP_PORT'] || 61613).to_i # !! The author runs AMQ listening here
end
# Required vhost name
def virt_host()
ENV['STOMP_VHOST'] || "localhost" # The 1.1 virtual host name
end
# Create a 1.1 commection
def get_connection()
conn_hdrs = {"accept-version" => "1.1", # 1.1 only
"host" => virt_host, # the vhost
}
conn_hash = { :hosts => [
{:login => login, :passcode => passcode, :host => host, :port => port},
],
:connect_headers => conn_hdrs,
}
conn = Stomp::Connection.new(conn_hash)
end
# Number of messages
def nmsgs()
(ENV['STOMP_NMSGS'] || 1).to_i # Number of messages
end
# Include "suppress-content-length' header
def suppresscl()
ENV['STOMP_SUPPRESS_CL']
end
end
stomp-1.4.4/notes/ 0000755 0000041 0000041 00000000000 13120662775 014053 5 ustar www-data www-data stomp-1.4.4/notes/heartbeat_readme.txt 0000644 0000041 0000041 00000012745 13120662775 020101 0 ustar www-data www-data Usage notes and comments follow (sorry for the length here, please read carefully).
Write failures: there is a single type of write failure, and it occurs when
an exception of some sort is raised during Heartbeat write.
This is the only type of write failure that can be detected.
If :reliable is true, an exception on heartbeat write will always causes a fail
over attempt.
Read failures: this is actually more complex than originally envisioned.
There are really three distinct types of read 'failures':
1) An exception is thrown during Heartbeat read. If :reliable is true, this
always causes a fail over attempt.
2) Heartbeat reads can not obtain the read_semaphore lock. This will occur
when the main connection thread has:
-- Called Connection#receive
-- Only heartbeats but no Stomp frames are on the inbound wire
-- Last Heartbeat read time is being maintained by the #receive attempt
3) Heartbeat reads obtain the read_semaphore lock, but the socket shows no
data is available (by IO#ready?). This will occur when:
-- The main thread has not called Connection#receive (the thread is doing other work)
-- There is no heartbeat to receive (IO#ready? indicates no input data available)
The requirement to handle cases 2) and 3) results in not one, but two different
counters being taken in to consideration.
To handle case 2) add to the connect hash:
:max_hbrlck_fails => x # x is a number strictly greater than 0. Default is 0,
which disables the functionality.
A running count of this failure type is maintained in the HB read thread. The
count is incremented when:
-- Lock obtain fails, *and*
-- A heartbeat is 'late'
The count is reset to 0 whenever:
-- A heart beat has been received on a timely basis
When the running count *reaches* the value specified in :max_hbrlck_fails, a
fail over attempt is initiated.
Advice: do *not* set this to 1 (in order to avoid fail overs on a transient
error).
To handle case 3) add to the connect hash:
:max_hbread_fails => y # y is a number strictly greater than 0. Default is 0,
which disables the functionality.
A running count of this failure type is maintained in the HB read thread.
The count is incremented when:
-- Lock obtain succeeds, *and*
-- IO#ready? indicates no data available
The count is reset to 0 under two conditions:
Condition 1)
-- A heartbeat is late, *and*
-- Lock obtain succeeds, *and*
-- IO#ready? indicates data is available, *and*
-- A single character is read from the wire
Condition 2)
-- A heartbeat has been received in a timely manner (perhaps by the main thread)
When the running count *reaches* the value specified in :max_hbread_fails,
a fail over attempt is initiated.
Advice: do *not* set this to 1 (in order to avoid fail overs on a transient
error).
-----------------------------------------------------------
General advice:
Set your heartbeat intervals to the maximum possible to obtain your desired
behavior. Do *not* set them at extremely low values even if the broker allows
that. An absurd example:
heart-beat:1,1
which will likely not work well.
-----------------------------------------------------------
General notes:
In your real world apps, think about whether one or both of these parameters
are appropriate.
Please add the:
-- on_hbread_fail
-- on_hbwrite_fail
methods to a callback logger. In those methods show 'ticker_data.inspect'
output. We would want that log output in future problem reports.
We make the comment about not setting these values to 1 because every server
we test with is prone to transient (single event) failures, particularly for
client HB reads.
We have done a variety of informal tests here, using both server kill and
packet drop strategies as appropriate. We believe more real world testing is
required.
-----------------------------------------------------------
08/07/2013
Issue #63 related, specifically fast send heart beats are being used and
spurious fail overs occur in rapid succession.
Background:
Fail over from heartbeat failures was introduced in gem version 1.2.10.
Subsequently:
This issue has been observed and documented in the following environment:
-- JRuby engine 1.7.4 *and*
-- ActiveMQ 5.8.0 *and*
-- 'fast' client send heartbeats
Heartbeat sends were at 2000ms.
At this point in time, fast send heart beats and spurious fail overs have
*not* been observed using:
-- Any native RUBY_ENGINE and ActiveMQ
-- Any native RUBY_ENGINE and Apollo (client send rates are limited by default)
-- Any native RUBY_ENGINE and RabbitMQ
-- JRuby and Apollo (client send rates are limited by default)
-- JRuby and RabbitMQ
Note that 'fast' will depend on your use case for heartbeats. Observations
are that sending heartbeat times less than 5000ms might be considered 'fast'
in the targeted environment.
The solution / bypass being put in place as of the above date was developed
through experimentation and is as follows:
- Add 'adjustment' logic to the heartbeat sender (thanks to ppaul for this idea).
- Re-introduce tolerance logic removed in d922fa.
- Add a new connection hash parameter to adjust heartbeat sends.
The newly introduced connection hash parameter is:
:fast_hbs_adjust => 0.0 # The default, no adjustment to sender sleep times (sec)
Recommendation for gem users that:
- Use fast send heartbeats
- Actually notice spurious fail overs
is to provide a very sender sleep time adjustment when connecting. Examples:
:fast_hbs_adjust => 0.05 # 50 milliseconds
:fast_hbs_adjust => 0.10 # 100 milliseconds
As usual, YMMV.
stomp-1.4.4/spec/ 0000755 0000041 0000041 00000000000 13120662775 013655 5 ustar www-data www-data stomp-1.4.4/spec/connection_spec.rb 0000644 0000041 0000041 00000045627 13120662775 017371 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'spec_helper'
describe Stomp::Connection do
before(:each) do
@parameters = {
:hosts => [
{:login => "login1", :passcode => "passcode1", :host => "localhost", :port => 61616, :ssl => false},
{:login => "login2", :passcode => "passcode2", :host => "remotehost", :port => 61617, :ssl => false}
],
:reliable => true,
:initial_reconnect_delay => 0.01,
:max_reconnect_delay => 30.0,
:use_exponential_back_off => true,
:back_off_multiplier => 2,
:max_reconnect_attempts => 0,
:randomize => false,
:connect_timeout => 0,
:parse_timeout => 5,
:connect_headers => {},
:dmh => false,
:closed_check => true,
:hbser => false,
:stompconn => false,
:usecrlf => false,
:max_hbread_fails => 0,
:max_hbrlck_fails => 0,
:fast_hbs_adjust => 0.0,
:connread_timeout => 0,
:tcp_nodelay => true,
:start_timeout => 0,
:sslctx_newparm => nil,
:ssl_post_conn_check => true,
}
#POG:
class Stomp::Connection
def _receive( s, connread = false )
end
end
# clone() does a shallow copy, we want a deep one so we can garantee the hosts order
normal_parameters = Marshal::load(Marshal::dump(@parameters))
@tcp_socket = double(:tcp_socket, :close => nil, :puts => nil, :write => nil, :setsockopt => nil, :flush => true)
allow(TCPSocket).to receive(:open).and_return @tcp_socket
@connection = Stomp::Connection.new(normal_parameters)
end
describe "autoflush" do
let(:parameter_hash) {
{
"hosts" => [
{:login => "login2", :passcode => "passcode2", :host => "remotehost", :port => 61617, :ssl => false},
{:login => "login1", :passcode => "passcode1", :host => "localhost", :port => 61616, :ssl => false}
],
"reliable" => true,
"initialReconnectDelay" => 0.01,
"maxReconnectDelay" => 30.0,
"useExponentialBackOff" => true,
"backOffMultiplier" => 2,
"maxReconnectAttempts" => 0,
"randomize" => false,
"connect_timeout" => 0,
"parse_timeout" => 5,
}
}
it "should call flush on the socket when autoflush is true" do
expect(@tcp_socket).to receive(:flush)
@connection = Stomp::Connection.new(parameter_hash.merge("autoflush" => true))
@connection.publish "/queue", "message", :suppress_content_length => false
end
it "should not call flush on the socket when autoflush is false" do
expect(@tcp_socket).not_to receive(:flush)
@connection = Stomp::Connection.new(parameter_hash)
@connection.publish "/queue", "message", :suppress_content_length => false
end
end
describe "(created using a hash)" do
it "should uncamelize and symbolize the main hash keys" do
used_hash = {
"hosts" => [
{:login => "login2", :passcode => "passcode2", :host => "remotehost", :port => 61617, :ssl => false},
{:login => "login1", :passcode => "passcode1", :host => "localhost", :port => 61616, :ssl => false}
],
"reliable" => true,
"initialReconnectDelay" => 0.01,
"maxReconnectDelay" => 30.0,
"useExponentialBackOff" => true,
"backOffMultiplier" => 2,
"maxReconnectAttempts" => 0,
"randomize" => false,
"connectTimeout" => 0,
"parseTimeout" => 5,
"usecrlf" => false,
:maxHbreadFails => 0,
:maxHbrlckFails => 0,
:fastHbsAdjust => 0.0,
:connreadTimeout => 0,
:tcpNodelay => true,
:startTimeout => 0,
:sslctxNewparm => nil,
}
@connection = Stomp::Connection.new(used_hash)
expect(@connection.instance_variable_get(:@parameters)).to eq(@parameters)
end
it "should start with first host in array" do
expect(@connection.instance_variable_get(:@host)).to eq("localhost")
end
it "should change host to next one with randomize false" do
@connection.send(:change_host) # use .send(:name) to test a private method!
expect(@connection.instance_variable_get(:@host)).to eq("remotehost")
end
it "should use default port (61613) if none is given" do
hash = {:hosts => [{:login => "login2", :passcode => "passcode2", :host => "remotehost", :ssl => false}]}
@connection = Stomp::Connection.new hash
expect(@connection.instance_variable_get(:@port)).to eq(61613)
end
context "should be able pass reliable as part of hash" do
it "should be false if reliable is set to false" do
hash = @parameters.merge({:reliable => false })
connection = Stomp::Connection.new(hash)
expect(connection.instance_variable_get(:@reliable)).to be false
end
it "should be true if reliable is set to true" do
hash = @parameters.merge({:reliable => true })
connection = Stomp::Connection.new(hash)
expect(connection.instance_variable_get(:@reliable)).to be true
end
it "should be true if reliable is not set" do
connection = Stomp::Connection.new(@parameters)
expect(connection.instance_variable_get(:@reliable)).to be true
end
end
context "when dealing with content-length header" do
it "should not suppress it when receiving :suppress_content_length => false" do
expect(@tcp_socket).to receive(:puts).with("content-length:7")
@connection.publish "/queue", "message", :suppress_content_length => false
end
it "should not suppress it when :suppress_content_length is nil" do
expect(@tcp_socket).to receive(:puts).with("content-length:7")
@connection.publish "/queue", "message"
end
it "should suppress it when receiving :suppress_content_length => true" do
expect(@tcp_socket).not_to receive(:puts).with("content-length:7")
@connection.publish "/queue", "message", :suppress_content_length => true
end
it "should get the correct byte length when dealing with Unicode characters" do
expect(@tcp_socket).to receive(:puts).with("content-length:18")
@connection.publish "/queue", "сообщение" # 'сообщение' is 'message' in Russian
end
end
describe "when unacknowledging a message" do
before :each do
@message = Stomp::Message.new(nil)
@message.body = "message body"
@message.headers = {"destination" => "/queue/original", "message-id" => "ID"}
@transaction_id = "transaction-#{@message.headers["message-id"]}-0"
@retry_headers = {
:destination => @message.headers["destination"],
:transaction => @transaction_id,
:retry_count => 1
}
end
it "should use a transaction" do
expect(@connection).to receive(:begin).with(@transaction_id).ordered
expect(@connection).to receive(:commit).with(@transaction_id).ordered
@connection.unreceive @message
end
it "should acknowledge the original message if ack mode is client" do
expect(@connection).to receive(:ack).with(@message.headers["message-id"], :transaction => @transaction_id)
@connection.subscribe(@message.headers["destination"], :ack => "client")
@connection.unreceive @message
end
it "should acknowledge the original message if forced" do
@connection.subscribe(@message.headers["destination"])
expect(@connection).to receive(:ack)
@connection.unreceive(@message, :force_client_ack => true)
end
it "should not acknowledge the original message if ack mode is not client or it did not subscribe to the queue" do
@connection.subscribe(@message.headers["destination"], :ack => "client")
expect(@connection).to receive(:ack)
@connection.unreceive @message
# At this time the message headers are symbolized
@connection.unsubscribe(@message.headers[:destination])
expect(@connection).not_to receive(:ack)
@connection.unreceive @message
@connection.subscribe(@message.headers[:destination], :ack => "individual")
@connection.unreceive @message
end
it "should send the message back to the queue it came" do
@connection.subscribe(@message.headers["destination"], :ack => "client")
expect(@connection).to receive(:publish).with(@message.headers["destination"], @message.body, @retry_headers)
@connection.unreceive @message
end
it "should increment the retry_count header" do
@message.headers["retry_count"] = 4
@connection.unreceive @message
expect(@message.headers[:retry_count]).to eq(5)
end
it "should not send the message to the dead letter queue as persistent if retry_count is less than max redeliveries" do
max_redeliveries = 5
dead_letter_queue = "/queue/Dead"
@message.headers["retry_count"] = max_redeliveries - 1
transaction_id = "transaction-#{@message.headers["message-id"]}-#{@message.headers["retry_count"]}"
@retry_headers = @retry_headers.merge :transaction => transaction_id, :retry_count => @message.headers["retry_count"] + 1
expect(@connection).to receive(:publish).with(@message.headers["destination"], @message.body, @retry_headers)
@connection.unreceive @message, :dead_letter_queue => dead_letter_queue, :max_redeliveries => max_redeliveries
end
# If the retry_count has reached max_redeliveries, then we're done.
it "should send the message to the dead letter queue as persistent if max redeliveries have been reached" do
max_redeliveries = 5
dead_letter_queue = "/queue/Dead"
@message.headers["retry_count"] = max_redeliveries
transaction_id = "transaction-#{@message.headers["message-id"]}-#{@message.headers["retry_count"]}"
@retry_headers = @retry_headers.merge :persistent => true, :transaction => transaction_id, :retry_count => @message.headers["retry_count"] + 1, :original_destination=> @message.headers["destination"]
expect(@connection).to receive(:publish).with(dead_letter_queue, @message.body, @retry_headers)
@connection.unreceive @message, :dead_letter_queue => dead_letter_queue, :max_redeliveries => max_redeliveries
end
it "should rollback the transaction and raise the exception if happened during transaction" do
expect(@connection).to receive(:publish).and_raise "Error"
expect(@connection).to receive(:abort).with(@transaction_id)
expect {@connection.unreceive @message}.to raise_error("Error")
end
end
describe "when sending a nil message body" do
it "should should not raise an error" do
@connection = Stomp::Connection.new("niluser", "nilpass", "localhost", 61613)
expect {
@connection.publish("/queue/nilq", nil)
}.not_to raise_error
end
end
describe "when using ssl" do
# Mocking ruby's openssl extension, so we can test without requiring openssl
module ::OpenSSL
module SSL
VERIFY_NONE = 0
VERIFY_PEER = 1
class SSLSocket
end
class SSLContext
attr_accessor :verify_mode
end
end
end
before(:each) do
ssl_context = double(:verify_mode => OpenSSL::SSL::VERIFY_PEER)
ssl_parameters = {:hosts => [{:login => "login2", :passcode => "passcode2", :host => "remotehost", :ssl => true}]}
@ssl_socket = double(:ssl_socket, :puts => nil, :write => nil,
:setsockopt => nil, :flush => true, :context => ssl_context)
allow(@ssl_socket).to receive(:sync_close=)
expect(TCPSocket).to receive(:open).and_return @tcp_socket
expect(OpenSSL::SSL::SSLSocket).to receive(:new).and_return(@ssl_socket)
expect(@ssl_socket).to receive(:connect)
expect(@ssl_socket).to receive(:post_connection_check)
@connection = Stomp::Connection.new ssl_parameters
end
it "should use ssl socket if ssl use is enabled" do
expect(@connection.instance_variable_get(:@socket)).to eq(@ssl_socket)
end
it "should use default port for ssl (61612) if none is given" do
expect(@connection.instance_variable_get(:@port)).to eq(61612)
end
end
describe "when called to increase reconnect delay" do
it "should exponentialy increase when use_exponential_back_off is true" do
expect(@connection.send(:increase_reconnect_delay)).to eq(0.02)
expect(@connection.send(:increase_reconnect_delay)).to eq(0.04)
expect(@connection.send(:increase_reconnect_delay)).to eq(0.08)
end
it "should not increase when use_exponential_back_off is false" do
@parameters[:use_exponential_back_off] = false
@connection = Stomp::Connection.new(@parameters)
expect(@connection.send(:increase_reconnect_delay)).to eq(0.01)
expect(@connection.send(:increase_reconnect_delay)).to eq(0.01)
end
it "should not increase when max_reconnect_delay is reached" do
@parameters[:initial_reconnect_delay] = 8.0
@connection = Stomp::Connection.new(@parameters)
expect(@connection.send(:increase_reconnect_delay)).to eq(16.0)
expect(@connection.send(:increase_reconnect_delay)).to eq(30.0)
end
it "should change to next host on socket error" do
@connection.instance_variable_set(:@failure, "some exception")
#retries the same host
expect(TCPSocket).to receive(:open).and_raise "exception"
#tries the new host
expect(TCPSocket).to receive(:open).and_return @tcp_socket
@connection.send(:socket)
expect(@connection.instance_variable_get(:@host)).to eq("remotehost")
end
it "should use default options if those where not given" do
expected_hash = {
:hosts => [
{:login => "login2", :passcode => "passcode2", :host => "remotehost", :port => 61617, :ssl => false},
# Once connected the host is sent to the end of array
{:login => "login1", :passcode => "passcode1", :host => "localhost", :port => 61616, :ssl => false}
],
:reliable => true,
:initial_reconnect_delay => 0.01,
:max_reconnect_delay => 30.0,
:use_exponential_back_off => true,
:back_off_multiplier => 2,
:max_reconnect_attempts => 0,
:randomize => false,
:connect_timeout => 0,
:parse_timeout => 5,
:connect_headers => {},
:dmh => false,
:closed_check => true,
:hbser => false,
:stompconn => false,
:max_hbread_fails => 0,
:max_hbrlck_fails => 0,
:fast_hbs_adjust => 0.0,
:connread_timeout => 0,
:tcp_nodelay => true,
:start_timeout => 0,
:sslctx_newparm => nil,
:ssl_post_conn_check => true,
}
used_hash = {
:hosts => [
{:login => "login1", :passcode => "passcode1", :host => "localhost", :port => 61616, :ssl => false},
{:login => "login2", :passcode => "passcode2", :host => "remotehost", :port => 61617, :ssl => false}
]
}
@connection = Stomp::Connection.new(used_hash)
expect(@connection.instance_variable_get(:@parameters)).to eq(expected_hash)
end
it "should use the given options instead of default ones" do
used_hash = {
:hosts => [
{:login => "login2", :passcode => "passcode2", :host => "remotehost", :port => 61617, :ssl => false},
{:login => "login1", :passcode => "passcode1", :host => "localhost", :port => 61616, :ssl => false}
],
:initial_reconnect_delay => 5.0,
:max_reconnect_delay => 100.0,
:use_exponential_back_off => false,
:back_off_multiplier => 3,
:max_reconnect_attempts => 10,
:randomize => true,
:reliable => false,
:connect_timeout => 0,
:parse_timeout => 20,
:connect_headers => {:lerolero => "ronaldo"},
:dead_letter_queue => "queue/Error",
:max_redeliveries => 10,
:dmh => false,
:closed_check => true,
:hbser => true,
:stompconn => true,
:usecrlf => true,
:max_hbread_fails => 123,
:max_hbrlck_fails => 456,
:fast_hbs_adjust => 0.2,
:connread_timeout => 42,
:tcp_nodelay => false,
:start_timeout => 6,
:sslctx_newparm=>:TLSv1,
:ssl_post_conn_check =>false,
}
@connection = Stomp::Connection.new(used_hash)
received_hash = @connection.instance_variable_get(:@parameters)
# Using randomize we can't assure the hosts order
received_hash.delete(:hosts)
used_hash.delete(:hosts)
expect(received_hash).to eq(used_hash)
end
end
end
describe "when closing a socket" do
it "should close the tcp connection" do
expect(@tcp_socket).to receive(:close)
expect(@connection.__send__(:close_socket)).to be true # Use Object.__send__
end
it "should ignore exceptions" do
expect(@tcp_socket).to receive(:close).and_raise "exception"
expect(@connection.__send__(:close_socket)).to be true # Use Object.__send__
end
end
describe "when checking if max reconnect attempts have been reached" do
it "should return false if not using failover" do
host = @parameters[:hosts][0]
@connection = Stomp::Connection.new(host[:login], host[:passcode], host[:host], host[:port], reliable = true, 5, connect_headers = {})
@connection.instance_variable_set(:@connection_attempts, 10000)
expect(@connection.send(:max_reconnect_attempts?)).to be false
end
it "should return false if max_reconnect_attempts = 0" do
@connection.instance_variable_set(:@connection_attempts, 10000)
expect(@connection.send(:max_reconnect_attempts?)).to be false
end
it "should return true if connection attempts > max_reconnect_attempts" do
limit = 10000
@parameters[:max_reconnect_attempts] = limit
@connection = Stomp::Connection.new(@parameters)
@connection.instance_variable_set(:@connection_attempts, limit-1)
expect(@connection.send(:max_reconnect_attempts?)).to be false
@connection.instance_variable_set(:@connection_attempts, limit)
expect(@connection.send(:max_reconnect_attempts?)).to be true
end
# These should be raised for the user to deal with
it "should not rescue MaxReconnectAttempts" do
@connection = Stomp::Connection.new(@parameters)
allow(@connection).to receive(:socket).and_raise(Stomp::Error::MaxReconnectAttempts)
expect { @connection.receive() }.to raise_error(RuntimeError)
end
end
end
stomp-1.4.4/spec/client_shared_examples.rb 0000644 0000041 0000041 00000003606 13120662775 020711 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'spec_helper'
shared_examples_for "standard Client" do
before(:each) do
@destination = "/queue/test/ruby/client"
@message_text = "test_client-#{Time.now.to_i}"
end
describe "the closed? method" do
it "should be false when the connection is open" do
allow(@mock_connection).to receive(:closed?).and_return(false)
expect(@client.closed?).to eq(false)
end
it "should be true when the connection is closed" do
allow(@mock_connection).to receive(:closed?).and_return(true)
expect(@client.closed?).to eq(true)
end
end
describe "the open? method" do
it "should be true when the connection is open" do
allow(@mock_connection).to receive(:open?).and_return(true)
expect(@client.open?).to eq(true)
end
it "should be false when the connection is closed" do
allow(@mock_connection).to receive(:open?).and_return(false)
expect(@client.open?).to eq(false)
end
end
describe "the subscribe method" do
before(:each) do
allow(@mock_connection).to receive(:subscribe).and_return(true)
end
it "should raise RuntimeError if not passed a block" do
expect {
@client.subscribe(@destination)
}.to raise_error(RuntimeError)
end
it "should not raise an error when passed a block" do
expect {
@client.subscribe(@destination) {|msg| received = msg}
}.not_to raise_error
end
it "should raise RuntimeError on duplicate subscriptions" do
expect {
@client.subscribe(@destination)
@client.subscribe(@destination)
}.to raise_error(RuntimeError)
end
it "should raise RuntimeError with duplicate id headers" do
expect {
@client.subscribe(@destination, {'id' => 'abcdef'})
@client.subscribe(@destination, {'id' => 'abcdef'})
}.to raise_error(RuntimeError)
end
end
end
stomp-1.4.4/spec/spec_helper.rb 0000644 0000041 0000041 00000000461 13120662775 016474 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'rubygems' if RUBY_VERSION < "1.9"
require 'rspec'
dir = File.dirname(__FILE__)
lib_path = File.expand_path("#{dir}/../lib")
$LOAD_PATH.unshift lib_path unless $LOAD_PATH.include?(lib_path)
puts "RSpec version: #{RSpec::Version::STRING}"
$stdout.flush
require 'stomp'
stomp-1.4.4/spec/client_spec.rb 0000644 0000041 0000041 00000052143 13120662775 016477 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'spec_helper'
require 'client_shared_examples'
describe Stomp::Client do
let(:null_logger) { double("mock Stomp::NullLogger") }
before(:each) do
allow(Stomp::NullLogger).to receive(:new).and_return(null_logger)
@mock_connection = double('connection', :autoflush= => true)
allow(Stomp::Connection).to receive(:new).and_return(@mock_connection)
end
describe "(created with no params)" do
before(:each) do
@client = Stomp::Client.new
end
it "should not return any errors" do
expect {
@client = Stomp::Client.new
}.not_to raise_error
end
it "should not return any errors when created with the open constructor" do
expect {
@client = Stomp::Client.open
}.not_to raise_error
end
it_should_behave_like "standard Client"
end
describe 'delegated params' do
before :each do
@mock_connection = double('connection', :autoflush= => true,
:login => 'dummy login',
:passcode => 'dummy passcode',
:port => 12345,
:host => 'dummy host',
:ssl => 'dummy ssl')
allow(Stomp::Connection).to receive(:new).and_return(@mock_connection)
@client = Stomp::Client.new
end
describe 'it should delegate parameters to its connection' do
subject { @client }
describe '#login' do
subject { super().login }
it { should eql 'dummy login' }
end
describe '#passcode' do
subject { super().passcode }
it { should eql 'dummy passcode' }
end
describe '#port' do
subject { super().port }
it { should eql 12345 }
end
describe '#host' do
subject { super().host }
it { should eql 'dummy host' }
end
describe '#ssl' do
subject { super().ssl }
it { should eql 'dummy ssl' }
end
end
end
describe "(autoflush)" do
it "should delegate to the connection for accessing the autoflush property" do
expect(@mock_connection).to receive(:autoflush)
Stomp::Client.new.autoflush
end
it "should delegate to the connection for setting the autoflush property" do
expect(@mock_connection).to receive(:autoflush=).with(true)
Stomp::Client.new.autoflush = true
end
it "should set the autoflush property on the connection when passing in autoflush as a parameter to the Stomp::Client" do
expect(@mock_connection).to receive(:autoflush=).with(true)
Stomp::Client.new("login", "password", 'localhost', 61613, false, true)
end
end
describe "(created with invalid params)" do
it "should return ArgumentError if port is nil" do
expect {
@client = Stomp::Client.new('login', 'passcode', 'localhost', nil)
}.to raise_error(ArgumentError)
end
it "should return ArgumentError if port is < 1" do
expect {
@client = Stomp::Client.new('login', 'passcode', 'localhost', 0)
}.to raise_error(ArgumentError)
end
it "should return ArgumentError if port is > 65535" do
expect {
@client = Stomp::Client.new('login', 'passcode', 'localhost', 65536)
}.to raise_error(ArgumentError)
end
it "should return ArgumentError if port is empty" do
expect {
@client = Stomp::Client.new('login', 'passcode', 'localhost', '')
}.to raise_error(ArgumentError)
end
it "should return ArgumentError if reliable is something other than true or false" do
expect {
@client = Stomp::Client.new('login', 'passcode', 'localhost', '12345', 'foo')
}.to raise_error(ArgumentError)
end
end
describe "(created with positional params)" do
before(:each) do
@client = Stomp::Client.new('testlogin', 'testpassword', 'localhost', '12345', false)
@cli_thread = @client.parameters[:client_main]
end
it "should properly parse the URL provided" do
expect(Stomp::Connection).to receive(:new).with(:hosts => [{:login => 'testlogin',
:passcode => 'testpassword',
:host => 'localhost',
:port => 12345}],
:logger => null_logger,
:reliable => false,
:client_main => @cli_thread)
Stomp::Client.new('testlogin', 'testpassword', 'localhost', '12345', false)
end
it_should_behave_like "standard Client"
end
describe "(created with non-authenticating stomp:// URL and non-TLD host)" do
before(:each) do
@client = Stomp::Client.new('stomp://foobar:12345')
@cli_thread = @client.parameters[:client_main]
end
it "should properly parse the URL provided" do
expect(Stomp::Connection).to receive(:new).with(:hosts => [{:login => '',
:passcode => '',
:host => 'foobar',
:port => 12345}],
:logger => null_logger,
:reliable => false,
:client_main => @cli_thread)
Stomp::Client.new('stomp://foobar:12345')
end
it_should_behave_like "standard Client"
end
describe "(created with non-authenticating stomp:// URL and a host with a '-')" do
before(:each) do
@client = Stomp::Client.new('stomp://foo-bar:12345')
@cli_thread = @client.parameters[:client_main]
end
it "should properly parse the URL provided" do
expect(Stomp::Connection).to receive(:new).with(:hosts => [{:login => '',
:passcode => '',
:host => 'foo-bar',
:port => 12345}],
:logger => null_logger,
:reliable => false,
:client_main => @cli_thread)
Stomp::Client.new('stomp://foo-bar:12345')
end
it_should_behave_like "standard Client"
end
describe "(created with authenticating stomp:// URL and non-TLD host)" do
before(:each) do
@client = Stomp::Client.new('stomp://test-login:testpasscode@foobar:12345')
@cli_thread = @client.parameters[:client_main]
end
it "should properly parse the URL provided" do
expect(Stomp::Connection).to receive(:new).with(:hosts => [{:login => 'test-login',
:passcode => 'testpasscode',
:host => 'foobar',
:port => 12345}],
:logger => null_logger,
:reliable => false,
:client_main => @cli_thread)
Stomp::Client.new('stomp://test-login:testpasscode@foobar:12345')
end
it_should_behave_like "standard Client"
end
describe "(created with authenticating stomp:// URL and a host with a '-')" do
before(:each) do
@client = Stomp::Client.new('stomp://test-login:testpasscode@foo-bar:12345')
@cli_thread = @client.parameters[:client_main]
end
it "should properly parse the URL provided" do
expect(Stomp::Connection).to receive(:new).with(:hosts => [{:login => 'test-login',
:passcode => 'testpasscode',
:host => 'foo-bar',
:port => 12345}],
:logger => null_logger,
:reliable => false,
:client_main => @cli_thread)
Stomp::Client.new('stomp://test-login:testpasscode@foo-bar:12345')
end
it_should_behave_like "standard Client"
end
describe "(created with non-authenticating stomp:// URL and TLD host)" do
before(:each) do
@client = Stomp::Client.new('stomp://host.foobar.com:12345')
@cli_thread = @client.parameters[:client_main]
end
after(:each) do
end
it "should properly parse the URL provided" do
expect(Stomp::Connection).to receive(:new).with(:hosts => [{:login => '',
:passcode => '',
:host => 'host.foobar.com',
:port => 12345}],
:logger => null_logger,
:reliable => false,
:client_main => @cli_thread)
Stomp::Client.new('stomp://host.foobar.com:12345')
end
it_should_behave_like "standard Client"
end
describe "(created with authenticating stomp:// URL and non-TLD host)" do
before(:each) do
@client = Stomp::Client.new('stomp://testlogin:testpasscode@host.foobar.com:12345')
@cli_thread = @client.parameters[:client_main]
end
it "should properly parse the URL provided" do
expect(Stomp::Connection).to receive(:new).with(:hosts => [{:login => 'testlogin',
:passcode => 'testpasscode',
:host => 'host.foobar.com',
:port => 12345}],
:logger => null_logger,
:reliable => false,
:client_main => @cli_thread)
Stomp::Client.new('stomp://testlogin:testpasscode@host.foobar.com:12345')
end
it_should_behave_like "standard Client"
end
describe "(created with failover URL)" do
before(:each) do
@client = Stomp::Client.new('failover://(stomp://login1:passcode1@localhost:61616,stomp://login2:passcode2@remotehost:61617)')
@cli_thread = @client.parameters[:client_main]
#default options
@parameters = {
:initial_reconnect_delay => 0.01,
:max_reconnect_delay => 30.0,
:use_exponential_back_off => true,
:back_off_multiplier => 2,
:max_reconnect_attempts => 0,
:randomize => false,
:connect_timeout => 0,
:reliable => true
}
end
it "should properly parse a URL with failover://" do
url = "failover://(stomp://login1:passcode1@localhost:61616,stomp://login2:passcode2@remotehost:61617)"
@parameters[:hosts] = [
{:login => "login1", :passcode => "passcode1", :host => "localhost", :port => 61616, :ssl => false},
{:login => "login2", :passcode => "passcode2", :host => "remotehost", :port => 61617, :ssl => false}
]
@parameters.merge!({:logger => null_logger})
expect(Stomp::Connection).to receive(:new).with(@parameters)
@parameters[:client_main] = @cli_thread
client = Stomp::Client.new(url)
expect(client.parameters).to eq(@parameters)
end
it "should properly parse a URL with failover:" do
url = "failover:(stomp://login1:passcode1@localhost:61616,stomp://login2:passcode2@remotehost1:61617,stomp://login3:passcode3@remotehost2:61618)"
@parameters[:hosts] = [
{:login => "login1", :passcode => "passcode1", :host => "localhost", :port => 61616, :ssl => false},
{:login => "login2", :passcode => "passcode2", :host => "remotehost1", :port => 61617, :ssl => false},
{:login => "login3", :passcode => "passcode3", :host => "remotehost2", :port => 61618, :ssl => false}
]
@parameters.merge!({:logger => null_logger})
@parameters[:client_main] = @cli_thread
expect(Stomp::Connection).to receive(:new).with(@parameters)
client = Stomp::Client.new(url)
expect(client.parameters).to eq(@parameters)
end
it "should properly parse a URL without user and password" do
url = "failover:(stomp://localhost:61616,stomp://remotehost:61617)"
@parameters[:hosts] = [
{:login => "", :passcode => "", :host => "localhost", :port => 61616, :ssl => false},
{:login => "", :passcode => "", :host => "remotehost", :port => 61617, :ssl => false}
]
@parameters.merge!({:logger => null_logger})
@parameters[:client_main] = @cli_thread
expect(Stomp::Connection).to receive(:new).with(@parameters)
client = Stomp::Client.new(url)
@parameters[:client_main] = client.parameters[:client_main]
expect(client.parameters).to eq(@parameters)
end
it "should properly parse a URL with user and/or password blank" do
url = "failover:(stomp://@localhost:61616,stomp://@remotehost:61617)"
@parameters[:hosts] = [
{:login => "", :passcode => "", :host => "localhost", :port => 61616, :ssl => false},
{:login => "", :passcode => "", :host => "remotehost", :port => 61617, :ssl => false}
]
@parameters.merge!({:logger => null_logger})
@parameters[:client_main] = @cli_thread
expect(Stomp::Connection).to receive(:new).with(@parameters)
client = Stomp::Client.new(url)
@parameters[:client_main] = client.parameters[:client_main]
expect(client.parameters).to eq(@parameters)
end
it "should properly parse a URL with the options query" do
query = "initialReconnectDelay=5000&maxReconnectDelay=60000&useExponentialBackOff=false&backOffMultiplier=3"
query += "&maxReconnectAttempts=4&randomize=true&backup=true&timeout=10000"
url = "failover:(stomp://login1:passcode1@localhost:61616,stomp://login2:passcode2@remotehost:61617)?#{query}"
#
@parameters = {
:initial_reconnect_delay => 5.0,
:max_reconnect_delay => 60.0,
:use_exponential_back_off => false,
:back_off_multiplier => 3,
:max_reconnect_attempts => 4,
:randomize => true,
:connect_timeout => 0,
:reliable => true
}
@parameters[:hosts] = [
{:login => "login1", :passcode => "passcode1", :host => "localhost", :port => 61616, :ssl => false},
{:login => "login2", :passcode => "passcode2", :host => "remotehost", :port => 61617, :ssl => false}
]
@parameters.merge!({:logger => null_logger})
@parameters[:client_main] = @cli_thread
expect(Stomp::Connection).to receive(:new).with(@parameters)
client = Stomp::Client.new(url)
@parameters[:client_main] = client.parameters[:client_main]
expect(client.parameters).to eq(@parameters)
end
end
describe '#error_listener' do
context 'on getting a ResourceAllocationException' do
let(:message) do
message = Stomp::Message.new('')
message.body = "javax.jms.ResourceAllocationException: Usage"
message.headers = {'message' => %q{message = "Usage Manager Memory Limit reached. Stopping producer (ID:producer) to prevent flooding queue://errors. See } }
message.command = Stomp::CMD_ERROR
message
end
it 'should handle ProducerFlowControlException errors by raising' do
expect do
@client = Stomp::Client.new
@error_listener = @client.instance_variable_get(:@error_listener)
@error_listener.call(message)
end.to raise_exception(Stomp::Error::ProducerFlowControlException)
end
end
end
describe '(used with custom headers)' do
before :each do
@client = Stomp::Client.new
end
def original_headers
{:custom_header => 'value'}
end
let(:connection_headers) { original_headers }
let(:headers) { original_headers }
shared_examples_for 'argument-safe method' do
describe 'given headers hash' do
subject { headers }
it 'is immutable' do
expect match(original_headers)
end
end
end
describe '#begin' do
before {
expect(@mock_connection).to receive(:begin).with('name', connection_headers)
@client.begin('name', headers)
}
it_behaves_like 'argument-safe method'
end
describe '#abort' do
before {
expect(@mock_connection).to receive(:abort).with('name', connection_headers)
@client.abort('name', headers)
}
it_behaves_like 'argument-safe method'
end
describe '#commit' do
before {
expect(@mock_connection).to receive(:commit).with('name', connection_headers)
@client.commit('name', headers)
}
it_behaves_like 'argument-safe method'
end
describe '#subscribe' do
let(:connection_headers) { original_headers.merge({:id => Digest::SHA1.hexdigest('destination')}) }
before {
expect(@mock_connection).to receive(:subscribe).with('destination', connection_headers)
@client.subscribe('destination', headers) {|dummy_subscriber| }
}
it_behaves_like 'argument-safe method'
end
describe '#unsubscribe' do
let(:connection_headers) { original_headers.merge({:id => Digest::SHA1.hexdigest('destination')}) }
before {
expect(@mock_connection).to receive(:unsubscribe).with('destination', connection_headers)
@client.unsubscribe('destination', headers) {|dummy_subscriber| }
}
it_behaves_like 'argument-safe method'
end
describe '#ack' do
describe 'with STOMP 1.0' do
let(:message) { double('message', :headers => {'message-id' => 'id'}) }
before {
allow(@client).to receive(:protocol).and_return(Stomp::SPL_10)
expect(@mock_connection).to receive(:ack).with('id', connection_headers)
@client.ack(message, headers)
}
it_behaves_like 'argument-safe method'
end
describe 'with STOMP 1.1' do
let(:message) { double('message', :headers => {'message-id' => 'id', 'subscription' => 'subscription_name'}) }
let(:connection_headers) { original_headers.merge({:subscription => 'subscription_name'}) }
before {
allow(@client).to receive(:protocol).and_return(Stomp::SPL_11)
expect(@mock_connection).to receive(:ack).with('id', connection_headers)
@client.ack(message, headers)
}
it_behaves_like 'argument-safe method'
end
describe 'with STOMP 1.2' do
let(:message) { double('message', :headers => {'ack' => 'id'}) }
before {
allow(@client).to receive(:protocol).and_return(Stomp::SPL_12)
expect(@mock_connection).to receive(:ack).with('id', connection_headers)
@client.ack(message, headers)
}
it_behaves_like 'argument-safe method'
end
end
describe '#nack' do
describe 'with STOMP 1.0' do
let(:message) { double('message', :headers => {'message-id' => 'id'}) }
before {
allow(@client).to receive(:protocol).and_return(Stomp::SPL_10)
expect(@mock_connection).to receive(:nack).with('id', connection_headers)
@client.nack(message, headers)
}
it_behaves_like 'argument-safe method'
end
describe 'with STOMP 1.1' do
let(:message) { double('message', :headers => {'message-id' => 'id', 'subscription' => 'subscription_name'}) }
let(:connection_headers) { original_headers.merge({:subscription => 'subscription_name'}) }
before {
allow(@client).to receive(:protocol).and_return(Stomp::SPL_11)
expect(@mock_connection).to receive(:nack).with('id', connection_headers)
@client.nack(message, headers)
}
it_behaves_like 'argument-safe method'
end
describe 'with STOMP 1.2' do
let(:message) { double('message', :headers => {'ack' => 'id'}) }
before {
allow(@client).to receive(:protocol).and_return(Stomp::SPL_12)
expect(@mock_connection).to receive(:nack).with('id', connection_headers)
@client.nack(message, headers)
}
it_behaves_like 'argument-safe method'
end
end
describe '#publish' do
describe 'without listener' do
let(:message) { double('message') }
before {
expect(@mock_connection).to receive(:publish).with('destination', message, connection_headers)
@client.publish('destination', message, headers)
}
it_behaves_like 'argument-safe method'
end
describe 'with listener' do
let(:message) { double('message') }
let(:connection_headers) { original_headers.merge({:receipt => 'receipt-uuid'}) }
before {
allow(@client).to receive(:uuid).and_return('receipt-uuid')
expect(@mock_connection).to receive(:publish).with('destination', message, connection_headers)
@client.publish('destination', message, headers) {|dummy_listener| }
}
it_behaves_like 'argument-safe method'
end
end
end
end
stomp-1.4.4/spec/message_spec.rb 0000644 0000041 0000041 00000003242 13120662775 016641 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'spec_helper'
describe Stomp::Message do
context 'when initializing a new message' do
context 'with invalid parameters' do
it 'should return an empty message when receiving an empty string or nil parameter' do
message = Stomp::Message.new('')
expect(message).to be_empty
# message.should be_empty
end
it 'should raise Stomp::Error::InvalidFormat when receiving a invalid formated message' do
expect{ Stomp::Message.new('any invalid format') }.to raise_error(Stomp::Error::InvalidFormat)
end
end
context 'with valid parameters' do
subject do
@message = ["CONNECTED\n", "session:host_address\n", "\n", "body value\n", "\000\n"]
Stomp::Message.new(@message.join)
end
it 'should parse the headers' do
expect(subject.headers).to eq({'session' => 'host_address'})
end
it 'should parse the body' do
expect(subject.body).to eq(@message[3])
end
it 'should parse the command' do
expect(subject.command).to eq(@message[0].chomp)
end
end
context 'with multiple line ends on the body' do
subject do
@message = ["CONNECTED\n", "session:host_address\n", "\n", "body\n\n value\n\n\n", "\000\n"]
Stomp::Message.new(@message.join)
end
it 'should parse the headers' do
expect(subject.headers).to eq({'session' => 'host_address'})
end
it 'should parse the body' do
expect(subject.body).to eq(@message[3])
end
it 'should parse the command' do
expect(subject.command).to eq(@message[0].chomp)
end
end
end
end
stomp-1.4.4/lib/ 0000755 0000041 0000041 00000000000 13120662775 013471 5 ustar www-data www-data stomp-1.4.4/lib/stomp.rb 0000644 0000041 0000041 00000003112 13120662775 015155 0 ustar www-data www-data # -*- encoding: utf-8 -*-
# Copyright 2005-2006 Brian McCallister
# Copyright 2006 LogicBlaze Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
require 'stomp/constants' # Constants first
require 'stomp/ext/hash' # #Hash additions
require 'stomp/connection' # Main Stomp#Connection
require 'stomp/client' # Main Stomp#Client
require 'stomp/message' # Stomp#Message
require 'stomp/version' # Stomp#Version#STRING
require 'stomp/errors' # All Stomp# exceptions
require 'stomp/codec' # Stomp 1.1 codec
require 'stomp/sslparams' # Stomp SSL support
require 'stomp/null_logger' # A NullLogger class
# Private methods in #Client
require 'client/utils' # private Client Utility methods
# Private methods in #Connection
require 'connection/utils' # private Connection Utility methods
require 'connection/netio' # private Network io methods
require 'connection/heartbeats' # private 1.1+ heartbeat related methods
require 'connection/utf8' # private 1.1+ UTF8 related methods
module Stomp
end
stomp-1.4.4/lib/client/ 0000755 0000041 0000041 00000000000 13120662775 014747 5 ustar www-data www-data stomp-1.4.4/lib/client/utils.rb 0000644 0000041 0000041 00000016343 13120662775 016443 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'thread'
require 'digest/sha1'
module Stomp
class Client
private
def parse_hash_params(params)
return false unless params.is_a?(Hash)
@parameters = params
# Do not override user choice of false.
@parameters[:reliable] = true unless @parameters[:reliable] == false
true
end
def parse_stomp_url(login)
original_verbose, $VERBOSE = $VERBOSE, nil # shut off warnings
regexp = /^stomp:\/\/#{URL_REPAT}/
url = regexp.match(login)
$VERBOSE = original_verbose
return false unless url
@login = url[3] || ""
@passcode = url[4] || ""
@host = url[5]
@port = url[6].to_i
@parameters = { :reliable => false,
:hosts => [ { :login => @login,
:passcode => @passcode,
:host => @host,
:port => @port} ] }
true
end
# e.g. failover://(stomp://login1:passcode1@localhost:61616,stomp://login2:passcode2@remotehost:61617)?option1=param
def parse_failover_url(login)
rval = nil
original_verbose, $VERBOSE = $VERBOSE, nil # shut off warnings
md = FAILOVER_REGEX.match(login)
$VERBOSE = original_verbose
if md
finhosts = parse_hosts(login)
options = {}
if md_last = md[-1]
parts = md_last.split(/&|=/)
raise Stomp::Error::MalformedFailoverOptionsError unless ( parts.size % 2 ) == 0
options = Hash[*parts]
end
@parameters = {:hosts => finhosts}.merge!(filter_options(options))
@parameters[:reliable] = true
rval = true
end
rval
end
def parse_positional_params(login, passcode, host, port, reliable)
@parameters = { :reliable => reliable,
:hosts => [ { :login => login,
:passcode => passcode,
:host => host,
:port => port.to_i } ] }
true
end
# Set a subscription id in the headers hash if one does not already exist.
# For simplicities sake, all subscriptions have a subscription ID.
# setting an id in the SUBSCRIPTION header is described in the stomp protocol docs:
# http://stomp.github.com/
def set_subscription_id_if_missing(destination, headers)
headers[:id] = build_subscription_id(destination, headers)
end
def build_subscription_id(destination, headers)
return headers[:id] until headers[:id].nil?
return headers['id'] until headers['id'].nil?
# p [ "DBBSID1", destination, headers ]
Digest::SHA1.hexdigest(destination)
end
# Parse a stomp URL.
def parse_hosts(url)
hosts = []
original_verbose, $VERBOSE = $VERBOSE, nil # shut off warnings
host_match = /stomp(\+ssl)?:\/\/#{URL_REPAT}/
url.scan(host_match).each do |match|
host = {}
host[:ssl] = match[0] == "+ssl" ? true : false
host[:login] = match[3] || ""
host[:passcode] = match[4] || ""
host[:host] = match[5]
host[:port] = match[6].to_i
hosts << host
end
$VERBOSE = original_verbose
hosts
end
# A sanity check of required arguments.
def check_arguments!()
raise ArgumentError.new("missing :hosts parameter") unless @parameters[:hosts]
raise ArgumentError.new("invalid :hosts type") unless @parameters[:hosts].is_a?(Array)
@parameters[:hosts].each do |hv|
# Validate port requested
raise ArgumentError.new("empty :port value in #{hv.inspect}") if hv[:port] == ''
unless hv[:port].nil?
tpv = hv[:port].to_i
raise ArgumentError.new("invalid :port value=#{tpv} from #{hv.inspect}") if tpv < 1 || tpv > 65535
end
# Validate host requested (no validation here. if nil or '', localhost will
# be used in #Connection.)
end
raise ArgumentError unless @parameters[:reliable].is_a?(TrueClass) || @parameters[:reliable].is_a?(FalseClass)
#
if @parameters[:reliable] && @start_timeout > 0
warn "WARN detected :reliable == true and :start_timeout > 0"
warn "WARN this may cause incorrect fail-over behavior"
warn "WARN use :start_timeout => 0 to correct fail-over behavior"
end
end
# filter_options returns a new Hash of filtered options.
def filter_options(options)
new_options = {}
new_options[:initial_reconnect_delay] = (options["initialReconnectDelay"] || 10).to_f / 1000 # In ms
new_options[:max_reconnect_delay] = (options["maxReconnectDelay"] || 30000 ).to_f / 1000 # In ms
new_options[:use_exponential_back_off] = !(options["useExponentialBackOff"] == "false") # Default: true
new_options[:back_off_multiplier] = (options["backOffMultiplier"] || 2 ).to_i
new_options[:max_reconnect_attempts] = (options["maxReconnectAttempts"] || 0 ).to_i
new_options[:randomize] = options["randomize"] == "true" # Default: false
new_options[:connect_timeout] = 0
new_options
end
# find_listener returns the listener for a given subscription in a given message.
def find_listener(message)
subscription_id = message.headers['subscription']
if subscription_id == nil
# For backward compatibility, some messages may already exist with no
# subscription id, in which case we can attempt to synthesize one.
set_subscription_id_if_missing(message.headers['destination'], message.headers)
subscription_id = message.headers[:id]
end
listener = @listeners[subscription_id]
listener.call(message) if listener
end
# Register a receipt listener.
def register_receipt_listener(listener)
id = uuid
@receipt_listeners[id] = listener
id
end
def find_receipt_listener(message)
listener = @receipt_listeners[message.headers['receipt-id']]
if listener
listener.call(message)
@receipt_listeners.delete(message.headers['receipt-id'])
end
end
def create_listener_maps
@listeners = {}
@receipt_listeners = {}
@replay_messages_by_txn = {}
@listener_map = Hash.new do |message|
unless @connection.slog(:on_miscerr, @connection.log_params, "Received unknown frame type: '#{message.command}'\n")
warn "Received unknown frame type: '#{message.command}'\n"
end
end
@listener_map[Stomp::CMD_MESSAGE] = lambda {|message| find_listener(message) }
@listener_map[Stomp::CMD_RECEIPT] = lambda {|message| find_receipt_listener(message) }
@listener_map[Stomp::CMD_ERROR] = @error_listener
end
# Start a single listener thread. Misnamed I think.
def start_listeners()
create_listener_maps
@listener_thread = Thread.start do
loop do
message = @connection.receive
# AMQ specific behavior
if message.nil? && (!@parameters[:reliable])
raise Stomp::Error::NilMessageError
end
next unless message # message can be nil on rapid AMQ stop/start sequences
@listener_map[message.command].call(message)
end
end
end # method start_listeners
end # class Client
end # module Stomp
stomp-1.4.4/lib/stomp/ 0000755 0000041 0000041 00000000000 13120662775 014633 5 ustar www-data www-data stomp-1.4.4/lib/stomp/codec.rb 0000644 0000041 0000041 00000001724 13120662775 016241 0 ustar www-data www-data # -*- encoding: utf-8 -*-
module Stomp
#
# == Purpose
#
# A general CODEC for STOMP 1.1 header keys and values.
#
# See:
#
# * http://stomp.github.com/index.html
#
# for encode/decode rules.
#
class HeaderCodec
public
# encode encodes header data per the STOMP 1.1 specification.
def self.encode(in_string = nil)
return in_string unless in_string
ev = Stomp::ENCODE_VALUES # avoid typing below
os = in_string + ""
0.step(ev.length-2,2) do |i| # [encoded, decoded]
os.gsub!(ev[i+1], ev[i])
end
os
end
# decode decodes header data per the STOMP 1.1 specification.
def self.decode(in_string = nil)
return in_string unless in_string
ev = Stomp::DECODE_VALUES # avoid typing below
os = in_string + ""
0.step(ev.length-2,2) do |i| # [encoded, decoded]
os.gsub!(ev[i], ev[i+1])
end
os
end
end # of class HeaderCodec
end # of module Stomp
stomp-1.4.4/lib/stomp/connection.rb 0000644 0000041 0000041 00000060233 13120662775 017323 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'socket'
require 'timeout'
require 'io/wait'
require 'digest/sha1'
module Stomp
# Low level connection which maps commands and supports
# synchronous receives
class Connection
public
# The CONNECTED frame from the broker.
attr_reader :connection_frame
# Any disconnect RECEIPT frame if requested.
attr_reader :disconnect_receipt
# The Stomp Protocol version.
attr_reader :protocol
# A unique session ID, assigned by the broker.
attr_reader :session
# Heartbeat receive has been on time.
attr_reader :hb_received # Heartbeat received on time
# Heartbeat send has been successful.
attr_reader :hb_sent # Heartbeat sent successfully
# JRuby detected
attr_reader :jruby
# Autoflush forces a flush on each transmit. This may be changed
# dynamically by calling code.
attr_accessor :autoflush
# Currently-connected host and port
attr_reader :host, :port
# default_port returns the default port used by the gem for TCP or SSL.
def self.default_port(ssl)
ssl ? 61612 : 61613
end
# SSL Helper
def self.ssl_v2xoptions()
require 'openssl' unless defined?(OpenSSL)
# Mimic code in later versions of Ruby 2.x (and backported to later
# versions of 1.9.3).
opts = OpenSSL::SSL::OP_ALL
opts &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS if defined?(OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS)
opts |= OpenSSL::SSL::OP_NO_COMPRESSION if defined?(OpenSSL::SSL::OP_NO_COMPRESSION)
opts |= OpenSSL::SSL::OP_NO_SSLv2 if defined?(OpenSSL::SSL::OP_NO_SSLv2)
opts |= OpenSSL::SSL::OP_NO_SSLv3 if defined?(OpenSSL::SSL::OP_NO_SSLv3)
end
# A new Connection object can be initialized using two forms:
#
# Hash (this is the recommended Connection initialization method):
#
# hash = {
# :hosts => [
# {:login => "login1", :passcode => "passcode1", :host => "localhost", :port => 61616, :ssl => false},
# {:login => "login2", :passcode => "passcode2", :host => "remotehost", :port => 61617, :ssl => false}
# ],
# # These are the default parameters and do not need to be set
# :reliable => true, # reliable (use failover)
# :initial_reconnect_delay => 0.01, # initial delay before reconnect (secs)
# :max_reconnect_delay => 30.0, # max delay before reconnect
# :use_exponential_back_off => true, # increase delay between reconnect attpempts
# :back_off_multiplier => 2, # next delay multiplier
# :max_reconnect_attempts => 0, # retry forever, use # for maximum attempts
# :randomize => false, # do not radomize hosts hash before reconnect
# :connect_timeout => 0, # Timeout for TCP/TLS connects, use # for max seconds
# :connect_headers => {}, # user supplied CONNECT headers (req'd for Stomp 1.1+)
# :parse_timeout => 5, # IO::select wait time on socket reads
# :logger => nil, # user suplied callback logger instance
# :dmh => false, # do not support multihomed IPV4 / IPV6 hosts during failover
# :closed_check => true, # check first if closed in each protocol method
# :hbser => false, # raise on heartbeat send exception
# :stompconn => false, # Use STOMP instead of CONNECT
# :usecrlf => false, # Use CRLF command and header line ends (1.2+)
# :max_hbread_fails => 0, # Max HB read fails before retry. 0 => never retry
# :max_hbrlck_fails => 0, # Max HB read lock obtain fails before retry. 0 => never retry
# :fast_hbs_adjust => 0.0, # Fast heartbeat senders sleep adjustment, seconds, needed ...
# # For fast heartbeat senders. 'fast' == YMMV. If not
# # correct for your environment, expect unnecessary fail overs
# :connread_timeout => 0, # Timeout during CONNECT for read of CONNECTED/ERROR, secs
# :tcp_nodelay => true, # Turns on the TCP_NODELAY socket option; disables Nagle's algorithm
# :start_timeout => 0, # Timeout around Stomp::Client initialization
# :sslctx_newparm => nil, # Param for SSLContext.new
# :ssl_post_conn_check => true, # Further verify broker identity
# }
#
# e.g. c = Stomp::Connection.new(hash)
#
# Positional parameters:
#
# login (String, default : '')
# passcode (String, default : '')
# host (String, default : 'localhost')
# port (Integer, default : 61613)
# reliable (Boolean, default : false)
# reconnect_delay (Integer, default : 5)
#
# e.g. c = Stomp::Connection.new("username", "password", "localhost", 61613, true)
#
def initialize(login = '', passcode = '', host = 'localhost', port = 61613, reliable = false, reconnect_delay = 5, connect_headers = {})
@protocol = Stomp::SPL_10 # Assumed at first
@hb_received = true # Assumed at first
@hb_sent = true # Assumed at first
@hbs = @hbr = false # Sending/Receiving heartbeats. Assume no for now.
@jruby = false # Assumed at first
# Initialize some variables
@closed, @socket, @hhas10, @rt, @st = true, nil, false, nil, nil
if defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/
@jruby = true
end
if login.is_a?(Hash)
hashed_initialize(login)
else
@host = host
@port = port
@login = login
@passcode = passcode
@reliable = reliable
@reconnect_delay = reconnect_delay
@connect_headers = connect_headers
@ssl = false
@parameters = nil
@parse_timeout = 5 # To override, use hashed parameters
@connect_timeout = 0 # To override, use hashed parameters
@logger = Stomp::NullLogger.new # To override, use hashed parameters
@autoflush = false # To override, use hashed parameters or setter
@closed_check = true # Run closed check in each protocol method
@hbser = false # Raise if heartbeat send exception
@stompconn = false # If true, use STOMP rather than CONNECT
@usecrlf = false # If true, use \r\n as line ends (1.2 only)
@max_hbread_fails = 0 # 0 means never retry for HB read failures
@max_hbrlck_fails = 0 # 0 means never retry for HB read lock failures
@fast_hbs_adjust = 0.0 # Fast heartbeat senders sleep adjustment
@connread_timeout = 0 # Connect read CONNECTED/ERROR timeout
@tcp_nodelay = true # Disable Nagle
@start_timeout = 0 # Client only, startup timeout
@sslctx_newparm = nil # SSLContext.new paramater
@ssl_post_conn_check = true # Additional broker verification
warn "login looks like a URL, do you have the correct parameters?" if @login =~ /:\/\//
end
# Use Mutexes: only one lock per each thread.
# Reverted to original implementation attempt using Mutex.
@transmit_semaphore = Mutex.new
@read_semaphore = Mutex.new
@socket_semaphore = Mutex.new
@gets_semaphore = Mutex.new
@subscriptions = {}
@failure = nil
@connection_attempts = 0
socket
end
# hashed_initialize prepares a new connection with a Hash of initialization
# parameters.
def hashed_initialize(params)
lp = _hdup(params)
@parameters = refine_params(lp)
@reliable = @parameters[:reliable]
@reconnect_delay = @parameters[:initial_reconnect_delay]
@connect_headers = @parameters[:connect_headers]
@parse_timeout = @parameters[:parse_timeout]
@connect_timeout = @parameters[:connect_timeout]
@logger = @parameters[:logger] || Stomp::NullLogger.new
@autoflush = @parameters[:autoflush]
@closed_check = @parameters[:closed_check]
@hbser = @parameters[:hbser]
@stompconn = @parameters[:stompconn]
@usecrlf = @parameters[:usecrlf]
@max_hbread_fails = @parameters[:max_hbread_fails]
@max_hbrlck_fails = @parameters[:max_hbrlck_fails]
@fast_hbs_adjust = @parameters[:fast_hbs_adjust]
@connread_timeout = @parameters[:connread_timeout]
@sslctx_newparm = @parameters[:sslctx_newparm]
@ssl_post_conn_check = @parameters[:ssl_post_conn_check]
#
# Try to support Ruby 1.9.x and 2.x ssl.
unless defined?(RSpec)
@parameters[:hosts].each do |ah|
ah[:ssl] = Stomp::SSLParams.new if ah[:ssl] == true
end
end
#sets the first host to connect
change_host
end
# open is syntactic sugar for 'Connection.new', see 'initialize' for usage.
def Connection.open(login = '', passcode = '', host = 'localhost', port = 61613, reliable = false, reconnect_delay = 5, connect_headers = {})
Connection.new(login, passcode, host, port, reliable, reconnect_delay, connect_headers)
end
# open? tests if this connection is open.
def open?
!@closed
end
# closed? tests if this connection is closed.
def closed?
@closed
end
# Begin starts a transaction, and requires a name for the transaction
def begin(name, headers = {})
raise Stomp::Error::NoCurrentConnection if @closed_check && closed?
raise Stomp::Error::ProtocolErrorEmptyHeaderKey if headers.has_key?("")
raise Stomp::Error::ProtocolErrorEmptyHeaderValue if @protocol == Stomp::SPL_10 && headers.has_value?("")
headers = headers.symbolize_keys
headers[:transaction] = name
_headerCheck(headers)
slog(:on_begin, log_params, headers)
transmit(Stomp::CMD_BEGIN, headers)
end
# Acknowledge a message, used when a subscription has specified
# client acknowledgement e.g.:
#
# connection.subscribe("/queue/a", :ack => 'client')
#
# connection.subscribe("/queue/a", :ack => 'client-individual')
#
# as appropriate for the protocol level.
#
# Accepts an optional transaction header ( :transaction => 'some_transaction_id' ).
#
# When the connection protocol level is 1.0 or 1.1 the message_or_ack_id parameter
# should match the message-id header of the MESSAGE being acknowledged e.g.:
#
# connection.ack(message.headers['message-id'])
#
# When the connection protocol level is 1.2 the message_or_ack_id parameter
# should match the ack header of the MESSAGE being acknowledged e.g.:
#
# connection.ack(message.headers['ack'])
#
# In summary, the behavior is protocol level dependent, see the specifications
# and comments in the code.
def ack(message_or_ack_id, headers = {})
raise Stomp::Error::NoCurrentConnection if @closed_check && closed?
raise Stomp::Error::ProtocolErrorEmptyHeaderKey if headers.has_key?("")
raise Stomp::Error::ProtocolErrorEmptyHeaderValue if @protocol == Stomp::SPL_10 && headers.has_value?("")
raise Stomp::Error::MessageIDRequiredError if message_or_ack_id.nil? || message_or_ack_id == ""
headers = headers.symbolize_keys
case @protocol
when Stomp::SPL_12
# The ACK frame MUST include an "id" header matching the "ack" header
# of the MESSAGE being acknowledged.
headers[:id] = message_or_ack_id
when Stomp::SPL_11
# ACK has two REQUIRED headers: "message-id", which MUST contain a value
# matching the message-id header of the MESSAGE being acknowledged and
# "subscription", which MUST be set to match the value of SUBSCRIBE's
# id header.
headers[:'message-id'] = message_or_ack_id
raise Stomp::Error::SubscriptionRequiredError unless headers[:subscription]
else # Stomp::SPL_10
# ACK has one required header, "message-id", which must contain a value
# matching the message-id for the MESSAGE being acknowledged.
headers[:'message-id'] = message_or_ack_id
end
_headerCheck(headers)
slog(:on_ack, log_params, headers)
transmit(Stomp::CMD_ACK, headers)
end
# STOMP 1.1+ NACK.
#
# When the connection protocol level is 1.1 the message_or_ack_id parameter
# should match the message-id header of the MESSAGE being acknowledged.
#
# When the connection protocol level is 1.2 the message_or_ack_id parameter
# should match the ack header of the MESSAGE being acknowledged.
#
# Behavior is protocol level dependent, see the specifications and comments below.
def nack(message_or_ack_id, headers = {})
raise Stomp::Error::NoCurrentConnection if @closed_check && closed?
raise Stomp::Error::UnsupportedProtocolError if @protocol == Stomp::SPL_10
raise Stomp::Error::ProtocolErrorEmptyHeaderKey if headers.has_key?("")
raise Stomp::Error::MessageIDRequiredError if message_or_ack_id.nil? || message_or_ack_id == ""
headers = headers.symbolize_keys
case @protocol
when Stomp::SPL_12
# The NACK frame MUST include an id header matching the ack header
# of the MESSAGE being acknowledged.
headers[:id] = message_or_ack_id
else # Stomp::SPL_11 only
# NACK has two REQUIRED headers: message-id, which MUST contain a value
# matching the message-id for the MESSAGE being acknowledged and
# subscription, which MUST be set to match the value of the subscription's
# id header.
headers[:'message-id'] = message_or_ack_id
raise Stomp::Error::SubscriptionRequiredError unless headers[:subscription]
end
_headerCheck(headers)
slog(:on_nack, log_params, headers)
transmit(Stomp::CMD_NACK, headers)
end
# Commit commits a transaction by name.
def commit(name, headers = {})
raise Stomp::Error::NoCurrentConnection if @closed_check && closed?
raise Stomp::Error::ProtocolErrorEmptyHeaderKey if headers.has_key?("")
raise Stomp::Error::ProtocolErrorEmptyHeaderValue if @protocol == Stomp::SPL_10 && headers.has_value?("")
headers = headers.symbolize_keys
headers[:transaction] = name
_headerCheck(headers)
slog(:on_commit, log_params, headers)
transmit(Stomp::CMD_COMMIT, headers)
end
# Abort aborts a transaction by name.
def abort(name, headers = {})
raise Stomp::Error::NoCurrentConnection if @closed_check && closed?
raise Stomp::Error::ProtocolErrorEmptyHeaderKey if headers.has_key?("")
raise Stomp::Error::ProtocolErrorEmptyHeaderValue if @protocol == Stomp::SPL_10 && headers.has_value?("")
headers = headers.symbolize_keys
headers[:transaction] = name
_headerCheck(headers)
slog(:on_abort, log_params, headers)
transmit(Stomp::CMD_ABORT, headers)
end
# Subscribe subscribes to a destination. A subscription name is required.
# For Stomp 1.1+ a session unique subscription ID is also required.
def subscribe(destination, headers = {}, subId = nil)
raise Stomp::Error::NoCurrentConnection if @closed_check && closed?
raise Stomp::Error::ProtocolErrorEmptyHeaderKey if headers.has_key?("")
raise Stomp::Error::ProtocolErrorEmptyHeaderValue if @protocol == Stomp::SPL_10 && headers.has_value?("")
headers = headers.symbolize_keys
raise Stomp::Error::DestinationRequired unless destination
headers[:destination] = destination
if @protocol >= Stomp::SPL_11
raise Stomp::Error::SubscriptionRequiredError if (headers[:id].nil? && subId.nil?)
headers[:id] = subId if headers[:id].nil?
end
_headerCheck(headers)
slog(:on_subscribe, log_params, headers)
# Store the subscription so that we can replay if we reconnect.
if @reliable
subId = destination if subId.nil?
raise Stomp::Error::DuplicateSubscription if @subscriptions[subId]
@subscriptions[subId] = headers
end
transmit(Stomp::CMD_SUBSCRIBE, headers)
end
# Unsubscribe from a destination. A subscription name is required.
# For Stomp 1.1+ a session unique subscription ID is also required.
def unsubscribe(destination, headers = {}, subId = nil)
raise Stomp::Error::NoCurrentConnection if @closed_check && closed?
raise Stomp::Error::ProtocolErrorEmptyHeaderKey if headers.has_key?("")
raise Stomp::Error::ProtocolErrorEmptyHeaderValue if @protocol == Stomp::SPL_10 && headers.has_value?("")
headers = headers.symbolize_keys
raise Stomp::Error::DestinationRequired unless destination
headers[:destination] = destination
if @protocol >= Stomp::SPL_11
raise Stomp::Error::SubscriptionRequiredError if (headers[:id].nil? && subId.nil?)
headers[:id] = subId unless headers[:id]
end
_headerCheck(headers)
slog(:on_unsubscribe, log_params, headers)
transmit(Stomp::CMD_UNSUBSCRIBE, headers)
if @reliable
subId = destination if subId.nil?
@subscriptions.delete(subId)
end
end
# Publish message to destination.
# To disable content length header use header ( :suppress_content_length => true ).
# Accepts a transaction header ( :transaction => 'some_transaction_id' ).
def publish(destination, message, headers = {})
raise Stomp::Error::NoCurrentConnection if @closed_check && closed?
raise Stomp::Error::ProtocolErrorEmptyHeaderKey if headers.has_key?("")
raise Stomp::Error::ProtocolErrorEmptyHeaderValue if @protocol == Stomp::SPL_10 && headers.has_value?("")
headers = headers.symbolize_keys
raise Stomp::Error::DestinationRequired unless destination
headers[:destination] = destination
_headerCheck(headers)
slog(:on_publish, log_params, message, headers)
transmit(Stomp::CMD_SEND, headers, message)
end
# Send a message back to the source or to the dead letter queue.
# Accepts a dead letter queue option ( :dead_letter_queue => "/queue/DLQ" ).
# Accepts a limit number of redeliveries option ( :max_redeliveries => 6 ).
# Accepts a force client acknowledgement option (:force_client_ack => true).
def unreceive(message, options = {})
raise Stomp::Error::NoCurrentConnection if @closed_check && closed?
options = { :dead_letter_queue => "/queue/DLQ", :max_redeliveries => 6 }.merge(options)
# Lets make sure all keys are symbols
message.headers = message.headers.symbolize_keys
retry_count = message.headers[:retry_count].to_i || 0
message.headers[:retry_count] = retry_count + 1
transaction_id = "transaction-#{message.headers[:'message-id']}-#{retry_count}"
message_id = message.headers.delete(:'message-id')
# Prevent duplicate 'subscription' headers on subsequent receives
message.headers.delete(:subscription) if message.headers[:subscription]
begin
self.begin transaction_id
if client_ack?(message) || options[:force_client_ack]
self.ack(message_id, :transaction => transaction_id)
end
if message.headers[:retry_count] <= options[:max_redeliveries]
self.publish(message.headers[:destination], message.body,
message.headers.merge(:transaction => transaction_id))
else
# Poison ack, sending the message to the DLQ
self.publish(options[:dead_letter_queue], message.body,
message.headers.merge(:transaction => transaction_id,
:original_destination => message.headers[:destination],
:persistent => true))
end
self.commit transaction_id
rescue Exception => exception
self.abort transaction_id
raise exception
end
end
# client_ack? determines if headers contain :ack => "client".
def client_ack?(message)
headers = @subscriptions[message.headers[:destination]]
!headers.nil? && headers[:ack] == "client"
end
# disconnect closes this connection. If requested, a disconnect RECEIPT
# will be received.
def disconnect(headers = {})
raise Stomp::Error::NoCurrentConnection if @closed_check && closed?
raise Stomp::Error::ProtocolErrorEmptyHeaderKey if headers.has_key?("")
raise Stomp::Error::ProtocolErrorEmptyHeaderValue if @protocol == Stomp::SPL_10 && headers.has_value?("")
headers = headers.symbolize_keys
_headerCheck(headers)
if @protocol >= Stomp::SPL_11
@st.kill if @st # Kill ticker thread if any
@rt.kill if @rt # Kill ticker thread if any
end
transmit(Stomp::CMD_DISCONNECT, headers)
@disconnect_receipt = receive if headers[:receipt]
slog(:on_disconnect, log_params)
close_socket
end
# poll returns a pending message if one is available, otherwise
# returns nil.
def poll()
raise Stomp::Error::NoCurrentConnection if @closed_check && closed?
# No need for a read lock here. The receive method eventually fulfills
# that requirement.
return nil if @socket.nil? || !@socket.ready?
receive()
end
# receive returns the next Message off of the wire. this can return nil
# in cases where:
# * the broker has closed the connection
# * the connection is not reliable
def receive()
raise Stomp::Error::NoCurrentConnection if @closed_check && closed?
super_result = __old_receive()
if super_result.nil? && @reliable && !closed?
errstr = "connection.receive returning EOF as nil - resetting connection.\n"
unless slog(:on_miscerr, log_params, "es_recv: " + errstr)
$stderr.print errstr
end
# !!! This initiates a re-connect !!!
# The call to __old_receive() will in turn call socket(). Before
# that we should change the target host, otherwise the host that
# just failed may be attempted first.
_reconn_prep()
#
super_result = __old_receive()
end
#
if super_result.nil? && !@reliable
@st.kill if @st # Kill ticker thread if any
@rt.kill if @rt # Kill ticker thread if any
close_socket()
@closed = true
warn 'warning: broker sent EOF, and connection not reliable' unless defined?(Test)
end
slog(:on_receive, log_params, super_result)
return super_result
end
# set_logger selects a new callback logger instance.
def set_logger(logger)
@logger = logger
end
# valid_utf8? returns an indicator if the given string is a valid UTF8 string.
def valid_utf8?(s)
case RUBY_VERSION
when /1\.8/
rv = _valid_utf8?(s)
else
rv = s.encoding.name != Stomp::UTF8 ? false : s.valid_encoding?
end
rv
end
# sha1 returns a SHA1 digest for arbitrary string data.
def sha1(data)
Digest::SHA1.hexdigest(data)
end
# uuid returns a type 4 UUID.
def uuid()
b = []
0.upto(15) do |i|
b << rand(255)
end
b[6] = (b[6] & 0x0F) | 0x40
b[8] = (b[8] & 0xbf) | 0x80
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
rs = sprintf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x",
b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15])
rs
end
# hbsend_interval returns the connection's heartbeat send interval.
def hbsend_interval()
return 0 unless @hbsend_interval
@hbsend_interval / 1000.0 # ms
end
# hbrecv_interval returns the connection's heartbeat receive interval.
def hbrecv_interval()
return 0 unless @hbrecv_interval
@hbrecv_interval / 1000.0 # ms
end
# hbsend_count returns the current connection's heartbeat send count.
def hbsend_count()
return 0 unless @hbsend_count
@hbsend_count
end
# hbrecv_count returns the current connection's heartbeat receive count.
def hbrecv_count()
return 0 unless @hbrecv_count
@hbrecv_count
end
# log call router
def slog(name, *parms)
return false unless @logger
@logger.send(name, *parms) if @logger.respond_to?(:"#{name}")
@logger.respond_to?(:"#{name}")
end
end # class
end # module
stomp-1.4.4/lib/stomp/errors.rb 0000644 0000041 0000041 00000022251 13120662775 016476 0 ustar www-data www-data # -*- encoding: utf-8 -*-
module Stomp
# Module level container for Stomp gem error classes.
module Error
# NoListenerGiven is raised if:
# * No listener block is passed to Client#subscribe
class NoListenerGiven < RuntimeError
def message
"No listener given"
end
end
# DestinationRequired is raised if:
# * No destination is passed to subscribe, unsubscribe, publish
class DestinationRequired < RuntimeError
def message
"Destination required"
end
end
# InvalidFormat is raised if:
# * During frame parsing if a malformed frame is detected.
class InvalidFormat < RuntimeError
def message
"Invalid message - invalid format"
end
end
# InvalidServerCommand is raised if:
# * An invalid STOMP COMMAND is received from the server.
class InvalidServerCommand < RuntimeError
def message
"Invalid command from server"
end
end
# InvalidMessageLength is raised if:
# * An invalid message length is detected during a frame read.
class InvalidMessageLength < RuntimeError
def message
"Invalid content length received"
end
end
# PacketParsingTimeout is raised if:
# * A frame read has started, but does not complete in 5 seconds.
# * Use :parse_timeout connect parameter to override the timeout.
class PacketParsingTimeout < RuntimeError
def message
"Packet parsing timeout"
end
end
# ReceiveTimeout is raised if:
# * The read socket shows "not ready" at any time after the timeout
# specified by :parse_timeout in the connection hash.
class ReceiveTimeout < RuntimeError
def message
"Receive status timeout"
end
end
# SocketOpenTimeout is raised if:
# * A timeout occurs during a socket open.
class SocketOpenTimeout < RuntimeError
def message
"Socket open timeout"
end
end
# NoCurrentConnection is raised if:
# * Any method is called when a current connection does not exist.
# * And @closed_check is true (the default).
class NoCurrentConnection < RuntimeError
def message
"no current connection exists"
end
end
# MaxReconnectAttempts is raised if:
# * The maximum number of retries has been reached for a reliable connection.
class MaxReconnectAttempts < RuntimeError
def message
"Maximum number of reconnection attempts reached"
end
end
# DuplicateSubscription is raised if:
# * A duplicate subscription ID is detected in the current session.
class DuplicateSubscription < RuntimeError
def message
"duplicate subscriptions are disallowed"
end
end
# ProtocolErrorEmptyHeaderKey is raised if:
# * Any header key is empty ("")
class ProtocolErrorEmptyHeaderKey < RuntimeError
def message
"Empty header key"
end
end
# ProtocolErrorEmptyHeaderValue is raised if:
# * Any header value is empty ("") *and*
# * Connection protocol level == 1.0
class ProtocolErrorEmptyHeaderValue < RuntimeError
def message
"Empty header value, STOMP 1.0"
end
end
# ProtocolError11p - base class of 1.1 CONNECT errors
class ProtocolError11p < RuntimeError
def message
"STOMP 1.1+ CONNECT error"
end
end
# ProtocolErrorConnect is raised if:
# * Incomplete Stomp 1.1 headers are detected during a connect.
class ProtocolErrorConnect < ProtocolError11p
def message
"STOMP 1.1+ CONNECT error, missing/incorrect CONNECT headers"
end
end
# UnsupportedProtocolError is raised if:
# * No supported Stomp protocol levels are detected during a connect.
class UnsupportedProtocolError < ProtocolError11p
def message
"unsupported protocol level(s)"
end
end
# InvalidHeartBeatHeaderError is raised if:
# * A "heart-beat" header is present, but the values are malformed.
class InvalidHeartBeatHeaderError < ProtocolError11p
def message
"heart-beat header value is malformed"
end
end
# SubscriptionRequiredError is raised if:
# * No subscription id is specified for a Stomp 1.1 subscribe.
class SubscriptionRequiredError < RuntimeError
def message
"a valid subscription id header is required"
end
end
# UTF8ValidationError is raised if:
# * Stomp 1.1 headers are not valid UTF8.
class UTF8ValidationError < RuntimeError
def message
"header is invalid UTF8"
end
end
# MessageIDRequiredError is raised if:
# * No messageid parameter is specified for ACK or NACK.
class MessageIDRequiredError < RuntimeError
def message
"a valid message id is required for ACK/NACK"
end
end
# SSLClientParamsError is raised if:
# * Incomplete SSLParams are specified for an SSL connect.
class SSLClientParamsError < RuntimeError
def message
"certificate and key files are both required"
end
end
# StompServerError is raised if:
# * Invalid (nil) data is received from the Stomp server.
class StompServerError < RuntimeError
def message
"Connected, header read is nil, is this really a Stomp Server?"
end
end
# SSLNoKeyFileError is raised if:
# * A supplied key file does not exist.
class SSLNoKeyFileError < RuntimeError
def message
"client key file does not exist"
end
end
# SSLUnreadableKeyFileError is raised if:
# * A supplied key file is not readable.
class SSLUnreadableKeyFileError < RuntimeError
def message
"client key file can not be read"
end
end
# SSLNoCertFileError is raised if:
# * A supplied SSL cert file does not exist.
class SSLNoCertFileError < RuntimeError
def message
"client cert file does not exist"
end
end
# SSLUnreadableCertFileError is raised if:
# * A supplied SSL cert file is not readable.
class SSLUnreadableCertFileError < RuntimeError
def message
"client cert file can not be read"
end
end
# SSLNoTruststoreFileError is raised if:
# * A supplied SSL trust store file does not exist.
class SSLNoTruststoreFileError < RuntimeError
def message
"a client truststore file does not exist"
end
end
# SSLUnreadableTruststoreFileError is raised if:
# * A supplied SSL trust store file is not readable.
class SSLUnreadableTruststoreFileError < RuntimeError
def message
"a client truststore file can not be read"
end
end
# LoggerConnectionError is not raised by the gem. It may be
# raised by client logic in callback logger methods to signal
# that a connection should not proceed.
class LoggerConnectionError < RuntimeError
end
# NilMessageError is raised if:
# * Invalid (nil) data is received from the Stomp server in a client's
# listener thread, and the connection is not reliable.
class NilMessageError < RuntimeError
def message
"Received message is nil, and connection not reliable"
end
end
# MalformedFailoverOptionsError is raised if failover URL
# options can not be parsed
class MalformedFailoverOptionsError < RuntimeError
def message
"failover options are malformed"
end
end
# ConnectReadTimeout is raised if:
# * A read for CONNECTED/ERROR is untimely
class ConnectReadTimeout < RuntimeError
def message
"Connect read for CONNECTED/ERROR timeout"
end
end
class StompException < RuntimeError; end
class BrokerException < StompException
attr_reader :headers, :message, :receipt_id, :broker_backtrace
def initialize(message)
@message = message.headers.delete('message')
@receipt_id = message.headers.delete('receipt-id') || 'no receipt id'
@headers = message.headers
@broker_backtrace = message.body
end
end
class ProducerFlowControlException < BrokerException
attr_reader :producer_id, :dest_name
def initialize(message)
super(message)
msg_headers = /.*producer\s+\((.*)\).*to\s+prevent\s+flooding\s+([^\s]*)\.\s+/i.match(@message)
@producer_id = msg_headers && msg_headers[1]
@dest_name = msg_headers && msg_headers[2]
end
end
class ProtocolException < BrokerException
def initialize(message)
super(message)
end
end
class StartTimeoutException < StompException
def initialize(timeout)
@timeout = timeout
end
def message
"Client failed to start in #{@timeout} seconds"
end
end
class ReadReceiptTimeoutException < StompException
def initialize(timeout)
@timeout = timeout
end
def message
"Read receipt not received after #{@timeout} seconds"
end
end
# HandShakeDetectedError is raised if:
# * A normal read detects inbound handskake data
class HandShakeDetectedError < RuntimeError
def message
"Handshake data found, possible mismatched port and sslparams"
end
end
end # module Error
end # module Stomp
stomp-1.4.4/lib/stomp/sslparams.rb 0000644 0000041 0000041 00000005346 13120662775 017175 0 ustar www-data www-data # -*- encoding: utf-8 -*-
module Stomp
#
# == Purpose
#
# Parameters for STOMP ssl connections.
#
class SSLParams
# The trust store files. Normally the certificate of the CA that signed
# the server's certificate. One file name, or a CSV list of file names.
attr_accessor :ts_files
# The client certificate file.
attr_accessor :cert_file
# The client private key file.
attr_accessor :key_file
# The client private key password.
attr_accessor :key_password
# SSL Connect Verify Result. The result of the handshake.
attr_accessor :verify_result
# The certificate of the connection peer (the server), received during
# the handshake.
attr_accessor :peer_cert
# Optional list of SSL ciphers to be used. In the format documented for
# Ruby's OpenSSL.
attr_accessor :ciphers
# Absolute command to use Ruby default ciphers.
attr_reader :use_ruby_ciphers
# Back reference to the OpenSSL::SSL::SSLContext instance, gem sets before connect.
attr_accessor :ctx # Set by the gem during connect, before the callbacks
# Client wants file existance check on initialize. true/value or false/nil.
attr_reader :fsck #
# SSLContext options.
attr_reader :ssl_ctxopts #
# initialize returns a valid instance of SSLParams or raises an error.
def initialize(opts={})
# Server authentication parameters
@ts_files = opts[:ts_files] # A trust store file, normally a CA's cert
# or a CSV list of cert file names
# Client authentication parameters
@cert_file = opts[:cert_file] # Client cert
@key_file = opts[:key_file] # Client key
@key_password = opts[:key_password] # Client key password
#
raise Stomp::Error::SSLClientParamsError if @cert_file.nil? && !@key_file.nil?
raise Stomp::Error::SSLClientParamsError if !@cert_file.nil? && @key_file.nil?
#
@ciphers = opts[:ciphers]
@use_ruby_ciphers = opts[:use_ruby_ciphers] ? opts[:use_ruby_ciphers] : false
#
if opts[:fsck]
if @cert_file
raise Stomp::Error::SSLNoCertFileError if !File::exists?(@cert_file)
raise Stomp::Error::SSLUnreadableCertFileError if !File::readable?(@cert_file)
end
if @key_file
raise Stomp::Error::SSLNoKeyFileError if !File::exists?(@key_file)
raise Stomp::Error::SSLUnreadableKeyFileError if !File::readable?(@key_file)
end
if @ts_files
tsa = @ts_files.split(",")
tsa.each do |fn|
raise Stomp::Error::SSLNoTruststoreFileError if !File::exists?(fn)
raise Stomp::Error::SSLUnreadableTruststoreFileError if !File::readable?(fn)
end
end
end
# SSLContext options. See example: ssl_ctxoptions.rb.
@ssl_ctxopts = opts[:ssl_ctxopts] # nil or options to set
end
end # of class SSLParams
end # of module Stomp
stomp-1.4.4/lib/stomp/client.rb 0000644 0000041 0000041 00000031561 13120662775 016444 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'thread'
require 'digest/sha1'
require 'timeout'
require 'forwardable'
module Stomp
# Typical Stomp client class. Uses a listener thread to receive frames
# from the server, any thread can send.
#
# Receives all happen in one thread, so consider not doing much processing
# in that thread if you have much message volume.
class Client
extend Forwardable
# Parameters hash
attr_reader :parameters
def_delegators :@connection, :login, :passcode, :port, :host, :ssl
def_delegator :@parameters, :reliable
# A new Client object can be initialized using three forms:
#
# Hash (this is the recommended Client initialization method):
#
# hash = {
# :hosts => [
# {:login => "login1", :passcode => "passcode1", :host => "localhost", :port => 61616, :ssl => false},
# {:login => "login2", :passcode => "passcode2", :host => "remotehost", :port => 61617, :ssl => false}
# ],
# # These are the default parameters and do not need to be set
# :reliable => true, # reliable (use failover)
# :initial_reconnect_delay => 0.01, # initial delay before reconnect (secs)
# :max_reconnect_delay => 30.0, # max delay before reconnect
# :use_exponential_back_off => true, # increase delay between reconnect attpempts
# :back_off_multiplier => 2, # next delay multiplier
# :max_reconnect_attempts => 0, # retry forever, use # for maximum attempts
# :randomize => false, # do not radomize hosts hash before reconnect
# :connect_timeout => 0, # Timeout for TCP/TLS connects, use # for max seconds
# :connect_headers => {}, # user supplied CONNECT headers (req'd for Stomp 1.1+)
# :parse_timeout => 5, # IO::select wait time on socket reads
# :logger => nil, # user suplied callback logger instance
# :dmh => false, # do not support multihomed IPV4 / IPV6 hosts during failover
# :closed_check => true, # check first if closed in each protocol method
# :hbser => false, # raise on heartbeat send exception
# :stompconn => false, # Use STOMP instead of CONNECT
# :usecrlf => false, # Use CRLF command and header line ends (1.2+)
# :max_hbread_fails => 0, # Max HB read fails before retry. 0 => never retry
# :max_hbrlck_fails => 0, # Max HB read lock obtain fails before retry. 0 => never retry
# :fast_hbs_adjust => 0.0, # Fast heartbeat senders sleep adjustment, seconds, needed ...
# # For fast heartbeat senders. 'fast' == YMMV. If not
# # correct for your environment, expect unnecessary fail overs
# :connread_timeout => 0, # Timeout during CONNECT for read of CONNECTED/ERROR, secs
# :tcp_nodelay => true, # Turns on the TCP_NODELAY socket option; disables Nagle's algorithm
# :start_timeout => 0, # Timeout around Stomp::Client initialization
# :sslctx_newparm => nil, # Param for SSLContext.new
# :ssl_post_conn_check => true, # Further verify broker identity
# }
#
# e.g. c = Stomp::Client.new(hash)
#
# Positional parameters:
# login (String, default : '')
# passcode (String, default : '')
# host (String, default : 'localhost')
# port (Integer, default : 61613)
# reliable (Boolean, default : false)
#
# e.g. c = Stomp::Client.new('login', 'passcode', 'localhost', 61613, true)
#
# Stomp URL :
# A Stomp URL must begin with 'stomp://' and can be in one of the following forms:
#
# stomp://host:port
# stomp://host.domain.tld:port
# stomp://login:passcode@host:port
# stomp://login:passcode@host.domain.tld:port
#
# e.g. c = Stomp::Client.new(urlstring)
#
def initialize(login = '', passcode = '', host = 'localhost', port = 61613, reliable = false, autoflush = false)
parse_hash_params(login) ||
parse_stomp_url(login) ||
parse_failover_url(login) ||
parse_positional_params(login, passcode, host, port, reliable)
@logger = @parameters[:logger] ||= Stomp::NullLogger.new
@start_timeout = @parameters[:start_timeout] || 0
@parameters[:client_main] = Thread::current
## p [ "CLINDBG", @parameters[:client_main] ]
check_arguments!()
# p [ "cldbg01", @parameters ]
begin
Timeout::timeout(@start_timeout) {
create_error_handler
create_connection(autoflush)
start_listeners()
}
rescue TimeoutError
# p [ "cldbg02" ]
ex = Stomp::Error::StartTimeoutException.new(@start_timeout)
raise ex
end
end
def create_error_handler
client_thread = Thread.current
@error_listener = lambda do |error|
exception = case error.body
when /ResourceAllocationException/i
Stomp::Error::ProducerFlowControlException.new(error)
when /ProtocolException/i
Stomp::Error::ProtocolException.new(error)
else
Stomp::Error::BrokerException.new(error)
end
@receipt_listeners.delete(error.headers['receipt-id']) if error.headers['receipt-id']
client_thread.raise exception
end
end
def create_connection(autoflush)
# p [ "ccon01", @parameters ]
@connection = Connection.new(@parameters)
@connection.autoflush = autoflush
end
private :create_connection
# open is syntactic sugar for 'Client.new', see 'initialize' for usage.
def self.open(login = '', passcode = '', host = 'localhost', port = 61613, reliable = false)
Client.new(login, passcode, host, port, reliable)
end
# join the listener thread for this client,
# generally used to wait for a quit signal.
def join(limit = nil)
@listener_thread.join(limit)
end
# Begin starts work in a a transaction by name.
def begin(name, headers = {})
@connection.begin(name, headers)
end
# Abort aborts work in a transaction by name.
def abort(name, headers = {})
@connection.abort(name, headers)
# replay any ack'd messages in this transaction
replay_list = @replay_messages_by_txn[name]
if replay_list
replay_list.each do |message|
find_listener(message) # find_listener also calls the listener
end
end
end
# Commit commits work in a transaction by name.
def commit(name, headers = {})
txn_id = headers[:transaction]
@replay_messages_by_txn.delete(txn_id)
@connection.commit(name, headers)
end
# Subscribe to a destination, must be passed a block
# which will be used as a callback listener.
# Accepts a transaction header ( :transaction => 'some_transaction_id' ).
def subscribe(destination, headers = {})
raise Stomp::Error::NoListenerGiven unless block_given?
headers = headers.symbolize_keys
raise Stomp::Error::DestinationRequired unless destination
# use subscription id to correlate messages to subscription. As described in
# the SUBSCRIPTION section of the protocol: http://stomp.github.com/.
# If no subscription id is provided, generate one.
headers = headers.merge(:id => build_subscription_id(destination, headers))
if @listeners[headers[:id]]
raise Stomp::Error::DuplicateSubscription
end
@listeners[headers[:id]] = lambda {|msg| yield msg}
@connection.subscribe(destination, headers)
end
# Unsubscribe from a subscription by name.
def unsubscribe(destination, headers = {})
headers = headers.symbolize_keys
raise Stomp::Error::DestinationRequired unless destination
headers = headers.merge(:id => build_subscription_id(destination, headers))
@connection.unsubscribe(destination, headers)
@listeners[headers[:id]] = nil
end
# Acknowledge a message, used when a subscription has specified
# client acknowledgement ( connection.subscribe("/queue/a",{:ack => 'client'}).
# Accepts a transaction header ( :transaction => 'some_transaction_id' ).
def ack(message, headers = {})
txn_id = headers[:transaction]
if txn_id
# lets keep around messages ack'd in this transaction in case we rollback
replay_list = @replay_messages_by_txn[txn_id]
if replay_list.nil?
replay_list = []
@replay_messages_by_txn[txn_id] = replay_list
end
replay_list << message
end
if block_given?
headers = headers.merge(:receipt => register_receipt_listener(lambda {|r| yield r}))
end
context = ack_context_for(message, headers)
@connection.ack context[:message_id], context[:headers]
end
# For posterity, we alias:
alias acknowledge ack
# Stomp 1.1+ NACK.
def nack(message, headers = {})
context = ack_context_for(message, headers)
@connection.nack context[:message_id], context[:headers]
end
#
def ack_context_for(message, headers)
id = case protocol
when Stomp::SPL_12
'ack'
when Stomp::SPL_11
headers = headers.merge(:subscription => message.headers['subscription'])
'message-id'
else
'message-id'
end
{:message_id => message.headers[id], :headers => headers}
end
# Unreceive a message, sending it back to its queue or to the DLQ.
def unreceive(message, options = {})
@connection.unreceive(message, options)
end
# Publishes message to destination.
# If a block is given a receipt will be requested and passed to the
# block on receipt.
# Accepts a transaction header ( :transaction => 'some_transaction_id' ).
def publish(destination, message, headers = {})
headers = headers.symbolize_keys
raise Stomp::Error::DestinationRequired unless destination
if block_given?
headers = headers.merge(:receipt => register_receipt_listener(lambda {|r| yield r}))
end
@connection.publish(destination, message, headers)
end
# Return the broker's CONNECTED frame to the client. Misnamed.
def connection_frame()
@connection.connection_frame
end
# Return any RECEIPT frame received by DISCONNECT.
def disconnect_receipt()
@connection.disconnect_receipt
end
# open? tests if this client connection is open.
def open?
@connection.open?()
end
# close? tests if this client connection is closed.
def closed?()
@connection.closed?()
end
# jruby? tests if the connection has detcted a JRuby environment
def jruby?()
@connection.jruby
end
# close frees resources in use by this client. The listener thread is
# terminated, and disconnect on the connection is called.
def close(headers={})
@listener_thread.exit
@connection.disconnect(headers)
end
# running checks if the thread was created and is not dead.
def running()
@listener_thread && !!@listener_thread.status
end
# set_logger identifies a new callback logger.
def set_logger(logger)
@logger = logger
@connection.set_logger(logger)
end
# protocol returns the current client's protocol level.
def protocol()
@connection.protocol()
end
# valid_utf8? validates any given string for UTF8 compliance.
def valid_utf8?(s)
@connection.valid_utf8?(s)
end
# sha1 returns a SHA1 sum of a given string.
def sha1(data)
@connection.sha1(data)
end
# uuid returns a type 4 UUID.
def uuid()
@connection.uuid()
end
# hbsend_interval returns the connection's heartbeat send interval.
def hbsend_interval()
@connection.hbsend_interval()
end
# hbrecv_interval returns the connection's heartbeat receive interval.
def hbrecv_interval()
@connection.hbrecv_interval()
end
# hbsend_count returns the current connection's heartbeat send count.
def hbsend_count()
@connection.hbsend_count()
end
# hbrecv_count returns the current connection's heartbeat receive count.
def hbrecv_count()
@connection.hbrecv_count()
end
# Poll for asynchronous messages issued by broker.
# Return nil of no message available, else the message
def poll()
@connection.poll()
end
# autoflush= sets the current connection's autoflush setting.
def autoflush=(af)
@connection.autoflush = af
end
# autoflush returns the current connection's autoflush setting.
def autoflush()
@connection.autoflush()
end
end # Class
end # Module
stomp-1.4.4/lib/stomp/slogger.rb 0000644 0000041 0000041 00000016324 13120662775 016630 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'logger' # use the standard Ruby logger .....
# == Example STOMP call back logger class.
#
# Optional callback methods:
#
# * on_connecting: connection starting
# * on_connected: successful connect
# * on_connectfail: unsuccessful connect (will usually be retried)
# * on_disconnect: successful disconnect
#
# * on_miscerr: on miscellaneous xmit/recv errors
#
# * on_publish: publish called
# * on_subscribe: subscribe called
# * on_unsubscribe: unsubscribe called
#
# * on_begin: begin called
# * on_ack: ack called
# * on_nack: nack called
# * on_commit: commit called
# * on_abort: abort called
#
# * on_receive: receive called and successful
#
# * on_ssl_connecting: SSL connection starting
# * on_ssl_connected: successful SSL connect
# * on_ssl_connectfail: unsuccessful SSL connect (will usually be retried)
#
# * on_hbread_fail: unsuccessful Heartbeat read
# * on_hbwrite_fail: unsuccessful Heartbeat write
# * on_hbfire: on any send or receive heartbeat
#
# All methods are optional, at the user's requirements.
#
# If a method is not provided, it is not called (of course.)
#
# IMPORTANT NOTE: in general, call back logging methods *SHOULD* not raise exceptions,
# otherwise the underlying STOMP connection may fail in mysterious ways.
#
# There are two useful exceptions to this rule for:
#
# * on_connectfail
# * on_ssl_connectfail
#
# These two methods can raise a Stomp::Errors::LoggerConnectionError. If this
# exception is raised, it is passed up the chain to the caller.
#
# Callback parameters: are a copy of the @parameters instance variable for
# the Stomp::Connection.
#
class Slogger < Stomp::NullLogger
# Initialize a new callback logger instance.
def initialize(init_parms = nil)
_init
@log.info("Logger initialization complete.")
end
def _init
@log = Logger::new(STDOUT) # User preference
@log.level = Logger::DEBUG # User preference
end
def marshal_dump
[]
end
def marshal_load(array)
_init
end
# Log connecting events
def on_connecting(parms)
begin
@log.debug "Connecting: #{info(parms)}"
rescue
@log.debug "Connecting oops"
end
end
# Log connected events
def on_connected(parms)
begin
@log.debug "Connected: #{info(parms)}"
rescue
@log.debug "Connected oops"
end
end
# Log connectfail events
def on_connectfail(parms)
begin
@log.debug "Connect Fail #{info(parms)}"
rescue
@log.debug "Connect Fail oops"
end
=begin
# An example LoggerConnectionError raise
@log.debug "Connect Fail, will raise"
raise Stomp::Error::LoggerConnectionError.new("quit from connect fail")
=end
end
# Log disconnect events
def on_disconnect(parms)
begin
@log.debug "Disconnected #{info(parms)}"
rescue
@log.debug "Disconnected oops"
end
end
# Log miscellaneous errors
def on_miscerr(parms, errstr)
begin
@log.debug "Miscellaneous Error #{info(parms)}"
@log.debug "Miscellaneous Error String #{errstr}"
rescue
@log.debug "Miscellaneous Error oops"
end
end
# Log Subscribe
def on_subscribe(parms, headers)
begin
@log.debug "Subscribe Parms #{info(parms)}"
@log.debug "Subscribe Headers #{headers}"
rescue
@log.debug "Subscribe oops"
end
end
# Log UnSubscribe
def on_unsubscribe(parms, headers)
begin
@log.debug "UnSubscribe Parms #{info(parms)}"
@log.debug "UnSubscribe Headers #{headers}"
rescue
@log.debug "UnSubscribe oops"
end
end
# Log Publish
def on_publish(parms, message, headers)
begin
@log.debug "Publish Parms #{info(parms)}"
@log.debug "Publish Message #{message}"
@log.debug "Publish Headers #{headers}"
rescue
@log.debug "Publish oops"
end
end
# Log Receive
def on_receive(parms, result)
begin
@log.debug "Receive Parms #{info(parms)}"
@log.debug "Receive Result #{result}"
rescue
@log.debug "Receive oops"
end
end
# Log Begin
def on_begin(parms, headers)
begin
@log.debug "Begin Parms #{info(parms)}"
@log.debug "Begin Result #{headers}"
rescue
@log.debug "Begin oops"
end
end
# Log Ack
def on_ack(parms, headers)
begin
@log.debug "Ack Parms #{info(parms)}"
@log.debug "Ack Result #{headers}"
rescue
@log.debug "Ack oops"
end
end
# Log NAck
def on_nack(parms, headers)
begin
@log.debug "NAck Parms #{info(parms)}"
@log.debug "NAck Result #{headers}"
rescue
@log.debug "NAck oops"
end
end
# Log Commit
def on_commit(parms, headers)
begin
@log.debug "Commit Parms #{info(parms)}"
@log.debug "Commit Result #{headers}"
rescue
@log.debug "Commit oops"
end
end
# Log Abort
def on_abort(parms, headers)
begin
@log.debug "Abort Parms #{info(parms)}"
@log.debug "Abort Result #{headers}"
rescue
@log.debug "Abort oops"
end
end
# Stomp 1.1+ - heart beat read (receive) failed.
def on_hbread_fail(parms, ticker_data = {})
begin
@log.debug "Hbreadf Parms #{info(parms)}"
@log.debug "Hbreadf Result #{ticker_data.inspect}"
rescue
@log.debug "Hbreadf oops"
end
end
# Stomp 1.1+ - heart beat send (transmit) failed.
def on_hbwrite_fail(parms, ticker_data = {})
begin
@log.debug "Hbwritef Parms #{info(parms)}"
@log.debug "Hbwritef Result #{ticker_data.inspect}"
rescue
@log.debug "Hbwritef oops"
end
end
# Log SSL connection start.
def on_ssl_connecting(parms)
begin
@log.debug "SSL Connecting Parms #{info(parms)}"
rescue
@log.debug "SSL Connecting oops"
end
end
# Log a successful SSL connect.
def on_ssl_connected(parms)
begin
@log.debug "SSL Connected Parms #{info(parms)}"
rescue
@log.debug "SSL Connected oops"
end
end
# Log an unsuccessful SSL connect.
def on_ssl_connectfail(parms)
begin
@log.debug "SSL Connect Fail Parms #{info(parms)}"
@log.debug "SSL Connect Fail Exception #{parms[:ssl_exception]}, #{parms[:ssl_exception].message}"
rescue
@log.debug "SSL Connect Fail oops"
end
=begin
# An example LoggerConnectionError raise
@log.debug "SSL Connect Fail, will raise"
raise Stomp::Error::LoggerConnectionError.new("quit from SSL connect")
=end
end
# Log heart beat fires
def on_hbfire(parms, srind, firedata = {})
begin
@log.debug "HeartBeat Fire Parms #{info(parms)}"
@log.debug "HeartBeat Fire Send/Receive #{srind}"
rescue
@log.debug "HeartBeat Fire oops"
end
end
private
# Example information extract.
def info(parms)
#
# Available in the parms Hash:
# parms[:cur_host]
# parms[:cur_port]
# parms[:cur_login]
# parms[:cur_passcode]
# parms[:cur_ssl]
# parms[:cur_recondelay]
# parms[:cur_parseto]
# parms[:cur_conattempts]
# parms[:openstat]
#
# For the on_ssl_connectfail callback these are also available:
# parms[:ssl_exception]
#
"Host: #{parms[:cur_host]}, Port: #{parms[:cur_port]}, Login: #{parms[:cur_login]}, Passcode: #{parms[:cur_passcode]}, ssl: #{parms[:cur_ssl]}"
end
end # of class
stomp-1.4.4/lib/stomp/version.rb 0000644 0000041 0000041 00000000335 13120662775 016646 0 ustar www-data www-data # -*- encoding: utf-8 -*-
module Stomp
# Define the gem version.
module Version #:nodoc: all
MAJOR = 1
MINOR = 4
PATCH = 4
# PATCH = "4.plvl.001"
STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
end
end
stomp-1.4.4/lib/stomp/message.rb 0000644 0000041 0000041 00000010071 13120662775 016603 0 ustar www-data www-data # -*- encoding: utf-8 -*-
module Stomp
# Message is a container class for frames. Misnamed technically.
class Message
public
# The COMMAND value.
attr_accessor :command
# The Headers Hash.
attr_accessor :headers
# The message Body.
attr_accessor :body
# The original input(s).
attr_accessor :original
# Commands that are allowed from the wire per the specifications.
@@allowed_commands = [ Stomp::CMD_CONNECTED, Stomp::CMD_MESSAGE, Stomp::CMD_RECEIPT, Stomp::CMD_ERROR ]
# initialize returns a Message from a raw physical frame.
def initialize(frame, protocol11p = false)
# p [ "00", frame, frame.encoding ]
# Set default empty values
self.command = ''
self.headers = {}
self.body = ''
self.original = frame
return self if is_blank?(frame)
# Figure out where individual parts of the frame begin and end.
command_index = frame.index("\n")
raise Stomp::Error::InvalidFormat, 'command index' unless command_index
#
headers_index = frame.index("\n\n", command_index+1)
raise Stomp::Error::InvalidFormat, 'headers index' unless headers_index
#
lastnull_index = frame.rindex("\0")
raise Stomp::Error::InvalidFormat, 'lastnull index' unless lastnull_index
# Extract working copies of each frame part
work_command = frame[0..command_index-1]
raise Stomp::Error::InvalidServerCommand, "invalid command: #{work_command.inspect}" unless @@allowed_commands.include?(work_command)
#
work_headers = frame[command_index+1..headers_index-1]
raise Stomp::Error::InvalidFormat, 'nil headers' unless work_headers
#
work_body = frame[headers_index+2..lastnull_index-1]
raise Stomp::Error::InvalidFormat, 'nil body' unless work_body
# Set the frame values
if protocol11p
work_command.force_encoding(Stomp::UTF8) if work_command.respond_to?(:force_encoding)
end
self.command = work_command
work_headers.split("\n").map do |value|
fc = value.index(":")
raise Stomp::Error::InvalidFormat, 'parsed header value' unless fc
#
pk = value[0...fc]
pv = value[fc+1..-1]
#
if protocol11p
pk.force_encoding(Stomp::UTF8) if pk.respond_to?(:force_encoding)
pv.force_encoding(Stomp::UTF8) if pv.respond_to?(:force_encoding)
# Stomp 1.1+ - Servers may put multiple values for a single key on the wire.
# If so, we support reading those, and passing them to the user.
if self.headers[pk]
if self.headers[pk].is_a?(Array) # The 3rd and any subsequent ones for this key
self.headers[pk] << pv
else
# The 2nd one for this key
tv = self.headers[pk] + ""
self.headers[pk] = []
self.headers[pk] << tv << pv
end
else
self.headers[pk] = pv # The 1st one for this key
end
else
# Stomp 1.0
self.headers[pk.strip] = pv.strip unless self.headers[pk.strip] # Only receive the 1st one
end
end
raise Stomp::Error::ProtocolErrorEmptyHeaderKey if self.headers.has_key?("")
raise Stomp::Error::ProtocolErrorEmptyHeaderValue if (!protocol11p) && self.headers.has_value?("")
body_length = -1
if self.headers['content-length']
body_length = self.headers['content-length'].to_i
raise Stomp::Error::InvalidMessageLength if work_body.length != body_length
end
self.body = work_body[0..body_length]
end
# to_s returns a string prepresentation of this Message.
def to_s
""
end
# is_blank? tests if a data value is nil or empty.
def is_blank?(value)
value.nil? || (value.respond_to?(:empty?) && value.empty?)
end
# empty? tests if a Message has any blank parts.
def empty?
is_blank?(command) && is_blank?(headers) && is_blank?(body)
end
end # class Message
end # module Stomp
stomp-1.4.4/lib/stomp/constants.rb 0000644 0000041 0000041 00000014466 13120662775 017207 0 ustar www-data www-data # -*- encoding: utf-8 -*-
module Stomp
# Client generated frames
CMD_CONNECT = "CONNECT"
CMD_STOMP = "STOMP"
CMD_DISCONNECT = "DISCONNECT"
CMD_SEND = "SEND"
CMD_SUBSCRIBE = "SUBSCRIBE"
CMD_UNSUBSCRIBE = "UNSUBSCRIBE"
CMD_ACK = "ACK"
CMD_NACK = "NACK"
CMD_BEGIN = "BEGIN"
CMD_COMMIT = "COMMIT"
CMD_ABORT = "ABORT"
# Server generated names
CMD_CONNECTED = "CONNECTED"
CMD_MESSAGE = "MESSAGE"
CMD_RECEIPT = "RECEIPT"
CMD_ERROR = "ERROR"
# Protocols
SPL_10 = "1.0"
SPL_11 = "1.1"
SPL_12 = "1.2"
# Stomp 1.0 and 1.1 and 1.2
SUPPORTED = [SPL_10, SPL_11, SPL_12]
# UTF-8 Encoding Name
UTF8 = "UTF-8"
#
# Octet 0
#
NULL = "\0"
#
# New line
#
NL = "\n"
NL_ASCII = 0x0a
#
# Line Feed (New Line)
#
LF = "\n"
LF_ASCII = 0x0a
#
# New line
#
CR = "\r"
CR_ASCII = 0x0d
#
# Back Slash
#
BACK_SLASH = "\\"
BACK_SLASH_ASCII = 0x5c
#
# Literal colon
#
LITERAL_COLON = ":"
COLON_ASCII = 0x3a
#
# Literal letter c
#
LITERAL_C = "c"
C_ASCII = 0x63
#
# Literal letter n
#
LITERAL_N = "n"
N_ASCII = 0x6e
#
# Codec from/to values.
#
ENCODE_VALUES = [
"\\\\\\\\", "\\", # encoded, decoded
"\\" + "n", "\n",
"\\" + "r", "\r",
"\\c", ":",
]
#
DECODE_VALUES = [
"\\\\", "\\", # encoded, decoded
"\\" + "n", "\n",
"\\" + "r", "\r",
"\\c", ":",
]
# A fairly safe and generally supported ciphers list.
DEFAULT_CIPHERS = [
["AES128-GCM-SHA256","TLSv1/SSLv3",128,128],
["AES128-SHA256","TLSv1/SSLv3",128,128],
["AES128-SHA","TLSv1/SSLv3",128,128],
["AES256-GCM-SHA384","TLSv1/SSLv3",256,256],
["AES256-SHA256","TLSv1/SSLv3",256,256],
["AES256-SHA","TLSv1/SSLv3",256,256],
["CAMELLIA128-SHA","TLSv1/SSLv3",128,128],
["CAMELLIA256-SHA","TLSv1/SSLv3",256,256],
["DES-CBC3-SHA","TLSv1/SSLv3",168,168],
["DES-CBC-SHA","TLSv1/SSLv3",56,56],
["DHE-DSS-AES128-GCM-SHA256","TLSv1/SSLv3",128,128],
["DHE-DSS-AES128-SHA256","TLSv1/SSLv3",128,128],
["DHE-DSS-AES128-SHA","TLSv1/SSLv3",128,128],
["DHE-DSS-AES256-GCM-SHA384","TLSv1/SSLv3",256,256],
["DHE-DSS-AES256-SHA256","TLSv1/SSLv3",256,256],
["DHE-DSS-AES256-SHA","TLSv1/SSLv3",256,256],
["DHE-DSS-CAMELLIA128-SHA","TLSv1/SSLv3",128,128],
["DHE-DSS-CAMELLIA256-SHA","TLSv1/SSLv3",256,256],
["DHE-DSS-SEED-SHA","TLSv1/SSLv3",128,128],
["DHE-RSA-AES128-GCM-SHA256","TLSv1/SSLv3",128,128],
["DHE-RSA-AES128-SHA256","TLSv1/SSLv3",128,128],
["DHE-RSA-AES128-SHA","TLSv1/SSLv3",128,128],
["DHE-RSA-AES256-GCM-SHA384","TLSv1/SSLv3",256,256],
["DHE-RSA-AES256-SHA256","TLSv1/SSLv3",256,256],
["DHE-RSA-AES256-SHA","TLSv1/SSLv3",256,256],
["DHE-RSA-CAMELLIA128-SHA","TLSv1/SSLv3",128,128],
["DHE-RSA-CAMELLIA256-SHA","TLSv1/SSLv3",256,256],
["DHE-RSA-SEED-SHA","TLSv1/SSLv3",128,128],
["ECDH-ECDSA-AES128-GCM-SHA256","TLSv1/SSLv3",128,128],
["ECDH-ECDSA-AES128-SHA256","TLSv1/SSLv3",128,128],
["ECDH-ECDSA-AES128-SHA","TLSv1/SSLv3",128,128],
["ECDH-ECDSA-AES256-GCM-SHA384","TLSv1/SSLv3",256,256],
["ECDH-ECDSA-AES256-SHA384","TLSv1/SSLv3",256,256],
["ECDH-ECDSA-AES256-SHA","TLSv1/SSLv3",256,256],
["ECDH-ECDSA-DES-CBC3-SHA","TLSv1/SSLv3",168,168],
["ECDH-ECDSA-RC4-SHA","TLSv1/SSLv3",128,128],
["ECDHE-ECDSA-AES128-GCM-SHA256","TLSv1/SSLv3",128,128],
["ECDHE-ECDSA-AES128-SHA256","TLSv1/SSLv3",128,128],
["ECDHE-ECDSA-AES128-SHA","TLSv1/SSLv3",128,128],
["ECDHE-ECDSA-AES256-GCM-SHA384","TLSv1/SSLv3",256,256],
["ECDHE-ECDSA-AES256-SHA384","TLSv1/SSLv3",256,256],
["ECDHE-ECDSA-AES256-SHA","TLSv1/SSLv3",256,256],
["ECDHE-ECDSA-DES-CBC3-SHA","TLSv1/SSLv3",168,168],
["ECDHE-ECDSA-RC4-SHA","TLSv1/SSLv3",128,128],
["ECDHE-RSA-AES128-GCM-SHA256","TLSv1/SSLv3",128,128],
["ECDHE-RSA-AES128-SHA256","TLSv1/SSLv3",128,128],
["ECDHE-RSA-AES128-SHA","TLSv1/SSLv3",128,128],
["ECDHE-RSA-AES256-GCM-SHA384","TLSv1/SSLv3",256,256],
["ECDHE-RSA-AES256-SHA384","TLSv1/SSLv3",256,256],
["ECDHE-RSA-AES256-SHA","TLSv1/SSLv3",256,256],
["ECDHE-RSA-DES-CBC3-SHA","TLSv1/SSLv3",168,168],
["ECDHE-RSA-RC4-SHA","TLSv1/SSLv3",128,128],
["ECDH-RSA-AES128-GCM-SHA256","TLSv1/SSLv3",128,128],
["ECDH-RSA-AES128-SHA256","TLSv1/SSLv3",128,128],
["ECDH-RSA-AES128-SHA","TLSv1/SSLv3",128,128],
["ECDH-RSA-AES256-GCM-SHA384","TLSv1/SSLv3",256,256],
["ECDH-RSA-AES256-SHA384","TLSv1/SSLv3",256,256],
["ECDH-RSA-AES256-SHA","TLSv1/SSLv3",256,256],
["ECDH-RSA-DES-CBC3-SHA","TLSv1/SSLv3",168,168],
["ECDH-RSA-RC4-SHA","TLSv1/SSLv3",128,128],
["EDH-DSS-DES-CBC3-SHA","TLSv1/SSLv3",168,168],
["EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56],
["EDH-DSS-DES-CBC-SHA","TLSv1/SSLv3",56,56],
["EDH-RSA-DES-CBC3-SHA","TLSv1/SSLv3",168,168],
["EDH-RSA-DES-CBC-SHA","TLSv1/SSLv3",56,56],
["EXP-DES-CBC-SHA","TLSv1/SSLv3",40,56],
["EXP-EDH-DSS-DES-CBC-SHA","TLSv1/SSLv3",40,56],
["EXP-EDH-RSA-DES-CBC-SHA","TLSv1/SSLv3",40,56],
["EXP-RC2-CBC-MD5","TLSv1/SSLv3",40,128],
["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128],
["PSK-3DES-EDE-CBC-SHA","TLSv1/SSLv3",168,168],
["PSK-AES128-CBC-SHA","TLSv1/SSLv3",128,128],
["PSK-AES256-CBC-SHA","TLSv1/SSLv3",256,256],
["PSK-RC4-SHA","TLSv1/SSLv3",128,128],
["RC4-MD5","TLSv1/SSLv3",128,128],
["RC4-SHA","TLSv1/SSLv3",128,128],
["SEED-SHA","TLSv1/SSLv3",128,128],
["SRP-DSS-3DES-EDE-CBC-SHA","TLSv1/SSLv3",168,168],
["SRP-DSS-AES-128-CBC-SHA","TLSv1/SSLv3",128,128],
["SRP-DSS-AES-256-CBC-SHA","TLSv1/SSLv3",256,256],
["SRP-RSA-3DES-EDE-CBC-SHA","TLSv1/SSLv3",168,168],
["SRP-RSA-AES-128-CBC-SHA","TLSv1/SSLv3",128,128],
["SRP-RSA-AES-256-CBC-SHA","TLSv1/SSLv3",256,256],
]
HAND_SHAKE_DATA = "\x15\x03\x03\x00\x02\x02\n"
original_verbose, $VERBOSE = $VERBOSE, nil # try to shut off warnings
# stomp URL regex pattern, for e.g. login:passcode@host:port or host:port
URL_REPAT = '((([\w~!@#$%^&*()\-+=.?:<>,.]*\w):([\w~!@#$%^&*()\-+=.?:<>,.]*))?@)?([\w\.\-]+):(\d+)'
# Failover URL regex, for e.g.
#failover:(stomp+ssl://login1:passcode1@remotehost1:61612,stomp://login2:passcode2@remotehost2:61613)
FAILOVER_REGEX = /^failover:(\/\/)?\(stomp(\+ssl)?:\/\/#{URL_REPAT}(,stomp(\+ssl)?:\/\/#{URL_REPAT})*\)(\?(.*))?$/
$VERBOSE = original_verbose
end # Module Stomp
stomp-1.4.4/lib/stomp/ext/ 0000755 0000041 0000041 00000000000 13120662775 015433 5 ustar www-data www-data stomp-1.4.4/lib/stomp/ext/hash.rb 0000644 0000041 0000041 00000001343 13120662775 016704 0 ustar www-data www-data # -*- encoding: utf-8 -*-
class ::Hash
# Returns self with keys uncamelized and converted to symbols.
def uncamelize_and_symbolize_keys
self.uncamelize_and_stringify_keys.symbolize_keys
end
# Returns self with keys uncamelized and converted to strings.
def uncamelize_and_stringify_keys
uncamelized = {}
self.each_pair do |key, value|
new_key = key.to_s.split(/(?=[A-Z])/).join('_').downcase
uncamelized[new_key] = value
end
uncamelized
end
# Returns self with all keys symbolized.
def symbolize_keys
symbolized = {}
self.each_pair do |key, value|
symbolized[key.to_sym] = value
end
symbolized
end unless self.method_defined?(:symbolize_keys)
end # class Hash
stomp-1.4.4/lib/stomp/null_logger.rb 0000644 0000041 0000041 00000001772 13120662775 017500 0 ustar www-data www-data # -*- encoding: utf-8 -*-
module Stomp
class NullLogger
def on_miscerr(parms, error_msg)
$stderr.print "\non_miscerr\n"
$stderr.print parms.inspect
$stderr.print "\n"
$stderr.print error_msg
$stderr.print "\n"
end
def on_connecting(parms); end
def on_connected(parms); end
def on_connectfail(parms); end
def on_disconnect(parms); end
def on_subscribe(parms, headers); end
def on_unsubscribe(parms, headers); end
def on_publish(parms, message, headers); end
def on_receive(parms, result); end
def on_begin(parms, headers); end
def on_ack(parms, headers); end
def on_nack(parms, headers); end
def on_commit(parms, headers); end
def on_abort(parms, headers); end
def on_hbread_fail(parms, ticker_data); end
def on_hbwrite_fail(parms, ticker_data); end
def on_ssl_connecting(parms); end
def on_ssl_connected(parms); end
def on_ssl_connectfail(parms); end
def on_hbfire(parms, srind, curt); end
end
end
stomp-1.4.4/lib/connection/ 0000755 0000041 0000041 00000000000 13120662775 015630 5 ustar www-data www-data stomp-1.4.4/lib/connection/utils.rb 0000644 0000041 0000041 00000022343 13120662775 017321 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'socket'
require 'timeout'
require 'io/wait'
require 'digest/sha1'
module Stomp
class Connection
private
# Support multi-homed servers.
def _expand_hosts(hash)
new_hash = hash.clone
new_hash[:hosts_cloned] = hash[:hosts].clone
new_hash[:hosts] = []
#
hash[:hosts].each do |host_parms|
ai = Socket.getaddrinfo(host_parms[:host], nil, nil, Socket::SOCK_STREAM)
next if ai.nil? || ai.size == 0
info6 = ai.detect {|info| info[4] == Socket::AF_INET6}
info4 = ai.detect {|info| info[4] == Socket::AF_INET}
if info6
new_hostp = host_parms.clone
new_hostp[:host] = info6[3]
new_hash[:hosts] << new_hostp
end
if info4
new_hostp = host_parms.clone
new_hostp[:host] = info4[3]
new_hash[:hosts] << new_hostp
end
end
return new_hash
end
# Handle 1.9+ character representation.
def parse_char(char)
RUBY_VERSION > '1.9' ? char : char.chr
end
# Create parameters for any callback logger.
def log_params()
lparms = @parameters.clone if @parameters
lparms = {} unless lparms
lparms[:cur_host] = @host
lparms[:cur_port] = @port
lparms[:cur_login] = @login
lparms[:cur_passcode] = @passcode
lparms[:cur_ssl] = @ssl
lparms[:cur_recondelay] = @reconnect_delay
lparms[:cur_parseto] = @parse_timeout
lparms[:cur_conattempts] = @connection_attempts
lparms[:cur_failure] = @failure # To assist in debugging
lparms[:openstat] = open?
#
lparms
end
# _pre_connect handles low level logic just prior to a physical connect.
def _pre_connect()
@connect_headers = @connect_headers.symbolize_keys
raise Stomp::Error::ProtocolErrorConnect if (@connect_headers[:"accept-version"] && !@connect_headers[:host])
raise Stomp::Error::ProtocolErrorConnect if (!@connect_headers[:"accept-version"] && @connect_headers[:host])
return unless (@connect_headers[:"accept-version"] && @connect_headers[:host]) # 1.0
# Try 1.1 or greater
@hhas10 = false
okvers = []
avers = @connect_headers[:"accept-version"].split(",")
avers.each do |nver|
if Stomp::SUPPORTED.index(nver)
okvers << nver
@hhas10 = true if nver == Stomp::SPL_10
end
end
raise Stomp::Error::UnsupportedProtocolError if okvers == []
@connect_headers[:"accept-version"] = okvers.join(",") # This goes to server
# Heartbeats - pre connect
return unless @connect_headers[:"heart-beat"]
_validate_hbheader()
end
# _post_connect handles low level logic just after a physical connect.
def _post_connect()
return unless (@connect_headers[:"accept-version"] && @connect_headers[:host]) # 1.0
if @connection_frame.command == Stomp::CMD_ERROR
@connection_frame.headers = _decodeHeaders(@connection_frame.headers)
return
end
# We are CONNECTed
cfh = @connection_frame.headers.symbolize_keys
@protocol = cfh[:version]
if @protocol
# Should not happen, but check anyway
raise Stomp::Error::UnsupportedProtocolError unless Stomp::SUPPORTED.index(@protocol)
else # CONNECTed to a 1.0 server that does not return *any* 1.1 type headers
@protocol = Stomp::SPL_10 # reset
return
end
# Heartbeats
return unless @connect_headers[:"heart-beat"]
_init_heartbeats()
end
# socket creates and returns a new socket for use by the connection.
def socket()
@socket_semaphore.synchronize do
used_socket = @socket
used_socket = nil if closed?
while used_socket.nil? || !@failure.nil?
@failure = nil
begin
used_socket = open_socket() # sets @closed = false if OK
# Open is complete
connect(used_socket)
slog(:on_connected, log_params)
@connection_attempts = 0
rescue
@failure = $!
used_socket = nil
@closed = true
raise unless @reliable
raise if @failure.is_a?(Stomp::Error::LoggerConnectionError)
# Catch errors which are:
# a) emitted from corrupted 1.1+ 'connect' (caller programming error)
# b) should never be retried
raise if @failure.is_a?(Stomp::Error::ProtocolError11p)
begin
unless slog(:on_connectfail,log_params)
$stderr.print "connect to #{@host} failed: #{$!} will retry(##{@connection_attempts}) in #{@reconnect_delay}\n"
end
rescue Exception => aex
raise if aex.is_a?(Stomp::Error::LoggerConnectionError)
end
if max_reconnect_attempts?
$stderr.print "In socket() Reached MaxReconnectAttempts"
### _dump_threads()
mt = @parameters[:client_main]
if !mt.nil?
mt.raise Stomp::Error::MaxReconnectAttempts
Thread::exit
end
raise Stomp::Error::MaxReconnectAttempts
end
sleep(@reconnect_delay)
@connection_attempts += 1
if @parameters
change_host()
increase_reconnect_delay()
end
end
end
@socket = used_socket
end
end
# refine_params sets up defaults for a Hash initialize.
def refine_params(params)
params = params.uncamelize_and_symbolize_keys
default_params = {
:connect_headers => {},
:reliable => true,
# Failover parameters
:initial_reconnect_delay => 0.01,
:max_reconnect_delay => 30.0,
:use_exponential_back_off => true,
:back_off_multiplier => 2,
:max_reconnect_attempts => 0,
:randomize => false,
:connect_timeout => 0,
# Parse Timeout
:parse_timeout => 5,
:dmh => false,
# Closed check logic
:closed_check => true,
:hbser => false,
:stompconn => false,
:max_hbread_fails => 0,
:max_hbrlck_fails => 0,
:fast_hbs_adjust => 0.0,
:connread_timeout => 0,
:tcp_nodelay => true,
:start_timeout => 0,
:sslctx_newparm => nil,
:ssl_post_conn_check => true,
}
res_params = default_params.merge(params)
if res_params[:dmh]
res_params = _expand_hosts(res_params)
end
return res_params
end
# change_host selects the next host for retries.
def change_host
@parameters[:hosts] = @parameters[:hosts].sort_by { rand } if @parameters[:randomize]
# Set first as master and send it to the end of array
current_host = @parameters[:hosts].shift
@parameters[:hosts] << current_host
@ssl = current_host[:ssl]
@host = current_host[:host]
@port = current_host[:port] || Connection::default_port(@ssl)
@login = current_host[:login] || ""
@passcode = current_host[:passcode] || ""
end
# Duplicate parameters hash
def _hdup(h)
ldup = {}
ldup.merge!(h)
ldup[:hosts] = []
hvals = h[:hosts].nil? ? h["hosts"] : h[:hosts]
hvals.each do |hv|
ldup[:hosts] << hv.dup
end
ldup
end
# max_reconnect_attempts? returns nil or the number of maximum reconnect
# attempts.
def max_reconnect_attempts?
!(@parameters.nil? || @parameters[:max_reconnect_attempts].nil?) && @parameters[:max_reconnect_attempts] != 0 && @connection_attempts >= @parameters[:max_reconnect_attempts]
end
# increase_reconnect_delay increases the reconnect delay for the next connection
# attempt.
def increase_reconnect_delay
@reconnect_delay *= @parameters[:back_off_multiplier] if @parameters[:use_exponential_back_off]
@reconnect_delay = @parameters[:max_reconnect_delay] if @reconnect_delay > @parameters[:max_reconnect_delay]
@reconnect_delay
end
# __old_receive receives a frame, blocks until the frame is received.
def __old_receive()
# The receive may fail so we may need to retry.
while true
begin
used_socket = socket()
return _receive(used_socket)
rescue Stomp::Error::MaxReconnectAttempts
unless slog(:on_miscerr, log_params, "Reached MaxReconnectAttempts")
$stderr.print "Reached MaxReconnectAttempts\n"
end
raise
rescue
@failure = $!
raise unless @reliable
errstr = "receive failed: #{$!}"
unless slog(:on_miscerr, log_params, "es1_oldrecv: " + errstr)
$stderr.print "\non_miscerr\n"
$stderr.print log_params.inspect
$stderr.print "\n"
$stderr.print "es2_oldrecv: " + errstr
$stderr.print "\n"
end
# !!! This initiates a re-connect !!!
_reconn_prep()
end
end
end
# _reconn_prep prepares for a reconnect retry
def _reconn_prep()
close_socket()
if @parameters
change_host()
end
@st.kill if @st # Kill ticker thread if any
@rt.kill if @rt # Kill ticker thread if any
@socket = nil
end
end # class Connection
end # module Stomp
stomp-1.4.4/lib/connection/netio.rb 0000644 0000041 0000041 00000047172 13120662775 017306 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'socket'
require 'timeout'
require 'io/wait'
require 'digest/sha1'
module Stomp
class Connection
def _interruptible_gets(read_socket)
# The gets thread may be interrupted by the heartbeat thread. Ensure that
# if so interrupted, a new gets cannot start until after the heartbeat
# thread finishes its work. This is PURELY to avoid a segfault bug
# involving OpenSSL::Buffer.
@gets_semaphore.synchronize { @getst = Thread.current }
read_socket.gets
ensure
@gets_semaphore.synchronize { @getst = nil }
end
private
# Really read from the wire.
def _receive(read_socket, connread = false)
# p [ "ioscheck", @iosto, connread ]
# _dump_callstack()
# drdbg = true
drdbg = false
@read_semaphore.synchronize do
line = nil
if connread
begin
Timeout::timeout(@connread_timeout, Stomp::Error::ConnectReadTimeout) do
line = _init_line_read(read_socket)
end
rescue Stomp::Error::ConnectReadTimeout => ex
if @reliable
_reconn_prep()
end
raise ex
end
else
p [ "CONR01" ] if drdbg
_dump_callstack() if drdbg
line = _init_line_read(read_socket)
end
#
p [ "nilcheck", line.nil? ] if drdbg
return nil if line.nil?
#An extra \n at the beginning of the frame, possibly not caught by is_ready?
line = '' if line == "\n"
if line == HAND_SHAKE_DATA
raise Stomp::Error::HandShakeDetectedError
end
p [ "wiredatain_01A", line, Time.now ] if drdbg
line = _normalize_line_end(line) if @protocol >= Stomp::SPL_12
p [ "wiredatain_01B", line, Time.now ] if drdbg
# Reads the beginning of the message until it runs into a empty line
message_header = ''
begin
message_header += line
p [ "wiredatain_02A", line, Time.now ] if drdbg
unless connread || @ssl
raise Stomp::Error::ReceiveTimeout unless IO.select([read_socket], nil, nil, @iosto)
end
p [ "wiredatain_02B", line, Time.now ] if drdbg
line = _interruptible_gets(read_socket)
p [ "wiredatain_02C", line ] if drdbg
raise if line.nil?
line = _normalize_line_end(line) if @protocol >= Stomp::SPL_12
p [ "wiredatain_02D", line ] if drdbg
end until line =~ /^\s?\n$/
p [ "wiredatain_03A" ] if drdbg
# Checks if it includes content_length header
content_length = message_header.match(/content-length\s?:\s?(\d+)\s?\n/)
message_body = ''
p [ "wiredatain_03B", content_length ] if drdbg
# If content_length is present, read the specified amount of bytes
if content_length
unless connread || @ssl
raise Stomp::Error::ReceiveTimeout unless IO.select([read_socket], nil, nil, @iosto)
end
p [ "CL01" ] if drdbg
message_body = read_socket.read content_length[1].to_i
unless connread || @ssl
raise Stomp::Error::ReceiveTimeout unless IO.select([read_socket], nil, nil, @iosto)
end
raise Stomp::Error::InvalidMessageLength unless parse_char(read_socket.getc) == "\0"
# Else read the rest of the message until the first \0
else
unless connread || @ssl
raise Stomp::Error::ReceiveTimeout unless IO.select([read_socket], nil, nil, @iosto)
end
p [ "NOCL01" ] if drdbg
message_body = read_socket.readline("\0")
message_body.chop!
end
p [ "wiredatain_04" ] if drdbg
# If the buffer isn't empty, reads trailing new lines.
#
# Note: experiments with JRuby seem to show that socket.ready? never
# returns true. It appears that in cases where Ruby returns true
# that JRuby returns a Fixnum. We attempt to adjust for this
# in the _is_ready? method.
#
# Note 2: the draining of new lines must be done _after_ a message
# is read. Do _not_ leave them on the wire and attempt to drain them
# at the start of the next read. Attempting to do that breaks the
# asynchronous nature of the 'poll' method.
p [ "wiredatain_05_prep", "isr", _is_ready?(read_socket) ] if drdbg
while _is_ready?(read_socket)
unless connread || @ssl
raise Stomp::Error::ReceiveTimeout unless IO.select([read_socket], nil, nil, @iosto)
end
p [ "WHIR01" ] if drdbg
last_char = read_socket.getc
break unless last_char
if parse_char(last_char) != "\n"
read_socket.ungetc(last_char)
break
end
end
p [ "wiredatain_05A" ] if drdbg
if @protocol >= Stomp::SPL_11
@lr = Time.now.to_f if @hbr
end
# Adds the excluded \n and \0 and tries to create a new message with it
p [ "wiredatain_05B" ] if drdbg
msg = Message.new(message_header + "\n" + message_body + "\0", @protocol >= Stomp::SPL_11)
p [ "wiredatain_06", msg.command, msg.headers ] if drdbg
#
if @protocol >= Stomp::SPL_11 && msg.command != Stomp::CMD_CONNECTED
msg.headers = _decodeHeaders(msg.headers)
end
p [ "wiredatain_99", msg.command, msg.headers ] if drdbg
msg
end
end
#
# This is a total hack, to try and guess how JRuby will behave today.
#
def _is_ready?(s)
rdy = s.ready?
### p [ "isr?", rdy ]
return rdy unless @jruby
### p [ "jrdychk", rdy.class ]
if rdy.class == NilClass
# rdy = true
rdy = false # A test
else
rdy = (rdy.class == Fixnum || rdy.class == TrueClass) ? true : false
end
### p [ "isr?_last", rdy ]
rdy
end
# Normalize line ends because 1.2+ brokers can send 'mixed mode' headers, i.e.:
# - Some headers end with '\n'
# - Other headers end with '\r\n'
def _normalize_line_end(line)
return line unless @usecrlf
# p [ "nleln", line ]
line_len = line.respond_to?(:bytesize) ? line.bytesize : line.length
last2 = line[line_len-2...line_len]
# p [ "nlel2", last2 ]
return line unless last2 == "\r\n"
return line[0...line_len-2] + "\n"
end
# transmit logically puts a Message on the wire.
def transmit(command, headers = {}, body = '')
# The transmit may fail so we may need to retry.
while true
begin
used_socket = socket()
_transmit(used_socket, command, headers, body)
return
rescue Stomp::Error::MaxReconnectAttempts => e
_ = e
raise
rescue
@failure = $!
raise unless @reliable
errstr = "transmit to #{@host} failed: #{$!}\n"
unless slog(:on_miscerr, log_params, "es_trans: " + errstr)
$stderr.print errstr
end
# !!! This loop initiates a re-connect !!!
_reconn_prep()
end
end
end
# _transmit is the real wire write logic.
def _transmit(used_socket, command, headers = {}, body = '')
# p [ "wirewrite" ]
# _dump_callstack()
if @protocol >= Stomp::SPL_11 && command != Stomp::CMD_CONNECT
headers = _encodeHeaders(headers)
end
@transmit_semaphore.synchronize do
# Handle nil body
body = '' if body.nil?
# The content-length should be expressed in bytes.
# Ruby 1.8: String#length => # of bytes; Ruby 1.9: String#length => # of characters
# With Unicode strings, # of bytes != # of characters. So, use String#bytesize when available.
body_length_bytes = body.respond_to?(:bytesize) ? body.bytesize : body.length
# ActiveMQ interprets every message as a BinaryMessage
# if content_length header is included.
# Using :suppress_content_length => true will suppress this behaviour
# and ActiveMQ will interpret the message as a TextMessage.
# For more information refer to http://juretta.com/log/2009/05/24/activemq-jms-stomp/
# Lets send this header in the message, so it can maintain state when using unreceive
headers[:'content-length'] = "#{body_length_bytes}" unless headers[:suppress_content_length]
headers[:'content-type'] = "text/plain; charset=UTF-8" unless headers[:'content-type'] || headers[:suppress_content_type]
_wire_write(used_socket,command)
headers.each do |k,v|
if v.is_a?(Array)
v.each do |e|
_wire_write(used_socket,"#{k}:#{e}")
end
else
_wire_write(used_socket,"#{k}:#{v}")
end
end
_wire_write(used_socket,"")
if body != ''
if headers[:suppress_content_length]
if tz = body.index("\00")
used_socket.write body[0..tz-1]
else
used_socket.write body
end
else
used_socket.write body
end
end
used_socket.write "\0"
used_socket.flush if autoflush
if @protocol >= Stomp::SPL_11
@ls = Time.now.to_f if @hbs
end
end
end
# Use CRLF if protocol is >= 1.2, and the client requested CRLF
def _wire_write(sock, data)
# p [ "debug_01", @protocol, @usecrlf ]
if @protocol >= Stomp::SPL_12 && @usecrlf
wiredata = "#{data}#{Stomp::CR}#{Stomp::LF}"
# p [ "wiredataout_01:", wiredata ]
sock.write(wiredata)
else
# p [ "wiredataout_02:", "#{data}\n" ]
sock.puts data
end
end
# open_tcp_socket opens a TCP socket.
def open_tcp_socket()
## $stderr.print("h: #{@host}, p: #{@port}\n")
tcp_socket = nil
slog(:on_connecting, log_params)
Timeout::timeout(@connect_timeout, Stomp::Error::SocketOpenTimeout) do
tcp_socket = TCPSocket.open(@host, @port)
end
tcp_socket
end
# open_ssl_socket opens an SSL socket.
def open_ssl_socket()
require 'openssl' unless defined?(OpenSSL)
begin # Any raised SSL exceptions
ctx = @sslctx_newparm ? OpenSSL::SSL::SSLContext.new(@sslctx_newparm) : OpenSSL::SSL::SSLContext.new
ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE # Assume for now
#
# Note: if a client uses :ssl => true this would result in the gem using
# the _default_ Ruby ciphers list. This is _known_ to fail in later
# Ruby releases. The gem now detects :ssl => true, and replaces that
# with:
# * :ssl => Stomp::SSLParams.new
#
# The above results in the use of Stomp default parameters.
#
# To specifically request Stomp default parameters, use:
# * :ssl => Stomp::SSLParams.new(..., :ciphers => Stomp::DEFAULT_CIPHERS)
#
# If connecting with an SSLParams instance, and the _default_ Ruby
# ciphers list is actually required, use:
# * :ssl => Stomp::SSLParams.new(..., :use_ruby_ciphers => true)
#
# If a custom ciphers list is required, connect with:
# * :ssl => Stomp::SSLParams.new(..., :ciphers => custom_ciphers_list)
#
if @ssl != true
#
# Here @ssl is:
# * an instance of Stomp::SSLParams
# Control would not be here if @ssl == false or @ssl.nil?.
#
# Back reference the SSLContext
@ssl.ctx = ctx
# Server authentication parameters if required
if @ssl.ts_files
ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
truststores = OpenSSL::X509::Store.new
fl = @ssl.ts_files.split(",")
fl.each do |fn|
# Add next cert file listed
raise Stomp::Error::SSLNoTruststoreFileError if !File::exists?(fn)
raise Stomp::Error::SSLUnreadableTruststoreFileError if !File::readable?(fn)
truststores.add_file(fn)
end
ctx.cert_store = truststores
end
# Client authentication parameters.
# Both cert file and key file must be present or not, it can not be a mix.
raise Stomp::Error::SSLClientParamsError if @ssl.cert_file.nil? && !@ssl.key_file.nil?
raise Stomp::Error::SSLClientParamsError if !@ssl.cert_file.nil? && @ssl.key_file.nil?
if @ssl.cert_file # Any check will do here
raise Stomp::Error::SSLNoCertFileError if !File::exists?(@ssl.cert_file)
raise Stomp::Error::SSLUnreadableCertFileError if !File::readable?(@ssl.cert_file)
ctx.cert = OpenSSL::X509::Certificate.new(File.read(@ssl.cert_file))
raise Stomp::Error::SSLNoKeyFileError if !File::exists?(@ssl.key_file)
raise Stomp::Error::SSLUnreadableKeyFileError if !File::readable?(@ssl.key_file)
ctx.key = OpenSSL::PKey::RSA.new(File.read(@ssl.key_file), @ssl.key_password)
end
# Cipher list
# As of this writing, there are numerous problems with supplying
# cipher lists to jruby. So we do not attempt to do that here.
if !@ssl.use_ruby_ciphers # No Ruby ciphers (the default)
if @ssl.ciphers # User ciphers list?
ctx.ciphers = @ssl.ciphers # Accept user supplied ciphers
else
ctx.ciphers = Stomp::DEFAULT_CIPHERS # Just use Stomp defaults
end
end unless @jruby
# Set SSLContext Options if user asks for it in Stomp::SSLParams
# and SSL supports it.
if @ssl.ssl_ctxopts && ctx.respond_to?(:options=)
ctx.options = @ssl.ssl_ctxopts
end
end
#
ssl = nil
slog(:on_ssl_connecting, log_params)
# _dump_ctx(ctx)
Timeout::timeout(@connect_timeout, Stomp::Error::SocketOpenTimeout) do
tcp_socket = TCPSocket.open(@host, @port)
ssl = OpenSSL::SSL::SSLSocket.new(tcp_socket, ctx)
ssl.hostname = @host if ssl.respond_to? :hostname=
ssl.sync_close = true # Sync ssl close with underlying TCP socket
ssl.connect
if (ssl.context.verify_mode != OpenSSL::SSL::VERIFY_NONE) && @ssl_post_conn_check
ssl.post_connection_check(@host)
end
end
def ssl.ready?
! @rbuffer.empty? || @io.ready?
end
if @ssl != true
# Pass back results if possible
if RUBY_VERSION =~ /1\.8\.[56]/
@ssl.verify_result = "N/A for Ruby #{RUBY_VERSION}"
else
@ssl.verify_result = ssl.verify_result
end
@ssl.peer_cert = ssl.peer_cert
end
slog(:on_ssl_connected, log_params)
ssl
rescue Exception => ex
lp = log_params.clone
lp[:ssl_exception] = ex
slog(:on_ssl_connectfail, lp)
if ssl
# shut down the TCP socket - we just failed to do the SSL handshake in time
ssl.close
end
#
puts ex.backtrace
$stdout.flush
raise # Reraise
end
end
# close_socket closes the current open socket, and hence the connection.
def close_socket()
begin
# Need to set @closed = true before closing the socket
# within the @read_semaphore thread
@closed = true
@read_semaphore.synchronize do
@socket.close
end
rescue
#Ignoring if already closed
end
@closed
end
# open_socket opens a TCP or SSL soclet as required.
def open_socket()
used_socket = @ssl ? open_ssl_socket : open_tcp_socket
# try to close the old connection if any
close_socket
@closed = false
if @parameters # nil in some rspec tests
unless @reconnect_delay
@reconnect_delay = @parameters[:initial_reconnect_delay] || iosto1
end
end
# Use keepalive
used_socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true)
# TCP_NODELAY option (disables Nagle's algorithm)
used_socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, !!(@parameters && @parameters[:tcp_nodelay]))
@iosto = @parse_timeout ? @parse_timeout.to_f : 0.0
used_socket
end
# connect performs a basic STOMP CONNECT operation.
def connect(used_socket)
@connect_headers = {} unless @connect_headers # Caller said nil/false
headers = @connect_headers.clone
headers[:login] = @login unless @login.to_s.empty?
headers[:passcode] = @passcode unless @login.to_s.empty?
_pre_connect
if !@hhas10 && @stompconn
_transmit(used_socket, Stomp::CMD_STOMP, headers)
else
_transmit(used_socket, Stomp::CMD_CONNECT, headers)
end
@connection_frame = _receive(used_socket, true)
_post_connect
@disconnect_receipt = nil
@session = @connection_frame.headers["session"] if @connection_frame
# replay any subscriptions.
@subscriptions.each {|k,v|
_transmit(used_socket, Stomp::CMD_SUBSCRIBE, v)
}
end
def _init_line_read(read_socket)
line = ''
if @protocol == Stomp::SPL_10 || (@protocol >= Stomp::SPL_11 && !@hbr)
if @jruby
# Handle JRuby specific behavior.
### p [ "ilrjr00", _is_ready?(read_socket), RUBY_VERSION ]
if RUBY_VERSION < "2"
while true
### p [ "ilrjr01A1", _is_ready?(read_socket) ]
line = _interruptible_gets(read_socket) # Data from wire
break unless line == "\n"
line = ''
end
else # RUBY_VERSION >= "2"
while _is_ready?(read_socket)
### p [ "ilrjr01B2", _is_ready?(read_socket) ]
line = _interruptible_gets(read_socket) # Data from wire
break unless line == "\n"
line = ''
end
end
else
line = _interruptible_gets(read_socket) # The old way
end
else # We are >= 1.1 *AND* receiving heartbeats.
while true
line = _interruptible_gets(read_socket) # Data from wire
break unless line == "\n"
line = ''
@lr = Time.now.to_f
end
end
line
end
# Used for debugging
def _dump_ctx(ctx)
p [ "dc01", ctx.inspect ]
p [ "dc02ciphers", ctx.ciphers ]
end
# used for debugging
def _dump_callstack()
i = 0
caller.each do |c|
p [ "csn", i, c ]
i += 1
end
end # _dump_callstack
# used for debugging
def _dump_threads()
tl = Thread::list
tl.each do |at|
p [ "THDMPN", at ]
end
p [ "THDMPMain", @parameters[:client_main] ]
end
end # class Connection
end # module Stomp
stomp-1.4.4/lib/connection/utf8.rb 0000644 0000041 0000041 00000021050 13120662775 017041 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'socket'
require 'timeout'
require 'io/wait'
require 'digest/sha1'
module Stomp
class Connection
private
# Ref:
# http://unicode.org/mail-arch/unicode-ml/y2003-m02/att-0467/01-The_Algorithm_to_Valide_an_UTF-8_String
#
# *CONSIDER* replacing this with a dependency on the utf8_validator gem.
# This code has been copied from there.
#
def _valid_utf8?(string)
case RUBY_VERSION
when /1\.8\.[56]/
bytes = []
0.upto(string.length-1) {|i|
bytes << string[i]
}
else
bytes = string.bytes
end
#
valid = true
index = -1
nb_hex = nil
ni_hex = nil
state = "start"
next_byte_save = nil
#
bytes.each do |next_byte|
index += 1
next_byte_save = next_byte
ni_hex = sprintf "%x", index
nb_hex = sprintf "%x", next_byte
# puts "Top: #{next_byte}(0x#{nb_hex}), index: #{index}(0x#{ni_hex})" if DEBUG
case state
# State: 'start'
# The 'start' state:
# * handles all occurrences of valid single byte characters i.e., the ASCII character set
# * provides state transition logic for start bytes of valid characters with 2-4 bytes
# * signals a validation failure for all other single bytes
#
when "start"
# puts "state: start" if DEBUG
case next_byte
# ASCII
# * Input = 0x00-0x7F : change state to START
when (0x00..0x7f)
# puts "state: start 1" if DEBUG
state = "start"
# Start byte of two byte characters
# * Input = 0xC2-0xDF: change state to A
when (0xc2..0xdf)
# puts "state: start 2" if DEBUG
state = "a"
# Start byte of some three byte characters
# * Input = 0xE1-0xEC, 0xEE-0xEF: change state to B
when (0xe1..0xec)
# puts "state: start 3" if DEBUG
state = "b"
when (0xee..0xef)
# puts "state: start 4" if DEBUG
state = "b"
# Start byte of special three byte characters
# * Input = 0xE0: change state to C
when 0xe0
# puts "state: start 5" if DEBUG
state = "c"
# Start byte of the remaining three byte characters
# * Input = 0xED: change state to D
when 0xed
# puts "state: start 6" if DEBUG
state = "d"
# Start byte of some four byte characters
# * Input = 0xF1-0xF3:change state to E
when (0xf1..0xf3)
# puts "state: start 7" if DEBUG
state = "e"
# Start byte of special four byte characters
# * Input = 0xF0: change state to F
when 0xf0
# puts "state: start 8" if DEBUG
state = "f"
# Start byte of very special four byte characters
# * Input = 0xF4: change state to G
when 0xf4
# puts "state: start 9" if DEBUG
state = "g"
# All other single characters are invalid
# * Input = Others (0x80-0xBF,0xC0-0xC1, 0xF5-0xFF): ERROR
else
valid = false
break
end # of the inner case, the 'start' state
# The last continuation byte of a 2, 3, or 4 byte character
# State: 'a'
# o Input = 0x80-0xBF: change state to START
# o Others: ERROR
when "a"
# puts "state: a" if DEBUG
if (0x80..0xbf) === next_byte
state = "start"
else
valid = false
break
end
# The first continuation byte for most 3 byte characters
# (those with start bytes in: 0xe1-0xec or 0xee-0xef)
# State: 'b'
# o Input = 0x80-0xBF: change state to A
# o Others: ERROR
when "b"
# puts "state: b" if DEBUG
if (0x80..0xbf) === next_byte
state = "a"
else
valid = false
break
end
# The first continuation byte for some special 3 byte characters
# (those with start byte 0xe0)
# State: 'c'
# o Input = 0xA0-0xBF: change state to A
# o Others: ERROR
when "c"
# puts "state: c" if DEBUG
if (0xa0..0xbf) === next_byte
state = "a"
else
valid = false
break
end
# The first continuation byte for the remaining 3 byte characters
# (those with start byte 0xed)
# State: 'd'
# o Input = 0x80-0x9F: change state to A
# o Others: ERROR
when "d"
# puts "state: d" if DEBUG
if (0x80..0x9f) === next_byte
state = "a"
else
valid = false
break
end
# The first continuation byte for some 4 byte characters
# (those with start bytes in: 0xf1-0xf3)
# State: 'e'
# o Input = 0x80-0xBF: change state to B
# o Others: ERROR
when "e"
# puts "state: e" if DEBUG
if (0x80..0xbf) === next_byte
state = "b"
else
valid = false
break
end
# The first continuation byte for some special 4 byte characters
# (those with start byte 0xf0)
# State: 'f'
# o Input = 0x90-0xBF: change state to B
# o Others: ERROR
when "f"
# puts "state: f" if DEBUG
if (0x90..0xbf) === next_byte
state = "b"
else
valid = false
break
end
# The first continuation byte for the remaining 4 byte characters
# (those with start byte 0xf4)
# State: 'g'
# o Input = 0x80-0x8F: change state to B
# o Others: ERROR
when "g"
# puts "state: g" if DEBUG
if (0x80..0x8f) === next_byte
state = "b"
else
valid = false
break
end
#
else
raise RuntimeError, "state: default"
end
end
#
# puts "State at end: #{state}" if DEBUG
# Catch truncation at end of string
if valid and state != 'start'
# puts "Resetting valid value" if DEBUG
valid = false
end
#
valid
end # of _valid_utf8?
# Stomp 1.1+ header check for UTF8 validity. Raises Stomp::Error::UTF8ValidationError if header data is not valid UTF8.
def _headerCheck(h)
return if @protocol == Stomp::SPL_10 # Do nothing for this environment
#
h.each_pair do |k,v|
# Keys here are symbolized
ks = k.to_s
ks.force_encoding(Stomp::UTF8) if ks.respond_to?(:force_encoding)
raise Stomp::Error::UTF8ValidationError unless valid_utf8?(ks)
#
if v.is_a?(Array)
v.each do |e|
e.force_encoding(Stomp::UTF8) if e.respond_to?(:force_encoding)
raise Stomp::Error::UTF8ValidationError unless valid_utf8?(e)
end
else
vs = v.to_s + "" # Values are usually Strings, but could be TrueClass or Symbol
# The + "" above forces an 'unfreeze' if necessary
vs.force_encoding(Stomp::UTF8) if vs.respond_to?(:force_encoding)
raise Stomp::Error::UTF8ValidationError unless valid_utf8?(vs)
end
end
end
# encode returns a Hash of encoded headers per the Stomp 1.1 specification.
def _encodeHeaders(h)
eh = {}
h.each_pair do |k,v|
# Keys are symbolized
ks = k.to_s
if v.is_a?(Array)
kenc = Stomp::HeaderCodec::encode(ks)
eh[kenc] = []
v.each do |e|
eh[kenc] << Stomp::HeaderCodec::encode(e)
end
else
vs = v.to_s
eh[Stomp::HeaderCodec::encode(ks).to_sym] = Stomp::HeaderCodec::encode(vs)
end
end
eh
end
# decode returns a Hash of decoded headers per the Stomp 1.1 specification.
def _decodeHeaders(h)
dh = {}
h.each_pair do |k,v|
# Keys here are NOT! symbolized
if v.is_a?(Array)
kdec = Stomp::HeaderCodec::decode(k)
dh[kdec] = []
v.each do |e|
dh[kdec] << Stomp::HeaderCodec::decode(e)
end
else
vs = v.to_s
dh[Stomp::HeaderCodec::decode(k)] = Stomp::HeaderCodec::decode(vs)
end
end
dh
end
end # class Connection
end # module Stomp
stomp-1.4.4/lib/connection/heartbeats.rb 0000644 0000041 0000041 00000023161 13120662775 020302 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'socket'
require 'timeout'
require 'io/wait'
require 'digest/sha1'
module Stomp
class Connection
private
def _validate_hbheader()
return if @connect_headers[:"heart-beat"] == "0,0" # Caller does not want heartbeats. OK.
parts = @connect_headers[:"heart-beat"].split(",")
if (parts.size != 2) || (parts[0] != parts[0].to_i.to_s) || (parts[1] != parts[1].to_i.to_s)
raise Stomp::Error::InvalidHeartBeatHeaderError
end
end
def _init_heartbeats()
return if @connect_headers[:"heart-beat"] == "0,0" # Caller does not want heartbeats. OK.
# Init.
#
@cx = @cy = @sx = @sy = 0 # Variable names as in spec
#
@hbsend_interval = @hbrecv_interval = 0.0 # Send/Receive ticker interval.
#
@hbsend_count = @hbrecv_count = 0 # Send/Receive ticker counts.
#
@ls = @lr = -1.0 # Last send/receive time (from Time.now.to_f)
#
@st = @rt = nil # Send/receive ticker thread
# Handle current client / server capabilities.
#
cfh = @connection_frame.headers.symbolize_keys
return if cfh[:"heart-beat"] == "0,0" # Server does not want heartbeats
# Conect header parts.
parts = @connect_headers[:"heart-beat"].split(",")
@cx = parts[0].to_i
@cy = parts[1].to_i
# Connected frame header parts.
parts = cfh[:"heart-beat"].split(",")
@sx = parts[0].to_i
@sy = parts[1].to_i
# Catch odd situations like server has used => heart-beat:000,00000
return if (@cx == 0 && @cy == 0) || (@sx == 0 && @sy == 0)
# See if we are doing anything at all.
@hbs = @hbr = true # Sending/Receiving heartbeats. Assume yes at first.
# Check if sending is possible.
@hbs = false if @cx == 0 || @sy == 0 # Reset if neither side wants
# Check if receiving is possible.
@hbr = false if @sx == 0 || @cy == 0 # Reset if neither side wants
# Check if we should not do heartbeats at all
return if (!@hbs && !@hbr)
# If sending
if @hbs
sm = @cx >= @sy ? @cx : @sy # ticker interval, ms
@hbsend_interval = 1000.0 * sm # ticker interval, μs
@ls = Time.now.to_f # best guess at start
_start_send_ticker()
end
# If receiving
if @hbr
rm = @sx >= @cy ? @sx : @cy # ticker interval, ms
@hbrecv_interval = 1000.0 * rm # ticker interval, μs
@lr = Time.now.to_f # best guess at start
_start_receive_ticker()
end
end
# _start_send_ticker starts a thread to send heartbeats when required.
def _start_send_ticker()
sleeptime = @hbsend_interval / 1000000.0 # Sleep time secs
reconn = false
adjust = 0.0
@st = Thread.new {
first_time = true
while true do
#
slt = sleeptime - adjust - @fast_hbs_adjust
sleep(slt)
next unless @socket # nil under some circumstances ??
curt = Time.now.to_f
slog(:on_hbfire, log_params, "send_fire", :curt => curt, :last_sleep => slt)
delta = curt - @ls
# Be tolerant (minus), and always do this the first time through.
# Reintroduce logic removed in d922fa.
compval = (@hbsend_interval - (@hbsend_interval/5.0)) / 1000000.0
if delta > compval || first_time
first_time = false
slog(:on_hbfire, log_params, "send_heartbeat", {:last_sleep => slt,
:curt => curt, :last_send => @ls, :delta => delta,
:compval => compval})
# Send a heartbeat
@transmit_semaphore.synchronize do
begin
@socket.puts
@socket.flush # Do not buffer heartbeats
@ls = Time.now.to_f # Update last send
@hb_sent = true # Reset if necessary
@hbsend_count += 1
rescue Exception => sendex
@hb_sent = false # Set the warning flag
slog(:on_hbwrite_fail, log_params, {"ticker_interval" => sleeptime,
"exception" => sendex})
if @hbser
raise # Re-raise if user requested this, otherwise ignore
end
if @reliable
reconn = true
break # exit the synchronize do
end
end
end # of the synchronize
if reconn
# Attempt a fail over reconnect. This is 'safe' here because
# this thread no longer holds the @transmit_semaphore lock.
@rt.kill if @rt # Kill the receiver thread if one exists
_reconn_prep_hb() # Drive reconnection logic
Thread.exit # This sender thread is done
end
end
adjust = Time.now.to_f - curt
Thread.pass
end
}
end
# _start_receive_ticker starts a thread that receives heartbeats when required.
def _start_receive_ticker()
sleeptime = @hbrecv_interval / 1000000.0 # Sleep time secs
read_fail_count = 0
lock_fail_count = 0
fail_hard = false
@rt = Thread.new {
#
while true do
sleep sleeptime
next unless @socket # nil under some circumstances ??
rdrdy = _is_ready?(@socket)
curt = Time.now.to_f
slog(:on_hbfire, log_params, "receive_fire", :curt => curt)
#
begin
delta = curt - @lr
if delta > sleeptime
slog(:on_hbfire, log_params, "receive_heartbeat", {})
# Client code could be off doing something else (that is, no reading of
# the socket has been requested by the caller). Try to handle that case.
lock = @read_semaphore.try_lock
if lock
lock_fail_count = 0 # clear
rdrdy = _is_ready?(@socket)
if rdrdy
read_fail_count = 0 # clear
last_char = @socket.getc
if last_char.nil? # EOF from broker?
fail_hard = true
else
@lr = Time.now.to_f
plc = parse_char(last_char)
if plc == "\n" # Server Heartbeat
@hbrecv_count += 1
@hb_received = true # Reset if necessary
else
@socket.ungetc(last_char)
end
end
@read_semaphore.unlock # Release read lock
else # Socket is not ready
@read_semaphore.unlock # Release read lock
@hb_received = false
read_fail_count += 1
slog(:on_hbread_fail, log_params, {"ticker_interval" => sleeptime,
"read_fail_count" => read_fail_count,
"lock_fail" => false,
"lock_fail_count" => lock_fail_count,
"fail_point" => "not_ready"})
end
else # try_lock failed
# Shrug. Could not get lock. Client must be actually be reading.
@hb_received = false
# But notify caller if possible
lock_fail_count += 1
slog(:on_hbread_fail, log_params, {"ticker_interval" => sleeptime,
"read_fail_count" => read_fail_count,
"lock_fail" => true,
"lock_fail_count" => lock_fail_count,
"fail_point" => "try_lock_fail"})
end # of the try_lock
else # delta <= sleeptime
@hb_received = true # Reset if necessary
read_fail_count = 0 # reset
lock_fail_count = 0 # reset
end # of the if delta > sleeptime
rescue Exception => recvex
slog(:on_hbread_fail, log_params, {"ticker_interval" => sleeptime,
"exception" => recvex,
"read_fail_count" => read_fail_count,
"lock_fail_count" => lock_fail_count,
"fail_point" => "receive_exception"})
fail_hard = true
end
# Do we want to attempt a retry?
if @reliable
# Retry on hard fail or max read fails
if fail_hard ||
(@max_hbread_fails > 0 && read_fail_count >= @max_hbread_fails)
# This is an attempt at a connection retry.
@st.kill if @st # Kill the sender thread if one exists
_reconn_prep_hb() # Drive reconnection logic
Thread.exit # This receiver thread is done
end
# Retry on max lock fails. Different logic in order to avoid a deadlock.
if (@max_hbrlck_fails > 0 && lock_fail_count >= @max_hbrlck_fails)
# This is an attempt at a connection retry.
@gets_semaphore.synchronize do
@getst.raise(Errno::EBADF.new) if @getst # kill the socket reading thread if exists
@socket.close rescue nil # Attempt a forced close
end
@st.kill if @st # Kill the sender thread if one exists
Thread.exit # This receiver thread is done
end
end
Thread.pass # Prior to next receive loop
#
end # of the "while true"
} # end of the Thread.new
end
# _reconn_prep_hb prepares for a reconnect retry
def _reconn_prep_hb()
if @parameters
change_host()
end
@socket = nil
used_socket = socket()
return used_socket
end
end # class Connection
end # module Stomp
stomp-1.4.4/test/ 0000755 0000041 0000041 00000000000 13120662775 013702 5 ustar www-data www-data stomp-1.4.4/test/test_urlogin.rb 0000644 0000041 0000041 00000006755 13120662775 016762 0 ustar www-data www-data # -*- encoding: utf-8 -*-
if Kernel.respond_to?(:require_relative)
require_relative("test_helper")
else
$:.unshift(File.dirname(__FILE__))
require 'test_helper'
end
=begin
Main class for testing Stomp::Client URL based Logins.
=end
class TestURLLogins < Test::Unit::TestCase
include TestBase
def setup
hostname = host()
portnum = port()
sslpn = ssl_port()
@tdstomp = [
"stomp://guestl:guestp@#{hostname}:#{portnum}",
"stomp://#{hostname}:#{portnum}",
"stomp://@#{hostname}:#{portnum}",
"stomp://f@#$$%^&*()_+=o.o:@#{hostname}:#{portnum}",
'stomp://f@#$$%^&*()_+=o.o::b~!@#$%^&*()+-_=?:<>,.@@' + hostname + ":#{portnum}",
]
@tdfailover = [
"failover://(stomp://#{hostname}:#{portnum})",
"failover://(stomp://#{hostname}:#{portnum})",
"failover://(stomp://#{hostname}:#{portnum})?whatup=doc&coyote=kaboom",
"failover://(stomp://#{hostname}:#{portnum})?whatup=doc",
"failover://(stomp://#{hostname}:#{portnum})?whatup=doc&coyote=kaboom&randomize=true",
'failover://(stomp://f@#$$%^&*()_+=o.o::b~!@#$%^&*()+-_=?:<>,.@@' + "#{hostname}" + ":#{portnum}" + ")",
'failover://(stomp://f@#$$%^&*()_+=o.o::b~!@#$%^&*()+-_=:<>,.@@' + "#{hostname}" + ":#{portnum}" + ")",
'failover://(stomp://f@#$$%^&*()_+=o.o::b~!@#$%^&*()+-_=?:<>,.@@' + "#{hostname}" + ":#{portnum}" + ")?a=b",
'failover://(stomp://f@#$$%^&*()_+=o.o::b~!@#$%^&*()+-_=:<>,.@@' + "#{hostname}" + ":#{portnum}" + ")?c=d&e=f",
"failover://(stomp://usera:passa@#{hostname}:#{portnum})",
"failover://(stomp://usera:@#{hostname}:#{portnum})",
"failover://(stomp://#{hostname}:#{portnum},stomp://#{hostname}:#{portnum})",
"failover://(stomp://usera:passa@#{hostname}:#{portnum},stomp://#{hostname}:#{portnum})",
"failover://(stomp://usera:@#{hostname}:#{portnum},stomp://#{hostname}:#{portnum})",
"failover://(stomp://#{hostname}:#{portnum},stomp://#{hostname}:#{portnum})?a=b&c=d",
"failover://(stomp://#{hostname}:#{portnum},stomp://#{hostname}:#{portnum})?a=b&c=d&connect_timeout=2020",
]
@sslfailover = [
"failover://(stomp+ssl://#{hostname}:#{sslpn})",
"failover://(stomp+ssl://usera:passa@#{hostname}:#{sslpn})",
"failover://(stomp://usera:@#{hostname}:#{portnum},stomp+ssl://#{hostname}:#{sslpn})",
]
@badparms = "failover://(stomp://#{hostname}:#{portnum})?a=b&noequal"
@client = nil
end
def teardown
@client.close if @client && @client.open? # allow tests to close
end
# test stomp:// URLs
def test_0010_stomp_urls()
@tdstomp.each_with_index do |url, ndx|
c = Stomp::Client.new(url)
assert !c.nil?, url
assert c.open?, url
c.close
end
end
# test failover:// urls - tcp
def test_0020_failover_urls_tcp()
@tdfailover.each_with_index do |url, ndx|
# p [ "xurl", url, "xndx", ndx ]
c = Stomp::Client.new(url)
assert !c.nil?, url
assert c.open?, url
c.close
end
end
# test failover:// urls - ssl
def test_0020_failover_urls_ssl()
@sslfailover.each_with_index do |url, ndx|
# p [ "sslxurl", url, "sslxndx", ndx ]
c = Stomp::Client.new(url)
assert !c.nil?, url
assert c.open?, url
c.close
end
end if ENV['STOMP_TESTSSL']
# test failover:// with bad parameters
def test_0020_failover_badparms()
assert_raise(Stomp::Error::MalformedFailoverOptionsError) {
_ = Stomp::Client.new(@badparms)
}
end
end unless ENV['STOMP_RABBIT']
stomp-1.4.4/test/unitst.sh 0000755 0000041 0000041 00000000767 13120662775 015601 0 ustar www-data www-data #!/bin/bash
#
eval $DeBug
# ------------------------------------------------------------------------------
cmd_base=$(dirname $0)
source $cmd_base/funcs.sh
# ------------------------------------------------------------------------------
pushd $cmd_base
RUN=${RUBY:-ruby}
slist=$(ls -1 *.rb | grep -v helper | grep -v 1method)
for rbf in $slist
do
echo "${RUN} -I ../lib ${rbf}"
$RUN -I ../lib $rbf
done
# ------------------------------------------------------------------------------
popd
set +x
exit
stomp-1.4.4/test/MultiBrokerUnitTestExample.sh 0000755 0000041 0000041 00000004747 13120662775 021530 0 ustar www-data www-data #!/bin/sh
#
set -x
#
# An example of running unit tests against multiple message brokers.
#
pref="STOMP_PORT=61613 rake test --trace"
echo =============== AMQ Stomp 1.0 ===============
eval $pref
pref="STOMP_PORT=61613 STOMP_TEST11p=1.1 STOMP_AMQ11=y STOMP_NOWILD=y rake test --trace"
echo =============== AMQ Stomp 1.1 ===============
eval $pref
pref="STOMP_PORT=61613 STOMP_TEST11p=1.2 STOMP_AMQ11=y STOMP_NOWILD=y rake test --trace"
echo =============== AMQ Stomp 1.2 ===============
eval $pref
pref="STOMP_TESTSSL=y STOMP_PORT=62613 STOMP_SSLPORT=62614 STOMP_DOTQUEUE=y STOMP_NOWILD=y rake test --trace"
echo =============== Apollo Stomp 1.0 ===============
eval $pref
pref="STOMP_TESTSSL=y STOMP_PORT=62613 STOMP_SSLPORT=62614 STOMP_DOTQUEUE=y STOMP_TEST11p=1.1 STOMP_NOWILD=y STOMP_APOLLO=y rake test --trace"
echo =============== Apollo Stomp 1.1 ===============
eval $pref
pref="STOMP_TESTSSL=y STOMP_PORT=62613 STOMP_SSLPORT=62614 STOMP_DOTQUEUE=y STOMP_TEST11p=1.2 STOMP_NOWILD=y STOMP_APOLLO=y rake test --trace"
echo =============== Apollo Stomp 1.2 ===============
eval $pref
pref="STOMP_TESTSSL=y STOMP_PORT=62613 STOMP_SSLPORT=62614 STOMP_DOTQUEUE=y STOMP_TEST11p=1.2 STOMP_NOWILD=y STOMP_CRLF=y STOMP_APOLLO=y rake test --trace"
echo =============== Apollo Stomp 1.2 - CRLF=y ===============
eval $pref
pref="STOMP_TESTSSL=y STOMP_PORT=62613 STOMP_SSLPORT=62614 STOMP_DOTQUEUE=y STOMP_TEST11p=1.2 STOMP_NOWILD=y STOMP_CONN=y STOMP_APOLLO=y rake test --trace"
echo =============== Apollo Stomp 1.2 - CONN=y ===============
eval $pref
pref="STOMP_RABBIT=y STOMP_PORT=41613 STOMP_DOTQUEUE=y STOMP_NOWILD=y rake test --trace"
echo =============== RabbitMQ Stomp 1.0 ===============
eval $pref
pref="STOMP_RABBIT=y STOMP_PORT=41613 STOMP_DOTQUEUE=y STOMP_NOWILD=y STOMP_TEST11p=1.1 rake test --trace"
echo =============== RabbitMQ Stomp 1.1 ===============
eval $pref
pref="STOMP_RABBIT=y STOMP_PORT=41613 STOMP_DOTQUEUE=y STOMP_NOWILD=y STOMP_TEST11p=1.2 rake test --trace"
echo =============== RabbitMQ Stomp 1.2 ===============
eval $pref
pref="STOMP_ARTEMIS=y STOMP_PORT=31613 STOMP_NOWILD=y rake test --trace"
echo =============== Artemis Stomp 1.0 ===============
eval $pref
pref="STOMP_ARTEMIS=y STOMP_PORT=31613 STOMP_NOWILD=y STOMP_TEST11p=1.1 rake test --trace"
echo =============== Artemis Stomp 1.1 ===============
eval $pref
pref="STOMP_ARTEMIS=y STOMP_PORT=31613 STOMP_NOWILD=y STOMP_TEST11p=1.2 rake test --trace"
echo =============== Artemis Stomp 1.2 ===============
eval $pref
set +x
exit 0
stomp-1.4.4/test/test_ssl.rb 0000644 0000041 0000041 00000003602 13120662775 016070 0 ustar www-data www-data # -*- encoding: utf-8 -*-
if Kernel.respond_to?(:require_relative)
require_relative("test_helper")
else
$:.unshift(File.dirname(__FILE__))
require 'test_helper'
end
=begin
Main class for testing Stomp::SSLParams.
=end
class TestSSL < Test::Unit::TestCase
include TestBase
def setup
@conn = get_ssl_connection()
end
def teardown
@conn.disconnect if @conn && @conn.open? # allow tests to disconnect
end
#
def test_ssl_0000
assert @conn.open?
end
# Test SSLParams basic.
def test_ssl_0010_parms
ssl_params = Stomp::SSLParams.new
assert ssl_params.ts_files.nil?
assert ssl_params.cert_file.nil?
assert ssl_params.key_file.nil?
assert ssl_params.fsck.nil?
end
# Test using correct parameters.
def test_ssl_0020_noraise
_ = Stomp::SSLParams.new(:cert_file => "dummy1", :key_file => "dummy2")
_ = Stomp::SSLParams.new(:ts_files => "dummyts1")
_ = Stomp::SSLParams.new(:ts_files => "dummyts1",
:cert_file => "dummy1", :key_file => "dummy2")
end
# Test using incorrect / incomplete parameters.
def test_ssl_0030_raise
assert_raise(Stomp::Error::SSLClientParamsError) {
_ = Stomp::SSLParams.new(:cert_file => "dummy1")
}
assert_raise(Stomp::Error::SSLClientParamsError) {
_ = Stomp::SSLParams.new(:key_file => "dummy2")
}
end
# Test that :fsck works.
def test_ssl_0040_fsck
assert_raise(Stomp::Error::SSLNoCertFileError) {
_ = Stomp::SSLParams.new(:cert_file => "dummy1",
:key_file => "dummy2", :fsck => true)
}
assert_raise(Stomp::Error::SSLNoKeyFileError) {
_ = Stomp::SSLParams.new(:cert_file => __FILE__,
:key_file => "dummy2", :fsck => true)
}
assert_raise(Stomp::Error::SSLNoTruststoreFileError) {
_ = Stomp::SSLParams.new(:ts_files => "/tmp/not-likely-here.txt",
:fsck => true)
}
end
#
end if ENV['STOMP_TESTSSL']
stomp-1.4.4/test/test_client.rb 0000644 0000041 0000041 00000050111 13120662775 016542 0 ustar www-data www-data # -*- encoding: utf-8 -*-
if Kernel.respond_to?(:require_relative)
require_relative("test_helper")
else
$:.unshift(File.dirname(__FILE__))
require 'test_helper'
end
=begin
Main class for testing Stomp::Client instances.
=end
class TestClient < Test::Unit::TestCase
include TestBase
def setup
@client = get_client()
# Multi_thread test data
@max_threads = 20
@max_msgs = 50
end
def teardown
@client.close if @client && @client.open? # allow tests to close
end
# Test poll works.
def test_poll_async
# If the test 'hangs' here, Connection#poll is broken.
m = @client.poll
assert m.nil?
end
# Test ACKs.
def test_ack_api_works
@client.publish make_destination, message_text, {:suppress_content_length => true}
received = nil
@client.subscribe(make_destination, {:ack => 'client'}) {|msg| received = msg}
sleep 0.01 until received
assert_equal message_text, received.body
receipt = nil
ack_headers = {}
if @client.protocol == Stomp::SPL_11 # 1.1 only
ack_headers["subscription"] = received.headers["subscription"]
end
@client.acknowledge(received, ack_headers) {|r| receipt = r}
sleep 0.01 until receipt
assert_not_nil receipt.headers['receipt-id']
checkEmsg(@client)
end
# Test Client subscribe
def test_asynch_subscribe
received = false
@client.subscribe(make_destination) {|msg| received = msg}
@client.publish make_destination, message_text
sleep 0.01 until received
assert_equal message_text, received.body
checkEmsg(@client)
end
# Test not ACKing messages.
def test_noack
@client.publish make_destination, message_text
received = nil
@client.subscribe(make_destination, :ack => :client) {|msg| received = msg}
sleep 0.01 until received
assert_equal message_text, received.body
@client.close
# was never acked so should be resent to next client
@client = get_client()
received2 = nil
@client.subscribe(make_destination) {|msg| received2 = msg}
sleep 0.01 until received2
assert_equal message_text, received2.body
assert_equal received.body, received2.body
assert_equal received.headers['message-id'], received2.headers['message-id'] unless ENV['STOMP_RABBIT']
checkEmsg(@client)
end unless RUBY_ENGINE =~ /jruby/
# Test obtaining a RECEIPT via a listener.
def test_receipts
receipt = false
@client.publish(make_destination, message_text) {|r| receipt = r}
sleep 0.1 until receipt
assert_equal receipt.command, Stomp::CMD_RECEIPT
message = nil
@client.subscribe(make_destination) {|m| message = m}
sleep 0.1 until message
assert_equal message_text, message.body
checkEmsg(@client)
end
# Test requesting a receipt on disconnect.
def test_disconnect_receipt
@client.close :receipt => "xyz789"
assert_not_nil(@client.disconnect_receipt, "should have a receipt")
assert_equal(@client.disconnect_receipt.headers['receipt-id'],
"xyz789", "receipt sent and received should match")
end
# Test publish and immediate subscribe.
def test_publish_then_sub
@client.publish make_destination, message_text
message = nil
@client.subscribe(make_destination) {|m| message = m}
sleep 0.01 until message
assert_equal message_text, message.body
checkEmsg(@client)
end
# Test that Client subscribe requires a block.
def test_subscribe_requires_block
assert_raise(Stomp::Error::NoListenerGiven) do
@client.subscribe make_destination
end
checkEmsg(@client)
end unless RUBY_ENGINE =~ /jruby/
# Test transaction publish.
def test_transactional_publish
@client.begin 'tx1'
@client.publish make_destination, message_text, :transaction => 'tx1'
@client.commit 'tx1'
message = nil
@client.subscribe(make_destination) {|m| message = m}
sleep 0.01 until message
assert_equal message_text, message.body
checkEmsg(@client)
end
# Test transaction publish and abort.
def test_transaction_publish_then_rollback
@client.begin 'tx1'
@client.publish make_destination, "first_message", :transaction => 'tx1'
@client.abort 'tx1'
@client.begin 'tx1'
@client.publish make_destination, "second_message", :transaction => 'tx1'
@client.commit 'tx1'
message = nil
@client.subscribe(make_destination) {|m| message = m}
sleep 0.01 until message
assert_equal "second_message", message.body
checkEmsg(@client)
end unless RUBY_ENGINE =~ /jruby/
# Test transaction publish and abort, receive with new client.
# New client uses ack => client.
def test_tran_ack_abrt_newcli_cli
@client.close if @client && @client.open? # allow tests to close
@client = get_client()
q = make_destination
data = message_text
@client.publish q, data
@client.begin 'tx1'
message = nil
sid = nil
if @client.protocol() == Stomp::SPL_10
@client.subscribe(q, :ack => 'client') {|m| message = m}
else # 1.1 and 1.2 are the same for this
sid = @client.uuid()
@client.subscribe(q, :ack => 'client', :id => sid) {|m| message = m}
end
sleep 0.01 until message
assert_equal data, message.body
case @client.protocol()
when Stomp::SPL_10
@client.acknowledge message, :transaction => 'tx1'
checkEmsg(@client)
when Stomp::SPL_11
@client.acknowledge message, :transaction => 'tx1', :subscription => message.headers['subscription']
checkEmsg(@client)
else # 1.2+
@client.acknowledge message, :transaction => 'tx1', :id => message.headers['ack']
checkEmsg(@client)
end
message = nil # reset
@client.abort 'tx1' # now abort
checkEmsg(@client)
# lets recreate the connection
@client.close
@client = get_client()
sid = nil
message2 = nil
@client.begin 'tx2'
if @client.protocol() == Stomp::SPL_10
@client.subscribe(q, :ack => 'client') {|m| message2 = m}
else # 1.1 and 1.2 are the same for this
sid = @client.uuid()
@client.subscribe(q, :ack => 'client', :id => sid) {|m| message2 = m}
end
sleep 0.01 until message2
assert_not_nil message
assert_equal data, message2.body
case @client.protocol()
when Stomp::SPL_10
@client.acknowledge message2, :transaction => 'tx2'
checkEmsg(@client)
when Stomp::SPL_11
@client.acknowledge message2, :transaction => 'tx2', :subscription => message2.headers['subscription']
checkEmsg(@client)
else # 1.2+
@client.acknowledge message2, :transaction => 'tx2', :id => message2.headers['ack']
checkEmsg(@client)
end
@client.commit 'tx2'
checkEmsg(@client)
@client.close
end unless ENV['STOMP_ARTEMIS'] # See Artemis docs for 1.3, page 222
# Test transaction publish and abort, receive with new client.
# New client uses ack => auto.
def test_tran_ack_abrt_newcli_auto
@client.close if @client && @client.open? # allow tests to close
@client = get_client()
q = make_destination
data = message_text
@client.publish q, data
@client.begin 'tx1'
message = nil
sid = nil
if @client.protocol() == Stomp::SPL_10
@client.subscribe(q, :ack => 'client') {|m| message = m}
else # 1.1 and 1.2 are the same for this
sid = @client.uuid()
@client.subscribe(q, :ack => 'client', :id => sid) {|m| message = m}
end
sleep 0.01 until message
assert_equal data, message.body
case @client.protocol()
when Stomp::SPL_10
@client.acknowledge message, :transaction => 'tx1'
checkEmsg(@client)
when Stomp::SPL_11
@client.acknowledge message, :transaction => 'tx1', :subscription => message.headers['subscription']
checkEmsg(@client)
else # 1.2+
@client.acknowledge message, :transaction => 'tx1', :id => message.headers['ack']
checkEmsg(@client)
end
message = nil # reset
@client.abort 'tx1' # now abort
checkEmsg(@client)
# lets recreate the connection
@client.close
@client = get_client()
sid = nil
message2 = nil
@client.begin 'tx2'
if @client.protocol() == Stomp::SPL_10
@client.subscribe(q, :ack => 'auto') {|m| message2 = m}
else # 1.1 and 1.2 are the same for this
sid = @client.uuid()
@client.subscribe(q, :ack => 'auto', :id => sid) {|m| message2 = m}
end
sleep 0.01 until message2
assert_not_nil message2
assert_equal data, message2.body
@client.commit 'tx2'
checkEmsg(@client)
@client.close
end unless ENV['STOMP_ARTEMIS'] # See Artemis docs for 1.3, page 222
# Test that subscription destinations must be unique for a Client.
def test_raise_on_multiple_subscriptions_to_same_make_destination
subscribe_dest = make_destination
@client.subscribe(subscribe_dest) {|m| nil }
assert_raise(Stomp::Error::DuplicateSubscription) do
@client.subscribe(subscribe_dest) {|m| nil }
end
checkEmsg(@client)
end
# Test that subscription IDs must be unique for a Client.
def test_raise_on_multiple_subscriptions_to_same_id
subscribe_dest = make_destination
@client.subscribe(subscribe_dest, {'id' => 'myid'}) {|m| nil }
assert_raise(Stomp::Error::DuplicateSubscription) do
@client.subscribe(subscribe_dest, {'id' => 'myid'}) {|m| nil }
end
checkEmsg(@client)
end
# Test that subscription IDs must be unique for a Client, mixed id specification.
def test_raise_on_multiple_subscriptions_to_same_id_mixed
subscribe_dest = make_destination
@client.subscribe(subscribe_dest, {'id' => 'myid'}) {|m| nil }
assert_raise(Stomp::Error::DuplicateSubscription) do
@client.subscribe(subscribe_dest, {:id => 'myid'}) {|m| nil }
end
checkEmsg(@client)
end
# Test wildcard subscribe. Primarily for AMQ.
def test_asterisk_wildcard_subscribe
queue_base_name = make_destination
queue1 = queue_base_name + ".a"
queue2 = queue_base_name + ".b"
send_message = message_text
@client.publish queue1, send_message
@client.publish queue2, send_message
messages = []
@client.subscribe(queue_base_name + ".*", :ack => 'client') do |m|
messages << m
@client.acknowledge(m)
end
Timeout::timeout(4) do
sleep 0.1 while messages.size < 2
end
messages.each do |message|
assert_not_nil message
assert_equal send_message, message.body
end
results = [queue1, queue2].collect do |queue|
messages.any? do |message|
message_source = message.headers['destination']
message_source == queue
end
end
assert results.all?{|a| a == true }
checkEmsg(@client)
end unless ENV['STOMP_NOWILD']
# Test wildcard subscribe with >. Primarily for AMQ.
def test_greater_than_wildcard_subscribe
queue_base_name = make_destination + "."
queue1 = queue_base_name + "foo.a"
queue2 = queue_base_name + "bar.a"
queue3 = queue_base_name + "foo.b"
send_message = message_text
@client.publish queue1, send_message
@client.publish queue2, send_message
@client.publish queue3, send_message
messages = []
# should subscribe to all three queues
@client.subscribe(queue_base_name + ">", :ack => 'client') do |m|
messages << m
@client.acknowledge(m)
end
Timeout::timeout(4) do
sleep 0.1 while messages.size < 3
end
messages.each do |message|
assert_not_nil message
assert_equal send_message, message.body
end
# make sure that the messages received came from the expected queues
results = [queue1, queue2, queue3].collect do |queue|
messages.any? do |message|
message_source = message.headers['destination']
message_source == queue
end
end
assert results.all?{|a| a == true }
checkEmsg(@client)
end unless ENV['STOMP_NOWILD'] || ENV['STOMP_DOTQUEUE']
# Test transaction with client side reacknowledge.
def test_transaction_with_client_side_reack
@client.close if @client && @client.open? # allow tests to close
@client = get_client()
q = make_destination
data = message_text
@client.publish q, data
@client.begin 'tx1'
message = nil
sid = nil
if @client.protocol() == Stomp::SPL_10
@client.subscribe(q, :ack => 'client') { |m| message = m }
else
sid = @client.uuid()
@client.subscribe(q, :ack => 'client', :id => sid) { |m| message = m }
end
sleep 0.1 while message.nil?
assert_equal data, message.body
case @client.protocol()
when Stomp::SPL_10
@client.acknowledge message, :transaction => 'tx1'
checkEmsg(@client)
when Stomp::SPL_11
@client.acknowledge message, :transaction => 'tx1', :subscription => message.headers['subscription']
checkEmsg(@client)
else # 1.2+
@client.acknowledge message, :transaction => 'tx1', :id => message.headers['ack']
checkEmsg(@client)
end
message = nil
@client.abort 'tx1'
# Wait for redlivery (Client logic)
sleep 0.1 while message.nil?
assert_not_nil message
assert_equal data, message.body
@client.begin 'tx2'
case @client.protocol()
when Stomp::SPL_10
@client.acknowledge message, :transaction => 'tx2'
checkEmsg(@client)
when Stomp::SPL_11
@client.acknowledge message, :transaction => 'tx2', :subscription => message.headers['subscription']
checkEmsg(@client)
else # 1.2+
@client.acknowledge message, :transaction => 'tx2', :id => message.headers['ack']
checkEmsg(@client)
end
@client.commit 'tx2'
checkEmsg(@client)
@client.close
@client = nil
end
# Test that a connection frame is received.
def test_connection_frame
assert_not_nil @client.connection_frame
checkEmsg(@client)
end unless RUBY_ENGINE =~ /jruby/
# Test basic unsubscribe.
def test_unsubscribe
@client.close if @client && @client.open? # close setup work
@client = nil
message = nil
dest = make_destination
to_send = message_text
client = get_client()
sid = nil
if client.protocol() == Stomp::SPL_10
client.subscribe(dest, :ack => 'client') { |m| message = m }
else
sid = client.uuid()
client.subscribe(dest, :ack => 'client', :id => sid) { |m| message = m }
end
client.publish dest, to_send
Timeout::timeout(4) do
sleep 0.01 until message
end
assert_equal to_send, message.body, "first body check"
if client.protocol() == Stomp::SPL_10
client.unsubscribe dest
else
client.unsubscribe dest, :id => sid
end
client.close
# Same message should remain on the queue. Receive it again with ack=>auto.
message_copy = nil
client = get_client()
if client.protocol() == Stomp::SPL_10
client.subscribe(dest, :ack => 'auto') { |m| message_copy = m }
else
sid = client.uuid()
client.subscribe(dest, :ack => 'auto', :id => sid) { |m| message_copy = m }
end
Timeout::timeout(4) do
sleep 0.01 until message_copy
end
assert_equal to_send, message_copy.body, "second body check"
assert_equal message.headers['message-id'], message_copy.headers['message-id'], "header check" unless ENV['STOMP_RABBIT']
checkEmsg(client)
client.close
end
# Test subscribe from a worker thread.
def test_thread_one_subscribe
msg = nil
dest = make_destination
Thread.new(@client) do |acli|
if acli.protocol() == Stomp::SPL_10
acli.subscribe(dest) { |m| msg = m }
else
acli.subscribe(dest, :id => acli.uuid()) { |m| msg = m }
end
Timeout::timeout(4) do
sleep 0.01 until msg
end
end
#
@client.publish(dest, message_text)
sleep 1
assert_not_nil msg
checkEmsg(@client)
end unless RUBY_ENGINE =~ /jruby/
# Test subscribe from multiple worker threads.
def test_thread_multi_subscribe
#
lock = Mutex.new
msg_ctr = 0
dest = make_destination
1.upto(@max_threads) do |tnum|
# Threads within threads .....
Thread.new(@client) do |acli|
# this is ugly .....
if acli.protocol() == Stomp::SPL_10
acli.subscribe(dest) { |m|
_ = m
lock.synchronize do
msg_ctr += 1
end
# Simulate message processing
sleep 0.05
}
else
acli.subscribe(dest, :id => acli.uuid()) { |m|
_ = m
lock.synchronize do
msg_ctr += 1
end
# Simulate message processing
sleep 0.05
}
end
end
end
#
1.upto(@max_msgs) do |mnum|
msg = Time.now.to_s + " #{mnum}"
@client.publish(dest, msg)
end
#
max_sleep = (RUBY_VERSION =~ /1\.8\.6/) ? 30 : 5
sleep_incr = 0.10
total_slept = 0
while true
break if @max_msgs == msg_ctr
total_slept += sleep_incr
break if total_slept > max_sleep
sleep sleep_incr
end
assert_equal @max_msgs, msg_ctr
checkEmsg(@client)
end
# Test that methods detect no client connection is present.
def test_closed_checks_client
@client.close
#
assert_raise Stomp::Error::NoCurrentConnection do
m = Stomp::Message.new("")
@client.acknowledge(m) {|r| _ = r}
end
#
assert_raise Stomp::Error::NoCurrentConnection do
@client.begin("dummy_data")
end
#
assert_raise Stomp::Error::NoCurrentConnection do
@client.commit("dummy_data")
end
#
assert_raise Stomp::Error::NoCurrentConnection do
@client.abort("dummy_data")
end
#
assert_raise Stomp::Error::NoCurrentConnection do
@client.subscribe("dummy_data", {:ack => 'auto'}) {|msg| _ = msg}
end
#
assert_raise Stomp::Error::NoCurrentConnection do
@client.unsubscribe("dummy_data")
end
#
assert_raise Stomp::Error::NoCurrentConnection do
@client.publish("dummy_data","dummy_data")
end
#
assert_raise Stomp::Error::NoCurrentConnection do
@client.unreceive("dummy_data")
end
#
assert_raise Stomp::Error::NoCurrentConnection do
@client.close("dummy_data")
end
end
# test JRuby detection
def test_jruby_presence
if defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/
assert @client.jruby?
else
assert !@client.jruby?
end
end
# test max redeliveries is not broken (6c2c1c1)
def test_max_redeliveries
@client.close
2.upto(2) do |max_re|
rdmsg = "To Be Redelivered: #{max_re.to_s}"
dest = make_destination + ".#{max_re.to_s}"
@client = get_client()
sid = "sid_max_redeliveries_#{max_re.to_s}"
received = nil
rm_actual = 0
sh = @client.protocol() == Stomp::SPL_10 ? {} : {:id => sid}
@client.subscribe(dest, sh) {|msg|
rm_actual += 1
@client.unreceive(msg, :max_redeliveries => max_re,
:dead_letter_queue => make_dlq())
received = msg if rm_actual - 1 == max_re
}
@client.publish(dest, rdmsg)
sleep 0.01 until received
assert_equal rdmsg, received.body
sleep 0.5
@client.unsubscribe dest, sh
assert_equal max_re, rm_actual - 1
@client.close
end
end unless ENV['STOMP_ARTEMIS'] # need to investigate this, but skip
# Artemis for now
# test issue99, OK values
def test_cli_iss99_ok
return unless host() == "localhost" && port() == 61613
@client.close
#
ok_vals = dflt_data_ok()
ok_vals.each do |hsv|
cli = Stomp::Client.open(hsv)
cli.close
end
end
# test issue99, exception values
def test_cli_iss99_ex
return unless host() == "localhost" && port() == 61613
@client.close
#
ex_vals = dflt_data_ex()
ex_vals.each do |hsv|
assert_raise ArgumentError do
_ = Stomp::Client.open(hsv)
end
end
end
def test_cli_nodest_sub
assert_raise Stomp::Error::DestinationRequired do
@client.subscribe(nil) {|msg| puts msg}
end
end
def test_cli_nodest_unsub
assert_raise Stomp::Error::DestinationRequired do
@client.unsubscribe(nil)
end
end
def test_cli_nodest_pub
assert_raise Stomp::Error::DestinationRequired do
@client.publish(nil, "msg")
end
end
private
def message_text
name = caller_method_name unless name
"test_client#" + name
end
end
stomp-1.4.4/test/test_message.rb 0000644 0000041 0000041 00000012417 13120662775 016717 0 ustar www-data www-data # -*- encoding: us-ascii -*-
#
# !!!!
#
# This can *NOT* currently be marked as UTF-8 encoded. It uses invalid UTF-8
# sequences for testing. Tests will fail under 1.9.x+ if this file is marked
# as UTF-8 encoded. Tests will fail under 2.0.0 if this file is *NOT* marked
# as US-ASCII.
#
if Kernel.respond_to?(:require_relative)
require_relative("test_helper")
else
$:.unshift(File.dirname(__FILE__))
require 'test_helper'
end
#
# Test Ruby 1.8 with $KCODE='U'
#
=begin
Main class for testing Stomp::Message.
=end
class TestMessage < Test::Unit::TestCase
include TestBase
#
def setup
$KCODE = 'U' if RUBY_VERSION =~ /1\.8/
@conn = get_connection()
# Message body data
@messages = [
"normal text message",
"bad byte: \372",
"\004\b{\f:\tbody\"\001\207\004\b{\b:\016statusmsg\"\aOK:\017statuscodei\000:\tdata{\t:\voutput\"3Enabled, not running, last run 693 seconds ago:\frunningi\000:\fenabledi\006:\flastrunl+\aE\021\022M:\rsenderid\"\032xx.xx.xx.xx:\016requestid\"%849d647bbe3e421ea19ac9f947bbdde4:\020senderagent\"\fpuppetd:\016msgtarget\"%/topic/mcollective.puppetd.reply:\thash\"\001\257ZdQqtaDmmdD0jZinnEcpN+YbkxQDn8uuCnwsQdvGHau6d+gxnnfPLUddWRSb\nZNMs+sQUXgJNfcV1eVBn1H+Z8QQmzYXVDMqz7J43jmgloz5PsLVbN9K3PmX/\ngszqV/WpvIyAqm98ennWqSzpwMuiCC4q2Jr3s3Gm6bUJ6UkKXnY=\n:\fmsgtimel+\a\372\023\022M"
]
#
end
def teardown
@conn.disconnect if @conn # allow tests to disconnect
end
# Various message bodies, including the failing test case reported
def test_0010_kcode
#
dest = make_destination
if @conn.protocol == Stomp::SPL_10
@conn.subscribe dest
else
sh = {}
@conn.subscribe dest, sh, @conn.uuid()
end
@messages.each do |abody|
@conn.publish dest, abody
msg = @conn.receive
assert_instance_of Stomp::Message , msg, "type check for #{abody}"
assert_equal abody, msg.body, "equal check for #{abody}"
end
end
# All possible byte values
def test_0020_kcode
#
abody = ""
"\000".upto("\377") {|abyte| abody << abyte }
#
dest = make_destination
if @conn.protocol == Stomp::SPL_10
@conn.subscribe dest
else
sh = {}
@conn.subscribe dest, sh, @conn.uuid()
end
@conn.publish dest, abody
msg = @conn.receive
assert_instance_of Stomp::Message , msg, "type check for #{abody}"
assert_equal abody, msg.body, "equal check for #{abody}"
end
# A single byte at a time
def test_0030_kcode
#
dest = make_destination
if @conn.protocol == Stomp::SPL_10
@conn.subscribe dest
else
sh = {:id => @conn.uuid()}
@conn.subscribe dest, sh
end
#
"\000".upto("\377") do |abody|
@conn.publish dest, abody
msg = @conn.receive
assert_instance_of Stomp::Message , msg, "type check for #{abody}"
assert_equal abody, msg.body, "equal check for #{abody}"
end
end
# Test various valid and invalid frames.
def test_0040_msg_create
#
assert_raise(Stomp::Error::InvalidFormat) {
_ = Stomp::Message.new("junk", false)
}
#
assert_raise(Stomp::Error::InvalidFormat) {
_ = Stomp::Message.new("command\njunk", false)
}
#
assert_raise(Stomp::Error::InvalidFormat) {
_ = Stomp::Message.new("command\nheaders\n\njunk", false)
}
#
assert_raise(Stomp::Error::InvalidServerCommand) {
_ = Stomp::Message.new("junkcommand\nheaders\n\njunk\0\n\n", false)
}
#
assert_raise(Stomp::Error::InvalidFormat) {
_ = Stomp::Message.new("ERROR\nbadheaders\n\njunk\0\n\n", false)
}
#
_ = Stomp::Message.new("CONNECTED\nh1:val1\n\njunk\0\n", false)
_ = Stomp::Message.new("MESSAGE\nh1:val1\n\njunk\0\n", false)
_ = Stomp::Message.new("MESSAGE\nh2:val2\n\n\0", false)
_ = Stomp::Message.new("RECEIPT\nh1:val1\n\njunk\0\n", false)
_ = Stomp::Message.new("ERROR\nh1:val1\n\njunk\0\n", false)
end
# Test multiple headers with the same key
def test_0050_mh_msg_create
aframe = bframe = nil
amsg = "MESSAGE\n" +
"h1:val1\n" +
"h2:val3\n" +
"h2:val2\n" +
"h2:val1\n" +
"h3:val1\n" +
"\n" +
"payload" +
"\0\n"
aframe = Stomp::Message.new(amsg, false)
bframe = Stomp::Message.new(amsg, true)
#
assert aframe.headers["h2"].is_a?(String), "Expected a String"
assert_equal "val3", aframe.headers["h2"], "Expected 1st value"
#
assert bframe.headers["h2"].is_a?(Array), "Expected an Array"
assert_equal 3, bframe.headers["h2"].length, "Expected 3 values"
assert_equal "val3", bframe.headers["h2"][0], "Expected val3"
assert_equal "val2", bframe.headers["h2"][1], "Expected val2"
assert_equal "val1", bframe.headers["h2"][2], "Expected val1"
end
# Test headers with empty key / value
def test_0060_hdr_ekv
#
amsg = "MESSAGE\n" +
"h1:val1\n" +
":val3\n" +
"h2:val2\n" +
"\n" +
"payload" +
"\0\n"
assert_raise Stomp::Error::ProtocolErrorEmptyHeaderKey do
_ = Stomp::Message.new(amsg, false)
end
assert_raise Stomp::Error::ProtocolErrorEmptyHeaderKey do
_ = Stomp::Message.new(amsg, true)
end
#
amsg = "MESSAGE\n" +
"h1:val1\n" +
"h2:val3\n" +
"h3:\n" +
"\n" +
"payload" +
"\0\n"
assert_raise Stomp::Error::ProtocolErrorEmptyHeaderValue do
_ = Stomp::Message.new(amsg, false)
end
_ = Stomp::Message.new(amsg, true)
end
end
stomp-1.4.4/test/test_codec.rb 0000644 0000041 0000041 00000007320 13120662775 016345 0 ustar www-data www-data # -*- encoding: utf-8 -*-
if Kernel.respond_to?(:require_relative)
require_relative("test_helper")
else
$:.unshift(File.dirname(__FILE__))
require 'test_helper'
end
=begin
Main class for testing Stomp::HeadreCodec methods.
=end
class TestCodec < Test::Unit::TestCase
include TestBase
def setup
@conn = get_connection()
# Data for multi_thread tests
@max_threads = 20
@max_msgs = 100
end
def teardown
@conn.disconnect if @conn.open? # allow tests to disconnect
end
# Test that the codec does nothing to strings that do not need encoding.
def test_1000_check_notneeded
test_data = [
"a",
"abcdefghijklmnopqrstuvwxyz",
"ªºÀÁ",
"AÇBØCꞇDẼ",
"ªºÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ" +
"ĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġDŽDždžLJLjǼǽǾǿȀȁȂȃȌȍȒɰɵɲɮᴘᴤᴭᴥᵻᶅ" +
"ᶑṆṌṕṽẄẂỚỘⅱⅲꜨꝐꞂ",
]
#
test_data.each do |s|
#
s_decoded_a = Stomp::HeaderCodec::decode(s)
assert_equal s, s_decoded_a, "Sanity check decode: #{s} | #{s_decoded_a}"
s_reencoded = Stomp::HeaderCodec::encode(s_decoded_a)
assert_equal s_decoded_a, s_reencoded, "Sanity check reencode: #{s_decoded_a} | #{s_reencoded}"
#
end
end
# Test the basic encoding / decoding requirements.
def test_1010_basic_encode_decode
test_data = [
[ "\\\\\\\\", "\\\\" ], # [encoded, decoded]
[ "\\\\", "\\" ], # [encoded, decoded]
["\\n", "\n"],
["\\r", "\r"],
["\\c", ":"],
["\\\\\\n\\c", "\\\n:"],
["\\\\\\r\\c", "\\\r:"],
["\\c\\n\\\\", ":\n\\"],
["\\c\\r\\\\", ":\r\\"],
["\\\\\\c", "\\:"],
["c\\cc", "c:c"],
["n\\nn", "n\nn"],
["r\\rr", "r\rr"],
]
#
test_data.each do |s|
encoded_orig = s[0]
decoded_orig = s[1]
# Part 1
s_decoded_a = Stomp::HeaderCodec::decode(encoded_orig)
assert_equal decoded_orig, s_decoded_a, "Sanity check decode: #{decoded_orig} | #{s_decoded_a}"
#
s_encoded_a = Stomp::HeaderCodec::encode(decoded_orig)
assert_equal encoded_orig, s_encoded_a, "Sanity check encode: #{encoded_orig} | #{s_encoded_a}"
# Part 2
s_decoded_b = Stomp::HeaderCodec::decode(s_encoded_a)
assert_equal decoded_orig, s_decoded_b, "Sanity check 2 decode: #{decoded_orig} | #{s_decoded_b}"
#
s_encoded_b = Stomp::HeaderCodec::encode(s_decoded_a)
assert_equal encoded_orig, s_encoded_b, "Sanity check 2 encode: #{encoded_orig} | #{s_encoded_b}"
end
end
# Test more complex strings with the codec.
def test_1020_fancier
test_data = [
[ "a\\\\b", "a\\b" ], # [encoded, decoded]
[ "\\\\\\n\\c", "\\\n:" ],
[ "\\\\\\r\\c", "\\\r:" ],
[ "\\rr\\\\\\n\\c", "\rr\\\n:" ],
]
#
test_data.each do |s|
encoded_orig = s[0]
decoded_orig = s[1]
# Part 1
s_decoded_a = Stomp::HeaderCodec::decode(encoded_orig)
assert_equal decoded_orig, s_decoded_a, "Sanity check decode: #{decoded_orig} | #{s_decoded_a}"
#
s_encoded_a = Stomp::HeaderCodec::encode(decoded_orig)
assert_equal encoded_orig, s_encoded_a, "Sanity check encode: #{encoded_orig} | #{s_encoded_a}"
# Part 2
s_decoded_b = Stomp::HeaderCodec::decode(s_encoded_a)
assert_equal decoded_orig, s_decoded_b, "Sanity check 2 decode: #{decoded_orig} | #{s_decoded_b}"
#
s_encoded_b = Stomp::HeaderCodec::encode(s_decoded_a)
assert_equal encoded_orig, s_encoded_b, "Sanity check 2 encode: #{encoded_orig} | #{s_encoded_b}"
end
end
end # of class
stomp-1.4.4/test/funcs.sh 0000755 0000041 0000041 00000000122 13120662775 015352 0 ustar www-data www-data # ------------------------------------------------------------------------------
stomp-1.4.4/test/test_anonymous.rb 0000644 0000041 0000041 00000032654 13120662775 017330 0 ustar www-data www-data # -*- encoding: utf-8 -*-
if Kernel.respond_to?(:require_relative)
require_relative("test_helper")
else
$:.unshift(File.dirname(__FILE__))
require 'test_helper'
end
=begin
Main class for testing Stomp::Connection instances with anonymous logins.
=end
class TestAnonymous < Test::Unit::TestCase
include TestBase
def setup
@conn = get_anonymous_connection()
# Data for multi_thread tests
@max_threads = 20
@max_msgs = 100
end
def teardown
@conn.disconnect if @conn.open? # allow tests to disconnect
end
# Test basic connection creation.
def test_connection_exists
assert_not_nil @conn
end
# Test asynchronous polling.
def test_poll_async
sq = ENV['STOMP_ARTEMIS'] ? "jms.queue.queue.do.not.put.messages.on.this.queue" :
"/queue/do.not.put.messages.on.this.queue"
@conn.subscribe(sq, :id => "a.no.messages.queue")
# If the test 'hangs' here, Connection#poll is broken.
m = @conn.poll
assert m.nil?
end
# Test suppression of content length header.
def test_no_length
conn_subscribe make_destination
#
@conn.publish make_destination, "test_stomp#test_no_length",
{ :suppress_content_length => true }
msg = @conn.receive
assert_equal "test_stomp#test_no_length", msg.body
#
@conn.publish make_destination, "test_stomp#test_\000_length",
{ :suppress_content_length => true }
msg2 = @conn.receive
assert_equal "test_stomp#test_", msg2.body
checkEmsg(@conn)
end unless ENV['STOMP_RABBIT']
# Test direct / explicit receive.
def test_explicit_receive
conn_subscribe make_destination
@conn.publish make_destination, "test_stomp#test_explicit_receive"
msg = @conn.receive
assert_equal "test_stomp#test_explicit_receive", msg.body
end
# Test asking for a receipt.
def test_receipt
conn_subscribe make_destination, :receipt => "abc"
msg = @conn.receive
assert_equal "abc", msg.headers['receipt-id']
checkEmsg(@conn)
end
# Test asking for a receipt on disconnect.
def test_disconnect_receipt
@conn.disconnect :receipt => "abc123"
assert_not_nil(@conn.disconnect_receipt, "should have a receipt")
assert_equal(@conn.disconnect_receipt.headers['receipt-id'],
"abc123", "receipt sent and received should match")
end
# Test ACKs for Stomp 1.0
def test_client_ack_with_symbol_10
if @conn.protocol != Stomp::SPL_10
assert true
return
end
queue = make_destination()
@conn.subscribe queue, :ack => :client
@conn.publish queue, "test_stomp#test_client_ack_with_symbol_10"
msg = @conn.receive
# ACK has one required header, message-id, which must contain a value
# matching the message-id for the MESSAGE being acknowledged.
@conn.ack msg.headers['message-id']
checkEmsg(@conn)
end
# Test ACKs for Stomp 1.1
def test_client_ack_with_symbol_11
if @conn.protocol != Stomp::SPL_11
assert true
return
end
sid = @conn.uuid()
queue = make_destination()
@conn.subscribe queue, :ack => :client, :id => sid
@conn.publish queue, "test_stomp#test_client_ack_with_symbol_11"
msg = @conn.receive
# ACK has two REQUIRED headers: message-id, which MUST contain a value
# matching the message-id for the MESSAGE being acknowledged and
# subscription, which MUST be set to match the value of the subscription's
# id header.
@conn.ack msg.headers['message-id'], :subscription => msg.headers['subscription']
checkEmsg(@conn)
end
# Test ACKs for Stomp 1.2
def test_client_ack_with_symbol_12
if @conn.protocol != Stomp::SPL_12
assert true
return
end
sid = @conn.uuid()
queue = make_destination()
@conn.subscribe queue, :ack => :client, :id => sid
@conn.publish queue, "test_stomp#test_client_ack_with_symbol_11"
msg = @conn.receive
# The ACK frame MUST include an id header matching the ack header
# of the MESSAGE being acknowledged.
@conn.ack msg.headers['ack']
checkEmsg(@conn)
end
# Test a message with 0x00 embedded in the body.
def test_embedded_null
conn_subscribe make_destination
@conn.publish make_destination, "a\0"
msg = @conn.receive
assert_equal "a\0" , msg.body
checkEmsg(@conn)
end
# Test connection open checking.
def test_connection_open?
assert_equal true , @conn.open?
@conn.disconnect
assert_equal false, @conn.open?
end
# Test connection closed checking.
def test_connection_closed?
assert_equal false, @conn.closed?
@conn.disconnect
assert_equal true, @conn.closed?
end
# Test that methods detect a closed connection.
def test_closed_checks_conn
@conn.disconnect
#
assert_raise Stomp::Error::NoCurrentConnection do
@conn.ack("dummy_data")
end
#
assert_raise Stomp::Error::NoCurrentConnection do
@conn.begin("dummy_data")
end
#
assert_raise Stomp::Error::NoCurrentConnection do
@conn.commit("dummy_data")
end
#
assert_raise Stomp::Error::NoCurrentConnection do
@conn.abort("dummy_data")
end
#
assert_raise Stomp::Error::NoCurrentConnection do
conn_subscribe("dummy_data")
end
#
assert_raise Stomp::Error::NoCurrentConnection do
@conn.unsubscribe("dummy_data")
end
#
assert_raise Stomp::Error::NoCurrentConnection do
@conn.publish("dummy_data","dummy_data")
end
#
assert_raise Stomp::Error::NoCurrentConnection do
@conn.unreceive("dummy_data")
end
#
assert_raise Stomp::Error::NoCurrentConnection do
@conn.disconnect("dummy_data")
end
#
assert_raise Stomp::Error::NoCurrentConnection do
_ = @conn.receive
end
#
assert_raise Stomp::Error::NoCurrentConnection do
_ = @conn.poll
end
end
# Test that we receive a Stomp::Message.
def test_response_is_instance_of_message_class
conn_subscribe make_destination
@conn.publish make_destination, "a\0"
msg = @conn.receive
assert_instance_of Stomp::Message , msg
checkEmsg(@conn)
end
# Test converting a Message to a string.
def test_message_to_s
conn_subscribe make_destination
@conn.publish make_destination, "a\0"
msg = @conn.receive
assert_match(/^ max_sleep
sleep sleep_incr
end
assert_equal @max_msgs, msg_ctr
checkEmsg(@conn)
end unless RUBY_ENGINE =~ /jruby/
# Test polling with multiple threads.
def test_multi_thread_poll
#
lock = Mutex.new
msg_ctr = 0
dest = make_destination
#
1.upto(@max_threads) do |tnum|
Thread.new(@conn) do |amq|
while true
received = amq.poll
if received
lock.synchronize do
msg_ctr += 1
end
# Simulate message processing
sleep 0.05
else
# Wait a bit for more work
sleep 0.05
end
end
end
end
#
conn_subscribe( dest )
1.upto(@max_msgs) do |mnum|
msg = Time.now.to_s + " #{mnum}"
@conn.publish(dest, msg)
end
#
max_sleep = (RUBY_VERSION =~ /1\.8\.6/) ? 30 : 5
max_sleep = 30 if RUBY_ENGINE =~ /mingw/
sleep_incr = 0.10
total_slept = 0
while true
break if @max_msgs == msg_ctr
total_slept += sleep_incr
break if total_slept > max_sleep
sleep sleep_incr
end
assert_equal @max_msgs, msg_ctr
checkEmsg(@conn)
end unless RUBY_ENGINE =~ /jruby/
# Test using a nil body.
def test_nil_body
dest = make_destination
@conn.publish dest, nil
conn_subscribe dest
msg = @conn.receive
assert_equal "", msg.body
checkEmsg(@conn)
end
# Test transaction message sequencing.
def test_transaction
conn_subscribe make_destination
@conn.begin "txA"
@conn.publish make_destination, "txn message", 'transaction' => "txA"
@conn.publish make_destination, "first message"
msg = @conn.receive
assert_equal "first message", msg.body
@conn.commit "txA"
msg = @conn.receive
assert_equal "txn message", msg.body
checkEmsg(@conn)
end unless ENV['STOMP_ARTEMIS'] # See Artemis docs for 1.3, page 222
# Test duplicate subscriptions.
def test_duplicate_subscription
@conn.disconnect # not reliable
@conn = Stomp::Connection.open(nil, nil, host, port, true, nil, nil) # reliable
dest = make_destination
conn_subscribe dest
#
assert_raise Stomp::Error::DuplicateSubscription do
conn_subscribe dest
end
checkEmsg(@conn)
end
# Test nil 1.1 connection parameters.
def test_nil_connparms
@conn.disconnect
#
@conn = Stomp::Connection.open(nil, nil, host, port, false, 5, nil)
checkEmsg(@conn)
end
# Basic NAK test.
def test_nack11p_0010
if @conn.protocol == Stomp::SPL_10
assert_raise Stomp::Error::UnsupportedProtocolError do
@conn.nack "dummy msg-id"
end
else
dest = make_destination
smsg = "test_stomp#test_nack01: #{Time.now.to_f}"
@conn.publish dest, smsg
#
sid = @conn.uuid()
@conn.subscribe dest, :ack => :client, :id => sid
msg = @conn.receive
assert_equal smsg, msg.body
case @conn.protocol
when Stomp::SPL_12
@conn.nack msg.headers["ack"]
sleep 0.05 # Give racy brokers a chance to handle the last nack before unsubscribe
@conn.unsubscribe dest, :id => sid
else # Stomp::SPL_11
@conn.nack msg.headers["message-id"], :subscription => sid
sleep 0.05 # Give racy brokers a chance to handle the last nack before unsubscribe
@conn.unsubscribe dest, :id => sid
end
# phase 2
teardown()
setup()
sid = @conn.uuid()
@conn.subscribe dest, :ack => :auto, :id => sid
msg2 = @conn.receive
assert_equal smsg, msg2.body
checkEmsg(@conn)
end
end unless (ENV['STOMP_AMQ11'] || ENV['STOMP_ARTEMIS'])
# Test to illustrate Issue #44. Prior to a fix for #44, these tests would
# fail only when connecting to a pure STOMP 1.0 server that does not
# return a 'version' header at all.
def test_conn10_simple
@conn.disconnect
#
vhost = ENV['STOMP_RABBIT'] ? "/" : host
hash = { :hosts => [
{:host => host, :port => port, :ssl => false},
],
:connect_headers => {"accept-version" => "1.0", "host" => vhost},
:reliable => false,
}
c = nil
c = Stomp::Connection.new(hash)
c.disconnect if c
#
hash = { :hosts => [
{:host => host, :port => port, :ssl => false},
],
:connect_headers => {"accept-version" => "3.14159,1.0,12.0", "host" => vhost},
:reliable => false,
}
c = nil
c = Stomp::Connection.new(hash)
c.disconnect if c
end
# test JRuby detection
def test_jruby_presence
if defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/
assert @conn.jruby
else
assert !@conn.jruby
end
end
end
stomp-1.4.4/test/test_connection1p.rb 0000644 0000041 0000041 00000026441 13120662775 017675 0 ustar www-data www-data # -*- encoding: utf-8 -*-
if Kernel.respond_to?(:require_relative)
require_relative("test_helper")
else
$:.unshift(File.dirname(__FILE__))
require 'test_helper'
end
=begin
Main class for testing Stomp::Connection instances, protocol levels 1.1+.
=end
class TestConnection1P < Test::Unit::TestCase
include TestBase
def setup
@conn = get_connection()
end
def teardown
@conn.disconnect if @conn.open? # allow tests to disconnect
end
# Test basic connection open.
def test_conn_1p_0000
assert @conn.open?
end
# Test missing connect headers - part 1.
def test_conn_1p_0010
@conn.disconnect
#
cha = {:host => "localhost"}
assert_raise Stomp::Error::ProtocolErrorConnect do
_ = Stomp::Connection.open(user, passcode, host, port, false, 5, cha)
end
#
chb = {"accept-version" => "1.0"}
assert_raise Stomp::Error::ProtocolErrorConnect do
_ = Stomp::Connection.open(user, passcode, host, port, false, 5, chb)
end
end
# Test missing connect headers - part 2.
def test_conn_1p_0015
@conn.disconnect
#
cha = {:host => "localhost"}
hash = { :hosts => [
{:login => user, :passcode => passcode, :host => host, :port => port, :ssl => nil},
],
:reliable => true, # Note, issue #57 discussion
:connect_headers => cha,
:stompconn => get_stomp_conn(),
:usecrlf => get_crlf(),
:initial_reconnect_delay => 0.1,
:max_reconnect_delay => 30,
:use_exponential_back_off => true,
:back_off_multiplier => 2,
:max_reconnect_attempts => 10,
}
assert_raise Stomp::Error::ProtocolErrorConnect do
_ = Stomp::Connection.open(hash)
end
hash[:connect_headers] = {"accept-version" => "1.1"}
assert_raise Stomp::Error::ProtocolErrorConnect do
_ = Stomp::Connection.open(hash)
end
end
# Test requesting only a 1.0 connection.
def test_conn_1p_0020
@conn.disconnect
#
cha = {:host => "localhost", "accept-version" => "1.0"}
cha[:host] = "/" if ENV['STOMP_RABBIT']
conn = nil
conn = Stomp::Connection.open(user, passcode, host, port, false, 5, cha)
conn.disconnect
assert_equal conn.protocol, Stomp::SPL_10
end
# Test requesting only a 1.1+ connection.
def test_conn_1p_0030
@conn.disconnect
#
cha = get_conn_headers()
conn = nil
conn = Stomp::Connection.open(user, passcode, host, port, false, 5, cha)
conn.disconnect
assert conn.protocol >= Stomp::SPL_11
end
# Test basic request for no heartbeats.
def test_conn_1p_0040
@conn.disconnect
#
cha = get_conn_headers()
cha["heart-beat"] = "0,0" # No heartbeats
conn = nil
conn = Stomp::Connection.open(user, passcode, host, port, false, 5, cha)
conn.disconnect
assert conn.protocol >= Stomp::SPL_11
end
# Test malformed heartbeat header.
def test_conn_1p_0050
@conn.disconnect
#
cha = get_conn_headers()
cha["heart-beat"] = "10,10,20" # Bad header Heartbeats
conn = nil
assert_raise Stomp::Error::InvalidHeartBeatHeaderError do
conn = Stomp::Connection.open(user, passcode, host, port, false, 5, cha)
end
end
# Test malformed heartbeat header.
def test_conn_11h_0060
@conn.disconnect
#
cha = get_conn_headers()
cha["heart-beat"] = "a,10" # Bad header Heartbeats
conn = nil
assert_raise Stomp::Error::InvalidHeartBeatHeaderError do
conn = Stomp::Connection.open(user, passcode, host, port, false, 5, cha)
end
end
# Test a valid heartbeat header.
def test_conn_1p_0070
@conn.disconnect
#
cha = get_conn_headers()
cha["heart-beat"] = "500,1000" # Valid heart beat headers
conn = nil
conn = Stomp::Connection.open(user, passcode, host, port, false, 5, cha)
conn.disconnect
assert conn.hbsend_interval > 0
assert conn.hbrecv_interval > 0
end
# Test only sending heartbeats.
def test_conn_1p_0080
@conn.disconnect
#
cha = get_conn_headers()
cha["heart-beat"] = "10000,0" # Valid heart beat headers, send only
conn = nil
logger = Tlogger.new
conn = Stomp::Connection.open(user, passcode, host, port, false, 5, cha)
conn.set_logger(logger)
sleep 65
conn.set_logger(nil)
conn.disconnect
hb_asserts_send(conn)
end if ENV['STOMP_HB11LONG']
# Test only receiving heartbeats.
def test_conn_1p_0090
@conn.disconnect
#
cha = get_conn_headers()
cha["heart-beat"] = "0,6000" # Valid heart beat headers, receive only
conn = nil
logger = Tlogger.new
conn = Stomp::Connection.open(user, passcode, host, port, false, 5, cha)
# m = conn.receive # This will hang forever .....
conn.set_logger(logger)
sleep 65
conn.set_logger(nil)
conn.disconnect
hb_asserts_recv(conn)
end if ENV['STOMP_HB11LONG']
# Test sending and receiving heartbeats.
def test_conn_1p_0100
@conn.disconnect
#
cha = get_conn_headers()
cha["heart-beat"] = "5000,10000" # Valid heart beat headers, send and receive
conn = nil
logger = Tlogger.new
conn = Stomp::Connection.open(user, passcode, host, port, false, 5, cha)
# m = conn.receive # This will hang forever .....
conn.set_logger(logger)
sleep 65
conn.set_logger(nil)
conn.disconnect
hb_asserts_both(conn)
end if ENV['STOMP_HB11LONG']
# Test valid UTF8 data.
def test_conn_1p_0110
@conn.disconnect
#
cha = get_conn_headers()
cha["heart-beat"] = "0,0" # No heartbeats
conn = nil
conn = Stomp::Connection.open(user, passcode, host, port, false, 5, cha)
good_data = [
"\x41\xc3\xb1\x42",
"\xc2\x80", # 2 byte characters
"\xc2\xbf",
"\xdf\x80",
"\xdf\xbf",
"\xe0\xa0\x80", # 3 byte characters
"\xe0\xbf\x80",
"\xe0\xa0\xbf",
"\xe0\xbf\xbf",
"\xf1\x80\x80\x80", # 4 byte characters
"\xf1\xbf\xbf\xbf",
"\xf2\x80\x80\x80",
"\xf2\xbf\xbf\xbf",
"\xf3\x80\x80\x80",
"\xf3\xbf\xbf\xbf",
]
good_data.each do |string|
assert conn.valid_utf8?(string), "good unicode specs 01: #{string}"
end
conn.disconnect
end
# Test invalid UTF8 data.
def test_conn_1p_0120
@conn.disconnect
#
cha = get_conn_headers()
cha["heart-beat"] = "0,0" # No heartbeats
conn = nil
conn = Stomp::Connection.open(user, passcode, host, port, false, 5, cha)
bad_data = [
"\x41\xc2\xc3\xb1\x42",
"\xed\xa0\x80", # UTF-16 surrogate halves
"\xed\xad\xbf",
"\xed\xae\x80",
"\xed\xaf\xbf",
"\xed\xb0\x80",
"\xed\xbe\x80",
"\xed\xbf\xbf",
"\xc0", # Single bytes
"\xc1",
"\xf5","\xf6","\xf7","\xf8","\xf9","\xfa","\xfb","\xfc",
"\xfd","\xfe","\xff",
"\xc0\x80", # Not shortest representation
"\xc1\x80",
"\xc0\x30",
"\xc1\x30",
"\xe0\x80\x80",
"\xf0\x80\x80\x80",
]
bad_data.each do |string|
assert !conn.valid_utf8?(string), "bad unicode specs 01: #{string}"
end
conn.disconnect
end
# Repeated headers test. Brokers have a lot of freedom given the verbiage
# in the specs.
def test_conn_1p_0124
dest = make_destination
msg = "payload: #{Time.now.to_f}"
shdrs = { "key1" => "val1", "key2" => "val2",
"key3" => ["kv3", "kv2", "kv1"] }
@conn.publish dest, msg, shdrs
#
sid = @conn.uuid()
@conn.subscribe dest, :id => sid
#
received = @conn.receive
assert_equal msg, received.body
if @conn.protocol != Stomp::SPL_10
assert_equal shdrs["key3"], received.headers["key3"] unless ENV['STOMP_RABBIT'] || ENV['STOMP_AMQ11'] || ENV['STOMP_ARTEMIS']
else
assert_equal "kv3", received.headers["key3"]
end
#
@conn.unsubscribe dest, :id => sid
end
# Test frozen headers.
def test_conn_1p_0127
dest = make_destination
sid = @conn.uuid()
sid.freeze
@conn.subscribe dest, :id => sid
end
# Test heartbeats with send and receive.
def test_conn_1p_0130
@conn.disconnect
#
cha = get_conn_headers()
cha["heart-beat"] = "10000,6000" # Valid heart beat headers, send and receive
conn = nil
logger = Tlogger.new
conn = Stomp::Connection.open(user, passcode, host, port, false, 5, cha)
# m = conn.receive # This will hang forever .....
conn.set_logger(logger)
sleep 65
conn.set_logger(nil)
conn.disconnect
hb_asserts_both(conn)
end if ENV['STOMP_HB11LONG']
# Test heartbeats with send and receive.
def test_conn_1p_0135
@conn.disconnect
#
cha = get_conn_headers()
cha["heart-beat"] = "10000,1000" # Valid heart beat headers, send and receive
conn = nil
logger = Tlogger.new
conn = Stomp::Connection.open(user, passcode, host, port, false, 5, cha)
# m = conn.receive # This will hang forever .....
conn.set_logger(logger)
sleep 65
conn.set_logger(nil)
conn.disconnect
hb_asserts_both(conn)
end if ENV['STOMP_HB11LONG']
# Test heartbeats with send and receive.
def test_conn_1p_0140
@conn.disconnect
#
cha = get_conn_headers()
cha["heart-beat"] = "1000,10000" # Valid heart beat headers, send and receive
conn = nil
logger = Tlogger.new
conn = Stomp::Connection.open(user, passcode, host, port, false, 5, cha)
# m = conn.receive # This will hang forever .....
conn.set_logger(logger)
sleep 65
conn.set_logger(nil)
conn.disconnect
hb_asserts_both(conn)
end if ENV['STOMP_HB11LONG']
# Test very basic encoding / decoding of headers
def test_conn_1p_0200
@conn.disconnect
#
cha = get_conn_headers()
conn = Stomp::Connection.open(user, passcode, host, port, false, 5, cha)
msg = "payload: #{Time.now.to_f}"
dest = make_destination
shdrs = { "ab:cd" => "ef:gh", "a\nb" => "c\nd", "x\\y" => "z\\s" }
if conn.protocol >= Stomp::SPL_12
shdrs["bb\rcc"] = "dd\ree"
end
conn.publish dest, msg, shdrs
#
sid = conn.uuid()
conn.subscribe dest, :id => sid
#
received = conn.receive
assert_equal msg, received.body
#
shdrs.each_pair {|k,v|
assert received.headers.has_key?(k), "Key not found: #{k}"
assert received.headers.has_value?(v), "Value not found: #{v}"
assert received.headers[k] == v, "Mismatch: #{k},#{v}"
}
conn.disconnect
end unless ENV['STOMP_RABBIT']
# Test that 1.1+ connections do not break suppress_content_length
# (Issue #52)
def test_conn_1p_0210
msg = "payload: #{Time.now.to_f}"
dest = make_destination
shdrs = { :suppress_content_length => true }
@conn.publish dest, msg, shdrs
#
sid = @conn.uuid()
@conn.subscribe dest, :id => sid
#
received = @conn.receive
assert_equal msg, received.body
assert_nil received.headers["content-length"], "No content length expected."
end if ENV['STOMP_AMQ11']
private
def hb_asserts_both(conn)
assert conn.hbsend_interval > 0
assert conn.hbrecv_interval > 0
assert conn.hbsend_count > 0
assert conn.hbrecv_count > 0
end
def hb_asserts_send(conn)
assert conn.hbsend_interval > 0
assert conn.hbrecv_interval == 0
assert conn.hbsend_count > 0
assert conn.hbrecv_count == 0
end
def hb_asserts_recv(conn)
assert conn.hbsend_interval == 0
assert conn.hbrecv_interval > 0
assert conn.hbsend_count == 0
assert conn.hbrecv_count > 0
end
end if ENV['STOMP_TEST11p']
stomp-1.4.4/test/test_helper.rb 0000644 0000041 0000041 00000013634 13120662775 016554 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'test/unit'
require 'timeout'
if Kernel.respond_to?(:require_relative)
require_relative("../lib/stomp")
require_relative("tlogger")
else
$:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
require 'stomp'
require 'tlogger'
end
begin
_ = RUBY_ENGINE
rescue NameError
RUBY_ENGINE = "unknown"
end
=begin
Test helper methods.
=end
module TestBase
# Get user
def user
ENV['STOMP_USER'] || "guest"
end
# Gete passcode
def passcode
ENV['STOMP_PASSCODE'] || "guest"
end
# Get host
def host
ENV['STOMP_HOST'] || "localhost"
end
# Get port
def port
(ENV['STOMP_PORT'] || 61613).to_i
end
# Get SSL port
def ssl_port
(ENV['STOMP_SSLPORT'] || 61612).to_i
end
# Helper for minitest on 1.9
def caller_method_name
parse_caller(caller(2).first).last
end
# Helper for minitest on 1.9
def parse_caller(at)
if /^(.+?):(\d+)(?::in `(.*)')?/ =~ at
file = Regexp.last_match[1]
line = Regexp.last_match[2].to_i
method = Regexp.last_match[3]
method.gsub!(" ","_")
[file, line, method]
end
end
# Get a Stomp Connection.
def get_connection()
ch = get_conn_headers()
hash = { :hosts => [
{:login => user, :passcode => passcode, :host => host, :port => port, :ssl => nil},
],
:reliable => false,
:connect_headers => ch,
:stompconn => get_stomp_conn(),
:usecrlf => get_crlf(),
}
conn = Stomp::Connection.open(hash)
conn
end
# Get a Stomp Anonymous Connection.
def get_anonymous_connection()
ch = get_conn_headers()
hash = { :hosts => [
{:host => host, :port => port, :ssl => nil},
],
:reliable => false,
:connect_headers => ch,
:stompconn => get_stomp_conn(),
:usecrlf => get_crlf(),
}
conn = Stomp::Connection.open(hash)
conn
end
# Get a Stomp SSL Connection.
def get_ssl_connection()
ch = get_conn_headers()
ssl_params = Stomp::SSLParams.new(:use_ruby_ciphers => jruby?())
hash = { :hosts => [
{:login => user, :passcode => passcode, :host => host, :port => ssl_port, :ssl => ssl_params},
],
:connect_headers => ch,
:stompconn => get_stomp_conn(),
:usecrlf => get_crlf(),
}
conn = Stomp::Connection.new(hash)
conn
end
# Get a Stomp Client.
def get_client()
hash = { :hosts => [
{:login => user, :passcode => passcode, :host => host, :port => port},
],
:connect_headers => get_conn_headers(),
:stompconn => get_stomp_conn(),
:usecrlf => get_crlf(),
}
client = Stomp::Client.new(hash)
client
end
# Get a connection headers hash.
def get_conn_headers()
ch = {}
if ENV['STOMP_TEST11p']
#
raise "Invalid 1.1 plus test protocol" if ENV['STOMP_TEST11p'] == Stomp::SPL_10
#
if Stomp::SUPPORTED.index(ENV['STOMP_TEST11p'])
ch['accept-version'] = ENV['STOMP_TEST11p']
else
ch['accept-version'] = Stomp::SPL_11 # Just use 1.1
end
#
ch['host'] = ENV['STOMP_RABBIT'] ? "/" : host
end
ch
end
# Determine if tests should use STOMP instead of CONNECT
def get_stomp_conn()
usc = false
usc = true if ENV['STOMP_TEST11p'] && Stomp::SUPPORTED.index(ENV['STOMP_TEST11p']) && ENV['STOMP_TEST11p'] >= Stomp::SPL_11 && ENV['STOMP_CONN']
usc
end
# Determine if tests should \r\n as line ends
def get_crlf()
ucr = false
ucr = true if ENV['STOMP_TEST11p'] && Stomp::SUPPORTED.index(ENV['STOMP_TEST11p']) && ENV['STOMP_TEST11p'] >= Stomp::SPL_12 && ENV['STOMP_CRLF']
ucr
end
# Subscribe to a destination.
def conn_subscribe(dest, headers = {})
if @conn.protocol >= Stomp::SPL_11
headers[:id] = @conn.uuid() unless headers[:id]
end
@conn.subscribe dest, headers
end
# Get a dynamic destination name.
def make_destination
name = caller_method_name unless name
case
when ENV['STOMP_DOTQUEUE']
qname = "/queue/test.ruby.stomp." + name
when ENV['STOMP_ARTEMIS']
qname = "jms.queue.queue.test.ruby.stomp." + name
else
qname = "/queue/test/ruby/stomp/" + name
end
return qname
end
# get DLQ name
def make_dlq
return "jms.queue.DLQ" if ENV['STOMP_ARTEMIS']
"/queue/DLQ"
end
#
def checkEmsg(cc)
m = cc.poll
if m
assert m.command != Stomp::CMD_ERROR, "checkEmsg"
end
end
# Check for JRuby before a connection exists
def jruby?()
jr = defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/ ? true : false
return jr
end
# OK Data For Default Tests
def dflt_data_ok()
[
#
{ :hosts => [
{:login => 'guest', :passcode => 'guest', :host => "localhost", :port => 61613, :ssl => false},
],
:reliable => false,
},
#
{ :hosts => [
{:login => 'guest', :passcode => 'guest', :ssl => false},
],
:reliable => false,
},
#
{ :hosts => [
{:login => 'guest', :passcode => 'guest', :port => 61613, :ssl => false},
],
:reliable => false,
},
#
{ :hosts => [
{:login => 'guest', :passcode => 'guest', :host => "localhost" , :ssl => false},
],
:reliable => false,
},
#
{ :hosts => [
{:login => 'guest', :passcode => 'guest', :host => '' , :ssl => false},
],
:reliable => false,
},
]
end
# Exception Data For Default Tests
def dflt_data_ex()
[
{},
{:hosts => 123},
{ :hosts => [
{:login => 'guest', :passcode => 'guest', :host => "localhost", :port => '' , :ssl => false},
],
:reliable => false,
},
{ :hosts => [
{:login => 'guest', :passcode => 'guest', :host => "localhost", :port => -1 , :ssl => false},
],
:reliable => false,
},
]
end
end
stomp-1.4.4/test/.gitignore 0000644 0000041 0000041 00000000016 13120662775 015667 0 ustar www-data www-data #
1method.rb
stomp-1.4.4/test/tlogger.rb 0000644 0000041 0000041 00000003737 13120662775 015704 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require 'logger' # use the standard Ruby logger .....
=begin
Callback logger for Stomp 1.1+ heartbeat tests.
See the examples directory for a more robust logger example.
=end
class Tlogger
# Initialize a callback logger class.
def initialize(init_parms = nil)
puts
@log = Logger::new(STDOUT) # User preference
@log.level = Logger::DEBUG # User preference
@log.info("Logger initialization complete.")
end
# Log miscellaneous errors.
def on_miscerr(parms, errstr)
begin
@log.debug "Miscellaneous Error #{info(parms)}"
@log.debug "Miscellaneous Error String #{errstr}"
rescue
@log.debug "Miscellaneous Error oops"
end
end
# Stomp 1.1+ - heart beat send (transmit) failed
def on_hbwrite_fail(parms, ticker_data)
begin
@log.debug "Hbwritef Parms #{info(parms)}"
@log.debug "Hbwritef Result #{ticker_data.inspect}"
rescue
@log.debug "Hbwritef oops"
end
end
# Stomp 1.1+ - heart beat read (receive) failed
def on_hbread_fail(parms, ticker_data)
begin
@log.debug "Hbreadf Parms #{info(parms)}"
@log.debug "Hbreadf Result #{ticker_data.inspect}"
rescue
@log.debug "Hbreadf oops"
end
end
# Stomp 1.1+ - heart beat thread fires
def on_hbfire(parms, type, firedata)
begin
@log.debug "HBfire #{type} " + "=" * 30
@log.debug "HBfire #{type} Parms #{info(parms)}"
@log.debug "HBfire #{type} Firedata #{firedata.inspect}"
rescue
@log.debug "HBfire #{type} oops"
end
end
private
def info(parms)
#
# Available in the parms Hash:
# parms[:cur_host]
# parms[:cur_port]
# parms[:cur_login]
# parms[:cur_passcode]
# parms[:cur_ssl]
# parms[:cur_recondelay]
# parms[:cur_parseto]
# parms[:cur_conattempts]
# parms[:openstat]
#
"Host: #{parms[:cur_host]}, Port: #{parms[:cur_port]}, Login: #{parms[:cur_login]}, Passcode: #{parms[:cur_passcode]}"
end
end # of class
stomp-1.4.4/test/test_connection.rb 0000644 0000041 0000041 00000041257 13120662775 017436 0 ustar www-data www-data # -*- encoding: utf-8 -*-
if Kernel.respond_to?(:require_relative)
require_relative("test_helper")
else
$:.unshift(File.dirname(__FILE__))
require 'test_helper'
end
=begin
Main class for testing Stomp::Connection instances.
=end
class TestConnection < Test::Unit::TestCase
include TestBase
def setup
@conn = get_connection()
# Data for multi_thread tests
@max_threads = 20
@max_msgs = 100
end
def teardown
@conn.disconnect if @conn.open? # allow tests to disconnect
end
# Test basic connection creation.
def test_connection_exists
assert_not_nil @conn
end
# Test asynchronous polling.
def test_poll_async
sq = ENV['STOMP_ARTEMIS'] ? "jms.queue.queue.do.not.put.messages.on.this.queue" :
"/queue/do.not.put.messages.on.this.queue"
@conn.subscribe(sq, :id => "a.no.messages.queue")
# If the test 'hangs' here, Connection#poll is broken.
m = @conn.poll
assert m.nil?
end
# Test suppression of content length header.
def test_no_length
conn_subscribe make_destination
#
@conn.publish make_destination, "test_stomp#test_no_length",
{ :suppress_content_length => true }
msg = @conn.receive
assert_equal "test_stomp#test_no_length", msg.body
#
@conn.publish make_destination, "test_stomp#test_\000_length",
{ :suppress_content_length => true }
msg2 = @conn.receive
assert_equal "test_stomp#test_", msg2.body
checkEmsg(@conn)
end unless ENV['STOMP_RABBIT']
# Test direct / explicit receive.
def test_explicit_receive
conn_subscribe make_destination
@conn.publish make_destination, "test_stomp#test_explicit_receive"
msg = @conn.receive
assert_equal "test_stomp#test_explicit_receive", msg.body
end
# Test asking for a receipt.
def test_receipt
conn_subscribe make_destination, :receipt => "abc"
msg = @conn.receive
assert_equal "abc", msg.headers['receipt-id']
checkEmsg(@conn)
end
# Test asking for a receipt on disconnect.
def test_disconnect_receipt
@conn.disconnect :receipt => "abc123"
assert_not_nil(@conn.disconnect_receipt, "should have a receipt")
assert_equal(@conn.disconnect_receipt.headers['receipt-id'],
"abc123", "receipt sent and received should match")
end
# Test ACKs for Stomp 1.0
def test_client_ack_with_symbol_10
if @conn.protocol != Stomp::SPL_10
assert true
return
end
queue = make_destination()
@conn.subscribe queue, :ack => :client
@conn.publish queue, "test_stomp#test_client_ack_with_symbol_10"
msg = @conn.receive
# ACK has one required header, message-id, which must contain a value
# matching the message-id for the MESSAGE being acknowledged.
@conn.ack msg.headers['message-id']
checkEmsg(@conn)
end
# Test ACKs for Stomp 1.1
def test_client_ack_with_symbol_11
if @conn.protocol != Stomp::SPL_11
assert true
return
end
sid = @conn.uuid()
queue = make_destination()
@conn.subscribe queue, :ack => :client, :id => sid
@conn.publish queue, "test_stomp#test_client_ack_with_symbol_11"
msg = @conn.receive
# ACK has two REQUIRED headers: message-id, which MUST contain a value
# matching the message-id for the MESSAGE being acknowledged and
# subscription, which MUST be set to match the value of the subscription's
# id header.
@conn.ack msg.headers['message-id'], :subscription => msg.headers['subscription']
checkEmsg(@conn)
end
# Test ACKs for Stomp 1.2
def test_client_ack_with_symbol_12
if @conn.protocol != Stomp::SPL_12
assert true
return
end
sid = @conn.uuid()
queue = make_destination()
@conn.subscribe queue, :ack => :client, :id => sid
@conn.publish queue, "test_stomp#test_client_ack_with_symbol_11"
msg = @conn.receive
# The ACK frame MUST include an id header matching the ack header
# of the MESSAGE being acknowledged.
@conn.ack msg.headers['ack']
checkEmsg(@conn)
end
# Test a message with 0x00 embedded in the body.
def test_embedded_null
conn_subscribe make_destination
@conn.publish make_destination, "a\0"
msg = @conn.receive
assert_equal "a\0" , msg.body
checkEmsg(@conn)
end
# Test connection open checking.
def test_connection_open?
assert_equal true , @conn.open?
@conn.disconnect
assert_equal false, @conn.open?
end
# Test connection closed checking.
def test_connection_closed?
assert_equal false, @conn.closed?
@conn.disconnect
assert_equal true, @conn.closed?
end
# Test that methods detect a closed connection.
def test_closed_checks_conn
@conn.disconnect
#
assert_raise Stomp::Error::NoCurrentConnection do
@conn.ack("dummy_data")
end
#
assert_raise Stomp::Error::NoCurrentConnection do
@conn.begin("dummy_data")
end
#
assert_raise Stomp::Error::NoCurrentConnection do
@conn.commit("dummy_data")
end
#
assert_raise Stomp::Error::NoCurrentConnection do
@conn.abort("dummy_data")
end
#
assert_raise Stomp::Error::NoCurrentConnection do
conn_subscribe("dummy_data")
end
#
assert_raise Stomp::Error::NoCurrentConnection do
@conn.unsubscribe("dummy_data")
end
#
assert_raise Stomp::Error::NoCurrentConnection do
@conn.publish("dummy_data","dummy_data")
end
#
assert_raise Stomp::Error::NoCurrentConnection do
@conn.unreceive("dummy_data")
end
#
assert_raise Stomp::Error::NoCurrentConnection do
@conn.disconnect("dummy_data")
end
#
assert_raise Stomp::Error::NoCurrentConnection do
_ = @conn.receive
end
#
assert_raise Stomp::Error::NoCurrentConnection do
_ = @conn.poll
end
end
# Test that we receive a Stomp::Message.
def test_response_is_instance_of_message_class
conn_subscribe make_destination
@conn.publish make_destination, "a\0"
msg = @conn.receive
assert_instance_of Stomp::Message , msg
checkEmsg(@conn)
end
# Test converting a Message to a string.
def test_message_to_s
conn_subscribe make_destination
@conn.publish make_destination, "a\0"
msg = @conn.receive
assert_match(/^ max_sleep
sleep sleep_incr
end
assert_equal @max_msgs, msg_ctr
checkEmsg(@conn)
end unless RUBY_ENGINE =~ /jruby/
# Test polling with multiple threads.
def test_multi_thread_poll
#
lock = Mutex.new
msg_ctr = 0
dest = make_destination
#
1.upto(@max_threads) do |tnum|
Thread.new(@conn) do |amq|
while true
received = amq.poll
if received
lock.synchronize do
msg_ctr += 1
end
# Simulate message processing
sleep 0.05
else
# Wait a bit for more work
sleep 0.05
end
end
end
end
#
conn_subscribe( dest )
1.upto(@max_msgs) do |mnum|
msg = Time.now.to_s + " #{mnum}"
@conn.publish(dest, msg)
end
#
max_sleep = (RUBY_VERSION =~ /1\.8\.6/) ? 30 : 5
max_sleep = 30 if RUBY_ENGINE =~ /mingw/
sleep_incr = 0.10
total_slept = 0
while true
break if @max_msgs == msg_ctr
total_slept += sleep_incr
break if total_slept > max_sleep
sleep sleep_incr
end
assert_equal @max_msgs, msg_ctr
checkEmsg(@conn)
end unless RUBY_ENGINE =~ /jruby/
# Test using a nil body.
def test_nil_body
dest = make_destination
@conn.publish dest, nil
conn_subscribe dest
msg = @conn.receive
assert_equal "", msg.body
checkEmsg(@conn)
end
# Test transaction message sequencing.
def test_transaction
conn_subscribe make_destination
@conn.begin "txA"
@conn.publish make_destination, "txn message", 'transaction' => "txA"
@conn.publish make_destination, "first message"
msg = @conn.receive
assert_equal "first message", msg.body
@conn.commit "txA"
msg = @conn.receive
assert_equal "txn message", msg.body
checkEmsg(@conn)
end unless ENV['STOMP_ARTEMIS'] # See Artemis docs for 1.3, page 222
# Test duplicate subscriptions.
def test_duplicate_subscription
@conn.disconnect # not reliable
@conn = Stomp::Connection.open(user, passcode, host, port, true) # reliable
dest = make_destination
conn_subscribe dest
#
assert_raise Stomp::Error::DuplicateSubscription do
conn_subscribe dest
end
checkEmsg(@conn)
end
# Test nil 1.1 connection parameters.
def test_nil_connparms
@conn.disconnect
#
@conn = Stomp::Connection.open(user, passcode, host, port, false, 5, nil)
checkEmsg(@conn)
end
# Basic NAK test.
def test_nack11p_0010
if @conn.protocol == Stomp::SPL_10
assert_raise Stomp::Error::UnsupportedProtocolError do
@conn.nack "dummy msg-id"
end
else
dest = make_destination
smsg = "test_stomp#test_nack01: #{Time.now.to_f}"
@conn.publish dest, smsg
#
sid = @conn.uuid()
@conn.subscribe dest, :ack => :client, :id => sid
msg = @conn.receive
assert_equal smsg, msg.body
case @conn.protocol
when Stomp::SPL_12
@conn.nack msg.headers["ack"]
sleep 0.05 # Give racy brokers a chance to handle the last nack before unsubscribe
@conn.unsubscribe dest, :id => sid
else # Stomp::SPL_11
@conn.nack msg.headers["message-id"], :subscription => sid
sleep 0.05 # Give racy brokers a chance to handle the last nack before unsubscribe
@conn.unsubscribe dest, :id => sid
end
# phase 2
teardown()
setup()
sid = @conn.uuid()
@conn.subscribe dest, :ack => :auto, :id => sid
msg2 = @conn.receive
assert_equal smsg, msg2.body
checkEmsg(@conn)
end
end unless (ENV['STOMP_AMQ11'] || ENV['STOMP_ARTEMIS'])
# Test to illustrate Issue #44. Prior to a fix for #44, these tests would
# fail only when connecting to a pure STOMP 1.0 server that does not
# return a 'version' header at all.
def test_conn10_simple
@conn.disconnect
#
vhost = ENV['STOMP_RABBIT'] ? "/" : host
hash = { :hosts => [
{:login => user, :passcode => passcode, :host => host, :port => port, :ssl => false},
],
:connect_headers => {"accept-version" => "1.0", "host" => vhost},
:reliable => false,
}
c = nil
c = Stomp::Connection.new(hash)
c.disconnect if c
#
hash = { :hosts => [
{:login => user, :passcode => passcode, :host => host, :port => port, :ssl => false},
],
:connect_headers => {"accept-version" => "3.14159,1.0,12.0", "host" => vhost},
:reliable => false,
}
c = nil
c = Stomp::Connection.new(hash)
c.disconnect if c
end
# test JRuby detection
def test_jruby_presence
if defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/
assert @conn.jruby
else
assert !@conn.jruby
end
end
# Test that methods detect an empty header key.
def test_empty_header_key
#
bad_headers = {"a" => "11", "" => "emptykey", :c => "ccc"}
#
assert_raise Stomp::Error::ProtocolErrorEmptyHeaderKey do
@conn.ack("dummy_data", bad_headers)
end
#
assert_raise Stomp::Error::ProtocolErrorEmptyHeaderKey do
@conn.nack("dummy_data", bad_headers)
end if @conn.protocol != Stomp::SPL_10
#
assert_raise Stomp::Error::ProtocolErrorEmptyHeaderKey do
@conn.begin("dummy_data", bad_headers)
end
#
assert_raise Stomp::Error::ProtocolErrorEmptyHeaderKey do
@conn.commit("dummy_data", bad_headers)
end
#
assert_raise Stomp::Error::ProtocolErrorEmptyHeaderKey do
@conn.abort("dummy_data", bad_headers)
end
#
assert_raise Stomp::Error::ProtocolErrorEmptyHeaderKey do
@conn.subscribe("dummy_data", bad_headers)
end
#
assert_raise Stomp::Error::ProtocolErrorEmptyHeaderKey do
@conn.unsubscribe("dummy_data", bad_headers)
end
#
assert_raise Stomp::Error::ProtocolErrorEmptyHeaderKey do
@conn.publish("dummy_data","dummy_data", bad_headers)
end
#
assert_raise Stomp::Error::ProtocolErrorEmptyHeaderKey do
@conn.disconnect(bad_headers)
end
end
# Test that methods detect an empty header value.
# STOMP 1.0 only.
def test_empty_header_value
if @conn.protocol != Stomp::SPL_10
assert true
return
end
#
bad_headers = {"a" => "11", "hdra" => "", :c => "ccc"}
#
assert_raise Stomp::Error::ProtocolErrorEmptyHeaderValue do
@conn.ack("dummy_data", bad_headers)
end
#
assert_raise Stomp::Error::ProtocolErrorEmptyHeaderValue do
@conn.nack("dummy_data", bad_headers)
end if @conn.protocol != Stomp::SPL_10
#
assert_raise Stomp::Error::ProtocolErrorEmptyHeaderValue do
@conn.begin("dummy_data", bad_headers)
end
#
assert_raise Stomp::Error::ProtocolErrorEmptyHeaderValue do
@conn.commit("dummy_data", bad_headers)
end
#
assert_raise Stomp::Error::ProtocolErrorEmptyHeaderValue do
@conn.abort("dummy_data", bad_headers)
end
#
assert_raise Stomp::Error::ProtocolErrorEmptyHeaderValue do
@conn.subscribe("dummy_data", bad_headers)
end
#
assert_raise Stomp::Error::ProtocolErrorEmptyHeaderValue do
@conn.unsubscribe("dummy_data", bad_headers)
end
#
assert_raise Stomp::Error::ProtocolErrorEmptyHeaderValue do
@conn.publish("dummy_data","dummy_data", bad_headers)
end
#
assert_raise Stomp::Error::ProtocolErrorEmptyHeaderValue do
@conn.disconnect(bad_headers)
end
end
# test issue99, OK values
def test_con_iss99_ok
return unless host() == "localhost" && port() == 61613
#
ok_vals = dflt_data_ok()
ok_vals.each do |hsv|
conn = Stomp::Connection.new(hsv)
conn.disconnect
end
end
def test_conn_nodest_sub
assert_raise Stomp::Error::DestinationRequired do
@conn.subscribe(nil)
end
end
def test_conn_nodest_unsub
assert_raise Stomp::Error::DestinationRequired do
@conn.unsubscribe(nil)
end
end
def test_conn_nodest_pub
assert_raise Stomp::Error::DestinationRequired do
@conn.publish(nil, "msg")
end
end
end
stomp-1.4.4/stomp.gemspec 0000644 0000041 0000041 00000010301 13120662775 015425 0 ustar www-data www-data # Generated by jeweler
# DO NOT EDIT THIS FILE DIRECTLY
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
# -*- encoding: utf-8 -*-
# stub: stomp 1.4.4 ruby lib
Gem::Specification.new do |s|
s.name = "stomp".freeze
s.version = "1.4.4"
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
s.require_paths = ["lib".freeze]
s.authors = ["Brian McCallister".freeze, "Marius Mathiesen".freeze, "Thiago Morello".freeze, "Guy M. Allard".freeze]
s.date = "2017-06-11"
s.description = "Ruby client for the Stomp messaging protocol. Note that this gem is no longer supported on rubyforge.".freeze
s.email = ["brianm@apache.org".freeze, "marius@stones.com".freeze, "morellon@gmail.com".freeze, "allard.guy.m@gmail.com".freeze]
s.executables = ["catstomp".freeze, "stompcat".freeze]
s.extra_rdoc_files = [
"LICENSE",
"README.md"
]
s.files = [
"CHANGELOG.md",
"LICENSE",
"README.md",
"Rakefile",
"adhoc/.gitignore",
"adhoc/README.md",
"adhoc/issue121_01.rb",
"adhoc/issue121_01_conn.rb",
"adhoc/issue121_02.rb",
"adhoc/issue121_03.rb",
"adhoc/payload_generator.rb",
"adhoc/payload_generator_adhoctest.rb",
"adhoc/stomp_adhoc_common.rb",
"bin/catstomp",
"bin/stompcat",
"examples/amqdurasub.rb",
"examples/artemis/artlogger.rb",
"examples/artemis/cliwaiter_not_reliable.rb",
"examples/artemis/cliwaiter_reliable.rb",
"examples/client11_ex1.rb",
"examples/client11_putget1.rb",
"examples/conn11_ex1.rb",
"examples/conn11_ex2.rb",
"examples/conn11_hb1.rb",
"examples/consume_file.rb",
"examples/consumer.rb",
"examples/contrib.sh",
"examples/contributors.rb",
"examples/examplogger.rb",
"examples/get11conn_ex1.rb",
"examples/get11conn_ex2.rb",
"examples/lflogger.rb",
"examples/logexamp.rb",
"examples/logexamp_ssl.rb",
"examples/publish_file.rb",
"examples/publish_file_conn.rb",
"examples/publisher.rb",
"examples/put11conn_ex1.rb",
"examples/putget11_rh1.rb",
"examples/ssl_common.rb",
"examples/ssl_ctxoptions.rb",
"examples/ssl_newparm.rb",
"examples/ssl_uc1.rb",
"examples/ssl_uc1_ciphers.rb",
"examples/ssl_uc2.rb",
"examples/ssl_uc2_ciphers.rb",
"examples/ssl_uc3.rb",
"examples/ssl_uc3_ciphers.rb",
"examples/ssl_uc4.rb",
"examples/ssl_uc4_ciphers.rb",
"examples/ssl_ucx_default_ciphers.rb",
"examples/stomp11_common.rb",
"examples/topic_consumer.rb",
"examples/topic_publisher.rb",
"lib/client/utils.rb",
"lib/connection/heartbeats.rb",
"lib/connection/netio.rb",
"lib/connection/utf8.rb",
"lib/connection/utils.rb",
"lib/stomp.rb",
"lib/stomp/client.rb",
"lib/stomp/codec.rb",
"lib/stomp/connection.rb",
"lib/stomp/constants.rb",
"lib/stomp/errors.rb",
"lib/stomp/ext/hash.rb",
"lib/stomp/message.rb",
"lib/stomp/null_logger.rb",
"lib/stomp/slogger.rb",
"lib/stomp/sslparams.rb",
"lib/stomp/version.rb",
"notes/heartbeat_readme.txt",
"spec/client_shared_examples.rb",
"spec/client_spec.rb",
"spec/connection_spec.rb",
"spec/message_spec.rb",
"spec/spec_helper.rb",
"stomp.gemspec",
"test/.gitignore",
"test/MultiBrokerUnitTestExample.sh",
"test/funcs.sh",
"test/test_anonymous.rb",
"test/test_client.rb",
"test/test_codec.rb",
"test/test_connection.rb",
"test/test_connection1p.rb",
"test/test_helper.rb",
"test/test_message.rb",
"test/test_ssl.rb",
"test/test_urlogin.rb",
"test/tlogger.rb",
"test/unitst.sh"
]
s.homepage = "https://github.com/stompgem/stomp".freeze
s.licenses = ["Apache-2.0".freeze]
s.rubygems_version = "2.6.11".freeze
s.summary = "Ruby client for the Stomp messaging protocol".freeze
if s.respond_to? :specification_version then
s.specification_version = 4
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
s.add_development_dependency(%q.freeze, [">= 2.14.1", "~> 2.14"])
else
s.add_dependency(%q.freeze, [">= 2.14.1", "~> 2.14"])
end
else
s.add_dependency(%q.freeze, [">= 2.14.1", "~> 2.14"])
end
end
stomp-1.4.4/LICENSE 0000644 0000041 0000041 00000026136 13120662775 013740 0 ustar www-data www-data
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
stomp-1.4.4/CHANGELOG.md 0000644 0000041 0000041 00000030566 13120662775 014546 0 ustar www-data www-data # Stomp Gem Change Log
## 1.4.4 20170611
* Merge fix for issue 141.
* Fix broken MatReconnectAttempts
* Attempt to detect mismatched SSL port and params.
* Issue 139, add ssl checks to receive timeout logic.
* Eliminate assert_nothing_raised from tests.
* Add Artemis suport to standard test bed.
* Run JRuby tests more easily.
## 1.4.3 20160821
* Quick fix of install failures. Do not try to use install 1.4.2.
## 1.4.2 20160820
* Refine SSL examples.
* Address issue #124 with additional RDOC.
* spec for Stomp::Client - check that headers passed to connection contain
required values as well as given custom and that given hash is not modified.
* Stomp::Client now does not modify given headers hash
* spec description enhancement.
* fix build_subscription_id - symbol and string were mixed up.
* STOMP_TESTSSL flag should enable all SSL tests.
* Add a basic Gemfile.
* Fix a memory leak in receipt implementation.
* Add unit test helper script.
## 1.4.1 20160623
* Add call to #post_connection_check to normal SSL processing. This change
further validates the name of the broker connected to. This change adds to
the current SSL connection processing logic, and is **highly recommended**. In the
case a client cannot tolerate this logic, it can be disabled by adding
:ssl_post_conn_check => false to the connection hash.
* Fix typo in SSL failure recovery processing.
## 1.4.0 20160608
* Connection parameter :parse_timeout now means IO:select wait time for socket
reads. Consumer clients should see a significantly reduced memory
footprint. If the default (5 seconds) is not used by your client,
we suggest you test carefully.
* Add example programs for sending / receiving large messages.
* Changelog format is changed from .rdoc to .md.
* README format is changed from .rdoc to .md.
* README format change of contributor's list.
* Add example utilities for generating the contributor's list.
* Eliminate many warnings when using 'rake test', mostly from the 2.x Ruby series.
* Get rakefile up to date.
* Add the 'adhoc' subdirectory, an area for experiments and issue recreation code.
## 1.3.5 20160302
* Add AMQ specific durable topic example.
* Output error to stderr only in logger is undefined.
* Move README changelog lower.
* Handle newline at start of receive buffer.
* Use Timeout::timeout instead of deprecated kernel version.
* If socket open on reconnect, close it before new open.
* On misc_err, make error messages more readable.
* Attempt to support both Rspec 2.14.1+ and 3.x.
## 1.3.4 20141202
* Change :start_timeout default to 0 (might break some clients) (#98).
* Allow user set of SSLContext options (#105).
* Allow user set of parm in SSLContext.new(parm) (#105).
## 1.3.3 20140810
* Do not attempt to write empty message bodies.
* Explicity close ssl socket on connection timeout.
* Fix incorrect behavior for empty header keys (#93)
* Do not override explicit :reliable => false.
* Fix client fail-over fails (#98)
## 1.3.2 20131208
* Anon tests assigned unique class name.
* Fix TypeError on connect timeout with 1.8.x, 2.x.
* Complete revert to previous logger logic.
* start_timeout and tcp_nodelay parameters
* SSL Fix, revert not setting default ciphers.
* Copy hash params at init.
* Fix ssl => true for Ruby 1.9.x and 2.x.
* Expanded list of STOMP default SSL ciphers:
* Do not change caller's :hosts array
* Issue #78, again.
* Clean up logger interfacing.
* Fixes from RSpec testing
## 1.3.1 20131002
* Method calls to the logger object should check for that method first (#83)
## 1.3.0 20130930
* ERROR frames now raise an exception in the Stomp::Client thread(#73, #81)
* Allow anonymous connections (#75)
* Fix for subscription id handling in STOMP 1.1 (#78)
* Added a NullLogger (#77)
* Added :tcp_nodelay option (disable Nagle's algorithm) (#76)
* Read receipt ids are now UUIDs
* Added a :start_timeout parameter
## 1.2.16 20130812
* Stomp::Client's should expose connection's host params
## 1.2.15 20130809
* Add user-specified timeout for initial CONNECTED/ERROR frame read.
* Eliminate dup Timeout::timeout in ssl connect
* Add license information to gemspec (#69)
## 1.2.14 20130819
* Version bump (1.2.13 release had Stomp::Version of 1.1.12.)
* Prevent dup subscription header on re-receive
## 1.2.13 20130817
* Issue #68, Stomp::Client#unreceive max_redeliveries off-by-one error
## 1.2.12 20130811
* Fix infinite loop when max reconn attempts is reached
* Enhance JRuby support in tests
* Issue #63, nil message on rapid AMQ restarts
* Issue #63, fast spurious failovers with JRuby and AMQ
* Issue #67, SSL SNI support (thanks Hiram)
* Proper cleanup when not reliable adn EOF from broker
* Remove extraneous privte declarations
* Issue #65, allow non-word characters in login and passcode using stomp://
* Issue #66, allow a single broker in a failover URL
## 1.2.11 20130728
* Issue #60, timeout/hang under JRuby
* More generally support JRuby use and testing
* Issue #58, nil message in Client on AMQ shutdown
* More robust RabbitMQ tests
## 1.2.10 20130708
* Issue #57, reconnect delays not honored if erroneous headers
* Support fail overs when heartbeat send/receive fails
* Update callback logger example
## 1.2.9 20130328
* Refactoring and documentation updates (glennr)
* Fix test encoding for Ruby 2.0+
* Fixes to tests due to :suppress_content_length fix
* Issue #50 Stomp::Client reconnects fail
* Correctly honor :suppress_content_length with 1.1 (JP Hastings-Spital)
* Fix reference to client.publish rather than client.send (JP Hastings-Spital)
## 1.2.8 20121228
* Fix inverted encode / decode logic (fairly major 1.1+ bug)
* Enhance codec tests
* Enhance Stomp 1.1+ tests
## 1.2.7 20121102
* Stomp 1.2 support (see http://stomp.github.com)
* Reset reconnect_delay to default value upon successful reconnect
* Enhance tests for Stomp 1.2
## 1.2.6 20120913
* Provide ability to eliminate checks for closed in protocol methods
* Cover ssl.connect with connection timeout parameter
* If heartbeat send raises, do not reraise unless client requests that
* Remove methods that invoke __send__
* Move internal methods to 'private'
## 1.2.5 20120804
* Issue #48 any forks with modifications will be affected!
* Source code restructured into individual files
* Common indentation used throughout the source
* Many method comments have been added
* See notes in source regarding making methods private in the next release
* See notes in source regarding removal of methods in the next release
* Include examples and tests in rdoc generated during install
* Issue #47 socket is open during retries
## 1.2.4 20120625
* Add ability for client to request flush on write to the connection (Issue #45)
* Add ability for client to retrieve heartbeat intervals and counters
* Fix I/O errors with heartbeats and multithreaded clients (Issue #46)
* Enhance tests for heartbeats
* Correct typos and clarify comments in many examples
## 1.2.3 20120616
* Fix UnsupportedProtocol on connect to a 1.0 broker
* Add Client#poll method
* Add help to stompcat and catstomp
* Allow password to be set for private SSL key
* Update comments to reflect new repository URL
* Reformat changelog dates to ISO8601
* Fix SSL connection failures using JRuby
* Use symbols, not strings for all header keys
* Add IPV6 to IPV4 failover for dual homed systems when requested
## 1.2.2 20120324
* Major performance improvement for read of messages without content-length header
* Correct Stomp 1.1 failing test
* Update sample code to reflect removal of 'send'
* Add on_ssl_connectfail callback and allow clients to signal quit from the callback
* Ensure that SSL certificates and SSL related files exist and are readable
* Allow SSL file checks before connect using SSLParams.new(:fsck => true, ...)
* Correct a test for Windows compatibility
## 1.2.1 20120313
* Robust SSL certificate support. See examples and: https://github.com/stompgem/stomp/wiki/extended-ssl-overview
* Really remove the deprecated #send methods
* Fix exception in Stomp 1.1 code when headers are frozen
* Revert 245e734a0. See ce8335fb2f for details. Fixes broken Connection#poll.
* Add reconnection attempts to callback logging.
* Add SSL specific connection information to callback logging.
## 1.2.0 20111214
* Stomp 1.1 protocol support. A significant change. Please test existing 1.0 code well. See the examples directory for 1.1 examples.
* Accept :reliable in a Stomp::Client connection hash
* Add connect timeout with hashed parameters
* Do not allow calls after close/disconnect
* Enhance supported logger callbacks
* Fix subscription id in find_listener
* Start to bootstrap STOMP 1.1 support
## 1.1.10 20111107
* Fixes for JRuby support
* Fix EOF error on disconnect
* Refactoring and additional test
* Set up tests for use of RabbitMQ
## 1.1.9 20110615
* Support wildcard destinations
* Handle subscribe with string or symbol ID
* Check for duplicate subscriptions in spec tests
* Support AMQ and Apollo servers in uinit tests
* Correct UTF-8 (Unicode) content-length calcualtion in Ruby 1.9
* Send of a nil body causes exception
* Add optional callback logging. See the examples install directory, files logexamp.rb and slogger.rb
* Correct date stamps in this file
## 1.1.8 20110316
* Set KEEPALIVE on connection socket options
* Attempt to support JRuby more robustly (poll remains broken)
* Switch to ruby supplied IO#ready?
* Test enhancements for suppress_content_length header
* Miscellaneous small documentation updates
* Add parse_timeout parameter for use with hashed logins
* Allow connection to hosts with a - (dash) in the host name
* Add limit parameter to thread joins
## 1.1.7 20110109
* Binary parse of raw STOMP frame
* Fix broken tests on Ruby 1.9.2
## 1.1.6 20100610
* Fixed multi-thread app hanging
## 1.1.5 20100317
* Added publish method (send is now deprecated)
* Changes on Rake File
* Added original_destination header to unreceive
* suppress content length header is send on the message for future handling (like unreceive)
## 1.1.4 20100121
* Added unreceive message method that sends the message back to its queue or to the
dead letter queue, depending on the :max_redeliveries option, similar to a13m one.
* Added environment variable option for running 'rake test' on any stomp server, using any port with any user.
* Added suppress_content_length header option for ActiveMQ knowing it is a text message (see:
http://juretta.com/log/2009/05/24/activemq-jms-stomp/)
* Fixed some bugs with Ruby 1.9 (concatenate string + exception)
* Major changes on message parsing feature
* Fixed bug with old socket not being closed when using failover
* Fixed broken poll method on Connection
* Fixed broken close method on Client
* Added connection_frame accessor
* Added disconnect receipt
## 1.1.3 20091124
* Failover support
* SSL support
* Stomp::Connection and Stomp::Client accept a hash on their constructor
## 1.1 20090227
* Ruby 1.9 Support
* Add support for connect_headers, to control the CONNECT command.
* Refactored lib dir to separate concerns.
* Better test coverage
* General code cleanup.
## 1.0.6 20080805
* Whitespace cleanup
* Refactored Rakefile and added stomp.gemspec for GitHub friendliness.
* Added .gitignore file
* Refactored layout of lib dir to separate concerns
* Cleanup of initializers, and provide Client accessors for reading values (for testing)
* Removed test/test_url_* files as they only differed from the test_client.rb in their
setup. Super UnDry. Added URL tests to cover stomp URL as param.
* Created initial RSpec specs which stub/mock objects and should not require a running
Stomp server instance.
## v1.0.5 20070201
* better url parsing
* git-svn-id: http://svn.codehaus.org/stomp/ruby/trunk@48 fd4e7336-3dff-0310-b68a-b6615a75f13b
## v1.0.4 20070115
* Allow URL style connections descriptors
* git-svn-id: http://svn.codehaus.org/stomp/ruby/trunk@44 fd4e7336-3dff-0310-b68a-b6615a75f13b
## v1.0.3 20070114
* Additional fixes for reliable by Andrew Kuklewicz
* git-svn-id: http://svn.codehaus.org/stomp/ruby/trunk@42 fd4e7336-3dff-0310-b68a-b6615a75f13b
## v1.0.2 20060922
* Moving ruby so we can tag it ;-)
* git-svn-id: http://svn.codehaus.org/stomp/ruby/trunk@37 fd4e7336-3dff-0310-b68a-b6615a75f13b
## v1.0.1 20051217
* Increment version
* git-svn-id: http://svn.codehaus.org/stomp/trunk/ruby@24 fd4e7336-3dff-0310-b68a-b6615a75f13b
## v1.0.0 20051015
* works in repl, getting messages in weird order or dupes in test, but unable to isolate so far #(
* git-svn-id: http://svn.codehaus.org/stomp/trunk/ruby@20 fd4e7336-3dff-0310-b68a-b6615a75f13b
stomp-1.4.4/README.md 0000644 0000041 0000041 00000047675 13120662775 014225 0 ustar www-data www-data # README
* [Project Information](https://github.com/stompgem/stomp)
## Overview
An implementation of the Stomp protocol for Ruby. See:
* [STOMP 1.0, 1.1, and 1.2] (http://stomp.github.com/index.html)
## Hash Login Example Usage (**this is the recommended login technique**):
```
hash = {
:hosts => [
# First connect is to remotehost1
{:login => "login1", :passcode => "passcode1", :host => "remotehost1", :port => 61612, :ssl => true},
# First failover connect is to remotehost2
{:login => "login2", :passcode => "passcode2", :host => "remotehost2", :port => 61613, :ssl => false},
],
# These are the default parameters and do not need to be set
:reliable => true, # reliable (use failover)
:initial_reconnect_delay => 0.01, # initial delay before reconnect (secs)
:max_reconnect_delay => 30.0, # max delay before reconnect
:use_exponential_back_off => true, # increase delay between reconnect attpempts
:back_off_multiplier => 2, # next delay multiplier
:max_reconnect_attempts => 0, # retry forever, use # for maximum attempts
:randomize => false, # do not radomize hosts hash before reconnect
:connect_timeout => 0, # Timeout for TCP/TLS connects, use # for max seconds
:connect_headers => {}, # user supplied CONNECT headers (req'd for Stomp 1.1+)
:parse_timeout => 5, # IO::select wait time on socket reads
:logger => nil, # user suplied callback logger instance
:dmh => false, # do not support multihomed IPV4 / IPV6 hosts during failover
:closed_check => true, # check first if closed in each protocol method
:hbser => false, # raise on heartbeat send exception
:stompconn => false, # Use STOMP instead of CONNECT
:usecrlf => false, # Use CRLF command and header line ends (1.2+)
:max_hbread_fails => 0, # Max HB read fails before retry. 0 => never retry
:max_hbrlck_fails => 0, # Max HB read lock obtain fails before retry. 0 => never retry
:fast_hbs_adjust => 0.0, # Fast heartbeat senders sleep adjustment, seconds, needed ...
# For fast heartbeat senders. 'fast' == YMMV. If not
# correct for your environment, expect unnecessary fail overs
:connread_timeout => 0, # Timeout during CONNECT for read of CONNECTED/ERROR, secs
:tcp_nodelay => true, # Turns on the TCP_NODELAY socket option; disables Nagle's algorithm
:start_timeout => 0, # Timeout around Stomp::Client initialization
:sslctx_newparm => nil, # Param for SSLContext.new
:ssl_post_conn_check => true, # Further verify broker identity
}
# for a client
client = Stomp::Client.new(hash)
# for a connection
connection = Stomp::Connection.new(hash)
```
### Positional Parameter Usage:
```
client = Stomp::Client.new("user", "pass", "localhost", 61613)
client.publish("/queue/mine", "hello world!")
client.subscribe("/queue/mine") do |msg|
p msg
end
```
### Stomp URL Usage:
A Stomp URL must begin with 'stomp://' and can be in one of the following forms:
```
stomp://host:port
stomp://host.domain.tld:port
stomp://login:passcode@host:port
stomp://login:passcode@host.domain.tld:port
# e.g. c = Stomp::Client.new(urlstring)
```
### Failover + SSL Example URL Usage:
```
options = "initialReconnectDelay=5000&randomize=false&useExponentialBackOff=false"
# remotehost1 uses SSL, remotehost2 doesn't
client = Stomp::Client.new("failover:(stomp+ssl://login1:passcode1@remotehost1:61612,stomp://login2:passcode2@remotehost2:61613)?#{options}")
client.publish("/queue/mine", "hello world!")
client.subscribe("/queue/mine") do |msg|
p msg
end
```
### New:
See _CHANGELOG.rdoc_ for details.
* Gem version 1.4.4. Miscellaneous fixes, see CHANGELOG.rdoc for details.
* Gem version 1.4.3. Fix broken install. Do not try to install 1.4.2.
* Gem version 1.4.2. Fix memory leak, and others !: see CHANGELOG.md for details.
* Gem version 1.4.1. Important SSL changes !: see CHANGELOG.md for details.
* Gem version 1.4.0. Note: Change sementics of :parse_timeout, see CHANGELOG.md for details.
* Gem version 1.3.5. Miscellaneous fixes, see CHANGELOG.rdoc for details.
* Gem version 1.3.4. Miscellaneous fixes, see CHANGELOG.rdoc for details.
* Gem version 1.3.3. Miscellaneous fixes, see CHANGELOG.rdoc for details.
* Gem version 1.3.2. Miscellaneous fixes, see changelog for details.
* Gem version 1.3.1. Bugfix for logging.
* Gem version 1.3.0. Added ERROR frame raising as exception, added anonymous connections, miscellaneous other fixes.
For changes in older versions see CHANGELOG.rdoc for details.
### Historical Information:
Up until March 2009 the project was maintained and primarily developed by Brian McCallister.
### Source Code and Project URLs:
[Source Code and Project](https://github.com/stompgem/stomp)
### Stomp Protocol Information:
[Protocol Information](http://stomp.github.com/index.html)
#### Contributors (by first author date) ####
Contribution information: