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 }