github.com/gagliardetto/solana-go@v1.11.0/rpc/client.go (about) 1 // Copyright 2021 github.com/gagliardetto 2 // This file has been modified by github.com/gagliardetto 3 // 4 // Copyright 2020 dfuse Platform Inc. 5 // 6 // Licensed under the Apache License, Version 2.0 (the "License"); 7 // you may not use this file except in compliance with the License. 8 // You may obtain a copy of the License at 9 // 10 // http://www.apache.org/licenses/LICENSE-2.0 11 // 12 // Unless required by applicable law or agreed to in writing, software 13 // distributed under the License is distributed on an "AS IS" BASIS, 14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 // See the License for the specific language governing permissions and 16 // limitations under the License. 17 18 package rpc 19 20 import ( 21 "context" 22 "errors" 23 "io" 24 "net" 25 "net/http" 26 "time" 27 28 "github.com/gagliardetto/solana-go/rpc/jsonrpc" 29 "github.com/klauspost/compress/gzhttp" 30 ) 31 32 var ( 33 ErrNotFound = errors.New("not found") 34 ErrNotConfirmed = errors.New("not confirmed") 35 ) 36 37 type Client struct { 38 rpcURL string 39 rpcClient JSONRPCClient 40 } 41 42 type JSONRPCClient interface { 43 CallForInto(ctx context.Context, out interface{}, method string, params []interface{}) error 44 CallWithCallback(ctx context.Context, method string, params []interface{}, callback func(*http.Request, *http.Response) error) error 45 CallBatch(ctx context.Context, requests jsonrpc.RPCRequests) (jsonrpc.RPCResponses, error) 46 } 47 48 // New creates a new Solana JSON RPC client. 49 // Client is safe for concurrent use by multiple goroutines. 50 func New(rpcEndpoint string) *Client { 51 opts := &jsonrpc.RPCClientOpts{ 52 HTTPClient: newHTTP(), 53 } 54 55 rpcClient := jsonrpc.NewClientWithOpts(rpcEndpoint, opts) 56 return NewWithCustomRPCClient(rpcClient) 57 } 58 59 // New creates a new Solana JSON RPC client with the provided custom headers. 60 // The provided headers will be added to each RPC request sent via this RPC client. 61 func NewWithHeaders(rpcEndpoint string, headers map[string]string) *Client { 62 opts := &jsonrpc.RPCClientOpts{ 63 HTTPClient: newHTTP(), 64 CustomHeaders: headers, 65 } 66 rpcClient := jsonrpc.NewClientWithOpts(rpcEndpoint, opts) 67 return NewWithCustomRPCClient(rpcClient) 68 } 69 70 // Close closes the client. 71 func (cl *Client) Close() error { 72 if cl.rpcClient == nil { 73 return nil 74 } 75 if c, ok := cl.rpcClient.(io.Closer); ok { 76 return c.Close() 77 } 78 return nil 79 } 80 81 // NewWithCustomRPCClient creates a new Solana RPC client 82 // with the provided RPC client. 83 func NewWithCustomRPCClient(rpcClient JSONRPCClient) *Client { 84 return &Client{ 85 rpcClient: rpcClient, 86 } 87 } 88 89 var ( 90 defaultMaxIdleConnsPerHost = 9 91 defaultTimeout = 5 * time.Minute 92 defaultKeepAlive = 180 * time.Second 93 ) 94 95 func newHTTPTransport() *http.Transport { 96 return &http.Transport{ 97 IdleConnTimeout: defaultTimeout, 98 MaxConnsPerHost: defaultMaxIdleConnsPerHost, 99 MaxIdleConnsPerHost: defaultMaxIdleConnsPerHost, 100 Proxy: http.ProxyFromEnvironment, 101 DialContext: (&net.Dialer{ 102 Timeout: defaultTimeout, 103 KeepAlive: defaultKeepAlive, 104 DualStack: true, 105 }).DialContext, 106 ForceAttemptHTTP2: true, 107 // MaxIdleConns: 100, 108 TLSHandshakeTimeout: 10 * time.Second, 109 // ExpectContinueTimeout: 1 * time.Second, 110 } 111 } 112 113 // newHTTP returns a new Client from the provided config. 114 // Client is safe for concurrent use by multiple goroutines. 115 func newHTTP() *http.Client { 116 tr := newHTTPTransport() 117 118 return &http.Client{ 119 Timeout: defaultTimeout, 120 Transport: gzhttp.Transport(tr), 121 } 122 } 123 124 // RPCCallForInto allows to access the raw RPC client and send custom requests. 125 func (cl *Client) RPCCallForInto(ctx context.Context, out interface{}, method string, params []interface{}) error { 126 return cl.rpcClient.CallForInto(ctx, out, method, params) 127 } 128 129 func (cl *Client) RPCCallWithCallback( 130 ctx context.Context, 131 method string, 132 params []interface{}, 133 callback func(*http.Request, *http.Response) error, 134 ) error { 135 return cl.rpcClient.CallWithCallback(ctx, method, params, callback) 136 } 137 138 func (cl *Client) RPCCallBatch( 139 ctx context.Context, 140 requests jsonrpc.RPCRequests, 141 ) (jsonrpc.RPCResponses, error) { 142 return cl.rpcClient.CallBatch(ctx, requests) 143 } 144 145 func NewBoolean(b bool) *bool { 146 return &b 147 } 148 149 func NewTransactionVersion(v uint64) *uint64 { 150 return &v 151 }