nchan_tools 0.1.11 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 65a7cdf81145f3dde05ac13e82dc9dcc09063eff263ec642a6b9e3682db033d1
4
- data.tar.gz: 5d8d9ff2c06a5ebd982a123be59a3ed13310b99c7daa869e86e30832f69ee509
3
+ metadata.gz: 2c506959c2eba296db96ed5e1598412798117f4e33bae4a909e223148a829b4a
4
+ data.tar.gz: 4f178a9eac6fa954d06b5f9f4d6d21cb5c3e6320390e3f422fdcb0589e5276d9
5
5
  SHA512:
6
- metadata.gz: b771ba51b4108c2c01805e06730590c79f5150180d62bad58662e7f6f6f1ed250257c94acf992274292195381262ca01164f249df147ba3eabd149f0ad730259
7
- data.tar.gz: 5b422326b465e2df1f70315edad5dda73766c861aa18f4d65cbc64093bbf229a2a0845de7f207620751442e6a6b47887ebfd44f5002757ef2abf6c690220b0fe
6
+ metadata.gz: 183363cebe229289e9c3eb0c0989a2816b7bb06c2f3650a81fdad8b5a22c1a2502bd182081a49bbcdf076d0eef219f0ae8f3ccff6a31252e8a137d1940347231
7
+ data.tar.gz: e5c09c1e6759dd835fb9699a96e63e6d2bbb7ae7adefac324cae19083f0921d3699fc88bdeb54dde4810153ed9cf528d22f9829688c8f9a02fb2f547f507debf
@@ -15,14 +15,19 @@ opt_parser=OptionParser.new do |opts|
15
15
  opt[:url]=v
16
16
  end
17
17
  opts.on("-q", "--quiet", "output only results without any other information") do
18
- opt[:quiet]=false
19
- opts[:verbose] = !opt[:quiet]
18
+ opt[:quiet]=true
20
19
  end
21
20
  opts.on("--list-channels", "list all Nchan channels on Redis server or cluster") do |v|
22
21
  opt[:command]=:filter_channels
23
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
24
29
  opts.on("--filter-channels-min-subscribers=[NUMBER]") do |v|
25
- opt[:command]=:filter_channels
30
+ opt[:command]||=:filter_channels
26
31
  opt[:min_subscribers]=v.to_i
27
32
  end
28
33
  end
@@ -40,6 +45,8 @@ opt_parser.banner= <<~EOB
40
45
  EOB
41
46
  opt_parser.parse!
42
47
 
48
+ opt[:verbose] = !opt[:quiet]
49
+
43
50
  rdsck = Rdsck.new opt
44
51
  if not rdsck.connect
45
52
  STDERR.puts "failed to connect to #{opt[:url]}"
@@ -48,10 +55,13 @@ end
48
55
 
49
56
  case opt[:command]
50
57
  when :filter_channels
51
- puts "# scanning for channels #{opt[:min_subscribers] && "with subscribers >= #{opt[:min_subscribers]}"}"
58
+ rdsck.dbg "scanning for channels #{opt[:min_subscribers] && "with subscribers >= #{opt[:min_subscribers]}"}"
52
59
  chans = rdsck.filter_channels(min_subscribers: opt[:min_subscribers])
53
- puts "# found #{chans.count} channel#{chans.count != 1 && "s"}#{chans.count == 0 ? "." : ":"}"
60
+ rdsck.dbg "found #{chans.count} channel#{chans.count != 1 && "s"}#{chans.count == 0 ? "." : ":"}"
54
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])
55
65
  else
56
66
  puts "Nothing to do"
57
67
  end
@@ -1,4 +1,40 @@
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
4
40
 
@@ -22,9 +58,10 @@ class Rdsck
22
58
 
23
59
  def connect
24
60
  begin
25
- puts "connect to #{@url}"
26
61
  @redis=Redis.new url: @url
62
+
27
63
  mode = redis.info["redis_mode"]
64
+
28
65
  rescue StandardError => e
29
66
  STDERR.puts e.message
30
67
  return false
@@ -33,7 +70,6 @@ class Rdsck
33
70
  if mode == "cluster"
34
71
  @redis.close
35
72
  begin
36
- puts "cluster-connect to #{@url}"
37
73
  @redis=Redis.new cluster: [@url]
38
74
  @redis.ping
39
75
  rescue StandardError => e
@@ -71,6 +107,90 @@ class Rdsck
71
107
  #...
72
108
  end
73
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
+
74
194
  def filter_channels(filters={})
75
195
  script = <<~EOF
76
196
  local prev_cursor = ARGV[1]
@@ -102,7 +222,7 @@ class Rdsck
102
222
 
103
223
  results = []
104
224
  batch_size=500
105
- masters.each do |m|
225
+ @masters.each do |m|
106
226
  hash = m.script "load", script
107
227
  cursor, pattern = "0", "{channel:*}"
108
228
  loop do
@@ -1,3 +1,3 @@
1
1
  module NchanTools
2
- VERSION = "0.1.11"
2
+ VERSION = "0.1.12"
3
3
  end
data/nchan_tools.gemspec CHANGED
@@ -30,6 +30,8 @@ Gem::Specification.new do |spec|
30
30
  spec.add_dependency "celluloid-io"
31
31
  spec.add_dependency "HDRHistogram"
32
32
  spec.add_dependency "redis", "~>4.2.0"
33
+ spec.add_dependency "async"
34
+ spec.add_dependency "async-redis"
33
35
 
34
36
  spec.add_dependency "websocket-driver"
35
37
  spec.add_dependency 'websocket-extensions'
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.11
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: 2021-01-14 00:00:00.000000000 Z
11
+ date: 2021-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: typhoeus
@@ -108,6 +108,34 @@ dependencies:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
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'
111
139
  - !ruby/object:Gem::Dependency
112
140
  name: websocket-driver
113
141
  requirement: !ruby/object:Gem::Requirement
@@ -268,7 +296,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
268
296
  - !ruby/object:Gem::Version
269
297
  version: '0'
270
298
  requirements: []
271
- rubygems_version: 3.1.4
299
+ rubygems_version: 3.2.7
272
300
  signing_key:
273
301
  specification_version: 4
274
302
  summary: Development and testing utilities for Nchan