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