ratproto 0.3.2 → 0.3.4

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: 7ba70d80557249c2c85eeb1e185f1cc0261800b4d3a0aa07f2cf6b777fdd512e
4
- data.tar.gz: a722e3c61aca7f8827b682885fed4b7fddaef19eaa48b8d8635d82911dc489ff
3
+ metadata.gz: c5fee431ed4b84e739b1ff36768bfb1db007dd1457d63dfd1ba5279c92b66c00
4
+ data.tar.gz: 260c01a4b45629e2c55026404ad5bbbc6fe9e93a22647cba85d4897b11a7ed81
5
5
  SHA512:
6
- metadata.gz: 3334b2e69f3a8b4dcb1bc09781ff49d8884125c629b028c8a3b16f5428a341f9a6b0c03390631f77a57b88f40b121a69e5441eba119685d43b892e53d38ee560
7
- data.tar.gz: 15c356cacc4116c3d2cf142677c538eeb9691e108a1fde6f807267ae8de96cb12aec845d42199a73da2e4db9b43a9ab347d4cab801a9008c53bf6c7c4b02e47e
6
+ metadata.gz: ff763fe7c82d4a645de4228bf909e362b33efd98094390451bcf99b6b64c9ce165f83f17c4325746f7f4c73a076d3824944b5422c871f6bf25fdc89331f1a7a3
7
+ data.tar.gz: 855c076aa6553f04635f5275e2b94bef28bd78d91f816b9446cad9f8c5d305719dcb4dbdc85c986d9b736d3355d3cc4d2faec59425c2eca9f93b821c7cbf906e
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## [0.3.4] - 2026-09-03
2
+
3
+ - `stream`: for Jetstream sources, you can pass e.g. '-4h' as the cursor to start from 4 hours ago
4
+
5
+ ## [0.3.3] - 2026-08-17
6
+
7
+ - `stream`: added `--print-time` mode, bug fixes, unified timestamp formats
8
+ - added `status` command that prints account status
9
+
1
10
  ## [0.3.2] - 2026-07-30
2
11
 
3
12
  - `stream`: filter by record operation type using `-o`
data/lib/ratproto/cli.rb CHANGED
@@ -5,6 +5,7 @@ require 'clamp'
5
5
  require_relative 'version'
6
6
  require_relative 'ext'
7
7
  require_relative 'commands/base'
8
+ require_relative 'commands/account_status'
8
9
  require_relative 'commands/fetch'
9
10
  require_relative 'commands/resolve'
10
11
  require_relative 'commands/stream'
@@ -51,6 +52,7 @@ module RatProto
51
52
  end
52
53
 
53
54
  subcommand 'fetch', 'fetch a single record given its at:// URI', Commands::Fetch
55
+ subcommand 'status', 'print account status', Commands::AccountStatus
54
56
  subcommand 'stream', 'stream events from a relay or PDS firehose', Commands::Stream
55
57
  subcommand 'stream-labels', 'stream labels a labeller firehose', Commands::StreamLabels
56
58
  subcommand 'resolve', 'resolve a DID or @handle', Commands::Resolve
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'didkit'
4
+
5
+ require_relative 'base'
6
+
7
+ module RatProto
8
+ module Commands
9
+ class AccountStatus < Base
10
+ banner 'Print status of an account on its PDS'
11
+
12
+ parameter 'TARGET', 'DID or handle'
13
+
14
+ option ['-s', '--status'], :flag, 'print only the status without a full message'
15
+
16
+ def execute
17
+ begin
18
+ resolved_did = DID.resolve_handle(target)
19
+ rescue StandardError => e
20
+ signal_error "resolving #{target.inspect}: #{e.class}: #{e.message}"
21
+ end
22
+
23
+ if resolved_did.nil?
24
+ signal_error "couldn't resolve #{target}"
25
+ end
26
+
27
+ result = resolved_did.account_status
28
+
29
+ if status?
30
+ puts (result&.to_s || 'deleted')
31
+ return
32
+ end
33
+
34
+ case result
35
+ when :active
36
+ puts "#{resolved_did} at #{resolved_did.document.pds_host}: account active"
37
+ when nil
38
+ puts "#{resolved_did} at #{resolved_did.document.pds_host}: account not found"
39
+ else
40
+ puts "#{resolved_did} at #{resolved_did.document.pds_host}: account inactive (status = #{result})"
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -17,13 +17,8 @@ module RatProto
17
17
 
18
18
  option ['-j', '--jetstream'], :flag, 'use a Jetstream source'
19
19
 
