github.com/klaytn/klaytn@v1.12.1/networks/grpc/gClient.go (about) 1 // Modifications Copyright 2019 The klaytn Authors 2 // Copyright 2015 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from rpc/json.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package grpc 22 23 import ( 24 "context" 25 "encoding/json" 26 "io" 27 "sync" 28 "time" 29 30 "google.golang.org/grpc" 31 ) 32 33 type gKlaytnClient struct { 34 addr string 35 ctx context.Context 36 cancel context.CancelFunc 37 conn *grpc.ClientConn 38 } 39 40 // json message 41 type jsonRequest struct { 42 Method string `json:"method"` 43 Version string `json:"jsonrpc"` 44 Id json.RawMessage `json:"id,omitempty"` 45 Payload json.RawMessage `json:"params,omitempty"` 46 } 47 48 type jsonSuccessResponse struct { 49 Version string `json:"jsonrpc"` 50 Id interface{} `json:"id,omitempty"` 51 Result interface{} `json:"result"` 52 } 53 54 type jsonSubscription struct { 55 Subscription string `json:"subscription"` 56 Result interface{} `json:"result,omitempty"` 57 } 58 59 func NewgKlaytnClient(addr string) (*gKlaytnClient, error) { 60 return &gKlaytnClient{addr: addr}, nil 61 } 62 63 const timeout = 5 * time.Minute 64 65 func (gkc *gKlaytnClient) makeKlaytnClient(timeout time.Duration) (KlaytnNodeClient, error) { 66 gkc.ctx, gkc.cancel = context.WithTimeout(context.Background(), timeout) 67 conn, err := grpc.DialContext(gkc.ctx, gkc.addr, grpc.WithInsecure()) 68 if err != nil { 69 logger.Error("failed to dial server", "err", err) 70 return nil, err 71 } 72 gkc.conn = conn 73 74 return NewKlaytnNodeClient(gkc.conn), nil 75 } 76 77 func (gkc *gKlaytnClient) makeRPCRequest(service string, method string, args []interface{}) (*RPCRequest, error) { 78 payload, err := json.Marshal(args) 79 if err != nil { 80 return nil, err 81 } 82 id, err := json.Marshal(1) 83 if err != nil { 84 return nil, err 85 } 86 87 arguments := &jsonRequest{method, "2.0", id, payload} 88 params, err := json.Marshal(arguments) 89 if err != nil { 90 return nil, err 91 } 92 93 return &RPCRequest{Service: service, Method: method, Params: params}, nil 94 } 95 96 func (gkc *gKlaytnClient) handleRPCResponse(response *RPCResponse) error { 97 var out jsonSuccessResponse 98 if err := json.Unmarshal(response.Payload, &out); err != nil { 99 logger.Error("failed to handle response", "err", err) 100 return err 101 } 102 103 // fmt.Println(out.Result) 104 return nil 105 } 106 107 func (gkc *gKlaytnClient) handleSubscribe(client KlaytnNode_SubscribeClient, handle func(response *RPCResponse) error) { 108 var waitGroup sync.WaitGroup 109 waitGroup.Add(1) 110 111 ticker := time.NewTicker(1 * time.Second) 112 113 loop: 114 for { 115 select { 116 case <-ticker.C: 117 rev, err := client.Recv() 118 if err == io.EOF { 119 logger.Debug("close conn") 120 waitGroup.Done() 121 break loop 122 } 123 if rev != nil { 124 if err := handle(rev); err != nil { 125 logger.Warn("fail to handle", "err", err) 126 waitGroup.Done() 127 break loop 128 } 129 } 130 } 131 } 132 133 waitGroup.Wait() 134 } 135 136 func (gkc *gKlaytnClient) handleBiCall(stream KlaytnNode_BiCallClient, request func() (*RPCRequest, error), handle func(response *RPCResponse) error) { 137 var waitGroup sync.WaitGroup 138 waitGroup.Add(2) 139 140 go func() { 141 for { 142 req, err := request() 143 if err != nil { 144 logger.Warn("fail to make request", "err", err) 145 waitGroup.Done() 146 return 147 } 148 if err := stream.Send(req); err != nil { 149 logger.Warn("fail to send request", "err", err) 150 waitGroup.Done() 151 return 152 } 153 time.Sleep(1 * time.Second) 154 } 155 }() 156 157 go func() { 158 for { 159 time.Sleep(1 * time.Second) 160 var recv RPCResponse 161 if err := stream.RecvMsg(&recv); err != nil { 162 logger.Warn("fail to recv response", "err", err) 163 waitGroup.Done() 164 } 165 166 if err := handle(&recv); err != nil { 167 logger.Warn("fail to handle response", "err", err) 168 waitGroup.Done() 169 } 170 } 171 }() 172 173 waitGroup.Wait() 174 } 175 176 func (gkc *gKlaytnClient) Close() { 177 if gkc.cancel != nil { 178 gkc.cancel() 179 } 180 181 if gkc.conn != nil { 182 if err := gkc.conn.Close(); err != nil { 183 logger.Warn("fail to close conn", "err", err) 184 } 185 } 186 }