gopkg.in/dedis/onet.v2@v2.0.0-20181115163211-c8f3724038a7/server.go (about)

     1  package onet
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"runtime"
     8  	"sort"
     9  	"strconv"
    10  	"strings"
    11  	"sync"
    12  	"time"
    13  
    14  	"gopkg.in/dedis/kyber.v2"
    15  	"gopkg.in/dedis/onet.v2/cfgpath"
    16  	"gopkg.in/dedis/onet.v2/log"
    17  	"gopkg.in/dedis/onet.v2/network"
    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  	v := Version
   115  	if gitTag != "" {
   116  		v += "-"
   117  		v += gitTag
   118  	}
   119  
   120  	a := c.serviceManager.availableServices()
   121  	sort.Strings(a)
   122  
   123  	st := &Status{Field: map[string]string{
   124  		"Available_Services": strings.Join(a, ","),
   125  		"TX_bytes":           strconv.FormatUint(c.Router.Tx(), 10),
   126  		"RX_bytes":           strconv.FormatUint(c.Router.Rx(), 10),
   127  		"Uptime":             time.Now().Sub(c.started).String(),
   128  		"System": fmt.Sprintf("%s/%s/%s", runtime.GOOS, runtime.GOARCH,
   129  			runtime.Version()),
   130  		"Version":     v,
   131  		"Host":        c.ServerIdentity.Address.Host(),
   132  		"Port":        c.ServerIdentity.Address.Port(),
   133  		"Description": c.ServerIdentity.Description,
   134  		"ConnType":    string(c.ServerIdentity.Address.ConnType()),
   135  	}}
   136  
   137  	goverOnce.Do(func() {
   138  		v, err := version.ReadExe(os.Args[0])
   139  		if err == nil {
   140  			gover = v
   141  			goverOk = true
   142  		}
   143  	})
   144  
   145  	if goverOk {
   146  		st.Field["GoRelease"] = gover.Release
   147  		st.Field["GoModuleInfo"] = gover.ModuleInfo
   148  	}
   149  
   150  	return st
   151  }
   152  
   153  // Close closes the overlay and the Router
   154  func (c *Server) Close() error {
   155  	c.Lock()
   156  	if c.IsStarted {
   157  		c.closeitChannel <- true
   158  		c.IsStarted = false
   159  	}
   160  	c.Unlock()
   161  
   162  	// For all services that have `TestClose` defined, call it to make
   163  	// sure they are able to clean up. This should only be used for tests!
   164  	c.serviceManager.servicesMutex.Lock()
   165  	var wg sync.WaitGroup
   166  	for _, serv := range c.serviceManager.services {
   167  		wg.Add(1)
   168  		go func(s Service) {
   169  			defer wg.Done()
   170  			c, ok := s.(TestClose)
   171  			if ok {
   172  				c.TestClose()
   173  			}
   174  		}(serv)
   175  	}
   176  	c.serviceManager.servicesMutex.Unlock()
   177  	wg.Wait()
   178  	c.WebSocket.stop()
   179  	c.overlay.Close()
   180  	err := c.serviceManager.closeDatabase()
   181  	if err != nil {
   182  		log.Lvl3("Error closing database: " + err.Error())
   183  	}
   184  	err = c.Router.Stop()
   185  	log.Lvl3("Host Close", c.ServerIdentity.Address, "listening?", c.Router.Listening())
   186  	return err
   187  }
   188  
   189  // Address returns the address used by the Router.
   190  func (c *Server) Address() network.Address {
   191  	return c.ServerIdentity.Address
   192  }
   193  
   194  // Service returns the service with the given name.
   195  func (c *Server) Service(name string) Service {
   196  	return c.serviceManager.service(name)
   197  }
   198  
   199  // GetService is kept for backward-compatibility.
   200  func (c *Server) GetService(name string) Service {
   201  	log.Warn("This method is deprecated - use `Server.Service` instead")
   202  	return c.Service(name)
   203  }
   204  
   205  // ProtocolRegister will sign up a new protocol to this Server.
   206  // It returns the ID of the protocol.
   207  func (c *Server) ProtocolRegister(name string, protocol NewProtocol) (ProtocolID, error) {
   208  	return c.protocols.Register(name, protocol)
   209  }
   210  
   211  // protocolInstantiate instantiate a protocol from its ID
   212  func (c *Server) protocolInstantiate(protoID ProtocolID, tni *TreeNodeInstance) (ProtocolInstance, error) {
   213  	fn, ok := c.protocols.instantiators[c.protocols.ProtocolIDToName(protoID)]
   214  	if !ok {
   215  		return nil, errors.New("No protocol constructor with this ID")
   216  	}
   217  	return fn(tni)
   218  }
   219  
   220  // Start makes the router and the WebSocket listen on their respective
   221  // ports. It returns once all servers are started.
   222  func (c *Server) Start() {
   223  	InformServerStarted()
   224  	c.started = time.Now()
   225  	if !c.Quiet {
   226  		log.Lvlf1("Starting server at %s on address %s with public key %s",
   227  			c.started.Format("2006-01-02 15:04:05"),
   228  			c.ServerIdentity.Address, c.ServerIdentity.Public)
   229  	}
   230  	go c.Router.Start()
   231  	go c.WebSocket.start()
   232  	for !c.Router.Listening() || !c.WebSocket.Listening() {
   233  		time.Sleep(50 * time.Millisecond)
   234  	}
   235  	c.Lock()
   236  	c.IsStarted = true
   237  	c.Unlock()
   238  	// Wait for closing of the channel
   239  	<-c.closeitChannel
   240  }
   241  
   242  // StartInBackground starts the services and returns once everything
   243  // is up and running.
   244  func (c *Server) StartInBackground() {
   245  	go c.Start()
   246  	c.WaitStartup()
   247  }
   248  
   249  // WaitStartup can be called to ensure that the server is up and
   250  // running. It will loop and wait 50 milliseconds between each
   251  // test.
   252  func (c *Server) WaitStartup() {
   253  	for {
   254  		c.Lock()
   255  		s := c.IsStarted
   256  		c.Unlock()
   257  		if s {
   258  			return
   259  		}
   260  		time.Sleep(50 * time.Millisecond)
   261  	}
   262  }