Module: Hop::FFI
- Defined in:
- lib/hop/ffi.rb
Constant Summary collapse
- P =
Fiddle::TYPE_VOIDP
- I =
Fiddle::TYPE_INT
- LL =
Fiddle::TYPE_LONG_LONG
- SZ =
Fiddle::TYPE_SIZE_T
- CH =
Fiddle::TYPE_CHAR
- V =
Fiddle::TYPE_VOID
- ABI_EXPECTED =
3- LIB =
Fiddle.dlopen(lib_path)
- ABI_VERSION =
fn("hop_abi_version", [], I)
- NODE_NEW =
fn("hop_node_new", [], P)
- NODE_WITH_SECRET =
fn("hop_node_with_secret", [P, SZ], P)
- NODE_FREE =
fn("hop_node_free", [P], V)
- NODE_ADDRESS =
fn("hop_node_address", [P, P], CH)
- NODE_TICK =
fn("hop_node_tick", [P, LL], V)
- LINK_UP =
fn("hop_link_up", [P, LL, I], V)
- BYTES_RECEIVED =
fn("hop_bytes_received", [P, LL, P, SZ], V)
- LINK_DOWN =
fn("hop_link_down", [P, LL], V)
- DRAIN_OUTGOING =
fn("hop_drain_outgoing", [P, P, P], V)
- SUBSCRIBE =
fn("hop_subscribe", [P, P], V)
- PUBLISH_PREKEY =
fn("hop_publish_prekey", [P], CH)
- SEND_SERVICE_REQUEST =
fn("hop_send_service_request", [P, P, P, P, P, SZ, P], CH)
- SEND_SERVICE_RESPONSE =
fn("hop_send_service_response", [P, P, P, I, P, SZ], CH)
- POLL_SERVICE_REQUESTS =
fn("hop_poll_service_requests", [P, P, P], V)
- POLL_SERVICE_RESPONSES =
fn("hop_poll_service_responses", [P, P, P], V)
- ADDRESS_TO_BASE58 =
fn("hop_address_to_base58", [P, P, SZ], SZ)
- ADDRESS_FROM_BASE58 =
fn("hop_address_from_base58", [P, P], CH)
- SIGN_REACH_RECORD =
fn("hop_sign_reach_record", [P, P, I, P, P], V)
- VERIFY_REACH_RECORD =
fn("hop_verify_reach_record", [P, SZ, LL, P, P], CH)
- CLUSTER_JOIN =
Endpoint clustering (DESIGN.md ยง40).
fn("hop_cluster_join", [P, P], V)
- CLUSTER_JOIN_PASSPHRASE =
fn("hop_cluster_join_passphrase", [P, P, SZ], V)
- CLUSTER_MEMBERS =
fn("hop_cluster_members", [P], I)
- CLUSTER_SET_QUORUM =
fn("hop_cluster_set_quorum", [P, I], V)
- Closure =
Fiddle::Closure::BlockCaller
Class Method Summary collapse
- .address(node) ⇒ Object
- .assert_abi! ⇒ Object
- .cluster_join(node, secret) ⇒ Object
- .cluster_join_passphrase(node, pass) ⇒ Object
- .cluster_members(node) ⇒ Object
- .cluster_set_quorum(node, min) ⇒ Object
- .connected(node, link, initiator) ⇒ Object
- .disconnected(node, link) ⇒ Object
- .drain_outgoing(node) ⇒ Object
- .from_b58(text) ⇒ Object
- .lib_path ⇒ Object
- .node_free(node) ⇒ Object
-
.node_new ⇒ Object
---- thin wrappers ----.
- .node_with_secret(secret) ⇒ Object
- .publish_prekey(node) ⇒ Object
-
.read_bytes(ptr, len) ⇒ Object
---- helpers: read C memory that is valid only during a call ----.
- .read_cstr(ptr) ⇒ Object
- .received(node, link, data) ⇒ Object
- .send_service_request(node, dst, service, method, args) ⇒ Object
- .send_service_response(node, to, for_request_id, status, body) ⇒ Object
- .sign_reach(node, endpoint, ttl_secs) ⇒ Object
- .subscribe(node, topic) ⇒ Object
- .take_service_requests(node) ⇒ Object
- .take_service_responses(node) ⇒ Object
- .tick(node, now_ms) ⇒ Object
- .to_b58(addr32) ⇒ Object
- .verify_reach(record, now_secs) ⇒ Object
Class Method Details
.address(node) ⇒ Object
91 92 93 94 95 |
# File 'lib/hop/ffi.rb', line 91 def self.address(node) out = Fiddle::Pointer.malloc(32, Fiddle::RUBY_FREE) NODE_ADDRESS.call(node, out) out[0, 32].b end |
.assert_abi! ⇒ Object
67 68 69 70 |
# File 'lib/hop/ffi.rb', line 67 def self.assert_abi! got = ABI_VERSION.call raise "libhop ABI mismatch: wrapper expects #{ABI_EXPECTED}, library reports #{got}" if got != ABI_EXPECTED end |
.cluster_join(node, secret) ⇒ Object
85 |
# File 'lib/hop/ffi.rb', line 85 def self.cluster_join(node, secret) = CLUSTER_JOIN.call(node, secret) |
.cluster_join_passphrase(node, pass) ⇒ Object
86 |
# File 'lib/hop/ffi.rb', line 86 def self.cluster_join_passphrase(node, pass) = CLUSTER_JOIN_PASSPHRASE.call(node, pass, pass.bytesize) |
.cluster_members(node) ⇒ Object
87 |
# File 'lib/hop/ffi.rb', line 87 def self.cluster_members(node) = CLUSTER_MEMBERS.call(node) |
.cluster_set_quorum(node, min) ⇒ Object
88 |
# File 'lib/hop/ffi.rb', line 88 def self.cluster_set_quorum(node, min) = CLUSTER_SET_QUORUM.call(node, min) |
.connected(node, link, initiator) ⇒ Object
81 |
# File 'lib/hop/ffi.rb', line 81 def self.connected(node, link, initiator) = LINK_UP.call(node, link, initiator ? 0 : 1) |
.disconnected(node, link) ⇒ Object
82 |
# File 'lib/hop/ffi.rb', line 82 def self.disconnected(node, link) = LINK_DOWN.call(node, link) |
.drain_outgoing(node) ⇒ Object
97 98 99 100 101 102 |
# File 'lib/hop/ffi.rb', line 97 def self.drain_outgoing(node) out = [] sink = Closure.new(V, [P, LL, P, SZ]) { |_ctx, link, ptr, len| out << [link, read_bytes(ptr, len)] } DRAIN_OUTGOING.call(node, sink, nil) out end |
.from_b58(text) ⇒ Object
140 141 142 143 144 145 |
# File 'lib/hop/ffi.rb', line 140 def self.from_b58(text) out = Fiddle::Pointer.malloc(32, Fiddle::RUBY_FREE) raise "not a valid Hop address: #{text}" if ADDRESS_FROM_BASE58.call(text, out).zero? out[0, 32].b end |
.lib_path ⇒ Object
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/hop/ffi.rb', line 18 def self.lib_path ext = case RbConfig::CONFIG["host_os"] when /darwin/ then "dylib" when /mswin|mingw/ then "dll" else "so" end repo = File.("../../../..", __dir__) # sdk/ruby/lib/hop -> repo root candidates = [] candidates << File.join(ENV["HOP_LIBDIR"], "libhop.#{ext}") if ENV["HOP_LIBDIR"] candidates << File.join(repo, "target", "debug", "libhop.#{ext}") candidates << File.join(repo, "target", "release", "libhop.#{ext}") found = candidates.find { |c| File.exist?(c) } raise "libhop.#{ext} not found. Build it with `cargo build -p hop` or set HOP_LIBDIR.\n" \ "Looked in:\n #{candidates.join("\n ")}" unless found found end |
.node_free(node) ⇒ Object
79 |
# File 'lib/hop/ffi.rb', line 79 def self.node_free(node) = NODE_FREE.call(node) |
.node_new ⇒ Object
---- thin wrappers ----
77 |
# File 'lib/hop/ffi.rb', line 77 def self.node_new = NODE_NEW.call |
.node_with_secret(secret) ⇒ Object
78 |
# File 'lib/hop/ffi.rb', line 78 def self.node_with_secret(secret) = NODE_WITH_SECRET.call(secret, secret.bytesize) |
.publish_prekey(node) ⇒ Object
89 |
# File 'lib/hop/ffi.rb', line 89 def self.publish_prekey(node) = PUBLISH_PREKEY.call(node) != 0 |
.read_bytes(ptr, len) ⇒ Object
---- helpers: read C memory that is valid only during a call ----
73 |
# File 'lib/hop/ffi.rb', line 73 def self.read_bytes(ptr, len) = len.zero? ? "".b : Fiddle::Pointer.new(ptr)[0, len].b |
.read_cstr(ptr) ⇒ Object
74 |
# File 'lib/hop/ffi.rb', line 74 def self.read_cstr(ptr) = Fiddle::Pointer.new(ptr).to_s |
.received(node, link, data) ⇒ Object
83 |
# File 'lib/hop/ffi.rb', line 83 def self.received(node, link, data) = BYTES_RECEIVED.call(node, link, data, data.bytesize) |
.send_service_request(node, dst, service, method, args) ⇒ Object
104 105 106 107 108 109 110 |
# File 'lib/hop/ffi.rb', line 104 def self.send_service_request(node, dst, service, method, args) out = Fiddle::Pointer.malloc(32, Fiddle::RUBY_FREE) ok = SEND_SERVICE_REQUEST.call(node, dst, service, method, args, args.bytesize, out) != 0 raise "hop_send_service_request failed" unless ok out[0, 32].b end |
.send_service_response(node, to, for_request_id, status, body) ⇒ Object
112 113 114 |
# File 'lib/hop/ffi.rb', line 112 def self.send_service_response(node, to, for_request_id, status, body) SEND_SERVICE_RESPONSE.call(node, to, for_request_id, status, body, body.bytesize) != 0 end |
.sign_reach(node, endpoint, ttl_secs) ⇒ Object
147 148 149 150 151 152 |
# File 'lib/hop/ffi.rb', line 147 def self.sign_reach(node, endpoint, ttl_secs) result = nil sink = Closure.new(V, [P, P, SZ]) { |_ctx, ptr, len| result = read_bytes(ptr, len) } SIGN_REACH_RECORD.call(node, endpoint, ttl_secs, sink, nil) result end |
.subscribe(node, topic) ⇒ Object
84 |
# File 'lib/hop/ffi.rb', line 84 def self.subscribe(node, topic) = SUBSCRIBE.call(node, topic) |
.take_service_requests(node) ⇒ Object
116 117 118 119 120 121 122 123 |
# File 'lib/hop/ffi.rb', line 116 def self.take_service_requests(node) out = [] sink = Closure.new(V, [P, P, P, P, P, P, SZ]) do |_ctx, frm, rid, service, method, args, arglen| out << [read_bytes(frm, 32), read_bytes(rid, 32), read_cstr(service), read_cstr(method), read_bytes(args, arglen)] end POLL_SERVICE_REQUESTS.call(node, sink, nil) out end |
.take_service_responses(node) ⇒ Object
125 126 127 128 129 130 131 132 |
# File 'lib/hop/ffi.rb', line 125 def self.take_service_responses(node) out = [] sink = Closure.new(V, [P, P, P, I, P, SZ]) do |_ctx, frm, for_id, status, body, body_len| out << [read_bytes(frm, 32), read_bytes(for_id, 32), status & 0xFFFF, read_bytes(body, body_len)] end POLL_SERVICE_RESPONSES.call(node, sink, nil) out end |
.tick(node, now_ms) ⇒ Object
80 |
# File 'lib/hop/ffi.rb', line 80 def self.tick(node, now_ms) = NODE_TICK.call(node, now_ms) |
.to_b58(addr32) ⇒ Object
134 135 136 137 138 |
# File 'lib/hop/ffi.rb', line 134 def self.to_b58(addr32) out = Fiddle::Pointer.malloc(64, Fiddle::RUBY_FREE) n = ADDRESS_TO_BASE58.call(addr32, out, 64) out[0, n] end |
.verify_reach(record, now_secs) ⇒ Object
154 155 156 157 158 159 160 161 |
# File 'lib/hop/ffi.rb', line 154 def self.verify_reach(record, now_secs) info = nil sink = Closure.new(V, [P, P, P, LL, I]) do |_ctx, addr, endpoint, issued_at, ttl_secs| info = { address: read_bytes(addr, 32), endpoint: read_cstr(endpoint), issued_at: issued_at, ttl_secs: ttl_secs } end ok = VERIFY_REACH_RECORD.call(record, record.bytesize, now_secs, sink, nil) != 0 ok ? info : nil end |