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

     1  package onet
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"fmt"
     7  	"sync"
     8  
     9  	bolt "github.com/coreos/bbolt"
    10  	"gopkg.in/dedis/onet.v2/log"
    11  	"gopkg.in/dedis/onet.v2/network"
    12  )
    13  
    14  // Context represents the methods that are available to a service.
    15  type Context struct {
    16  	overlay           *Overlay
    17  	server            *Server
    18  	serviceID         ServiceID
    19  	manager           *serviceManager
    20  	bucketName        []byte
    21  	bucketVersionName []byte
    22  }
    23  
    24  // defaultContext is the implementation of the Context interface. It is
    25  // instantiated for each Service.
    26  func newContext(c *Server, o *Overlay, servID ServiceID, manager *serviceManager) *Context {
    27  	ctx := &Context{
    28  		overlay:           o,
    29  		server:            c,
    30  		serviceID:         servID,
    31  		manager:           manager,
    32  		bucketName:        []byte(ServiceFactory.Name(servID)),
    33  		bucketVersionName: []byte(ServiceFactory.Name(servID) + "version"),
    34  	}
    35  	err := manager.db.Update(func(tx *bolt.Tx) error {
    36  		_, err := tx.CreateBucketIfNotExists(ctx.bucketName)
    37  		if err != nil {
    38  			return err
    39  		}
    40  		_, err = tx.CreateBucketIfNotExists(ctx.bucketVersionName)
    41  		return err
    42  	})
    43  	if err != nil {
    44  		log.Panic("Failed to create bucket: " + err.Error())
    45  	}
    46  	return ctx
    47  }
    48  
    49  // NewTreeNodeInstance creates a TreeNodeInstance that is bound to a
    50  // service instead of the Overlay.
    51  func (c *Context) NewTreeNodeInstance(t *Tree, tn *TreeNode, protoName string) *TreeNodeInstance {
    52  	io := c.overlay.protoIO.getByName(protoName)
    53  	return c.overlay.NewTreeNodeInstanceFromService(t, tn, ProtocolNameToID(protoName), c.serviceID, io)
    54  }
    55  
    56  // SendRaw sends a message to the ServerIdentity.
    57  func (c *Context) SendRaw(si *network.ServerIdentity, msg interface{}) error {
    58  	_, err := c.server.Send(si, msg)
    59  	return err
    60  }
    61  
    62  // ServerIdentity returns this server's identity.
    63  func (c *Context) ServerIdentity() *network.ServerIdentity {
    64  	return c.server.ServerIdentity
    65  }
    66  
    67  // Suite returns the suite for the context's associated server.
    68  func (c *Context) Suite() network.Suite {
    69  	return c.server.Suite()
    70  }
    71  
    72  // ServiceID returns the service-id.
    73  func (c *Context) ServiceID() ServiceID {
    74  	return c.serviceID
    75  }
    76  
    77  // CreateProtocol returns a ProtocolInstance bound to the service.
    78  func (c *Context) CreateProtocol(name string, t *Tree) (ProtocolInstance, error) {
    79  	pi, err := c.overlay.CreateProtocol(name, t, c.serviceID)
    80  	return pi, err
    81  }
    82  
    83  // ProtocolRegister signs up a new protocol to this Server. Contrary go
    84  // GlobalProtocolRegister, the protocol registered here is tied to that server.
    85  // This is useful for simulations where more than one Server exists in the
    86  // global namespace.
    87  // It returns the ID of the protocol.
    88  func (c *Context) ProtocolRegister(name string, protocol NewProtocol) (ProtocolID, error) {
    89  	return c.server.ProtocolRegister(name, protocol)
    90  }
    91  
    92  // RegisterProtocolInstance registers a new instance of a protocol using overlay.
    93  func (c *Context) RegisterProtocolInstance(pi ProtocolInstance) error {
    94  	return c.overlay.RegisterProtocolInstance(pi)
    95  }
    96  
    97  // ReportStatus returns all status of the services.
    98  func (c *Context) ReportStatus() map[string]*Status {
    99  	return c.server.statusReporterStruct.ReportStatus()
   100  }
   101  
   102  // RegisterStatusReporter registers a new StatusReporter.
   103  func (c *Context) RegisterStatusReporter(name string, s StatusReporter) {
   104  	c.server.statusReporterStruct.RegisterStatusReporter(name, s)
   105  }
   106  
   107  // RegisterProcessor overrides the RegisterProcessor methods of the Dispatcher.
   108  // It delegates the dispatching to the serviceManager.
   109  func (c *Context) RegisterProcessor(p network.Processor, msgType network.MessageTypeID) {
   110  	c.manager.registerProcessor(p, msgType)
   111  }
   112  
   113  // RegisterProcessorFunc takes a message-type and a function that will be called
   114  // if this message-type is received.
   115  func (c *Context) RegisterProcessorFunc(msgType network.MessageTypeID, fn func(*network.Envelope)) {
   116  	c.manager.registerProcessorFunc(msgType, fn)
   117  }
   118  
   119  // RegisterMessageProxy registers a message proxy only for this server /
   120  // overlay
   121  func (c *Context) RegisterMessageProxy(m MessageProxy) {
   122  	c.overlay.RegisterMessageProxy(m)
   123  }
   124  
   125  // Service returns the corresponding service.
   126  func (c *Context) Service(name string) Service {
   127  	return c.manager.service(name)
   128  }
   129  
   130  // String returns the host it's running on.
   131  func (c *Context) String() string {
   132  	return c.server.ServerIdentity.String()
   133  }
   134  
   135  var testContextData = struct {
   136  	service map[string][]byte
   137  	sync.Mutex
   138  }{service: make(map[string][]byte, 0)}
   139  
   140  // The ContextDB interface allows for easy testing in the services.
   141  type ContextDB interface {
   142  	Load(key []byte) (interface{}, error)
   143  	LoadRaw(key []byte) ([]byte, error)
   144  	LoadVersion() (int, error)
   145  	SaveVersion(version int) error
   146  }
   147  
   148  // Save takes a key and an interface. The interface will be network.Marshal'ed
   149  // and saved in the database under the bucket named after the service name.
   150  //
   151  // The data will be stored in a different bucket for every service.
   152  func (c *Context) Save(key []byte, data interface{}) error {
   153  	buf, err := network.Marshal(data)
   154  	if err != nil {
   155  		return err
   156  	}
   157  	return c.manager.db.Update(func(tx *bolt.Tx) error {
   158  		b := tx.Bucket(c.bucketName)
   159  		return b.Put(key, buf)
   160  	})
   161  }
   162  
   163  // Load takes a key and returns the network.Unmarshaled data.
   164  // Returns a nil value if the key does not exist.
   165  func (c *Context) Load(key []byte) (interface{}, error) {
   166  	var buf []byte
   167  	err := c.manager.db.View(func(tx *bolt.Tx) error {
   168  		v := tx.Bucket(c.bucketName).Get(key)
   169  		if v == nil {
   170  			return nil
   171  		}
   172  
   173  		buf = make([]byte, len(v))
   174  		copy(buf, v)
   175  		return nil
   176  	})
   177  	if err != nil {
   178  		return nil, err
   179  	}
   180  
   181  	if buf == nil {
   182  		return nil, nil
   183  	}
   184  
   185  	_, ret, err := network.Unmarshal(buf, c.server.suite)
   186  	return ret, err
   187  }
   188  
   189  // LoadRaw takes a key and returns the raw, unmarshalled data.
   190  // Returns a nil value if the key does not exist.
   191  func (c *Context) LoadRaw(key []byte) ([]byte, error) {
   192  	var buf []byte
   193  	err := c.manager.db.View(func(tx *bolt.Tx) error {
   194  		v := tx.Bucket(c.bucketName).Get(key)
   195  		if v == nil {
   196  			return nil
   197  		}
   198  
   199  		buf = make([]byte, len(v))
   200  		copy(buf, v)
   201  		return nil
   202  	})
   203  	return buf, err
   204  }
   205  
   206  var dbVersion = []byte("dbVersion")
   207  
   208  // LoadVersion returns the version of the database, or 0 if
   209  // no version has been found.
   210  func (c *Context) LoadVersion() (int, error) {
   211  	var buf []byte
   212  	err := c.manager.db.View(func(tx *bolt.Tx) error {
   213  		v := tx.Bucket(c.bucketVersionName).Get(dbVersion)
   214  		if v == nil {
   215  			return nil
   216  		}
   217  
   218  		buf = make([]byte, len(v))
   219  		copy(buf, v)
   220  		return nil
   221  	})
   222  
   223  	if err != nil {
   224  		return -1, err
   225  	}
   226  
   227  	if len(buf) == 0 {
   228  		return 0, nil
   229  	}
   230  	var version int32
   231  	err = binary.Read(bytes.NewReader(buf), binary.LittleEndian, &version)
   232  	return int(version), err
   233  }
   234  
   235  // SaveVersion stores the given version as the current database version.
   236  func (c *Context) SaveVersion(version int) error {
   237  	buf := bytes.NewBuffer(nil)
   238  	err := binary.Write(buf, binary.LittleEndian, int32(version))
   239  	if err != nil {
   240  		return err
   241  	}
   242  	return c.manager.db.Update(func(tx *bolt.Tx) error {
   243  		b := tx.Bucket(c.bucketVersionName)
   244  		return b.Put(dbVersion, buf.Bytes())
   245  	})
   246  }
   247  
   248  // GetAdditionalBucket makes sure that a bucket with the given name
   249  // exists, by eventually creating it, and returns the created bucket name,
   250  // which is the servicename + "_" + the given name.
   251  //
   252  // This function should only be used if the Load and Save functions are not sufficient.
   253  // Additionally, the user should not create buckets directly on the DB but always
   254  // call this function to create new buckets to avoid bucket name conflicts.
   255  func (c *Context) GetAdditionalBucket(name []byte) (*bolt.DB, []byte) {
   256  	fullName := append(append(c.bucketName, byte('_')), name...)
   257  	err := c.manager.db.Update(func(tx *bolt.Tx) error {
   258  		_, err := tx.CreateBucketIfNotExists(fullName)
   259  		if err != nil {
   260  			return fmt.Errorf("create bucket: %s", err)
   261  		}
   262  		return nil
   263  	})
   264  	if err != nil {
   265  		panic(err)
   266  	}
   267  	return c.manager.db, fullName
   268  }