hookd-client 1.1.0 → 1.2.0

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: ba2b5b2434c982f13d1515e488d1bcc30056f66448fe34d9529004ae0ea1229a
4
- data.tar.gz: 437ffa486b1a4bb37c6c3e89dc33ab9dbb927b831496435948b47039b0d91384
3
+ metadata.gz: 97edc24416cdc28af2b3e6506d598711705cfc948bbb24416256343ed07e70d9
4
+ data.tar.gz: '008e6b1dd48ea295b47551c1cf9182ea4beceacff62751db9ee0829157911378'
5
5
  SHA512:
6
- metadata.gz: b3551c335feda2be9dfd807c1de65fe1f6f7e46698f193cb3112323c02c3b332e66aa9563caebdc3d24f730d5b8d49484099dfd7c0fd1e3f1370c9860350c79b
7
- data.tar.gz: 4f162c429ea63559cac8749ffcdace2f80014317c30d2d06e6d8954a44a7c8cdd308222e9133bc292a16db9bddcd1283f25b5f762922b46a68eb130737f23432
6
+ metadata.gz: baefacc1c8e98030276e92c3ea4c7ab3e78bf8bef6465e0a99c4574ec221aae4070d3e5c10e353fb4b732532aa19031cc5697dab4e355fe984f730fcc46ecc97
7
+ data.tar.gz: c382ec4a08173ecead4a6334b095a112c3fce9eed944216b48634652dfc20b33d0a820d380920e6682c987f8ad718a0e906d015c94603ca87898da4c93ab83bd
data/README.md CHANGED
@@ -39,7 +39,7 @@ puts "HTTPS endpoint: #{hook.https}"
39
39
  # Make a request to the HTTP endpoint to simulate an interaction
40
40
  Typhoeus.get(hook.http)
41
41
 
42
- # Poll for interactions
42
+ # Poll for interactions (single hook)
43
43
  interactions = client.poll(hook.id)
44
44
  interactions.each do |interaction|
45
45
  if interaction.dns?
@@ -50,6 +50,60 @@ interactions.each do |interaction|
50
50
  end
51
51
  ```
52
52
 
53
+ ### Batch Polling Example
54
+
55
+ When working with multiple hooks, use `poll_batch` for better performance:
56
+
57
+ ```ruby
58
+ require 'hookd'
59
+ require 'typhoeus'
60
+
61
+ # Initialize the client
62
+ client = Hookd::Client.new(
63
+ server: "https://hookd.example.com",
64
+ token: ENV['HOOKD_TOKEN']
65
+ )
66
+
67
+ # Register multiple hooks
68
+ puts "Registering 5 hooks..."
69
+ hooks = client.register(count: 5)
70
+
71
+ hook_ids = hooks.map(&:id)
72
+ puts "Created hooks: #{hook_ids.join(', ')}"
73
+
74
+ # Simulate some interactions...
75
+ # (make DNS queries, HTTP requests, etc.)
76
+
77
+ # Simulate some interactions
78
+ puts "\nSimulating HTTP requests..."
79
+ hooks.each do |hook|
80
+ Typhoeus.get(hook.http)
81
+ puts " ✓ GET #{hook.http}"
82
+ end
83
+
84
+ # Batch poll all hooks at once (1 HTTP request instead of 5)
85
+ puts "Batch polling #{hook_ids.size} hooks..."
86
+ results = client.poll_batch(hook_ids)
87
+
88
+ # Display results
89
+ results.each do |hook_id, result|
90
+ if result[:error]
91
+ puts "❌ Hook #{hook_id}: #{result[:error]}"
92
+ else
93
+ interactions = result[:interactions]
94
+ puts "✅ Hook #{hook_id}: #{interactions.size} interaction(s)"
95
+
96
+ interactions.each do |interaction|
97
+ if interaction.dns?
98
+ puts " - DNS: #{interaction.data['qname']} (#{interaction.data['qtype']})"
99
+ elsif interaction.http?
100
+ puts " - HTTP: #{interaction.data['method']} #{interaction.data['path']}"
101
+ end
102
+ end
103
+ end
104
+ end
105
+ ```
106
+
53
107
  ### Configuration
54
108
 
55
109
  The client requires two configuration parameters:
@@ -94,7 +148,7 @@ Raises:
94
148
 
95
149
  ##### `#poll(hook_id)`
96
150
 
97
- Poll for interactions captured by a hook.
151
+ Poll for interactions captured by a single hook.
98
152
 
