func (self *channelAPI) Blob_Mutation(perma grapher.PermaNode, mutation grapher.MutationNode) { mutJson := map[string]interface{}{"perma": perma.BlobRef(), "seq": mutation.SequenceNumber(), "type": "mutation", "signer": mutation.Signer(), "entity": mutation.EntityBlobRef(), "field": mutation.Field(), "time": mutation.Time()} switch mutation.Operation().(type) { case []ot.StringOperation: op := mutation.Operation().([]ot.StringOperation) // The following two lines work around a problem in GO/JSON mutJson["op"] = &op case []byte: msg := json.RawMessage(mutation.Operation().([]byte)) mutJson["op"] = &msg default: panic("Unsupported operation kind") } schema, err := json.Marshal(mutJson) if err != nil { panic(err.String()) } if self.bufferOnly { self.messageBuffer = append(self.messageBuffer, string(schema)) } else { err = self.forwardToFollowers(perma.BlobRef(), string(schema)) } if err != nil { log.Printf("Err Forward: %v", err) } }
func (self *Grapher) CreateEntityBlob(perma_blobref string, mimeType string, content []byte) (node AbstractNode, err os.Error) { perma, e := self.permaNode(perma_blobref) if e != nil { err = e return } c := json.RawMessage(content) deps := perma.frontier.IDs() entityJson := map[string]interface{}{"signer": self.userID, "perma": perma_blobref, "content": &c, "dep": deps, "mimetype": mimeType} entityBlob, err := json.Marshal(entityJson) if err != nil { panic(err.String()) } entityBlob = append([]byte(`{"type":"entity",`), entityBlob[1:]...) log.Printf("Storing entity %v\n", string(entityBlob)) entityBlobRef := newBlobRef(entityBlob) // Process it var schema superSchema schema.Type = "entity" schema.Signer = self.userID schema.PermaNode = perma_blobref schema.Content = &c schema.MimeType = mimeType schema.Dependencies = deps _, node, err = self.handleSchemaBlob(&schema, entityBlobRef) return }
func (self *Replication) getnHandlerIntern(prefix string, conn *Connection) { channel, err := self.store.GetBlobs(prefix) if err != nil { log.Printf("Error while talking to store: %v\n", err) return } for blob := range channel { log.Printf("sendblob %v\n", blob.BlobRef) conn.Send("BLOB", json.RawMessage(blob.Data)) } }
// Called from the store when a new blob has been stored func (self *Replication) HandleBlob(blob []byte, blobref string) os.Error { for connection, flags := range self.connections { if flags&connStreaming == connStreaming { // Do not send the blob on the same connection on which it has been received if !connection.hasReceivedBlob(blobref) { connection.Send("BLOB", json.RawMessage(blob)) } } } return nil }
func (self *Replication) getnxHandlerIntern(prefix string, except map[string]bool, conn *Connection) { channel, err := self.store.GetBlobs(prefix) if err != nil { log.Printf("Error while talking to store: %v\n", err) return } for blob := range channel { if _, ok := except[blob.BlobRef]; ok { continue } conn.Send("BLOB", json.RawMessage(blob.Data)) } }
func (self *channelAPI) Blob_Entity(perma grapher.PermaNode, entity grapher.EntityNode) { entityJson := map[string]interface{}{"perma": perma.BlobRef(), "seq": entity.SequenceNumber(), "type": "entity", "signer": entity.Signer(), "mimetype": entity.MimeType(), "blobref": entity.BlobRef()} msg := json.RawMessage(entity.Content()) entityJson["content"] = &msg schema, err := json.Marshal(entityJson) if err != nil { panic(err.String()) } if self.bufferOnly { self.messageBuffer = append(self.messageBuffer, string(schema)) } else { err = self.forwardToFollowers(perma.BlobRef(), string(schema)) } if err != nil { log.Printf("Err Forward: %v", err) } }
func (self *Message) EncodePayload(data interface{}) os.Error { if data == nil { self.Payload = nil return nil } if raw, ok := data.(json.RawMessage); ok { self.Payload = &raw return nil } bytes, err := json.Marshal(data) if err != nil { return err } p := json.RawMessage(bytes) self.Payload = &p return nil }
// Handles the 'GET' command func (self *Replication) getHandler(msg Message) { var blobref string if msg.DecodePayload(&blobref) != nil { log.Printf("Error in GET request") return } blob, err := self.store.GetBlob(blobref) if err != nil { log.Printf("Error while talking to store: %v\n", err) return } // TODO: If this is not a JSON blob ... err = msg.connection.Send("BLOB", json.RawMessage(blob)) if err != nil { log.Printf("Error while sending %v\n", err) } }
} // PkgPath will be non-empty even for an exported type, // so we need to check the type name as well. return isExported(t.Name()) || t.PkgPath() == "" } // ---------------------------------------------------------------------------- // Server // ---------------------------------------------------------------------------- // A value sent as a placeholder for the response when the server receives // an invalid request. type InvalidRequest struct{} var invalidRequest = InvalidRequest{} var null = json.RawMessage([]byte("null")) type JsonRequest struct { // A String containing the name of the method to be invoked. Method string `json:"method"` // An Array of objects to pass as arguments to the method. Params *json.RawMessage `json:"params"` // The request id. This can be of any type. It is used to match the // response with the request that it is replying to. Id *json.RawMessage `json:"id"` } type JsonResponse struct { // The Object that was returned by the invoked method. This must be null // in case there was an error invoking the method. Result interface{} `json:"result"`
func (self *Grapher) CreateMutationBlob(perma_blobref string, entity_blobref string, field string, operation []byte, applyAtSeqNumber int64) (node AbstractNode, err os.Error) { perma, e := self.permaNode(perma_blobref) if e != nil { err = e return } entity, e := self.entity(perma.BlobRef(), entity_blobref) if e != nil { err = e return } transformer, e := self.transformer(perma, entity, field) if e != nil { err = e return } // Update the operation such that it can be applied after all currently applied operations m := &mutationNode{} m.permaBlobRef = perma_blobref m.mutationBlobRef = "Z" // This ensures that the client mutation looses against all server mutations. The client-side must handle it the same. m.mutationSigner = self.userID m.entityBlobRef = entity_blobref m.field = field m.operation = operation m.time = time.Seconds() if transformer != nil { ch, e := self.getMutationsAscending(perma.BlobRef(), entity_blobref, field, applyAtSeqNumber, perma.SequenceNumber()) if e != nil { err = e return } e = transformer.TransformClientMutation(m, ch) if e != nil { err = e return } } deps := perma.frontier.IDs() mutJson := map[string]interface{}{"signer": self.userID, "perma": perma_blobref, "dep": deps, "entity": entity_blobref, "field": field} var msg json.RawMessage switch m.operation.(type) { case ot.StringOperation: op := m.operation.(ot.StringOperation) // The following two lines work around a problem in GO/JSON op_bytes, err := op.MarshalJSON() if err != nil { return nil, err } msg = json.RawMessage(op_bytes) case []byte: msg = json.RawMessage(m.operation.([]byte)) default: panic("Unsupported operation kind") } mutJson["op"] = &msg schema, err := json.Marshal(mutJson) if err != nil { panic(err.String()) } mutBlob := []byte(`{"type":"mutation",`) mutBlob = append(mutBlob, schema[1:]...) log.Printf("Storing mut %v\n", string(mutBlob)) mutBlobRef := newBlobRef(mutBlob) // Process it var schema2 superSchema schema2.Type = "mutation" schema2.Signer = self.userID schema2.PermaNode = perma_blobref schema2.Dependencies = deps schema2.Entity = entity_blobref schema2.Field = field schema2.Operation = &msg _, node, err = self.handleSchemaBlob(&schema2, mutBlobRef) return }
// Handles the 'TCHLD' command func (self *Replication) treeHashChildrenHandler(msg Message) { req := struct { Prefix string "prefix" Kind int "kind" Children []string "chld" }{} var prefix string // This is a request? if msg.DecodePayload(&prefix) == nil { req.Kind, req.Children, _ = self.store.HashTree().Children(prefix) req.Prefix = prefix msg.connection.Send("TCHLD", &req) return } if msg.DecodePayload(&req) != nil { log.Printf("Error in TCHL message") return } kind1, children1, prefix := req.Kind, req.Children, req.Prefix kind2, children2, err := self.store.HashTree().Children(prefix) if kind1 == HashTree_NIL || kind2 == HashTree_NIL || err != nil { log.Printf("Comparison of hash trees failed: prefix=%v, kind1=%v, kind2=%v, err=%v\n", prefix, kind1, kind2, err) return } // Turn a list of strings into a map of strings for further efficient processing map1 := map[string]bool{} for _, ch := range children1 { map1[ch] = true } map2 := map[string]bool{} for _, ch := range children2 { map2[ch] = true } if kind1 == HashTree_IDs && kind2 == HashTree_IDs { // Both returned hashes. Compare the two sets of hashes for key, _ := range map1 { if _, ok := map2[key]; !ok { msg.connection.Send("GET", key) } } for key, _ := range map2 { if _, ok := map1[key]; !ok { blob, err := self.store.GetBlob(key) if err != nil { log.Printf("Retrieving block %v failed\n", key) } else { msg.connection.Send("BLOB", json.RawMessage(blob)) } } } } else if kind1 == HashTree_InnerNodes && kind2 == HashTree_InnerNodes { // Both returned subtree nodes? Recursion into the sub tree nodes for i := 0; i < HashTree_NodeDegree; i++ { if children1[i] == children2[i] { continue } p := prefix + string(hextable[i]) if children1[i] == "" { self.getnHandlerIntern(p, msg.connection) } else if children2[i] == "" { // Get all blobs with this prefix msg.connection.Send("GETN", p) } else { // Recursion msg.connection.Send("TCHLD", p) } } } else if kind1 == HashTree_InnerNodes && kind2 == HashTree_IDs { for i := 0; i < HashTree_NodeDegree; i++ { // Get all blox with this prefix (except those in map1) from the other side p := prefix + string(hextable[i]) lst := []string{} for key, _ := range map1 { lst = append(lst, key) } r := struct { Prefix string "prefix" Except []string "except" }{p, lst} msg.connection.Send("GETNX", &r) } } else { for i := 0; i < HashTree_NodeDegree; i++ { // Send all blobs with this prefix (except those in map2) to the other side p := prefix + string(hextable[i]) self.getnxHandlerIntern(p, map2, msg.connection) } } }