test-valkey-glide-rb 0.0.1.pre.rc1
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/.rubocop.yml +69 -0
- data/.rubocop_todo.yml +22 -0
- data/AGENTS.md +224 -0
- data/CLAUDE.md +130 -0
- data/CONTRIBUTING.md +115 -0
- data/DEVELOPER.md +390 -0
- data/README.md +268 -0
- data/Rakefile +99 -0
- data/examples/README.md +55 -0
- data/examples/cluster.rb +24 -0
- data/examples/opentelemetry.rb +50 -0
- data/examples/pipelining.rb +29 -0
- data/examples/standalone.rb +22 -0
- data/examples/statistics.rb +24 -0
- data/lib/valkey/bindings.rb +319 -0
- data/lib/valkey/commands/bitmap_commands.rb +86 -0
- data/lib/valkey/commands/cluster_commands.rb +259 -0
- data/lib/valkey/commands/connection_commands.rb +318 -0
- data/lib/valkey/commands/function_commands.rb +255 -0
- data/lib/valkey/commands/generic_commands.rb +525 -0
- data/lib/valkey/commands/geo_commands.rb +87 -0
- data/lib/valkey/commands/hash_commands.rb +592 -0
- data/lib/valkey/commands/hyper_log_log_commands.rb +51 -0
- data/lib/valkey/commands/json_commands.rb +389 -0
- data/lib/valkey/commands/list_commands.rb +348 -0
- data/lib/valkey/commands/module_commands.rb +125 -0
- data/lib/valkey/commands/pubsub_commands.rb +237 -0
- data/lib/valkey/commands/scripting_commands.rb +287 -0
- data/lib/valkey/commands/server_commands.rb +961 -0
- data/lib/valkey/commands/set_commands.rb +220 -0
- data/lib/valkey/commands/sorted_set_commands.rb +971 -0
- data/lib/valkey/commands/stream_commands.rb +636 -0
- data/lib/valkey/commands/string_commands.rb +371 -0
- data/lib/valkey/commands/transaction_commands.rb +175 -0
- data/lib/valkey/commands/vector_search_commands.rb +271 -0
- data/lib/valkey/commands.rb +68 -0
- data/lib/valkey/errors.rb +41 -0
- data/lib/valkey/native/aarch64-unknown-linux-gnu/libglide_ffi.so +0 -0
- data/lib/valkey/native/x86_64-unknown-linux-gnu/libglide_ffi.so +0 -0
- data/lib/valkey/opentelemetry.rb +207 -0
- data/lib/valkey/pipeline.rb +20 -0
- data/lib/valkey/pubsub_callback.rb +10 -0
- data/lib/valkey/request_error_type.rb +10 -0
- data/lib/valkey/request_type.rb +436 -0
- data/lib/valkey/response_type.rb +20 -0
- data/lib/valkey/utils.rb +267 -0
- data/lib/valkey/version.rb +5 -0
- data/lib/valkey.rb +617 -0
- metadata +107 -0
data/Rakefile
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Only load bundler gem tasks when not testing installed gem
|
|
4
|
+
# bundler/gem_tasks can interfere with load path when testing installed gems
|
|
5
|
+
require 'bundler/gem_tasks' unless ENV["TEST_INSTALLED_GEM"]
|
|
6
|
+
require 'rake/testtask'
|
|
7
|
+
|
|
8
|
+
# =============================================================================
|
|
9
|
+
# Native Library Build Tasks
|
|
10
|
+
# =============================================================================
|
|
11
|
+
|
|
12
|
+
def native_lib_ext
|
|
13
|
+
case RbConfig::CONFIG['host_os']
|
|
14
|
+
when /darwin/
|
|
15
|
+
'dylib'
|
|
16
|
+
else
|
|
17
|
+
'so'
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
namespace :native do
|
|
22
|
+
desc "Initialize the valkey-glide submodule"
|
|
23
|
+
task :submodule do
|
|
24
|
+
puts "Initializing valkey-glide submodule..."
|
|
25
|
+
sh "git submodule update --init --recursive"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
desc "Build the native FFI library (release mode)"
|
|
29
|
+
task build: :submodule do
|
|
30
|
+
puts "Building native FFI library..."
|
|
31
|
+
Dir.chdir("valkey-glide/ffi") do
|
|
32
|
+
sh "cargo build --release"
|
|
33
|
+
end
|
|
34
|
+
puts "Native library built successfully!"
|
|
35
|
+
puts "Location: valkey-glide/ffi/target/release/libglide_ffi.#{native_lib_ext}"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
desc "Build the native FFI library (debug mode)"
|
|
39
|
+
task build_debug: :submodule do
|
|
40
|
+
puts "Building native FFI library (debug)..."
|
|
41
|
+
Dir.chdir("valkey-glide/ffi") do
|
|
42
|
+
sh "cargo build"
|
|
43
|
+
end
|
|
44
|
+
puts "Native library built successfully!"
|
|
45
|
+
puts "Location: valkey-glide/ffi/target/debug/libglide_ffi.#{native_lib_ext}"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
desc "Clean native build artifacts"
|
|
49
|
+
task :clean do
|
|
50
|
+
puts "Cleaning native build artifacts..."
|
|
51
|
+
if Dir.exist?("valkey-glide/ffi")
|
|
52
|
+
Dir.chdir("valkey-glide/ffi") do
|
|
53
|
+
sh "cargo clean"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
puts "Clean complete!"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
desc "Copy built library to lib/valkey for gem packaging"
|
|
60
|
+
task package: :build do
|
|
61
|
+
require 'fileutils'
|
|
62
|
+
src = "valkey-glide/ffi/target/release/libglide_ffi.#{native_lib_ext}"
|
|
63
|
+
dest = "lib/valkey/libglide_ffi.#{native_lib_ext}"
|
|
64
|
+
|
|
65
|
+
if File.exist?(src)
|
|
66
|
+
FileUtils.cp(src, dest)
|
|
67
|
+
puts "Copied #{src} to #{dest}"
|
|
68
|
+
else
|
|
69
|
+
abort "Native library not found at #{src}. Run 'rake native:build' first."
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
desc "Build the native FFI library"
|
|
75
|
+
task native: "native:build"
|
|
76
|
+
|
|
77
|
+
# =============================================================================
|
|
78
|
+
# Test Tasks
|
|
79
|
+
# =============================================================================
|
|
80
|
+
|
|
81
|
+
namespace :test do
|
|
82
|
+
groups = %i[valkey cluster]
|
|
83
|
+
groups.each do |group|
|
|
84
|
+
Rake::TestTask.new(group) do |t|
|
|
85
|
+
t.libs << "test"
|
|
86
|
+
# Only add local lib to load path when not testing installed gem
|
|
87
|
+
t.libs << "lib" unless ENV["TEST_INSTALLED_GEM"]
|
|
88
|
+
t.test_files = FileList["test/#{group}/**/*_test.rb"]
|
|
89
|
+
t.options = '-v' if ENV['CI'] || ENV['VERBOSE']
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
lost_tests = Dir["test/**/*_test.rb"] - groups.map { |g| Dir["test/#{g}/**/*_test.rb"] }.flatten
|
|
94
|
+
abort "The following test files are in no group:\n#{lost_tests.join("\n")}" unless lost_tests.empty?
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
task test: ["test:valkey"]
|
|
98
|
+
|
|
99
|
+
task default: :test
|
data/examples/README.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Examples
|
|
2
|
+
|
|
3
|
+
Runnable examples for Valkey GLIDE Ruby. Requires a Valkey or Redis OSS server unless noted.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
From the repository root:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bin/setup
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Run examples with the gem loaded from `lib/`:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bundle exec ruby examples/standalone.rb
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Or:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
RUBYOPT="-I$(pwd)/lib" ruby examples/standalone.rb
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Examples
|
|
26
|
+
|
|
27
|
+
| File | Description | Server |
|
|
28
|
+
|------|-------------|--------|
|
|
29
|
+
| [standalone.rb](./standalone.rb) | Basic connect, SET, GET | Standalone `:6379` |
|
|
30
|
+
| [cluster.rb](./cluster.rb) | Cluster connect, SET, GET | Cluster `:7000`–`:7005` |
|
|
31
|
+
| [pipelining.rb](./pipelining.rb) | Non-atomic pipeline | Standalone `:6379` |
|
|
32
|
+
| [opentelemetry.rb](./opentelemetry.rb) | OTel file exporter + traced commands | Standalone `:6379` |
|
|
33
|
+
| [statistics.rb](./statistics.rb) | Client statistics | Standalone `:6379` |
|
|
34
|
+
|
|
35
|
+
## Environment variables
|
|
36
|
+
|
|
37
|
+
| Variable | Default | Purpose |
|
|
38
|
+
|----------|---------|---------|
|
|
39
|
+
| `VALKEY_HOST` | `127.0.0.1` | Server host |
|
|
40
|
+
| `VALKEY_PORT` | `6379` | Standalone port |
|
|
41
|
+
| `VALKEY_CLUSTER_PORT` | `7000` | First cluster node port |
|
|
42
|
+
|
|
43
|
+
## Standalone with Docker
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
docker run -d --name valkey -p 6379:6379 valkey/valkey:8
|
|
47
|
+
bundle exec ruby examples/standalone.rb
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Cluster with Docker
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
docker run -d -p 7000-7005:7000-7005 grokzen/redis-cluster:7.0.15
|
|
54
|
+
bundle exec ruby examples/cluster.rb
|
|
55
|
+
```
|
data/examples/cluster.rb
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Cluster mode example.
|
|
4
|
+
#
|
|
5
|
+
# Run: bundle exec ruby examples/cluster.rb
|
|
6
|
+
# Requires a 6-node cluster on 127.0.0.1:7000-7005 (see examples/README.md).
|
|
7
|
+
|
|
8
|
+
require "valkey"
|
|
9
|
+
|
|
10
|
+
base_port = Integer(ENV.fetch("VALKEY_CLUSTER_PORT", 7000))
|
|
11
|
+
host = ENV.fetch("VALKEY_HOST", "127.0.0.1")
|
|
12
|
+
|
|
13
|
+
nodes = 6.times.map { |i| { host: host, port: base_port + i } }
|
|
14
|
+
|
|
15
|
+
client = Valkey.new(nodes: nodes, cluster_mode: true)
|
|
16
|
+
|
|
17
|
+
puts "PING: #{client.ping}"
|
|
18
|
+
puts "SET: #{client.set('cluster_key', 'cluster_value')}"
|
|
19
|
+
puts "GET: #{client.get('cluster_key')}"
|
|
20
|
+
|
|
21
|
+
client.del("cluster_key")
|
|
22
|
+
client.close
|
|
23
|
+
|
|
24
|
+
puts "Done."
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# OpenTelemetry example using file exporters (no collector required).
|
|
4
|
+
#
|
|
5
|
+
# Run: bundle exec ruby examples/opentelemetry.rb
|
|
6
|
+
# Traces: /tmp/valkey_ruby_example_traces.json
|
|
7
|
+
# Metrics: /tmp/valkey_ruby_example_metrics.json
|
|
8
|
+
|
|
9
|
+
require "valkey"
|
|
10
|
+
require "fileutils"
|
|
11
|
+
|
|
12
|
+
TRACES_FILE = "/tmp/valkey_ruby_example_traces.json"
|
|
13
|
+
METRICS_FILE = "/tmp/valkey_ruby_example_metrics.json"
|
|
14
|
+
|
|
15
|
+
FileUtils.rm_f(TRACES_FILE)
|
|
16
|
+
FileUtils.rm_f(METRICS_FILE)
|
|
17
|
+
|
|
18
|
+
Valkey::OpenTelemetry.init(
|
|
19
|
+
traces: {
|
|
20
|
+
endpoint: "file://#{TRACES_FILE}",
|
|
21
|
+
sample_percentage: 100
|
|
22
|
+
},
|
|
23
|
+
metrics: {
|
|
24
|
+
endpoint: "file://#{METRICS_FILE}"
|
|
25
|
+
},
|
|
26
|
+
flush_interval_ms: 1000
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
host = ENV.fetch("VALKEY_HOST", "127.0.0.1")
|
|
30
|
+
port = Integer(ENV.fetch("VALKEY_PORT", 6379))
|
|
31
|
+
|
|
32
|
+
client = Valkey.new(host: host, port: port)
|
|
33
|
+
|
|
34
|
+
client.set("otel_key", "otel_value")
|
|
35
|
+
client.get("otel_key")
|
|
36
|
+
client.pipelined do |pipe|
|
|
37
|
+
pipe.set("otel_pipe_1", "a")
|
|
38
|
+
pipe.get("otel_pipe_1")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
client.del("otel_key", "otel_pipe_1")
|
|
42
|
+
client.close
|
|
43
|
+
|
|
44
|
+
# Allow exporter flush
|
|
45
|
+
sleep 2
|
|
46
|
+
|
|
47
|
+
puts "OpenTelemetry initialized: #{Valkey::OpenTelemetry.initialized?}"
|
|
48
|
+
puts "Traces file: #{TRACES_FILE} (#{File.size?(TRACES_FILE) || 0} bytes)"
|
|
49
|
+
puts "Metrics file: #{METRICS_FILE} (#{File.size?(METRICS_FILE) || 0} bytes)"
|
|
50
|
+
puts "Done."
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Pipeline example — batch commands in one round trip.
|
|
4
|
+
#
|
|
5
|
+
# Run: bundle exec ruby examples/pipelining.rb
|
|
6
|
+
|
|
7
|
+
require "valkey"
|
|
8
|
+
|
|
9
|
+
host = ENV.fetch("VALKEY_HOST", "127.0.0.1")
|
|
10
|
+
port = Integer(ENV.fetch("VALKEY_PORT", 6379))
|
|
11
|
+
|
|
12
|
+
client = Valkey.new(host: host, port: port)
|
|
13
|
+
|
|
14
|
+
client.del("pipe_counter")
|
|
15
|
+
|
|
16
|
+
results = client.pipelined do |pipe|
|
|
17
|
+
pipe.set("pipe_key", "pipe_value")
|
|
18
|
+
pipe.get("pipe_key")
|
|
19
|
+
pipe.incr("pipe_counter")
|
|
20
|
+
pipe.get("pipe_counter")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
puts "Pipeline results:"
|
|
24
|
+
results.each_with_index { |r, i| puts " [#{i}] #{r.inspect}" }
|
|
25
|
+
|
|
26
|
+
client.del("pipe_key", "pipe_counter")
|
|
27
|
+
client.close
|
|
28
|
+
|
|
29
|
+
puts "Done."
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Basic standalone Valkey example.
|
|
4
|
+
#
|
|
5
|
+
# Run: bundle exec ruby examples/standalone.rb
|
|
6
|
+
# Requires Valkey/Redis on VALKEY_HOST:VALKEY_PORT (default 127.0.0.1:6379).
|
|
7
|
+
|
|
8
|
+
require "valkey"
|
|
9
|
+
|
|
10
|
+
host = ENV.fetch("VALKEY_HOST", "127.0.0.1")
|
|
11
|
+
port = Integer(ENV.fetch("VALKEY_PORT", 6379))
|
|
12
|
+
|
|
13
|
+
client = Valkey.new(host: host, port: port)
|
|
14
|
+
|
|
15
|
+
puts "PING: #{client.ping}"
|
|
16
|
+
puts "SET: #{client.set('hello', 'world')}"
|
|
17
|
+
puts "GET: #{client.get('hello')}"
|
|
18
|
+
|
|
19
|
+
client.del("hello")
|
|
20
|
+
client.close
|
|
21
|
+
|
|
22
|
+
puts "Done."
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Client statistics example.
|
|
4
|
+
#
|
|
5
|
+
# Run: bundle exec ruby examples/statistics.rb
|
|
6
|
+
|
|
7
|
+
require "valkey"
|
|
8
|
+
|
|
9
|
+
host = ENV.fetch("VALKEY_HOST", "127.0.0.1")
|
|
10
|
+
port = Integer(ENV.fetch("VALKEY_PORT", 6379))
|
|
11
|
+
|
|
12
|
+
client = Valkey.new(host: host, port: port)
|
|
13
|
+
client.set("stats_demo", "1")
|
|
14
|
+
client.get("stats_demo")
|
|
15
|
+
|
|
16
|
+
stats = client.get_statistics
|
|
17
|
+
|
|
18
|
+
puts "Client statistics:"
|
|
19
|
+
stats.each { |k, v| puts " #{k}: #{v}" }
|
|
20
|
+
|
|
21
|
+
client.del("stats_demo")
|
|
22
|
+
client.close
|
|
23
|
+
|
|
24
|
+
puts "Done."
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Valkey
|
|
4
|
+
module Bindings
|
|
5
|
+
extend FFI::Library
|
|
6
|
+
|
|
7
|
+
# Determine platform-specific library extension and directory name
|
|
8
|
+
def self.platform_info
|
|
9
|
+
os = if FFI::Platform.mac?
|
|
10
|
+
"darwin"
|
|
11
|
+
elsif FFI::Platform.windows?
|
|
12
|
+
"windows"
|
|
13
|
+
else
|
|
14
|
+
"linux"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Detect architecture
|
|
18
|
+
arch = case RbConfig::CONFIG["host_cpu"]
|
|
19
|
+
when /x86_64|amd64/i
|
|
20
|
+
"x86_64"
|
|
21
|
+
when /aarch64|arm64/i
|
|
22
|
+
"aarch64"
|
|
23
|
+
when /i[3-6]86/i
|
|
24
|
+
"x86"
|
|
25
|
+
else
|
|
26
|
+
RbConfig::CONFIG["host_cpu"]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
lib_ext = case os
|
|
30
|
+
when "darwin"
|
|
31
|
+
"dylib"
|
|
32
|
+
when "windows"
|
|
33
|
+
"dll"
|
|
34
|
+
else
|
|
35
|
+
"so"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Platform directory name matches Rust target triple convention
|
|
39
|
+
platform_dir = case os
|
|
40
|
+
when "darwin"
|
|
41
|
+
"#{arch}-apple-darwin"
|
|
42
|
+
when "linux"
|
|
43
|
+
"#{arch}-unknown-linux-gnu"
|
|
44
|
+
when "windows"
|
|
45
|
+
"#{arch}-pc-windows-msvc"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
{ os: os, arch: arch, lib_ext: lib_ext, platform_dir: platform_dir }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
platform = platform_info
|
|
52
|
+
lib_ext = platform[:lib_ext]
|
|
53
|
+
platform_dir = platform[:platform_dir]
|
|
54
|
+
|
|
55
|
+
# Look for the native library in the following locations (in order):
|
|
56
|
+
# 1. valkey-glide submodule build output (development/source builds)
|
|
57
|
+
# 2. Platform-specific bundled library in lib/valkey/native/{platform}/ (for gem distribution)
|
|
58
|
+
# 3. Legacy bundled library in lib/valkey (fallback for old gem structure)
|
|
59
|
+
lib_paths = [
|
|
60
|
+
# Submodule build output (release) - from lib/valkey/ go up 2 levels to repo root
|
|
61
|
+
File.expand_path("../../valkey-glide/ffi/target/release/libglide_ffi.#{lib_ext}", __dir__),
|
|
62
|
+
# Submodule build output (debug)
|
|
63
|
+
File.expand_path("../../valkey-glide/ffi/target/debug/libglide_ffi.#{lib_ext}", __dir__),
|
|
64
|
+
# Platform-specific bundled library (for gem distribution)
|
|
65
|
+
File.expand_path("./native/#{platform_dir}/libglide_ffi.#{lib_ext}", __dir__),
|
|
66
|
+
# Legacy bundled library (fallback)
|
|
67
|
+
File.expand_path("./libglide_ffi.#{lib_ext}", __dir__)
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
lib_path = lib_paths.find { |path| File.exist?(path) }
|
|
71
|
+
|
|
72
|
+
unless lib_path
|
|
73
|
+
raise LoadError, <<~ERROR
|
|
74
|
+
Could not find libglide_ffi native library for platform: #{platform_dir}
|
|
75
|
+
|
|
76
|
+
Searched in:
|
|
77
|
+
#{lib_paths.map { |p| " - #{p}" }.join("\n")}
|
|
78
|
+
|
|
79
|
+
To build from source:
|
|
80
|
+
1. Initialize the submodule: git submodule update --init --recursive
|
|
81
|
+
2. Build the FFI library: cd valkey-glide/ffi && cargo build --release
|
|
82
|
+
|
|
83
|
+
Detected platform: OS=#{platform[:os]}, Arch=#{platform[:arch]}
|
|
84
|
+
ERROR
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
ffi_lib lib_path
|
|
88
|
+
|
|
89
|
+
class ClientType < FFI::Struct
|
|
90
|
+
layout(
|
|
91
|
+
:tag, :uint # 0 = AsyncClient, 1 = SyncClient
|
|
92
|
+
)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
class ConnectionResponse < FFI::Struct
|
|
96
|
+
layout(
|
|
97
|
+
:conn_ptr, :pointer, # *const c_void
|
|
98
|
+
:connection_error_message, :string # *const c_char (null-terminated C string)
|
|
99
|
+
)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
class CommandError < FFI::Struct
|
|
103
|
+
layout(
|
|
104
|
+
:command_error_message, :string,
|
|
105
|
+
:command_error_type, :int # Assuming RequestErrorType is repr(C) enum
|
|
106
|
+
)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
class BatchOptionsInfo < FFI::Struct
|
|
110
|
+
layout(
|
|
111
|
+
:retry_server_error, :bool,
|
|
112
|
+
:retry_connection_error, :bool,
|
|
113
|
+
:has_timeout, :bool,
|
|
114
|
+
:timeout, :uint, # Assuming u32 is represented as uint in C
|
|
115
|
+
:route_info, :pointer # *const RouteInfo
|
|
116
|
+
)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
class CmdInfo < FFI::Struct
|
|
120
|
+
layout(
|
|
121
|
+
:request_type, :int, # Assuming RequestType is repr(C) enum
|
|
122
|
+
:args, :pointer, # *const *const u8 (pointer to array of pointers to args)
|
|
123
|
+
:arg_count, :ulong, # usize (number of arguments)
|
|
124
|
+
:args_len, :pointer # *const usize (pointer to array of argument lengths)
|
|
125
|
+
)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
class ScriptHashBuffer < FFI::Struct
|
|
129
|
+
layout(
|
|
130
|
+
:ptr, :pointer, # *mut u8 (pointer to the script hash)
|
|
131
|
+
:len, :ulong, # usize (length of the script hash)
|
|
132
|
+
:capacity, :ulong # usize (capacity of the buffer)
|
|
133
|
+
)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
class BatchInfo < FFI::Struct
|
|
137
|
+
layout(
|
|
138
|
+
:cmd_count, :ulong, # usize
|
|
139
|
+
:cmds, :pointer, # *const *const CmdInfo
|
|
140
|
+
:is_atomic, :bool # bool
|
|
141
|
+
)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
class CommandResponse < FFI::Struct
|
|
145
|
+
layout(
|
|
146
|
+
:response_type, :int, # Assuming ResponseType is repr(C) enum
|
|
147
|
+
:int_value, :int64,
|
|
148
|
+
:float_value, :double,
|
|
149
|
+
:bool_value, :bool,
|
|
150
|
+
:string_value, :pointer, # points to C string
|
|
151
|
+
:string_value_len, :long,
|
|
152
|
+
:array_value, :pointer, # points to CommandResponse array
|
|
153
|
+
:array_value_len, :long,
|
|
154
|
+
:map_key, :pointer, # CommandResponse*
|
|
155
|
+
:map_value, :pointer, # CommandResponse*
|
|
156
|
+
:sets_value, :pointer, # CommandResponse*
|
|
157
|
+
:sets_value_len, :long,
|
|
158
|
+
:arena_ptr, :pointer # *mut c_void - arena allocator pointer
|
|
159
|
+
)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
callback :success_callback, %i[ulong pointer], :void
|
|
163
|
+
callback :failure_callback, %i[ulong string int], :void
|
|
164
|
+
|
|
165
|
+
class AsyncClientData < FFI::Struct
|
|
166
|
+
layout(
|
|
167
|
+
:success_callback, :success_callback,
|
|
168
|
+
:failure_callback, :failure_callback
|
|
169
|
+
)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
class ClientData < FFI::Union
|
|
173
|
+
layout(
|
|
174
|
+
:async_client, AsyncClientData
|
|
175
|
+
)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
class CommandResult < FFI::Struct
|
|
179
|
+
layout(
|
|
180
|
+
:response, CommandResponse.by_ref,
|
|
181
|
+
:command_error, CommandError.by_ref,
|
|
182
|
+
:arena, :pointer # *mut ResponseArena
|
|
183
|
+
)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
callback :pubsub_callback, [
|
|
187
|
+
:ulong, # client_ptr
|
|
188
|
+
:int, # kind (PushKind enum)
|
|
189
|
+
:pointer, :long, # message + length
|
|
190
|
+
:pointer, :long, # channel + length
|
|
191
|
+
:pointer, :long # pattern + length
|
|
192
|
+
], :void
|
|
193
|
+
|
|
194
|
+
attach_function :create_client, [
|
|
195
|
+
:pointer, # *const u8 (connection_request_bytes)
|
|
196
|
+
:ulong, # usize (connection_request_len)
|
|
197
|
+
ClientType.by_ref, # *const ClientType
|
|
198
|
+
:pubsub_callback # callback
|
|
199
|
+
], :pointer # *const ConnectionResponse
|
|
200
|
+
|
|
201
|
+
attach_function :create_client_from_uri, [
|
|
202
|
+
:string, # *const c_char (uri_str)
|
|
203
|
+
:string, # *const c_char (extra_options_json)
|
|
204
|
+
ClientType.by_ref, # *const ClientType
|
|
205
|
+
:pubsub_callback # callback
|
|
206
|
+
], :pointer # *const ConnectionResponse
|
|
207
|
+
|
|
208
|
+
attach_function :free_connection_response, [
|
|
209
|
+
:pointer # *mut ConnectionResponse
|
|
210
|
+
], :void
|
|
211
|
+
|
|
212
|
+
attach_function :close_client, [
|
|
213
|
+
:pointer # client_adapter_ptr
|
|
214
|
+
], :void
|
|
215
|
+
|
|
216
|
+
attach_function :command, [
|
|
217
|
+
:pointer, # client_adapter_ptr
|
|
218
|
+
:ulong, # request_id
|
|
219
|
+
:int, # command_type
|
|
220
|
+
:ulong, # arg_count
|
|
221
|
+
:pointer, # args (pointer to usize[])
|
|
222
|
+
:pointer, # args_len (pointer to c_ulong[])
|
|
223
|
+
:pointer, # route_bytes
|
|
224
|
+
:ulong, # route_bytes_len
|
|
225
|
+
:ulong # span_ptr (u64)
|
|
226
|
+
], :pointer, blocking: true # returns *mut CommandResult, releases GVL during I/O
|
|
227
|
+
|
|
228
|
+
attach_function :batch, [
|
|
229
|
+
:pointer, # client_ptr
|
|
230
|
+
:ulong, # callback_index
|
|
231
|
+
BatchInfo.by_ref, # *const BatchInfo
|
|
232
|
+
:bool, # raise_on_error
|
|
233
|
+
:pointer, # *const BatchOptionsInfo
|
|
234
|
+
:ulong # span_ptr (u64)
|
|
235
|
+
], :pointer, blocking: true # returns *mut CommandResult, releases GVL during I/O
|
|
236
|
+
|
|
237
|
+
attach_function :store_script, [
|
|
238
|
+
:pointer, # *const u8 (script_bytes)
|
|
239
|
+
:ulong # usize (script_len)
|
|
240
|
+
], :pointer # returns *mut ScriptHashBuffer
|
|
241
|
+
|
|
242
|
+
attach_function :invoke_script, [
|
|
243
|
+
:pointer, # client_ptr
|
|
244
|
+
:ulong, # request_id
|
|
245
|
+
:pointer, # hash (pointer to C string)
|
|
246
|
+
:ulong, # keys_count (number of keys)
|
|
247
|
+
:pointer, # keys (pointer to usize[])
|
|
248
|
+
:pointer, # keys_len (pointer to c_ulong[])
|
|
249
|
+
:ulong, # args_count (number of args)
|
|
250
|
+
:pointer, # args (pointer to usize[])
|
|
251
|
+
:pointer, # args_len (pointer to c_ulong[])
|
|
252
|
+
:pointer, # route_bytes (pointer to u8)
|
|
253
|
+
:ulong, # route_bytes_len (usize)
|
|
254
|
+
:uint64 # span_ptr (OpenTelemetry span pointer)
|
|
255
|
+
], :pointer, blocking: true # returns *mut CommandResult, releases GVL during I/O
|
|
256
|
+
|
|
257
|
+
# OpenTelemetry structures
|
|
258
|
+
class OpenTelemetryTracesConfig < FFI::Struct
|
|
259
|
+
layout(
|
|
260
|
+
:endpoint, :pointer, # const char* (trace collector endpoint)
|
|
261
|
+
:has_sample_percentage, :bool, # whether sample_percentage is set
|
|
262
|
+
:sample_percentage, :uint32 # sampling percentage (0-100)
|
|
263
|
+
)
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
class OpenTelemetryMetricsConfig < FFI::Struct
|
|
267
|
+
layout(
|
|
268
|
+
:endpoint, :pointer # const char* (metrics collector endpoint)
|
|
269
|
+
)
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
class OpenTelemetryConfig < FFI::Struct
|
|
273
|
+
layout(
|
|
274
|
+
:traces, :pointer, # OpenTelemetryTracesConfig*
|
|
275
|
+
:metrics, :pointer, # OpenTelemetryMetricsConfig*
|
|
276
|
+
:has_flush_interval_ms, :bool, # whether flush_interval_ms is set
|
|
277
|
+
:flush_interval_ms, :int64 # flush interval in milliseconds
|
|
278
|
+
)
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# Statistics structure
|
|
282
|
+
class Statistics < FFI::Struct
|
|
283
|
+
layout(
|
|
284
|
+
:total_connections, :ulong,
|
|
285
|
+
:total_clients, :ulong,
|
|
286
|
+
:total_values_compressed, :ulong,
|
|
287
|
+
:total_values_decompressed, :ulong,
|
|
288
|
+
:total_original_bytes, :ulong,
|
|
289
|
+
:total_bytes_compressed, :ulong,
|
|
290
|
+
:total_bytes_decompressed, :ulong,
|
|
291
|
+
:compression_skipped_count, :ulong,
|
|
292
|
+
:subscription_out_of_sync_count, :ulong,
|
|
293
|
+
:subscription_last_sync_timestamp, :ulong
|
|
294
|
+
)
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# OpenTelemetry functions
|
|
298
|
+
attach_function :init_open_telemetry, [
|
|
299
|
+
OpenTelemetryConfig.by_ref # OpenTelemetry configuration
|
|
300
|
+
], :pointer # returns error string or NULL on success
|
|
301
|
+
|
|
302
|
+
attach_function :free_c_string, [
|
|
303
|
+
:pointer # C string to free
|
|
304
|
+
], :void
|
|
305
|
+
|
|
306
|
+
attach_function :create_otel_span, [
|
|
307
|
+
:int # request_type (RequestType enum value)
|
|
308
|
+
], :uint64 # returns span pointer (u64) or 0 on failure
|
|
309
|
+
|
|
310
|
+
attach_function :create_batch_otel_span, [], :uint64 # returns span pointer (u64) or 0 on failure
|
|
311
|
+
|
|
312
|
+
attach_function :drop_otel_span, [
|
|
313
|
+
:uint64 # span_ptr to close
|
|
314
|
+
], :void
|
|
315
|
+
|
|
316
|
+
# Statistics function
|
|
317
|
+
attach_function :get_statistics, [], Statistics.by_value # returns statistics by value
|
|
318
|
+
end
|
|
319
|
+
end
|