prosody 0.5.1 → 0.6.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.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.config/rail.toml +26 -0
  3. data/.release-please-manifest.json +1 -1
  4. data/.ruby-version +1 -1
  5. data/.taplo.toml +1 -1
  6. data/AGENTS.md +29 -15
  7. data/CHANGELOG.md +7 -0
  8. data/CONFIGURATION.md +19 -16
  9. data/Cargo.lock +254 -235
  10. data/Cargo.toml +11 -8
  11. data/README.md +100 -23
  12. data/examples/keyed_state.rb +10 -2
  13. data/examples/keyed_state.rbs +1 -0
  14. data/ext/prosody/Cargo.toml +1 -1
  15. data/ext/prosody/src/admin.rs +36 -36
  16. data/ext/prosody/src/bridge/mod.rs +5 -10
  17. data/ext/prosody/src/client/config/connections.rs +170 -0
  18. data/ext/prosody/src/client/config/middleware.rs +184 -0
  19. data/ext/prosody/src/client/config/mod.rs +396 -0
  20. data/ext/prosody/src/client/config/state.rs +323 -0
  21. data/ext/prosody/src/client/mod.rs +31 -117
  22. data/ext/prosody/src/client/readers.rs +106 -0
  23. data/ext/prosody/src/client/request.rs +2 -2
  24. data/ext/prosody/src/client/support.rs +13 -32
  25. data/ext/prosody/src/gvl.rs +8 -6
  26. data/ext/prosody/src/handler/{context.rs → context/mod.rs} +36 -150
  27. data/ext/prosody/src/handler/context/vending.rs +138 -0
  28. data/ext/prosody/src/handler/message.rs +36 -0
  29. data/ext/prosody/src/handler/mod.rs +18 -8
  30. data/ext/prosody/src/handler/state/deque.rs +144 -0
  31. data/ext/prosody/src/handler/state/mod.rs +163 -268
  32. data/ext/prosody/src/handler/state/query.rs +264 -0
  33. data/ext/prosody/src/handler/state/registration.rs +15 -86
  34. data/ext/prosody/src/handler/state/scan.rs +33 -141
  35. data/ext/prosody/src/handler/state/set.rs +98 -0
  36. data/ext/prosody/src/lib.rs +54 -36
  37. data/ext/prosody/src/logging.rs +6 -6
  38. data/ext/prosody/src/published.rs +171 -152
  39. data/ext/prosody/src/scheduler/result.rs +2 -1
  40. data/ext/prosody/src/util.rs +65 -3
  41. data/lib/prosody/client.rb +32 -0
  42. data/lib/prosody/configuration.rb +20 -12
  43. data/lib/prosody/demand.rb +27 -0
  44. data/lib/prosody/native_stubs/client.rb +157 -0
  45. data/lib/prosody/native_stubs/context.rb +178 -0
  46. data/lib/prosody/native_stubs/message.rb +133 -0
  47. data/lib/prosody/native_stubs.rb +11 -956
  48. data/lib/prosody/state/deque.rb +253 -0
  49. data/lib/prosody/state/map.rb +313 -0
  50. data/lib/prosody/state/set.rb +121 -0
  51. data/lib/prosody/state/value.rb +58 -0
  52. data/lib/prosody/state.rb +157 -677
  53. data/lib/prosody/version.rb +1 -1
  54. data/lib/prosody.rb +2 -1
  55. data/sig/configuration.rbs +19 -10
  56. data/sig/prosody.rbs +37 -4
  57. data/sig/published.rbs +102 -0
  58. data/sig/state.rbs +109 -122
  59. data/typecheck/payload_types.rb +12 -0
  60. data/typecheck/payload_types.rbs +1 -0
  61. metadata +30 -11
  62. data/ext/prosody/src/client/config.rs +0 -1300
data/sig/state.rbs CHANGED
@@ -1,43 +1,38 @@
1
1
  module Prosody
2
2
  type state_config_value = String | Integer | bool
3
3
 
4
+ # The effect of commit or rollback: :applied when buffered operations were
5
+ # drained, :no_op when nothing was buffered.
6
+ type store_outcome = :applied | :no_op
7
+
8
+ # Query keywords as the traversal methods collect them.
9
+ type query_options = Hash[Symbol, String | Integer | Range[String?] | Range[Integer?] | nil]
10
+
4
11
  # --- error taxonomy -----------------------------------------------------
