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

     1  package onet
     2  
     3  import (
     4  	"crypto/sha256"
     5  	"errors"
     6  	"fmt"
     7  	"net/http"
     8  	"os"
     9  	"path"
    10  	"strconv"
    11  	"sync"
    12  
    13  	bolt "github.com/coreos/bbolt"
    14  	"gopkg.in/dedis/onet.v2/log"
    15  	"gopkg.in/dedis/onet.v2/network"
    16  	"gopkg.in/satori/go.uuid.v1"
    17  )
    18  
    19  func init() {
    20  	network.RegisterMessage(GenericConfig{})
    21  }
    22  
    23  // Service is a generic interface to define any type of services.
    24  // A Service has multiple roles:
    25  // * Processing websocket client requests with ProcessClientRequests
    26  // * Handling onet information to ProtocolInstances created with
    27  //  	NewProtocol
    28  // * Handling any kind of messages between Services between different hosts with
    29  //   	the Processor interface
    30  type Service interface {
    31  	// NewProtocol is called upon a ProtocolInstance's first message when Onet needs
    32  	// to instantiate the protocol. A Service is expected to manually create
    33  	// the ProtocolInstance it is using. If a Service returns (nil,nil), that
    34  	// means this Service lets Onet handle the protocol instance.
    35  	NewProtocol(*TreeNodeInstance, *GenericConfig) (ProtocolInstance, error)
    36  	// ProcessClientRequest is called when a message from an external
    37  	// client is received by the websocket for this service. The message is
    38  	// forwarded to the corresponding handler keyed by the path. If the
    39  	// handler is a normal one, i.e., a request-response handler, it
    40  	// returns a message in the first return value and the second
    41  	// (StreamingTunnel) will be set to nil. If the handler is a streaming
    42  	// handler, the first return value is set to nil but the second
    43  	// (StreamingTunnel) will exist. It should be used to stream messages
    44  	// to the client. See the StreamingTunnel documentation on how it
    45  	// should be used. The returned error will be formatted as a websocket
    46  	// error code 4000, using the string form of the error as the message.
    47  	ProcessClientRequest(req *http.Request, handler string, msg []byte) (reply []byte, tunnel *StreamingTunnel, err error)
    48  	// Processor makes a Service being able to handle any kind of packets
    49  	// directly from the network. It is used for inter service communications,
    50  	// which are mostly single packets with no or little interactions needed. If
    51  	// a complex logic is used for these messages, it's best to put that logic
    52  	// into a ProtocolInstance that the Service will launch, since there's nicer
    53  	// utilities for ProtocolInstance.
    54  	network.Processor
    55  }
    56  
    57  // NewServiceFunc is the type of a function that is used to instantiate a given Service
    58  // A service is initialized with a Server (to send messages to someone).
    59  type NewServiceFunc func(c *Context) (Service, error)
    60  
    61  // ServiceID is a type to represent a uuid for a Service
    62  type ServiceID uuid.UUID
    63  
    64  // String returns the string representation of this ServiceID
    65  func (s ServiceID) String() string {
    66  	return uuid.UUID(s).String()
    67  }
    68  
    69  // Equal returns true if and only if s2 equals this ServiceID.
    70  func (s ServiceID) Equal(s2 ServiceID) bool {
    71  	return uuid.Equal(uuid.UUID(s), uuid.UUID(s2))
    72  }
    73  
    74  // IsNil returns true iff the ServiceID is Nil
    75  func (s ServiceID) IsNil() bool {
    76  	return s.Equal(ServiceID(uuid.Nil))
    77  }
    78  
    79  // NilServiceID is the empty ServiceID
    80  var NilServiceID = ServiceID(uuid.Nil)
    81  
    82  // GenericConfig is a config that can hold any type of specific configs for
    83  // protocols. It is passed down to the service NewProtocol function.
    84  type GenericConfig struct {
    85  	Data []byte
    86  }
    87  
    88  // A serviceFactory is used to register a NewServiceFunc
    89  type serviceFactory struct {
    90  	constructors []serviceEntry
    91  	mutex        sync.RWMutex
    92  }
    93  
    94  // A serviceEntry holds all references to a service
    95  type serviceEntry struct {
    96  	constructor NewServiceFunc
    97  	serviceID   ServiceID
    98  	name        string
    99  }
   100  
   101  // ServiceFactory is the global service factory to instantiate Services
   102  var ServiceFactory = serviceFactory{
   103  	constructors: []serviceEntry{},
   104  }
   105  
   106  // Register takes a name and a function, then creates a ServiceID out of it and stores the
   107  // mapping and the creation function.
   108  func (s *serviceFactory) Register(name string, fn NewServiceFunc) (ServiceID, error) {
   109  	if !s.ServiceID(name).Equal(NilServiceID) {
   110  		return NilServiceID, fmt.Errorf("service %s already registered", name)
   111  	}
   112  	id := ServiceID(uuid.NewV5(uuid.NamespaceURL, name))
   113  	s.mutex.Lock()
   114  	defer s.mutex.Unlock()
   115  	s.constructors = append(s.constructors, serviceEntry{
   116  		constructor: fn,
   117  		serviceID:   id,
   118  		name:        name,
   119  	})
   120  	return id, nil
   121  }
   122  
   123  // Unregister - mainly for tests
   124  func (s *serviceFactory) Unregister(name string) error {
   125  	s.mutex.Lock()
   126  	defer s.mutex.Unlock()
   127  	index := -1
   128  	for i, c := range s.constructors {
   129  		if c.name == name {
   130  			index = i
   131  			break
   132  		}
   133  	}
   134  	if index < 0 {
   135  		return errors.New("Didn't find service " + name)
   136  	}
   137  	s.constructors = append(s.constructors[:index], s.constructors[index+1:]...)
   138  	return nil
   139  }
   140  
   141  // RegisterNewService is a wrapper around service factory
   142  func RegisterNewService(name string, fn NewServiceFunc) (ServiceID, error) {
   143  	return ServiceFactory.Register(name, fn)
   144  }
   145  
   146  // UnregisterService removes a service from the global pool.
   147  func UnregisterService(name string) error {
   148  	return ServiceFactory.Unregister(name)
   149  }
   150  
   151  // registeredServiceIDs returns all the services registered
   152  func (s *serviceFactory) registeredServiceIDs() []ServiceID {
   153  	s.mutex.RLock()
   154  	defer s.mutex.RUnlock()
   155  	var ids = make([]ServiceID, 0, len(s.constructors))
   156  	for _, c := range s.constructors {
   157  		ids = append(ids, c.serviceID)
   158  	}
   159  	return ids
   160  }
   161  
   162  // RegisteredServiceNames returns all the names of the services registered
   163  func (s *serviceFactory) RegisteredServiceNames() []string {
   164  	s.mutex.RLock()
   165  	defer s.mutex.RUnlock()
   166  	var names = make([]string, 0, len(s.constructors))
   167  	for _, n := range s.constructors {
   168  		names = append(names, n.name)
   169  	}
   170  	return names
   171  }
   172  
   173  // ServiceID returns the ServiceID out of the name of the service
   174  func (s *serviceFactory) ServiceID(name string) ServiceID {
   175  	s.mutex.RLock()
   176  	defer s.mutex.RUnlock()
   177  	for _, c := range s.constructors {
   178  		if name == c.name {
   179  			return c.serviceID
   180  		}
   181  	}
   182  	return NilServiceID
   183  }
   184  
   185  // Name returns the Name out of the ID
   186  func (s *serviceFactory) Name(id ServiceID) string {
   187  	s.mutex.RLock()
   188  	defer s.mutex.RUnlock()
   189  	for _, c := range s.constructors {
   190  		if id.Equal(c.serviceID) {
   191  			return c.name
   192  		}
   193  	}
   194  	return ""
   195  }
   196  
   197  // start launches a new service
   198  func (s *serviceFactory) start(name string, con *Context) (Service, error) {
   199  	s.mutex.RLock()
   200  	defer s.mutex.RUnlock()
   201  	for _, c := range s.constructors {
   202  		if name == c.name {
   203  			return c.constructor(con)
   204  		}
   205  	}
   206  	return nil, errors.New("Didn't find service " + name)
   207  }
   208  
   209  // serviceManager is the place where all instantiated services are stored
   210  // It gives access to: all the currently running services
   211  type serviceManager struct {
   212  	// the actual services
   213  	services map[ServiceID]Service
   214  	// making sure we're not racing for services
   215  	servicesMutex sync.Mutex
   216  	// the onet host
   217  	server *Server
   218  	// a bbolt database for all services
   219  	db     *bolt.DB
   220  	dbPath string
   221  	// should the db be deleted on close?
   222  	delDb bool
   223  	// the dispatcher can take registration of Processors
   224  	network.Dispatcher
   225  }
   226  
   227  // newServiceManager will create a serviceStore out of all the registered Service
   228  func newServiceManager(srv *Server, o *Overlay, dbPath string, delDb bool) *serviceManager {
   229  	services := make(map[ServiceID]Service)
   230  	s := &serviceManager{
   231  		services:   services,
   232  		server:     srv,
   233  		dbPath:     dbPath,
   234  		delDb:      delDb,
   235  		Dispatcher: network.NewRoutineDispatcher(),
   236  	}
   237  
   238  	s.updateDbFileName()
   239  
   240  	db, err := openDb(s.dbFileName())
   241  	if err != nil {
   242  		log.Panic("Failed to create new database: " + err.Error())
   243  	}
   244  	s.db = db
   245  
   246  	for name, inst := range protocols.instantiators {
   247  		log.Lvl4("Registering global protocol", name)
   248  		srv.ProtocolRegister(name, inst)
   249  	}
   250  
   251  	ids := ServiceFactory.registeredServiceIDs()
   252  	for _, id := range ids {
   253  		name := ServiceFactory.Name(id)
   254  		log.Lvl3("Starting service", name)
   255  
   256  		cont := newContext(srv, o, id, s)
   257  
   258  		srvc, err := ServiceFactory.start(name, cont)
   259  		if err != nil {
   260  			log.Fatalf("Trying to instantiate service %v: %v", name, err)
   261  		}
   262  		log.Lvl3("Started Service", name)
   263  		s.servicesMutex.Lock()
   264  		services[id] = srvc
   265  		s.servicesMutex.Unlock()
   266  		srv.WebSocket.registerService(name, srvc)
   267  	}
   268  	log.Lvl3(srv.Address(), "instantiated all services")
   269  	srv.statusReporterStruct.RegisterStatusReporter("Db", s)
   270  	return s
   271  }
   272  
   273  // openDb opens a database at `path`. It creates the database if it does not exist.
   274  // The caller must ensure that all parent directories exist.
   275  func openDb(path string) (*bolt.DB, error) {
   276  	db, err := bolt.Open(path, 0600, nil)
   277  	if err != nil {
   278  		return nil, err
   279  	}
   280  	return db, nil
   281  }
   282  
   283  func (s *serviceManager) dbFileNameOld() string {
   284  	pub, _ := s.server.ServerIdentity.Public.MarshalBinary()
   285  	return path.Join(s.dbPath, fmt.Sprintf("%x.db", pub))
   286  }
   287  
   288  func (s *serviceManager) dbFileName() string {
   289  	pub, _ := s.server.ServerIdentity.Public.MarshalBinary()
   290  	h := sha256.New()
   291  	h.Write(pub)
   292  	return path.Join(s.dbPath, fmt.Sprintf("%x.db", h.Sum(nil)))
   293  }
   294  
   295  // updateDbFileName checks if the old database file name exists, if it does, it
   296  // will rename it to the new file name.
   297  func (s *serviceManager) updateDbFileName() {
   298  	if _, err := os.Stat(s.dbFileNameOld()); err == nil {
   299  		// we assume the new name does not exist
   300  		log.Lvl2("Renaming database from", s.dbFileNameOld(), "to", s.dbFileName())
   301  		if err := os.Rename(s.dbFileNameOld(), s.dbFileName()); err != nil {
   302  			log.Error(err)
   303  		}
   304  	}
   305  }
   306  
   307  // Process implements the Processor interface: service manager will relay
   308  // messages to the right Service.
   309  func (s *serviceManager) Process(env *network.Envelope) {
   310  	// will launch a go routine for that message
   311  	s.Dispatch(env)
   312  }
   313  
   314  // closeDatabase closes the database.
   315  // It also removes the database file if the path is not default (i.e. testing config)
   316  func (s *serviceManager) closeDatabase() error {
   317  	if s.db != nil {
   318  		err := s.db.Close()
   319  		if err != nil {
   320  			log.Error("Close database failed with: " + err.Error())
   321  		}
   322  	}
   323  
   324  	if s.delDb {
   325  		err := os.Remove(s.dbFileName())
   326  		if err != nil {
   327  			return err
   328  		}
   329  	}
   330  	return nil
   331  }
   332  
   333  // GetStatus is a function that returns the status report of the server.
   334  func (s *serviceManager) GetStatus() *Status {
   335  	if s.db == nil {
   336  		return &Status{Field: map[string]string{"Open": "false"}}
   337  	}
   338  	st := s.db.Stats()
   339  	return &Status{Field: map[string]string{
   340  		"Open":             "true",
   341  		"FreePageN":        strconv.Itoa(st.FreePageN),
   342  		"PendingPageN":     strconv.Itoa(st.PendingPageN),
   343  		"FreeAlloc":        strconv.Itoa(st.FreeAlloc),
   344  		"FreelistInuse":    strconv.Itoa(st.FreelistInuse),
   345  		"TxN":              strconv.Itoa(st.TxN),
   346  		"OpenTxN":          strconv.Itoa(st.OpenTxN),
   347  		"Tx.PageCount":     strconv.Itoa(st.TxStats.PageCount),
   348  		"Tx.PageAlloc":     strconv.Itoa(st.TxStats.PageAlloc),
   349  		"Tx.CursorCount":   strconv.Itoa(st.TxStats.CursorCount),
   350  		"Tx.NodeCount":     strconv.Itoa(st.TxStats.NodeCount),
   351  		"Tx.NodeDeref":     strconv.Itoa(st.TxStats.NodeDeref),
   352  		"Tx.Rebalance":     strconv.Itoa(st.TxStats.Rebalance),
   353  		"Tx.RebalanceTime": st.TxStats.RebalanceTime.String(),
   354  		"Tx.Split":         strconv.Itoa(st.TxStats.Split),
   355  		"Tx.Spill":         strconv.Itoa(st.TxStats.Spill),
   356  		"Tx.SpillTime":     st.TxStats.SpillTime.String(),
   357  		"Tx.Write":         strconv.Itoa(st.TxStats.Write),
   358  		"Tx.WriteTime":     st.TxStats.WriteTime.String(),
   359  	}}
   360  }
   361  
   362  // registerProcessor the processor to the service manager and tells the host to dispatch
   363  // this message to the service manager. The service manager will then dispatch
   364  // the message in a go routine. XXX This is needed because we need to have
   365  // messages for service dispatched in asynchronously regarding the protocols.
   366  // This behavior with go routine is fine for the moment but for better
   367  // performance / memory / resilience, it may be changed to a real queuing
   368  // system later.
   369  func (s *serviceManager) registerProcessor(p network.Processor, msgType network.MessageTypeID) {
   370  	// delegate message to host so the host will pass the message to ourself
   371  	s.server.RegisterProcessor(s, msgType)
   372  	// handle the message ourselves (will be launched in a go routine)
   373  	s.Dispatcher.RegisterProcessor(p, msgType)
   374  }
   375  
   376  func (s *serviceManager) registerProcessorFunc(msgType network.MessageTypeID, fn func(*network.Envelope)) {
   377  	// delegate message to host so the host will pass the message to ourself
   378  	s.server.RegisterProcessor(s, msgType)
   379  	// handle the message ourselves (will be launched in a go routine)
   380  	s.Dispatcher.RegisterProcessorFunc(msgType, fn)
   381  
   382  }
   383  
   384  // availableServices returns a list of all services available to the serviceManager.
   385  // If no services are instantiated, it returns an empty list.
   386  func (s *serviceManager) availableServices() (ret []string) {
   387  	s.servicesMutex.Lock()
   388  	defer s.servicesMutex.Unlock()
   389  	for id := range s.services {
   390  		ret = append(ret, ServiceFactory.Name(id))
   391  	}
   392  	return
   393  }
   394  
   395  // service returns the service implementation being registered to this name or
   396  // nil if no service by this name is available.
   397  func (s *serviceManager) service(name string) Service {
   398  	id := ServiceFactory.ServiceID(name)
   399  	if id.Equal(NilServiceID) {
   400  		return nil
   401  	}
   402  	s.servicesMutex.Lock()
   403  	defer s.servicesMutex.Unlock()
   404  	ser, ok := s.services[id]
   405  	if !ok {
   406  		log.Error("this service is not instantiated")
   407  		return nil
   408  	}
   409  	return ser
   410  }
   411  
   412  func (s *serviceManager) serviceByID(id ServiceID) (Service, bool) {
   413  	var serv Service
   414  	var ok bool
   415  	s.servicesMutex.Lock()
   416  	defer s.servicesMutex.Unlock()
   417  	if serv, ok = s.services[id]; !ok {
   418  		return nil, false
   419  	}
   420  	return serv, true
   421  }
   422  
   423  // newProtocol contains the logic of how and where a ProtocolInstance is
   424  // created. If the token's ServiceID is nil, then onet handles the creation of
   425  // the PI. If the corresponding service returns (nil,nil), then onet handles
   426  // the creation of the PI. Otherwise the service is responsible for setting up
   427  // the PI.
   428  func (s *serviceManager) newProtocol(tni *TreeNodeInstance, config *GenericConfig) (pi ProtocolInstance, err error) {
   429  	si, ok := s.serviceByID(tni.Token().ServiceID)
   430  	defaultHandle := func() (ProtocolInstance, error) { return s.server.protocolInstantiate(tni.Token().ProtoID, tni) }
   431  	if !ok {
   432  		// let onet handle it
   433  		return defaultHandle()
   434  	}
   435  
   436  	defer func() {
   437  		if r := recover(); r != nil {
   438  			pi = nil
   439  			err = fmt.Errorf("could not create new protocol: %v", r)
   440  			return
   441  		}
   442  	}()
   443  
   444  	pi, err = si.NewProtocol(tni, config)
   445  	if pi == nil && err == nil {
   446  		return defaultHandle()
   447  	}
   448  	return
   449  }