github.com/intfoundation/intchain@v0.0.0-20220727031208-4316ad31ca73/cmd/utils/server.go (about)

     1  package utils
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/intfoundation/intchain/log"
     6  	"github.com/intfoundation/intchain/node"
     7  	"github.com/intfoundation/intchain/rpc"
     8  	"gopkg.in/urfave/cli.v1"
     9  	"net"
    10  	"net/http"
    11  	"strings"
    12  )
    13  
    14  var (
    15  	httpListener       net.Listener
    16  	httpMux            *http.ServeMux
    17  	httpHandlerMapping map[string]*rpc.Server
    18  
    19  	wsListener       net.Listener
    20  	wsMux            *http.ServeMux
    21  	wsOrigins        []string
    22  	wsHandlerMapping map[string]*rpc.Server
    23  )
    24  
    25  func StartRPC(ctx *cli.Context) error {
    26  
    27  	// Use Default Config
    28  	rpcConfig := node.DefaultConfig
    29  
    30  	// Setup the config from context
    31  	SetHTTP(ctx, &rpcConfig)
    32  	SetWS(ctx, &rpcConfig)
    33  	wsOrigins = rpcConfig.WSOrigins
    34  
    35  	httperr := startHTTP(rpcConfig.HTTPEndpoint(), rpcConfig.HTTPCors, rpcConfig.HTTPVirtualHosts, rpcConfig.HTTPTimeouts)
    36  	if httperr != nil {
    37  		return httperr
    38  	}
    39  
    40  	wserr := startWS(rpcConfig.WSEndpoint())
    41  	if wserr != nil {
    42  		return wserr
    43  	}
    44  
    45  	return nil
    46  }
    47  
    48  func StopRPC() {
    49  	// Stop HTTP Listener
    50  	if httpListener != nil {
    51  		httpAddr := httpListener.Addr().String()
    52  		httpListener.Close()
    53  		httpListener = nil
    54  		log.Info("HTTP endpoint closed", "url", fmt.Sprintf("http://%s", httpAddr))
    55  	}
    56  	if httpMux != nil {
    57  		for _, httpHandler := range httpHandlerMapping {
    58  			httpHandler.Stop()
    59  		}
    60  	}
    61  
    62  	// Stop WS Listener
    63  	if wsListener != nil {
    64  		wsAddr := wsListener.Addr().String()
    65  		wsListener.Close()
    66  		wsListener = nil
    67  		log.Info("WebSocket endpoint closed", "url", fmt.Sprintf("ws://%s", wsAddr))
    68  	}
    69  	if wsMux != nil {
    70  		for _, wsHandler := range wsHandlerMapping {
    71  			wsHandler.Stop()
    72  		}
    73  	}
    74  }
    75  
    76  func IsHTTPRunning() bool {
    77  	return httpListener != nil && httpMux != nil
    78  }
    79  
    80  func IsWSRunning() bool {
    81  	return wsListener != nil && wsMux != nil
    82  }
    83  
    84  func HookupHTTP(chainId string, httpHandler *rpc.Server) error {
    85  	if httpMux != nil {
    86  		log.Infof("Hookup HTTP for (chainId, http Handler): (%v, %v)", chainId, httpHandler)
    87  		if httpHandler != nil {
    88  			httpMux.Handle("/", httpHandler)
    89  			httpHandlerMapping[chainId] = httpHandler
    90  		}
    91  	}
    92  	return nil
    93  }
    94  
    95  func HookupWS(chainId string, wsHandler *rpc.Server) error {
    96  	if wsMux != nil {
    97  		log.Infof("Hookup WS for (chainId, ws Handler): (%v, %v)", chainId, wsHandler)
    98  		if wsHandler != nil {
    99  			wsMux.Handle("/", wsHandler.WebsocketHandler(wsOrigins))
   100  			wsHandlerMapping[chainId] = wsHandler
   101  		}
   102  	}
   103  	return nil
   104  }
   105  
   106  func startHTTP(endpoint string, cors []string, vhosts []string, timeouts rpc.HTTPTimeouts) error {
   107  	// Short circuit if the HTTP endpoint isn't being exposed
   108  	if endpoint == "" {
   109  		return nil
   110  	}
   111  
   112  	var err error
   113  	httpListener, httpMux, err = startIntChainHTTPEndpoint(endpoint, cors, vhosts, timeouts)
   114  	if err != nil {
   115  		return err
   116  	}
   117  	httpHandlerMapping = make(map[string]*rpc.Server)
   118  
   119  	log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%s", endpoint), "cors", strings.Join(cors, ","), "vhosts", strings.Join(vhosts, ","))
   120  	return nil
   121  }
   122  
   123  func startIntChainHTTPEndpoint(endpoint string, cors []string, vhosts []string, timeouts rpc.HTTPTimeouts) (net.Listener, *http.ServeMux, error) {
   124  	var (
   125  		listener net.Listener
   126  		err      error
   127  	)
   128  	if listener, err = net.Listen("tcp", endpoint); err != nil {
   129  		return nil, nil, err
   130  	}
   131  	mux := http.NewServeMux()
   132  	go rpc.NewHTTPServer(cors, vhosts, timeouts, mux).Serve(listener)
   133  	return listener, mux, err
   134  }
   135  
   136  func startWS(endpoint string) error {
   137  	// Short circuit if the WS endpoint isn't being exposed
   138  	if endpoint == "" {
   139  		return nil
   140  	}
   141  
   142  	var err error
   143  	wsListener, wsMux, err = startIntChainWSEndpoint(endpoint)
   144  	if err != nil {
   145  		return err
   146  	}
   147  	wsHandlerMapping = make(map[string]*rpc.Server)
   148  
   149  	log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", wsListener.Addr()))
   150  	return nil
   151  }
   152  
   153  func startIntChainWSEndpoint(endpoint string) (net.Listener, *http.ServeMux, error) {
   154  	var (
   155  		listener net.Listener
   156  		err      error
   157  	)
   158  	if listener, err = net.Listen("tcp", endpoint); err != nil {
   159  		return nil, nil, err
   160  	}
   161  	mux := http.NewServeMux()
   162  	wsServer := &http.Server{Handler: mux}
   163  	go wsServer.Serve(listener)
   164  	return listener, mux, err
   165  }