go.dedis.ch/onet/v3@v3.2.11-0.20210930124529-e36530bca7ef/server.go (about)

     1  package onet
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"runtime"
     7  	"sort"
     8  	"strconv"
     9  	"strings"
    10  	"sync"
    11  	"time"
    12  
    13  	"go.dedis.ch/kyber/v3"
    14  	"go.dedis.ch/onet/v3/cfgpath"
    15  	"go.dedis.ch/onet/v3/log"
    16  	"go.dedis.ch/onet/v3/network"
    17  	"golang.org/x/xerrors"
    18  	"rsc.io/goversion/version"
    19  )
    20  
    21  // Server connects the Router, the Overlay, and the Services together. It sets
    22  // up everything and returns once a working network has been set up.
    23  type Server struct {
    24  	// Our private-key
    25  	private kyber.Scalar
    26  	*network.Router
    27  	// Overlay handles the mapping from tree and entityList to ServerIdentity.
    28  	// It uses tokens to represent an unique ProtocolInstance in the system
    29  	overlay *Overlay
    30  	// lock associated to access trees
    31  	treesLock            sync.Mutex
    32  	serviceManager       *serviceManager
    33  	statusReporterStruct *statusReporterStruct
    34  	// protocols holds a map of all available protocols and how to create an
    35  	// instance of it
    36  	protocols *protocolStorage
    37  	// webservice
    38  	WebSocket *WebSocket
    39  	// when this node has been started
    40  	started time.Time
    41  	// once everything's up and running
    42  	closeitChannel chan bool
    43  	IsStarted      bool
    44  
    45  	suite network.Suite
    46  }
    47  
    48  func dbPathFromEnv() string {
    49  	p := os.Getenv("CONODE_SERVICE_PATH")
    50  	if p == "" {
    51  		p = cfgpath.GetDataPath("conode")
    52  	}
    53  	return p
    54  }
    55  
    56  // NewServer returns a fresh Server tied to a given Router.
    57  // If dbPath is "", the server will write its database to the default
    58  // location. If dbPath is != "", it is considered a temp dir, and the
    59  // DB is deleted on close.
    60  func newServer(s network.Suite, dbPath string, r *network.Router, pkey kyber.Scalar) *Server {
    61  	delDb := false
    62  	if dbPath == "" {
    63  		dbPath = dbPathFromEnv()
    64  		log.ErrFatal(os.MkdirAll(dbPath, 0750))
    65  	} else {
    66  		delDb = true
    67  	}
    68  
    69  	c := &Server{
    70  		private:              pkey,
    71  		statusReporterStruct: newStatusReporterStruct(),
    72  		Router:               r,
    73  		protocols:            newProtocolStorage(),
    74  		suite:                s,
    75  		closeitChannel:       make(chan bool),
    76  	}
    77  	c.overlay = NewOverlay(c)
    78  	c.WebSocket = NewWebSocket(r.ServerIdentity)
    79  	c.serviceManager = newServiceManager(c, c.overlay, dbPath, delDb)
    80  	c.statusReporterStruct.RegisterStatusReporter("Generic", c)
    81  	return c
    82  }
    83  
    84  // NewServerTCP returns a new Server out of a private-key and its related
    85  // public key within the ServerIdentity. The server will use a default
    86  // TcpRouter as Router.
    87  func NewServerTCP(e *network.ServerIdentity, suite network.Suite) *Server {
    88  	return NewServerTCPWithListenAddr(e, suite, "")
    89  }
    90  
    91  // NewServerTCPWithListenAddr returns a new Server out of a private-key and
    92  // its related public key within the ServerIdentity. The server will use a
    93  // TcpRouter listening on the given address as Router.
    94  func NewServerTCPWithListenAddr(e *network.ServerIdentity, suite network.Suite,
    95  	listenAddr string) *Server {
    96  	r, err := network.NewTCPRouterWithListenAddr(e, suite, listenAddr)
    97  	log.ErrFatal(err)
    98  	return newServer(suite, "", r, e.GetPrivate())
    99  }
   100  
   101  // Suite can (and should) be used to get the underlying Suite.
   102  // Currently the suite is hardcoded into the network library.
   103  // Don't use network.Suite but Host's Suite function instead if possible.
   104  func (c *Server) Suite() network.Suite {
   105  	return c.suite
   106  }
   107  
   108  var gover version.Version
   109  var goverOnce sync.Once
   110  var goverOk = false
   111  
   112  // GetStatus is a function that returns the status report of the server.
   113  func (c *Server) GetStatus() *Status {
   114  	a := c.serviceManager.availableServices()
   115  	sort.Strings(a)
   116  
   117  	st := &Status{Field: map[string]string{
   118  		"Available_Services": strings.Join(a, ","),
   119  		"TX_bytes":           strconv.FormatUint(c.Router.Tx(), 10),
   120  		"RX_bytes":           strconv.FormatUint(c.Router.Rx(), 10),
   121  		"Uptime":             time.Now().Sub(c.started).String(),
   122  		"System": fmt.Sprintf("%s/%s/%s", runtime.GOOS, runtime.GOARCH,
   123  			runtime.Version()),
   124  		"Host":        c.ServerIdentity.Address.Host(),
   125  		"Port":        c.ServerIdentity.Address.Port(),
   126  		"Description": c.ServerIdentity.Description,
   127  		"ConnType":    string(c.ServerIdentity.Address.ConnType()),
   128  		"GoRoutines":  fmt.Sprintf("%v", runtime.NumGoroutine()),
   129  	}}
   130  
   131  	goverOnce.Do(func() {
   132  		v, err := version.ReadExe(os.Args[0])
   133  		if err == nil {
   134  			gover = v
   135  			goverOk = true
   136  		}
   137  	})
   138  
   139  	if goverOk {
   140  		st.Field["GoRelease"] = gover.Release
   141  		st.Field["GoModuleInfo"] = gover.ModuleInfo
   142  	}
   143  
   144  	return st
   145  }
   146  
   147  // Close closes the overlay and the Router
   148  func (c *Server) Close() error {
   149  	c.Lock()
   150  	if c.IsStarted {
   151  		c.closeitChannel <- true
   152  		c.IsStarted = false
   153  	}
   154  	c.Unlock()
   155  
   156  	err := c.Router.Stop()
   157  	if err != nil {
   158  		err = xerrors.Errorf("stopping: %v", err)
   159  		log.Error("While stopping router:", err)
   160  	}
   161  	c.WebSocket.stop()
   162  	c.overlay.Close()
   163  	err = c.serviceManager.closeDatabase()
   164  	if err != nil {
   165  		err = xerrors.Errorf("closing db: %v", err)
   166  		log.Lvl3("Error closing database: " + err.Error())
   167  	}
   168  	log.Lvl3("Host Close", c.ServerIdentity.Address, "listening?", c.Router.Listening())
   169  	return err
   170  }
   171  
   172  // Address returns the address used by the Router.
   173  func (c *Server) Address() network.Address {
   174  	return c.ServerIdentity.Address
   175  }
   176  
   177  // Service returns the service with the given name.
   178  func (c *Server) Service(name string) Service {
   179  	return c.serviceManager.service(name)
   180  }
   181  
   182  // GetService is kept for backward-compatibility.
   183  func (c *Server) GetService(name string) Service {
   184  	log.Warn("This method is deprecated - use `Server.Service` instead")
   185  	return c.Service(name)
   186  }
   187  
   188  // ProtocolRegister will sign up a new protocol to this Server.
   189  // It returns the ID of the protocol.
   190  func (c *Server) ProtocolRegister(name string, protocol NewProtocol) (ProtocolID, error) {
   191  	id, err := c.protocols.Register(name, protocol)
   192  	if err != nil {
   193  		return id, xerrors.Errorf("registering protocol: %v", err)
   194  	}
   195  	return id, nil
   196  }
   197  
   198  // protocolInstantiate instantiate a protocol from its ID
   199  func (c *Server) protocolInstantiate(protoID ProtocolID, tni *TreeNodeInstance) (ProtocolInstance, error) {
   200  	fn, ok := c.protocols.instantiators[c.protocols.ProtocolIDToName(protoID)]
   201  	if !ok {
   202  		return nil, xerrors.New("No protocol constructor with this ID")
   203  	}
   204  	pi, err := fn(tni)
   205  	if err != nil {
   206  		return nil, xerrors.Errorf("creating protocol: %v", err)
   207  	}
   208  	return pi, nil
   209  }
   210  
   211  // Start makes the router and the WebSocket listen on their respective
   212  // ports. It returns once all servers are started.
   213  func (c *Server) Start() {
   214  	InformServerStarted()
   215  	c.started = time.Now()
   216  	if !c.Quiet {
   217  		log.Lvlf1("Starting server at %s on address %s",
   218  			c.started.Format("2006-01-02 15:04:05"),
   219  			c.ServerIdentity.Address)
   220  	}
   221  	go c.Router.Start()
   222  	go c.WebSocket.start()
   223  	for !c.Router.Listening() || !c.WebSocket.Listening() {
   224  		time.Sleep(50 * time.Millisecond)
   225  	}
   226  	c.Lock()
   227  	c.IsStarted = true
   228  	c.Unlock()
   229  	// Wait for closing of the channel
   230  	<-c.closeitChannel
   231  }
   232  
   233  // StartInBackground starts the services and returns once everything
   234  // is up and running.
   235  func (c *Server) StartInBackground() {
   236  	go c.Start()
   237  	c.WaitStartup()
   238  }
   239  
   240  // WaitStartup can be called to ensure that the server is up and
   241  // running. It will loop and wait 50 milliseconds between each
   242  // test.
   243  func (c *Server) WaitStartup() {
   244  	for {
   245  		c.Lock()
   246  		s := c.IsStarted
   247  		c.Unlock()
   248  		if s {
   249  			return
   250  		}
   251  		time.Sleep(50 * time.Millisecond)
   252  	}
   253  }
   254  
   255  // For all services that have `TestClose` defined, call it to make
   256  // sure they are able to clean up. This should only be used for tests!
   257  func (c *Server) callTestClose() {
   258  	wg := sync.WaitGroup{}
   259  	c.serviceManager.servicesMutex.Lock()
   260  	for _, serv := range c.serviceManager.services {
   261  		wg.Add(1)
   262  		go func(s Service) {
   263  			defer wg.Done()
   264  			c, ok := s.(TestClose)
   265  			if ok {
   266  				c.TestClose()
   267  			}
   268  		}(serv)
   269  	}
   270  	c.serviceManager.servicesMutex.Unlock()
   271  	wg.Wait()
   272  }