20
- option(
21
- ['-r', '--cursor'], 'CURSOR',
20
+ option ['-r', '--cursor'], 'CURSOR',
22
21
  'start from a given cursor (pass 0 to read from the beginning of the playback window)'
23
- ) do |value|
24
- raise ArgumentError, 'must be a decimal integer' unless value =~ /\A\d+\z/
25
- value.to_i
26
- end
27
22
 
28
23
  option ['-d', '--did'], 'DID[,DID...]', 'filter events by DID (comma-separated or repeated)',
29
24
  multivalued: true, attribute_name: :did_values
@@ -40,23 +35,26 @@ module RatProto
40
35
  'print account status events (default: enabled unless filtering by collection or operation)'
41
36
 
42
37
  option ['-q', '--quiet'], :flag, 'disable status messages'
43
- option ['-s', '--print-cursor'], :flag, 'only print current cursor (seq)'
38
+ option ['-s', '--print-cursor'], :flag, 'only print cursor (seq) of first event and disconnect'
39
+ option ['--print-time'], :flag, 'only print timestamp of first event and disconnect'
44
40
 
45
41
 
46
42
  def execute
47
43
  require 'skyfall'
48
44
 
49
45
  prepare_filters
46
+ validate_cursor
50
47
 
51
48
  @sky = build_stream
52
49
  configure_interrupt_handler
53
50
 
54
- if print_cursor?
51
+ if print_cursor? || print_time?
55
52
  @sky.on_message do |msg|
56
53
  print_cursor_and_stop(msg)
57
54
  next
58
55
  end
59
56
 
57
+ @sky.on_error { |e| report_error(e) }
60
58
  @sky.connect
61
59
  else
62
60
  configure_callbacks
@@ -95,6 +93,29 @@ module RatProto
95
93
  @operations = (@operations.length > 0) ? @operations.map { |operation| validate_operation(operation) } : nil
96
94
  end
97
95
 
96
+ def validate_cursor
97
+ return if cursor.nil?
98
+
99
+ if cursor.start_with?('-')
100
+ if !jetstream?
101
+ signal_usage_error("time offset cursors are only supported with Jetstream right now")
102
+ end
103
+
104
+ if cursor =~ /\A\-([0-9]+(\.[0-9]+)?)([hms])\z/i
105
+ amount, unit = $1, $3.downcase
106
+
107
+ multiplier = { 'h' => 3600, 'm' => 60, 's' => 1 }[unit]
108
+ @cursor = (Time.now.to_f - amount.to_f * multiplier) * 1_000_000
109
+ else
110
+ signal_usage_error("invalid time offset specifier: #{cursor}")
111
+ end
112
+ elsif cursor =~ /\A[0-9]+\z/
113
+ @cursor = cursor.to_i
114
+ else
115
+ signal_usage_error("cursor must be an integer number or an offset specifier")
116
+ end
117
+ end
118
+
98
119
  def validate_operation(operation)
99
120
  if OPERATION_TYPES.include?(operation)
100
121
  operation.to_sym
@@ -106,7 +127,7 @@ module RatProto
106
127
  def build_stream
107
128
  if jetstream?
108
129
  options = {}
109
- options[:cursor] = cursor if cursor
130
+ options[:cursor] = @cursor if @cursor
110
131
 
111
132
  # pass DID/collection filters to Jetstream to filter events server-side
112
133
  options[:wanted_dids] = @dids if @dids
@@ -147,12 +168,12 @@ module RatProto
147
168
  end
148
169
 
149
170
  def print_commit_message(msg)
171
+ time = msg.time.getlocal
172
+ @last_timestamp = time
173
+
150
174
  return if @no_collections
151
175
  return if @dids && !@dids.include?(msg.repo)
152
176
 
153
- time = msg.time.getlocal.iso8601
154
- @last_timestamp = time
155
-
156
177
  msg.operations.each do |op|
157
178
  next if @collections && !@collections.include?(op.collection)
158
179
  next if @operations && !@operations.include?(op.action)
@@ -163,11 +184,11 @@ module RatProto
163
184
  end
164
185
 
165
186
  def print_account_message(msg)
166
- return if @dids && !@dids.include?(msg.repo)
167
-
168
- time = msg.time.getlocal.iso8601
187
+ time = msg.time.getlocal
169
188
  @last_timestamp = time
170
189
 
190
+ return if @dids && !@dids.include?(msg.repo)
191
+
171
192
  status = (msg.active?) ? :active : msg.status
172
193
 
173
194
  puts "[#{time}] (#{msg.seq}) #{msg.repo} #account (status = #{status.inspect})"
