nchan_tools 0.1.11 → 0.1.12

Sign up to get free protection for your applications and to get access to all the features.
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