nem-ruby 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.
Files changed (136) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +119 -0
  5. data/.travis.yml +23 -0
  6. data/CODE_OF_CONDUCT.md +74 -0
  7. data/Gemfile +6 -0
  8. data/README.md +81 -0
  9. data/Rakefile +6 -0
  10. data/examples/apostille_audit.rb +22 -0
  11. data/examples/apostille_create.rb +31 -0
  12. data/examples/endpoint/account.rb +73 -0
  13. data/examples/endpoint/account_local.rb +21 -0
  14. data/examples/endpoint/block.rb +14 -0
  15. data/examples/endpoint/chain.rb +15 -0
  16. data/examples/endpoint/debug.rb +17 -0
  17. data/examples/endpoint/local.rb +17 -0
  18. data/examples/endpoint/mosaic.rb +9 -0
  19. data/examples/endpoint/namespace.rb +13 -0
  20. data/examples/endpoint/node.rb +24 -0
  21. data/examples/endpoint/timesync.rb +9 -0
  22. data/examples/endpoint/transaction.rb +42 -0
  23. data/examples/localnode.rb +0 -0
  24. data/examples/nis.rb +34 -0
  25. data/examples/node_pool.rb +23 -0
  26. data/examples/transaction/importance_transfer.rb +23 -0
  27. data/examples/transaction/mosaic_definition_creation.rb +52 -0
  28. data/examples/transaction/mosaic_supply_change.rb +25 -0
  29. data/examples/transaction/multisig_add_cosignatory.rb +31 -0
  30. data/examples/transaction/multisig_aggregate_modification.rb +29 -0
  31. data/examples/transaction/multisig_signature.rb +41 -0
  32. data/examples/transaction/multisig_transfer.rb +35 -0
  33. data/examples/transaction/provision_namespace.rb +20 -0
  34. data/examples/transaction/transfer.rb +32 -0
  35. data/examples/transaction/transfer_mosaic.rb +72 -0
  36. data/examples/transaction/transfer_with_encrypted_message.rb +40 -0
  37. data/examples/transaction/transfer_with_local.rb +34 -0
  38. data/lib/nem.rb +21 -0
  39. data/lib/nem/apostille.rb +104 -0
  40. data/lib/nem/apostille_audit.rb +47 -0
  41. data/lib/nem/client.rb +170 -0
  42. data/lib/nem/configuration.rb +29 -0
  43. data/lib/nem/endpoint.rb +4 -0
  44. data/lib/nem/endpoint/account.rb +264 -0
  45. data/lib/nem/endpoint/base.rb +45 -0
  46. data/lib/nem/endpoint/block.rb +15 -0
  47. data/lib/nem/endpoint/chain.rb +17 -0
  48. data/lib/nem/endpoint/debug.rb +54 -0
  49. data/lib/nem/endpoint/local/account.rb +54 -0
  50. data/lib/nem/endpoint/local/chain.rb +15 -0
  51. data/lib/nem/endpoint/mosaic.rb +13 -0
  52. data/lib/nem/endpoint/namespace.rb +37 -0
  53. data/lib/nem/endpoint/node.rb +83 -0
  54. data/lib/nem/endpoint/timesync.rb +9 -0
  55. data/lib/nem/endpoint/transaction.rb +34 -0
  56. data/lib/nem/error.rb +6 -0
  57. data/lib/nem/fee.rb +2 -0
  58. data/lib/nem/fee/importance_transfer.rb +24 -0
  59. data/lib/nem/fee/mosaic_definition_creation.rb +24 -0
  60. data/lib/nem/fee/mosaic_supply_change_transfer.rb +24 -0
  61. data/lib/nem/fee/multisig.rb +24 -0
  62. data/lib/nem/fee/multisig_aggregation_modification.rb +28 -0
  63. data/lib/nem/fee/provision_namespace.rb +34 -0
  64. data/lib/nem/fee/transfer.rb +66 -0
  65. data/lib/nem/keypair.rb +44 -0
  66. data/lib/nem/mixin.rb +2 -0
  67. data/lib/nem/mixin/assignable.rb +12 -0
  68. data/lib/nem/model.rb +3 -0
  69. data/lib/nem/model/account.rb +67 -0
  70. data/lib/nem/model/account_historical.rb +19 -0
  71. data/lib/nem/model/block.rb +33 -0
  72. data/lib/nem/model/chain.rb +14 -0
  73. data/lib/nem/model/connection.rb +23 -0
  74. data/lib/nem/model/experience.rb +20 -0
  75. data/lib/nem/model/explorer_block.rb +21 -0
  76. data/lib/nem/model/harvest.rb +23 -0
  77. data/lib/nem/model/heartbeat.rb +21 -0
  78. data/lib/nem/model/importance.rb +29 -0
  79. data/lib/nem/model/importance_transfer_transaction.rb +16 -0
  80. data/lib/nem/model/keypair.rb +19 -0
  81. data/lib/nem/model/message.rb +91 -0
  82. data/lib/nem/model/mosaic.rb +21 -0
  83. data/lib/nem/model/mosaic_attachment.rb +22 -0
  84. data/lib/nem/model/mosaic_definition.rb +65 -0
  85. data/lib/nem/model/mosaic_definition_creation_transaction.rb +18 -0
  86. data/lib/nem/model/mosaic_id.rb +27 -0
  87. data/lib/nem/model/mosaic_levy.rb +32 -0
  88. data/lib/nem/model/mosaic_owned.rb +22 -0
  89. data/lib/nem/model/mosaic_properties.rb +44 -0
  90. data/lib/nem/model/mosaic_supply.rb +21 -0
  91. data/lib/nem/model/mosaic_supply_change_transaction.rb +18 -0
  92. data/lib/nem/model/multisig_aggregate_modification_transaction.rb +21 -0
  93. data/lib/nem/model/multisig_info.rb +16 -0
  94. data/lib/nem/model/multisig_signature_transaction.rb +17 -0
  95. data/lib/nem/model/multisig_transaction.rb +21 -0
  96. data/lib/nem/model/namespace.rb +24 -0
  97. data/lib/nem/model/nem_announce_result.rb +19 -0
  98. data/lib/nem/model/network_time.rb +16 -0
  99. data/lib/nem/model/nis_node_info.rb +26 -0
  100. data/lib/nem/model/node.rb +41 -0
  101. data/lib/nem/model/provision_namespace_transaction.rb +18 -0
  102. data/lib/nem/model/status.rb +21 -0
  103. data/lib/nem/model/timer.rb +31 -0
  104. data/lib/nem/model/timesync.rb +19 -0
  105. data/lib/nem/model/transaction.rb +71 -0
  106. data/lib/nem/model/transfer_transaction.rb +24 -0
  107. data/lib/nem/model/unlocked_info.rb +24 -0
  108. data/lib/nem/mosaic.rb +2 -0
  109. data/lib/nem/mosaic/dim_coin.rb +21 -0
  110. data/lib/nem/mosaic/dim_token.rb +21 -0
  111. data/lib/nem/mosaic/ecobit_eco.rb +21 -0
  112. data/lib/nem/mosaic/xem.rb +21 -0
  113. data/lib/nem/node.rb +29 -0
  114. data/lib/nem/node_pool.rb +31 -0
  115. data/lib/nem/request.rb +2 -0
  116. data/lib/nem/request/announce.rb +76 -0
  117. data/lib/nem/transaction.rb +3 -0
  118. data/lib/nem/transaction/base.rb +45 -0
  119. data/lib/nem/transaction/importance_transfer.rb +42 -0
  120. data/lib/nem/transaction/mosaic_definition_creation.rb +45 -0
  121. data/lib/nem/transaction/mosaic_supply_change.rb +45 -0
  122. data/lib/nem/transaction/multisig.rb +29 -0
  123. data/lib/nem/transaction/multisig_aggregate_modification.rb +30 -0
  124. data/lib/nem/transaction/multisig_cosignatory_modification.rb +33 -0
  125. data/lib/nem/transaction/multisig_signature.rb +31 -0
  126. data/lib/nem/transaction/provision_namespace.rb +65 -0
  127. data/lib/nem/transaction/transfer.rb +63 -0
  128. data/lib/nem/util.rb +44 -0
  129. data/lib/nem/util/assignable.rb +51 -0
  130. data/lib/nem/util/convert.rb +112 -0
  131. data/lib/nem/util/deserializer.rb +158 -0
  132. data/lib/nem/util/ed25519.rb +316 -0
  133. data/lib/nem/util/serializer.rb +260 -0
  134. data/lib/nem/version.rb +3 -0
  135. data/nem-ruby.gemspec +46 -0
  136. metadata +350 -0
