kubo/core/commands/object.go
2014-10-30 06:35:29 -07:00

136 lines
3.6 KiB
Go

package commands
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"github.com/jbenet/go-ipfs/core"
dag "github.com/jbenet/go-ipfs/merkledag"
)
// ObjectData takes a key string from args and writes out the raw bytes of that node (if there is one)
func ObjectData(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
dagnode, err := n.Resolver.ResolvePath(args[0])
if err != nil {
return fmt.Errorf("objectData error: %v", err)
}
log.Debugf("objectData: found dagnode %q (# of bytes: %d - # links: %d)", args[0], len(dagnode.Data), len(dagnode.Links))
_, err = io.Copy(out, bytes.NewReader(dagnode.Data))
return err
}
// ObjectLinks takes a key string from args and lists the links it points to
func ObjectLinks(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
dagnode, err := n.Resolver.ResolvePath(args[0])
if err != nil {
return fmt.Errorf("objectLinks error: %v", err)
}
log.Debugf("ObjectLinks: found dagnode %q (# of bytes: %d - # links: %d)", args[0], len(dagnode.Data), len(dagnode.Links))
for _, link := range dagnode.Links {
_, err = fmt.Fprintf(out, "%s %d %q\n", link.Hash.B58String(), link.Size, link.Name)
if err != nil {
break
}
}
return err
}
// ErrUnknownObjectEnc is returned if a invalid encoding is supplied
var ErrUnknownObjectEnc = errors.New("unknown object encoding")
type objectEncoding string
const (
objectEncodingJSON objectEncoding = "json"
objectEncodingProtobuf = "protobuf"
)
func getObjectEnc(o interface{}) objectEncoding {
v, ok := o.(string)
if !ok {
// chosen as default because it's human readable
log.Warning("option is not a string - falling back to json")
return objectEncodingJSON
}
return objectEncoding(v)
}
// ObjectGet takes a key string from args and a format option and serializes the dagnode to that format
func ObjectGet(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
dagnode, err := n.Resolver.ResolvePath(args[0])
if err != nil {
return fmt.Errorf("ObjectGet error: %v", err)
}
log.Debugf("objectGet: found dagnode %q (# of bytes: %d - # links: %d)", args[0], len(dagnode.Data), len(dagnode.Links))
// sadly all encodings dont implement a common interface
var data []byte
switch getObjectEnc(opts["encoding"]) {
case objectEncodingJSON:
data, err = json.MarshalIndent(dagnode, "", " ")
case objectEncodingProtobuf:
data, err = dagnode.Marshal()
default:
return ErrUnknownObjectEnc
}
if err != nil {
return fmt.Errorf("ObjectGet error: %v", err)
}
_, err = io.Copy(out, bytes.NewReader(data))
return err
}
// ErrObjectTooLarge is returned when too much data was read from stdin. current limit 512k
var ErrObjectTooLarge = errors.New("input object was too large. limit is 512kbytes")
const inputLimit = 512 * 1024
// ObjectPut takes a format option, serilizes bytes from stdin and updates the dag with that data
func ObjectPut(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
var (
dagnode *dag.Node
data []byte
err error
)
data, err = ioutil.ReadAll(io.LimitReader(os.Stdin, inputLimit+10))
if err != nil {
return fmt.Errorf("ObjectPut error: %v", err)
}
if len(data) >= inputLimit {
return ErrObjectTooLarge
}
switch getObjectEnc(opts["encoding"]) {
case objectEncodingJSON:
dagnode = new(dag.Node)
err = json.Unmarshal(data, dagnode)
case objectEncodingProtobuf:
dagnode, err = dag.Decoded(data)
default:
return ErrUnknownObjectEnc
}
if err != nil {
return fmt.Errorf("ObjectPut error: %v", err)
}
return addNode(n, dagnode, "stdin", out)
}