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.
- checksums.yaml +4 -4
- data/.config/rail.toml +26 -0
- data/.release-please-manifest.json +1 -1
- data/.ruby-version +1 -1
- data/.taplo.toml +1 -1
- data/AGENTS.md +29 -15
- data/CHANGELOG.md +7 -0
- data/CONFIGURATION.md +19 -16
- data/Cargo.lock +254 -235
- data/Cargo.toml +11 -8
- data/README.md +100 -23
- data/examples/keyed_state.rb +10 -2
- data/examples/keyed_state.rbs +1 -0
- data/ext/prosody/Cargo.toml +1 -1
- data/ext/prosody/src/admin.rs +36 -36
- data/ext/prosody/src/bridge/mod.rs +5 -10
- data/ext/prosody/src/client/config/connections.rs +170 -0
- data/ext/prosody/src/client/config/middleware.rs +184 -0
- data/ext/prosody/src/client/config/mod.rs +396 -0
- data/ext/prosody/src/client/config/state.rs +323 -0
- data/ext/prosody/src/client/mod.rs +31 -117
- data/ext/prosody/src/client/readers.rs +106 -0
- data/ext/prosody/src/client/request.rs +2 -2
- data/ext/prosody/src/client/support.rs +13 -32
- data/ext/prosody/src/gvl.rs +8 -6
- data/ext/prosody/src/handler/{context.rs → context/mod.rs} +36 -150
- data/ext/prosody/src/handler/context/vending.rs +138 -0
- data/ext/prosody/src/handler/message.rs +36 -0
- data/ext/prosody/src/handler/mod.rs +18 -8
- data/ext/prosody/src/handler/state/deque.rs +144 -0
- data/ext/prosody/src/handler/state/mod.rs +163 -268
- data/ext/prosody/src/handler/state/query.rs +264 -0
- data/ext/prosody/src/handler/state/registration.rs +15 -86
- data/ext/prosody/src/handler/state/scan.rs +33 -141
- data/ext/prosody/src/handler/state/set.rs +98 -0
- data/ext/prosody/src/lib.rs +54 -36
- data/ext/prosody/src/logging.rs +6 -6
- data/ext/prosody/src/published.rs +171 -152
- data/ext/prosody/src/scheduler/result.rs +2 -1
- data/ext/prosody/src/util.rs +65 -3
- data/lib/prosody/client.rb +32 -0
- data/lib/prosody/configuration.rb +20 -12
- data/lib/prosody/demand.rb +27 -0
- data/lib/prosody/native_stubs/client.rb +157 -0
- data/lib/prosody/native_stubs/context.rb +178 -0
- data/lib/prosody/native_stubs/message.rb +133 -0
- data/lib/prosody/native_stubs.rb +11 -956
- data/lib/prosody/state/deque.rb +253 -0
- data/lib/prosody/state/map.rb +313 -0
- data/lib/prosody/state/set.rb +121 -0
- data/lib/prosody/state/value.rb +58 -0
- data/lib/prosody/state.rb +157 -677
- data/lib/prosody/version.rb +1 -1
- data/lib/prosody.rb +2 -1
- data/sig/configuration.rbs +19 -10
- data/sig/prosody.rbs +37 -4
- data/sig/published.rbs +102 -0
- data/sig/state.rbs +109 -122
- data/typecheck/payload_types.rb +12 -0
- data/typecheck/payload_types.rbs +1 -0
- metadata +30 -11
- data/ext/prosody/src/client/config.rs +0 -1300
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
//! Native handle for a presence-only ordered set of `String` members.
|
|
2
|
+
//!
|
|
3
|
+
//! A set stores membership only. Member traversal reuses the map key cursor,
|
|
4
|
+
//! since both yield bare `String` keys.
|
|
5
|
+
|
|
6
|
+
use super::{NativeMapKeyScan, key_query, outcome_symbol, run_state, wrapped_class};
|
|
7
|
+
use crate::bridge::Bridge;
|
|
8
|
+
use magnus::{Error, Module, RHash, RModule, Ruby, StaticSymbol, method};
|
|
9
|
+
use opentelemetry::propagation::TextMapCompositePropagator;
|
|
10
|
+
use prosody::consumer::event_context::DynSetState;
|
|
11
|
+
use std::sync::Arc;
|
|
12
|
+
|
|
13
|
+
/// Native set handle, wrapped by `Prosody::SetState`.
|
|
14
|
+
#[magnus::wrap(class = "Prosody::NativeSetState")]
|
|
15
|
+
pub struct NativeSetState {
|
|
16
|
+
state: Arc<dyn DynSetState>,
|
|
17
|
+
bridge: Bridge,
|
|
18
|
+
propagator: Arc<TextMapCompositePropagator>,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
impl NativeSetState {
|
|
22
|
+
pub(crate) fn new(
|
|
23
|
+
state: Arc<dyn DynSetState>,
|
|
24
|
+
bridge: Bridge,
|
|
25
|
+
propagator: Arc<TextMapCompositePropagator>,
|
|
26
|
+
) -> Self {
|
|
27
|
+
Self {
|
|
28
|
+
state,
|
|
29
|
+
bridge,
|
|
30
|
+
propagator,
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
fn contains(ruby: &Ruby, this: &Self, member: String) -> Result<bool, Error> {
|
|
35
|
+
run_op!(ruby, this, &this.state, contains(member))
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
fn contains_many(ruby: &Ruby, this: &Self, members: Vec<String>) -> Result<Vec<bool>, Error> {
|
|
39
|
+
run_op!(ruby, this, &this.state, contains_many(members))
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
fn is_empty(ruby: &Ruby, this: &Self) -> Result<bool, Error> {
|
|
43
|
+
run_op!(ruby, this, &this.state, is_empty())
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
fn insert(ruby: &Ruby, this: &Self, member: String) -> Result<(), Error> {
|
|
47
|
+
run_op!(ruby, this, &this.state, insert(member))
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
fn remove(ruby: &Ruby, this: &Self, member: String) -> Result<(), Error> {
|
|
51
|
+
run_op!(ruby, this, &this.state, remove(member))
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
fn clear(ruby: &Ruby, this: &Self) -> Result<(), Error> {
|
|
55
|
+
run_op!(ruby, this, &this.state, clear())
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
fn keys(
|
|
59
|
+
ruby: &Ruby,
|
|
60
|
+
this: &Self,
|
|
61
|
+
direction: StaticSymbol,
|
|
62
|
+
options: RHash,
|
|
63
|
+
) -> Result<NativeMapKeyScan, Error> {
|
|
64
|
+
let query = key_query(ruby, direction, options)?;
|
|
65
|
+
Ok(NativeMapKeyScan::new(
|
|
66
|
+
this.state.keys().with_query(query).stream(),
|
|
67
|
+
this.bridge.clone(),
|
|
68
|
+
Arc::clone(&this.propagator),
|
|
69
|
+
))
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
fn commit(ruby: &Ruby, this: &Self) -> Result<StaticSymbol, Error> {
|
|
73
|
+
let outcome = run_op!(ruby, this, &this.state, commit())?;
|
|
74
|
+
Ok(outcome_symbol(ruby, outcome))
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
fn rollback(ruby: &Ruby, this: &Self) -> Result<StaticSymbol, Error> {
|
|
78
|
+
let state = Arc::clone(&this.state);
|
|
79
|
+
let outcome = run_state(ruby, &this.bridge, &this.propagator, async move {
|
|
80
|
+
Ok(state.rollback().await)
|
|
81
|
+
})?;
|
|
82
|
+
Ok(outcome_symbol(ruby, outcome))
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
pub(super) fn register(ruby: &Ruby, module: RModule) -> Result<(), Error> {
|
|
86
|
+
let class = wrapped_class(ruby, module, "Prosody::NativeSetState")?;
|
|
87
|
+
class.define_method("contains", method!(NativeSetState::contains, 1))?;
|
|
88
|
+
class.define_method("contains_many", method!(NativeSetState::contains_many, 1))?;
|
|
89
|
+
class.define_method("is_empty", method!(NativeSetState::is_empty, 0))?;
|
|
90
|
+
class.define_method("insert", method!(NativeSetState::insert, 1))?;
|
|
91
|
+
class.define_method("remove", method!(NativeSetState::remove, 1))?;
|
|
92
|
+
class.define_method("clear", method!(NativeSetState::clear, 0))?;
|
|
93
|
+
class.define_method("keys", method!(NativeSetState::keys, 2))?;
|
|
94
|
+
class.define_method("commit", method!(NativeSetState::commit, 0))?;
|
|
95
|
+
class.define_method("rollback", method!(NativeSetState::rollback, 0))?;
|
|
96
|
+
Ok(())
|
|
97
|
+
}
|
|
98
|
+
}
|
data/ext/prosody/src/lib.rs
CHANGED
|
@@ -8,19 +8,20 @@
|
|
|
8
8
|
//! provides client functionality for interacting with message brokers,
|
|
9
9
|
//! manages message handling, and includes logging and scheduling capabilities.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
#![expect(
|
|
12
|
+
clippy::multiple_crate_versions,
|
|
13
|
+
reason = "the dependency graph resolves some crates at two versions"
|
|
14
|
+
)]
|
|
14
15
|
#![recursion_limit = "256"]
|
|
15
16
|
|
|
16
17
|
use crate::bridge::Bridge;
|
|
18
|
+
use crate::util::report;
|
|
19
|
+
use magnus::RModule;
|
|
17
20
|
use magnus::value::Lazy;
|
|
18
|
-
use
|
|
19
|
-
use mimalloc::MiMalloc;
|
|
20
|
-
use std::io::{self, Write};
|
|
21
|
+
use rustfs_mimalloc::MiMalloc;
|
|
21
22
|
use std::process;
|
|
22
23
|
use std::sync::{LazyLock, OnceLock};
|
|
23
|
-
use tokio::runtime::Runtime;
|
|
24
|
+
use tokio::runtime::{Builder, Runtime};
|
|
24
25
|
|
|
25
26
|
mod admin;
|
|
26
27
|
mod bridge;
|
|
@@ -33,6 +34,13 @@ mod scheduler;
|
|
|
33
34
|
mod tracing_util;
|
|
34
35
|
mod util;
|
|
35
36
|
|
|
37
|
+
/// Stack size of each Tokio worker thread.
|
|
38
|
+
///
|
|
39
|
+
/// Core futures are large, most of all in debug builds. A timer write that
|
|
40
|
+
/// polls through the Cassandra driver can overflow the Tokio default of
|
|
41
|
+
/// 2 MiB. The size applies to every build.
|
|
42
|
+
const WORKER_STACK_SIZE: usize = 8 * 1024 * 1024;
|
|
43
|
+
|
|
36
44
|
#[global_allocator]
|
|
37
45
|
static GLOBAL: MiMalloc = MiMalloc;
|
|
38
46
|
|
|
@@ -47,14 +55,18 @@ pub static TRACING_INIT: OnceLock<()> = OnceLock::new();
|
|
|
47
55
|
///
|
|
48
56
|
/// This runtime powers all async operations in the extension, including
|
|
49
57
|
/// message processing, scheduling, and communication with Ruby.
|
|
50
|
-
static RUNTIME: LazyLock<Runtime> = LazyLock::new(||
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
+
static RUNTIME: LazyLock<Runtime> = LazyLock::new(|| {
|
|
59
|
+
let runtime = Builder::new_multi_thread()
|
|
60
|
+
.enable_all()
|
|
61
|
+
.thread_stack_size(WORKER_STACK_SIZE)
|
|
62
|
+
.build();
|
|
63
|
+
|
|
64
|
+
match runtime {
|
|
65
|
+
Ok(runtime) => runtime,
|
|
66
|
+
Err(error) => {
|
|
67
|
+
report(format_args!("failed to create Tokio runtime: {error:#}"));
|
|
68
|
+
process::abort();
|
|
69
|
+
}
|
|
58
70
|
}
|
|
59
71
|
});
|
|
60
72
|
|
|
@@ -62,32 +74,38 @@ static RUNTIME: LazyLock<Runtime> = LazyLock::new(|| match Runtime::new() {
|
|
|
62
74
|
///
|
|
63
75
|
/// This is lazily initialized during extension startup and provides
|
|
64
76
|
/// access to the `Prosody` module in Ruby.
|
|
65
|
-
#[
|
|
77
|
+
#[expect(
|
|
78
|
+
clippy::expect_used,
|
|
79
|
+
reason = "magnus Lazy takes an infallible initializer"
|
|
80
|
+
)]
|
|
66
81
|
pub static ROOT_MOD: Lazy<RModule> = Lazy::new(|ruby| {
|
|
67
82
|
ruby.define_module("Prosody")
|
|
68
83
|
.expect("Failed to define Prosody module")
|
|
69
84
|
});
|
|
70
85
|
|
|
71
|
-
///
|
|
72
|
-
///
|
|
73
|
-
/// This function initializes the various components of the extension.
|
|
86
|
+
/// The extension entry point that Ruby calls when it loads the library.
|
|
74
87
|
///
|
|
75
|
-
///
|
|
76
|
-
///
|
|
77
|
-
///
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
///
|
|
81
|
-
/// Returns a Magnus error if any initialization step fails, such as
|
|
82
|
-
/// defining Ruby classes or configuring components.
|
|
83
|
-
#[magnus::init]
|
|
84
|
-
fn init(ruby: &Ruby) -> Result<(), Error> {
|
|
85
|
-
admin::init(ruby)?;
|
|
86
|
-
bridge::init(ruby)?;
|
|
87
|
-
handler::init(ruby)?;
|
|
88
|
-
published::init(ruby)?;
|
|
89
|
-
client::init(ruby)?;
|
|
90
|
-
util::init(ruby)?;
|
|
88
|
+
/// `#[magnus::init]` generates the exported `Init_prosody` function beside
|
|
89
|
+
/// `init`. The module is private, so that generated function is not public
|
|
90
|
+
/// API.
|
|
91
|
+
mod entry {
|
|
92
|
+
use magnus::{Error, Ruby};
|
|
91
93
|
|
|
92
|
-
|
|
94
|
+
/// Initializes the Prosody Ruby extension.
|
|
95
|
+
///
|
|
96
|
+
/// # Errors
|
|
97
|
+
///
|
|
98
|
+
/// Returns a Magnus error if any initialization step fails, such as
|
|
99
|
+
/// defining Ruby classes or configuring components.
|
|
100
|
+
#[magnus::init]
|
|
101
|
+
fn init(ruby: &Ruby) -> Result<(), Error> {
|
|
102
|
+
crate::admin::init(ruby)?;
|
|
103
|
+
crate::bridge::init(ruby)?;
|
|
104
|
+
crate::handler::init(ruby)?;
|
|
105
|
+
crate::published::init(ruby)?;
|
|
106
|
+
crate::client::init(ruby)?;
|
|
107
|
+
crate::util::init(ruby)?;
|
|
108
|
+
|
|
109
|
+
Ok(())
|
|
110
|
+
}
|
|
93
111
|
}
|
data/ext/prosody/src/logging.rs
CHANGED
|
@@ -8,12 +8,10 @@
|
|
|
8
8
|
//! It uses bump allocation for efficient string formatting and concurrent
|
|
9
9
|
//! processing for high-throughput logging scenarios.
|
|
10
10
|
|
|
11
|
-
#![allow(clippy::print_stderr)]
|
|
12
|
-
|
|
13
11
|
use crate::ROOT_MOD;
|
|
14
12
|
use crate::bridge::Bridge;
|
|
15
13
|
use crate::id;
|
|
16
|
-
use crate::util::ThreadSafeValue;
|
|
14
|
+
use crate::util::{ThreadSafeValue, report};
|
|
17
15
|
use bumpalo::Bump;
|
|
18
16
|
use bumpalo::collections::string::String as BumpString;
|
|
19
17
|
use educe::Educe;
|
|
@@ -113,12 +111,12 @@ async fn log_event(bridge: Bridge, logger: Arc<ThreadSafeValue>, (level, msg): (
|
|
|
113
111
|
};
|
|
114
112
|
|
|
115
113
|
if let Err(error) = logger.get(ruby).funcall::<_, _, Value>(method, (msg,)) {
|
|
116
|
-
|
|
114
|
+
report(format_args!("failed to log to Ruby: {error:#}"));
|
|
117
115
|
}
|
|
118
116
|
})
|
|
119
117
|
.await
|
|
120
118
|
{
|
|
121
|
-
|
|
119
|
+
report(format_args!("failed to log to Ruby: {error:#}"));
|
|
122
120
|
}
|
|
123
121
|
}
|
|
124
122
|
|
|
@@ -150,7 +148,9 @@ impl<S: Subscriber> Layer<S> for Logger {
|
|
|
150
148
|
event.record(&mut visitor);
|
|
151
149
|
|
|
152
150
|
if let Err(error) = self.tx.send((*metadata.level(), visitor.to_string())) {
|
|
153
|
-
|
|
151
|
+
report(format_args!(
|
|
152
|
+
"failed to send log message: {error:#}; message: {visitor}"
|
|
153
|
+
));
|
|
154
154
|
}
|
|
155
155
|
});
|
|
156
156
|
}
|