@@ -0,0 +1,35 @@
1
+ require 'pp'
2
+ require 'nem'
3
+
4
+ # Library configuration
5
+ Nem.configure do |conf|
6
+ # conf.logger = Logger.new('./nem-ruby.log')
7
+ # conf.logger.level = Logger::DEBUG
8
+ # you can set deadline(sec)
9
+ # conf.deadline = 7200
10
+ # set :mainnet if you'd like to use on mainnet!
11
+ # conf.default_network = :mainnet # use on mainnet!
12
+ end
13
+
14
+ # multisig
15
+ M_PUBLIC_KEY = '6d72b57d2bc199d328e7ea3e24775f7f614760bc18f3f8501cd3daa9870cc40c'
16
+
17
+ # cosignatory
18
+ A_PRIVATE_KEY = '4ce5c8f9fce571db0d9ac1adf00b8d3ba0f078ed40835fd3d730a2f24b834214'
19
+
20
+ # recipient
21
+ B_ADDRESS = 'TA4TX6U5HG2MROAESH2JE5524T4ZOY2EQKQ6ELHF'
22
+
23
+ kp = Nem::Keypair.new(A_PRIVATE_KEY)
24
+ node = Nem::Node.new
25
+ tx_endpoint = Nem::Endpoint::Transaction.new(node)
26
+
27
+ ttx = Nem::Transaction::Transfer.new(B_ADDRESS, 1, 'Good luck!')
28
+ tx = Nem::Transaction::Multisig.new(ttx, M_PUBLIC_KEY)
29
+ pp "Fee: #{tx.fee.to_i}"
30
+
31
+ req = Nem::Request::Announce.new(tx, kp)
32
+ res = tx_endpoint.prepare_announce(req)
33
+
34
+ pp "Message: #{res.message}"
35
+ pp "TransactionHash: #{res.transaction_hash}"
@@ -0,0 +1,20 @@
1
+ require 'pp'
2
+ require 'nem'
3
+
4
+ Nem.logger.level = Logger::DEBUG
5
+
6
+ # namespace creator
7
+ A_PRIVATE_KEY = '4ce5c8f9fce571db0d9ac1adf00b8d3ba0f078ed40835fd3d730a2f24b834214'
8
+
9
+ kp = Nem::Keypair.new(A_PRIVATE_KEY)
10
+ node = Nem::Node.new(host: '104.128.226.60')
11
+ tx_endpoint = Nem::Endpoint::Transaction.new(node)
12
+
13
+ tx = Nem::Transaction::ProvisionNamespace.new('sushi')
14
+ pp "Fee: #{tx.fee.to_i}"
15
+
16
+ req = Nem::Request::Announce.new(tx, kp)
17
+ res = tx_endpoint.announce(req)
18
+
19
+ pp "Message: #{res.message}"
20
+ pp "TransactionHash: #{res.transaction_hash}"
@@ -0,0 +1,32 @@
1
+ require 'pp'
2
+ require 'nem'
3
+
4
+ # Library configuration
5
+ Nem.configure do |conf|
6
+ conf.logger = Logger.new('./nem-ruby.log')
7
+ conf.logger.level = Logger::DEBUG
8
+ # you can set deadline(sec)
9
+ # conf.deadline = 7200
10
+ # set :mainnet if you'd like to use on mainnet!
11
+ # conf.default_network = :mainnet # use on mainnet!
12
+ end
13
+
14
+ # sender
15
+ A_PRIVATE_KEY = '4ce5c8f9fce571db0d9ac1adf00b8d3ba0f078ed40835fd3d730a2f24b834214'
16
+
17
+ # recipient
18
+ B_ADDRESS = 'TA4TX6U5HG2MROAESH2JE5524T4ZOY2EQKQ6ELHF'
19
+
20
+ kp = Nem::Keypair.new(A_PRIVATE_KEY)
21
+ node = Nem::Node.new(host: '104.128.226.60')
22
+ tx_endpoint = Nem::Endpoint::Transaction.new(node)
23
+
24
+ # with plain message
25
+ tx = Nem::Transaction::Transfer.new(B_ADDRESS, 1, 'Good luck!')
26
+ pp "Fee: #{tx.fee.to_i}"
27
+
28
+ req = Nem::Request::Announce.new(tx, kp)
29
+ res = tx_endpoint.announce(req)
30
+
31
+ pp "Message: #{res.message}"
32
+ pp "TransactionHash: #{res.transaction_hash}"
@@ -0,0 +1,72 @@
1
+ require 'pp'
2
+ require 'nem'
3
+
4
+ Nem.logger.level = Logger::DEBUG
5
+
6
+ # sender
7
+ A_PRIVATE_KEY = '4ce5c8f9fce571db0d9ac1adf00b8d3ba0f078ed40835fd3d730a2f24b834214'
8
+
9
+ # recipient
10
+ B_ADDRESS = 'TA4TX6U5HG2MROAESH2JE5524T4ZOY2EQKQ6ELHF'
11
+
12
+ kp = Nem::Keypair.new(A_PRIVATE_KEY)
13
+ node = Nem::Node.new(host: '104.128.226.60')
14
+ tx_endpoint = Nem::Endpoint::Transaction.new(node)
15
+ # ns_endpoint = Nem::Endpoint::Namespace.new(node)
16
+
17
+ # TODO:
18
+
19
+ # fetch mosaic definition
20
+ # mo_dmdps = ns_endpoint.mosaic_definition('kon')
21
+ # mo_def = mo_dmdps.first.mosaic
22
+
23
+ # define custom mosaic attachment
24
+ # class MyMosaic < Nem::Model::MosaicAttachment
25
+ # def initialize(quantity)
26
+ # # set values what you defined
27
+ # mosaic_id = Nem::Model::MosaicId.new(
28
+ # namespace_id: 'my',
29
+ # name: 'mosaic'
30
+ # )
31
+ # # set values what you defined
32
+ # properties = Nem::Model::MosaicProperties.new(
33
+ # divisibility: 3,
34
+ # initial_supply: 123_456_789
35
+ # )
36
+ # super(
37
+ # mosaic_id: mosaic_id,
38
+ # properties: properties,
39
+ # quantity: quantity
40
+ # )
41
+ # end
42
+ # end
43
+
44
+ # define custom mosaic attachment
45
+ class KonHeart < Nem::Model::MosaicAttachment
46
+ def initialize(quantity)
47
+ mosaic_id = Nem::Model::MosaicId.new(
48
+ namespace_id: 'kon',
49
+ name: 'heart'
50
+ )
51
+ properties = Nem::Model::MosaicProperties.new(
52
+ divisibility: 3,
53
+ initial_supply: 100_000_000
54
+ )
55
+ super(
56
+ mosaic_id: mosaic_id,
57
+ properties: properties,
58
+ quantity: quantity
59
+ )
60
+ end
61
+ end
62
+
63
+ tx = Nem::Transaction::Transfer.new(B_ADDRESS, 1, 'Good luck!')
64
+ tx.mosaics << Nem::Mosaic::Xem.new(1)
65
+ tx.mosaics << KonHeart.new(1)
66
+ pp "Fee: #{tx.fee.to_i}"
67
+
68
+ req = Nem::Request::Announce.new(tx, kp)
69
+ res = tx_endpoint.announce(req)
70
+
71
+ pp "Message: #{res.message}"
72
+ pp "TransactionHash: #{res.transaction_hash}"
@@ -0,0 +1,40 @@
1
+ require 'pp'
2
+ require 'nem'
3
+
4
+ # Library configuration
5
+ Nem.configure do |conf|
6
+ conf.logger = Logger.new('./nem-ruby.log')
7
+ conf.logger.level = Logger::DEBUG
8
+ # you can set deadline(sec)
9
+ # conf.deadline = 7200
10
+ # set :mainnet if you'd like to use on mainnet!
11
+ # conf.default_network = :mainnet
12
+ end
13
+
14
+ # sender
15
+ A_PRIVATE_KEY = '4ce5c8f9fce571db0d9ac1adf00b8d3ba0f078ed40835fd3d730a2f24b834214'
16
+
17
+ # recipient
18
+ B_ADDRESS = 'TA4TX6U5HG2MROAESH2JE5524T4ZOY2EQKQ6ELHF'
19
+ B_PUBLIC_KEY = '9e7ab2924cd1a3482df784db190614cfc8a33671f5d80a5b15a9c9e8b4d13933'
20
+
21
+ kp = Nem::Keypair.new(A_PRIVATE_KEY)
22
+ node = Nem::Node.new(host: '104.128.226.60')
23
+ tx_endpoint = Nem::Endpoint::Transaction.new(node)
24
+
25
+ # with encrypted message
26
+ message = Nem::Model::Message.new('Good luck!',
27
+ type: :encrypted,
28
+ private_key: kp.private,
29
+ public_key: B_PUBLIC_KEY
30
+ )
31
+ message.encrypt!
32
+
33
+ tx = Nem::Transaction::Transfer.new(B_ADDRESS, 1, message, {})
34
+ pp "Fee: #{tx.fee.to_i}"
35
+
36
+ req = Nem::Request::Announce.new(tx, kp)
37
+ res = tx_endpoint.announce(req)
38
+
39
+ pp "Message: #{res.message}"
40
+ pp "TransactionHash: #{res.transaction_hash}"
@@ -0,0 +1,34 @@
1
+ require 'pp'
2
+ require 'nem'
3
+
4
+ # Library configuration
5
+ Nem.configure do |conf|
6
+ conf.logger = Logger.new('./nem-ruby.log')
7
+ conf.logger.level = Logger::DEBUG
8
+ # you can set deadline(sec)
9
+ # conf.deadline = 7200
10
+ # set :mainnet if you'd like to use on mainnet!
11
+ # conf.default_network = :mainnet # use on mainnet!
12
+ end
13
+
14
+ # sender
15
+ A_PRIVATE_KEY = '4ce5c8f9fce571db0d9ac1adf00b8d3ba0f078ed40835fd3d730a2f24b834214'
16
+
17
+ # recipient
18
+ B_ADDRESS = 'TA4TX6U5HG2MROAESH2JE5524T4ZOY2EQKQ6ELHF'
19
+
20
+ kp = Nem::Keypair.new(A_PRIVATE_KEY)
21
+ # connect localhost if no params
22
+ node = Nem::Node.new
23
+ tx_endpoint = Nem::Endpoint::Transaction.new(node)
24
+
25
+ # with plain message
26
+ tx = Nem::Transaction::Transfer.new(B_ADDRESS, 1, 'Good luck!')
27
+ pp "Fee: #{tx.fee.to_i}"
28
+
29
+ req = Nem::Request::Announce.new(tx, kp)
30
+ # use #prepare method for local node without signature
31
+ res = tx_endpoint.prepare_announce(req)
32
+
33
+ pp "Message: #{res.message}"
34
+ pp "TransactionHash: #{res.transaction_hash}"
@@ -0,0 +1,21 @@
1
+ require 'nem/version'
2
+ require 'nem/error'
3
+ require 'nem/configuration'
4
+ require 'nem/util'
5
+ require 'nem/fee'
6
+ require 'nem/mixin'
7
+ require 'nem/transaction'
8
+ require 'nem/request'
9
+ require 'nem/endpoint'
10
+ require 'nem/model'
11
+ require 'nem/keypair'
12
+ require 'nem/node'
13
+ require 'nem/node_pool'
14
+ require 'nem/client'
15
+ require 'nem/apostille'
16
+ require 'nem/apostille_audit'
17
+ require 'nem/mosaic'
18
+
19
+ module Nem
20
+ extend Nem::Configuration
21
+ end
@@ -0,0 +1,104 @@
1
+ require 'digest/md5'
2
+ require 'digest/sha1'
3
+ require 'digest/sha2'
4
+ require 'digest/sha3'
5
+
6
+ class Nem::Apostille
7
+ CHECKSUM = 'fe4e5459'.freeze
8
+
9
+ # @param [Nem::Keypair] keypair
10
+ # @param [string] file - The file
11
+ # @param [symbol] hashing - An hashing type (md5, sha1, sha256, sha3-256, sha3-512)
12
+ # @param [boolean] multisig - true if transaction is multisig, false otherwise
13
+ # @param [boolean] private - true if apostille is private / transferable / updateable, false if public
14
+ def initialize(keypair, file, hashing = :sha256, multisig: false, private: false, network: nil)
15
+ @keypair = keypair
16
+ @file = file
17
+ @hashing = hashing
18
+ @multisig = multisig
19
+ @private = private
20
+ @network = network || Nem.default_network
21
+ end
22
+
23
+ def private?
24
+ @private
25
+ end
26
+
27
+ def multisig?
28
+ @multisig
29
+ end
30
+
31
+ def transaction
32
+ if private?
33
+ raise 'Not implemented private apostille.'
34
+ else
35
+ dedicated_address = apostille[:sink]
36
+ apostille_hash = calc_hash
37
+ end
38
+
39
+ Nem::Transaction::Transfer.new(dedicated_address, 0, apostille_hash)
40
+ end
41
+
42
+ def apostille_format(transaction_hash)
43
+ ext = File.extname(@file.path)
44
+ name = File.basename(@file.path, ext)
45
+ date = Date.today.strftime('%Y-%m-%d')
46
+ '%s -- Apostille TX %s -- Date %s%s' % [
47
+ name,
48
+ transaction_hash,
49
+ date,
50
+ ext
51
+ ]
52
+ end
53
+
54
+ private
55
+
56
+ def calc_hash
57
+ checksum = "#{CHECKSUM}#{hex_type}"
58
+ hashed = case @hashing
59
+ when /\Amd5\z/ then Digest::MD5.file(@file)
60
+ when /\Asha1\z/ then Digest::SHA1.file(@file)
61
+ when /\Asha256\z/ then Digest::SHA256.file(@file)
62
+ when /\Asha3-256\z/ then Digest::SHA3.file(@file, 256)
63
+ else Digest::SHA3.file(@file, 512)
64
+ end
65
+ checksum << hashed.hexdigest
66
+ end
67
+
68
+ def algo
69
+ case @hashing
70
+ when /\Amd5\z/ then 0x01
71
+ when /\Asha1\z/ then 0x02
72
+ when /\Asha256\z/ then 0x03
73
+ when /\Asha3-256\z/ then 0x08
74
+ when /\Asha3-512\z/ then 0x09
75
+ else raise "Undefined hashing: #{@hashing}"
76
+ end
77
+ end
78
+
79
+ def version
80
+ private? ? 0x80 : 0x00
81
+ end
82
+
83
+ def hex_type
84
+ '%02x' % (algo | version)
85
+ end
86
+
87
+ def apostille
88
+ if @network == :mainnet
89
+ if private?
90
+ raise 'Not implemented private apostille.'
91
+ else
92
+ { private_key: nil,
93
+ sink: 'NCZSJHLTIMESERVBVKOW6US64YDZG2PFGQCSV23J' }
94
+ end
95
+ else
96
+ if private?
97
+ raise 'Not implemented private apostille.'
98
+ else
99
+ { private_key: nil,
100
+ sink: 'TC7MCY5AGJQXZQ4BN3BOPNXUVIGDJCOHBPGUM2GE' }
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,47 @@
1
+ require 'digest/md5'
2
+ require 'digest/sha1'
3
+ require 'digest/sha2'
4
+ require 'digest/sha3'
5
+
6
+ class Nem::ApostilleAudit
7
+ CHECKSUM = 'fe4e5459'.freeze
8
+
9
+ # @param [File] file
10
+ # @param [apostille_hash] Apostille formatted hash
11
+ def initialize(file, apostille_hash)
12
+ @file = file
13
+ @apostille_hash = apostille_hash
14
+ @checksum, @version, @algo, @hash = split_apostille_hash
15
+ end
16
+
17
+ def valid?
18
+ raise 'Not implemented private apostille' if private?
19
+ raise "Invalid checksum: #{@checksum}" unless @checksum == CHECKSUM
20
+ @hash == calc_hash
21
+ end
22
+
23
+ def private?
24
+ @version == 0x80
25
+ end
26
+
27
+ def split_apostille_hash
28
+ [ @apostille_hash[0, 8],
29
+ @apostille_hash[8, 1].to_i,
30
+ @apostille_hash[9, 1].to_i,
31
+ @apostille_hash[10, @apostille_hash.size] ]
32
+ end
33
+
34
+ private
35
+
36
+ def calc_hash
37
+ hashed = case @algo
38
+ when 0x01 then Digest::MD5.file(@file)
39
+ when 0x02 then Digest::SHA1.file(@file)
40
+ when 0x03 then Digest::SHA256.file(@file)
41
+ when 0x08 then Digest::SHA3.file(@file, 256)
42
+ when 0x09 then Digest::SHA3.file(@file, 512)
43
+ else raise "Undefined alog #{@algo}"
44
+ end
45
+ hashed.hexdigest
46
+ end
47
+ end
@@ -0,0 +1,170 @@
1
+ require 'faraday'
2
+ require 'faraday_middleware'
3
+ require 'uri'
4
+ require 'json'
5
+ require 'time'
6
+
7
+ # @attr [Hash] options connection options
8
+ class Nem::Client
9
+ DEFAULTS = {
10
+ url: -> { ENV['NEM_URL'] },
11
+ scheme: 'http',
12
+ host: '127.0.0.1',
13
+ port: 7890,
14
+ timeout: 5
15
+ }.freeze
16
+
17
+ LOCAL_ONLY_PATHES = [
18
+ '/account/generate',
19
+ '/local/account/transfers/incoming',
20
+ '/local/account/transfers/outgoing',
21
+ '/local/account/transfers/all',
22
+ '/node/boot',
23
+ '/transaction/prepare-announce',
24
+ '/shutdown'
25
+ ]
26
+
27
+ attr_reader :options
28
+
29
+ # @param [hash] options HTTP Client connection information
30
+ # @option options [Symbol] :url URL
31
+ # @option options [Symbol] :scheme default http (http only)
32
+ # @option options [Symbol] :host default 127.0.0.1
33
+ # @option options [Symbol] :port default 7890
34
+ # @option options [Symbol] :timeout default 5
35
+ def initialize(options = {})
36
+ @options = parse_options(options)
37
+ end
38
+
39
+ # @param [Symbol] method HTTP Method(GET or POST)
40
+ # @param [String] path API Path
41
+ # @param [Hash] params API Parameters
42
+ # @return [Hash] Hash converted API Response
43
+ def request(method, path, params = {})
44
+ log(method, path, params)
45
+ if connection.remote? && local_only?(path)
46
+ raise Nem::Error, "The request (#{method} #{path}) is only permitted to local NIS."
47
+ end
48
+ if params.is_a?(Hash) && !params.empty?
49
+ params.reject! { |_, value| value.nil? }
50
+ end
51
+
52
+ res = connection.send(method, path, params)
53
+ # begin
54
+ # rescue Faraday::ConnectionFailed => err
55
+ # error(method, path, params, err.message)
56
+ # retry
57
+ # end
58
+
59
+ body = res.body
60
+ hash = parse_body(body) unless body.empty?
61
+ block_given? ? yield(hash) : hash
62
+ end
63
+
64
+ # @param [Symbol] method HTTP Method(GET or POST)
65
+ # @param [String] path API Path
66
+ # @param [Hash] params API Parameters
67
+ # @return [Hash] Hash converted API Response
68
+ # @raise [Nem::Error] NIS error
69
+ def request!(method, path, params = {})
70
+ hash = request(method, path, params)
71
+ raise error_handling(hash) if hash && hash.key?(:error)
72
+ block_given? ? yield(hash) : hash
73
+ end
74
+
75
+ private
76
+
77
+ def error_handling(hash)
78
+ error_klass = case hash[:error]
79
+ when 'Not Found' then Nem::NotFoundError
80
+ when 'Bad Request' then Nem::BadRequestError
81
+ when 'Internal Server Error' then Nem::InternalServerError
82
+ else Nem::Error
83
+ end
84
+ error_klass.new(hash[:message])
85
+ end
86
+
87
+ def local_only?(path)
88
+ LOCAL_ONLY_PATHES.include?(path)
89
+ end
90
+
91
+ def connection
92
+ @connection ||= Faraday.new(url: @options[:url]) do |f|
93
+ f.options[:timeout] = @options[:timeout]
94
+ f.request :json
95
+ # f.response :logger do | logger |
96
+ # logger.filter(/(privateKey=)(\w+)/,'\1[FILTERED]')
97
+ # end
98
+ f.adapter Faraday.default_adapter
99
+ end.tap { |c| c.extend(Local) }
100
+ end
101
+
102
+ def parse_body(body)
103
+ JSON.parse(body, symbolize_names: true)
104
+ end
105
+
106
+ def parse_options(options = {})
107
+ defaults = DEFAULTS.dup
108
+ options = options.dup
109
+
110
+ defaults[:url] = defaults[:url].call if defaults[:url].respond_to?(:call)
111
+
112
+ defaults.keys.each do |key|
113
+ options[key] = options[key.to_s] if options.key?(key.to_s)
114
+ end
115
+
116
+ url = options[:url] || defaults[:url]
117
+
118
+ if url
119
+ uri = URI(url)
120
+ if uri.scheme == 'http'
121
+ defaults[:scheme] = uri.scheme
122
+ defaults[:host] = uri.host
123
+ defaults[:port] = uri.port
124
+ else
125
+ raise ArgumentError, "invalid URI scheme '#{uri.scheme}'"
126
+ end
127
+ end
128
+
129
+ defaults.keys.each do |key|
130
+ options[key] = defaults[key] if options[key].nil?
131
+ end
132
+
133
+ options[:url] = URI::Generic.build(
134
+ scheme: options[:scheme],
135
+ host: options[:host],
136
+ port: options[:port]
137
+ ).to_s
138
+
139
+ options
140
+ end
141
+
142
+ def log(method, path, params)
143
+ Nem.logger.debug "host:%s\tmethod:%s\tpath:%s\tparams:%s" % [
144
+ connection.url_prefix,
145
+ method,
146
+ path,
147
+ params.to_hash
148
+ ]
149
+ end
150
+
151
+ def error(method, path, params, message)
152
+ Nem.logger.debug "host:%s\tmethod:%s\tpath:%s\tparams:%s\tmessage:%s" % [
153
+ connection.url_prefix,
154
+ method,
155
+ path,
156
+ params.to_hash,
157
+ message
158
+ ]
159
+ end
160
+
161
+ module Local
162
+ def local?
163
+ host == '127.0.0.1' || host == 'localhost'
164
+ end
165
+
166
+ def remote?
167
+ !local?
168
+ end
169
+ end
170
+ end