github.com/core-coin/go-core/v2@v2.1.9/node/api.go (about)

     1  // Copyright 2015 by the Authors
     2  // This file is part of the go-core library.
     3  //
     4  // The go-core 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-core 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-core library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package node
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"strings"
    23  
    24  	"github.com/core-coin/go-core/v2/common/hexutil"
    25  	"github.com/core-coin/go-core/v2/crypto"
    26  	"github.com/core-coin/go-core/v2/internal/debug"
    27  	"github.com/core-coin/go-core/v2/p2p"
    28  	"github.com/core-coin/go-core/v2/p2p/enode"
    29  	"github.com/core-coin/go-core/v2/rpc"
    30  )
    31  
    32  // apis returns the collection of built-in RPC APIs.
    33  func (n *Node) apis() []rpc.API {
    34  	return []rpc.API{
    35  		{
    36  			Namespace: "admin",
    37  			Version:   "1.0",
    38  			Service:   &privateAdminAPI{n},
    39  		}, {
    40  			Namespace: "admin",
    41  			Version:   "1.0",
    42  			Service:   &publicAdminAPI{n},
    43  			Public:    true,
    44  		}, {
    45  			Namespace: "debug",
    46  			Version:   "1.0",
    47  			Service:   debug.Handler,
    48  		}, {
    49  			Namespace: "web3",
    50  			Version:   "1.0",
    51  			Service:   &publicWeb3API{n},
    52  			Public:    true,
    53  		},
    54  	}
    55  }
    56  
    57  // privateAdminAPI is the collection of administrative API methods exposed only
    58  // over a secure RPC channel.
    59  type privateAdminAPI struct {
    60  	node *Node // Node interfaced by this API
    61  }
    62  
    63  // AddPeer requests connecting to a remote node, and also maintaining the new
    64  // connection at all times, even reconnecting if it is lost.
    65  func (api *privateAdminAPI) AddPeer(url string) (bool, error) {
    66  	// Make sure the server is running, fail otherwise
    67  	server := api.node.Server()
    68  	if server == nil {
    69  		return false, ErrNodeStopped
    70  	}
    71  	// Try to add the url as a static peer and return
    72  	node, err := enode.Parse(enode.ValidSchemes, url)
    73  	if err != nil {
    74  		return false, fmt.Errorf("invalid enode: %v", err)
    75  	}
    76  	server.AddPeer(node)
    77  	return true, nil
    78  }
    79  
    80  // RemovePeer disconnects from a remote node if the connection exists
    81  func (api *privateAdminAPI) RemovePeer(url string) (bool, error) {
    82  	// Make sure the server is running, fail otherwise
    83  	server := api.node.Server()
    84  	if server == nil {
    85  		return false, ErrNodeStopped
    86  	}
    87  	// Try to remove the url as a static peer and return
    88  	node, err := enode.Parse(enode.ValidSchemes, url)
    89  	if err != nil {
    90  		return false, fmt.Errorf("invalid enode: %v", err)
    91  	}
    92  	server.RemovePeer(node)
    93  	return true, nil
    94  }
    95  
    96  // AddTrustedPeer allows a remote node to always connect, even if slots are full
    97  func (api *privateAdminAPI) AddTrustedPeer(url string) (bool, error) {
    98  	// Make sure the server is running, fail otherwise
    99  	server := api.node.Server()
   100  	if server == nil {
   101  		return false, ErrNodeStopped
   102  	}
   103  	node, err := enode.Parse(enode.ValidSchemes, url)
   104  	if err != nil {
   105  		return false, fmt.Errorf("invalid enode: %v", err)
   106  	}
   107  	server.AddTrustedPeer(node)
   108  	return true, nil
   109  }
   110  
   111  // RemoveTrustedPeer removes a remote node from the trusted peer set, but it
   112  // does not disconnect it automatically.
   113  func (api *privateAdminAPI) RemoveTrustedPeer(url string) (bool, error) {
   114  	// Make sure the server is running, fail otherwise
   115  	server := api.node.Server()
   116  	if server == nil {
   117  		return false, ErrNodeStopped
   118  	}
   119  	node, err := enode.Parse(enode.ValidSchemes, url)
   120  	if err != nil {
   121  		return false, fmt.Errorf("invalid enode: %v", err)
   122  	}
   123  	server.RemoveTrustedPeer(node)
   124  	return true, nil
   125  }
   126  
   127  // PeerEvents creates an RPC subscription which receives peer events from the
   128  // node's p2p.Server
   129  func (api *privateAdminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription, error) {
   130  	// Make sure the server is running, fail otherwise
   131  	server := api.node.Server()
   132  	if server == nil {
   133  		return nil, ErrNodeStopped
   134  	}
   135  
   136  	// Create the subscription
   137  	notifier, supported := rpc.NotifierFromContext(ctx)
   138  	if !supported {
   139  		return nil, rpc.ErrNotificationsUnsupported
   140  	}
   141  	rpcSub := notifier.CreateSubscription()
   142  
   143  	go func() {
   144  		events := make(chan *p2p.PeerEvent)
   145  		sub := server.SubscribeEvents(events)
   146  		defer sub.Unsubscribe()
   147  
   148  		for {
   149  			select {
   150  			case event := <-events:
   151  				notifier.Notify(rpcSub.ID, event)
   152  			case <-sub.Err():
   153  				return
   154  			case <-rpcSub.Err():
   155  				return
   156  			case <-notifier.Closed():
   157  				return
   158  			}
   159  		}
   160  	}()
   161  
   162  	return rpcSub, nil
   163  }
   164  
   165  // StartRPC starts the HTTP RPC API server.
   166  func (api *privateAdminAPI) StartRPC(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) {
   167  	api.node.lock.Lock()
   168  	defer api.node.lock.Unlock()
   169  
   170  	// Determine host and port.
   171  	if host == nil {
   172  		h := DefaultHTTPHost
   173  		if api.node.config.HTTPHost != "" {
   174  			h = api.node.config.HTTPHost
   175  		}
   176  		host = &h
   177  	}
   178  	if port == nil {
   179  		port = &api.node.config.HTTPPort
   180  	}
   181  
   182  	// Determine config.
   183  	config := httpConfig{
   184  		CorsAllowedOrigins: api.node.config.HTTPCors,
   185  		Vhosts:             api.node.config.HTTPVirtualHosts,
   186  		Modules:            api.node.config.HTTPModules,
   187  	}
   188  	if cors != nil {
   189  		config.CorsAllowedOrigins = nil
   190  		for _, origin := range strings.Split(*cors, ",") {
   191  			config.CorsAllowedOrigins = append(config.CorsAllowedOrigins, strings.TrimSpace(origin))
   192  		}
   193  	}
   194  	if vhosts != nil {
   195  		config.Vhosts = nil
   196  		for _, vhost := range strings.Split(*host, ",") {
   197  			config.Vhosts = append(config.Vhosts, strings.TrimSpace(vhost))
   198  		}
   199  	}
   200  	if apis != nil {
   201  		config.Modules = nil
   202  		for _, m := range strings.Split(*apis, ",") {
   203  			config.Modules = append(config.Modules, strings.TrimSpace(m))
   204  		}
   205  	}
   206  
   207  	if err := api.node.http.setListenAddr(*host, *port); err != nil {
   208  		return false, err
   209  	}
   210  	if err := api.node.http.enableRPC(api.node.rpcAPIs, config); err != nil {
   211  		return false, err
   212  	}
   213  	if err := api.node.http.start(); err != nil {
   214  		return false, err
   215  	}
   216  	return true, nil
   217  }
   218  
   219  // StopRPC shuts down the HTTP server.
   220  func (api *privateAdminAPI) StopRPC() (bool, error) {
   221  	api.node.http.stop()
   222  	return true, nil
   223  }
   224  
   225  // StartWS starts the websocket RPC API server.
   226  func (api *privateAdminAPI) StartWS(host *string, port *int, allowedOrigins *string, apis *string) (bool, error) {
   227  	api.node.lock.Lock()
   228  	defer api.node.lock.Unlock()
   229  
   230  	// Determine host and port.
   231  	if host == nil {
   232  		h := DefaultWSHost
   233  		if api.node.config.WSHost != "" {
   234  			h = api.node.config.WSHost
   235  		}
   236  		host = &h
   237  	}
   238  	if port == nil {
   239  		port = &api.node.config.WSPort
   240  	}
   241  
   242  	// Determine config.
   243  	config := wsConfig{
   244  		Modules: api.node.config.WSModules,
   245  		Origins: api.node.config.WSOrigins,
   246  		// ExposeAll: api.node.config.WSExposeAll,
   247  	}
   248  	if apis != nil {
   249  		config.Modules = nil
   250  		for _, m := range strings.Split(*apis, ",") {
   251  			config.Modules = append(config.Modules, strings.TrimSpace(m))
   252  		}
   253  	}
   254  	if allowedOrigins != nil {
   255  		config.Origins = nil
   256  		for _, origin := range strings.Split(*allowedOrigins, ",") {
   257  			config.Origins = append(config.Origins, strings.TrimSpace(origin))
   258  		}
   259  	}
   260  
   261  	// Enable WebSocket on the server.
   262  	server := api.node.wsServerForPort(*port, false)
   263  	if err := server.setListenAddr(*host, *port); err != nil {
   264  		return false, err
   265  	}
   266  	openApis, _ := api.node.GetAPIs()
   267  	if err := server.enableWS(openApis, config); err != nil {
   268  		return false, err
   269  	}
   270  	if err := server.start(); err != nil {
   271  		return false, err
   272  	}
   273  	api.node.http.log.Info("WebSocket endpoint opened", "url", api.node.WSEndpoint())
   274  	return true, nil
   275  }
   276  
   277  // StopWS terminates all WebSocket servers.
   278  func (api *privateAdminAPI) StopWS() (bool, error) {
   279  	api.node.http.stopWS()
   280  	api.node.ws.stop()
   281  	return true, nil
   282  }
   283  
   284  // publicAdminAPI is the collection of administrative API methods exposed over
   285  // both secure and unsecure RPC channels.
   286  type publicAdminAPI struct {
   287  	node *Node // Node interfaced by this API
   288  }
   289  
   290  // Peers retrieves all the information we know about each individual peer at the
   291  // protocol granularity.
   292  func (api *publicAdminAPI) Peers() ([]*p2p.PeerInfo, error) {
   293  	server := api.node.Server()
   294  	if server == nil {
   295  		return nil, ErrNodeStopped
   296  	}
   297  	return server.PeersInfo(), nil
   298  }
   299  
   300  // NodeInfo retrieves all the information we know about the host node at the
   301  // protocol granularity.
   302  func (api *publicAdminAPI) NodeInfo() (*p2p.NodeInfo, error) {
   303  	server := api.node.Server()
   304  	if server == nil {
   305  		return nil, ErrNodeStopped
   306  	}
   307  	return server.NodeInfo(), nil
   308  }
   309  
   310  // Datadir retrieves the current data directory the node is using.
   311  func (api *publicAdminAPI) Datadir() string {
   312  	return api.node.DataDir()
   313  }
   314  
   315  // publicWeb3API offers helper utils
   316  type publicWeb3API struct {
   317  	stack *Node
   318  }
   319  
   320  // ClientVersion returns the node name
   321  func (s *publicWeb3API) ClientVersion() string {
   322  	return s.stack.Server().Name
   323  }
   324  
   325  // Sha3 applies the core sha3 implementation on the input.
   326  // It assumes the input is hex encoded.
   327  func (s *publicWeb3API) Sha3(input hexutil.Bytes) hexutil.Bytes {
   328  	return crypto.SHA3(input)
   329  }