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 }