github.com/ZuluSpl0it/Sia@v1.3.7/node/api/server/server.go (about)

     1  // Package server provides a server that can wrap a node and serve an http api
     2  // for interacting with the node.
     3  package server
     4  
     5  import (
     6  	"net"
     7  	"net/http"
     8  	"strings"
     9  
    10  	"github.com/NebulousLabs/Sia/modules"
    11  	"github.com/NebulousLabs/Sia/node"
    12  	"github.com/NebulousLabs/Sia/node/api"
    13  	"github.com/NebulousLabs/Sia/types"
    14  
    15  	"github.com/NebulousLabs/errors"
    16  )
    17  
    18  // A Server is a collection of siad modules that can be communicated with over
    19  // an http api.
    20  type Server struct {
    21  	api               *api.API
    22  	apiServer         *http.Server
    23  	done              chan struct{}
    24  	listener          net.Listener
    25  	node              *node.Node
    26  	requiredUserAgent string
    27  	serveErr          error
    28  	Dir               string
    29  }
    30  
    31  // serve listens for and handles API calls. It is a blocking function.
    32  func (srv *Server) serve() error {
    33  	// The server will run until an error is encountered or the listener is
    34  	// closed, via either the Close method or by signal handling.  Closing the
    35  	// listener will result in the benign error handled below.
    36  	err := srv.apiServer.Serve(srv.listener)
    37  	if err != nil && !strings.HasSuffix(err.Error(), "use of closed network connection") {
    38  		return err
    39  	}
    40  	return nil
    41  }
    42  
    43  // Close closes the Server's listener, causing the HTTP server to shut down.
    44  func (srv *Server) Close() error {
    45  	// Stop accepting API requests.
    46  	err := srv.listener.Close()
    47  	// Wait for serve() to return and capture its error.
    48  	<-srv.done
    49  	err = errors.Compose(err, srv.serveErr)
    50  	// Shutdown modules.
    51  	err = errors.Compose(err, srv.node.Close())
    52  	return errors.AddContext(err, "error while closing server")
    53  }
    54  
    55  // APIAddress returns the underlying node's api address
    56  func (srv *Server) APIAddress() string {
    57  	return srv.listener.Addr().String()
    58  }
    59  
    60  // GatewayAddress returns the underlying node's gateway address
    61  func (srv *Server) GatewayAddress() modules.NetAddress {
    62  	return srv.node.Gateway.Address()
    63  }
    64  
    65  // HostPublicKey returns the host's public key or an error if the node is no
    66  // host.
    67  func (srv *Server) HostPublicKey() (types.SiaPublicKey, error) {
    68  	if srv.node.Host == nil {
    69  		return types.SiaPublicKey{}, errors.New("can't get public host key of a non-host node")
    70  	}
    71  	return srv.node.Host.PublicKey(), nil
    72  }
    73  
    74  // New creates a new API server from the provided modules. The API will
    75  // require authentication using HTTP basic auth if the supplied password is not
    76  // the empty string. Usernames are ignored for authentication. This type of
    77  // authentication sends passwords in plaintext and should therefore only be
    78  // used if the APIaddr is localhost.
    79  func New(APIaddr string, requiredUserAgent string, requiredPassword string, nodeParams node.NodeParams) (*Server, error) {
    80  	// Create the server listener.
    81  	listener, err := net.Listen("tcp", APIaddr)
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  
    86  	// Create the Sia node for the server.
    87  	node, err := node.New(nodeParams)
    88  	if err != nil {
    89  		return nil, errors.AddContext(err, "server is unable to create the Sia node")
    90  	}
    91  
    92  	// Create the api for the server.
    93  	api := api.New(requiredUserAgent, requiredPassword, node.ConsensusSet, node.Explorer, node.Gateway, node.Host, node.Miner, node.Renter, node.TransactionPool, node.Wallet)
    94  	srv := &Server{
    95  		api: api,
    96  		apiServer: &http.Server{
    97  			Handler: api,
    98  		},
    99  		done:              make(chan struct{}),
   100  		listener:          listener,
   101  		node:              node,
   102  		requiredUserAgent: requiredUserAgent,
   103  		Dir:               nodeParams.Dir,
   104  	}
   105  
   106  	// Spin up a goroutine that serves the API and closes srv.done when
   107  	// finished.
   108  	go func() {
   109  		srv.serveErr = srv.serve()
   110  		close(srv.done)
   111  	}()
   112  
   113  	return srv, nil
   114  }