tigerbeetle 0.0.1.pre.dev → 0.0.1
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 +6 -0
- data/README.md +92 -0
- data/ext/tb_client/extconf.rb +39 -0
- data/ext/tb_client/pkg.tar.gz +0 -0
- data/lib/tb_client/shared_lib.rb +59 -0
- data/lib/tb_client.rb +282 -0
- data/lib/tigerbeetle/account.rb +38 -0
- data/lib/tigerbeetle/account_balance.rb +23 -0
- data/lib/tigerbeetle/account_filter.rb +31 -0
- data/lib/tigerbeetle/client.rb +213 -0
- data/lib/tigerbeetle/converters/account.rb +63 -0
- data/lib/tigerbeetle/converters/account_balance.rb +31 -0
- data/lib/tigerbeetle/converters/account_filter.rb +32 -0
- data/lib/tigerbeetle/converters/base.rb +35 -0
- data/lib/tigerbeetle/converters/create_accounts_result.rb +21 -0
- data/lib/tigerbeetle/converters/create_transfers_result.rb +21 -0
- data/lib/tigerbeetle/converters/query_filter.rb +33 -0
- data/lib/tigerbeetle/converters/time.rb +23 -0
- data/lib/tigerbeetle/converters/transfer.rb +64 -0
- data/lib/tigerbeetle/converters/uint_128.rb +24 -0
- data/lib/tigerbeetle/converters.rb +12 -0
- data/lib/tigerbeetle/id.rb +30 -0
- data/lib/tigerbeetle/query_filter.rb +31 -0
- data/lib/tigerbeetle/request.rb +7 -0
- data/lib/tigerbeetle/transfer.rb +40 -0
- data/lib/tigerbeetle/version.rb +1 -1
- data/lib/tigerbeetle.rb +10 -1
- data/tigerbeetle.gemspec +17 -2
- metadata +87 -6
- data/Gemfile +0 -3
@@ -0,0 +1,213 @@
|
|
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/query_filter'
|
8
|
+
require 'tigerbeetle/request'
|
9
|
+
require 'tigerbeetle/transfer'
|
10
|
+
|
11
|
+
module TigerBeetle
|
12
|
+
class Client
|
13
|
+
# TODO: Make this counter atomic
|
14
|
+
@counter = 0
|
15
|
+
|
16
|
+
def self.next_id
|
17
|
+
@counter += 1
|
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 "Error while initializing 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 "Error registering a 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
|
+
|
135
|
+
TBClient.tb_client_deinit(client)
|
136
|
+
@client = nil
|
137
|
+
end
|
138
|
+
|
139
|
+
private
|
140
|
+
|
141
|
+
attr_reader :context, :client, :inflight_requests, :logger
|
142
|
+
|
143
|
+
def log_callback(level, ptr, length)
|
144
|
+
message = ptr.read_string(length).force_encoding('UTF-8')
|
145
|
+
case level
|
146
|
+
when :ERR then logger.error(message)
|
147
|
+
when :WARN then logger.warn(message)
|
148
|
+
when :INFO then logger.info(message)
|
149
|
+
when :DEBUG then logger.debug(message)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def callback(client_id, packet, timestamp, result_ptr, result_len)
|
154
|
+
request_id = packet[:user_data].read_uint64
|
155
|
+
request = inflight_requests[request_id]
|
156
|
+
result = deserialize(result_ptr, request.converter, result_len)
|
157
|
+
request.block.call(result)
|
158
|
+
end
|
159
|
+
|
160
|
+
def submit_request(operation, request, request_converter, response_converter, &block)
|
161
|
+
raise 'Client is not connected' unless client
|
162
|
+
|
163
|
+
request_id = self.class.next_id
|
164
|
+
user_data_ptr = FFI::MemoryPointer.new(:uint64, 1)
|
165
|
+
user_data_ptr.write_uint64(request_id)
|
166
|
+
|
167
|
+
data_ptr = serialize(request, request_converter)
|
168
|
+
|
169
|
+
packet = TBClient::Packet.new
|
170
|
+
packet[:user_data] = user_data_ptr
|
171
|
+
packet[:operation] = operation
|
172
|
+
packet[:status] = :OK
|
173
|
+
packet[:data_size] = data_ptr.size
|
174
|
+
packet[:data] = data_ptr
|
175
|
+
|
176
|
+
queue = Queue.new
|
177
|
+
inflight_requests[request_id] = Request.new(packet, response_converter) do |response|
|
178
|
+
if block
|
179
|
+
block.call(response)
|
180
|
+
else
|
181
|
+
queue << response
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
status = TBClient.tb_client_submit(client, packet)
|
186
|
+
raise "Unable to submit request: #{status}" unless status == :OK
|
187
|
+
|
188
|
+
# block until the client return a response
|
189
|
+
queue.pop unless block
|
190
|
+
end
|
191
|
+
|
192
|
+
def serialize(data, converter)
|
193
|
+
data_ptr = FFI::MemoryPointer.new(converter.native_type, data.length, true)
|
194
|
+
data.each_with_index do |value, i|
|
195
|
+
# initialize type at the memory address and write value over it
|
196
|
+
converter.to_native(data_ptr[i], value)
|
197
|
+
end
|
198
|
+
|
199
|
+
data_ptr
|
200
|
+
end
|
201
|
+
|
202
|
+
def deserialize(ptr, converter, length)
|
203
|
+
type = converter.native_type
|
204
|
+
# copy the memory own to retain the data after tb_client has freed its memory
|
205
|
+
own_ptr = FFI::MemoryPointer.new(:char, type.size * length)
|
206
|
+
own_ptr.put_bytes(0, ptr.read_bytes(type.size * length))
|
207
|
+
|
208
|
+
Array.new(length / type.size) do |i|
|
209
|
+
converter.from_native(own_ptr + i * type.size)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
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,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: 0,
|
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,40 @@
|
|
1
|
+
module TigerBeetle
|
2
|
+
TRANSFER_PARAMS = %i[
|
3
|
+
id debit_account_id credit_account_id amount pending_id user_data_128
|
4
|
+
user_data_64 user_data_32 timeout ledger code flags timestamp
|
5
|
+
]
|
6
|
+
|
7
|
+
Transfer = Struct.new(*TRANSFER_PARAMS) do
|
8
|
+
def initialize(
|
9
|
+
id: 0,
|
10
|
+
debit_account_id: 0,
|
11
|
+
credit_account_id: 0,
|
12
|
+
amount: 0,
|
13
|
+
pending_id: 0,
|
14
|
+
user_data_128: 0,
|
15
|
+
user_data_64: 0,
|
16
|
+
user_data_32: 0,
|
17
|
+
timeout: 0,
|
18
|
+
ledger: 0,
|
19
|
+
code: 0,
|
20
|
+
flags: [],
|
21
|
+
timestamp: nil
|
22
|
+
)
|
23
|
+
super(
|
24
|
+
id,
|
25
|
+
debit_account_id,
|
26
|
+
credit_account_id,
|
27
|
+
amount,
|
28
|
+
pending_id,
|
29
|
+
user_data_128,
|
30
|
+
user_data_64,
|
31
|
+
user_data_32,
|
32
|
+
timeout,
|
33
|
+
ledger,
|
34
|
+
code,
|
35
|
+
flags,
|
36
|
+
timestamp
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|