github.com/klaytn/klaytn@v1.12.1/networks/grpc/gServer.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/http.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package grpc
    22  
    23  import (
    24  	"bufio"
    25  	"bytes"
    26  	"context"
    27  	"encoding/json"
    28  	"io"
    29  	"net"
    30  	"time"
    31  
    32  	"github.com/klaytn/klaytn/common"
    33  	"github.com/klaytn/klaytn/log"
    34  	"github.com/klaytn/klaytn/networks/rpc"
    35  	"google.golang.org/grpc"
    36  	"google.golang.org/grpc/reflection"
    37  )
    38  
    39  var logger = log.NewModuleLogger(log.NetworksGRPC)
    40  
    41  type Listener struct {
    42  	Addr       string
    43  	handler    *rpc.Server
    44  	grpcServer *grpc.Server
    45  }
    46  
    47  // grpcReadWriteNopCloser wraps an io.Reader and io.Writer with a NOP Close method.
    48  type grpcReadWriteNopCloser struct {
    49  	io.Reader
    50  	io.Writer
    51  }
    52  
    53  func (t *grpcReadWriteNopCloser) SetWriteDeadline(time.Time) error { return nil }
    54  
    55  // Close does nothing and returns always nil.
    56  func (t *grpcReadWriteNopCloser) Close() error {
    57  	return nil
    58  }
    59  
    60  // klaytnServer is an implementation of KlaytnNodeServer.
    61  type klaytnServer struct {
    62  	handler *rpc.Server
    63  }
    64  
    65  type grpcWriter struct {
    66  	writer   KlaytnNode_SubscribeServer
    67  	writeErr chan error
    68  }
    69  
    70  func (gw *grpcWriter) Write(p []byte) (n int, err error) {
    71  	resp := &RPCResponse{Payload: p}
    72  	if err := gw.writer.Send(resp); err != nil {
    73  		if gw.writeErr != nil {
    74  			gw.writeErr <- err
    75  		}
    76  		return 0, err
    77  	}
    78  	return len(p), nil
    79  }
    80  
    81  type bufWriter struct {
    82  	writer   io.Writer
    83  	writeErr chan error
    84  	writeOk  chan []byte
    85  }
    86  
    87  func (gw *bufWriter) Write(p []byte) (n int, err error) {
    88  	if _, err := gw.writer.Write(p); err != nil {
    89  		gw.writeErr <- err
    90  		return 0, err
    91  	}
    92  	gw.writeOk <- p
    93  	return len(p), nil
    94  }
    95  
    96  // BiCall handles bidirectional communication between client and server.
    97  func (kns *klaytnServer) BiCall(stream KlaytnNode_BiCallServer) error {
    98  	for {
    99  		request, err := stream.Recv()
   100  		if err == io.EOF {
   101  			return nil
   102  		}
   103  		if err != nil {
   104  			logger.Error("error reading the request", "err", err)
   105  			return err
   106  		}
   107  
   108  		preader := bytes.NewReader(request.Params)
   109  
   110  		// Create a custom encode/decode pair to enforce payload size and number encoding
   111  		encoder := func(v interface{}) error {
   112  			msg, err := json.Marshal(v)
   113  			if err != nil {
   114  				return err
   115  			}
   116  			resp := &RPCResponse{Payload: msg}
   117  			err = stream.Send(resp)
   118  			if err != nil {
   119  				return err
   120  			}
   121  			return err
   122  		}
   123  		decoder := func(v interface{}) error {
   124  			dec := json.NewDecoder(preader)
   125  			dec.UseNumber()
   126  			return dec.Decode(v)
   127  		}
   128  
   129  		ctx := context.Background()
   130  
   131  		reader := bufio.NewReaderSize(preader, common.MaxRequestContentLength)
   132  		kns.handler.ServeSingleRequest(ctx, rpc.NewFuncCodec(&grpcReadWriteNopCloser{reader, &grpcWriter{stream, nil}}, encoder, decoder))
   133  	}
   134  }
   135  
   136  // only server can send message to client repeatedly
   137  func (kns *klaytnServer) Subscribe(request *RPCRequest, stream KlaytnNode_SubscribeServer) error {
   138  	var (
   139  		writeErr = make(chan error, 1)
   140  		readErr  = make(chan error, 1)
   141  	)
   142  
   143  	preader := bytes.NewReader(request.Params)
   144  
   145  	// Create a custom encode/decode pair to enforce payload size and number encoding
   146  	encoder := func(v interface{}) error {
   147  		msg, err := json.Marshal(v)
   148  		if err != nil {
   149  			return err
   150  		}
   151  		resp := &RPCResponse{Payload: msg}
   152  		err = stream.Send(resp)
   153  		if err != nil {
   154  			writeErr <- err
   155  			return err
   156  		}
   157  		return err
   158  	}
   159  	decoder := func(v interface{}) error {
   160  		dec := json.NewDecoder(preader)
   161  		dec.UseNumber()
   162  		err := dec.Decode(v)
   163  		if err != nil {
   164  			readErr <- err
   165  		}
   166  		return err
   167  	}
   168  
   169  	ctx := context.Background()
   170  
   171  	reader := bufio.NewReaderSize(preader, common.MaxRequestContentLength)
   172  	kns.handler.ServeSingleRequest(ctx, rpc.NewFuncCodec(&grpcReadWriteNopCloser{reader, &grpcWriter{stream, writeErr}}, encoder, decoder))
   173  
   174  	var err error
   175  loop:
   176  	for {
   177  		select {
   178  		case err = <-writeErr:
   179  			logger.Warn("fail to write", "err", err)
   180  			break loop
   181  		case err = <-readErr:
   182  			logger.Warn("fail to read", "err", err)
   183  			break loop
   184  		}
   185  	}
   186  
   187  	return nil
   188  }
   189  
   190  // general RPC call, such as one-to-one communication
   191  func (kns *klaytnServer) Call(ctx context.Context, request *RPCRequest) (*RPCResponse, error) {
   192  	var (
   193  		err      error
   194  		writeErr = make(chan error, 1)
   195  		readErr  = make(chan error, 1)
   196  		writeOk  = make(chan []byte, 1)
   197  	)
   198  
   199  	preader := bytes.NewReader(request.Params)
   200  
   201  	var res bytes.Buffer
   202  	writer := &bufWriter{&res, writeErr, writeOk}
   203  
   204  	// Create a custom encode/decode pair to enforce payload size and number encoding
   205  	encoder := func(v interface{}) error {
   206  		msg, err := json.Marshal(v)
   207  		if err != nil {
   208  			return err
   209  		}
   210  		_, err = writer.Write(msg)
   211  		if err != nil {
   212  			writeErr <- err
   213  			return err
   214  		}
   215  		return err
   216  	}
   217  	decoder := func(v interface{}) error {
   218  		dec := json.NewDecoder(preader)
   219  		dec.UseNumber()
   220  		err := dec.Decode(v)
   221  		if err != nil {
   222  			readErr <- err
   223  		}
   224  		return err
   225  	}
   226  
   227  	reader := bufio.NewReaderSize(preader, common.MaxRequestContentLength)
   228  	kns.handler.ServeSingleRequest(ctx, rpc.NewFuncCodec(&grpcReadWriteNopCloser{reader, writer}, encoder, decoder))
   229  loop:
   230  	for {
   231  		select {
   232  		case _ = <-writeOk:
   233  			break loop
   234  		case err = <-writeErr:
   235  			logger.Error("fail to write", "err", err)
   236  			break loop
   237  		case err = <-readErr:
   238  			logger.Error("fail to read", "err", err)
   239  			break loop
   240  		}
   241  	}
   242  
   243  	if err == nil {
   244  		return &RPCResponse{Payload: res.Bytes()}, nil
   245  	} else {
   246  		return &RPCResponse{Payload: []byte("")}, err
   247  	}
   248  }
   249  
   250  // SetRPCServer sets the RPC server.
   251  func (gs *Listener) SetRPCServer(handler *rpc.Server) {
   252  	gs.handler = handler
   253  }
   254  
   255  func (gs *Listener) Start() {
   256  	lis, err := net.Listen("tcp", gs.Addr)
   257  	if err != nil {
   258  		// TODO-Klaytn-gRPC Need to handle err
   259  		logger.Error("failed to listen", "err", err)
   260  	}
   261  	gs.grpcServer = grpc.NewServer()
   262  
   263  	RegisterKlaytnNodeServer(gs.grpcServer, &klaytnServer{handler: gs.handler})
   264  
   265  	// Register reflection service on gRPC server.
   266  	reflection.Register(gs.grpcServer)
   267  	if err := gs.grpcServer.Serve(lis); err != nil {
   268  		// TODO-Klaytn-gRPC Need to handle err
   269  		logger.Error("failed to serve", "err", err)
   270  	}
   271  }
   272  
   273  func (gs *Listener) Stop() {
   274  	if gs.grpcServer != nil {
   275  		gs.grpcServer.Stop()
   276  	}
   277  }