github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/core/commands/block.go (about)

     1  package commands
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"io/ioutil"
     9  	"strings"
    10  
    11  	mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
    12  	"github.com/ipfs/go-ipfs/blocks"
    13  	key "github.com/ipfs/go-ipfs/blocks/key"
    14  	cmds "github.com/ipfs/go-ipfs/commands"
    15  	u "github.com/ipfs/go-ipfs/util"
    16  )
    17  
    18  type BlockStat struct {
    19  	Key  string
    20  	Size int
    21  }
    22  
    23  func (bs BlockStat) String() string {
    24  	return fmt.Sprintf("Key: %s\nSize: %d\n", bs.Key, bs.Size)
    25  }
    26  
    27  var BlockCmd = &cmds.Command{
    28  	Helptext: cmds.HelpText{
    29  		Tagline: "Manipulate raw IPFS blocks",
    30  		ShortDescription: `
    31  'ipfs block' is a plumbing command used to manipulate raw ipfs blocks.
    32  Reads from stdin or writes to stdout, and <key> is a base58 encoded
    33  multihash.
    34  `,
    35  	},
    36  
    37  	Subcommands: map[string]*cmds.Command{
    38  		"stat": blockStatCmd,
    39  		"get":  blockGetCmd,
    40  		"put":  blockPutCmd,
    41  	},
    42  }
    43  
    44  var blockStatCmd = &cmds.Command{
    45  	Helptext: cmds.HelpText{
    46  		Tagline: "Print information of a raw IPFS block",
    47  		ShortDescription: `
    48  'ipfs block stat' is a plumbing command for retreiving information
    49  on raw ipfs blocks. It outputs the following to stdout:
    50  
    51  	Key  - the base58 encoded multihash
    52  	Size - the size of the block in bytes
    53  
    54  `,
    55  	},
    56  
    57  	Arguments: []cmds.Argument{
    58  		cmds.StringArg("key", true, false, "The base58 multihash of an existing block to get").EnableStdin(),
    59  	},
    60  	Run: func(req cmds.Request, res cmds.Response) {
    61  		b, err := getBlockForKey(req, req.Arguments()[0])
    62  		if err != nil {
    63  			res.SetError(err, cmds.ErrNormal)
    64  			return
    65  		}
    66  
    67  		res.SetOutput(&BlockStat{
    68  			Key:  b.Key().Pretty(),
    69  			Size: len(b.Data),
    70  		})
    71  	},
    72  	Type: BlockStat{},
    73  	Marshalers: cmds.MarshalerMap{
    74  		cmds.Text: func(res cmds.Response) (io.Reader, error) {
    75  			bs := res.Output().(*BlockStat)
    76  			return strings.NewReader(bs.String()), nil
    77  		},
    78  	},
    79  }
    80  
    81  var blockGetCmd = &cmds.Command{
    82  	Helptext: cmds.HelpText{
    83  		Tagline: "Get a raw IPFS block",
    84  		ShortDescription: `
    85  'ipfs block get' is a plumbing command for retreiving raw ipfs blocks.
    86  It outputs to stdout, and <key> is a base58 encoded multihash.
    87  `,
    88  	},
    89  
    90  	Arguments: []cmds.Argument{
    91  		cmds.StringArg("key", true, false, "The base58 multihash of an existing block to get").EnableStdin(),
    92  	},
    93  	Run: func(req cmds.Request, res cmds.Response) {
    94  		b, err := getBlockForKey(req, req.Arguments()[0])
    95  		if err != nil {
    96  			res.SetError(err, cmds.ErrNormal)
    97  			return
    98  		}
    99  
   100  		res.SetOutput(bytes.NewReader(b.Data))
   101  	},
   102  }
   103  
   104  var blockPutCmd = &cmds.Command{
   105  	Helptext: cmds.HelpText{
   106  		Tagline: "Stores input as an IPFS block",
   107  		ShortDescription: `
   108  ipfs block put is a plumbing command for storing raw ipfs blocks.
   109  It reads from stdin, and <key> is a base58 encoded multihash.
   110  `,
   111  	},
   112  
   113  	Arguments: []cmds.Argument{
   114  		cmds.FileArg("data", true, false, "The data to be stored as an IPFS block").EnableStdin(),
   115  	},
   116  	Run: func(req cmds.Request, res cmds.Response) {
   117  		n, err := req.InvocContext().GetNode()
   118  		if err != nil {
   119  			res.SetError(err, cmds.ErrNormal)
   120  			return
   121  		}
   122  
   123  		file, err := req.Files().NextFile()
   124  		if err != nil {
   125  			res.SetError(err, cmds.ErrNormal)
   126  			return
   127  		}
   128  
   129  		data, err := ioutil.ReadAll(file)
   130  		if err != nil {
   131  			res.SetError(err, cmds.ErrNormal)
   132  			return
   133  		}
   134  
   135  		err = file.Close()
   136  		if err != nil {
   137  			res.SetError(err, cmds.ErrNormal)
   138  			return
   139  		}
   140  
   141  		b := blocks.NewBlock(data)
   142  		log.Debugf("BlockPut key: '%q'", b.Key())
   143  
   144  		k, err := n.Blocks.AddBlock(b)
   145  		if err != nil {
   146  			res.SetError(err, cmds.ErrNormal)
   147  			return
   148  		}
   149  
   150  		res.SetOutput(&BlockStat{
   151  			Key:  k.String(),
   152  			Size: len(data),
   153  		})
   154  	},
   155  	Marshalers: cmds.MarshalerMap{
   156  		cmds.Text: func(res cmds.Response) (io.Reader, error) {
   157  			bs := res.Output().(*BlockStat)
   158  			return strings.NewReader(bs.Key + "\n"), nil
   159  		},
   160  	},
   161  	Type: BlockStat{},
   162  }
   163  
   164  func getBlockForKey(req cmds.Request, skey string) (*blocks.Block, error) {
   165  	n, err := req.InvocContext().GetNode()
   166  	if err != nil {
   167  		return nil, err
   168  	}
   169  
   170  	if !u.IsValidHash(skey) {
   171  		return nil, errors.New("Not a valid hash")
   172  	}
   173  
   174  	h, err := mh.FromB58String(skey)
   175  	if err != nil {
   176  		return nil, err
   177  	}
   178  
   179  	k := key.Key(h)
   180  	b, err := n.Blocks.GetBlock(req.Context(), k)
   181  	if err != nil {
   182  		return nil, err
   183  	}
   184  
   185  	log.Debugf("ipfs block: got block with key: %q", b.Key())
   186  	return b, nil
   187  }