solana_rpc_ruby 1.0.0.pre → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8bea15d348b3cc9652473f49747cff8a89992b43543bcf3d569c1aef933c03cf
4
- data.tar.gz: d9741e5591c96851ba5d71c70ac09687e7888748e5a82dcbde3e2eab3cebff7f
3
+ metadata.gz: 2b473e11604fa0d409efbe09260aa85bf467a1b76b6fa014e7a0716e019b3c5e
4
+ data.tar.gz: 7e116f4bdb58358bf85c3260eb526be306445d87ec87788648ee40ffbd9bd80d
5
5
  SHA512:
6
- metadata.gz: f28f02c36ed297a1fb527244e2e4e859a636920bd99c9a8cdc4fd20b2f345738d8c2fd011786ccbe4f2b69677d4d089cee77b85572dbb55b18cd6a94ad89e931
7
- data.tar.gz: c6ac7e9ee342c856553bcb3053c50f8dee9db48c667946a5d0ecb775b3b026c39eacfed59b254697d0aebe1b89c2a933cff7b4f65b72823855f9dc7d1a48b69a
6
+ metadata.gz: 5013b6799259a02d77cc232e3a1456a2de52b71c93c31e78a376c702656ed7c6444577e2f4467ceb8c5aa7df7b9b78d4bb05ee27711f003e08d6576c15b84fc4
7
+ data.tar.gz: ada8e45a050f6bc74e712f9a61a2e8b62032a6a9e60e8a21627c99dd5ce48673833b3cc119c6a893b117dcb81233e1aa8c196bb5cd27145bf684ab88b9c257cb
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
1
  # Changelog
2
- ## 1.0.0 (TBA)
2
+ ## 1.0.0
3
3
  * Initial release