5
12
  # Raised for keyed-state failures a retry cannot resolve (unregistered
6
- # collection, identity mismatch, duplicate registration, bad TTL). Never
13
+ # collection, identity mismatch, duplicate registration, bad TTL, JSON null
14
+ # write; use clear/delete to remove a value). Never
7
15
  # Terminal: core folds Terminal into Transient.
8
16
  class PermanentStateError < PermanentError
9
17
  end
10
18
 
11
19
  # Raised for keyed-state failures that may succeed on retry, plus every
12
- # caller mistake (null write, wrong item shape, invalid index, invalid
13
- # direction). Never Terminal.
20
+ # caller mistake the client detects (wrong item shape, invalid index,
21
+ # invalid direction). Never Terminal.
14
22
  class TransientStateError < TransientError
15
23
  end
16
24
 
17
- # Raised when a JSON null is written to a collection. Null is not storable
18
- # (indistinguishable from absence); use clear/delete instead.
19
- class NullValueError < TransientStateError
20
- end
21
-
22
- class StateAccess < Data
23
- attr_reader vend_method: Symbol
24
- attr_reader wrapper: Symbol
25
- attr_reader published_vend_method: Symbol?
26
- attr_reader published_wrapper: Symbol?
27
- end
28
-
29
25
  # Concrete immutable definition object returned by the constructor helpers.
30
26
  class StateDefinition < Data
31
27
  attr_reader name: String
32
28
  attr_reader kind: String
33
- attr_reader payload: String
29
+ attr_reader payload: String?
34
30
  attr_reader ttl_seconds: Integer?
35
31
  attr_reader read_uncommitted: bool?
36
32
  attr_reader published: bool?
37
33
  attr_reader read_cache: (Numeric | false)?
38
34
  attr_reader keyset_limit: Integer?
39
35
  attr_reader capacity: Integer?
40
- attr_reader access: StateAccess
41
36
 
42
37
  def to_state_config: () -> Hash[Symbol, state_config_value]
43
38
  end
@@ -61,6 +56,14 @@ module Prosody
61
56
  def to_state_config: () -> Hash[Symbol, state_config_value]
62
57
  end
63
58
 
59
+ interface _SetDefinition
60
+ def name: () -> String
61
+ def kind: () -> "set"
62
+ def payload: () -> nil
63
+ def read_cache: () -> (Numeric | false)?
64
+ def to_state_config: () -> Hash[Symbol, state_config_value]
65
+ end
66
+
64
67
  interface _DequeDefinition[T = json_value]
65
68
  def name: () -> String
66
69
  def kind: () -> "deque"
@@ -96,6 +99,7 @@ module Prosody
96
99
  # `[P]` type parameter is annotation-only, naming the message payload type.
97
100
  def self.value: [T] (_ToS name, ?ttl: Integer?, ?read_uncommitted: bool?, ?published: bool?, ?read_cache: (Numeric | false)?) -> _ValueDefinition[T]
98
101
  def self.map: [V] (_ToS name, ?ttl: Integer?, ?keyset_limit: Integer?, ?read_uncommitted: bool?, ?published: bool?, ?read_cache: (Numeric | false)?) -> _MapDefinition[V]
102
+ def self.set: (_ToS name, ?ttl: Integer?, ?keyset_limit: Integer?, ?read_uncommitted: bool?, ?published: bool?, ?read_cache: (Numeric | false)?) -> _SetDefinition
99
103
  def self.deque: [T] (_ToS name, ?ttl: Integer?, ?capacity: Integer?, ?read_uncommitted: bool?, ?published: bool?, ?read_cache: (Numeric | false)?) -> _DequeDefinition[T]
100
104
  def self.message_value: [P] (_ToS name, ?ttl: Integer?, ?read_uncommitted: bool?) -> _MessageValueDefinition[P]
101
105
  def self.message_map: [P] (_ToS name, ?ttl: Integer?, ?keyset_limit: Integer?, ?read_uncommitted: bool?) -> _MessageMapDefinition[P]
@@ -104,12 +108,10 @@ module Prosody
104
108
  # --- handles ------------------------------------------------------------
105
109
  # A single-value keyed-state handle. Reads return the stored value or nil.
106
110
  # Every op is fiber-yield async: it looks blocking but never blocks the thread.