@@ -198,7 +219,8 @@ module RatProto
198
219
  def print_cursor_and_stop(msg)
199
220
  return if @disconnecting
200
221
 
201
- puts msg.seq
222
+ puts (print_time?) ? msg.time.getlocal : msg.seq
223
+
202
224
  @sky.disconnect
203
225
  @disconnecting = true
204
226
  end
@@ -25,7 +25,8 @@ module RatProto
25
25
  multivalued: true, attribute_name: :target_patterns
26
26
 
27
27
  option ['-q', '--quiet'], :flag, 'disable status messages'
28
- option ['-s', '--print-cursor'], :flag, 'only print current cursor (seq)'
28
+ option ['-s', '--print-cursor'], :flag, 'only print cursor (seq) of first event and disconnect'
29
+ option ['--print-time'], :flag, 'only print timestamp of first event and disconnect'
29
30
 
30
31
 
31
32
  def execute
@@ -38,12 +39,13 @@ module RatProto
38
39
  @sky = Skyfall::Firehose.new(@service, :subscribe_labels, cursor)
39
40
  configure_interrupt_handler
40
41
 
41
- if print_cursor?
42
+ if print_cursor? || print_time?
42
43
  @sky.on_message do |msg|
43
44
  print_cursor_and_stop(msg)
44
45
  next
45
46
  end
46
47
 
48
+ @sky.on_error { |e| log "ERROR: #{e.message}" }
47
49
  @sky.connect
48
50
  else
49
51
  configure_callbacks
@@ -91,19 +93,20 @@ module RatProto
91
93
  @sky.on_disconnect { log "Disconnected" }
92
94
  @sky.on_reconnect { log "Connection lost, trying to reconnect..." }
93
95
  @sky.on_timeout { log "Connection stalled, triggering a reconnect..." }
94
- @sky.on_error { |e| log "ERROR: #{e}" }
96
+ @sky.on_error { |e| log "ERROR: #{e.message}" }
95
97
 
96
98
  @sky.on_message do |msg|
97
99
  next unless msg.type == :labels
98
100
 
99
101
  msg.labels.each do |label|
102
+ time = label.created_at.getlocal
103
+ @last_timestamp = time
104
+
100
105
  next if @labels && !@labels.include?(label.value)
101
106
  next if @targets && @targets.none? { |pattern| pattern.match?(label.subject) }
102
107
 
103
- @last_timestamp = label.created_at
104
-
105
108
  json = JSON.generate(label.data.except('cid', 'cts', 'sig', 'src', 'ver'))
106
- puts "[#{label.created_at}] (#{msg.seq}) #{json}"
109
+ puts "[#{time}] (#{msg.seq}) #{json}"
107
110
  end
108
111
  end
109
112
  end
@@ -123,7 +126,8 @@ module RatProto
123
126
  def print_cursor_and_stop(msg)
124
127
  return if @disconnecting
125
128
 
126
- puts msg.seq
129
+ puts (print_time?) ? msg.labels.first.created_at.getlocal : msg.seq
130
+
127
131
  @sky.disconnect
128
132
  @disconnecting = true
129
133
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RatProto
4
- VERSION = "0.3.2"
4
+ VERSION = "0.3.4"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ratproto
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kuba Suder
@@ -102,6 +102,7 @@ files:
102
102
  - exe/rat
103
103
  - lib/ratproto.rb
104
104
  - lib/ratproto/cli.rb
105
+ - lib/ratproto/commands/account_status.rb
105
106
  - lib/ratproto/commands/base.rb
106
107
  - lib/ratproto/commands/fetch.rb
107
108
  - lib/ratproto/commands/resolve.rb
@@ -117,6 +118,7 @@ metadata:
117
118
  bug_tracker_uri: https://tangled.org/mackuba.eu/ratproto/issues
118
119
  changelog_uri: https://tangled.org/mackuba.eu/ratproto/blob/master/CHANGELOG.md
119
120
  source_code_uri: https://tangled.org/mackuba.eu/ratproto
121
+ rubygems_mfa_required: 'true'
120
122
  rdoc_options: []
121
123
  require_paths:
122
124
  - lib
@@ -131,7 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
131
133
  - !ruby/object:Gem::Version
132
134
  version: '0'
133
135
  requirements: []
134
- rubygems_version: 3.6.9
136
+ rubygems_version: 4.0.18
135
137
  specification_version: 4
136
138
  summary: Ruby CLI tool for accessing Bluesky API / ATProto
137
139
  test_files: []