ton_sdk_client 1.7.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.
@@ -0,0 +1,20 @@
1
+ module TonSdk
2
+ class Helper
3
+
4
+ # converts a symbol which may contain _, into a capital-case string
5
+ # :aaa_bbb_ccc -> AaaBbbCcc
6
+ def self.sym_to_capitalized_case_str(symb)
7
+ symb.to_s.split('_').map(&:capitalize).join
8
+ end
9
+
10
+
11
+ # converts a capital-case string
12
+ # into a symbol
13
+ # AaaBbbCcc --> :aaa_bbb_ccc
14
+ def self.capitalized_case_str_to_snake_case_sym(str)
15
+ str.split(/(?=[A-Z])/).map(&:downcase).join("_").to_sym
16
+ end
17
+
18
+ def self.base64_from_hex(hex_digest) = [[hex_digest].pack("H*")].pack("m0")
19
+ end
20
+ end
@@ -0,0 +1,230 @@
1
+ require 'ffi'
2
+ require 'rbconfig'
3
+ require 'concurrent'
4
+ require 'logger'
5
+
6
+ module TonSdk
7
+ module Interop
8
+ extend FFI::Library
9
+
10
+ class << self
11
+ attr_reader :logger
12
+ end
13
+
14
+ @logger = Logger.new(STDOUT)
15
+
16
+ class TcStringData < FFI::Struct
17
+ layout :content, :pointer,
18
+ :len, :uint32
19
+
20
+ def self.from_string(s)
21
+ tcs = TcStringData.new
22
+ bytes_count = s.unpack("C*").size
23
+ ptr1 = FFI::MemoryPointer.new(:char, bytes_count)
24
+ ptr1.put_bytes(0, s, 0, bytes_count)
25
+ tcs[:content] = ptr1
26
+ tcs[:len] = ptr1.size
27
+ tcs
28
+ end
29
+ end
30
+
31
+ class TcResponse < FFI::Struct
32
+ layout :result_json, TcStringData,
33
+ :error_json, TcStringData
34
+ end
35
+
36
+ DEFAULT_LIB_NAME = 'tonclient'
37
+ base_lib_name2 = case RbConfig::CONFIG['host_os']
38
+ when /linux/
39
+ 'linux'
40
+ when /darwin/
41
+ 'darwin'
42
+ when /mswin|mingw32|windows/
43
+ 'win32'
44
+ else
45
+ raise "unsupported OS: #{RbConfig::CONFIG['host_os']}"
46
+ end
47
+
48
+ lib_full_name = if !ENV['TON_CLIENT_NATIVE_LIB_NAME'].nil?
49
+ ENV['TON_CLIENT_NATIVE_LIB_NAME']
50
+ else
51
+ fl_nm = "#{DEFAULT_LIB_NAME}.#{FFI::Platform::LIBSUFFIX}"
52
+ File.join(File.expand_path(File.dirname(File.dirname(__dir__))), fl_nm)
53
+ end
54
+
55
+ ffi_lib(lib_full_name)
56
+
57
+
58
+
59
+
60
+ #
61
+ # in C
62
+ #
63
+ # enum tc_response_types_t {
64
+ # tc_response_success = 0,
65
+ # tc_response_error = 1,
66
+ # tc_response_nop = 2,
67
+ # tc_response_custom = 100,
68
+ # };
69
+ module TcResponseCodes
70
+ SUCCESS = 0
71
+ ERROR = 1
72
+ NOP = 2
73
+ APP_REQUEST = 3
74
+ APP_NOTIFY = 4
75
+ CUSTOM = 100
76
+ MAX = 999
77
+ end
78
+
79
+
80
+ #
81
+ # in C
82
+ #
83
+ # tc_string_handle_t* tc_create_context(tc_string_data_t config);
84
+ # void tc_destroy_context(uint32_t context);
85
+
86
+ attach_function(:tc_create_context, [TcStringData.by_value], :pointer)
87
+ attach_function(:tc_destroy_context, [:uint32], :void)
88
+
89
+
90
+ #
91
+ # in C
92
+ #
93
+ # tc_string_data_t tc_read_string(const tc_string_handle_t* string);
94
+ # void tc_destroy_string(const tc_string_handle_t* string);
95
+
96
+ attach_function(:tc_read_string, [:pointer], TcStringData.by_value)
97
+ attach_function(:tc_destroy_string, [:pointer], :void)
98
+
99
+
100
+ #
101
+ # in C
102
+ #
103
+ # void tc_request(
104
+ # uint32_t context,
105
+ # tc_string_data_t function_name,
106
+ # tc_string_data_t function_params_json,
107
+ # uint32_t request_id,
108
+ # tc_response_handler_t response_handler);
109
+
110
+ # typedef void (*tc_response_handler_t)(
111
+ # uint32_t request_id,
112
+ # tc_string_data_t params_json,
113
+ # uint32_t response_type,
114
+ # bool finished);
115
+
116
+ callback(:tc_response_handler, [:uint32, TcStringData.by_value, :uint32, :bool], :void)
117
+ attach_function(:tc_request, [:uint32, TcStringData.by_value, TcStringData.by_value, :uint32, :tc_response_handler], :void) # TODO possibly blocking: true
118
+
119
+ #
120
+ # in C
121
+ #
122
+ # tc_string_handle_t* tc_request_sync(
123
+ # uint32_t context,
124
+ # tc_string_data_t function_name,
125
+ # tc_string_data_t function_params_json);
126
+ attach_function(:tc_request_sync, [:uint32, TcStringData.by_value, TcStringData.by_value], :pointer)
127
+
128
+
129
+
130
+ @@request_counter = Concurrent::AtomicFixnum.new(1)
131
+
132
+ def self.request_to_native_lib(
133
+ ctx,
134
+ function_name,
135
+ function_params_json = nil,
136
+ client_callback: nil,
137
+ is_single_thread_only: trfue
138
+ )
139
+ function_name_tc_str = TcStringData.from_string(function_name)
140
+ function_params_json_str = function_params_json || ""
141
+ function_params_json_tc_str = TcStringData.from_string(function_params_json_str)
142
+
143
+ @sm = Concurrent::Semaphore.new(1)
144
+ if is_single_thread_only == true
145
+ @sm.acquire()
146
+ end
147
+
148
+
149
+ # using @@request_counter here to pass a @@request_counter and handlers and then retrieve them
150
+ # is probably isn't needed.
151
+ # Thanks to the way Ruby is, the same affect can be achived by a block which is an easier way.
152
+ # Nonetheless, @@request_counter is incremented with each request and then sent out to a server
153
+ # in order to keep a server happy,
154
+ # because otherwise a server will, probably, reply in a wrong way.
155
+
156
+ self.tc_request(
157
+ ctx,
158
+ function_name_tc_str,
159
+ function_params_json_tc_str,
160
+ @@request_counter.value
161
+ ) do |req_id, params_json, response_type, is_finished|
162
+
163
+ tc_data_json_content = if params_json[:len] > 0
164
+ res = params_json[:content].read_string(params_json[:len])
165
+ JSON.parse(res)
166
+ else
167
+ ''
168
+ end
169
+
170
+ begin
171
+ case response_type
172
+
173
+ when TcResponseCodes::SUCCESS
174
+ if block_given?
175
+ yield NativeLibResponsetResult.new(result: tc_data_json_content)
176
+ end
177
+
178
+ when TcResponseCodes::ERROR
179
+ if block_given?
180
+ yield NativeLibResponsetResult.new(error: tc_data_json_content)
181
+ end
182
+
183
+ when TcResponseCodes::NOP
184
+ nil
185
+
186
+ when TcResponseCodes::APP_REQUEST
187
+ if !client_callback.nil?
188
+ client_callback.call(:request, tc_data_json_content)
189
+ end
190
+
191
+ when TcResponseCodes::APP_NOTIFY
192
+ if !client_callback.nil?
193
+ client_callback.call(:notify, tc_data_json_content)
194
+ end
195
+
196
+ when TcResponseCodes::CUSTOM..TcResponseCodes::MAX
197
+ if !client_callback.nil?
198
+ client_callback.call(:custom, tc_data_json_content)
199
+ end
200
+
201
+ else
202
+ raise ArgumentError.new("unsupported response type: #{response_type}")
203
+ end
204
+
205
+ rescue => e
206
+ @logger.error(e)
207
+ ensure
208
+ if is_single_thread_only == true
209
+ @sm.release()
210
+ end
211
+ end
212
+ end
213
+
214
+
215
+
216
+ if is_single_thread_only == true
217
+ @sm.acquire()
218
+ end
219
+
220
+ @@request_counter.increment()
221
+ nil
222
+ end
223
+
224
+ def self.request_to_native_lib_sync(ctx, function_name, function_params_json)
225
+ function_name_tc_str = TcStringData.from_string(function_name)
226
+ function_params_json_tc_str = TcStringData.from_string(function_params_json)
227
+ self.tc_request_sync(ctx, function_name_tc_str, function_params_json_tc_str)
228
+ end
229
+ end
230
+ end
@@ -0,0 +1,452 @@
1
+ module TonSdk
2
+ module Net
3
+
4
+ #
5
+ # types
6
+ #
7
+
8
+ module ErrorCode
9
+ QUERY_FAILED = 601
10
+ SUBSCRIBE_FAILED = 602
11
+ WAIT_FOR_FAILED = 603
12
+ GET_SUBSCRIPTION_FAILED = 604
13
+ INVALID_SERVER_RESPONSE = 605
14
+ CLOCK_OUT_OF_SYNC = 606
15
+ WAIT_FOR_TIMEOUT = 607
16
+ GRAPHQL_ERROR = 608
17
+ NETWORK_MODULE_SUSPENDED = 609
18
+ WEBSOCKET_DISCONNECTED = 610
19
+ NOT_SUPPORTED = 611
20
+ NO_ENDPOINTS_PROVIDED = 612
21
+ GRAPHQL_WEBSOCKET_INIT_ERROR = 613,
22
+ NETWORK_MODULE_RESUMED = 614
23
+ end
24
+
25
+ class OrderBy
26
+ SORT_DIRECTION_VALUES = [:asc, :desc]
27
+
28
+ attr_reader :path, :direction
29
+
30
+ def initialize(path:, direction:)
31
+ @path = path
32
+ unless SORT_DIRECTION_VALUES.include?(direction)
33
+ raise ArgumentError.new("direction #{direction} doesn't exist; existing values: #{SORT_DIRECTION_VALUES}")
34
+ end
35
+
36
+ @direction = direction
37
+ end
38
+ end
39
+
40
+ class ParamsOfQueryCollection
41
+ attr_reader :collection, :filter, :result, :order, :limit
42
+
43
+ def initialize(collection: , filter: nil, result: , order: [], limit: nil)
44
+ @collection = collection
45
+ @filter = filter
46
+ @result = result
47
+ @order = order
48
+ @limit = limit
49
+ end
50
+
51
+ def to_h
52
+ ord_h_s = if !@order.nil?
53
+ @order.map do |x|
54
+ {
55
+ path: x.path,
56
+ direction: x.direction.to_s.upcase
57
+ }
58
+ end
59
+ end
60
+
61
+ {
62
+ collection: @collection,
63
+ filter: @filter,
64
+ result: @result,
65
+ order: ord_h_s,
66
+ limit: @limit
67
+ }
68
+ end
69
+ end
70
+
71
+ class ResultOfQueryCollection
72
+ attr_reader :result
73
+
74
+ def initialize(a)
75
+ @result = a
76
+ end
77
+ end
78
+
79
+ class ParamsOfWaitForCollection
80
+ attr_reader :collection, :filter, :result, :timeout
81
+
82
+ def initialize(collection:, filter: nil, result:, timeout: nil)
83
+ @collection = collection
84
+ @filter = filter
85
+ @result = result
86
+ @timeout = timeout
87
+ end
88
+
89
+ def to_h
90
+ {
91
+ collection: @collection,
92
+ filter: @filter,
93
+ result: @result,
94
+ timeout: @timeout
95
+ }
96
+ end
97
+ end
98
+
99
+ class ResultOfWaitForCollection
100
+ attr_reader :result
101
+
102
+ def initialize(a)
103
+ @result = a
104
+ end
105
+ end
106
+
107
+ class ParamsOfSubscribeCollection
108
+ attr_reader :collection, :filter, :result
109
+
110
+ def initialize(collection:, filter: nil, result:)
111
+ @collection = collection
112
+ @filter = filter
113
+ @result = result
114
+ end
115
+
116
+ def to_h
117
+ {
118
+ collection: @collection,
119
+ filter: @filter,
120
+ result: @result
121
+ }
122
+ end
123
+ end
124
+
125
+ class ResultOfSubscribeCollection
126
+ attr_reader :handle
127
+
128
+ def initialize(a)
129
+ @handle = a
130
+ end
131
+
132
+ def to_h = { handle: @handle }
133
+ end
134
+
135
+ class ParamsOfQuery
136
+ attr_reader :query, :variables
137
+
138
+ def initialize(query:, variables: nil)
139
+ @query = query
140
+ @variables = variables
141
+ end
142
+
143
+ def to_h
144
+ {
145
+ query: @query,
146
+ variables: @variables
147
+ }
148
+ end
149
+ end
150
+
151
+ class ResultOfQuery
152
+ attr_reader :result
153
+
154
+ def initialize(a)
155
+ @result = a
156
+ end
157
+ end
158
+
159
+ class ParamsOfFindLastShardBlock
160
+ attr_reader :address
161
+
162
+ def initialize(a)
163
+ @address = a
164
+ end
165
+
166
+ def to_h = { address: @address }
167
+ end
168
+
169
+ class ResultOfFindLastShardBlock
170
+ attr_reader :block_id
171
+
172
+ def initialize(a)
173
+ @block_id = a
174
+ end
175
+ end
176
+
177
+ class EndpointsSet
178
+ attr_reader :endpoints
179
+
180
+ def initialize(a)
181
+ @endpoints = a
182
+ end
183
+
184
+ def to_h = { endpoints: @endpoints }
185
+ end
186
+
187
+ class ParamsOfQueryOperation
188
+ attr_reader :type_, :params
189
+
190
+ def new_with_type_query_collection(params)
191
+ @type_ = :query_collection
192
+ @params = params
193
+ end
194
+
195
+ def new_with_type_wait_for_collection(params)
196
+ @type_ = :wait_for_collection
197
+ @params = params
198
+ end
199
+
200
+ def new_with_type_aggregate_collection(params)
201
+ @type_ = :aggregate_collection
202
+ @params = params
203
+ end
204
+
205
+ def to_h
206
+ tp = {
207
+ type: Helper.sym_to_capitalized_case_str(@type_)
208
+ }
209
+
210
+ param_keys = @params.to_h
211
+ tp.merge(param_keys)
212
+ end
213
+ end
214
+
215
+ class ParamsOfBatchQuery
216
+ attr_reader :operations
217
+
218
+ def initialize(a)
219
+ @operations = a
220
+ end
221
+
222
+ def to_h = { operations: @operations.compact.map(&:to_h) }
223
+ end
224
+
225
+ class ResultOfBatchQuery
226
+ attr_reader :results
227
+
228
+ def initialize(a)
229
+ @results = a
230
+ end
231
+
232
+ def to_h = { results: @results }
233
+ end
234
+
235
+ class ParamsOfAggregateCollection
236
+ attr_reader :collection, :filter, :fields
237
+
238
+ def initialize(collection:, filter: nil, fields: [])
239
+ @collection = collection
240
+ @filter = filter
241
+ @fields = fields
242
+ end
243
+
244
+ def to_h
245
+ {
246
+ collection: @collection,
247
+ filter: @filter,
248
+ fields: @fields.map(&:to_h)
249
+ }
250
+ end
251
+ end
252
+
253
+ class FieldAggregation
254
+ AGGREGATION_FN_VALUES = [
255
+ :count,
256
+ :min,
257
+ :max,
258
+ :sum,
259
+ :average
260
+ ]
261
+
262
+ attr_reader :field, :fn
263
+
264
+ def initialize(field:, fn:)
265
+ unless AGGREGATION_FN_VALUES.include?(fn)
266
+ raise ArgumentError.new("aggregate function #{fn} doesn't exist; existing values: #{AGGREGATION_FN_VALUES}")
267
+ end
268
+ @field = field
269
+ @fn = fn
270
+ end
271
+
272
+ def to_h
273
+ {
274
+ field: @field,
275
+ fn: @fn.to_s.upcase
276
+ }
277
+ end
278
+ end
279
+
280
+ class ResultOfAggregateCollection
281
+ attr_reader :values
282
+
283
+ def initialize(a)
284
+ @values = a
285
+ end
286
+
287
+ def to_h = { values: @values }
288
+ end
289
+
290
+
291
+
292
+ #
293
+ # functions
294
+ #
295
+
296
+ def self.query_collection(ctx, params)
297
+ Interop::request_to_native_lib(
298
+ ctx,
299
+ "net.query_collection",
300
+ params.to_h.to_json,
301
+ is_single_thread_only: false
302
+ ) do |resp|
303
+ if resp.success?
304
+ yield NativeLibResponsetResult.new(
305
+ result: ResultOfQueryCollection.new(resp.result["result"])
306
+ )
307
+ else
308
+ yield resp
309
+ end
310
+ end
311
+ end
312
+
313
+ def self.wait_for_collection(ctx, params)
314
+ Interop::request_to_native_lib(
315
+ ctx,
316
+ "net.wait_for_collection",
317
+ params.to_h.to_json,
318
+ is_single_thread_only: false
319
+ ) do |resp|
320
+ if resp.success?
321
+ yield NativeLibResponsetResult.new(
322
+ result: ResultOfWaitForCollection.new(resp.result["result"])
323
+ )
324
+ else
325
+ yield resp
326
+ end
327
+ end
328
+ end
329
+
330
+ def self.unsubscribe(ctx, params)
331
+ Interop::request_to_native_lib(ctx, "net.unsubscribe", params.to_h.to_json) do |resp|
332
+ if resp.success?
333
+ yield NativeLibResponsetResult.new(
334
+ result: ""
335
+ )
336
+ else
337
+ yield resp
338
+ end
339
+ end
340
+ end
341
+
342
+ def self.subscribe_collection(ctx, params, client_callback: nil)
343
+ Interop::request_to_native_lib(
344
+ ctx,
345
+ "net.subscribe_collection",
346
+ params.to_h.to_json,
347
+ client_callback: client_callback,
348
+ is_single_thread_only: false
349
+ ) do |resp|
350
+ if resp.success?
351
+ yield NativeLibResponsetResult.new(
352
+ result: ResultOfSubscribeCollection.new(resp.result["handle"])
353
+ )
354
+ else
355
+ yield resp
356
+ end
357
+ end
358
+ end
359
+
360
+ def self.query(ctx, params)
361
+ Interop::request_to_native_lib(ctx, "net.query", params.to_h.to_json) do |resp|
362
+ if resp.success?
363
+ yield NativeLibResponsetResult.new(
364
+ result: ResultOfQuery.new(resp.result["result"])
365
+ )
366
+ else
367
+ yield resp
368
+ end
369
+ end
370
+ end
371
+
372
+ def self.suspend(ctx)
373
+ Interop::request_to_native_lib(ctx, "net.suspend", "") do |resp|
374
+ if resp.success?
375
+ yield NativeLibResponsetResult.new(result: "")
376
+ else
377
+ yield resp
378
+ end
379
+ end
380
+ end
381
+
382
+ def self.resume(ctx)
383
+ Interop::request_to_native_lib(ctx, "net.resume", "") do |resp|
384
+ if resp.success?
385
+ yield NativeLibResponsetResult.new(result: "")
386
+ else
387
+ yield resp
388
+ end
389
+ end
390
+ end
391
+
392
+ def self.find_last_shard_block(ctx, params)
393
+ Interop::request_to_native_lib(ctx, "net.find_last_shard_block", params.to_h.to_json) do |resp|
394
+ if resp.success?
395
+ yield NativeLibResponsetResult.new(
396
+ result: ResultOfFindLastShardBlock.new(resp.result["block_id"])
397
+ )
398
+ else
399
+ yield resp
400
+ end
401
+ end
402
+ end
403
+
404
+ def self.fetch_endpoints(ctx)
405
+ Interop::request_to_native_lib(ctx, "net.fetch_endpoints", nil) do |resp|
406
+ if resp.success?
407
+ yield NativeLibResponsetResult.new(
408
+ result: EndpointsSet.new(resp.result["endpoints"])
409
+ )
410
+ else
411
+ yield resp
412
+ end
413
+ end
414
+ end
415
+
416
+ def self.set_endpoints(ctx, params)
417
+ Interop::request_to_native_lib(ctx, "net.set_endpoints", params.to_h.to_json) do |resp|
418
+ if resp.success?
419
+ yield NativeLibResponsetResult.new(
420
+ result: nil
421
+ )
422
+ else
423
+ yield resp
424
+ end
425
+ end
426
+ end
427
+ end
428
+
429
+ def self.batch_query(ctx, params)
430
+ Interop::request_to_native_lib(ctx, "net.batch_query", params.to_h.to_json) do |resp|
431
+ if resp.success?
432
+ yield NativeLibResponsetResult.new(
433
+ result: ResultOfBatchQuery.new(resp.result["results"])
434
+ )
435
+ else
436
+ yield resp
437
+ end
438
+ end
439
+ end
440
+
441
+ def self.aggregate_collection(ctx, params)
442
+ Interop::request_to_native_lib(ctx, "net.aggregate_collection", params.to_h.to_json) do |resp|
443
+ if resp.success?
444
+ yield NativeLibResponsetResult.new(
445
+ result: ResultOfAggregateCollection.new(resp.result["values"])
446
+ )
447
+ else
448
+ yield resp
449
+ end
450
+ end
451
+ end
452
+ end