107
- class ValueState[T = json_value]
111
+ class ValueState[T = json_value] < State::Handle
108
112
  def get: () -> T?
109
113
  def set: (T value) -> void
110
114
  def clear: () -> void
111
- def commit: () -> nil
112
- def rollback: () -> nil
113
115
 
114
116
  # idiomatic conveniences
115
117
  def value: () -> T? # alias of #get
@@ -120,35 +122,36 @@ module Prosody
120
122
  end
121
123
 
122
124
  # A String-keyed ordered-map keyed-state handle.
123
- class MapState[V = json_value]
125
+ class MapState[V = json_value] < State::Handle
124
126
  include State::Scanning
125
127
 
126
128
  def get: (String key) -> V?
127
129
  def get_many: (Array[String] keys) -> Array[V?]
130
+ def contains_many: (Array[String] keys) -> Array[bool]
131
+ def empty?: () -> bool
128
132
  def set: (String key, V value) -> void
129
133
  def delete: (String key) -> nil
130
134
  def clear: () -> void
131
- def commit: () -> nil
132
- def rollback: () -> nil
133
- def each_pair: () { (String, V) -> void } -> void
134
- | () -> Enumerator[[ String, V ], void]
135
- def reverse_each_pair: () { (String, V) -> void } -> void
136
- | () -> Enumerator[[ String, V ], void]
137
- def each_key: () { (String) -> void } -> void
138
- | () -> Enumerator[String, void]
139
- def reverse_each_key: () { (String) -> void } -> void
140
- | () -> Enumerator[String, void]
141
- def each_value: () { (V) -> void } -> void
142
- | () -> Enumerator[V, void]
143
- def reverse_each_value: () { (V) -> void } -> void
144
- | () -> Enumerator[V, void]
135
+ # Traversals accept optional query keywords (see State::Scanning).
136
+ def each_pair: (?from: String?, ?after: String?, ?to: String?, ?before: String?, ?range: Range[String?]?, ?prefix: String?, ?limit: Integer?) { ([String, V]) -> void } -> void
137
+ | (?from: String?, ?after: String?, ?to: String?, ?before: String?, ?range: Range[String?]?, ?prefix: String?, ?limit: Integer?) -> Enumerator[[ String, V ], void]
138
+ def reverse_each_pair: (?from: String?, ?after: String?, ?to: String?, ?before: String?, ?range: Range[String?]?, ?prefix: String?, ?limit: Integer?) { ([String, V]) -> void } -> void
139
+ | (?from: String?, ?after: String?, ?to: String?, ?before: String?, ?range: Range[String?]?, ?prefix: String?, ?limit: Integer?) -> Enumerator[[ String, V ], void]
140
+ def each_key: (?from: String?, ?after: String?, ?to: String?, ?before: String?, ?range: Range[String?]?, ?prefix: String?, ?limit: Integer?) { (String) -> void } -> void
141
+ | (?from: String?, ?after: String?, ?to: String?, ?before: String?, ?range: Range[String?]?, ?prefix: String?, ?limit: Integer?) -> Enumerator[String, void]
142
+ def reverse_each_key: (?from: String?, ?after: String?, ?to: String?, ?before: String?, ?range: Range[String?]?, ?prefix: String?, ?limit: Integer?) { (String) -> void } -> void
143
+ | (?from: String?, ?after: String?, ?to: String?, ?before: String?, ?range: Range[String?]?, ?prefix: String?, ?limit: Integer?) -> Enumerator[String, void]
144
+ def each_value: (?from: String?, ?after: String?, ?to: String?, ?before: String?, ?range: Range[String?]?, ?prefix: String?, ?limit: Integer?) { (V) -> void } -> void
145
+ | (?from: String?, ?after: String?, ?to: String?, ?before: String?, ?range: Range[String?]?, ?prefix: String?, ?limit: Integer?) -> Enumerator[V, void]
146
+ def reverse_each_value: (?from: String?, ?after: String?, ?to: String?, ?before: String?, ?range: Range[String?]?, ?prefix: String?, ?limit: Integer?) { (V) -> void } -> void
147
+ | (?from: String?, ?after: String?, ?to: String?, ?before: String?, ?range: Range[String?]?, ?prefix: String?, ?limit: Integer?) -> Enumerator[V, void]
145
148
 
146
149
  # idiomatic Hash-style conveniences (bounded reads only)