4
+
5
+ ## 1.0.1
6
+ * Add optional id argument that can be passed to MethodsWrapper class.
7
+
8
+ ## 1.1.0
9
+ * Add websockets connection to gem.
10
+
11
+ ## 1.1.1
12
+ * Fix SolanaRpcRuby::ApiError occurring when websocket program runs for too long
13
+ (#<SolanaRpcRuby::ApiError: NoMethodError undefined method ping)
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- ![specs](https://github.com/Block-Logic/solana-rpc-ruby/actions/workflows/specs.yml/badge.svg?branch=177580443_create_wrapper_for_solana_rpc)
1
+ ![specs](https://github.com/Block-Logic/solana-rpc-ruby/actions/workflows/specs.yml/badge.svg)
2
2
  # solana_rpc_ruby
3
3
  A Solana RPC Client for Ruby. This gem provides a wrapper methods for Solana RPC JSON API https://docs.solana.com/developing/clients/jsonrpc-api.
4
4
 
@@ -21,7 +21,7 @@ Next, you need to run the generator:
21
21
  rails g solana_rpc_ruby:install
22
22
  ```
23
23
 
24
- The latter command will generate a new config file `config/solana_rpc_ruby_config.rb` looking like this:
24
+ The latter command will generate a new config file `config/initializers/solana_rpc_ruby_config.rb` looking like this:
25
25
 
26
26
  ```ruby
27
27
  require 'solana_rpc_ruby'
@@ -29,21 +29,171 @@ require 'solana_rpc_ruby'
29
29
  SolanaRpcRuby.config do |c|
30
30
  c.cluster = 'https://api.testnet.solana.com'
31
31
  c.json_rpc_version = '2.0'
32
- c.encoding = 'base58'
33
32
  # ...other options
34
33
  end
35
34
  ```
36
35
  You can customize it to your needs.
37
36
 
38
37
  ### Usage examples
38
+
39
+ #### JSON RPC API
39
40
  ```ruby
40
41
  # If you set default cluster you don't need to pass it every time.
41
- method_wrapper = SolanaRpcRuby::MethodsWrapper.new(cluster: 'https://api.testnet.solana.com')
42
+ method_wrapper = SolanaRpcRuby::MethodsWrapper.new(
43
+ # optional, if not passed, default cluster from config will be used
44
+ cluster: 'https://api.testnet.solana.com',
45
+
46
+ # optional, if not passed, default random number
47
+ # from range 1 to 99_999 will be used
48
+ id: 123
49
+ )
50
+
42
51
  response = method_wrapper.get_account_info(account_pubkey)
43
52
  puts response
53
+
54
+ # You can check cluster and id that are used.
55
+ method_wrapper.cluster
56
+ method_wrapper.id
57
+ ```
58
+ #### Subscription Websocket (BETA)
59
+ ```ruby
60
+ ws_method_wrapper = SolanaRpcRuby::WebsocketsMethodsWrapper.new(
61
+ # optional, if not passed, default ws_cluster from config will be used
62
+ cluster: 'ws://api.testnet.solana.com',
63
+
64
+ # optional, if not passed, default random number
65
+ # from range 1 to 99_999 will be used
66
+ id: 123
67
+ )
68
+
69
+ # You should see stream of messages in your console.
70
+ ws_method_wrapper.root_subscribe
71
+
72
+ # You can pass a block to do something with websocket's messages, ie:
73
+ block = Proc.new do |message|
74
+ json = JSON.parse(message)
75
+ puts json['params']
76
+ end
77
+
78
+ ws_method_wrapper.root_subscribe(&block)
79
+
80
+ # You can check cluster and id that are used.
81
+ ws_method_wrapper.cluster
82
+ ws_method_wrapper.id
83
+ ```
84
+
85
+ #### Websockets usage in Rails
86
+ You can easily plug-in websockets connection to your rails app by using ActionCable.
87
+ Here is an example for development environment.
88
+ More explanation on Action Cable here: https://www.pluralsight.com/guides/updating-a-rails-app's-wall-feed-in-real-time-with-actioncable
89
+
90
+ 0. Make sure that you have action_cable and solana_rpc_ruby gems installed properly. Also install redis unless you have it.
91
+
92
+ 1. Mount action_cable in `routes.rb`.
93
+ ```
94
+ Rails.application.routes.draw do
95
+ mount ActionCable.server => '/cable'
96
+ ...
97
+ end
98
+ ```
99
+
100
+ 2. Update `config/environments/development.rb`.
101
+ ```
102
+ config.action_cable.url = "ws://localhost:3000/cable"
103
+ config.action_cable.allowed_request_origins = [/http:\/\/*/, /https:\/\/*/]
104
+ ```
105
+
106
+ 3. Update adapter in `cable.yml`.
107
+ ```
108
+ development:
109
+ adapter: redis
110
+ url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
111
+ ```
112
+
113
+ 4. Create a channel.
114
+ ```
115
+ rails g channel wall
44
116
  ```
45
117
 
46
- All info about methods you can find in the docs on: FILL THE ADDRESS!!!
118
+ 5. Your `wall_channel.rb` should look like this:
119
+ ```
120
+ class WallChannel < ApplicationCable::Channel
121
+ def subscribed
122
+ stream_from "wall_channel"
123
+ end
124
+
125
+ def unsubscribed
126
+ # Any cleanup needed when channel is unsubscribed
127
+ end
128
+ end
129
+ ```
130
+
131
+ 6. Your `wall_channel.js` should look like this (json keys are configured for `root_subscription` method response):
132
+ ```
133
+ import consumer from "./consumer"
134
+
135
+ consumer.subscriptions.create("WallChannel", {
136
+ connected() {
137
+ console.log("Connected to WallChannel");
138
+ // Called when the subscription is ready for use on the server
139
+ },
140
+
141
+ disconnected() {
142
+ // Called when the subscription has been terminated by the server
143
+ },
144
+
145
+ received(data) {
146
+ let wall = document.getElementById('wall');
147
+
148
+ wall.innerHTML += "<p>Result: "+ data['message']['result'] + "</p>";
149
+ // Called when there's incoming data on the websocket for this channel
150
+ }
151
+ });
152
+
153
+
154
+ ```
155
+
156
+ 7. Create placeholder somewhere in your view for messages.
157
+ ```
158
+ <div id='wall' style='overflow-y: scroll; height:400px;''>
159
+ <h1>Solana subscription messages</h1>
160
+ </div>
161
+ ```
162
+
163
+ 8. Create a script with a block to run websockets (`script/websockets_solana.rb`).
164
+ ```
165
+ require_relative '../config/environment'
166
+
167
+ ws_method_wrapper = SolanaRpcRuby::WebsocketsMethodsWrapper.new
168
+
169
+ # Example of block that can be passed to the method to manipulate the data.
170
+ block = Proc.new do |message|
171
+ json = JSON.parse(message)
172
+
173
+ ActionCable.server.broadcast(
174
+ "wall_channel",
175
+ {
176
+ message: json['params']
177
+ }
178
+ )
179
+ end
180
+
181
+ ws_method_wrapper.root_subscribe(&block)
182
+ ```
183
+ 9. Run `rails s`, open webpage where you put your placeholder.
184
+ 10. Open `http://localhost:3000/address_with_websockets_view`.
185
+ 11. Run `rails r script/websockets_solana.rb` in another terminal window.
186
+ 12. You should see incoming websocket messages on your webpage.
187
+ ### Demo scripts
188
+ Gem is coming with demo scripts that you can run and test API and Websockets.
189
+
190
+ 1. Clone the repo
191
+ 2. Set the gemset
192
+ 3. Run `ruby demo.rb` or `ruby demo_ws_METHOD.rb` to see example output.
193
+ 4. Check the gem or Solana JSON RPC API docs to get more information about method usage and modify demo scripts loosely.
194
+
195
+ All info about methods you can find in the docs on: https://www.rubydoc.info/github/Block-Logic/solana-rpc-ruby/main/SolanaRpcRuby
196
+
47
197
  Also, as a reference you can use docs from solana: https://docs.solana.com/developing/clients/jsonrpc-api
48
198
  ## License
49
199
 
@@ -6,7 +6,7 @@ module SolanaRpcRuby
6
6
 
7
7
  desc 'Creates a SolanaRpcRuby config file.'
8
8
  def copy_config
9
- template 'solana_rpc_ruby_config.rb', "#{Rails.root}/config/solana_rpc_ruby.rb"
9
+ template 'solana_rpc_ruby_config.rb', "#{Rails.root}/config/initializers/solana_rpc_ruby.rb"
10
10
  end
11
11
  end
12
12
  end
@@ -1,14 +1,13 @@
1
1
  require_relative 'solana_rpc_ruby'
2
2
 
3
- # DEVNET_CLUSTER = 'https://api.devnet.solana.com'
4
- # MAINNET_CLUSTER = 'https://api.mainnet-beta.solana.com'
5
- # TESTNET_CLUSTER = 'https://api.testnet.solana.com'
6
-
7
3
  SolanaRpcRuby.config do |c|
8
- # These are mandatory options that you must set before using gem:
4
+ # These are options that you can set before using gem:
9
5
  #
6
+ # You can use this setting or pass cluster directly, check the docs.
10
7
  # c.cluster = 'https://api.testnet.solana.com'
11
- # c.json_rpc = '2.0
12
- # c.encoding = 'base58'
13
- # c.id = 1
8
+ # c.ws_cluster = 'ws://api.testnet.solana.com'
9
+
10
+
11
+ # This one is mandatory.
12
+ c.json_rpc_version = '2.0'
14
13
  end
@@ -1,5 +1,4 @@
1
1
  require 'net/http'
2
-
3
2
  module SolanaRpcRuby
4
3
  ##
5
4
  # ApiClient class serves as a client for solana JSON RPC API.
@@ -14,29 +13,29 @@ module SolanaRpcRuby
14
13
  attr_accessor :default_headers
15
14
 
16
15
  # Initialize object with cluster address where requests will be sent.
17
- #
18
- # @param cluster [String]
16
+ #
17
+ # @param cluster [String]
19
18
  def initialize(cluster = nil)
20
19
  @cluster = cluster || SolanaRpcRuby.cluster
21
20
 
22
21
  message = 'Cluster is missing. Please provide default cluster in config or pass it to the client directly.'
23
22
  raise ArgumentError, message unless @cluster
24
23
  end
25
-
24
+
26
25
  # Sends request to the api.
27
26
  #
28
- # @param body [Hash]
27
+ # @param body [Hash]
29
28
  # @param http_method [Symbol]
30
29
  # @param params [Hash]
31
- #
30
+ #
32
31
  # @return [Object] Net::HTTPOK
33
32
  def call_api(body:, http_method:, params: {})
34
33
  uri = URI(@cluster)
35
34
  rpc_response = Net::HTTP.public_send(
36
- http_method,
37
- uri,
38
- body,
39
- default_headers,
35
+ http_method,
36
+ uri,
37
+ body,
38
+ default_headers,
40
39
  )
41
40
 
42
41
  rpc_response
@@ -44,12 +43,12 @@ module SolanaRpcRuby
44
43
  rescue Timeout::Error,
45
44
  Net::HTTPError,
46
45
  Net::HTTPNotFound,
47
- Net::HTTPServerException,
46
+ Net::HTTPClientException,
48
47
  Net::HTTPFatalError,
49
48
  Net::ReadTimeout => e
50
-
51
49
  fail ApiError.new(message: e.message)
52
50
  rescue StandardError => e
51
+
53
52
  message = "#{e.class} #{e.message}\n Backtrace: \n #{e.backtrace}"
54
53
  fail ApiError.new(message: message)
55
54
  end
@@ -6,20 +6,20 @@ module SolanaRpcRuby
6
6
  # Error code.
7
7
  # @return [Integer]
8
8
  attr_reader :code
9
-
9
+
10
10
  # Error message.
11
11
  # @return [String]
12
12
  attr_reader :message
13
-
13
+
14
14
  # Initialize object with json response from the API with error.
15
- #
15
+ #
16
16
  # @param code [Integer]
17
17
  # @param message [String]
18
- #
18
+ #
19
19
  # @return [SolanaRpcRuby::ApiError]
20
20
  def initialize(code: nil, message:)
21
21
  @code = code
22
- @message = message
22
+ @message = message.to_s
23
23
 
24
24
  super message
25
25
  end
@@ -12,5 +12,18 @@ module SolanaRpcRuby
12
12
 
13
13
  object.nil? || object.empty?
14
14
  end
15
+
16
+ # Creates method name to match names required by Solana RPC JSON.
17
+ #
18
+ # @param method [String]
19
+ #
20
+ # @return [String]
21
+ def create_method_name(method)
22
+ return '' unless method && (method.is_a?(String) || method.is_a?(Symbol))
23
+
24
+ method.to_s.split('_').map.with_index do |string, i|
25
+ i == 0 ? string : string.capitalize
26
+ end.join
27
+ end
15
28
  end
16
29
  end