github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/rpc/comms/comms.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package comms
    18  
    19  import (
    20  	"io"
    21  	"net"
    22  
    23  	"fmt"
    24  	"strings"
    25  
    26  	"strconv"
    27  
    28  	"github.com/ethereum/go-ethereum/logger"
    29  	"github.com/ethereum/go-ethereum/logger/glog"
    30  	"github.com/ethereum/go-ethereum/rpc/codec"
    31  	"github.com/ethereum/go-ethereum/rpc/shared"
    32  )
    33  
    34  const (
    35  	maxHttpSizeReqLength = 1024 * 1024 // 1MB
    36  )
    37  
    38  var (
    39  	// List with all API's which are offered over the in proc interface by default
    40  	DefaultInProcApis = shared.AllApis
    41  
    42  	// List with all API's which are offered over the IPC interface by default
    43  	DefaultIpcApis = shared.AllApis
    44  
    45  	// List with API's which are offered over thr HTTP/RPC interface by default
    46  	DefaultHttpRpcApis = strings.Join([]string{
    47  		shared.DbApiName, shared.EthApiName, shared.NetApiName, shared.Web3ApiName,
    48  	}, ",")
    49  )
    50  
    51  type EthereumClient interface {
    52  	// Close underlying connection
    53  	Close()
    54  	// Send request
    55  	Send(interface{}) error
    56  	// Receive response
    57  	Recv() (interface{}, error)
    58  	// List with modules this client supports
    59  	SupportedModules() (map[string]string, error)
    60  }
    61  
    62  func handle(id int, conn net.Conn, api shared.EthereumApi, c codec.Codec) {
    63  	codec := c.New(conn)
    64  
    65  	for {
    66  		requests, isBatch, err := codec.ReadRequest()
    67  		if err == io.EOF {
    68  			codec.Close()
    69  			return
    70  		} else if err != nil {
    71  			codec.Close()
    72  			glog.V(logger.Debug).Infof("Closed IPC Conn %06d recv err - %v\n", id, err)
    73  			return
    74  		}
    75  
    76  		if isBatch {
    77  			responses := make([]*interface{}, len(requests))
    78  			responseCount := 0
    79  			for _, req := range requests {
    80  				res, err := api.Execute(req)
    81  				if req.Id != nil {
    82  					rpcResponse := shared.NewRpcResponse(req.Id, req.Jsonrpc, res, err)
    83  					responses[responseCount] = rpcResponse
    84  					responseCount += 1
    85  				}
    86  			}
    87  
    88  			err = codec.WriteResponse(responses[:responseCount])
    89  			if err != nil {
    90  				codec.Close()
    91  				glog.V(logger.Debug).Infof("Closed IPC Conn %06d send err - %v\n", id, err)
    92  				return
    93  			}
    94  		} else {
    95  			var rpcResponse interface{}
    96  			res, err := api.Execute(requests[0])
    97  
    98  			rpcResponse = shared.NewRpcResponse(requests[0].Id, requests[0].Jsonrpc, res, err)
    99  			err = codec.WriteResponse(rpcResponse)
   100  			if err != nil {
   101  				codec.Close()
   102  				glog.V(logger.Debug).Infof("Closed IPC Conn %06d send err - %v\n", id, err)
   103  				return
   104  			}
   105  		}
   106  	}
   107  }
   108  
   109  // Endpoint must be in the form of:
   110  // ${protocol}:${path}
   111  // e.g. ipc:/tmp/geth.ipc
   112  //      rpc:localhost:8545
   113  func ClientFromEndpoint(endpoint string, c codec.Codec) (EthereumClient, error) {
   114  	if strings.HasPrefix(endpoint, "ipc:") {
   115  		cfg := IpcConfig{
   116  			Endpoint: endpoint[4:],
   117  		}
   118  		return NewIpcClient(cfg, codec.JSON)
   119  	}
   120  
   121  	if strings.HasPrefix(endpoint, "rpc:") {
   122  		parts := strings.Split(endpoint, ":")
   123  		addr := "http://localhost"
   124  		port := uint(8545)
   125  		if len(parts) >= 3 {
   126  			addr = parts[1] + ":" + parts[2]
   127  		}
   128  
   129  		if len(parts) >= 4 {
   130  			p, err := strconv.Atoi(parts[3])
   131  
   132  			if err != nil {
   133  				return nil, err
   134  			}
   135  			port = uint(p)
   136  		}
   137  
   138  		cfg := HttpConfig{
   139  			ListenAddress: addr,
   140  			ListenPort:    port,
   141  		}
   142  
   143  		return NewHttpClient(cfg, codec.JSON), nil
   144  	}
   145  
   146  	return nil, fmt.Errorf("Invalid endpoint")
   147  }