147
150
  def []: (String key) -> V? # alias of #get
148
151
  def []=: (String key, V value) -> V # alias of #set (assignment yields value)
149
152
  def store: (String key, V value) -> V # wrapper over #set, returns value
150
- def each: () { (String, V) -> void } -> void # alias of #each_pair
151
- | () -> Enumerator[[ String, V ], void]
153
+ def each: (?from: String?, ?after: String?, ?to: String?, ?before: String?, ?range: Range[String?]?, ?prefix: String?, ?limit: Integer?) { ([String, V]) -> void } -> void # alias of #each_pair
154
+ | (?from: String?, ?after: String?, ?to: String?, ?before: String?, ?range: Range[String?]?, ?prefix: String?, ?limit: Integer?) -> Enumerator[[ String, V ], void]
152
155
  def values_at: (*String keys) -> Array[V?]
153
156
  def fetch: (String key) -> V
154
157
  | [D] (String key, D default) -> (V | D)
@@ -164,14 +167,32 @@ module Prosody
164
167
 
165
168
  private
166
169
  def initialize: ((NativeJsonMapState | NativeMessageMapState) native) -> void
167
- def traverse: (Symbol direction) { (String, V) -> void } -> void
168
- | (Symbol direction) -> Enumerator[[ String, V ], void]
169
- def traverse_keys: (Symbol direction) { (String) -> void } -> void
170
- | (Symbol direction) -> Enumerator[String, void]
170
+ end
171
+
172
+ # A presence-only ordered set of String members. Mirrors Ruby's Set.
173
+ class SetState < State::Handle
174
+ include State::Scanning
175
+
176
+ def add: (String member) -> self
177
+ def <<: (String member) -> self
178
+ def delete: (String member) -> self
179
+ def include?: (String member) -> bool
180
+ def member?: (String member) -> bool
181
+ def contains_many: (Array[String] members) -> Array[bool]
182
+ def empty?: () -> bool
183
+ def clear: () -> self
184
+ # Traversals accept optional query keywords (see State::Scanning).
185
+ def each: (?from: String?, ?after: String?, ?to: String?, ?before: String?, ?range: Range[String?]?, ?prefix: String?, ?limit: Integer?) { (String) -> void } -> void
186
+ | (?from: String?, ?after: String?, ?to: String?, ?before: String?, ?range: Range[String?]?, ?prefix: String?, ?limit: Integer?) -> Enumerator[String, void]
187
+ def reverse_each: (?from: String?, ?after: String?, ?to: String?, ?before: String?, ?range: Range[String?]?, ?prefix: String?, ?limit: Integer?) { (String) -> void } -> void
188
+ | (?from: String?, ?after: String?, ?to: String?, ?before: String?, ?range: Range[String?]?, ?prefix: String?, ?limit: Integer?) -> Enumerator[String, void]
189
+
190
+ private
191
+ def initialize: (NativeSetState native) -> void
171
192
  end
172
193
 
173
194
  # A deque keyed-state handle.
174
- class DequeState[T = json_value]
195
+ class DequeState[T = json_value] < State::Handle
175
196
  include State::Scanning
176
197
 
177
198
  def push: (T value) -> void
@@ -182,13 +203,12 @@ module Prosody
182
203
  def size: () -> Integer
183
204
  def empty?: () -> bool
184
205
  def clear: () -> void
185
- def commit: () -> nil
186
- def rollback: () -> nil
187
206
  def get: (Integer index) -> T?
188
- def each: () { (T) -> void } -> void
189
- | () -> Enumerator[T, void]
190
- def reverse_each: () { (T) -> void } -> void
191
- | () -> Enumerator[T, void]
207
+ # Traversals accept optional position keywords (see State::Scanning).
208
+ def each: (?from: Integer?, ?after: Integer?, ?to: Integer?, ?before: Integer?, ?range: Range[Integer?]?, ?limit: Integer?) { (T) -> void } -> void
209
+ | (?from: Integer?, ?after: Integer?, ?to: Integer?, ?before: Integer?, ?range: Range[Integer?]?, ?limit: Integer?) -> Enumerator[T, void]
210
+ def reverse_each: (?from: Integer?, ?after: Integer?, ?to: Integer?, ?before: Integer?, ?range: Range[Integer?]?, ?limit: Integer?) { (T) -> void } -> void
211
+ | (?from: Integer?, ?after: Integer?, ?to: Integer?, ?before: Integer?, ?range: Range[Integer?]?, ?limit: Integer?) -> Enumerator[T, void]
192
212
 
