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  }