nchan_tools 0.1.7 → 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: 9cce7f7cc54b6764afddca855f9e1a58d929f05a81b7d364489ff87d9f298e81
4
- data.tar.gz: 9892571bd84b6779007eaf94a151f1d0e42209396848bddf22e3bcfabe83475d
3
+ metadata.gz: 2c506959c2eba296db96ed5e1598412798117f4e33bae4a909e223148a829b4a
4
+ data.tar.gz: 4f178a9eac6fa954d06b5f9f4d6d21cb5c3e6320390e3f422fdcb0589e5276d9
5
5
  SHA512:
6
- metadata.gz: 23fb2e18d4885b2cdff8fbb8e79ed1b99fd65ff51f247ba908b24bb604c0a541c7d553e264578a8d799c7edd35c545bb9275e50704ea20b2009c363f459ec425
7
- data.tar.gz: fbdfd34328967212fcbff8f491cf2109da6ba5b3856d07abe654992197fad874bb844a5a7ec7ac26b4db0b177d2e37bfb1b8d45c33c4ecc4a3cb60192818bf07
6
+ metadata.gz: 183363cebe229289e9c3eb0c0989a2816b7bb06c2f3650a81fdad8b5a22c1a2502bd182081a49bbcdf076d0eef219f0ae8f3ccff6a31252e8a137d1940347231
7
+ data.tar.gz: e5c09c1e6759dd835fb9699a96e63e6d2bbb7ae7adefac324cae19083f0921d3699fc88bdeb54dde4810153ed9cf528d22f9829688c8f9a02fb2f547f507debf
@@ -4,32 +4,31 @@ require "redis"
4
4
  require "optparse"
5
5
  require 'nchan_tools/rdsck'
6
6
 
7
- $opt = {
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 (#{$opt[:url]})", "Redis server and port..") do |v|
22
- $opt[:url]=v
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
- $opt[:quiet]=false
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
- $opt[:command]=:filter_channels
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
- $opt[:command]=:filter_channels
32
- $opt[:min_subscribers]=v.to_i
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
- rdsck = Rdsck.new $opt
48
+ opt[:verbose] = !opt[:quiet]
49
+
50
+ rdsck = Rdsck.new opt
50
51
  if not rdsck.connect
51
- STDERR.puts "failed to connect to #{$opt[:url]}"
52
+ STDERR.puts "failed to connect to #{opt[:url]}"
52
53
  exit 1
53
54
  end
54
55
 
55
- case $opt[:command]
56
+ case opt[:command]
56
57
  when :filter_channels
57
- puts "# scanning for channels #{$opt[:min_subscribers] && "with subscribers >= #{$opt[:min_subscribers]}"}"
58
- chans = rdsck.filter_channels(min_subscribers: $opt[:min_subscribers])
59
- puts "# found #{chans.count} channel#{chans.count != 1 && "s"}#{chans.count == 0 ? "." : ":"}"
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
@@ -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: $opt[: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: [$opt[:url]]
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:#{$opt[:namespace]}/#{$opt[:channel_id]}}"
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
@@ -1,3 +1,3 @@
1
1
  module NchanTools
2
- VERSION = "0.1.7"
2
+ VERSION = "0.1.12"
3
3
  end
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", "~> 1.16"
42
- spec.add_development_dependency "rake", "~> 10.0"
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.7
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: 2020-12-29 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
@@ -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: '1.16'
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: '1.16'
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: '10.0'
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: '10.0'
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.1.4
299
+ rubygems_version: 3.2.7
258
300
  signing_key:
259
301
  specification_version: 4
260
302
  summary: Development and testing utilities for Nchan