Class: BinaryCodec::STObject

Inherits:
SerializedType show all
Defined in:
lib/binary-codec/types/st_object.rb

Constant Summary collapse

OBJECT_END_MARKER_BYTE =
[225]
OBJECT_END_MARKER =
'ObjectEndMarker'.freeze
ST_OBJECT =
'STObject'.freeze
DESTINATION =
'Destination'.freeze
ACCOUNT =
'Account'.freeze
SOURCE_TAG =
'SourceTag'.freeze
DEST_TAG =
'DestinationTag'.freeze

Instance Attribute Summary

Attributes inherited from SerializedType

#bytes

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from SerializedType

from_bytes, from_hex, from_json, get_type_by_name, #to_byte_sink, #to_bytes, #to_hex, #value_of

Constructor Details

#initialize(byte_buf = nil) ⇒ STObject

attr_reader :type, :bytes



16
17
18
# File 'lib/binary-codec/types/st_object.rb', line 16

def initialize(byte_buf = nil)
  @bytes = byte_buf || Array.new(0)
end

Class Method Details

.check_for_duplicate_tags(obj1, obj2) ⇒ Object



145
146
147
148
149
150
151
152
153
# File 'lib/binary-codec/types/st_object.rb', line 145

def self.check_for_duplicate_tags(obj1, obj2)
  if obj1['SourceTag'] && obj2['SourceTag']
    raise 'Cannot have Account X-Address and SourceTag'
  end

  if obj1['DestinationTag'] && obj2['DestinationTag']
    raise 'Cannot have Destination X-Address and DestinationTag'
  end
end

.from(value, filter = nil, definitions = nil) ⇒ STObject

Creates a new STObject instance from a value.

Parameters:

  • value (STObject, String, Array<Integer>, Hash)

    The value to convert.

  • filter (Proc, nil) (defaults to: nil)

    Optional filter for fields.

  • definitions (Definitions, nil) (defaults to: nil)

    Optional definitions.

Returns:



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/binary-codec/types/st_object.rb', line 25

def self.from(value, filter = nil, definitions = nil)
  return value if value.is_a?(STObject)
  definitions ||= Definitions.instance

  if value.is_a?(String)
    return STObject.new(hex_to_bytes(value))
  end

  if value.is_a?(Array)
    return STObject.new(value)
  end

  list = BytesList.new
  serializer = BinarySerializer.new(list)
  is_unl_modify = false

  # Handle X-Addresses and check for duplicate tags
  processed_value = value.each_with_object({}) do |(key, val), acc|
    if val && val.is_a?(String) && AddressCodec::AddressCodec.new.valid_x_address?(val)
      handled = handle_x_address(key.to_s, val)
      check_for_duplicate_tags(handled, value)
      acc.merge!(handled)
    else
      acc[key.to_s] = val
    end
  end

  sorted_fields = processed_value.keys.map do |field_name|
    field = definitions.get_field_instance(field_name)
    raise "Field #{field_name} is not defined" if field.nil?
    field
  end.select(&:is_serialized).sort_by(&:ordinal)

  if filter
    sorted_fields = sorted_fields.select { |f| filter.call(f.name) }
  end

  sorted_fields.each do |field|
    associated_value = processed_value[field.name]
    next if associated_value.nil?

    # Special handling for UNLModify
    if field.name == 'UNLModify' # This might need more specific check depending on value
       is_unl_modify = true
    end
    is_unl_modify_workaround = (field.name == 'Account' && is_unl_modify)

    serializer.write_field_and_value(field, associated_value, is_unl_modify_workaround)

    if field.type == 'STObject'
      serializer.put(OBJECT_END_MARKER_BYTE)
    end
  end

  STObject.new(list.to_bytes)
end

.from_parser(parser, size_hint = nil) ⇒ STObject

Construct a STObject from a BinaryParser

Parameters:

  • parser (BinaryParser)

    BinaryParser to read STObject from

  • size_hint (Integer) (defaults to: nil)

    Optional size hint for the object

Returns:



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/binary-codec/types/st_object.rb', line 87

def self.from_parser(parser, size_hint = nil)
  list = BytesList.new
  bytes = BinarySerializer.new(list)

  until parser.end?
    field = parser.read_field

    break if field.name == OBJECT_END_MARKER

    associated_value = parser.read_field_value(field)

    bytes.write_field_and_value(field, associated_value)
    bytes.put(OBJECT_END_MARKER_BYTE) if field.type == ST_OBJECT
  end

  STObject.new(list.to_bytes)
end

Instance Method Details

#to_json(_definitions = nil, _field_name = nil) ⇒ String

Method to get the JSON interpretation of self.bytes

Returns:

  • (String)

    A stringified JSON object



108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/binary-codec/types/st_object.rb', line 108

def to_json(_definitions = nil, _field_name = nil)
  parser = BinaryParser.new(to_hex)
  accumulator = {}

  until parser.end?
    field = parser.read_field
    break if field.name == OBJECT_END_MARKER # Break if the object end marker is reached
    value = parser.read_field_value(field).to_json
    value = JSON.parse(value) if field.type == ST_OBJECT || field.type == Amount
    accumulator[field.name] = value
  end

  JSON.generate(accumulator)
end