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 +4 -4
- data/README.md +105 -2
- data/lib/hookd/client.rb +40 -0
- data/lib/hookd/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 97edc24416cdc28af2b3e6506d598711705cfc948bbb24416256343ed07e70d9
|
|
4
|
+
data.tar.gz: '008e6b1dd48ea295b47551c1cf9182ea4beceacff62751db9ee0829157911378'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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