everscale-client-ruby 1.1.23
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/bin/ton-client-ruby +50 -0
- data/lib/code_generator/api.json +13837 -0
- data/lib/code_generator/api_converter.rb +400 -0
- data/lib/code_generator/code_generator.rb +339 -0
- data/lib/code_generator/helpers.rb +13 -0
- data/lib/code_generator/release.rb +48 -0
- data/lib/everscale-client-ruby/Binding/binding.rb +209 -0
- data/lib/everscale-client-ruby/Binding/struct.rb +21 -0
- data/lib/everscale-client-ruby/Client/Abi.rb +196 -0
- data/lib/everscale-client-ruby/Client/Boc.rb +196 -0
- data/lib/everscale-client-ruby/Client/Client.rb +83 -0
- data/lib/everscale-client-ruby/Client/Context.rb +34 -0
- data/lib/everscale-client-ruby/Client/Crypto.rb +465 -0
- data/lib/everscale-client-ruby/Client/Debot.rb +60 -0
- data/lib/everscale-client-ruby/Client/Net.rb +237 -0
- data/lib/everscale-client-ruby/Client/Processing.rb +59 -0
- data/lib/everscale-client-ruby/Client/Proofs.rb +34 -0
- data/lib/everscale-client-ruby/Client/Tvm.rb +62 -0
- data/lib/everscale-client-ruby/Client/Utils.rb +59 -0
- data/lib/everscale-client-ruby/Helpers/CommonHelpers.rb +70 -0
- data/lib/everscale-client-ruby/version.rb +4 -0
- data/lib/everscale-client-ruby.rb +44 -0
- metadata +164 -0
@@ -0,0 +1,339 @@
|
|
1
|
+
require 'byebug'
|
2
|
+
require 'json'
|
3
|
+
require File.dirname(__FILE__) + '/helpers.rb'
|
4
|
+
|
5
|
+
class CodeGenerator
|
6
|
+
include InstanceHelpers
|
7
|
+
|
8
|
+
attr_accessor :types
|
9
|
+
attr_accessor :root_dir
|
10
|
+
|
11
|
+
TAB = " "
|
12
|
+
|
13
|
+
def initialize(types, root_dir)
|
14
|
+
@types = types
|
15
|
+
@root_dir = root_dir
|
16
|
+
end
|
17
|
+
|
18
|
+
def generate_self_code
|
19
|
+
generateModules(types)
|
20
|
+
generateReadme(types)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def generateModules(types)
|
26
|
+
types.modules.each do |mod|
|
27
|
+
modulesFolder = root_dir + "/lib/everscale-client-ruby/Client"
|
28
|
+
moduleFilePath = "#{modulesFolder}/#{mod.name.capitalize}.rb"
|
29
|
+
newModuleContent = ""
|
30
|
+
if mod.name == "client"
|
31
|
+
newModuleContent = generateClientModule(mod, types.modules)
|
32
|
+
else
|
33
|
+
newModuleContent = generateModule(mod)
|
34
|
+
end
|
35
|
+
if File.exists?(moduleFilePath)
|
36
|
+
File.delete(moduleFilePath)
|
37
|
+
end
|
38
|
+
File.open(moduleFilePath, 'w+') { |f| f.write(newModuleContent) }
|
39
|
+
end
|
40
|
+
|
41
|
+
p 'generate_self_code ok'
|
42
|
+
end
|
43
|
+
|
44
|
+
def generateReadme(types)
|
45
|
+
readmePath = root_dir + "/README.md"
|
46
|
+
content = %{
|
47
|
+
# Ruby Client for Free TON SDK
|
48
|
+
|
49
|
+
[](https://rubygems.org/gems/everscale-client-ruby)
|
50
|
+
[](https://github.com/tonlabs/TON-SDK)
|
51
|
+
|
52
|
+
## Install
|
53
|
+
|
54
|
+
Install gem
|
55
|
+
```bash
|
56
|
+
gem install ton-client-ruby
|
57
|
+
```
|
58
|
+
|
59
|
+
Install TON-SDK
|
60
|
+
```bash
|
61
|
+
ton-client-ruby setup
|
62
|
+
# result - path to dylib file for ton-client-ruby configuration
|
63
|
+
```
|
64
|
+
|
65
|
+
### Manual build FreeTON SDK
|
66
|
+
0. Install Rust to your OS
|
67
|
+
1. git clone https://github.com/tonlabs/TON-SDK
|
68
|
+
2. cd ./TON-SDK
|
69
|
+
3. cargo update
|
70
|
+
4. cargo build --release
|
71
|
+
|
72
|
+
## Usage
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
# For MAcOS
|
76
|
+
TonClient.configure { |config| config.ffi_lib(./TON-SDK/target/release/libton_client.dylib) }
|
77
|
+
# For Linux
|
78
|
+
# TonClient.configure { |config| config.ffi_lib(./TON-SDK/target/release/libton_client.so) }
|
79
|
+
|
80
|
+
client = TonClient.create(config: {network: {server_address: "net.ton.dev"}})
|
81
|
+
|
82
|
+
# All methods are asynchronous
|
83
|
+
|
84
|
+
# example: call method for Crypto module
|
85
|
+
payload = {composite: '17ED48941A08F981'}
|
86
|
+
client.crypto.factorize(payload) do |response|
|
87
|
+
p response.result['factors']
|
88
|
+
end
|
89
|
+
|
90
|
+
# e.g. ...
|
91
|
+
```\n\n
|
92
|
+
}
|
93
|
+
content << "## All Modules, methods and types\n\n"
|
94
|
+
|
95
|
+
# types
|
96
|
+
content << "<details>\n#{TAB}<summary>Types</summary>\n\n"
|
97
|
+
|
98
|
+
content << "#{customTypes()}\n"
|
99
|
+
|
100
|
+
types.modules.each do |mod|
|
101
|
+
(mod.enums || []).each do |type|
|
102
|
+
content << checkComment(type.summary, 0) if type.summary
|
103
|
+
content << checkComment(type.description, 0) if type.description
|
104
|
+
content << "\n- #### #{type.name}\n"
|
105
|
+
(type.cases || []).each do |enum_case|
|
106
|
+
content << "#{checkComment(enum_case.summary, 1).gsub(/#/, '')}" if enum_case.summary
|
107
|
+
content << "#{checkComment(enum_case.description, 1).gsub(/#/, '')}" if enum_case.description
|
108
|
+
content << "#{TAB}- case #{enum_case.name} = #{enum_case.value}\n\n"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
(mod.types || []).each do |type|
|
113
|
+
content << checkComment(type.summary, 0) if type.summary
|
114
|
+
content << checkComment(type.description, 0) if type.description
|
115
|
+
content << "\n- #### #{type.name}\n"
|
116
|
+
(type.fields || []).each do |field|
|
117
|
+
content << "#{checkComment(field.summary, 1).gsub(/#/, '')}\n" if field.summary
|
118
|
+
content << "#{checkComment(field.description, 1).gsub(/#/, '')}\n" if field.description
|
119
|
+
content << "#{TAB}- #{field.name}: #{field.type}\n\n"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
content << "</details>\n\n"
|
124
|
+
|
125
|
+
# methods
|
126
|
+
types.modules.each do |mod|
|
127
|
+
content << "<details>\n#{TAB}<summary>#{mod.name&.upcase}</summary>\n\n"
|
128
|
+
(mod.functions || []).each do |function|
|
129
|
+
content << "```ruby\n"
|
130
|
+
content << checkComment(function.summary, 2) if function.summary
|
131
|
+
content << checkComment(function.description, 2) if function.description
|
132
|
+
content << "\n#{TAB}#{TAB}def #{function.name}"
|
133
|
+
if function.arguments.empty?
|
134
|
+
content << "(&block)\n"
|
135
|
+
else
|
136
|
+
content << "(payload, &block)\n"
|
137
|
+
end
|
138
|
+
content << getFunctionComment(function, types)
|
139
|
+
content << "```\n"
|
140
|
+
end
|
141
|
+
content << "</details>\n\n"
|
142
|
+
end
|
143
|
+
|
144
|
+
content << %{
|
145
|
+
\n## Tests
|
146
|
+
|
147
|
+
1. create __.env.test__ file inside root directory of this library with variables
|
148
|
+
|
149
|
+
example for NodeSE
|
150
|
+
```
|
151
|
+
spec_ffi=./TON-SDK/target/release/libton_client.dylib
|
152
|
+
server_address=http://localhost:80
|
153
|
+
giver_abi_name=GiverNodeSE
|
154
|
+
giver_amount=10000000000
|
155
|
+
```
|
156
|
+
2. Run tests: inside folder of this library execute this commands
|
157
|
+
**rspec spec/binding.rb**
|
158
|
+
**rspec spec/client.rb**
|
159
|
+
**rspec spec/context.rb**
|
160
|
+
**rspec spec/abi.rb**
|
161
|
+
**rspec spec/boc.rb**
|
162
|
+
**rspec spec/crypto.rb**
|
163
|
+
**rspec spec/net.rb**
|
164
|
+
**rspec spec/processing.rb**
|
165
|
+
**rspec spec/tvm.rb**
|
166
|
+
**rspec spec/utils.rb**
|
167
|
+
|
168
|
+
\n## Update\n\n
|
169
|
+
```\n
|
170
|
+
ton-client-ruby update\n
|
171
|
+
```\n\n
|
172
|
+
or\n\n
|
173
|
+
```\n
|
174
|
+
curl https://raw.githubusercontent.com/tonlabs/TON-SDK/master/tools/api.json > api.json\n\n
|
175
|
+
```\n\n
|
176
|
+
```\n
|
177
|
+
ton-client-ruby update ./api.json\n
|
178
|
+
```\n
|
179
|
+
or\n\n
|
180
|
+
```\n
|
181
|
+
cd ton-client-ruby\n
|
182
|
+
```\n\n
|
183
|
+
```\n
|
184
|
+
./bin/ton-client-ruby update\n
|
185
|
+
```\n
|
186
|
+
}
|
187
|
+
content = checkContent(content)
|
188
|
+
if File.exists?(readmePath)
|
189
|
+
File.delete(readmePath)
|
190
|
+
end
|
191
|
+
File.open(readmePath, 'w+') { |f| f.write(content) }
|
192
|
+
end
|
193
|
+
|
194
|
+
private def checkContent(content)
|
195
|
+
content.gsub!(/^([\s]+)# RESPONSE/, "\n\\1# RESPONSE")
|
196
|
+
content.gsub(/<Optional>/i, '<Optional>')
|
197
|
+
end
|
198
|
+
|
199
|
+
def customTypes
|
200
|
+
content = %{
|
201
|
+
- #### #{lib_prefix}MnemonicDictionary
|
202
|
+
#{TAB}- case TON = 0
|
203
|
+
#{TAB}- case ENGLISH = 1
|
204
|
+
#{TAB}- case CHINESE_SIMPLIFIED = 2
|
205
|
+
#{TAB}- case CHINESE_TRADITIONAL = 3
|
206
|
+
#{TAB}- case FRENCH = 4
|
207
|
+
#{TAB}- case ITALIAN = 5
|
208
|
+
#{TAB}- case JAPANESE = 6
|
209
|
+
#{TAB}- case KOREAN = 7
|
210
|
+
#{TAB}- case SPANISH = 8
|
211
|
+
}
|
212
|
+
content
|
213
|
+
end
|
214
|
+
|
215
|
+
private def checkComment(string, tabs = 1)
|
216
|
+
replacedString = "\n"
|
217
|
+
tab = ""
|
218
|
+
tabs.times do |i|
|
219
|
+
tab << TAB
|
220
|
+
end
|
221
|
+
comment = "#"
|
222
|
+
replacedString << "#{tab}#{comment} "
|
223
|
+
symbolsWithSpace = "\\.|\\:|\\!|\\?|\\;"
|
224
|
+
regxp = /([^#{symbolsWithSpace}])\n/
|
225
|
+
result = string
|
226
|
+
result.gsub!(/\n+/, "\n")
|
227
|
+
result.gsub!(/ \n/, "\n#{comment} ")
|
228
|
+
result.gsub!(/(#{symbolsWithSpace})\s*\n/, "\\1#{replacedString}")
|
229
|
+
result.gsub!(regxp, "\\1")
|
230
|
+
"#{tab}# #{result}"
|
231
|
+
end
|
232
|
+
|
233
|
+
private def generateClientModule(mod, modules)
|
234
|
+
content = "module TonClient\n\n#{TAB}class #{mod.name.capitalize}\n#{TAB}#{TAB}include CommonInstanceHelpers\n\n"
|
235
|
+
content << "#{TAB}#{TAB}attr_reader :core, :context\n"
|
236
|
+
content << "#{TAB}#{TAB}private_accessor "
|
237
|
+
modules.each_with_index do |m, i|
|
238
|
+
next if m.name.downcase == 'client'
|
239
|
+
content << ((modules.size - 1) == i ? ":_#{m.name}\n" : ":_#{m.name}, ")
|
240
|
+
end
|
241
|
+
content << "#{TAB}#{TAB}MODULE = self.to_s.downcase.gsub(/^(.+::|)(\\w+)$/, '\\2').freeze\n\n"
|
242
|
+
content << "#{TAB}#{TAB}def initialize(context: Context.new, core: TonClient::TonBinding)\n"
|
243
|
+
content << "#{TAB}#{TAB}#{TAB}@context = context\n"
|
244
|
+
content << "#{TAB}#{TAB}#{TAB}@core = core\n#{TAB}#{TAB}end\n\n"
|
245
|
+
content << "#{TAB}#{TAB}def destroy_context\n"
|
246
|
+
content << "#{TAB}#{TAB}#{TAB}core.tc_destroy_context(context.id)\n#{TAB}#{TAB}end\n\n"
|
247
|
+
modules.each_with_index do |m, i|
|
248
|
+
next if m.name.downcase == 'client'
|
249
|
+
content << "#{TAB}#{TAB}def #{m.name}\n"
|
250
|
+
content << "#{TAB}#{TAB}#{TAB}_#{m.name} ||= #{m.name.capitalize}.new(context: context)\n"
|
251
|
+
content << "#{TAB}#{TAB}end\n\n"
|
252
|
+
end
|
253
|
+
|
254
|
+
mod.functions.each do |func|
|
255
|
+
content << gen_function(func, types)
|
256
|
+
end
|
257
|
+
|
258
|
+
content << "#{TAB}end\n"
|
259
|
+
content << "end\n\n"
|
260
|
+
|
261
|
+
content
|
262
|
+
end
|
263
|
+
|
264
|
+
private def generateModule(mod)
|
265
|
+
content = "module TonClient\n\n#{TAB}class #{mod.name.capitalize}\n#{TAB}#{TAB}include CommonInstanceHelpers\n\n"
|
266
|
+
content << "#{TAB}#{TAB}attr_reader :core, :context\n"
|
267
|
+
content << "#{TAB}#{TAB}MODULE = self.to_s.downcase.gsub(/^(.+::|)(\\w+)$/, '\\2').freeze\n\n"
|
268
|
+
content << "#{TAB}#{TAB}def initialize(context: Context.new, core: TonClient::TonBinding)\n"
|
269
|
+
content << "#{TAB}#{TAB}#{TAB}@context = context\n"
|
270
|
+
content << "#{TAB}#{TAB}#{TAB}@core = core\n"
|
271
|
+
content << "#{TAB}#{TAB}end\n\n"
|
272
|
+
|
273
|
+
mod.functions.each do |func|
|
274
|
+
content << gen_function(func, types)
|
275
|
+
end
|
276
|
+
|
277
|
+
content << "#{TAB}end\n"
|
278
|
+
content << "end\n\n"
|
279
|
+
|
280
|
+
content
|
281
|
+
end
|
282
|
+
|
283
|
+
private def gen_function(function, types)
|
284
|
+
content = getFunctionComment(function, types)
|
285
|
+
content << "#{TAB}#{TAB}def #{function.name}"
|
286
|
+
if function.arguments.empty?
|
287
|
+
content << "(&block)\n"
|
288
|
+
content << "#{TAB}#{TAB}#{TAB}core.requestLibrary(context: context.id, method_name: full_method_name(MODULE, __method__.to_s), payload: {}, &block)\n"
|
289
|
+
else
|
290
|
+
content << "(payload, &block)\n"
|
291
|
+
content << "#{TAB}#{TAB}#{TAB}core.requestLibrary(context: context.id, method_name: full_method_name(MODULE, __method__.to_s), payload: payload, &block)\n"
|
292
|
+
end
|
293
|
+
content << "#{TAB}#{TAB}end\n\n"
|
294
|
+
|
295
|
+
content
|
296
|
+
end
|
297
|
+
|
298
|
+
def getFunctionComment(function, types)
|
299
|
+
content = ''
|
300
|
+
if argument = function.arguments.first
|
301
|
+
content << "#{TAB}#{TAB}# INPUT: #{argument.type}\n"
|
302
|
+
if types.all_types[argument.type].respond_to?(:fields)
|
303
|
+
types.all_types[argument.type].fields.each do |arg|
|
304
|
+
content << "#{TAB}#{TAB}# #{arg.name}: #{arg.type} - "
|
305
|
+
content << "#{TAB}#{TAB}# #{checkComment(arg.summary, 2)}" if arg.summary
|
306
|
+
content << "#{TAB}#{TAB}# #{checkComment(arg.description, 2)}" if arg.description
|
307
|
+
content << "\n"
|
308
|
+
end
|
309
|
+
elsif types.all_types[argument.type].respond_to?(:cases)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
if types.all_types[function.result]
|
314
|
+
content << "#{TAB}#{TAB}# RESPONSE: #{function.result}\n"
|
315
|
+
if types.all_types[function.result].respond_to?(:fields)
|
316
|
+
types.all_types[function.result].fields.each do |arg|
|
317
|
+
content << "#{TAB}#{TAB}# #{arg.name}: #{arg.type} - "
|
318
|
+
content << "#{TAB}#{TAB}# #{checkComment(arg.summary, 2)}" if arg.summary
|
319
|
+
content << "#{TAB}#{TAB}# #{checkComment(arg.description, 2)}" if arg.description
|
320
|
+
content << "\n"
|
321
|
+
end
|
322
|
+
elsif types.all_types[function.result].respond_to?(:cases)
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
content
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
|
331
|
+
|
332
|
+
|
333
|
+
|
334
|
+
|
335
|
+
|
336
|
+
|
337
|
+
|
338
|
+
|
339
|
+
|
@@ -0,0 +1,48 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
script_file_path = File.expand_path(File.dirname(__FILE__))
|
4
|
+
|
5
|
+
require "#{script_file_path}/api_converter.rb"
|
6
|
+
require "#{script_file_path}/code_generator.rb"
|
7
|
+
GEM_DIR = "#{script_file_path}/../.."
|
8
|
+
|
9
|
+
|
10
|
+
`cd #{script_file_path} && curl https://raw.githubusercontent.com/tonlabs/TON-SDK/master/tools/api.json > api.json`
|
11
|
+
api_json_path = "#{script_file_path}/../../api.json"
|
12
|
+
json = ''
|
13
|
+
if File.exists?(api_json_path)
|
14
|
+
json = File.read(api_json_path)
|
15
|
+
else
|
16
|
+
p "File #{api_json_path} is not exist"
|
17
|
+
exit 0
|
18
|
+
end
|
19
|
+
converter = ApiConverter.new(json)
|
20
|
+
types = converter.convert
|
21
|
+
generator = CodeGenerator.new(types, GEM_DIR)
|
22
|
+
generator.generate_self_code
|
23
|
+
|
24
|
+
version_file = "#{script_file_path}/../everscale-client-ruby/version.rb"
|
25
|
+
file = File.read(version_file)
|
26
|
+
|
27
|
+
p 'check version'
|
28
|
+
if file[/VERSION = "(\d+)\.(\d+)\.(\d+)"/]
|
29
|
+
major = $1
|
30
|
+
minor = $2
|
31
|
+
current = $3
|
32
|
+
version = "#{major}.#{minor}.#{current.to_i + 1}"
|
33
|
+
p version
|
34
|
+
data = "module TonClient\n VERSION = \"#{version}\"\nend\n\n"
|
35
|
+
p data
|
36
|
+
p version_file
|
37
|
+
File.open(version_file, 'wb') { |f| f.write(data) }
|
38
|
+
p 'update version'
|
39
|
+
|
40
|
+
puts "make release? Y/N"
|
41
|
+
option = gets
|
42
|
+
if option.strip.downcase == 'y'
|
43
|
+
system(%{cd #{GEM_DIR} && git add .})
|
44
|
+
system(%{cd #{GEM_DIR} && git commit -m 'version #{version}'})
|
45
|
+
system(%{cd #{GEM_DIR} && bash -lc 'rake release'})
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
@@ -0,0 +1,209 @@
|
|
1
|
+
module TonClient
|
2
|
+
module TonBinding
|
3
|
+
@@request_id = 0
|
4
|
+
@@requests = {}
|
5
|
+
|
6
|
+
class Response
|
7
|
+
attr_reader :core
|
8
|
+
attr_accessor :result, :error, :custom_response, :finished, :request_id, :current_response
|
9
|
+
|
10
|
+
def initialize(core: TonClient::TonBinding)
|
11
|
+
@core = core
|
12
|
+
end
|
13
|
+
|
14
|
+
def update(request_id, string_data, response_type, finished)
|
15
|
+
response_hash = core.read_string_to_hash(string_data)
|
16
|
+
self.finished = finished
|
17
|
+
self.request_id = request_id
|
18
|
+
self.current_response = response_hash
|
19
|
+
case response_type
|
20
|
+
when 0
|
21
|
+
# result
|
22
|
+
self.result = response_hash
|
23
|
+
when 1
|
24
|
+
# error
|
25
|
+
self.error = response_hash
|
26
|
+
else
|
27
|
+
# another
|
28
|
+
if response_type >= 100
|
29
|
+
self.custom_responses = response_hash
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.generate_request_id
|
36
|
+
@@request_id = 0 if @@request_id == 4294967295
|
37
|
+
@@request_id += 1
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.get_request(id)
|
41
|
+
@@requests[id]
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.delete_request(id)
|
45
|
+
@@requests[id] = nil
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.set_request(id, &request_block)
|
49
|
+
@@requests[id] = request_block
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
module TonClient
|
56
|
+
|
57
|
+
module TonBinding
|
58
|
+
extend FFI::Library
|
59
|
+
ffi_lib FFI::Library::LIBC
|
60
|
+
|
61
|
+
# memory allocators
|
62
|
+
attach_function :malloc, [:size_t], :pointer
|
63
|
+
attach_function :calloc, [:size_t], :pointer
|
64
|
+
attach_function :valloc, [:size_t], :pointer
|
65
|
+
attach_function :realloc, [:pointer, :size_t], :pointer
|
66
|
+
attach_function :free, [:pointer], :void
|
67
|
+
|
68
|
+
# memory movers
|
69
|
+
attach_function :memcpy, [:pointer, :pointer, :size_t], :pointer
|
70
|
+
attach_function :bcopy, [:pointer, :pointer, :size_t], :void
|
71
|
+
|
72
|
+
def self.setup_bindings
|
73
|
+
|
74
|
+
# tc_string_handle_t* tc_create_context(tc_string_data_t config);
|
75
|
+
# attach_function :tc_create_context, [TcStringDataT.by_value], TcStringHandleT.by_ref
|
76
|
+
attach_function :tc_create_context, [TcStringDataT.by_value], :pointer
|
77
|
+
|
78
|
+
# fn tc_destroy_context(context: InteropContext)
|
79
|
+
attach_function :tc_destroy_context, [:uint32], :void
|
80
|
+
|
81
|
+
# tc_string_handle_t* tc_request_sync(
|
82
|
+
# uint32_t context,
|
83
|
+
# tc_string_data_t function_name,
|
84
|
+
# tc_string_data_t function_params_json);
|
85
|
+
# attach_function :tc_request_sync, [:uint32, TcStringDataT.by_value, TcStringDataT.by_value], TcStringHandleT.by_ref
|
86
|
+
attach_function :tc_request_sync, [:uint32, TcStringDataT.by_value, TcStringDataT.by_value], :pointer
|
87
|
+
|
88
|
+
# enum tc_response_types_t {
|
89
|
+
# tc_response_success = 0,
|
90
|
+
# tc_response_error = 1,
|
91
|
+
# tc_response_nop = 2,
|
92
|
+
# tc_response_custom = 100,
|
93
|
+
# };
|
94
|
+
# typedef void (*tc_response_handler_t)(
|
95
|
+
# uint32_t request_id,
|
96
|
+
# tc_string_data_t params_json,
|
97
|
+
# uint32_t response_type,
|
98
|
+
# bool finished);
|
99
|
+
callback :tc_response_handler_t, [:uint32, TcStringDataT.by_value, :uint32, :bool], :void
|
100
|
+
|
101
|
+
# void tc_request(
|
102
|
+
# uint32_t context,
|
103
|
+
# tc_string_data_t function_name,
|
104
|
+
# tc_string_data_t function_params_json,
|
105
|
+
# uint32_t request_id,
|
106
|
+
# tc_response_handler_t response_handler);
|
107
|
+
attach_function :tc_request, [:uint32, TcStringDataT.by_value, TcStringDataT.by_value, :uint32, :tc_response_handler_t], :void
|
108
|
+
|
109
|
+
# tc_string_data_t tc_read_string(const tc_string_handle_t* handle);
|
110
|
+
# attach_function :tc_read_string, [TcStringHandleT.by_ref], TcStringDataT.by_value
|
111
|
+
attach_function :tc_read_string, [:pointer], TcStringDataT.by_value
|
112
|
+
|
113
|
+
# void tc_destroy_string(const tc_string_handle_t* handle)
|
114
|
+
# attach_function :tc_destroy_string, [TcStringHandleT.by_ref], :void
|
115
|
+
attach_function :tc_destroy_string, [:pointer], :void
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.make_string(string)
|
119
|
+
result = TonBinding::TcStringDataT.new
|
120
|
+
result[:content] = FFI::MemoryPointer.from_string(string)
|
121
|
+
result[:len] = string.bytesize
|
122
|
+
result
|
123
|
+
end
|
124
|
+
|
125
|
+
# def self.read_string(tc_string_handle)
|
126
|
+
# is_ref = tc_string_handle.class == TonClient::TonBinding::TcStringHandleT
|
127
|
+
# if is_ref
|
128
|
+
# string = tc_read_string(tc_string_handle)
|
129
|
+
# else
|
130
|
+
# string = tc_string_handle
|
131
|
+
# end
|
132
|
+
|
133
|
+
# if string[:content].address > 1
|
134
|
+
# string = string[:content].read_string(string[:len]).force_encoding('UTF-8') + ''
|
135
|
+
# tc_destroy_string(tc_string_handle) if is_ref
|
136
|
+
# return string
|
137
|
+
# end
|
138
|
+
# nil
|
139
|
+
# end
|
140
|
+
|
141
|
+
def self.read_string(tc_string_handle)
|
142
|
+
is_ref = tc_string_handle.class == FFI::Pointer
|
143
|
+
if is_ref
|
144
|
+
string = tc_read_string(tc_string_handle)
|
145
|
+
else
|
146
|
+
string = tc_string_handle
|
147
|
+
end
|
148
|
+
|
149
|
+
if string[:content].address > 1
|
150
|
+
string = string[:content].read_string(string[:len]).force_encoding('UTF-8') + ''
|
151
|
+
tc_destroy_string(tc_string_handle) if is_ref
|
152
|
+
return string
|
153
|
+
end
|
154
|
+
nil
|
155
|
+
end
|
156
|
+
|
157
|
+
def self.read_string_to_hash(tc_string_handle_t_ref)
|
158
|
+
json_string = read_string(tc_string_handle_t_ref)
|
159
|
+
JSON.parse(json_string, {max_nesting: false}) if json_string
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.send_request_sync(context: 1, method_name: '', payload: {})
|
163
|
+
raise 'context not found' unless context
|
164
|
+
raise 'method_name is empty' if method_name.empty?
|
165
|
+
|
166
|
+
method_name_string = make_string(method_name)
|
167
|
+
payload_string = make_string(payload.to_json)
|
168
|
+
|
169
|
+
sdk_json_response = tc_request_sync(context, method_name_string, payload_string)
|
170
|
+
response = read_string_to_hash(sdk_json_response)
|
171
|
+
|
172
|
+
return response['result'] if response['result']
|
173
|
+
return response['error'] if response['error']
|
174
|
+
end
|
175
|
+
|
176
|
+
def self.send_request(context: 1, method_name: '', payload: {}, request_id: 1, &block)
|
177
|
+
raise 'context not found' unless context
|
178
|
+
raise 'method_name is empty' if method_name.empty?
|
179
|
+
|
180
|
+
if block
|
181
|
+
method_name_string = make_string(method_name)
|
182
|
+
payload_string = make_string(payload.to_json)
|
183
|
+
tc_request(context, method_name_string, payload_string, request_id, &block)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# block = { |response| }
|
188
|
+
def self.requestLibrary(context: 1, method_name: '', payload: {}, &block)
|
189
|
+
request_id = generate_request_id
|
190
|
+
set_request(request_id, &block)
|
191
|
+
send_request(context: context, method_name: method_name, payload: payload, request_id: request_id) do |request_id, string_data, response_type, finished|
|
192
|
+
if get_request(request_id)
|
193
|
+
response = Response.new
|
194
|
+
response.update(request_id, string_data, response_type, finished)
|
195
|
+
get_request(request_id).call(response)
|
196
|
+
delete_request(request_id) if finished
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
|
205
|
+
|
206
|
+
|
207
|
+
|
208
|
+
|
209
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module TonClient
|
2
|
+
module TonBinding
|
3
|
+
|
4
|
+
# typedef struct {
|
5
|
+
# const char* content;
|
6
|
+
# uint32_t len;
|
7
|
+
# } tc_string_data_t;
|
8
|
+
class TcStringDataT < FFI::Struct
|
9
|
+
layout :content, :pointer,
|
10
|
+
:len, :uint32
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
# typedef struct {
|
15
|
+
# } tc_string_handle_t;
|
16
|
+
class TcStringHandleT < FFI::Struct
|
17
|
+
layout :content, :pointer,
|
18
|
+
:len, :uint32
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|