193
213
  # idiomatic Array-style conveniences (bounded reads only). #get and #fetch
194
214
  # take a single Integer index (negatives resolve from the back, Array-style);
@@ -206,16 +226,14 @@ module Prosody
206
226
  private
207
227
  def initialize: ((NativeJsonDequeState | NativeMessageDequeState) native) -> void
208
228
  def at_negative: (Integer index) -> T?
209
- def traverse: (Symbol direction) { (T) -> void } -> void
210
- | (Symbol direction) -> Enumerator[T, void]
211
229
  end
212
230
 
213
231
  interface _NativeValueHandle[T]
214
232
  def get: () -> T?
215
233
  def set: (T value) -> void
216
234
  def clear: () -> void
217
- def commit: () -> nil
218
- def rollback: () -> nil
235
+ def commit: () -> store_outcome
236
+ def rollback: () -> store_outcome
219
237
  end
220
238
 
221
239
  class NativeJsonValueState
@@ -229,14 +247,16 @@ module Prosody
229
247
  interface _NativeMapHandle[V, S]
230
248
  def get: (String key) -> V?
231
249
  def contains_key: (String key) -> bool
250
+ def is_empty: () -> bool
232
251
  def get_many: (Array[String] keys) -> Array[V?]
252
+ def contains_many: (Array[String] keys) -> Array[bool]
233
253
  def set: (String key, V value) -> void
234
254
  def remove: (String key) -> void
235
255
  def clear: () -> void
236
- def scan: (Symbol direction) -> S
237
- def keys: (Symbol direction) -> NativeMapKeyScan
238
- def commit: () -> nil
239
- def rollback: () -> nil
256
+ def scan: (Symbol direction, query_options query) -> S
257
+ def keys: (Symbol direction, query_options query) -> NativeMapKeyScan
258
+ def commit: () -> store_outcome
259
+ def rollback: () -> store_outcome
240
260
  end
241
261
 
242
262
  class NativeJsonMapState
@@ -247,6 +267,18 @@ module Prosody
247
267
  include _NativeMapHandle[Message[json_value], NativeMessageMapScan]
248
268
  end
249
269
 
270
+ class NativeSetState
271
+ def contains: (String member) -> bool
272
+ def contains_many: (Array[String] members) -> Array[bool]
273
+ def is_empty: () -> bool
274
+ def insert: (String member) -> void
275
+ def remove: (String member) -> void
276
+ def clear: () -> void
277
+ def keys: (Symbol direction, query_options query) -> NativeMapKeyScan
278
+ def commit: () -> store_outcome
279
+ def rollback: () -> store_outcome
280
+ end
281
+
250
282
  interface _NativeDequeHandle[T, S]
251
283
  def len: () -> Integer
252
284
  def is_empty: () -> bool
@@ -258,9 +290,9 @@ module Prosody
258
290
  def pop_front: () -> T?
259
291
  def pop_back: () -> T?
260
292
  def clear: () -> void
261
- def scan: (Symbol direction) -> S
262
- def commit: () -> nil
263
- def rollback: () -> nil
293
+ def scan: (Symbol direction, query_options query) -> S
294
+ def commit: () -> store_outcome
295
+ def rollback: () -> store_outcome
264
296
  end
265
297
 
266
298
  class NativeJsonDequeState
@@ -272,7 +304,7 @@ module Prosody
272
304
  end
273
305
 
274
306
  interface _NativeScan[T]
275
- def next: () -> T?
307
+ def next_chunk: () -> Array[T]?
276
308
  def close: () -> void
277
309
  end
278
310
 
@@ -296,72 +328,19 @@ module Prosody
296
328
  include _NativeScan[String]
297
329
  end
298
330
 