99
153
  ```ruby
100
154
  interactions = client.poll("abc123")
@@ -112,6 +166,55 @@ Raises:
112
166
  - `Hookd::ServerError` - Server error (5xx)
113
167
  - `Hookd::ConnectionError` - Connection failed
114
168
 
169
+ ##### `#poll_batch(hook_ids)`
170
+
171
+ **Batch poll** - Poll for interactions from multiple hooks in a single request.
172
+
173
+ ```ruby
174
+ # Register multiple hooks
175
+ hooks = client.register(count: 3)
176
+ hook_ids = hooks.map(&:id)
177
+
178
+ # Batch poll all hooks at once (1 HTTP request instead of 3)
179
+ results = client.poll_batch(hook_ids)
180
+ # => {
181
+ # "abc123" => { interactions: [...], error: nil },
182
+ # "def456" => { interactions: [...], error: nil },
183
+ # "ghi789" => { interactions: [], error: nil }
184
+ # }
185
+
186
+ # Process results
187
+ results.each do |hook_id, result|
188
+ if result[:error]
189
+ puts "Error for #{hook_id}: #{result[:error]}"
190
+ else
191
+ puts "Hook #{hook_id}: #{result[:interactions].size} interactions"
192
+ result[:interactions].each do |interaction|
193
+ puts " - #{interaction.type}: #{interaction.data}"
194
+ end
195
+ end
196
+ end
197
+ ```
198
+
199
+ Parameters:
200
+ - `hook_ids` (Array<String>) - Array of hook IDs to poll
201
+
202
+ Returns: Hash mapping hook IDs to results
203
+ - Each result contains:
204
+ - `interactions` (Array<Hookd::Interaction>) - Array of interactions
205
+ - `error` (String, nil) - Error message if hook not found
206
+
207
+ Raises:
208
+ - `ArgumentError` - Invalid hook_ids (not an array or empty)
209
+ - `Hookd::AuthenticationError` - Authentication failed
210
+ - `Hookd::ServerError` - Server error (5xx)
211
+ - `Hookd::ConnectionError` - Connection failed
212
+
213
+ **Benefits:**
214
+ - **Performance**: Reduced latency with single HTTP request
215
+ - **Efficiency**: Automatic connection reuse with HTTPX
216
+ - **Atomic**: Consistent snapshot of all hooks
217
+
115
218
  ##### `#metrics`
116
219
 
117
220
  Get server metrics (requires authentication).
data/lib/hookd/client.rb CHANGED
@@ -62,6 +62,27 @@ module Hookd
62
62
  raise Error, "Invalid response format: #{e.message}"
63
63
  end
64
64
 
65
+ # Poll for interactions on multiple hooks (batch)
66
+ # @param hook_ids [Array<String>] the hook IDs to poll
67
+ # @return [Hash<String, Hash>] hash mapping hook_id to results
68
+ # Results format: { "hook_id" => { interactions: [...], error: "..." } }
69
+ # @raise [Hookd::AuthenticationError] if authentication fails
70
+ # @raise [Hookd::ServerError] if server returns 5xx
71
+ # @raise [Hookd::ConnectionError] if connection fails
72
+ # @raise [ArgumentError] if hook_ids is invalid
73
+ def poll_batch(hook_ids)
74
+ validate_hook_ids(hook_ids)
75
+
76
+ url = "#{@server}/poll"
77
+ options = { headers: { 'Content-Type' => 'application/json' }, json: hook_ids }
78
+ response = @http.post(url, **options)
79
+ response_data = handle_response(response)
80
+
81
+ transform_batch_results(response_data['results'])
82
+ rescue NoMethodError => e
83
+ raise Error, "Invalid response format: #{e.message}"
84
+ end
85
+
65
86
  # Get server metrics (requires authentication)
66
87
  # @return [Hash] metrics data
67
88
  # @raise [Hookd::AuthenticationError] if authentication fails
@@ -88,6 +109,25 @@ module Hookd
88
109
  handle_response(response)
89
110
  end
90
111
 
112
+ def validate_hook_ids(hook_ids)
113
+ raise ArgumentError, 'hook_ids must be an array' unless hook_ids.is_a?(Array)
114
+ raise ArgumentError, 'hook_ids cannot be empty' if hook_ids.empty?
115
+ end
116
+
117
+ def transform_batch_results(results)
118
+ return {} if results.nil? || !results.is_a?(Hash)
119
+
120
+ results.transform_values do |result|
121
+ next result if result['error']
122
+
123
+ interactions = result['interactions']
124
+ {
125
+ interactions: interactions&.map { |i| Interaction.from_hash(i) } || [],
126
+ error: result['error']
127
+ }
128
+ end
129
+ end
130
+
91
131
  def handle_response(response)
92
132
  # HTTPX returns HTTPX::ErrorResponse for connection/timeout errors
93
133
  if response.is_a?(HTTPX::ErrorResponse)
data/lib/hookd/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Hookd
4
- VERSION = '1.1.0'
4
+ VERSION = '1.2.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hookd-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua MARTINELLE