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 }