299
- class NativePublishedValue
300
- def get: (String key) -> json_value?
301
- end
302
-
303
- class NativePublishedMap
304
- def get: (String key, String map_key) -> json_value?
305
- def get_many: (String key, Array[String] map_keys) -> Array[json_value?]
306
- def contains_key: (String key, String map_key) -> bool
307
- def scan: (String key, Symbol direction) -> NativeJsonMapScan
308
- def keys: (String key, Symbol direction) -> NativeMapKeyScan
309
- end
310
-
311
- class NativePublishedDeque
312
- def get: (String key, Integer index) -> json_value?
313
- def length: (String key) -> Integer
314
- def is_empty: (String key) -> bool
315
- def peek_front: (String key) -> json_value?
316
- def peek_back: (String key) -> json_value?
317
- def scan: (String key, Symbol direction) -> NativeJsonDequeScan
318
- end
319
-
320
- class PublishedValue[T = json_value]
321
- def get: (_ToS key) -> T?
322
- end
323
-
324
- class PublishedMap[V = json_value]
325
- def get: (_ToS key, _ToS map_key) -> V?
326
- def get_many: (_ToS key, Array[_ToS] map_keys) -> Array[V?]
327
- def key?: (_ToS key, _ToS map_key) -> bool
328
- alias has_key? key?
329
- alias include? key?
330
- alias member? key?
331
- def each_pair: (_ToS key) { (String, V) -> void } -> void
332
- | (_ToS key) -> Enumerator[[String, V], void]
333
- def reverse_each_pair: (_ToS key) { (String, V) -> void } -> void
334
- | (_ToS key) -> Enumerator[[String, V], void]
335
- def each_key: (_ToS key) { (String) -> void } -> void
336
- | (_ToS key) -> Enumerator[String, void]
337
- def reverse_each_key: (_ToS key) { (String) -> void } -> void
338
- | (_ToS key) -> Enumerator[String, void]
339
- def each_value: (_ToS key) { (V) -> void } -> void
340
- | (_ToS key) -> Enumerator[V, void]
341
- def reverse_each_value: (_ToS key) { (V) -> void } -> void
342
- | (_ToS key) -> Enumerator[V, void]
343
- alias each each_pair
344
- end
345
-
346
- class PublishedDeque[T = json_value]
347
- def get: (_ToS key, Integer index) -> T?
348
- def length: (_ToS key) -> Integer
349
- alias size length
350
- def empty?: (_ToS key) -> bool
351
- def first: (_ToS key) -> T?
352
- def last: (_ToS key) -> T?
353
- def each: (_ToS key) { (T) -> void } -> void
354
- | (_ToS key) -> Enumerator[T, void]
355
- def reverse_each: (_ToS key) { (T) -> void } -> void
356
- | (_ToS key) -> Enumerator[T, void]
357
- end
358
-
359
331
  # --- shared state modules ------------------------------------------------
360
332
  module State
333
+ # The base class of the owned handles.
334
+ class Handle
335
+ def commit: () -> store_outcome
336
+ def rollback: () -> store_outcome
337
+ end
338
+
361
339
  # Adds keyed-state vending to the native context.
362
340
  module Vending
363
341
  def state: [T] (_ValueDefinition[T]) -> ValueState[T]
364
342
  | [V] (_MapDefinition[V]) -> MapState[V]
343
+ | (_SetDefinition) -> SetState
365
344
  | [T] (_DequeDefinition[T]) -> DequeState[T]
366
345
  | [P] (_MessageValueDefinition[P]) -> ValueState[Message[P]]
367
346
  | [P] (_MessageMapDefinition[P]) -> MapState[Message[P]]
@@ -369,10 +348,15 @@ module Prosody
369
348
  end
370
349
 
371
350
  # Shared native-scan driving mixed into the traversal handles.
351
+ # Query keywords apply in iteration order and narrow the selection. Map
352
+ # and set traversals take String keys and `prefix:`. Deque traversals take
353
+ # non-negative positions from the front.
372
354
  module Scanning
373
355
  private
374
- def scan_each: [T] (Symbol direction, ?Symbol opener) { (T) -> void } -> void
375
- def scan_items: [T] (_NativeScan[T] scan) { (T) -> void } -> void
356
+ def traverse: (Symbol opener, *untyped args) { (untyped) -> void } -> void
357
+ | (Symbol opener, *untyped args) -> Enumerator[untyped, void]
358
+ def traverse_values: (*untyped args) { (untyped) -> void } -> void
359
+ | (*untyped args) -> Enumerator[untyped, void]
376
360
  end
377
361
  end
378
362
 
@@ -380,8 +364,11 @@ module Prosody
380
364
  class Context
381
365
  include State::Vending
382
366
 
367
+ private
368
+
383
369
  def value_state: (String name) -> NativeJsonValueState
