prosody 0.1.1
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 +7 -0
- data/.cargo/config.toml +2 -0
- data/.release-please-manifest.json +3 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/.standard.yml +9 -0
- data/.taplo.toml +6 -0
- data/ARCHITECTURE.md +591 -0
- data/CHANGELOG.md +92 -0
- data/Cargo.lock +3513 -0
- data/Cargo.toml +77 -0
- data/LICENSE +21 -0
- data/Makefile +36 -0
- data/README.md +946 -0
- data/Rakefile +26 -0
- data/ext/prosody/Cargo.toml +38 -0
- data/ext/prosody/extconf.rb +6 -0
- data/ext/prosody/src/admin.rs +171 -0
- data/ext/prosody/src/bridge/callback.rs +60 -0
- data/ext/prosody/src/bridge/mod.rs +332 -0
- data/ext/prosody/src/client/config.rs +819 -0
- data/ext/prosody/src/client/mod.rs +379 -0
- data/ext/prosody/src/gvl.rs +149 -0
- data/ext/prosody/src/handler/context.rs +436 -0
- data/ext/prosody/src/handler/message.rs +144 -0
- data/ext/prosody/src/handler/mod.rs +338 -0
- data/ext/prosody/src/handler/trigger.rs +93 -0
- data/ext/prosody/src/lib.rs +82 -0
- data/ext/prosody/src/logging.rs +353 -0
- data/ext/prosody/src/scheduler/cancellation.rs +67 -0
- data/ext/prosody/src/scheduler/handle.rs +50 -0
- data/ext/prosody/src/scheduler/mod.rs +169 -0
- data/ext/prosody/src/scheduler/processor.rs +166 -0
- data/ext/prosody/src/scheduler/result.rs +197 -0
- data/ext/prosody/src/tracing_util.rs +56 -0
- data/ext/prosody/src/util.rs +219 -0
- data/lib/prosody/configuration.rb +333 -0
- data/lib/prosody/handler.rb +177 -0
- data/lib/prosody/native_stubs.rb +417 -0
- data/lib/prosody/processor.rb +321 -0
- data/lib/prosody/sentry.rb +36 -0
- data/lib/prosody/version.rb +10 -0
- data/lib/prosody.rb +42 -0
- data/release-please-config.json +10 -0
- data/sig/configuration.rbs +252 -0
- data/sig/handler.rbs +79 -0
- data/sig/processor.rbs +100 -0
- data/sig/prosody.rbs +171 -0
- data/sig/version.rbs +9 -0
- metadata +193 -0
|
@@ -0,0 +1,819 @@
|
|
|
1
|
+
//! # Configuration Module for Prosody Client
|
|
2
|
+
//!
|
|
3
|
+
//! This module handles the conversion between Ruby configuration objects and
|
|
4
|
+
//! the native Rust configuration structures needed by the Prosody library.
|
|
5
|
+
//! It defines serialization/deserialization logic and conversion traits that
|
|
6
|
+
//! transform Ruby configuration values into appropriate Prosody configuration
|
|
7
|
+
//! builders.
|
|
8
|
+
|
|
9
|
+
use magnus::{Error, Ruby, Value};
|
|
10
|
+
use prosody::cassandra::config::CassandraConfigurationBuilder;
|
|
11
|
+
use prosody::consumer::ConsumerConfigurationBuilder;
|
|
12
|
+
use prosody::consumer::SpanRelation;
|
|
13
|
+
use prosody::consumer::middleware::deduplication::DeduplicationConfigurationBuilder;
|
|
14
|
+
use prosody::consumer::middleware::defer::DeferConfigurationBuilder;
|
|
15
|
+
use prosody::consumer::middleware::monopolization::MonopolizationConfigurationBuilder;
|
|
16
|
+
use prosody::consumer::middleware::retry::RetryConfigurationBuilder;
|
|
17
|
+
use prosody::consumer::middleware::scheduler::SchedulerConfigurationBuilder;
|
|
18
|
+
use prosody::consumer::middleware::timeout::TimeoutConfigurationBuilder;
|
|
19
|
+
use prosody::consumer::middleware::topic::FailureTopicConfigurationBuilder;
|
|
20
|
+
use prosody::high_level::ConsumerBuilders;
|
|
21
|
+
use prosody::high_level::mode::Mode;
|
|
22
|
+
use prosody::producer::ProducerConfigurationBuilder;
|
|
23
|
+
use prosody::telemetry::emitter::TelemetryEmitterConfiguration;
|
|
24
|
+
use serde::{Deserialize, Deserializer};
|
|
25
|
+
use serde_magnus::deserialize;
|
|
26
|
+
use serde_untagged::UntaggedEnumVisitor;
|
|
27
|
+
use std::time::Duration;
|
|
28
|
+
|
|
29
|
+
/// Configuration structure for the Prosody client that maps Ruby configuration
|
|
30
|
+
/// values to their native Rust equivalents.
|
|
31
|
+
///
|
|
32
|
+
/// This structure contains all possible configuration options that can be
|
|
33
|
+
/// provided by the Ruby side, which are then converted to the appropriate
|
|
34
|
+
/// Prosody configuration builder types.
|
|
35
|
+
#[derive(Clone, Debug, Default, Deserialize)]
|
|
36
|
+
pub struct NativeConfiguration {
|
|
37
|
+
/// List of Kafka bootstrap server addresses
|
|
38
|
+
bootstrap_servers: Option<Vec<String>>,
|
|
39
|
+
|
|
40
|
+
/// Whether to use mock mode (for testing)
|
|
41
|
+
mock: Option<bool>,
|
|
42
|
+
|
|
43
|
+
/// Maximum time to wait for a send operation to complete (in seconds)
|
|
44
|
+
send_timeout: Option<f32>,
|
|
45
|
+
|
|
46
|
+
/// Kafka consumer group ID
|
|
47
|
+
group_id: Option<String>,
|
|
48
|
+
|
|
49
|
+
/// Global shared cache capacity across all partitions for message
|
|
50
|
+
/// deduplication
|
|
51
|
+
idempotence_cache_size: Option<u32>,
|
|
52
|
+
|
|
53
|
+
/// Version string for cache-busting deduplication hashes
|
|
54
|
+
idempotence_version: Option<String>,
|
|
55
|
+
|
|
56
|
+
/// TTL for deduplication records in Cassandra (in seconds)
|
|
57
|
+
idempotence_ttl: Option<f64>,
|
|
58
|
+
|
|
59
|
+
/// List of Kafka topics to subscribe to
|
|
60
|
+
subscribed_topics: Option<Vec<String>>,
|
|
61
|
+
|
|
62
|
+
/// List of event types that the consumer is allowed to process
|
|
63
|
+
allowed_events: Option<Vec<String>>,
|
|
64
|
+
|
|
65
|
+
/// Identifier for the system producing messages
|
|
66
|
+
source_system: Option<String>,
|
|
67
|
+
|
|
68
|
+
/// Maximum number of concurrent message processing tasks
|
|
69
|
+
max_concurrency: Option<u32>,
|
|
70
|
+
|
|
71
|
+
/// Maximum number of messages to process before committing offsets
|
|
72
|
+
max_uncommitted: Option<u16>,
|
|
73
|
+
|
|
74
|
+
/// Threshold in seconds after which a stalled consumer is detected
|
|
75
|
+
stall_threshold: Option<f32>,
|
|
76
|
+
|
|
77
|
+
/// Maximum time to wait for a clean shutdown (in seconds)
|
|
78
|
+
shutdown_timeout: Option<f32>,
|
|
79
|
+
|
|
80
|
+
/// Interval between Kafka poll operations (in seconds)
|
|
81
|
+
poll_interval: Option<f32>,
|
|
82
|
+
|
|
83
|
+
/// Interval between offset commit operations (in seconds)
|
|
84
|
+
commit_interval: Option<f32>,
|
|
85
|
+
|
|
86
|
+
/// Operation mode of the client (`pipeline`, `low_latency`, `best_effort`)
|
|
87
|
+
mode: Option<String>,
|
|
88
|
+
|
|
89
|
+
/// Base delay for retry operations (in seconds)
|
|
90
|
+
retry_base: Option<f32>,
|
|
91
|
+
|
|
92
|
+
/// Maximum number of retry attempts
|
|
93
|
+
max_retries: Option<u32>,
|
|
94
|
+
|
|
95
|
+
/// Maximum delay between retries (in seconds)
|
|
96
|
+
max_retry_delay: Option<f32>,
|
|
97
|
+
|
|
98
|
+
/// Topic to send failed messages to
|
|
99
|
+
failure_topic: Option<String>,
|
|
100
|
+
|
|
101
|
+
/// Configuration for the health probe port
|
|
102
|
+
probe_port: Option<ProbePort>,
|
|
103
|
+
|
|
104
|
+
/// List of Cassandra contact nodes (hostnames or IPs)
|
|
105
|
+
cassandra_nodes: Option<Vec<String>>,
|
|
106
|
+
|
|
107
|
+
/// Keyspace to use for storing timer data in Cassandra
|
|
108
|
+
cassandra_keyspace: Option<String>,
|
|
109
|
+
|
|
110
|
+
/// Preferred datacenter for Cassandra query routing
|
|
111
|
+
cassandra_datacenter: Option<String>,
|
|
112
|
+
|
|
113
|
+
/// Preferred rack identifier for Cassandra topology-aware routing
|
|
114
|
+
cassandra_rack: Option<String>,
|
|
115
|
+
|
|
116
|
+
/// Username for authenticating with Cassandra
|
|
117
|
+
cassandra_user: Option<String>,
|
|
118
|
+
|
|
119
|
+
/// Password for authenticating with Cassandra
|
|
120
|
+
cassandra_password: Option<String>,
|
|
121
|
+
|
|
122
|
+
/// Retention period for failed/unprocessed timer data in Cassandra (in
|
|
123
|
+
/// seconds)
|
|
124
|
+
cassandra_retention: Option<f32>,
|
|
125
|
+
|
|
126
|
+
/// Timer slab partitioning duration in seconds.
|
|
127
|
+
/// Controls how timers are grouped for storage and retrieval.
|
|
128
|
+
slab_size: Option<f32>,
|
|
129
|
+
|
|
130
|
+
// Scheduler configuration
|
|
131
|
+
/// Target proportion of execution time for failure/retry task processing
|
|
132
|
+
/// (0.0 to 1.0). Controls bandwidth allocation between Normal and
|
|
133
|
+
/// Failure task classes.
|
|
134
|
+
scheduler_failure_weight: Option<f64>,
|
|
135
|
+
|
|
136
|
+
/// Wait duration (in seconds) at which urgency boost reaches maximum
|
|
137
|
+
/// intensity.
|
|
138
|
+
scheduler_max_wait: Option<f32>,
|
|
139
|
+
|
|
140
|
+
/// Maximum urgency boost (in seconds of virtual time) for waiting tasks.
|
|
141
|
+
scheduler_wait_weight: Option<f64>,
|
|
142
|
+
|
|
143
|
+
/// Cache capacity for tracking per-key virtual time in the scheduler.
|
|
144
|
+
scheduler_cache_size: Option<u32>,
|
|
145
|
+
|
|
146
|
+
// Monopolization configuration
|
|
147
|
+
/// Whether monopolization detection is enabled.
|
|
148
|
+
monopolization_enabled: Option<bool>,
|
|
149
|
+
|
|
150
|
+
/// Threshold for monopolization detection (0.0 to 1.0).
|
|
151
|
+
monopolization_threshold: Option<f64>,
|
|
152
|
+
|
|
153
|
+
/// Rolling window duration (in seconds) for monopolization detection.
|
|
154
|
+
monopolization_window: Option<f32>,
|
|
155
|
+
|
|
156
|
+
/// Cache size for tracking key execution intervals.
|
|
157
|
+
monopolization_cache_size: Option<u32>,
|
|
158
|
+
|
|
159
|
+
// Defer configuration
|
|
160
|
+
/// Whether deferral is enabled for new messages.
|
|
161
|
+
defer_enabled: Option<bool>,
|
|
162
|
+
|
|
163
|
+
/// Base exponential backoff delay for deferred retries (in seconds).
|
|
164
|
+
defer_base: Option<f32>,
|
|
165
|
+
|
|
166
|
+
/// Maximum delay between deferred retries (in seconds).
|
|
167
|
+
defer_max_delay: Option<f32>,
|
|
168
|
+
|
|
169
|
+
/// Failure rate threshold for enabling deferral (0.0 to 1.0).
|
|
170
|
+
defer_failure_threshold: Option<f64>,
|
|
171
|
+
|
|
172
|
+
/// Sliding window duration (in seconds) for failure rate tracking.
|
|
173
|
+
defer_failure_window: Option<f32>,
|
|
174
|
+
|
|
175
|
+
/// Cache size for defer middleware.
|
|
176
|
+
defer_cache_size: Option<u32>,
|
|
177
|
+
|
|
178
|
+
/// Timeout for Kafka seek operations (in seconds).
|
|
179
|
+
defer_seek_timeout: Option<f32>,
|
|
180
|
+
|
|
181
|
+
/// Messages to read sequentially before seeking.
|
|
182
|
+
defer_discard_threshold: Option<i64>,
|
|
183
|
+
|
|
184
|
+
// Timeout configuration
|
|
185
|
+
/// Fixed timeout duration for handler execution (in seconds).
|
|
186
|
+
timeout: Option<f32>,
|
|
187
|
+
|
|
188
|
+
// Telemetry emitter configuration
|
|
189
|
+
/// Kafka topic to produce telemetry events to.
|
|
190
|
+
telemetry_topic: Option<String>,
|
|
191
|
+
|
|
192
|
+
/// Whether the telemetry emitter is enabled.
|
|
193
|
+
telemetry_enabled: Option<bool>,
|
|
194
|
+
|
|
195
|
+
// OTel span linking
|
|
196
|
+
/// Span linking for message execution spans (`child` or `follows_from`).
|
|
197
|
+
message_spans: Option<String>,
|
|
198
|
+
|
|
199
|
+
/// Span linking for timer execution spans (`child` or `follows_from`).
|
|
200
|
+
timer_spans: Option<String>,
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/// Configuration for the health probe port.
|
|
204
|
+
///
|
|
205
|
+
/// This enum represents the three possible states for the probe port
|
|
206
|
+
/// configuration:
|
|
207
|
+
/// - Unconfigured: The default state, where the standard configuration is used
|
|
208
|
+
/// - Disabled: Explicitly disables the probe port
|
|
209
|
+
/// - Configured: Sets the probe port to a specific port number
|
|
210
|
+
#[derive(Copy, Clone, Debug, Default)]
|
|
211
|
+
pub enum ProbePort {
|
|
212
|
+
/// Use default configuration
|
|
213
|
+
#[default]
|
|
214
|
+
Unconfigured,
|
|
215
|
+
|
|
216
|
+
/// Explicitly disable the probe port
|
|
217
|
+
Disabled,
|
|
218
|
+
|
|
219
|
+
/// Use a specific port number
|
|
220
|
+
Configured(u16),
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
impl<'de> Deserialize<'de> for ProbePort {
|
|
224
|
+
/// Deserializes a probe port configuration from various possible input
|
|
225
|
+
/// formats.
|
|
226
|
+
///
|
|
227
|
+
/// # Arguments
|
|
228
|
+
///
|
|
229
|
+
/// * `deserializer` - The deserializer to use
|
|
230
|
+
///
|
|
231
|
+
/// # Returns
|
|
232
|
+
///
|
|
233
|
+
/// A `ProbePort` enum variant based on the input:
|
|
234
|
+
/// - If a u16 is provided, it returns `ProbePort::Configured(port)`
|
|
235
|
+
/// - If a boolean `true` is provided, it returns `ProbePort::Unconfigured`
|
|
236
|
+
/// - If a boolean `false` is provided, it returns `ProbePort::Disabled`
|
|
237
|
+
/// - If nothing is provided, it returns `ProbePort::Unconfigured`
|
|
238
|
+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
239
|
+
where
|
|
240
|
+
D: Deserializer<'de>,
|
|
241
|
+
{
|
|
242
|
+
UntaggedEnumVisitor::new()
|
|
243
|
+
.u16(|port| Ok(Self::Configured(port)))
|
|
244
|
+
.bool(|enabled| {
|
|
245
|
+
if enabled {
|
|
246
|
+
Ok(Self::Unconfigured)
|
|
247
|
+
} else {
|
|
248
|
+
Ok(Self::Disabled)
|
|
249
|
+
}
|
|
250
|
+
})
|
|
251
|
+
.unit(|| Ok(Self::Unconfigured))
|
|
252
|
+
.deserialize(deserializer)
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
impl NativeConfiguration {
|
|
257
|
+
/// Converts a Ruby value into a `NativeConfiguration`.
|
|
258
|
+
///
|
|
259
|
+
/// # Arguments
|
|
260
|
+
///
|
|
261
|
+
/// * `ruby` - Reference to the Ruby VM
|
|
262
|
+
/// * `val` - The Ruby value to convert
|
|
263
|
+
///
|
|
264
|
+
/// # Returns
|
|
265
|
+
///
|
|
266
|
+
/// The converted `NativeConfiguration` if successful
|
|
267
|
+
///
|
|
268
|
+
/// # Errors
|
|
269
|
+
///
|
|
270
|
+
/// Returns a Magnus error if deserialization fails
|
|
271
|
+
pub fn from_value(ruby: &Ruby, val: Value) -> Result<Self, Error> {
|
|
272
|
+
deserialize(ruby, val)
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
impl<'a> From<&'a NativeConfiguration> for ProducerConfigurationBuilder {
|
|
277
|
+
/// Converts a `NativeConfiguration` reference into a
|
|
278
|
+
/// `ProducerConfigurationBuilder`.
|
|
279
|
+
///
|
|
280
|
+
/// This takes the relevant producer settings from the configuration and
|
|
281
|
+
/// sets them on a new `ProducerConfigurationBuilder` instance.
|
|
282
|
+
///
|
|
283
|
+
/// # Arguments
|
|
284
|
+
///
|
|
285
|
+
/// * `config` - The configuration to convert
|
|
286
|
+
///
|
|
287
|
+
/// # Returns
|
|
288
|
+
///
|
|
289
|
+
/// A configured `ProducerConfigurationBuilder`
|
|
290
|
+
fn from(config: &'a NativeConfiguration) -> Self {
|
|
291
|
+
let mut builder = Self::default();
|
|
292
|
+
|
|
293
|
+
if let Some(bootstrap_servers) = &config.bootstrap_servers {
|
|
294
|
+
builder.bootstrap_servers(bootstrap_servers.clone());
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if let Some(send_timeout) = &config.send_timeout {
|
|
298
|
+
builder.send_timeout(Duration::from_secs_f32(*send_timeout));
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if let Some(idempotence_cache_size) = &config.idempotence_cache_size {
|
|
302
|
+
builder.idempotence_cache_size(*idempotence_cache_size as usize);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if let Some(source_system) = &config.source_system {
|
|
306
|
+
builder.source_system(source_system.clone());
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if let Some(mock) = &config.mock {
|
|
310
|
+
builder.mock(*mock);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
builder
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
impl<'a> From<&'a NativeConfiguration> for ConsumerConfigurationBuilder {
|
|
318
|
+
/// Converts a `NativeConfiguration` reference into a
|
|
319
|
+
/// `ConsumerConfigurationBuilder`.
|
|
320
|
+
///
|
|
321
|
+
/// This takes the relevant consumer settings from the configuration and
|
|
322
|
+
/// sets them on a new `ConsumerConfigurationBuilder` instance.
|
|
323
|
+
///
|
|
324
|
+
/// # Arguments
|
|
325
|
+
///
|
|
326
|
+
/// * `config` - The configuration to convert
|
|
327
|
+
///
|
|
328
|
+
/// # Returns
|
|
329
|
+
///
|
|
330
|
+
/// A configured `ConsumerConfigurationBuilder`
|
|
331
|
+
fn from(config: &'a NativeConfiguration) -> Self {
|
|
332
|
+
let mut builder = Self::default();
|
|
333
|
+
|
|
334
|
+
if let Some(bootstrap_servers) = &config.bootstrap_servers {
|
|
335
|
+
builder.bootstrap_servers(bootstrap_servers.clone());
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if let Some(group_id) = &config.group_id {
|
|
339
|
+
builder.group_id(group_id.clone());
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if let Some(subscribed_topics) = &config.subscribed_topics {
|
|
343
|
+
builder.subscribed_topics(subscribed_topics.clone());
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if let Some(allowed_events) = &config.allowed_events {
|
|
347
|
+
builder.allowed_events(allowed_events.clone());
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if let Some(max_uncommitted) = &config.max_uncommitted {
|
|
351
|
+
builder.max_uncommitted(*max_uncommitted as usize);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if let Some(stall_threshold) = &config.stall_threshold {
|
|
355
|
+
builder.stall_threshold(Duration::from_secs_f32(*stall_threshold));
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if let Some(shutdown_timeout) = &config.shutdown_timeout {
|
|
359
|
+
builder.shutdown_timeout(Duration::from_secs_f32(*shutdown_timeout));
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
if let Some(poll_interval) = &config.poll_interval {
|
|
363
|
+
builder.poll_interval(Duration::from_secs_f32(*poll_interval));
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if let Some(commit_interval) = &config.commit_interval {
|
|
367
|
+
builder.commit_interval(Duration::from_secs_f32(*commit_interval));
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if let Some(mock) = &config.mock {
|
|
371
|
+
builder.mock(*mock);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if let Some(probe_port) = &config.probe_port {
|
|
375
|
+
match probe_port {
|
|
376
|
+
ProbePort::Unconfigured => {}
|
|
377
|
+
ProbePort::Disabled => {
|
|
378
|
+
builder.probe_port(None);
|
|
379
|
+
}
|
|
380
|
+
ProbePort::Configured(port) => {
|
|
381
|
+
builder.probe_port(*port);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if let Some(slab_size) = &config.slab_size {
|
|
387
|
+
builder.slab_size(Duration::from_secs_f32(*slab_size));
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
builder
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
impl<'a> From<&'a NativeConfiguration> for RetryConfigurationBuilder {
|
|
395
|
+
/// Converts a `NativeConfiguration` reference into a
|
|
396
|
+
/// `RetryConfigurationBuilder`.
|
|
397
|
+
///
|
|
398
|
+
/// This takes the relevant retry settings from the configuration and
|
|
399
|
+
/// sets them on a new `RetryConfigurationBuilder` instance.
|
|
400
|
+
///
|
|
401
|
+
/// # Arguments
|
|
402
|
+
///
|
|
403
|
+
/// * `config` - The configuration to convert
|
|
404
|
+
///
|
|
405
|
+
/// # Returns
|
|
406
|
+
///
|
|
407
|
+
/// A configured `RetryConfigurationBuilder`
|
|
408
|
+
fn from(config: &'a NativeConfiguration) -> Self {
|
|
409
|
+
let mut builder = Self::default();
|
|
410
|
+
|
|
411
|
+
if let Some(retry_base) = &config.retry_base {
|
|
412
|
+
builder.base(Duration::from_secs_f32(*retry_base));
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if let Some(max_retries) = &config.max_retries {
|
|
416
|
+
builder.max_retries(*max_retries);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
if let Some(max_retry_delay) = &config.max_retry_delay {
|
|
420
|
+
builder.max_delay(Duration::from_secs_f32(*max_retry_delay));
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
builder
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
impl<'a> From<&'a NativeConfiguration> for FailureTopicConfigurationBuilder {
|
|
428
|
+
/// Converts a `NativeConfiguration` reference into a
|
|
429
|
+
/// `FailureTopicConfigurationBuilder`.
|
|
430
|
+
///
|
|
431
|
+
/// This takes the relevant failure topic settings from the configuration
|
|
432
|
+
/// and sets them on a new `FailureTopicConfigurationBuilder` instance.
|
|
433
|
+
///
|
|
434
|
+
/// # Arguments
|
|
435
|
+
///
|
|
436
|
+
/// * `config` - The configuration to convert
|
|
437
|
+
///
|
|
438
|
+
/// # Returns
|
|
439
|
+
///
|
|
440
|
+
/// A configured `FailureTopicConfigurationBuilder`
|
|
441
|
+
fn from(config: &'a NativeConfiguration) -> Self {
|
|
442
|
+
let mut builder = Self::default();
|
|
443
|
+
|
|
444
|
+
if let Some(failure_topic) = &config.failure_topic {
|
|
445
|
+
builder.failure_topic(failure_topic.clone());
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
builder
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
impl<'a> TryFrom<&'a NativeConfiguration> for Mode {
|
|
453
|
+
type Error = String;
|
|
454
|
+
|
|
455
|
+
/// Attempts to convert a `NativeConfiguration` reference into a Prosody
|
|
456
|
+
/// Mode.
|
|
457
|
+
///
|
|
458
|
+
/// This extracts the mode setting from the configuration and converts it
|
|
459
|
+
/// to a Prosody Mode enum value.
|
|
460
|
+
///
|
|
461
|
+
/// # Arguments
|
|
462
|
+
///
|
|
463
|
+
/// * `value` - The configuration to convert
|
|
464
|
+
///
|
|
465
|
+
/// # Returns
|
|
466
|
+
///
|
|
467
|
+
/// The corresponding `Mode` if successful
|
|
468
|
+
///
|
|
469
|
+
/// # Errors
|
|
470
|
+
///
|
|
471
|
+
/// Returns a String error if the mode is unrecognized
|
|
472
|
+
fn try_from(value: &'a NativeConfiguration) -> Result<Self, Self::Error> {
|
|
473
|
+
let Some(mode_str) = value.mode.as_deref() else {
|
|
474
|
+
return Ok(Mode::default());
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
match mode_str {
|
|
478
|
+
"pipeline" => Ok(Mode::Pipeline),
|
|
479
|
+
"low_latency" => Ok(Mode::LowLatency),
|
|
480
|
+
"best_effort" => Ok(Mode::BestEffort),
|
|
481
|
+
string => Err(format!("unrecognized mode: {string}")),
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
impl<'a> From<&'a NativeConfiguration> for CassandraConfigurationBuilder {
|
|
487
|
+
/// Converts a `NativeConfiguration` reference into a
|
|
488
|
+
/// `CassandraConfigurationBuilder`.
|
|
489
|
+
///
|
|
490
|
+
/// This takes the relevant Cassandra settings from the configuration and
|
|
491
|
+
/// sets them on a new `CassandraConfigurationBuilder` instance.
|
|
492
|
+
///
|
|
493
|
+
/// # Arguments
|
|
494
|
+
///
|
|
495
|
+
/// * `config` - The configuration to convert
|
|
496
|
+
///
|
|
497
|
+
/// # Returns
|
|
498
|
+
///
|
|
499
|
+
/// A configured `CassandraConfigurationBuilder`
|
|
500
|
+
fn from(config: &'a NativeConfiguration) -> Self {
|
|
501
|
+
let mut builder = Self::default();
|
|
502
|
+
|
|
503
|
+
if let Some(nodes) = &config.cassandra_nodes {
|
|
504
|
+
builder.nodes(nodes.clone());
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
if let Some(keyspace) = &config.cassandra_keyspace {
|
|
508
|
+
builder.keyspace(keyspace.clone());
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
if let Some(datacenter) = &config.cassandra_datacenter {
|
|
512
|
+
builder.datacenter(Some(datacenter.clone()));
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
if let Some(rack) = &config.cassandra_rack {
|
|
516
|
+
builder.rack(Some(rack.clone()));
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
if let Some(user) = &config.cassandra_user {
|
|
520
|
+
builder.user(Some(user.clone()));
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
if let Some(password) = &config.cassandra_password {
|
|
524
|
+
builder.password(Some(password.clone()));
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
if let Some(retention) = &config.cassandra_retention {
|
|
528
|
+
builder.retention(Duration::from_secs_f32(*retention));
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
builder
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
impl<'a> From<&'a NativeConfiguration> for SchedulerConfigurationBuilder {
|
|
536
|
+
/// Converts a `NativeConfiguration` reference into a
|
|
537
|
+
/// `SchedulerConfigurationBuilder`.
|
|
538
|
+
///
|
|
539
|
+
/// This takes the relevant scheduler settings from the configuration and
|
|
540
|
+
/// sets them on a new `SchedulerConfigurationBuilder` instance.
|
|
541
|
+
///
|
|
542
|
+
/// # Arguments
|
|
543
|
+
///
|
|
544
|
+
/// * `config` - The configuration to convert
|
|
545
|
+
///
|
|
546
|
+
/// # Returns
|
|
547
|
+
///
|
|
548
|
+
/// A configured `SchedulerConfigurationBuilder`
|
|
549
|
+
fn from(config: &'a NativeConfiguration) -> Self {
|
|
550
|
+
let mut builder = Self::default();
|
|
551
|
+
|
|
552
|
+
if let Some(max_concurrency) = &config.max_concurrency {
|
|
553
|
+
builder.max_concurrency(*max_concurrency as usize);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
if let Some(failure_weight) = &config.scheduler_failure_weight {
|
|
557
|
+
builder.failure_weight(*failure_weight);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
if let Some(max_wait) = &config.scheduler_max_wait {
|
|
561
|
+
builder.max_wait(Duration::from_secs_f32(*max_wait));
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
if let Some(wait_weight) = &config.scheduler_wait_weight {
|
|
565
|
+
builder.wait_weight(*wait_weight);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
if let Some(cache_size) = &config.scheduler_cache_size {
|
|
569
|
+
builder.cache_size(*cache_size as usize);
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
builder
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
impl<'a> From<&'a NativeConfiguration> for MonopolizationConfigurationBuilder {
|
|
577
|
+
/// Converts a `NativeConfiguration` reference into a
|
|
578
|
+
/// `MonopolizationConfigurationBuilder`.
|
|
579
|
+
///
|
|
580
|
+
/// This takes the relevant monopolization settings from the configuration
|
|
581
|
+
/// and sets them on a new `MonopolizationConfigurationBuilder` instance.
|
|
582
|
+
///
|
|
583
|
+
/// # Arguments
|
|
584
|
+
///
|
|
585
|
+
/// * `config` - The configuration to convert
|
|
586
|
+
///
|
|
587
|
+
/// # Returns
|
|
588
|
+
///
|
|
589
|
+
/// A configured `MonopolizationConfigurationBuilder`
|
|
590
|
+
fn from(config: &'a NativeConfiguration) -> Self {
|
|
591
|
+
let mut builder = Self::default();
|
|
592
|
+
|
|
593
|
+
if let Some(enabled) = &config.monopolization_enabled {
|
|
594
|
+
builder.enabled(*enabled);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
if let Some(threshold) = &config.monopolization_threshold {
|
|
598
|
+
builder.monopolization_threshold(*threshold);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
if let Some(window) = &config.monopolization_window {
|
|
602
|
+
builder.window_duration(Duration::from_secs_f32(*window));
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
if let Some(cache_size) = &config.monopolization_cache_size {
|
|
606
|
+
builder.cache_size(*cache_size as usize);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
builder
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
impl<'a> From<&'a NativeConfiguration> for DeferConfigurationBuilder {
|
|
614
|
+
/// Converts a `NativeConfiguration` reference into a
|
|
615
|
+
/// `DeferConfigurationBuilder`.
|
|
616
|
+
///
|
|
617
|
+
/// This takes the relevant defer settings from the configuration and
|
|
618
|
+
/// sets them on a new `DeferConfigurationBuilder` instance.
|
|
619
|
+
///
|
|
620
|
+
/// # Arguments
|
|
621
|
+
///
|
|
622
|
+
/// * `config` - The configuration to convert
|
|
623
|
+
///
|
|
624
|
+
/// # Returns
|
|
625
|
+
///
|
|
626
|
+
/// A configured `DeferConfigurationBuilder`
|
|
627
|
+
fn from(config: &'a NativeConfiguration) -> Self {
|
|
628
|
+
let mut builder = Self::default();
|
|
629
|
+
|
|
630
|
+
if let Some(enabled) = &config.defer_enabled {
|
|
631
|
+
builder.enabled(*enabled);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
if let Some(base) = &config.defer_base {
|
|
635
|
+
builder.base(Duration::from_secs_f32(*base));
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
if let Some(max_delay) = &config.defer_max_delay {
|
|
639
|
+
builder.max_delay(Duration::from_secs_f32(*max_delay));
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
if let Some(failure_threshold) = &config.defer_failure_threshold {
|
|
643
|
+
builder.failure_threshold(*failure_threshold);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
if let Some(failure_window) = &config.defer_failure_window {
|
|
647
|
+
builder.failure_window(Duration::from_secs_f32(*failure_window));
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
if let Some(cache_size) = &config.defer_cache_size {
|
|
651
|
+
builder.cache_size(*cache_size as usize);
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
if let Some(seek_timeout) = &config.defer_seek_timeout {
|
|
655
|
+
builder.seek_timeout(Duration::from_secs_f32(*seek_timeout));
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
if let Some(discard_threshold) = &config.defer_discard_threshold {
|
|
659
|
+
builder.discard_threshold(*discard_threshold);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
builder
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
impl<'a> From<&'a NativeConfiguration> for TimeoutConfigurationBuilder {
|
|
667
|
+
/// Converts a `NativeConfiguration` reference into a
|
|
668
|
+
/// `TimeoutConfigurationBuilder`.
|
|
669
|
+
///
|
|
670
|
+
/// This takes the relevant timeout settings from the configuration and
|
|
671
|
+
/// sets them on a new `TimeoutConfigurationBuilder` instance.
|
|
672
|
+
///
|
|
673
|
+
/// # Arguments
|
|
674
|
+
///
|
|
675
|
+
/// * `config` - The configuration to convert
|
|
676
|
+
///
|
|
677
|
+
/// # Returns
|
|
678
|
+
///
|
|
679
|
+
/// A configured `TimeoutConfigurationBuilder`
|
|
680
|
+
fn from(config: &'a NativeConfiguration) -> Self {
|
|
681
|
+
let mut builder = Self::default();
|
|
682
|
+
|
|
683
|
+
if let Some(timeout) = &config.timeout {
|
|
684
|
+
builder.timeout(Some(Duration::from_secs_f32(*timeout)));
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
builder
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
impl<'a> From<&'a NativeConfiguration> for DeduplicationConfigurationBuilder {
|
|
692
|
+
/// Converts a `NativeConfiguration` reference into a
|
|
693
|
+
/// `DeduplicationConfigurationBuilder`.
|
|
694
|
+
///
|
|
695
|
+
/// This takes the relevant deduplication settings from the configuration
|
|
696
|
+
/// and sets them on a new `DeduplicationConfigurationBuilder` instance.
|
|
697
|
+
///
|
|
698
|
+
/// # Arguments
|
|
699
|
+
///
|
|
700
|
+
/// * `config` - The configuration to convert
|
|
701
|
+
///
|
|
702
|
+
/// # Returns
|
|
703
|
+
///
|
|
704
|
+
/// A configured `DeduplicationConfigurationBuilder`
|
|
705
|
+
fn from(config: &'a NativeConfiguration) -> Self {
|
|
706
|
+
let mut builder = Self::default();
|
|
707
|
+
|
|
708
|
+
if let Some(cache_capacity) = &config.idempotence_cache_size {
|
|
709
|
+
builder.cache_capacity(*cache_capacity as usize);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
if let Some(version) = &config.idempotence_version {
|
|
713
|
+
builder.version(version.clone());
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
if let Some(ttl) = &config.idempotence_ttl
|
|
717
|
+
&& ttl.is_finite()
|
|
718
|
+
&& *ttl >= 0.0_f64
|
|
719
|
+
{
|
|
720
|
+
builder.ttl(Duration::from_secs_f64(*ttl));
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
builder
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
impl<'a> TryFrom<&'a NativeConfiguration> for TelemetryEmitterConfiguration {
|
|
728
|
+
type Error = String;
|
|
729
|
+
|
|
730
|
+
/// Attempts to convert a `NativeConfiguration` reference into a
|
|
731
|
+
/// `TelemetryEmitterConfiguration`.
|
|
732
|
+
///
|
|
733
|
+
/// This takes the relevant telemetry emitter settings from the
|
|
734
|
+
/// configuration and constructs a `TelemetryEmitterConfiguration`,
|
|
735
|
+
/// falling back to environment-variable-aware defaults for any unset
|
|
736
|
+
/// fields.
|
|
737
|
+
///
|
|
738
|
+
/// # Arguments
|
|
739
|
+
///
|
|
740
|
+
/// * `config` - The configuration to convert
|
|
741
|
+
///
|
|
742
|
+
/// # Returns
|
|
743
|
+
///
|
|
744
|
+
/// A configured `TelemetryEmitterConfiguration` if successful
|
|
745
|
+
///
|
|
746
|
+
/// # Errors
|
|
747
|
+
///
|
|
748
|
+
/// Returns a `String` error if a related environment variable contains an
|
|
749
|
+
/// unparseable value.
|
|
750
|
+
fn try_from(config: &'a NativeConfiguration) -> Result<Self, Self::Error> {
|
|
751
|
+
let mut builder = Self::builder();
|
|
752
|
+
|
|
753
|
+
if let Some(topic) = &config.telemetry_topic {
|
|
754
|
+
builder.topic(topic.clone());
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
if let Some(enabled) = &config.telemetry_enabled {
|
|
758
|
+
builder.enabled(*enabled);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
builder.build().map_err(|e| e.to_string())
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
impl<'a> TryFrom<&'a NativeConfiguration> for ConsumerBuilders {
|
|
766
|
+
type Error = String;
|
|
767
|
+
|
|
768
|
+
/// Attempts to convert a `NativeConfiguration` reference into a
|
|
769
|
+
/// `ConsumerBuilders`.
|
|
770
|
+
///
|
|
771
|
+
/// This creates all the consumer-related configuration builders from
|
|
772
|
+
/// the configuration.
|
|
773
|
+
///
|
|
774
|
+
/// # Arguments
|
|
775
|
+
///
|
|
776
|
+
/// * `config` - The configuration to convert
|
|
777
|
+
///
|
|
778
|
+
/// # Returns
|
|
779
|
+
///
|
|
780
|
+
/// A `ConsumerBuilders` containing all consumer-related configuration
|
|
781
|
+
/// builders if successful
|
|
782
|
+
///
|
|
783
|
+
/// # Errors
|
|
784
|
+
///
|
|
785
|
+
/// Returns a `String` error if:
|
|
786
|
+
/// - The telemetry emitter configuration cannot be built (e.g. an
|
|
787
|
+
/// environment variable contains an unparseable value).
|
|
788
|
+
/// - `message_spans` or `timer_spans` contains an unrecognized value
|
|
789
|
+
/// (expected `"child"` or `"follows_from"`).
|
|
790
|
+
fn try_from(config: &'a NativeConfiguration) -> Result<Self, Self::Error> {
|
|
791
|
+
let mut consumer: ConsumerConfigurationBuilder = config.into();
|
|
792
|
+
|
|
793
|
+
if let Some(s) = &config.message_spans {
|
|
794
|
+
let relation = s
|
|
795
|
+
.parse::<SpanRelation>()
|
|
796
|
+
.map_err(|e| format!("message_spans: {e}"))?;
|
|
797
|
+
consumer.message_spans(relation);
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
if let Some(s) = &config.timer_spans {
|
|
801
|
+
let relation = s
|
|
802
|
+
.parse::<SpanRelation>()
|
|
803
|
+
.map_err(|e| format!("timer_spans: {e}"))?;
|
|
804
|
+
consumer.timer_spans(relation);
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
Ok(Self {
|
|
808
|
+
consumer,
|
|
809
|
+
retry: config.into(),
|
|
810
|
+
failure_topic: config.into(),
|
|
811
|
+
scheduler: config.into(),
|
|
812
|
+
monopolization: config.into(),
|
|
813
|
+
defer: config.into(),
|
|
814
|
+
timeout: config.into(),
|
|
815
|
+
dedup: config.into(),
|
|
816
|
+
emitter: config.try_into()?,
|
|
817
|
+
})
|
|
818
|
+
}
|
|
819
|
+
}
|