nchan_tools 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/CODE_OF_CONDUCT.md +7 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +3 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/nchan-benchmark +214 -0
- data/exe/nchan-pub +96 -0
- data/exe/nchan-sub +139 -0
- data/lib/nchan_tools/pubsub.rb +1897 -0
- data/lib/nchan_tools/version.rb +3 -0
- data/lib/nchan_tools.rb +5 -0
- data/nchan_tools.gemspec +43 -0
- metadata +258 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 03c7684cee5fb57143e8411351aea95d4bcb989cf8f2d66ebe716655f8f07b09
|
4
|
+
data.tar.gz: ed22f3cdd7eb55acab2ad29684daacd4e09edf0a3ffda1c4e2d5309affa896f3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3009d9a05e5f8d6d81302cf81389be78ef165621fd433fd08beb1d16d0dcba5fa7cbcc6dd56a83a86a6d4756dcd609fa33136031bb4a50077f0d811405aef0ce
|
7
|
+
data.tar.gz: cae127fd3166e2442625f3a177e6060561fb8fb0056dc63cc14f03b89404c80a87e1cfd9ee2ed3a0078f91e6665c4b090492f257e5e308368af1cff32a0e23c1
|
data/.gitignore
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
In the spirit of inclusiveness, cooperation and community, this software is
|
2
|
+
distributed with the strictly enforced CYHTFYW Code of Conduct. Failure to
|
3
|
+
comply with this code may result in punitive action and loss of privilege.
|
4
|
+
|
5
|
+
## CYHTFYW Code of Conduct:
|
6
|
+
|
7
|
+
1. Conduct yourself however the fuck you want.
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018 Leo Ponomarev
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "nchan_tools"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/exe/nchan-benchmark
ADDED
@@ -0,0 +1,214 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'securerandom'
|
4
|
+
require 'nchan_tools/pubsub'
|
5
|
+
require "optparse"
|
6
|
+
require 'timers'
|
7
|
+
require 'json'
|
8
|
+
require "pry"
|
9
|
+
require "HDRHistogram"
|
10
|
+
|
11
|
+
verbose = false
|
12
|
+
|
13
|
+
opt_parser=OptionParser.new do |opts|
|
14
|
+
opts.on("-v", "--verbose", "somewhat rather extraneously wordful output") do
|
15
|
+
verbose = true
|
16
|
+
end
|
17
|
+
end
|
18
|
+
opt_parser.banner="Usage: benchan.rb [options] url1 url2 url3..."
|
19
|
+
opt_parser.parse!
|
20
|
+
|
21
|
+
urls = []
|
22
|
+
urls += ARGV
|
23
|
+
begin
|
24
|
+
urls += STDIN.read_nonblock(100000).split /\s*\n+\s*/
|
25
|
+
rescue IO::WaitReadable
|
26
|
+
end
|
27
|
+
|
28
|
+
urls.uniq!
|
29
|
+
|
30
|
+
class Benchan
|
31
|
+
def initialize(urls)
|
32
|
+
@urls = urls
|
33
|
+
@n = urls.count
|
34
|
+
@initializing = 0
|
35
|
+
@ready = 0
|
36
|
+
@running = 0
|
37
|
+
@finished = 0
|
38
|
+
@subs = []
|
39
|
+
@results = {}
|
40
|
+
@failed = {}
|
41
|
+
|
42
|
+
@hdrh_publish = nil
|
43
|
+
@hdrh_receive = nil
|
44
|
+
|
45
|
+
subs = []
|
46
|
+
end
|
47
|
+
|
48
|
+
def run
|
49
|
+
puts "connecting to #{@n} Nchan server#{@n > 1 ? "s" : ""}..."
|
50
|
+
@urls.each do |url|
|
51
|
+
sub = Subscriber.new(url, 1, client: :websocket, timeout: 900000, extra_headers: {"Accept" => "text/x-json-hdrhistogram"})
|
52
|
+
sub.on_failure do |err|
|
53
|
+
unless @results[sub]
|
54
|
+
unless @results[sub.url]
|
55
|
+
@failed[sub] = true
|
56
|
+
abort err, sub
|
57
|
+
end
|
58
|
+
end
|
59
|
+
false
|
60
|
+
end
|
61
|
+
sub.on_message do |msg|
|
62
|
+
msg = msg.to_s
|
63
|
+
case msg
|
64
|
+
when "READY"
|
65
|
+
puts " #{sub.url} ok"
|
66
|
+
@ready +=1
|
67
|
+
if @ready == @n
|
68
|
+
control :run
|
69
|
+
puts "start benchmark..."
|
70
|
+
end
|
71
|
+
when "RUNNING"
|
72
|
+
puts " #{sub.url} running"
|
73
|
+
when /^RESULTS\n/
|
74
|
+
msg = msg[8..-1]
|
75
|
+
parsed = JSON.parse msg
|
76
|
+
@results[sub.url] = parsed
|
77
|
+
1+1
|
78
|
+
else
|
79
|
+
binding.pry
|
80
|
+
1+1
|
81
|
+
end
|
82
|
+
end
|
83
|
+
@subs << sub
|
84
|
+
sub.run
|
85
|
+
sub.wait :ready, 1
|
86
|
+
if @failed[sub]
|
87
|
+
puts " #{sub.url} failed"
|
88
|
+
else
|
89
|
+
puts " #{sub.url} ok"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
return if @failed.count > 0
|
93
|
+
puts "initializing benchmark..."
|
94
|
+
control :initialize
|
95
|
+
self.wait
|
96
|
+
puts "finished."
|
97
|
+
puts ""
|
98
|
+
end
|
99
|
+
|
100
|
+
def wait
|
101
|
+
@subs.each &:wait
|
102
|
+
end
|
103
|
+
|
104
|
+
def control(msg)
|
105
|
+
@subs.each { |sub| sub.client.send_data msg.to_s }
|
106
|
+
end
|
107
|
+
|
108
|
+
def abort(err, src_sub = nil)
|
109
|
+
puts " #{err}"
|
110
|
+
@subs.each do |sub|
|
111
|
+
sub.terminate unless sub == src_sub
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def hdrhistogram_stats(name, histogram)
|
116
|
+
fmt = <<-END.gsub(/^ {6}/, '')
|
117
|
+
%s
|
118
|
+
min: %.3fms
|
119
|
+
avg: %.3fms
|
120
|
+
99%%ile: %.3fms
|
121
|
+
max: %.3fms
|
122
|
+
stddev: %.3fms
|
123
|
+
samples: %d
|
124
|
+
END
|
125
|
+
fmt % [ name,
|
126
|
+
histogram.min, histogram.mean, histogram.percentile(99.0), histogram.max, histogram.stddev, histogram.count
|
127
|
+
]
|
128
|
+
end
|
129
|
+
|
130
|
+
def results
|
131
|
+
channels = 0
|
132
|
+
runtime = []
|
133
|
+
subscribers = 0
|
134
|
+
message_length = []
|
135
|
+
messages_sent = 0
|
136
|
+
messages_send_confirmed = 0
|
137
|
+
messages_send_unconfirmed = 0
|
138
|
+
messages_send_failed = 0
|
139
|
+
messages_received = 0
|
140
|
+
messages_unreceived = 0
|
141
|
+
hdrh_publish = nil
|
142
|
+
hdrh_receive = nil
|
143
|
+
@results.each do |url, data|
|
144
|
+
channels += data["channels"]
|
145
|
+
runtime << data["run_time_sec"]
|
146
|
+
subscribers += data["subscribers"]
|
147
|
+
message_length << data["message_length"]
|
148
|
+
messages_sent += data["messages"]["sent"]
|
149
|
+
messages_send_confirmed += data["messages"]["send_confirmed"]
|
150
|
+
messages_send_unconfirmed += data["messages"]["send_unconfirmed"]
|
151
|
+
messages_send_failed += data["messages"]["send_failed"]
|
152
|
+
messages_received += data["messages"]["received"]
|
153
|
+
messages_unreceived += data["messages"]["unreceived"]
|
154
|
+
|
155
|
+
if data["message_publishing_histogram"]
|
156
|
+
hdrh = HDRHistogram.unserialize(data["message_publishing_histogram"], unit: :ms, multiplier: 0.001)
|
157
|
+
if hdrh_publish
|
158
|
+
hdrh_publish.merge! hdrh
|
159
|
+
else
|
160
|
+
hdrh_publish = hdrh
|
161
|
+
end
|
162
|
+
end
|
163
|
+
if data["message_delivery_histogram"]
|
164
|
+
hdrh = HDRHistogram.unserialize(data["message_delivery_histogram"], unit: :ms, multiplier: 0.001)
|
165
|
+
if hdrh_receive
|
166
|
+
hdrh_receive.merge! hdrh
|
167
|
+
else
|
168
|
+
hdrh_receive = hdrh
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
message_length.uniq!
|
174
|
+
runtime.uniq!
|
175
|
+
|
176
|
+
fmt = <<-END.gsub(/^ {6}/, '')
|
177
|
+
Nchan servers: %d
|
178
|
+
runtime: %s
|
179
|
+
channels: %d
|
180
|
+
subscribers: %d
|
181
|
+
subscribers per channel: %.1f
|
182
|
+
messages:
|
183
|
+
length: %s
|
184
|
+
sent: %d
|
185
|
+
send_confirmed: %d
|
186
|
+
send_unconfirmed: %d
|
187
|
+
send_failed: %d
|
188
|
+
received: %d
|
189
|
+
unreceived: %d
|
190
|
+
send rate: %.3f/sec
|
191
|
+
receive rate: %.3f/sec
|
192
|
+
send rate per channel: %.3f/min
|
193
|
+
receive rate per subscriber: %.3f/min
|
194
|
+
END
|
195
|
+
out = fmt % [
|
196
|
+
@n, runtime.join(","), channels, subscribers, subscribers.to_f/channels,
|
197
|
+
message_length.join(","), messages_sent, messages_send_confirmed, messages_send_unconfirmed, messages_send_failed,
|
198
|
+
messages_received, messages_unreceived,
|
199
|
+
messages_sent.to_f/runtime.max,
|
200
|
+
messages_received.to_f/runtime.max,
|
201
|
+
(messages_sent.to_f* 60)/(runtime.max*channels),
|
202
|
+
(messages_received.to_f * 60)/(runtime.max * subscribers)
|
203
|
+
]
|
204
|
+
|
205
|
+
out << hdrhistogram_stats("message publishing latency", hdrh_publish) if hdrh_publish
|
206
|
+
out << hdrhistogram_stats("message delivery latency", hdrh_receive) if hdrh_receive
|
207
|
+
|
208
|
+
puts out
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
benchan = Benchan.new urls
|
213
|
+
benchan.run
|
214
|
+
benchan.results
|
data/exe/nchan-pub
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'securerandom'
|
3
|
+
require 'nchan_tools/pubsub'
|
4
|
+
require "optparse"
|
5
|
+
server= "localhost:8082"
|
6
|
+
msg=false
|
7
|
+
loop=false
|
8
|
+
repeat_sec=0.5
|
9
|
+
content_type=nil
|
10
|
+
eventsource_event=nil
|
11
|
+
msg_gen = false
|
12
|
+
on_response=Proc.new {}
|
13
|
+
method=:POST
|
14
|
+
runonce=false
|
15
|
+
accept = nil
|
16
|
+
timeout = 3
|
17
|
+
verbose = nil
|
18
|
+
url=nil
|
19
|
+
websocket = nil
|
20
|
+
|
21
|
+
opt=OptionParser.new do |opts|
|
22
|
+
opts.on("-s", "--server SERVER (#{server})", "server and port.") {|v| server=v}
|
23
|
+
opts.on("--url FULL_URL", "publishing url") {|v| url=v}
|
24
|
+
opts.on("-v", "--verbose", "Blabberhttp"){verbose=true}
|
25
|
+
opts.on("-l", "--loop [SECONDS]", "re-send message every N seconds (#{repeat_sec})") do |v|
|
26
|
+
loop=true
|
27
|
+
repeat_sec=Float(v) unless v.nil?
|
28
|
+
end
|
29
|
+
opts.on("-M", "--method [#{method}]", "method for request to server"){|v| method= v.upcase.to_sym}
|
30
|
+
opts.on("-m", "--message MSG", "publish this message instead of prompting"){|v| msg=v}
|
31
|
+
opts.on("-1", "--once", "run once then exit"){runonce=true}
|
32
|
+
opts.on("-a", "--accept TYPE", "set Accept header"){|v| accept=v}
|
33
|
+
opts.on("-c", "--content-type TYPE", "set content-type for all messages"){|v| content_type=v}
|
34
|
+
opts.on( "--eventsource_event EVENT", "event: line for eversource subscribers"){|v| eventsource_event=v}
|
35
|
+
opts.on("-e", "--eval RUBY_BLOCK", '{|n| "message #{n}" }'){|v| msg_gen = eval " Proc.new #{v} "}
|
36
|
+
opts.on("-w", "--websocket", "user websocket to publish"){websocket = true}
|
37
|
+
opts.on("-d", "--delete", "delete channel via a DELETE request"){method = :DELETE}
|
38
|
+
opts.on("-p", "--put", "create channel without submitting message"){method = :PUT}
|
39
|
+
opts.on("-t", "--timeout SECONDS", "publishing timeout (sec). default #{timeout} sec"){|v| timeout = v.to_i}
|
40
|
+
opts.on("-r", "--response", 'Show response code and body') do
|
41
|
+
on_response = Proc.new do |code, body|
|
42
|
+
puts code
|
43
|
+
puts body
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
opt.banner="Usage: pub.rb [options] url"
|
48
|
+
opt.parse!
|
49
|
+
|
50
|
+
url ||= "http://#{server}#{ARGV.last}"
|
51
|
+
|
52
|
+
puts "Publishing to #{url}."
|
53
|
+
|
54
|
+
|
55
|
+
loopmsg=("\r"*20) + "sending message #"
|
56
|
+
|
57
|
+
pub = Publisher.new url, nostore: true, timeout: timeout, verbose: verbose, websocket: websocket
|
58
|
+
pub.accept=accept
|
59
|
+
pub.nofail=true
|
60
|
+
repeat=true
|
61
|
+
i=1
|
62
|
+
if loop then
|
63
|
+
puts "Press enter to send message."
|
64
|
+
end
|
65
|
+
while repeat do
|
66
|
+
if msg or msg_gen
|
67
|
+
if loop
|
68
|
+
sleep repeat_sec
|
69
|
+
print "#{loopmsg} #{i}"
|
70
|
+
elsif !runonce
|
71
|
+
STDIN.gets
|
72
|
+
end
|
73
|
+
if msg
|
74
|
+
pub.submit msg, method, content_type, eventsource_event, &on_response
|
75
|
+
elsif msg_gen
|
76
|
+
this_msg = msg_gen.call(i).to_s
|
77
|
+
puts this_msg
|
78
|
+
pub.submit this_msg, method, content_type, eventsource_event, &on_response
|
79
|
+
end
|
80
|
+
else
|
81
|
+
if loop
|
82
|
+
puts "Can't repeat with custom message. use -m option"
|
83
|
+
end
|
84
|
+
puts "Enter message, press enter twice."
|
85
|
+
message = ""
|
86
|
+
while((line = STDIN.gets) != "\n") do #doesn't work when there are parameters. wtf?
|
87
|
+
message << line
|
88
|
+
end
|
89
|
+
message=message[0..-2] #remove trailing newline
|
90
|
+
|
91
|
+
pub.submit message, method, content_type, eventsource_event, &on_response
|
92
|
+
puts ""
|
93
|
+
end
|
94
|
+
i+=1
|
95
|
+
exit 0 if runonce
|
96
|
+
end
|
data/exe/nchan-sub
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'securerandom'
|
4
|
+
require 'nchan_tools/pubsub'
|
5
|
+
require "optparse"
|
6
|
+
require 'timers'
|
7
|
+
|
8
|
+
server= "localhost:8082"
|
9
|
+
par=1
|
10
|
+
|
11
|
+
opt = {
|
12
|
+
timeout: 60,
|
13
|
+
quit_message: 'FIN',
|
14
|
+
client: :longpoll,
|
15
|
+
extra_headers: nil,
|
16
|
+
nostore: true,
|
17
|
+
http2: false
|
18
|
+
}
|
19
|
+
|
20
|
+
no_message=false
|
21
|
+
print_content_type = false
|
22
|
+
show_id=false
|
23
|
+
origin = nil
|
24
|
+
|
25
|
+
permessage_deflate = false
|
26
|
+
ws_meta_subprotocol = false
|
27
|
+
|
28
|
+
url = nil
|
29
|
+
sub = nil
|
30
|
+
|
31
|
+
opt_parser=OptionParser.new do |opts|
|
32
|
+
opts.on("-s", "--server SERVER (#{server})", "server and port."){|v| server=v}
|
33
|
+
opts.on("-p", "--parallel NUM (#{par})", "number of parallel clients"){|v| par = v.to_i}
|
34
|
+
opts.on("-t", "--timeout SEC (#{opt[:timeout]})", "Long-poll timeout"){|v| opt[:timeout] = v}
|
35
|
+
opts.on("-q", "--quit STRING (#{opt[:quit_message]})", "Quit message"){|v| opt[:quit_message] = v}
|
36
|
+
opts.on("-c", "--client STRING (#{opt[:client]})", "sub client (one of #{Subscriber::Client.unique_aliases.join ', '})") do |v|
|
37
|
+
opt[:client] = v.to_sym
|
38
|
+
end
|
39
|
+
opts.on("--content-type", "show received content-type"){|v| print_content_type = true}
|
40
|
+
opts.on("-i", "--id", "Print message id (last-modified and etag headers)."){|v| show_id = true}
|
41
|
+
opts.on("-n", "--no-message", "Don't output retrieved message."){|v| no_message = true}
|
42
|
+
opts.on("--origin STR", "Set Origin header if appplicable."){|v| origin = v}
|
43
|
+
opts.on("--url URL", "full subscriber url") do |v|
|
44
|
+
url = v
|
45
|
+
end
|
46
|
+
opts.on("--http2", "use HTTP/2"){opt[:http2] = true}
|
47
|
+
|
48
|
+
opts.on("--websocket-permessage-deflate", "Try to use the websocket permessage-deflate extension."){opt[:permessage_deflate]=true}
|
49
|
+
opts.on("--websocket-permessage-deflate-max-window-bits NUM", "max-window-bits permessage-deflate setting") {|n|opt[:permessage_deflate_max_window_bits]=n.to_i}
|
50
|
+
opts.on("--websocket-permessage-deflate-server-max-window-bits NUM", "server-max-window-bits permessage-deflate setting") {|n|opt[:permessage_deflate_server_max_window_bits]=n.to_i}
|
51
|
+
opts.on("--websocket-meta-subprotocol", "Use the ws+meta.nchan websocket subprotocol"){opt[:subprotocol]="ws+meta.nchan"}
|
52
|
+
|
53
|
+
opts.on("-v", "--verbose", "somewhat rather extraneously wordful output") do
|
54
|
+
opt[:verbose] = true
|
55
|
+
Typhoeus::Config.verbose=true
|
56
|
+
end
|
57
|
+
end
|
58
|
+
opt_parser.banner="Usage: sub.rb [options] url"
|
59
|
+
opt_parser.parse!
|
60
|
+
|
61
|
+
url ||= "#{opt[:http2] ? 'h2' : 'http'}://#{server}#{ARGV.last}"
|
62
|
+
|
63
|
+
puts "Subscribing #{par} #{opt[:client]} client#{par!=1 ? "s":""} to #{url}."
|
64
|
+
puts "Timeout: #{opt[:timeout]}sec, quit msg: #{opt[:quit_message]}"
|
65
|
+
|
66
|
+
if origin
|
67
|
+
opt[:extra_headers] ||= {}
|
68
|
+
opt[:extra_headers]['Origin'] = origin
|
69
|
+
end
|
70
|
+
|
71
|
+
sub = Subscriber.new url, par, opt
|
72
|
+
|
73
|
+
|
74
|
+
NOMSGF="\r"*30 + "Received message %i, len:%i"
|
75
|
+
if no_message
|
76
|
+
class OutputTimer
|
77
|
+
include Celluloid
|
78
|
+
attr_reader :fired, :timer
|
79
|
+
|
80
|
+
def initialize(interval = 0.5)
|
81
|
+
@count = 0
|
82
|
+
@last_msg_length = 0
|
83
|
+
@timer = every(interval) do
|
84
|
+
printf NOMSGF, @count, @last_msg_length
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def incoming(msg)
|
89
|
+
@count += 1
|
90
|
+
@last_msg_length = msg.message.length
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
output_timer = OutputTimer.new
|
95
|
+
end
|
96
|
+
|
97
|
+
sub.on_message do |msg|
|
98
|
+
if no_message
|
99
|
+
output_timer.incoming(msg)
|
100
|
+
else
|
101
|
+
if msg.content_type
|
102
|
+
out = "(#{msg.content_type}) #{msg}"
|
103
|
+
else
|
104
|
+
out = msg.to_s
|
105
|
+
end
|
106
|
+
if show_id
|
107
|
+
out = "<#{msg.id}> #{out}"
|
108
|
+
end
|
109
|
+
puts out
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
sub.on_failure do |err_msg|
|
114
|
+
if Subscriber::IntervalPollClient === sub.client
|
115
|
+
unless err_msg.match(/\(code 304\)/)
|
116
|
+
false
|
117
|
+
end
|
118
|
+
else
|
119
|
+
false
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
sub.run
|
124
|
+
begin
|
125
|
+
sub.wait
|
126
|
+
rescue Interrupt => e
|
127
|
+
#do nothing
|
128
|
+
end
|
129
|
+
|
130
|
+
output_timer.terminate if output_timer
|
131
|
+
|
132
|
+
|
133
|
+
if sub.errors.count > 0
|
134
|
+
puts "Errors:"
|
135
|
+
sub.errors.each do |err|
|
136
|
+
puts err
|
137
|
+
end
|
138
|
+
exit 1
|
139
|
+
end
|