384
370
  def map_state: (String name) -> NativeJsonMapState
371
+ def set_state: (String name) -> NativeSetState
385
372
  def deque_state: (String name) -> NativeJsonDequeState
386
373
  def message_value_state: (String name) -> NativeMessageValueState
387
374
  def message_map_state: (String name) -> NativeMessageMapState
@@ -5,6 +5,7 @@
5
5
 
6
6
  ORDER_BACKLOG = Prosody.message_deque("order-backlog")
7
7
  ORDER_TOTALS = Prosody.map("order-totals")
8
+ ORDER_IDS = Prosody.set("order-ids")
8
9
 
9
10
  class TypedOrderHandler < Prosody::EventHandler
10
11
  def on_excise(_context, message)
@@ -15,17 +16,25 @@ class TypedOrderHandler < Prosody::EventHandler
15
16
  def on_message(context, message)
16
17
  payload = message.payload
17
18
  order_id = payload["order_id"]
19
+ demand = context.demand
20
+ consume_order(order_id, demand.retries) if demand.failure?
18
21
  total = payload["total"]
19
22
 
20
23
  # Message-backed state preserves the handler's payload type.
21
24
  backlog = context.state(ORDER_BACKLOG)
22
25
  backlog.push(message)
23
26
  oldest = backlog.first
27
+ backlog.reverse_each(range: 0..9, limit: 2) { |pending| pending.payload["order_id"].upcase }
24
28
 
25
29
  # This call is a regression constraint: state(ORDER_TOTALS) must infer as
26
30
  # MapState[Integer], not untyped or a generic JSON-valued state handle.
27
31
  consume_totals(context.state(ORDER_TOTALS))
28
32
 
33
+ # A set handle takes and yields String members.
34
+ order_ids = context.state(ORDER_IDS)
35
+ order_ids << order_id unless order_ids.include?(order_id)
36
+ order_ids.each(prefix: "order-", limit: 5) { |id| id.upcase }
37
+
29
38
  consume_order(order_id, total)
30
39
  oldest_payload = oldest&.payload
31
40
  consume_order(oldest_payload["order_id"], oldest_payload["total"]) if oldest_payload
@@ -43,6 +52,9 @@ class TypedOrderHandler < Prosody::EventHandler
43
52
 
44
53
  def consume_totals(totals)
45
54
  totals.set("latest", 1)
55
+ # Query keywords keep the item types.
56
+ totals.each_key(prefix: "order:", after: "order:1", limit: 10) { |key| key.upcase }
57
+ totals.reverse_each_value(range: "a"..."m").each { |total| total + 1 }
46
58
  nil
47
59
  end
48
60
  end
@@ -6,6 +6,7 @@ type handler_response = { "accepted" => bool }
6
6
 
7
7
  ORDER_BACKLOG: Prosody::_MessageDequeDefinition[order_event]
8
8
  ORDER_TOTALS: Prosody::_MapDefinition[Integer]
9
+ ORDER_IDS: Prosody::_SetDefinition
9
10
 
10
11
  class TypedOrderHandler < Prosody::EventHandler[order_event, handler_response]
11
12
  def on_message: (Prosody::Context context, Prosody::Message[order_event] message) -> handler_response
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prosody
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Griffith
@@ -43,14 +43,14 @@ dependencies:
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: 0.9.128
46
+ version: 0.9.130
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: 0.9.128
53
+ version: 0.9.130
54
54
  - !ruby/object:Gem::Dependency
55
55
  name: async-rspec
56
56
  requirement: !ruby/object:Gem::Requirement
@@ -71,42 +71,42 @@ dependencies:
71
71
  requirements:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
- version: '1.12'
74
+ version: '1.13'
75
75
  type: :development
76
76
  prerelease: false
77
77
  version_requirements: !ruby/object:Gem::Requirement
78
78
  requirements:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
- version: '1.12'
81
+ version: '1.13'
82
82
  - !ruby/object:Gem::Dependency
83
83
  name: opentelemetry-exporter-otlp
84
84
  requirement: !ruby/object:Gem::Requirement
85
85
  requirements:
86
86
  - - "~>"
87
87
  - !ruby/object:Gem::Version
88
- version: '0.34'
88
+ version: '0.37'
89
89
  type: :development
90
90
  prerelease: false
