nchan_tools 0.1.7 → 0.1.12
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 +4 -4
- data/exe/nchan-redis-debug +24 -20
- data/lib/nchan_tools/rdsck.rb +135 -4
- data/lib/nchan_tools/version.rb +1 -1
- data/nchan_tools.gemspec +5 -2
- metadata +53 -11
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2c506959c2eba296db96ed5e1598412798117f4e33bae4a909e223148a829b4a
|
|
4
|
+
data.tar.gz: 4f178a9eac6fa954d06b5f9f4d6d21cb5c3e6320390e3f422fdcb0589e5276d9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 183363cebe229289e9c3eb0c0989a2816b7bb06c2f3650a81fdad8b5a22c1a2502bd182081a49bbcdf076d0eef219f0ae8f3ccff6a31252e8a137d1940347231
|
|
7
|
+
data.tar.gz: e5c09c1e6759dd835fb9699a96e63e6d2bbb7ae7adefac324cae19083f0921d3699fc88bdeb54dde4810153ed9cf528d22f9829688c8f9a02fb2f547f507debf
|
data/exe/nchan-redis-debug
CHANGED
|
@@ -4,32 +4,31 @@ require "redis"
|
|
|
4
4
|
require "optparse"
|
|
5
5
|
require 'nchan_tools/rdsck'
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
opt = {
|
|
8
8
|
url: "redis://127.0.0.1:6379/",
|
|
9
9
|
verbose: false,
|
|
10
10
|
command: nil
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
def dbg(...)
|
|
14
|
-
if $opt[:verbose]
|
|
15
|
-
print("# ")
|
|
16
|
-
puts(...)
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
13
|
opt_parser=OptionParser.new do |opts|
|
|
21
|
-
opts.on("--url", "--url REDIS_URL (#{
|
|
22
|
-
|
|
14
|
+
opts.on("--url", "--url REDIS_URL (#{opt[:url]})", "Redis server and port..") do |v|
|
|
15
|
+
opt[:url]=v
|
|
23
16
|
end
|
|
24
17
|
opts.on("-q", "--quiet", "output only results without any other information") do
|
|
25
|
-
|
|
18
|
+
opt[:quiet]=true
|
|
26
19
|
end
|
|
27
20
|
opts.on("--list-channels", "list all Nchan channels on Redis server or cluster") do |v|
|
|
28
|
-
|
|
21
|
+
opt[:command]=:filter_channels
|
|
29
22
|
end
|
|
23
|
+
opts.on("--watch-channels", "watch for changes in Nchan channels on Redis server or cluster") do |v|
|
|
24
|
+
opt[:command]=:watch_channels
|
|
25
|
+
end
|
|
26
|
+
opts.on("--set-notify-keyspace-events", "when using --watch-channels, sets the notify-keyspace-events Redis config before starting. May not be possible if the redis 'config' command is disabled") do
|
|
27
|
+
opt[:set_notify_keyspace_events] = true
|
|
28
|
+
end
|
|
30
29
|
opts.on("--filter-channels-min-subscribers=[NUMBER]") do |v|
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
opt[:command]||=:filter_channels
|
|
31
|
+
opt[:min_subscribers]=v.to_i
|
|
33
32
|
end
|
|
34
33
|
end
|
|
35
34
|
opt_parser.banner= <<~EOB
|
|
@@ -46,18 +45,23 @@ opt_parser.banner= <<~EOB
|
|
|
46
45
|
EOB
|
|
47
46
|
opt_parser.parse!
|
|
48
47
|
|
|
49
|
-
|
|
48
|
+
opt[:verbose] = !opt[:quiet]
|
|
49
|
+
|
|
50
|
+
rdsck = Rdsck.new opt
|
|
50
51
|
if not rdsck.connect
|
|
51
|
-
STDERR.puts "failed to connect to #{
|
|
52
|
+
STDERR.puts "failed to connect to #{opt[:url]}"
|
|
52
53
|
exit 1
|
|
53
54
|
end
|
|
54
55
|
|
|
55
|
-
case
|
|
56
|
+
case opt[:command]
|
|
56
57
|
when :filter_channels
|
|
57
|
-
|
|
58
|
-
chans = rdsck.filter_channels(min_subscribers:
|
|
59
|
-
|
|
58
|
+
rdsck.dbg "scanning for channels #{opt[:min_subscribers] && "with subscribers >= #{opt[:min_subscribers]}"}"
|
|
59
|
+
chans = rdsck.filter_channels(min_subscribers: opt[:min_subscribers])
|
|
60
|
+
rdsck.dbg "found #{chans.count} channel#{chans.count != 1 && "s"}#{chans.count == 0 ? "." : ":"}"
|
|
60
61
|
puts chans.join("\n")
|
|
62
|
+
when :watch_channels
|
|
63
|
+
rdsck.dbg "watching for channels #{opt[:min_subscribers] && "with subscribers >= #{opt[:min_subscribers]}"}"
|
|
64
|
+
rdsck.watch_channels({min_subscribers: opt[:min_subscribers]}, opt[:set_notify_keyspace_events])
|
|
61
65
|
else
|
|
62
66
|
puts "Nothing to do"
|
|
63
67
|
end
|
data/lib/nchan_tools/rdsck.rb
CHANGED
|
@@ -1,10 +1,55 @@
|
|
|
1
1
|
class Rdsck
|
|
2
|
+
require "async"
|
|
3
|
+
require "async/redis"
|
|
4
|
+
|
|
5
|
+
#doesn't support psubscribe by default. can you believe it?!
|
|
6
|
+
class Async::Redis::Context::Psubscribe < Async::Redis::Context::Subscribe
|
|
7
|
+
MESSAGE = 'pmessage'
|
|
8
|
+
|
|
9
|
+
def listen
|
|
10
|
+
while response = @connection.read_response
|
|
11
|
+
return response if response.first == MESSAGE
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def subscribe(channels)
|
|
16
|
+
@connection.write_request ['PSUBSCRIBE', *channels]
|
|
17
|
+
@connection.flush
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def unsubscribe(channels)
|
|
21
|
+
@connection.write_request ['PUNSUBSCRIBE', *channels]
|
|
22
|
+
@connection.flush
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class Async::Redis::Client
|
|
27
|
+
def psubscribe(*channels)
|
|
28
|
+
context = Async::Redis::Context::Psubscribe.new(@pool, channels)
|
|
29
|
+
return context unless block_given?
|
|
30
|
+
begin
|
|
31
|
+
yield context
|
|
32
|
+
ensure
|
|
33
|
+
context.close
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
2
38
|
attr_accessor :url, :verbose, :namespace
|
|
3
39
|
attr_accessor :redis, :masters
|
|
40
|
+
|
|
41
|
+
def dbg(*args)
|
|
42
|
+
if @verbose
|
|
43
|
+
print("# ")
|
|
44
|
+
puts(*args)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
4
48
|
def initialize(opt)
|
|
5
49
|
@url=opt[:url]
|
|
6
50
|
@verbose=opt[:verbose]
|
|
7
51
|
@namespace=opt[:namespace]
|
|
52
|
+
@channel_id=opt[:channel_id]
|
|
8
53
|
end
|
|
9
54
|
|
|
10
55
|
def cluster?
|
|
@@ -13,8 +58,10 @@ class Rdsck
|
|
|
13
58
|
|
|
14
59
|
def connect
|
|
15
60
|
begin
|
|
16
|
-
@redis=Redis.new url:
|
|
61
|
+
@redis=Redis.new url: @url
|
|
62
|
+
|
|
17
63
|
mode = redis.info["redis_mode"]
|
|
64
|
+
|
|
18
65
|
rescue StandardError => e
|
|
19
66
|
STDERR.puts e.message
|
|
20
67
|
return false
|
|
@@ -23,7 +70,7 @@ class Rdsck
|
|
|
23
70
|
if mode == "cluster"
|
|
24
71
|
@redis.close
|
|
25
72
|
begin
|
|
26
|
-
@redis=Redis.new cluster: [
|
|
73
|
+
@redis=Redis.new cluster: [@url]
|
|
27
74
|
@redis.ping
|
|
28
75
|
rescue StandardError => e
|
|
29
76
|
STDERR.puts e.message
|
|
@@ -49,7 +96,7 @@ class Rdsck
|
|
|
49
96
|
end
|
|
50
97
|
|
|
51
98
|
def key(subkey=nil)
|
|
52
|
-
k = "{channel:#{
|
|
99
|
+
k = "{channel:#{@namespace}/#{@channel_id}}"
|
|
53
100
|
return subkey ? "#{k}:#{subkey}" : k
|
|
54
101
|
end
|
|
55
102
|
|
|
@@ -60,6 +107,90 @@ class Rdsck
|
|
|
60
107
|
#...
|
|
61
108
|
end
|
|
62
109
|
|
|
110
|
+
class Watch
|
|
111
|
+
def initialize(rdsck, node, filters, set_notify_config = nil)
|
|
112
|
+
@rdsck = rdsck
|
|
113
|
+
@sync = node
|
|
114
|
+
@filters = filters
|
|
115
|
+
@set_notify_config = set_notify_config
|
|
116
|
+
@host, @port, @location = @sync.connection[:host], @sync.connection[:port]
|
|
117
|
+
@url = @sync.connection[:id]
|
|
118
|
+
@async = Async::Redis::Client.new(Async::IO::Endpoint.tcp(@host, @port))
|
|
119
|
+
if set_notify_config
|
|
120
|
+
@rdsck.dbg "set #{@url} notify-keyspace-events to \"Kh\""
|
|
121
|
+
@prev_notify_keyspace_event_config = @sync.config("get", "notify-keyspace-events")
|
|
122
|
+
@prev_notify_keyspace_event_config = @prev_notify_keyspace_event_config[1] if @prev_notify_keyspace_event_config
|
|
123
|
+
|
|
124
|
+
@sync.config :set, "notify-keyspace-events", "Kh"
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def watch(task)
|
|
129
|
+
task.async do
|
|
130
|
+
#puts "subscribeme"
|
|
131
|
+
while true do
|
|
132
|
+
@async.psubscribe "__keyspace*__:{channel:*}" do |ctx|
|
|
133
|
+
type, pattern, name, msg = ctx.listen
|
|
134
|
+
#puts "TYPE: #{type}, PAT:#{pattern}, NAME:#{name}, MSG:#{msg}"
|
|
135
|
+
m=name.match(/^__.*__:(\{.*\})/)
|
|
136
|
+
if m && m[1]
|
|
137
|
+
key = m[1]
|
|
138
|
+
|
|
139
|
+
filtered = false
|
|
140
|
+
subs = nil
|
|
141
|
+
|
|
142
|
+
if @filters[:min_subscribers]
|
|
143
|
+
subs = @sync.hget key, "fake_subscribers"
|
|
144
|
+
subs = subs.to_i
|
|
145
|
+
filtered = true if subs < @filters[:min_subscribers]
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
if !filtered
|
|
149
|
+
if subs
|
|
150
|
+
puts "#{key} subscribers: #{subs}"
|
|
151
|
+
else
|
|
152
|
+
puts "#{key}"
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def stop
|
|
163
|
+
@async.close
|
|
164
|
+
if @set_notify_config
|
|
165
|
+
@rdsck.dbg "set #{@url} notify-keyspace-events back to #{@prev_notify_keyspace_event_config}"
|
|
166
|
+
@sync.config(:set, "notify-keyspace-events", @prev_notify_keyspace_event_config)
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def watch_channels(filters={}, set_notify_keyspace_events=nil)
|
|
172
|
+
watchers = []
|
|
173
|
+
@masters.each do |m|
|
|
174
|
+
watchers << Watch.new(self, m, filters, set_notify_keyspace_events)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
begin
|
|
179
|
+
Async do |task|
|
|
180
|
+
watchers.each do |watcher|
|
|
181
|
+
watcher.watch(task)
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
rescue Interrupt => e
|
|
185
|
+
dbg "stopping watch"
|
|
186
|
+
ensure
|
|
187
|
+
watchers.each do |watcher|
|
|
188
|
+
watcher.stop
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
end
|
|
193
|
+
|
|
63
194
|
def filter_channels(filters={})
|
|
64
195
|
script = <<~EOF
|
|
65
196
|
local prev_cursor = ARGV[1]
|
|
@@ -91,7 +222,7 @@ class Rdsck
|
|
|
91
222
|
|
|
92
223
|
results = []
|
|
93
224
|
batch_size=500
|
|
94
|
-
masters.each do |m|
|
|
225
|
+
@masters.each do |m|
|
|
95
226
|
hash = m.script "load", script
|
|
96
227
|
cursor, pattern = "0", "{channel:*}"
|
|
97
228
|
loop do
|
data/lib/nchan_tools/version.rb
CHANGED
data/nchan_tools.gemspec
CHANGED
|
@@ -29,6 +29,9 @@ Gem::Specification.new do |spec|
|
|
|
29
29
|
spec.add_dependency "celluloid"
|
|
30
30
|
spec.add_dependency "celluloid-io"
|
|
31
31
|
spec.add_dependency "HDRHistogram"
|
|
32
|
+
spec.add_dependency "redis", "~>4.2.0"
|
|
33
|
+
spec.add_dependency "async"
|
|
34
|
+
spec.add_dependency "async-redis"
|
|
32
35
|
|
|
33
36
|
spec.add_dependency "websocket-driver"
|
|
34
37
|
spec.add_dependency 'websocket-extensions'
|
|
@@ -38,6 +41,6 @@ Gem::Specification.new do |spec|
|
|
|
38
41
|
spec.add_dependency 'http-2'
|
|
39
42
|
end
|
|
40
43
|
spec.add_development_dependency "pry"
|
|
41
|
-
spec.add_development_dependency "bundler"
|
|
42
|
-
spec.add_development_dependency "rake"
|
|
44
|
+
spec.add_development_dependency "bundler"
|
|
45
|
+
spec.add_development_dependency "rake"
|
|
43
46
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: nchan_tools
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.12
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Leo Ponomarev
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2021-02-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: typhoeus
|
|
@@ -94,6 +94,48 @@ dependencies:
|
|
|
94
94
|
- - ">="
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
96
|
version: '0'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: redis
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - "~>"
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: 4.2.0
|
|
104
|
+
type: :runtime
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - "~>"
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: 4.2.0
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: async
|
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - ">="
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: '0'
|
|
118
|
+
type: :runtime
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - ">="
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: '0'
|
|
125
|
+
- !ruby/object:Gem::Dependency
|
|
126
|
+
name: async-redis
|
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
|
128
|
+
requirements:
|
|
129
|
+
- - ">="
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: '0'
|
|
132
|
+
type: :runtime
|
|
133
|
+
prerelease: false
|
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - ">="
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: '0'
|
|
97
139
|
- !ruby/object:Gem::Dependency
|
|
98
140
|
name: websocket-driver
|
|
99
141
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -182,30 +224,30 @@ dependencies:
|
|
|
182
224
|
name: bundler
|
|
183
225
|
requirement: !ruby/object:Gem::Requirement
|
|
184
226
|
requirements:
|
|
185
|
-
- - "
|
|
227
|
+
- - ">="
|
|
186
228
|
- !ruby/object:Gem::Version
|
|
187
|
-
version: '
|
|
229
|
+
version: '0'
|
|
188
230
|
type: :development
|
|
189
231
|
prerelease: false
|
|
190
232
|
version_requirements: !ruby/object:Gem::Requirement
|
|
191
233
|
requirements:
|
|
192
|
-
- - "
|
|
234
|
+
- - ">="
|
|
193
235
|
- !ruby/object:Gem::Version
|
|
194
|
-
version: '
|
|
236
|
+
version: '0'
|
|
195
237
|
- !ruby/object:Gem::Dependency
|
|
196
238
|
name: rake
|
|
197
239
|
requirement: !ruby/object:Gem::Requirement
|
|
198
240
|
requirements:
|
|
199
|
-
- - "
|
|
241
|
+
- - ">="
|
|
200
242
|
- !ruby/object:Gem::Version
|
|
201
|
-
version: '
|
|
243
|
+
version: '0'
|
|
202
244
|
type: :development
|
|
203
245
|
prerelease: false
|
|
204
246
|
version_requirements: !ruby/object:Gem::Requirement
|
|
205
247
|
requirements:
|
|
206
|
-
- - "
|
|
248
|
+
- - ">="
|
|
207
249
|
- !ruby/object:Gem::Version
|
|
208
|
-
version: '
|
|
250
|
+
version: '0'
|
|
209
251
|
description: publishing, subscribing, testing, and benchmarking utilities for Nchan.
|
|
210
252
|
email:
|
|
211
253
|
- leo@nchan.io
|
|
@@ -254,7 +296,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
254
296
|
- !ruby/object:Gem::Version
|
|
255
297
|
version: '0'
|
|
256
298
|
requirements: []
|
|
257
|
-
rubygems_version: 3.
|
|
299
|
+
rubygems_version: 3.2.7
|
|
258
300
|
signing_key:
|
|
259
301
|
specification_version: 4
|
|
260
302
|
summary: Development and testing utilities for Nchan
|