omq-backend-rust 0.2.0 → 0.3.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/CHANGELOG.md +12 -0
- data/README.md +9 -5
- data/lib/omq/backend/rust.rb +14 -7
- data/lib/omq/rust/engine.rb +76 -106
- data/lib/omq/rust/java/engine.rb +642 -0
- data/lib/omq/rust/java/platform.rb +95 -0
- data/lib/omq/rust/version.rb +13 -1
- metadata +10 -21
- data/Cargo.toml +0 -3
- data/ext/omq_backend_rust/Cargo.toml +0 -33
- data/ext/omq_backend_rust/build.rs +0 -23
- data/ext/omq_backend_rust/extconf.rb +0 -8
- data/ext/omq_backend_rust/src/error.rs +0 -16
- data/ext/omq_backend_rust/src/lib.rs +0 -51
- data/ext/omq_backend_rust/src/notify.rs +0 -69
- data/ext/omq_backend_rust/src/options.rs +0 -220
- data/ext/omq_backend_rust/src/rb.rs +0 -433
- data/ext/omq_backend_rust/src/runtime.rs +0 -439
- data/ext/omq_backend_rust/src/socket.rs +0 -707
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rbconfig"
|
|
4
|
+
|
|
5
|
+
require_relative "../version"
|
|
6
|
+
|
|
7
|
+
module OMQ
|
|
8
|
+
module Rust
|
|
9
|
+
module Java
|
|
10
|
+
class UnsupportedPlatformError < LoadError; end
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
def classifier
|
|
14
|
+
override = ENV.fetch("OMQ_JAVA_CLASSIFIER", "").strip
|
|
15
|
+
return validate_classifier(override) unless override.empty?
|
|
16
|
+
|
|
17
|
+
classifier_for(os_name: host_os_name, os_arch: host_os_arch)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def classifier_for(os_name:, os_arch:)
|
|
22
|
+
os = normalize_os(os_name)
|
|
23
|
+
arch = normalize_arch(os_arch)
|
|
24
|
+
|
|
25
|
+
classifier = "#{os}-#{arch}" if os && arch
|
|
26
|
+
return classifier if OMQ::Rust::OMQ_JAVA_CLASSIFIERS.include?(classifier)
|
|
27
|
+
|
|
28
|
+
raise UnsupportedPlatformError,
|
|
29
|
+
"unsupported OMQ.java platform: #{os_name.inspect}/#{os_arch.inspect} " \
|
|
30
|
+
"(supported: #{OMQ::Rust::OMQ_JAVA_CLASSIFIERS.join(", ")})"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def validate_classifier(classifier)
|
|
38
|
+
return classifier if OMQ::Rust::OMQ_JAVA_CLASSIFIERS.include?(classifier)
|
|
39
|
+
|
|
40
|
+
raise UnsupportedPlatformError,
|
|
41
|
+
"unsupported OMQ.java classifier: #{classifier.inspect} " \
|
|
42
|
+
"(supported: #{OMQ::Rust::OMQ_JAVA_CLASSIFIERS.join(", ")})"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def host_os_name
|
|
47
|
+
java_system_property("os.name") ||
|
|
48
|
+
RbConfig::CONFIG["host_os"] ||
|
|
49
|
+
RbConfig::CONFIG["target_os"] ||
|
|
50
|
+
RUBY_PLATFORM
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def host_os_arch
|
|
55
|
+
java_system_property("os.arch") ||
|
|
56
|
+
RbConfig::CONFIG["host_cpu"] ||
|
|
57
|
+
RbConfig::CONFIG["target_cpu"] ||
|
|
58
|
+
RUBY_PLATFORM
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def java_system_property(name)
|
|
63
|
+
return unless RUBY_ENGINE == "jruby"
|
|
64
|
+
|
|
65
|
+
require "java"
|
|
66
|
+
::Java::JavaLang::System.get_property(name)
|
|
67
|
+
rescue LoadError, NameError
|
|
68
|
+
nil
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def normalize_os(value)
|
|
73
|
+
case value.to_s.downcase
|
|
74
|
+
when /linux/
|
|
75
|
+
"linux"
|
|
76
|
+
when /darwin|mac\s*os|macos/
|
|
77
|
+
"macos"
|
|
78
|
+
when /windows|mswin|mingw|cygwin/
|
|
79
|
+
"windows"
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def normalize_arch(value)
|
|
85
|
+
case value.to_s.downcase
|
|
86
|
+
when "amd64", "x64", "x86-64", "x86_64"
|
|
87
|
+
"x86_64"
|
|
88
|
+
when "aarch64", "arm64"
|
|
89
|
+
"aarch64"
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
data/lib/omq/rust/version.rb
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module OMQ
|
|
4
|
+
module Backend
|
|
5
|
+
module Rust
|
|
6
|
+
VERSION = "0.3.0"
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
4
10
|
module Rust
|
|
5
|
-
|
|
11
|
+
OMQ_JAVA_VERSION = "0.3.0"
|
|
12
|
+
OMQ_JAVA_CLASSIFIERS = [
|
|
13
|
+
"linux-x86_64",
|
|
14
|
+
"macos-aarch64",
|
|
15
|
+
"macos-x86_64",
|
|
16
|
+
"windows-x86_64",
|
|
17
|
+
].freeze
|
|
6
18
|
end
|
|
7
19
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: omq-backend-rust
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Patrik Wenger
|
|
@@ -24,47 +24,36 @@ dependencies:
|
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: '0.28'
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
|
-
name:
|
|
27
|
+
name: omq-rs
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
29
29
|
requirements:
|
|
30
30
|
- - "~>"
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: '0.
|
|
32
|
+
version: '0.1'
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - "~>"
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: '0.
|
|
39
|
+
version: '0.1'
|
|
40
40
|
description: Drop-in Rust backend for OMQ. Same socket API (REQ/REP, PUB/SUB, PUSH/PULL,
|
|
41
|
-
DEALER/ROUTER, and all draft types),
|
|
42
|
-
|
|
43
|
-
engine.
|
|
41
|
+
DEALER/ROUTER, and all draft types), backed by the first-class omq-rs Ruby binding.
|
|
42
|
+
Fully interoperable with the default Ruby engine.
|
|
44
43
|
email:
|
|
45
44
|
- paddor@gmail.com
|
|
46
45
|
executables: []
|
|
47
|
-
extensions:
|
|
48
|
-
- ext/omq_backend_rust/extconf.rb
|
|
46
|
+
extensions: []
|
|
49
47
|
extra_rdoc_files: []
|
|
50
48
|
files:
|
|
51
49
|
- CHANGELOG.md
|
|
52
|
-
- Cargo.toml
|
|
53
50
|
- LICENSE
|
|
54
51
|
- README.md
|
|
55
|
-
- ext/omq_backend_rust/Cargo.toml
|
|
56
|
-
- ext/omq_backend_rust/build.rs
|
|
57
|
-
- ext/omq_backend_rust/extconf.rb
|
|
58
|
-
- ext/omq_backend_rust/src/error.rs
|
|
59
|
-
- ext/omq_backend_rust/src/lib.rs
|
|
60
|
-
- ext/omq_backend_rust/src/notify.rs
|
|
61
|
-
- ext/omq_backend_rust/src/options.rs
|
|
62
|
-
- ext/omq_backend_rust/src/rb.rs
|
|
63
|
-
- ext/omq_backend_rust/src/runtime.rs
|
|
64
|
-
- ext/omq_backend_rust/src/socket.rs
|
|
65
52
|
- lib/omq/backend/rust.rb
|
|
66
53
|
- lib/omq/rust/engine.rb
|
|
67
54
|
- lib/omq/rust/fd_watcher.rb
|
|
55
|
+
- lib/omq/rust/java/engine.rb
|
|
56
|
+
- lib/omq/rust/java/platform.rb
|
|
68
57
|
- lib/omq/rust/version.rb
|
|
69
58
|
homepage: https://github.com/zeromq/omq.rb/tree/main/gems/omq-backend-rust
|
|
70
59
|
licenses:
|
|
@@ -86,5 +75,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
86
75
|
requirements: []
|
|
87
76
|
rubygems_version: 4.0.16
|
|
88
77
|
specification_version: 4
|
|
89
|
-
summary:
|
|
78
|
+
summary: OMQ.rs backend for OMQ.rb
|
|
90
79
|
test_files: []
|
data/Cargo.toml
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
[package]
|
|
2
|
-
name = "omq_backend_rust"
|
|
3
|
-
version = "0.2.0"
|
|
4
|
-
edition = "2024"
|
|
5
|
-
license = "ISC"
|
|
6
|
-
authors = ["Patrik Wenger <paddor@gmail.com>"]
|
|
7
|
-
publish = false
|
|
8
|
-
|
|
9
|
-
[lib]
|
|
10
|
-
name = "omq_backend_rust"
|
|
11
|
-
crate-type = ["cdylib"]
|
|
12
|
-
|
|
13
|
-
[features]
|
|
14
|
-
default = ["plain", "curve", "lz4", "zstd"]
|
|
15
|
-
plain = ["omq-tokio/plain"]
|
|
16
|
-
curve = ["omq-tokio/curve"]
|
|
17
|
-
lz4 = ["omq-tokio/lz4"]
|
|
18
|
-
zstd = ["omq-tokio/zstd"]
|
|
19
|
-
|
|
20
|
-
[dependencies]
|
|
21
|
-
omq-proto = { version = "=0.25.1", default-features = false }
|
|
22
|
-
omq-tokio = { version = "=0.21.1", default-features = false }
|
|
23
|
-
tokio = { version = "1.52.0", features = ["rt", "rt-multi-thread", "time", "sync", "io-util", "net"] }
|
|
24
|
-
yring = { version = "0.3.11", features = ["async"] }
|
|
25
|
-
|
|
26
|
-
bytes = "1.12.0"
|
|
27
|
-
flume = { version = "0.12", default-features = false, features = ["async"] }
|
|
28
|
-
futures = { version = "0.3", default-features = false, features = ["std", "async-await"] }
|
|
29
|
-
rb-sys = "0.9"
|
|
30
|
-
libc = "0.2"
|
|
31
|
-
|
|
32
|
-
[build-dependencies]
|
|
33
|
-
rb-sys = "0.9"
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
use std::process::Command;
|
|
2
|
-
|
|
3
|
-
fn main() {
|
|
4
|
-
println!("cargo:rerun-if-env-changed=RUBY");
|
|
5
|
-
println!("cargo:rustc-check-cfg=cfg(ruby_engine, values(\"mri\", \"truffleruby\"))");
|
|
6
|
-
|
|
7
|
-
let ruby = std::env::var("RUBY").unwrap_or_else(|_| "ruby".to_string());
|
|
8
|
-
let output = Command::new(&ruby)
|
|
9
|
-
.arg("-rrbconfig")
|
|
10
|
-
.arg("-e")
|
|
11
|
-
.arg("print RbConfig::CONFIG.fetch('ruby_install_name')")
|
|
12
|
-
.output()
|
|
13
|
-
.unwrap_or_else(|err| panic!("failed to run {ruby}: {err}"));
|
|
14
|
-
|
|
15
|
-
if !output.status.success() {
|
|
16
|
-
panic!("failed to query Ruby engine with {ruby}");
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
match String::from_utf8_lossy(&output.stdout).trim() {
|
|
20
|
-
"truffleruby" => println!("cargo:rustc-cfg=ruby_engine=\"truffleruby\""),
|
|
21
|
-
_ => println!("cargo:rustc-cfg=ruby_engine=\"mri\""),
|
|
22
|
-
}
|
|
23
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
use omq_proto::error::Error as OmqError;
|
|
2
|
-
|
|
3
|
-
use crate::rb::RubyErr;
|
|
4
|
-
|
|
5
|
-
pub fn map_err(e: OmqError) -> RubyErr {
|
|
6
|
-
match e {
|
|
7
|
-
OmqError::Closed => RubyErr::io("socket closed"),
|
|
8
|
-
OmqError::Timeout => RubyErr::runtime("operation timed out"),
|
|
9
|
-
OmqError::Unroutable => RubyErr::runtime("no route to peer"),
|
|
10
|
-
OmqError::InvalidEndpoint(msg) => RubyErr::arg(msg),
|
|
11
|
-
OmqError::Protocol(msg) => RubyErr::runtime(msg),
|
|
12
|
-
OmqError::Io(e) => RubyErr::runtime(e.to_string()),
|
|
13
|
-
OmqError::HandshakeFailed(msg) => RubyErr::runtime(msg),
|
|
14
|
-
_ => RubyErr::runtime(format!("{e}")),
|
|
15
|
-
}
|
|
16
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
mod error;
|
|
2
|
-
mod notify;
|
|
3
|
-
mod options;
|
|
4
|
-
mod rb;
|
|
5
|
-
mod runtime;
|
|
6
|
-
mod socket;
|
|
7
|
-
|
|
8
|
-
use rb_sys::VALUE;
|
|
9
|
-
|
|
10
|
-
use crate::rb::{RbResult, RubyErr};
|
|
11
|
-
|
|
12
|
-
fn set_io_threads_impl(n: VALUE) -> RbResult<VALUE> {
|
|
13
|
-
let n = rb::value_to_i64(n)?;
|
|
14
|
-
if n < 0 {
|
|
15
|
-
return Err(RubyErr::arg("io_threads must be non-negative"));
|
|
16
|
-
}
|
|
17
|
-
let n = usize::try_from(n).map_err(|_| RubyErr::arg("io_threads too large"))?;
|
|
18
|
-
socket::set_io_threads(n);
|
|
19
|
-
Ok(rb::qnil())
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
unsafe extern "C" fn set_io_threads(_module: VALUE, n: VALUE) -> VALUE {
|
|
23
|
-
rb::wrap(|| set_io_threads_impl(n))
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
#[unsafe(no_mangle)]
|
|
27
|
-
/// # Safety
|
|
28
|
-
///
|
|
29
|
-
/// Ruby calls this once while loading the native extension.
|
|
30
|
-
pub unsafe extern "C" fn Init_omq_backend_rust() {
|
|
31
|
-
rb::wrap_init(init);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
fn init() -> RbResult<()> {
|
|
35
|
-
#[cfg(ruby_engine = "mri")]
|
|
36
|
-
unsafe {
|
|
37
|
-
rb_sys::rb_ext_ractor_safe(true);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
let omq = unsafe { rb::define_module(c"OMQ")? };
|
|
41
|
-
let rust = unsafe { rb::define_module_under(omq, c"Rust")? };
|
|
42
|
-
let native = unsafe { rb::define_module_under(rust, c"Native")? };
|
|
43
|
-
|
|
44
|
-
unsafe {
|
|
45
|
-
rb::define_module_function_1(native, c"io_threads=", set_io_threads)?;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
socket::register(native)?;
|
|
49
|
-
|
|
50
|
-
Ok(())
|
|
51
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
use std::os::fd::RawFd;
|
|
2
|
-
use std::sync::atomic::{AtomicBool, Ordering};
|
|
3
|
-
|
|
4
|
-
pub struct PipeNotify {
|
|
5
|
-
read_fd: RawFd,
|
|
6
|
-
write_fd: RawFd,
|
|
7
|
-
parking: AtomicBool,
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
unsafe impl Send for PipeNotify {}
|
|
11
|
-
unsafe impl Sync for PipeNotify {}
|
|
12
|
-
|
|
13
|
-
impl PipeNotify {
|
|
14
|
-
pub fn new() -> Self {
|
|
15
|
-
let mut fds = [0i32; 2];
|
|
16
|
-
let ret = unsafe { libc::pipe2(fds.as_mut_ptr(), libc::O_NONBLOCK | libc::O_CLOEXEC) };
|
|
17
|
-
assert!(
|
|
18
|
-
ret == 0,
|
|
19
|
-
"pipe2 failed: {}",
|
|
20
|
-
std::io::Error::last_os_error()
|
|
21
|
-
);
|
|
22
|
-
Self {
|
|
23
|
-
read_fd: fds[0],
|
|
24
|
-
write_fd: fds[1],
|
|
25
|
-
parking: AtomicBool::new(false),
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
pub fn notify(&self) {
|
|
30
|
-
if self.parking.load(Ordering::Acquire) {
|
|
31
|
-
self.write_byte();
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
pub fn force_wake(&self) {
|
|
36
|
-
self.write_byte();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
pub fn read_fd(&self) -> RawFd {
|
|
40
|
-
self.read_fd
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
pub fn park_begin(&self) {
|
|
44
|
-
self.parking.store(true, Ordering::Release);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
fn write_byte(&self) {
|
|
48
|
-
let val: u8 = 1;
|
|
49
|
-
loop {
|
|
50
|
-
let ret =
|
|
51
|
-
unsafe { libc::write(self.write_fd, &val as *const u8 as *const libc::c_void, 1) };
|
|
52
|
-
if ret >= 0 {
|
|
53
|
-
break;
|
|
54
|
-
}
|
|
55
|
-
if std::io::Error::last_os_error().raw_os_error() != Some(libc::EINTR) {
|
|
56
|
-
break;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
impl Drop for PipeNotify {
|
|
63
|
-
fn drop(&mut self) {
|
|
64
|
-
unsafe {
|
|
65
|
-
libc::close(self.read_fd);
|
|
66
|
-
libc::close(self.write_fd);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
use std::time::Duration;
|
|
2
|
-
|
|
3
|
-
use bytes::Bytes;
|
|
4
|
-
|
|
5
|
-
use rb_sys::VALUE;
|
|
6
|
-
|
|
7
|
-
use crate::rb::{self, RbResult, RubyErr};
|
|
8
|
-
|
|
9
|
-
pub fn build_options(hash: VALUE) -> RbResult<omq_tokio::Options> {
|
|
10
|
-
rb::check_hash(hash)?;
|
|
11
|
-
|
|
12
|
-
let mut opts = omq_tokio::Options::default();
|
|
13
|
-
|
|
14
|
-
if let Some(v) = get_opt_i64(hash, "send_hwm")? {
|
|
15
|
-
opts.send_hwm = v.max(0) as u32;
|
|
16
|
-
}
|
|
17
|
-
if let Some(v) = get_opt_i64(hash, "recv_hwm")? {
|
|
18
|
-
opts.recv_hwm = v.max(0) as u32;
|
|
19
|
-
}
|
|
20
|
-
if let Some(v) = get_opt_f64(hash, "linger")? {
|
|
21
|
-
opts.linger = if v.is_infinite() && v.is_sign_positive() {
|
|
22
|
-
None
|
|
23
|
-
} else {
|
|
24
|
-
Some(duration_from_seconds("linger", v)?)
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
if let Some(v) = get_opt_bytes(hash, "identity")?
|
|
28
|
-
&& !v.is_empty()
|
|
29
|
-
{
|
|
30
|
-
opts.identity = Bytes::from(v);
|
|
31
|
-
}
|
|
32
|
-
if let Some(v) = get_opt_bool(hash, "router_mandatory")? {
|
|
33
|
-
opts.router_mandatory = v;
|
|
34
|
-
}
|
|
35
|
-
if let Some(v) = get_opt_bool(hash, "conflate")? {
|
|
36
|
-
opts.conflate = v;
|
|
37
|
-
}
|
|
38
|
-
if let Some(v) = get_opt_duration(hash, "heartbeat_interval")? {
|
|
39
|
-
opts.heartbeat_interval = Some(v);
|
|
40
|
-
}
|
|
41
|
-
if let Some(v) = get_opt_duration(hash, "heartbeat_ttl")? {
|
|
42
|
-
opts.heartbeat_ttl = Some(v);
|
|
43
|
-
}
|
|
44
|
-
if let Some(v) = get_opt_duration(hash, "heartbeat_timeout")? {
|
|
45
|
-
opts.heartbeat_timeout = Some(v);
|
|
46
|
-
}
|
|
47
|
-
if let Some(v) = get_opt_usize(hash, "max_message_size")? {
|
|
48
|
-
opts.max_message_size = Some(v);
|
|
49
|
-
}
|
|
50
|
-
if let Some(v) = get_opt_usize(hash, "sndbuf")? {
|
|
51
|
-
opts.send_buffer_size = Some(v);
|
|
52
|
-
}
|
|
53
|
-
if let Some(v) = get_opt_usize(hash, "rcvbuf")? {
|
|
54
|
-
opts.recv_buffer_size = Some(v);
|
|
55
|
-
}
|
|
56
|
-
if let Some(v) = get_opt_bytes(hash, "compression_dict")?
|
|
57
|
-
&& !v.is_empty()
|
|
58
|
-
{
|
|
59
|
-
opts.compression_dict = Some(Bytes::from(v));
|
|
60
|
-
}
|
|
61
|
-
if let Some(v) = get_opt_bool(hash, "compression_auto_train")? {
|
|
62
|
-
opts.compression_auto_train = v;
|
|
63
|
-
}
|
|
64
|
-
if let Some(v) = get_opt_usize(hash, "compression_threshold")? {
|
|
65
|
-
opts.compression_threshold = Some(v);
|
|
66
|
-
}
|
|
67
|
-
if let Some(v) = get_opt_i64(hash, "compression_level")? {
|
|
68
|
-
opts.compression_level = Some(v as i32);
|
|
69
|
-
}
|
|
70
|
-
if let Some(v) = get_opt_usize(hash, "compression_dict_capacity")? {
|
|
71
|
-
opts.compression_dict_capacity = Some(v);
|
|
72
|
-
}
|
|
73
|
-
if let Some(v) = get_opt_usize(hash, "max_recv_dict_size")? {
|
|
74
|
-
opts.max_recv_dict_size = Some(v);
|
|
75
|
-
}
|
|
76
|
-
if let Some(v) = get_opt_i64(hash, "compression_offload_threshold")? {
|
|
77
|
-
opts.compression_offload_threshold = if v < 0 { None } else { Some(v as usize) };
|
|
78
|
-
}
|
|
79
|
-
if let Some(v) = get_opt_string(hash, "on_mute")? {
|
|
80
|
-
opts.on_mute = match v.as_str() {
|
|
81
|
-
"drop_newest" | "drop" => omq_tokio::OnMute::DropNewest,
|
|
82
|
-
_ => omq_tokio::OnMute::Block,
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if let Some(v) = get_opt_f64(hash, "reconnect_interval")? {
|
|
87
|
-
opts.reconnect = omq_proto::options::ReconnectPolicy::Fixed(duration_from_seconds(
|
|
88
|
-
"reconnect_interval",
|
|
89
|
-
v,
|
|
90
|
-
)?);
|
|
91
|
-
}
|
|
92
|
-
if let Some(min) = get_opt_f64(hash, "reconnect_interval_min")? {
|
|
93
|
-
let max = get_opt_f64(hash, "reconnect_interval_max")?.unwrap_or(min * 16.0);
|
|
94
|
-
opts.reconnect = omq_proto::options::ReconnectPolicy::Exponential {
|
|
95
|
-
min: duration_from_seconds("reconnect_interval min", min)?,
|
|
96
|
-
max: duration_from_seconds("reconnect_interval max", max)?,
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if let Some(mech_type) = get_opt_string(hash, "mechanism_type")? {
|
|
101
|
-
apply_mechanism(hash, &mech_type, &mut opts)?;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
Ok(opts)
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
fn apply_mechanism(hash: VALUE, mech_type: &str, opts: &mut omq_tokio::Options) -> RbResult<()> {
|
|
108
|
-
match mech_type {
|
|
109
|
-
"null" => {}
|
|
110
|
-
|
|
111
|
-
#[cfg(feature = "curve")]
|
|
112
|
-
"curve" => {
|
|
113
|
-
let is_server = get_opt_bool(hash, "mechanism_server")?.unwrap_or(false);
|
|
114
|
-
let pub_key = get_opt_bytes(hash, "mechanism_public_key")?;
|
|
115
|
-
let sec_key = get_opt_bytes(hash, "mechanism_secret_key")?;
|
|
116
|
-
|
|
117
|
-
if is_server {
|
|
118
|
-
if let (Some(pk), Some(sk)) = (pub_key, sec_key) {
|
|
119
|
-
let keypair = omq_proto::CurveKeypair {
|
|
120
|
-
public: omq_proto::CurvePublicKey::from_bytes(to_32(&pk, "public key")?),
|
|
121
|
-
secret: omq_proto::CurveSecretKey::from_bytes(to_32(&sk, "secret key")?),
|
|
122
|
-
};
|
|
123
|
-
opts.mechanism = omq_proto::MechanismSetup::CurveServer {
|
|
124
|
-
our_keypair: keypair,
|
|
125
|
-
options: omq_proto::CurveServerOptions::default(),
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
} else {
|
|
129
|
-
let srv_key = get_opt_bytes(hash, "mechanism_server_key")?;
|
|
130
|
-
if let (Some(pk), Some(sk), Some(svk)) = (pub_key, sec_key, srv_key) {
|
|
131
|
-
let keypair = omq_proto::CurveKeypair {
|
|
132
|
-
public: omq_proto::CurvePublicKey::from_bytes(to_32(&pk, "public key")?),
|
|
133
|
-
secret: omq_proto::CurveSecretKey::from_bytes(to_32(&sk, "secret key")?),
|
|
134
|
-
};
|
|
135
|
-
opts.mechanism = omq_proto::MechanismSetup::CurveClient {
|
|
136
|
-
our_keypair: keypair,
|
|
137
|
-
server_public: omq_proto::CurvePublicKey::from_bytes(to_32(
|
|
138
|
-
&svk,
|
|
139
|
-
"server key",
|
|
140
|
-
)?),
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
_ => {}
|
|
147
|
-
}
|
|
148
|
-
Ok(())
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
fn to_32(bytes: &[u8], label: &str) -> RbResult<[u8; 32]> {
|
|
152
|
-
bytes.try_into().map_err(|_| {
|
|
153
|
-
RubyErr::arg(format!(
|
|
154
|
-
"{label} must be exactly 32 bytes, got {}",
|
|
155
|
-
bytes.len()
|
|
156
|
-
))
|
|
157
|
-
})
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
fn get_opt_bytes(hash: VALUE, key: &str) -> RbResult<Option<Vec<u8>>> {
|
|
161
|
-
match rb::hash_get(hash, key)? {
|
|
162
|
-
Some(v) if v == rb::qnil() => Ok(None),
|
|
163
|
-
Some(v) => Ok(Some(rb::value_to_bytes(v)?)),
|
|
164
|
-
None => Ok(None),
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
fn get_opt_string(hash: VALUE, key: &str) -> RbResult<Option<String>> {
|
|
169
|
-
match rb::hash_get(hash, key)? {
|
|
170
|
-
Some(v) if v == rb::qnil() => Ok(None),
|
|
171
|
-
Some(v) => Ok(Some(rb::value_to_string(v)?)),
|
|
172
|
-
None => Ok(None),
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
fn get_opt_i64(hash: VALUE, key: &str) -> RbResult<Option<i64>> {
|
|
177
|
-
match rb::hash_get(hash, key)? {
|
|
178
|
-
Some(v) if v == rb::qnil() => Ok(None),
|
|
179
|
-
Some(v) => Ok(Some(rb::value_to_i64(v)?)),
|
|
180
|
-
None => Ok(None),
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
fn get_opt_f64(hash: VALUE, key: &str) -> RbResult<Option<f64>> {
|
|
185
|
-
match rb::hash_get(hash, key)? {
|
|
186
|
-
Some(v) if v == rb::qnil() => Ok(None),
|
|
187
|
-
Some(v) => Ok(Some(rb::value_to_f64(v)?)),
|
|
188
|
-
None => Ok(None),
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
fn get_opt_usize(hash: VALUE, key: &str) -> RbResult<Option<usize>> {
|
|
193
|
-
let Some(v) = get_opt_i64(hash, key)? else {
|
|
194
|
-
return Ok(None);
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
usize::try_from(v)
|
|
198
|
-
.map(Some)
|
|
199
|
-
.map_err(|_| RubyErr::arg(format!("{key} must be non-negative")))
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
fn get_opt_bool(hash: VALUE, key: &str) -> RbResult<Option<bool>> {
|
|
203
|
-
match rb::hash_get(hash, key)? {
|
|
204
|
-
Some(v) if v == rb::qnil() => Ok(None),
|
|
205
|
-
Some(v) => Ok(Some(rb::value_to_bool(v)?)),
|
|
206
|
-
None => Ok(None),
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
fn get_opt_duration(hash: VALUE, key: &str) -> RbResult<Option<Duration>> {
|
|
211
|
-
match get_opt_f64(hash, key)? {
|
|
212
|
-
Some(v) => Ok(Some(duration_from_seconds(key, v)?)),
|
|
213
|
-
None => Ok(None),
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
fn duration_from_seconds(label: &str, value: f64) -> RbResult<Duration> {
|
|
218
|
-
Duration::try_from_secs_f64(value)
|
|
219
|
-
.map_err(|_| RubyErr::arg(format!("{label} must be finite and non-negative")))
|
|
220
|
-
}
|