tigerbeetle 0.0.1.pre.dev → 0.0.2

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.
@@ -0,0 +1,215 @@
1
+ require 'ffi'
2
+ require 'tb_client'
3
+ require 'tigerbeetle/converters'
4
+ require 'tigerbeetle/account'
5
+ require 'tigerbeetle/account_balance'
6
+ require 'tigerbeetle/account_filter'
7
+ require 'tigerbeetle/atomic_counter'
8
+ require 'tigerbeetle/error'
9
+ require 'tigerbeetle/query_filter'
10
+ require 'tigerbeetle/request'
11
+ require 'tigerbeetle/transfer'
12
+
13
+ module TigerBeetle
14
+ class Client
15
+ def self.next_id
16
+ @counter ||= AtomicCounter.new
17
+ @counter.increment
18
+ end
19
+
20
+ def initialize(cluster_id = 0, address = '3000')
21
+ @inflight_requests = {}
22
+ # Keep a pointer to prevent proc from getting GCed
23
+ @callback = Proc.new { |*args| callback(*args) }
24
+ @client_id = self.class.next_id
25
+ @client = TBClient::Client.new
26
+
27
+ # FFI::MemoryPointer.new(:pointer, 1) # **void
28
+ cluster_id_ptr = serialize([cluster_id], Converters::UInt128)
29
+
30
+ status = TBClient.tb_client_init(
31
+ @client,
32
+ cluster_id_ptr,
33
+ address,
34
+ address.length,
35
+ @client_id,
36
+ &@callback
37
+ )
38
+ raise ClientError, "Unable to initialize native client: #{status}" unless status == :SUCCESS
39
+
40
+ # Make sure to deinitialize all clients when the process terminates
41
+ at_exit { deinit }
42
+ end
43
+
44
+ def logger=(logger)
45
+ @logger = logger
46
+ @log_callback = @logger ? Proc.new { |*args| log_callback(*args) } : nil
47
+
48
+ status = TBClient.tb_client_register_log_callback(@log_callback, true)
49
+ raise ClientError, "Unable to register logger: #{status}" unless status == :SUCCESS
50
+ end
51
+
52
+ def create_accounts(*accounts, &block)
53
+ submit_request(
54
+ :CREATE_ACCOUNTS,
55
+ accounts,
56
+ Converters::Account,
57
+ Converters::CreateAccountsResult,
58
+ &block
59
+ )
60
+ end
61
+
62
+ def create_transfers(*transfers, &block)
63
+ submit_request(
64
+ :CREATE_TRANSFERS,
65
+ transfers,
66
+ Converters::Transfer,
67
+ Converters::CreateTransfersResult,
68
+ &block
69
+ )
70
+ end
71
+
72
+ def lookup_accounts(*account_ids, &block)
73
+ submit_request(
74
+ :LOOKUP_ACCOUNTS,
75
+ account_ids,
76
+ Converters::UInt128,
77
+ Converters::Account,
78
+ &block
79
+ )
80
+ end
81
+
82
+ def lookup_transfers(*transfer_ids, &block)
83
+ submit_request(
84
+ :LOOKUP_TRANSFERS,
85
+ transfer_ids,
86
+ Converters::UInt128,
87
+ Converters::Transfer,
88
+ &block
89
+ )
90
+ end
91
+
92
+ def get_account_transfers(filter, &block)
93
+ submit_request(
94
+ :GET_ACCOUNT_TRANSFERS,
95
+ [filter],
96
+ Converters::AccountFilter,
97
+ Converters::Transfer,
98
+ &block
99
+ )
100
+ end
101
+
102
+ def get_account_balances(filter, &block)
103
+ submit_request(
104
+ :GET_ACCOUNT_BALANCES,
105
+ [filter],
106
+ Converters::AccountFilter,
107
+ Converters::AccountBalance,
108
+ &block
109
+ )
110
+ end
111
+
112
+ def query_accounts(filter, &block)
113
+ submit_request(
114
+ :QUERY_ACCOUNTS,
115
+ [filter],
116
+ Converters::QueryFilter,
117
+ Converters::Account,
118
+ &block
119
+ )
120
+ end
121
+
122
+ def query_transfers(filter, &block)
123
+ submit_request(
124
+ :QUERY_TRANSFERS,
125
+ [filter],
126
+ Converters::QueryFilter,
127
+ Converters::Transfer,
128
+ &block
129
+ )
130
+ end
131
+
132
+ def deinit
133
+ return unless client
134
+ return unless inflight_requests.empty?
135
+
136
+ TBClient.tb_client_deinit(client)
137
+ @client = nil
138
+ end
139
+
140
+ private
141
+
142
+ attr_reader :context, :client, :inflight_requests, :logger
143
+
144
+ def log_callback(level, ptr, length)
145
+ message = ptr.read_string(length).force_encoding('UTF-8')
146
+ case level
147
+ when :ERR then logger.error(message)
148
+ when :WARN then logger.warn(message)
149
+ when :INFO then logger.info(message)
150
+ when :DEBUG then logger.debug(message)
151
+ end
152
+ end
153
+
154
+ def callback(client_id, packet, timestamp, result_ptr, result_len)
155
+ request_id = packet[:user_data].read_uint64
156
+ request = inflight_requests[request_id]
157
+ result = deserialize(result_ptr, request.converter, result_len)
158
+ request.block.call(result)
159
+ inflight_requests.delete(request_id)
160
+ end
161
+
162
+ def submit_request(operation, request, request_converter, response_converter, &block)
163
+ raise ClientError, 'Client is not connected' unless client
164
+
165
+ request_id = self.class.next_id
166
+ user_data_ptr = FFI::MemoryPointer.new(:uint64, 1)
167
+ user_data_ptr.write_uint64(request_id)
168
+
169
+ data_ptr = serialize(request, request_converter)
170
+
171
+ packet = TBClient::Packet.new
172
+ packet[:user_data] = user_data_ptr
173
+ packet[:operation] = operation
174
+ packet[:status] = :OK
175
+ packet[:data_size] = data_ptr.size
176
+ packet[:data] = data_ptr
177
+
178
+ queue = Queue.new
179
+ inflight_requests[request_id] = Request.new(packet, response_converter) do |response|
180
+ if block
181
+ block.call(response)
182
+ else
183
+ queue << response
184
+ end
185
+ end
186
+
187
+ status = TBClient.tb_client_submit(client, packet)
188
+ raise ClientError, "Unable to submit request: #{status}" unless status == :OK
189
+
190
+ # block until the client return a response
191
+ queue.pop unless block
192
+ end
193
+
194
+ def serialize(data, converter)
195
+ data_ptr = FFI::MemoryPointer.new(converter.native_type, data.length, true)
196
+ data.each_with_index do |value, i|
197
+ # initialize type at the memory address and write value over it
198
+ converter.to_native(data_ptr[i], value)
199
+ end
200
+
201
+ data_ptr
202
+ end
203
+
204
+ def deserialize(ptr, converter, length)
205
+ type = converter.native_type
206
+ # copy the memory own to retain the data after tb_client has freed its memory
207
+ own_ptr = FFI::MemoryPointer.new(:char, type.size * length)
208
+ own_ptr.put_bytes(0, ptr.read_bytes(type.size * length))
209
+
210
+ Array.new(length / type.size) do |i|
211
+ converter.from_native(own_ptr + i * type.size)
212
+ end
213
+ end
214
+ end
215
+ end
@@ -0,0 +1,63 @@
1
+ require 'tb_client'
2
+ require 'tigerbeetle/account'
3
+ require 'tigerbeetle/converters/base'
4
+ require 'tigerbeetle/converters/time'
5
+ require 'tigerbeetle/converters/uint_128'
6
+
7
+ module TigerBeetle
8
+ module Converters
9
+ class Account < Base
10
+ def self.native_type
11
+ TBClient::Account
12
+ end
13
+
14
+ def from_native(ptr)
15
+ c_value = TBClient::Account.new(ptr)
16
+
17
+ TigerBeetle::Account.new(
18
+ id: Converters::UInt128.from_native(c_value[:id].to_ptr),
19
+ debits_pending: Converters::UInt128.from_native(c_value[:debits_pending].to_ptr),
20
+ debits_posted: Converters::UInt128.from_native(c_value[:debits_posted].to_ptr),
21
+ credits_pending: Converters::UInt128.from_native(c_value[:credits_pending].to_ptr),
22
+ credits_posted: Converters::UInt128.from_native(c_value[:credits_posted].to_ptr),
23
+ user_data_128: Converters::UInt128.from_native(c_value[:user_data_128].to_ptr),
24
+ user_data_64: c_value[:user_data_64],
25
+ user_data_32: c_value[:user_data_32],
26
+ ledger: c_value[:ledger],
27
+ code: c_value[:code],
28
+ flags: c_value[:flags],
29
+ timestamp: Converters::Time.from_native(ptr + c_value.offset_of(:timestamp))
30
+ )
31
+ end
32
+
33
+ def to_native(ptr, value)
34
+ validate_uint!(:id, 128, value.id)
35
+ validate_uint!(:debits_pending, 128, value.debits_pending)
36
+ validate_uint!(:debits_posted, 128, value.debits_posted)
37
+ validate_uint!(:credits_pending, 128, value.credits_pending)
38
+ validate_uint!(:credits_posted, 128, value.credits_posted)
39
+ validate_uint!(:user_data_128, 128, value.user_data_128)
40
+ validate_uint!(:user_data_64, 64, value.user_data_64)
41
+ validate_uint!(:user_data_32, 32, value.user_data_32)
42
+ validate_uint!(:ledger, 32, value.ledger)
43
+ validate_uint!(:code, 16, value.code)
44
+
45
+ TBClient::Account.new(ptr).tap do |result|
46
+ Converters::UInt128.to_native(result[:id].to_ptr, value.id)
47
+ Converters::UInt128.to_native(result[:debits_pending].to_ptr, value.debits_pending)
48
+ Converters::UInt128.to_native(result[:debits_posted].to_ptr, value.debits_posted)
49
+ Converters::UInt128.to_native(result[:credits_pending].to_ptr, value.credits_pending)
50
+ Converters::UInt128.to_native(result[:credits_posted].to_ptr, value.credits_posted)
51
+ Converters::UInt128.to_native(result[:user_data_128].to_ptr, value.user_data_128)
52
+ result[:user_data_64] = value.user_data_64
53
+ result[:user_data_32] = value.user_data_32
54
+ result[:reserved] = 0
55
+ result[:ledger] = value.ledger
56
+ result[:code] = value.code
57
+ result[:flags] = value.flags
58
+ Converters::Time.to_native(ptr + result.offset_of(:timestamp), value.timestamp || 0)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,31 @@
1
+ require 'tb_client'
2
+ require 'tigerbeetle/account_balance'
3
+ require 'tigerbeetle/converters/base'
4
+ require 'tigerbeetle/converters/time'
5
+ require 'tigerbeetle/converters/uint_128'
6
+
7
+ module TigerBeetle
8
+ module Converters
9
+ class AccountBalance < Base
10
+ def self.native_type
11
+ TBClient::AccountBalance
12
+ end
13
+
14
+ def from_native(ptr)
15
+ c_value = TBClient::AccountBalance.new(ptr)
16
+
17
+ TigerBeetle::AccountBalance.new(
18
+ debits_pending: Converters::UInt128.from_native(c_value[:debits_pending].to_ptr),
19
+ debits_posted: Converters::UInt128.from_native(c_value[:debits_posted].to_ptr),
20
+ credits_pending: Converters::UInt128.from_native(c_value[:credits_pending].to_ptr),
21
+ credits_posted: Converters::UInt128.from_native(c_value[:credits_posted].to_ptr),
22
+ timestamp: Converters::Time.from_native(ptr + c_value.offset_of(:timestamp))
23
+ )
24
+ end
25
+
26
+ def to_native(ptr, value)
27
+ raise 'Unexpected conversion of AccountBalance to native type'
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,32 @@
1
+ require 'tb_client'
2
+ require 'tigerbeetle/account_filter'
3
+ require 'tigerbeetle/converters/time'
4
+ require 'tigerbeetle/converters/uint_128'
5
+
6
+ module TigerBeetle
7
+ module Converters
8
+ class AccountFilter < Base
9
+ def self.native_type
10
+ TBClient::AccountFilter
11
+ end
12
+
13
+ def from_native(ptr)
14
+ raise 'Unexpected conversion of a native type to AccountFilter'
15
+ end
16
+
17
+ def to_native(ptr, value)
18
+ TBClient::AccountFilter.new(ptr).tap do |result|
19
+ Converters::UInt128.to_native(result[:account_id].to_ptr, value.account_id)
20
+ Converters::UInt128.to_native(result[:user_data_128].to_ptr, value.user_data_128)
21
+ result[:user_data_64] = value.user_data_64
22
+ result[:user_data_32] = value.user_data_32
23
+ result[:code] = value.code
24
+ Converters::Time.to_native(ptr + result.offset_of(:timestamp_min), value.timestamp_min || 0)
25
+ Converters::Time.to_native(ptr + result.offset_of(:timestamp_max), value.timestamp_max || 0)
26
+ result[:limit] = value.limit
27
+ result[:flags] = value.flags
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,35 @@
1
+ module TigerBeetle
2
+ module Converters
3
+ class Base
4
+ def self.from_native(ptr)
5
+ self.new.from_native(ptr)
6
+ end
7
+
8
+ def self.to_native(ptr, value)
9
+ self.new.to_native(ptr, value)
10
+ end
11
+
12
+ def self.native_type
13
+ raise NotImplementedError, 'Implement in sublcass'
14
+ end
15
+
16
+ def from_native(ptr)
17
+ raise NotImplementedError, 'Implement in sublcass'
18
+ end
19
+
20
+ def to_native(ptr, value)
21
+ raise NotImplementedError, 'Implement in sublcass'
22
+ end
23
+
24
+ private
25
+
26
+ def validate_uint!(name, bits, value)
27
+ if value > 2**bits - 1
28
+ raise ArgumentError, "#{name} == #{value} is too large to fit in #{bits} bits"
29
+ elsif value < 0
30
+ raise ArgumentError, "#{name} == #{value} cannot be negative"
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,21 @@
1
+ require 'tb_client'
2
+ require 'tigerbeetle/converters/base'
3
+
4
+ module TigerBeetle
5
+ module Converters
6
+ class CreateAccountsResult < Base
7
+ def self.native_type
8
+ TBClient::CreateAccountsResult
9
+ end
10
+
11
+ def from_native(ptr)
12
+ c_value = TBClient::CreateAccountsResult.new(ptr)
13
+ [c_value[:index], c_value[:result]]
14
+ end
15
+
16
+ def to_native(ptr, value)
17
+ raise 'Unexpected conversion of CreateAccountsResult to a native type'
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ require 'tb_client'
2
+ require 'tigerbeetle/converters/base'
3
+
4
+ module TigerBeetle
5
+ module Converters
6
+ class CreateTransfersResult < Base
7
+ def self.native_type
8
+ TBClient::CreateTransfersResult
9
+ end
10
+
11
+ def from_native(ptr)
12
+ c_value = TBClient::CreateTransfersResult.new(ptr)
13
+ [c_value[:index], c_value[:result]]
14
+ end
15
+
16
+ def to_native(ptr, value)
17
+ raise 'Unexpected conversion of CreateTransfersResult to a native type'
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,33 @@
1
+ require 'tb_client'
2
+ require 'tigerbeetle/query_filter'
3
+ require 'tigerbeetle/converters/base'
4
+ require 'tigerbeetle/converters/time'
5
+ require 'tigerbeetle/converters/uint_128'
6
+
7
+ module TigerBeetle
8
+ module Converters
9
+ class QueryFilter < Base
10
+ def self.native_type
11
+ TBClient::QueryFilter
12
+ end
13
+
14
+ def from_native(ptr)
15
+ raise 'Unexpected conversion of a native type to QueryFilter'
16
+ end
17
+
18
+ def to_native(ptr, value)
19
+ TBClient::QueryFilter.new(ptr).tap do |result|
20
+ Converters::UInt128.to_native(result[:user_data_128].to_ptr, value.user_data_128)
21
+ result[:user_data_64] = value.user_data_64
22
+ result[:user_data_32] = value.user_data_32
23
+ result[:code] = value.code
24
+ result[:ledger] = value.ledger
25
+ Converters::Time.to_native(ptr + result.offset_of(:timestamp_min), value.timestamp_min || 0)
26
+ Converters::Time.to_native(ptr + result.offset_of(:timestamp_max), value.timestamp_max || 0)
27
+ result[:limit] = value.limit
28
+ result[:flags] = value.flags
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,23 @@
1
+ require 'ffi'
2
+ require 'tigerbeetle/converters/base'
3
+
4
+ module TigerBeetle
5
+ module Converters
6
+ class Time < Base
7
+ def self.native_type
8
+ FFI::Type::UINT64
9
+ end
10
+
11
+ def from_native(ptr)
12
+ ::Time.at(ptr.read(FFI::Type::UINT64) / 1e9)
13
+ end
14
+
15
+ def to_native(ptr, value)
16
+ int = (value.to_f * 1e9).to_i
17
+ validate_uint!(:timestamp, 64, int)
18
+
19
+ ptr.write(FFI::Type::UINT64, int)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,64 @@
1
+ require 'tb_client'
2
+ require 'tigerbeetle/transfer'
3
+ require 'tigerbeetle/converters/base'
4
+ require 'tigerbeetle/converters/time'
5
+ require 'tigerbeetle/converters/uint_128'
6
+
7
+ module TigerBeetle
8
+ module Converters
9
+ class Transfer < Base
10
+ def self.native_type
11
+ TBClient::Transfer
12
+ end
13
+
14
+ def from_native(ptr)
15
+ c_value = TBClient::Transfer.new(ptr)
16
+
17
+ TigerBeetle::Transfer.new(
18
+ id: Converters::UInt128.from_native(c_value[:id].to_ptr),
19
+ debit_account_id: Converters::UInt128.from_native(c_value[:debit_account_id].to_ptr),
20
+ credit_account_id: Converters::UInt128.from_native(c_value[:credit_account_id].to_ptr),
21
+ amount: Converters::UInt128.from_native(c_value[:amount].to_ptr),
22
+ pending_id: Converters::UInt128.from_native(c_value[:pending_id].to_ptr),
23
+ user_data_128: Converters::UInt128.from_native(c_value[:user_data_128].to_ptr),
24
+ user_data_64: c_value[:user_data_64],
25
+ user_data_32: c_value[:user_data_32],
26
+ timeout: c_value[:timeout],
27
+ ledger: c_value[:ledger],
28
+ code: c_value[:code],
29
+ flags: c_value[:flags],
30
+ timestamp: Converters::Time.from_native(ptr + c_value.offset_of(:timestamp))
31
+ )
32
+ end
33
+
34
+ def to_native(ptr, value)
35
+ validate_uint!(:id, 128, value.id)
36
+ validate_uint!(:debit_account_id, 128, value.debit_account_id)
37
+ validate_uint!(:credit_account_id, 128, value.credit_account_id)
38
+ validate_uint!(:amount, 128, value.amount)
39
+ validate_uint!(:user_data_128, 128, value.user_data_128)
40
+ validate_uint!(:user_data_64, 64, value.user_data_64)
41
+ validate_uint!(:user_data_32, 32, value.user_data_32)
42
+ validate_uint!(:timeout, 32, value.timeout)
43
+ validate_uint!(:ledger, 32, value.ledger)
44
+ validate_uint!(:code, 16, value.code)
45
+
46
+ TBClient::Transfer.new(ptr).tap do |result|
47
+ Converters::UInt128.to_native(result[:id].to_ptr, value.id)
48
+ Converters::UInt128.to_native(result[:debit_account_id].to_ptr, value.debit_account_id)
49
+ Converters::UInt128.to_native(result[:credit_account_id].to_ptr, value.credit_account_id)
50
+ Converters::UInt128.to_native(result[:amount].to_ptr, value.amount)
51
+ Converters::UInt128.to_native(result[:pending_id].to_ptr, value.pending_id)
52
+ Converters::UInt128.to_native(result[:user_data_128].to_ptr, value.user_data_128)
53
+ result[:user_data_64] = value.user_data_64
54
+ result[:user_data_32] = value.user_data_32
55
+ result[:timeout] = value.timeout
56
+ result[:ledger] = value.ledger
57
+ result[:code] = value.code
58
+ result[:flags] = value.flags
59
+ Converters::Time.to_native(ptr + result.offset_of(:timestamp), value.timestamp || 0)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,24 @@
1
+ require 'tb_client'
2
+ require 'tigerbeetle/converters/base'
3
+
4
+ module TigerBeetle
5
+ module Converters
6
+ class UInt128 < Base
7
+ def self.native_type
8
+ TBClient::UInt128
9
+ end
10
+
11
+ def from_native(ptr)
12
+ c_value = TBClient::UInt128.new(ptr)
13
+ c_value[:low] + (c_value[:high] << 64)
14
+ end
15
+
16
+ def to_native(ptr, value)
17
+ TBClient::UInt128.new(ptr).tap do |result|
18
+ result[:low] = value % 2**64
19
+ result[:high] = value >> 64
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,12 @@
1
+ require 'tigerbeetle/converters/account'
2
+ require 'tigerbeetle/converters/account_balance'
3
+ require 'tigerbeetle/converters/account_filter'
4
+ require 'tigerbeetle/converters/create_accounts_result'
5
+ require 'tigerbeetle/converters/create_transfers_result'
6
+ require 'tigerbeetle/converters/query_filter'
7
+ require 'tigerbeetle/converters/time'
8
+ require 'tigerbeetle/converters/transfer'
9
+ require 'tigerbeetle/converters/uint_128'
10
+
11
+ module Converters
12
+ end
@@ -0,0 +1,4 @@
1
+ module TigerBeetle
2
+ class Error < StandardError; end
3
+ class ClientError < Error; end
4
+ end
@@ -0,0 +1,30 @@
1
+ require 'securerandom'
2
+
3
+ module TigerBeetle
4
+ module ID
5
+ @last_time_ms = 0
6
+
7
+ # Generates a Universally Unique and Sortable Identifier as a 128-bit integer. Based on ULIDs
8
+ # Inspired by ext/tb_client/tigerbeetle/src/clients/python/src/tigerbeetle/client.py#id
9
+ def self.generate
10
+ rnd_bytes = SecureRandom.random_bytes(10)
11
+ time_ms = (Time.now.to_f * 1000).to_i
12
+
13
+ # Ensure time_ms monotonically increases
14
+ if time_ms <= @last_time_ms
15
+ time_ms = @last_time_ms
16
+ else
17
+ @last_time_ms = time_ms
18
+ end
19
+
20
+ # Convert time_ms integer to 6 bytes (string) in big-endian
21
+ time_bytes = [time_ms].pack("Q>")[2..7]
22
+
23
+ # Combine time and randomness and convert to two 64-bit integers in big-endian
24
+ integers = (time_bytes + rnd_bytes).unpack("Q>Q>")
25
+
26
+ # Re-combine into a single 128-bit integer in big-endian
27
+ integers[0] << 64 | integers[1]
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,31 @@
1
+ module TigerBeetle
2
+ QUERY_FILTER_PARAMS = %i[
3
+ user_data_128 user_data_64 user_data_32 ledger code timestamp_min timestamp_max limit flags
4
+ ]
5
+
6
+ QueryFilter = Struct.new(*QUERY_FILTER_PARAMS) do
7
+ def initialize(
8
+ user_data_128: 0,
9
+ user_data_64: 0,
10
+ user_data_32: 0,
11
+ ledger: 0,
12
+ code: 0,
13
+ timestamp_min: 0,
14
+ timestamp_max: 0,
15
+ limit:,
16
+ flags: []
17
+ )
18
+ super(
19
+ user_data_128,
20
+ user_data_64,
21
+ user_data_32,
22
+ ledger,
23
+ code,
24
+ timestamp_min,
25
+ timestamp_max,
26
+ limit,
27
+ flags
28
+ )
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,7 @@
1
+ module TigerBeetle
2
+ Request = Struct.new(:packet, :converter, :block) do
3
+ def initialize(packet, converter, &block)
4
+ super(packet, converter, block)
5
+ end
6
+ end
7
+ end