91
91
  version_requirements: !ruby/object:Gem::Requirement
92
92
  requirements:
93
93
  - - "~>"
94
94
  - !ruby/object:Gem::Version
95
- version: '0.34'
95
+ version: '0.37'
96
96
  - !ruby/object:Gem::Dependency
97
97
  name: sentry-ruby
98
98
  requirement: !ruby/object:Gem::Requirement
99
99
  requirements:
100
100
  - - "~>"
101
101
  - !ruby/object:Gem::Version
102
- version: '6.6'
102
+ version: '7.0'
103
103
  type: :development
104
104
  prerelease: false
105
105
  version_requirements: !ruby/object:Gem::Requirement
106
106
  requirements:
107
107
  - - "~>"
108
108
  - !ruby/object:Gem::Version
109
- version: '6.6'
109
+ version: '7.0'
110
110
  description: |
111
111
  Prosody offers Ruby bindings to the Prosody Kafka client, providing features
112
112
  for message production and consumption, including configurable retry
@@ -118,6 +118,7 @@ extensions:
118
118
  extra_rdoc_files: []
119
119
  files:
120
120
  - ".cargo/config.toml"
121
+ - ".config/rail.toml"
121
122
  - ".release-please-manifest.json"
122
123
  - ".rspec"
123
124
  - ".ruby-version"
@@ -144,17 +145,25 @@ files:
144
145
  - ext/prosody/src/admin.rs
145
146
  - ext/prosody/src/bridge/callback.rs
146
147
  - ext/prosody/src/bridge/mod.rs
147
- - ext/prosody/src/client/config.rs
148
+ - ext/prosody/src/client/config/connections.rs
149
+ - ext/prosody/src/client/config/middleware.rs
150
+ - ext/prosody/src/client/config/mod.rs
151
+ - ext/prosody/src/client/config/state.rs
148
152
  - ext/prosody/src/client/mod.rs
153
+ - ext/prosody/src/client/readers.rs
149
154
  - ext/prosody/src/client/request.rs
150
155
  - ext/prosody/src/client/support.rs
151
156
  - ext/prosody/src/gvl.rs
152
- - ext/prosody/src/handler/context.rs
157
+ - ext/prosody/src/handler/context/mod.rs
158
+ - ext/prosody/src/handler/context/vending.rs
153
159
  - ext/prosody/src/handler/message.rs
154
160
  - ext/prosody/src/handler/mod.rs
161
+ - ext/prosody/src/handler/state/deque.rs
155
162
  - ext/prosody/src/handler/state/mod.rs
163
+ - ext/prosody/src/handler/state/query.rs
156
164
  - ext/prosody/src/handler/state/registration.rs
157
165
  - ext/prosody/src/handler/state/scan.rs
166
+ - ext/prosody/src/handler/state/set.rs
158
167
  - ext/prosody/src/handler/trigger.rs
159
168
  - ext/prosody/src/lib.rs
160
169
  - ext/prosody/src/logging.rs
@@ -167,19 +176,29 @@ files:
167
176
  - ext/prosody/src/tracing_util.rs
168
177
  - ext/prosody/src/util.rs
169
178
  - lib/prosody.rb
179
+ - lib/prosody/client.rb
170
180
  - lib/prosody/configuration.rb
181
+ - lib/prosody/demand.rb
171
182
  - lib/prosody/handler.rb
172
183
  - lib/prosody/native_stubs.rb
184
+ - lib/prosody/native_stubs/client.rb
185
+ - lib/prosody/native_stubs/context.rb
186
+ - lib/prosody/native_stubs/message.rb
173
187
  - lib/prosody/processor.rb
174
188
  - lib/prosody/request.rb
175
189
  - lib/prosody/sentry.rb
176
190
  - lib/prosody/state.rb
191
+ - lib/prosody/state/deque.rb
192
+ - lib/prosody/state/map.rb
193
+ - lib/prosody/state/set.rb
194
+ - lib/prosody/state/value.rb
177
195
  - lib/prosody/version.rb
178
196
  - release-please-config.json
179
197
  - sig/configuration.rbs
180
198
  - sig/handler.rbs
181
199
  - sig/processor.rbs
182
200
  - sig/prosody.rbs
201
+ - sig/published.rbs
183
202
  - sig/request.rbs
184
203
  - sig/sentry.rbs
185
204
  - sig/state.rbs