├── coding ├── pb │ ├── bin │ │ └── .gitignore │ ├── testfile │ ├── Makefile │ ├── ipld.proto │ ├── pbcodec_test.go │ ├── pbcodec.go │ └── ipld.pb.go ├── cbor.testfile ├── json.testfile ├── Makefile ├── bin │ └── convert.go ├── coding.go ├── transform.go └── coding_test.go ├── schemas ├── merkleweb ├── versions └── publish.sh ├── .travis.yml ├── _examples ├── commit │ └── commit.go ├── unixfs │ └── unixfs.go ├── files │ ├── combinator.go │ └── files.go └── sig │ └── sig.go ├── LICENSE ├── README.md ├── ipld_test.go ├── jsonld ├── ipld_test.go └── jsonld.go ├── transform.go ├── ipld.go └── walk.go /coding/pb/bin/.gitignore: -------------------------------------------------------------------------------- 1 | msgio 2 | multicodec 3 | -------------------------------------------------------------------------------- /schemas/merkleweb: -------------------------------------------------------------------------------- 1 | { 2 | "@context": { 3 | "mlink": "merkle-link", 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /coding/pb/testfile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/go-ipld-deprecated/HEAD/coding/pb/testfile -------------------------------------------------------------------------------- /coding/cbor.testfile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/go-ipld-deprecated/HEAD/coding/cbor.testfile -------------------------------------------------------------------------------- /schemas/versions: -------------------------------------------------------------------------------- 1 | Qmf1ec6n9f8kW8JTLjqaZceJVpDpZD4L3aPoJFvssBE7Eb 2 | QmR6yhcyhv4w89BQthwrL6xMrT7NnDy784UMwtSbTsrUVU 3 | -------------------------------------------------------------------------------- /schemas/publish.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | hash=$(ipfs add -r -q . | tail -n1) 3 | echo "$hash" >>versions 4 | echo "published $hash" 5 | -------------------------------------------------------------------------------- /coding/json.testfile: -------------------------------------------------------------------------------- 1 | /multicodec 2 | /json 3 | {"@codec":"/json","abc":{"mlink":"QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V"}} 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: 2 | - linux 3 | - osx 4 | 5 | language: go 6 | 7 | go: 8 | - 1.4 9 | - 1.5 10 | 11 | script: 12 | - go test -race -cpu 5 ./... 13 | 14 | sudo: false #docker containers for CI 15 | -------------------------------------------------------------------------------- /coding/Makefile: -------------------------------------------------------------------------------- 1 | 2 | pb/bin/multicodec: 3 | $(MAKE) -C pb bin/multicodec 4 | 5 | bin/convert: 6 | cd bin; go build convert.go 7 | 8 | json.testfile: pb/bin/multicodec Makefile 9 | : >$@ 10 | pb/bin/multicodec header /multicodec >>$@ 11 | pb/bin/multicodec header /json >>$@ 12 | echo '{"@codec":"/json","abc":{"mlink":"QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V"}}' >>$@ 13 | 14 | cbor.testfile: json.testfile 15 | pb/bin/multicodec header /multicodec >$@ 16 | ./convert -i $< -o $@.tmp -c '/cbor' 17 | cat $@.tmp >>$@ 18 | rm -f $@.tmp 19 | 20 | -------------------------------------------------------------------------------- /coding/pb/Makefile: -------------------------------------------------------------------------------- 1 | PB = $(wildcard *.proto) 2 | GO = $(PB:.proto=.pb.go) 3 | 4 | all: $(GO) test.pb 5 | 6 | %.pb.go: %.proto 7 | protoc --gogo_out=. --proto_path=../../../../../../:/usr/local/opt/protobuf/include:. $< 8 | 9 | clean: 10 | rm -f *.pb.go 11 | rm -f *.go 12 | 13 | testfile: bin/multicodec bin/msgio 14 | bin/multicodec header /mdagv1 >testfile 15 | bin/multicodec header /protobuf/msgio >>testfile 16 | hash=`ipfs add -q -r . | tail -n1` && \ 17 | ipfs object get "$$hash" --enc=protobuf | bin/msgio wrap >>testfile 18 | 19 | bin/multicodec: 20 | mkdir -p bin 21 | go get -d github.com/jbenet/go-multicodec/multicodec 22 | go build -o "$@" github.com/jbenet/go-multicodec/multicodec 23 | 24 | bin/msgio: 25 | mkdir -p bin 26 | go get -d github.com/jbenet/go-msgio/msgio 27 | go build -o "$@" github.com/jbenet/go-msgio/msgio 28 | -------------------------------------------------------------------------------- /_examples/commit/commit.go: -------------------------------------------------------------------------------- 1 | package commit 2 | 3 | import ( 4 | ipld "github.com/ipfs/go-ipld" 5 | ) 6 | 7 | // this would serialize to: 8 | // 9 | // { 10 | // "@context": "/ipfs//commit" 11 | // "parents": [ "", ... ] 12 | // "author": "", 13 | // "committer": "", 14 | // "object": "", 15 | // "comment": "comment as a string" 16 | // } 17 | // 18 | type Commit struct { 19 | Parents []ipld.Link // 20 | Author ipld.Link // link to an Authorship 21 | Committer ipld.Link // link to an Authorship 22 | Object ipld.Link // what we version ("tree" in git) 23 | Comment String // describes the commit 24 | } 25 | 26 | func (c *Commit) IPLDValidate() bool { 27 | // check at least one parent exists 28 | // check Parents have proper type 29 | // check author exists and has proper type 30 | // check commiter exists and has proper type 31 | // check object exists and has proper type 32 | return true 33 | } 34 | -------------------------------------------------------------------------------- /_examples/unixfs/unixfs.go: -------------------------------------------------------------------------------- 1 | package sig 2 | 3 | import ( 4 | "os" 5 | 6 | dag "github.com/ipfs/go-ipfsld/dag" 7 | ) 8 | 9 | // Dir represents a directory in unixfs. The links are 10 | // dag.Links with one additional property: 11 | // * unixMode - the full unix mode 12 | // 13 | // this would serialize to: 14 | // 15 | // { 16 | // "@context": "/ipfs//unixdir", 17 | // "": { "@value": "", "unixMode": }, 18 | // "": { "@value": "", "unixMode": }, 19 | // } 20 | // 21 | type Dir map[string]dag.Link 22 | 23 | func (d *Dir) Entry(e string) (dag.Link, error) { 24 | l, ok := d[e] 25 | if !ok { 26 | return nil, os.ErrNotExist 27 | } 28 | return l, nil 29 | } 30 | 31 | func (d *Dir) Mode(e string) (os.FileMode, error) { 32 | l, err := d.Entry(e) 33 | if err != nil { 34 | return 0, err 35 | } 36 | 37 | m, ok := l["unixMode"].(os.FileMode) 38 | if !ok { 39 | return 0, ErrInvalid 40 | } 41 | return m, nil 42 | } 43 | -------------------------------------------------------------------------------- /_examples/files/combinator.go: -------------------------------------------------------------------------------- 1 | package files 2 | 3 | import ( 4 | "bytes" 5 | "os" 6 | 7 | dag "github.com/ipfs/go-ipfsld/dag" 8 | ) 9 | 10 | type StreamCombinator interface { 11 | Apply(ctx cxt.Context, root dag.Link, store dag.Store) (io.Reader, error) 12 | } 13 | 14 | // StackStreamCombinator is a combinator that executes 15 | // stackstream code to produce binary output. 16 | type StackStreamCombinator struct { 17 | // Code is a stackstream program 18 | Code []byte 19 | } 20 | 21 | func (ssc *StackStreamCombinator) Apply(ctx cxt.Context, root dag.Node, store dag.Store) (io.Reader, error) { 22 | ... 23 | } 24 | 25 | // StreamCombinator is an object that carries some code 26 | // representing how to combine ipfs objects to produce 27 | // It may carry: 28 | // - Data: a raw data buffer 29 | // - Chunks: links to other (sub)files 30 | // - Combinator: function that produces output from Data and Chunks. 31 | type File struct { 32 | Data []byte 33 | Chunks []dag.Link 34 | Combinator dag.Link // when in doubt, concat. 35 | } 36 | -------------------------------------------------------------------------------- /_examples/sig/sig.go: -------------------------------------------------------------------------------- 1 | package sig 2 | 3 | import ( 4 | dag "github.com/ipfs/go-ipfsld/dag" 5 | ) 6 | 7 | // Signature is an object that represents a cryptographic 8 | // signature on any other merkle node. 9 | // 10 | // this would serialize to: 11 | // 12 | // { 13 | // "@context": "/ipfs//signature" 14 | // "key": "", 15 | // "object": "", 16 | // "sig": ")>" 17 | // } 18 | // 19 | type Signature struct { 20 | Key dag.Link // the signing key 21 | Object dag.Link // what is signed 22 | Sig []byte // the data representing the signature 23 | } 24 | 25 | // Sign creates a signature from a given key and a link to data. 26 | // Since this is a merkledag, signing the link is effectively the 27 | // same as an hmac signature. 28 | func Sign(key key.SigningKey, signed dag.Link) (Signature, error) { 29 | s := Signature{} 30 | s.Key = dag.LinkTo(key) 31 | s.Object = dag.LinkTo(signed) 32 | 33 | s, err := dag.Marshal(s.Object) 34 | if err != nil { 35 | return s, err 36 | } 37 | 38 | s.Sig, err = key.Sign(s) 39 | return s, err 40 | } 41 | -------------------------------------------------------------------------------- /coding/pb/ipld.proto: -------------------------------------------------------------------------------- 1 | package ipldpb; 2 | 3 | import "code.google.com/p/gogoprotobuf/gogoproto/gogo.proto"; 4 | 5 | option (gogoproto.gostring_all) = true; 6 | option (gogoproto.equal_all) = true; 7 | option (gogoproto.verbose_equal_all) = true; 8 | option (gogoproto.goproto_stringer_all) = false; 9 | option (gogoproto.stringer_all) = true; 10 | option (gogoproto.populate_all) = true; 11 | option (gogoproto.testgen_all) = true; 12 | option (gogoproto.benchgen_all) = true; 13 | option (gogoproto.marshaler_all) = true; 14 | option (gogoproto.sizer_all) = true; 15 | option (gogoproto.unmarshaler_all) = true; 16 | 17 | // An IPFS MerkleDAG Link 18 | message PBLink { 19 | 20 | // multihash of the target object 21 | optional bytes Hash = 1; 22 | 23 | // utf string name. should be unique per object 24 | optional string Name = 2; 25 | 26 | // cumulative size of target object 27 | optional uint64 Tsize = 3; 28 | } 29 | 30 | // An IPFS MerkleDAG Node 31 | message PBNode { 32 | 33 | // refs to other objects 34 | repeated PBLink Links = 2; 35 | 36 | // opaque user data 37 | optional bytes Data = 1; 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Jeromy Johnson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /coding/bin/convert.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io/ioutil" 5 | "flag" 6 | "os" 7 | 8 | mc "github.com/jbenet/go-multicodec" 9 | pb "github.com/ipfs/go-ipld/coding/pb" 10 | ipld "github.com/ipfs/go-ipld" 11 | coding "github.com/ipfs/go-ipld/coding" 12 | ) 13 | 14 | var codecs []mc.Multicodec = []mc.Multicodec{ 15 | coding.CborMulticodec(), 16 | coding.JsonMulticodec(), 17 | pb.Multicodec(), 18 | } 19 | 20 | func codecByName(name string) mc.Multicodec { 21 | for _, c := range codecs { 22 | if name == string(mc.HeaderPath(c.Header())) { 23 | return c 24 | } 25 | } 26 | return nil 27 | } 28 | 29 | func main() { 30 | infile := flag.String("i", "", "Input file") 31 | outfile := flag.String("o", "", "Output file") 32 | codecid := flag.String("c", "", "Multicodec to use") 33 | flag.Parse() 34 | file, err := ioutil.ReadFile(*infile) 35 | if err != nil { 36 | panic(err) 37 | } 38 | 39 | var n ipld.Node 40 | codec := coding.Multicodec() 41 | 42 | if err := mc.Unmarshal(codec, file, &n); err != nil { 43 | panic(err) 44 | } 45 | 46 | codec = codecByName(*codecid) 47 | if codec == nil { 48 | panic("Could not find codec " + *codecid) 49 | } 50 | 51 | delete(n, ipld.CodecKey) 52 | 53 | encoded, err := mc.Marshal(codec, &n) 54 | if err != nil { 55 | panic(err) 56 | } 57 | 58 | f, err := os.Create(*outfile) 59 | if err != nil { 60 | panic(err) 61 | } 62 | defer f.Close() 63 | 64 | _, err = f.Write(encoded); 65 | if err != nil { 66 | panic(err) 67 | } 68 | } 69 | 70 | 71 | -------------------------------------------------------------------------------- /_examples/files/files.go: -------------------------------------------------------------------------------- 1 | package files 2 | 3 | import ( 4 | "bytes" 5 | "os" 6 | 7 | dag "github.com/ipfs/go-ipfsld/dag" 8 | ) 9 | 10 | // File represents a readable byte stream. 11 | // It may carry: 12 | // - Data: a raw data buffer 13 | // - Chunks: links to other (sub)files 14 | // - Combinator: function that produces output from Data and Chunks. 15 | type File struct { 16 | Data []byte 17 | Chunks []dag.Link 18 | Combinator dag.Link // when in doubt, concat. 19 | } 20 | 21 | // Reader returns an io.Reader which will read from 22 | // the combinator. 23 | func (f *File) Reader() (io.Reader, error) { 24 | // if no combinator is defined, output only Data. 25 | if f.Combinator == nil { 26 | return bytes.NewReader(f.Data) 27 | } 28 | 29 | l, err := d.Entry(e) 30 | if err != nil { 31 | return 0, err 32 | } 33 | 34 | m, ok := l["unixMode"] 35 | if !ok { 36 | return 0, ErrInvalid 37 | } 38 | 39 | mc, ok := m.(os.FileMode) 40 | if !ok { 41 | return 0, ErrInvalid 42 | } 43 | 44 | return m, nil 45 | } 46 | 47 | type File struct { 48 | Data []byte 49 | Chunks []dag.Link 50 | } 51 | 52 | func Reader(f *File, s *dag.Store) (io.Reader, error) { 53 | return ReaderCtx(context.Background(), f, s) 54 | } 55 | 56 | func ReaderCtx(ctx cxt.Context, f *File, store *dag.Store) (io.Reader, error) { 57 | if f.Combinator == nil { 58 | return bytes.NewReader(f.Data), nil 59 | } 60 | 61 | var c Combinator 62 | if err := store.TypedGetCtx(ctx, f.Combinator.Hash(), &c); err != nil { 63 | return nil, err 64 | } 65 | 66 | dag.Unmarshal(cn) 67 | r := c.Combine() 68 | } 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **This package is deprecated!** 2 | 3 | See instead: 4 | 5 | - Content ID / CID: https://github.com/ipfs/go-cid 6 | - Node interface for IPLD: https://github.com/ipfs/go-ipld-format 7 | - CBOR IPLD Node: https://github.com/ipfs/go-ipld-cbor 8 | - Git IPLD Node: https://github.com/ipfs/go-ipld-git 9 | - Ethereum IPLD Node: https://github.com/ipfs/go-ipld-eth 10 | - Bitcoin IPLD Node: https://github.com/ipfs/go-ipld-btc 11 | - Zcash IPLD Node: https://github.com/ipfs/go-ipld-zcash 12 | 13 | 14 | # go-ipld 15 | 16 | [![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) 17 | [![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/) 18 | [![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) 19 | [![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) 20 | 21 | > The Go implementation of IPLD 22 | 23 | This is the Go implementation of the [IPLD spec](https://github.com/ipld/specs/blob/master/IPLD.md). 24 | 25 | WIP 26 | 27 | ## Install 28 | 29 | TODO 30 | 31 | ## Usage 32 | 33 | TODO 34 | 35 | ## Contribute 36 | 37 | Feel free to join in. All welcome. Open an [issue](https://github.com/ipfs/go-ipld/issues)! 38 | 39 | This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md). 40 | 41 | ### Want to hack on IPFS? 42 | 43 | [![](https://cdn.rawgit.com/jbenet/contribute-ipfs-gif/master/img/contribute.gif)](https://github.com/ipfs/community/blob/master/contributing.md) 44 | 45 | ## License 46 | 47 | MIT 48 | -------------------------------------------------------------------------------- /coding/coding.go: -------------------------------------------------------------------------------- 1 | package ipfsld 2 | 3 | import ( 4 | mc "github.com/jbenet/go-multicodec" 5 | mccbor "github.com/jbenet/go-multicodec/cbor" 6 | mcmux "github.com/jbenet/go-multicodec/mux" 7 | 8 | ipld "github.com/ipfs/go-ipld" 9 | pb "github.com/ipfs/go-ipld/coding/pb" 10 | ) 11 | 12 | // defaultCodec is the default applied if user does not specify a codec. 13 | // Most new objects will never specify a codec. We track the codecs with 14 | // the object so that multiple people using the same object will continue 15 | // to marshal using the same codec. the only reason this is important is 16 | // that the hashes must be the same. 17 | var defaultCodec string 18 | 19 | var muxCodec *mcmux.Multicodec 20 | 21 | func init() { 22 | // by default, always encode things as cbor 23 | defaultCodec = string(mc.HeaderPath(mccbor.Header)) 24 | muxCodec = mcmux.MuxMulticodec([]mc.Multicodec{ 25 | CborMulticodec(), 26 | JsonMulticodec(), 27 | pb.Multicodec(), 28 | }, selectCodec) 29 | } 30 | 31 | // Multicodec returns a muxing codec that marshals to 32 | // whatever codec makes sense depending on what information 33 | // the IPLD object itself carries 34 | func Multicodec() mc.Multicodec { 35 | return muxCodec 36 | } 37 | 38 | func selectCodec(v interface{}, codecs []mc.Multicodec) mc.Multicodec { 39 | vn, ok := v.(*ipld.Node) 40 | if !ok { 41 | return nil 42 | } 43 | 44 | codecKey, err := codecKey(*vn) 45 | if err != nil { 46 | return nil 47 | } 48 | 49 | for _, c := range codecs { 50 | if codecKey == string(mc.HeaderPath(c.Header())) { 51 | return c 52 | } 53 | } 54 | 55 | return nil // no codec 56 | } 57 | 58 | func codecKey(n ipld.Node) (string, error) { 59 | chdr, ok := (n)[ipld.CodecKey] 60 | if !ok { 61 | // if no codec is defined, use our default codec 62 | chdr = defaultCodec 63 | if pb.IsOldProtobufNode(n) { 64 | chdr = string(pb.Header) 65 | } 66 | } 67 | 68 | chdrs, ok := chdr.(string) 69 | if !ok { 70 | // if chdr is not a string, cannot read codec. 71 | return "", mc.ErrType 72 | } 73 | 74 | return chdrs, nil 75 | } 76 | -------------------------------------------------------------------------------- /coding/transform.go: -------------------------------------------------------------------------------- 1 | package ipfsld 2 | 3 | import ( 4 | "io" 5 | 6 | mc "github.com/jbenet/go-multicodec" 7 | mcjson "github.com/jbenet/go-multicodec/json" 8 | mccbor "github.com/jbenet/go-multicodec/cbor" 9 | ipld "github.com/ipfs/go-ipld" 10 | ) 11 | 12 | type transformCodec struct { 13 | mc.Multicodec 14 | } 15 | 16 | type transformDecoder struct { 17 | mc.Decoder 18 | } 19 | 20 | func JsonMulticodec() mc.Multicodec { 21 | return &transformCodec{mcjson.Multicodec(false)} 22 | } 23 | 24 | func CborMulticodec() mc.Multicodec { 25 | return &transformCodec{mccbor.Multicodec()} 26 | } 27 | 28 | func (c *transformCodec) Decoder(r io.Reader) mc.Decoder { 29 | return &transformDecoder{ c.Multicodec.Decoder(r) } 30 | } 31 | 32 | func (c *transformDecoder) Decode(v interface{}) error { 33 | err := c.Decoder.Decode(v) 34 | if err == nil { 35 | convert(v) 36 | } 37 | return err 38 | } 39 | 40 | func convert(val interface{}) interface{} { 41 | switch val.(type) { 42 | case *map[string]interface{}: 43 | vmi := val.(*map[string]interface{}) 44 | n := ipld.Node{} 45 | for k, v := range *vmi { 46 | n[k] = convert(v) 47 | (*vmi)[k] = convert(v) 48 | } 49 | return &n 50 | case map[string]interface{}: 51 | vmi := val.(map[string]interface{}) 52 | n := ipld.Node{} 53 | for k, v := range vmi { 54 | n[k] = convert(v) 55 | vmi[k] = convert(v) 56 | } 57 | return n 58 | case *map[interface{}]interface{}: 59 | vmi := val.(*map[interface{}]interface{}) 60 | n := ipld.Node{} 61 | for k, v := range *vmi { 62 | if k2, ok := k.(string); ok { 63 | n[k2] = convert(v) 64 | (*vmi)[k2] = convert(v) 65 | } 66 | } 67 | return &n 68 | case map[interface{}]interface{}: 69 | vmi := val.(map[interface{}]interface{}) 70 | n := ipld.Node{} 71 | for k, v := range vmi { 72 | if k2, ok := k.(string); ok { 73 | n[k2] = convert(v) 74 | vmi[k2] = convert(v) 75 | } 76 | } 77 | return n 78 | case *[]interface{}: 79 | convert(*val.(*[]interface{})) 80 | case []interface{}: 81 | slice := val.([]interface{}) 82 | for k, v := range slice { 83 | slice[k] = convert(v) 84 | } 85 | case *ipld.Node: 86 | convert(*val.(*ipld.Node)) 87 | case ipld.Node: 88 | n := val.(ipld.Node) 89 | for k, v := range n { 90 | n[k] = convert(v) 91 | } 92 | default: 93 | } 94 | return val 95 | } 96 | 97 | -------------------------------------------------------------------------------- /ipld_test.go: -------------------------------------------------------------------------------- 1 | package ipld 2 | 3 | import ( 4 | "testing" 5 | 6 | mh "github.com/jbenet/go-multihash" 7 | ) 8 | 9 | type TC struct { 10 | src Node 11 | links map[string]string 12 | typ string 13 | ctx interface{} 14 | } 15 | 16 | var testCases []TC 17 | 18 | func mmh(b58 string) mh.Multihash { 19 | h, err := mh.FromB58String(b58) 20 | if err != nil { 21 | panic("failed to decode multihash") 22 | } 23 | return h 24 | } 25 | 26 | func init() { 27 | testCases = append(testCases, TC{ 28 | src: Node{ 29 | "foo": "bar", 30 | "bar": []int{1, 2, 3}, 31 | "baz": Node{ 32 | "mlink": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo", 33 | }, 34 | "test": Node { 35 | // This is not a link because mlink is not a string but a Node 36 | "mlink": Node{ 37 | "mlink": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo", 38 | }, 39 | }, 40 | }, 41 | links: map[string]string{ 42 | "baz": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo", 43 | "test/mlink": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo", 44 | }, 45 | typ: "", 46 | ctx: nil, 47 | }, TC{ 48 | src: Node{ 49 | "@context": "/ipfs/QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo/mdag", 50 | "baz": Node{ 51 | "mlink": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo", 52 | }, 53 | "bazz": Node{ 54 | "mlink": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo", 55 | }, 56 | "bar": Node{ 57 | "mlink": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPb", 58 | }, 59 | "bar2": Node{ 60 | "@bar": Node{ 61 | "mlink": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPa", 62 | }, 63 | "\\@foo": Node{ 64 | "mlink": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPa", 65 | }, 66 | }, 67 | }, 68 | links: map[string]string{ 69 | "baz": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo", 70 | "bazz": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo", 71 | "bar": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPb", 72 | "bar2/@foo": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPa", 73 | }, 74 | typ: "", 75 | ctx: "/ipfs/QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo/mdag", 76 | }) 77 | } 78 | 79 | func TestParsing(t *testing.T) { 80 | for tci, tc := range testCases { 81 | t.Logf("===== Test case #%d =====", tci) 82 | doc := tc.src 83 | 84 | // check links 85 | links := doc.Links() 86 | t.Logf("links: %#v", links) 87 | if len(links) != len(tc.links) { 88 | t.Errorf("links do not match, not the same number of links, expected %d, got %d", len(tc.links), len(links)) 89 | } 90 | for k, l1 := range tc.links { 91 | l2 := links[k] 92 | if l1 != l2["mlink"] { 93 | t.Errorf("links do not match. %d/%#v %#v != %#v[mlink]", tci, k, l1, l2) 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /jsonld/ipld_test.go: -------------------------------------------------------------------------------- 1 | package jsonld 2 | 3 | import ( 4 | "testing" 5 | "reflect" 6 | 7 | ipld "github.com/ipfs/go-ipld" 8 | ) 9 | 10 | type TC struct { 11 | src ipld.Node 12 | jsonld ipld.Node 13 | } 14 | 15 | var testCases []TC 16 | 17 | func init() { 18 | testCases = append(testCases, TC{ 19 | src: ipld.Node{ 20 | "foo": "bar", 21 | "bar": []int{1, 2, 3}, 22 | "baz": ipld.Node{ 23 | "mlink": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo", 24 | }, 25 | }, 26 | jsonld: ipld.Node{ 27 | "foo": "bar", 28 | "bar": []int{1, 2, 3}, 29 | "baz": ipld.Node{ 30 | "mlink": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo", 31 | }, 32 | }, 33 | }, TC{ 34 | src: ipld.Node{ 35 | "foo": "bar", 36 | "bar": []int{1, 2, 3}, 37 | "@container": "@index", 38 | "@index": "links", 39 | "baz": ipld.Node{ 40 | "mlink": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo", 41 | }, 42 | }, 43 | jsonld: ipld.Node{ 44 | "links": ipld.Node{ 45 | "foo": "bar", 46 | "bar": []int{1, 2, 3}, 47 | "baz": ipld.Node{ 48 | "mlink": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo", 49 | }, 50 | }, 51 | }, 52 | }, TC{ 53 | src: ipld.Node{ 54 | "@attrs": ipld.Node{ 55 | "attr": "val", 56 | }, 57 | "foo": "bar", 58 | "@index": "files", 59 | "@type": "commit", 60 | "@container": "@index", 61 | "@context": "/ipfs/QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo/mdag", 62 | "baz": ipld.Node{ 63 | "foobar": "barfoo", 64 | "mlink": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo", 65 | }, 66 | "\\@bazz": ipld.Node{ 67 | "mlink": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo", 68 | }, 69 | "bar/ra\\b": ipld.Node{ 70 | "mlink": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPb", 71 | }, 72 | "bar": ipld.Node{ 73 | "@container": "@index", 74 | "foo": ipld.Node{ 75 | "mlink": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPa", 76 | }, 77 | }, 78 | }, 79 | jsonld: ipld.Node{ 80 | "attr": "val", 81 | "@type": "commit", 82 | "@context": "/ipfs/QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo/mdag", 83 | "files": ipld.Node{ 84 | "foo": "bar", 85 | "baz": ipld.Node{ 86 | "foobar": "barfoo", 87 | "mlink": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo", 88 | }, 89 | "@bazz": ipld.Node{ 90 | "mlink": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo", 91 | }, 92 | "bar/ra\\b": ipld.Node{ 93 | "mlink": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPb", 94 | }, 95 | "bar": ipld.Node{ 96 | }, 97 | }, 98 | }, 99 | }) 100 | } 101 | 102 | func TestParsing(t *testing.T) { 103 | for tci, tc := range testCases { 104 | t.Logf("===== Test case #%d =====", tci) 105 | doc := tc.src 106 | 107 | // check JSON-LD mode 108 | jsonld := ToLinkedDataAll(doc) 109 | if !reflect.DeepEqual(tc.jsonld, jsonld) { 110 | t.Errorf("JSON-LD version mismatch.\nGot: %#v\nExpect: %#v", jsonld, tc.jsonld) 111 | } else { 112 | t.Log("JSON-LD version OK") 113 | } 114 | 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /jsonld/jsonld.go: -------------------------------------------------------------------------------- 1 | package jsonld 2 | 3 | import( 4 | ipld "github.com/ipfs/go-ipld" 5 | ) 6 | 7 | const DefaultIndexName string = "@index" 8 | 9 | func containerIndexName(n ipld.Node, defaultval string) string { 10 | var index_name string = defaultval 11 | 12 | index_val, ok := n["@index"] 13 | if str, is_string := index_val.(string); ok && is_string { 14 | index_name = str 15 | } 16 | 17 | return index_name 18 | } 19 | 20 | func isContainerIndex(n ipld.Node) bool { 21 | return n["@container"] == "@index" 22 | } 23 | 24 | // Like ToLinkedDataAll but on the root node only, for use in Walk 25 | func ToLinkedData(d ipld.Node) ipld.Node { 26 | attrs, directives, _, index := ParseNodeIndex(d) 27 | for k, v := range directives { 28 | if k != "@container" { 29 | attrs[k] = v 30 | } 31 | } 32 | if len(index) > 0 { 33 | index_name := containerIndexName(attrs, DefaultIndexName) 34 | delete(attrs, "@index") 35 | if index_name[0] != '@' { 36 | attrs[index_name] = index 37 | } 38 | } 39 | return attrs 40 | } 41 | 42 | // Reorganize the data to be valid JSON-LD. This expand custom IPLD directives 43 | // and unescape keys. 44 | // 45 | // The main processing now is to transform a IPLD data structure like this: 46 | // 47 | // { 48 | // "@container": "@index", 49 | // "@index": "index-name", 50 | // "@attrs": { 51 | // "key": "value", 52 | // }, 53 | // "index": { ... } 54 | // } 55 | // 56 | // to: 57 | // 58 | // { 59 | // "key": "value", 60 | // "index-name": { 61 | // "index": { ... } 62 | // } 63 | // } 64 | // 65 | // In that case, it is good practice to define in the context the following 66 | // type (this function cannot change the context): 67 | // 68 | // "index-name": { "@container": "@index" } 69 | // 70 | func ToLinkedDataAll(d ipld.Node) ipld.Node { 71 | res, err := ipld.Transform(d, func(root, curr ipld.Node, path []string, err error) (ipld.Node, error) { 72 | return ToLinkedData(curr), err 73 | }) 74 | if err != nil { 75 | panic(err) // should not happen 76 | } 77 | return res 78 | } 79 | 80 | func copyNode(n ipld.Node) ipld.Node { 81 | var res ipld.Node = ipld.Node{} 82 | for k, v := range n { 83 | res[k] = v 84 | } 85 | return res 86 | } 87 | 88 | func ParseNodeIndex(n ipld.Node) (attrs, directives, index ipld.Node, escapedIndex ipld.Node) { 89 | attrs = ipld.Node{} 90 | directives = ipld.Node{} 91 | index = ipld.Node{} 92 | escapedIndex = ipld.Node{} 93 | 94 | if real_attrs, ok := n["@attrs"]; ok { 95 | if attrs_node, ok := real_attrs.(ipld.Node); ok { 96 | attrs = copyNode(attrs_node) 97 | } 98 | } 99 | 100 | index_container := isContainerIndex(n) 101 | 102 | for key, val := range n { 103 | if key == "@attrs" { 104 | continue 105 | } else if key[0] == '@' { 106 | if key == "@index" { 107 | attrs[key] = val 108 | } else { 109 | directives[key] = val 110 | } 111 | } else { 112 | if index_container { 113 | escapedIndex[key] = val 114 | index[ipld.UnescapePathComponent(key)] = val 115 | } else { 116 | attrs[ipld.UnescapePathComponent(key)] = val 117 | } 118 | } 119 | } 120 | 121 | return 122 | } 123 | 124 | -------------------------------------------------------------------------------- /transform.go: -------------------------------------------------------------------------------- 1 | package ipld 2 | 3 | import ( 4 | "errors" 5 | "strconv" 6 | "path" 7 | ) 8 | 9 | // TransformFunc is the type of the function called for each node visited by 10 | // Transform. The root argument is the node from which the Transform began. The 11 | // curr argument is the currently visited node. The path argument is the 12 | // traversal path, from root to curr. 13 | // 14 | // If there was a problem walking to curr, the err argument will describe the 15 | // problem and the function can decide how to handle the error (and Transform 16 | // _will not_ descend into any of the children of curr). 17 | // 18 | // TransformFunc may return a node, in which case the returned node will be used 19 | // for further traversal instead of the curr node. 20 | // 21 | // TransformFunc may return an error. If the error is the special SkipNode 22 | // error, the children of curr are skipped. All other errors halt processing 23 | // early. 24 | type TransformFunc func(root, curr Node, path []string, err error) (Node, error) 25 | 26 | // Transform traverses the given root node and all its children, calling 27 | // TransformFunc with every Node visited, including root. All errors that arise 28 | // while visiting nodes are passed to given TransformFunc. The traversing 29 | // algorithm is the same as the Walk function. 30 | // 31 | // Transform returns a node constructed from the different nodes returned by 32 | // TransformFunc. 33 | func Transform(root Node, transformFn TransformFunc) (Node, error) { 34 | n, err := transform(root, root, nil, transformFn) 35 | if node, ok := n.(Node); ok { 36 | return node, err 37 | } else { 38 | return nil, err 39 | } 40 | } 41 | 42 | // TransformFrom is just like Transform, but starts the Walk at given startFrom 43 | // sub-node. 44 | func TransformFrom(root Node, startFrom []string, transformFn TransformFunc) (interface{}, error) { 45 | start := GetPathCmp(root, startFrom) 46 | if start == nil { 47 | return nil, errors.New("no descendant at " + path.Join(startFrom...)) 48 | } 49 | return transform(root, start, startFrom, transformFn) 50 | } 51 | 52 | // transform is used to implement Transform 53 | func transform(root Node, curr interface{}, npath []string, transformFunc TransformFunc) (interface{}, error) { 54 | 55 | if nc, ok := curr.(Node); ok { // it's a node! 56 | // first, call user's WalkFunc. 57 | newnode, err := transformFunc(root, nc, npath, nil) 58 | res := Node{} 59 | if err == SkipNode { 60 | return newnode, nil // ok, let's skip this one. 61 | } else if err != nil { 62 | return nil, err // something bad happened, return early. 63 | } else if newnode != nil { 64 | nc = newnode 65 | } 66 | 67 | // then recurse. 68 | for k, v := range nc { 69 | n, err := transform(root, v, append(npath, k), transformFunc) 70 | if err != nil { 71 | return nil, err 72 | } else if n != nil { 73 | res[k] = n 74 | } 75 | } 76 | 77 | return res, nil 78 | 79 | } else if sc, ok := curr.([]interface{}); ok { // it's a slice! 80 | res := []interface{}{} 81 | for i, v := range sc { 82 | k := strconv.Itoa(i) 83 | n, err := transform(root, v, append(npath, k), transformFunc) 84 | if err != nil { 85 | return nil, err 86 | } else if n != nil { 87 | res = append(res, n) 88 | } 89 | } 90 | return res, nil 91 | 92 | } else { // it's just data. 93 | // ignore it. 94 | } 95 | return curr, nil 96 | } 97 | 98 | -------------------------------------------------------------------------------- /coding/pb/pbcodec_test.go: -------------------------------------------------------------------------------- 1 | package ipldpb 2 | 3 | import ( 4 | "bytes" 5 | "encoding/hex" 6 | "io/ioutil" 7 | "testing" 8 | "reflect" 9 | 10 | mc "github.com/jbenet/go-multicodec" 11 | mcproto "github.com/jbenet/go-multicodec/protobuf" 12 | 13 | ipld "github.com/ipfs/go-ipld" 14 | ) 15 | 16 | var testfile []byte 17 | 18 | func init() { 19 | var err error 20 | testfile, err = ioutil.ReadFile("testfile") 21 | if err != nil { 22 | panic("could not read testfile. please run: make testfile") 23 | } 24 | } 25 | 26 | func TestPBDecode(t *testing.T) { 27 | c := mcproto.Multicodec(&PBNode{}) 28 | buf := bytes.NewBuffer(testfile) 29 | dec := c.Decoder(buf) 30 | 31 | // pass the /mdagv1 32 | if err := mc.ConsumeHeader(buf, Header); err != nil { 33 | t.Fatal("failed to consume header", err) 34 | } 35 | 36 | var pbn PBNode 37 | if err := dec.Decode(&pbn); err != nil { 38 | t.Fatal("failed to decode", err) 39 | } 40 | 41 | if len(pbn.Links) < 7 { 42 | t.Fatal("incorrect number of links") 43 | } 44 | if len(pbn.Data) == 0 { 45 | t.Error("should have some data") 46 | } 47 | 48 | findLink := func(s string) *PBLink { 49 | for _, l := range pbn.Links { 50 | if *l.Name == s { 51 | return l 52 | } 53 | } 54 | return nil 55 | } 56 | 57 | makefile := findLink("Makefile") 58 | if makefile == nil { 59 | t.Error("did not find Makefile") 60 | } else { 61 | if *makefile.Tsize < 700 || *makefile.Tsize > 4096 { 62 | t.Error("makefile incorrect size") 63 | } 64 | } 65 | } 66 | 67 | func TestPB2LD(t *testing.T) { 68 | buf := bytes.NewBuffer(testfile) 69 | dec := Multicodec().Decoder(buf) 70 | 71 | var n ipld.Node 72 | if err := dec.Decode(&n); err != nil { 73 | t.Fatal("failed to decode", err) 74 | } 75 | 76 | attrs, ok := n["@attrs"].(ipld.Node) 77 | if !ok { 78 | t.Log(n) 79 | t.Fatal("invalid ipld.@attrs") 80 | } 81 | 82 | data, ok := attrs["data"].([]byte) 83 | if !ok { 84 | t.Log(n) 85 | t.Fatal("invalid ipld.@attrs.data") 86 | } 87 | if len(data) == 0 { 88 | t.Error("should have some data") 89 | } 90 | 91 | links, ok := attrs["links"].([]ipld.Node) 92 | if !ok { 93 | t.Fatal("invalid ipld.@attrs.links") 94 | } 95 | if len(links) < 7 { 96 | t.Fatal("incorrect number of links") 97 | } 98 | 99 | findLink := func(s string) ipld.Node { 100 | for i, l := range links { 101 | s2, ok := l["name"].(string) 102 | if !ok { 103 | t.Log(l) 104 | t.Fatalf("invalid ipld.links[%d].name", i) 105 | } 106 | if s2 == s { 107 | return l 108 | } 109 | } 110 | return nil 111 | } 112 | 113 | makefileLink := findLink("Makefile") 114 | if makefileLink == nil { 115 | t.Error("did not find Makefile") 116 | } 117 | 118 | makefile := n["Makefile"].(ipld.Node) 119 | if makefile == nil { 120 | t.Error("did not find Makefile") 121 | } else { 122 | size, ok := makefile["size"].(uint64) 123 | if !ok { 124 | t.Log(makefile) 125 | t.Fatal("invalid ipld.links[makefile].size") 126 | } 127 | if size < 700 || size > 4096 { 128 | t.Log(makefile) 129 | t.Error("makefile incorrect size") 130 | } 131 | if ! reflect.DeepEqual(makefile, makefileLink) { 132 | t.Error("makefile and @attrs.links[name=makefile] are not the same") 133 | } 134 | } 135 | } 136 | 137 | func TestLD2PB(t *testing.T) { 138 | decbuf := bytes.NewBuffer(testfile) 139 | encbuf := bytes.NewBuffer(nil) 140 | dec := Multicodec().Decoder(decbuf) 141 | enc := Multicodec().Encoder(encbuf) 142 | 143 | var n ipld.Node 144 | if err := dec.Decode(&n); err != nil { 145 | t.Fatal("failed to decode", err) 146 | } 147 | 148 | if err := enc.Encode(&n); err != nil { 149 | t.Log(n) 150 | t.Fatal("failed to encode", err) 151 | } 152 | 153 | if !bytes.Equal(testfile, encbuf.Bytes()) { 154 | t.Log(hex.Dump(testfile)) 155 | t.Log(hex.Dump(encbuf.Bytes())) 156 | t.Fatal("decoded bytes != encoded bytes") 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /coding/coding_test.go: -------------------------------------------------------------------------------- 1 | package ipfsld 2 | 3 | import ( 4 | "io/ioutil" 5 | "testing" 6 | "reflect" 7 | "bytes" 8 | 9 | ipld "github.com/ipfs/go-ipld" 10 | 11 | mc "github.com/jbenet/go-multicodec" 12 | mctest "github.com/jbenet/go-multicodec/test" 13 | ) 14 | 15 | var codedFiles map[string][]byte = map[string][]byte{ 16 | "json.testfile": []byte{}, 17 | "cbor.testfile": []byte{}, 18 | } 19 | 20 | func init() { 21 | for fname := range codedFiles { 22 | var err error 23 | codedFiles[fname], err = ioutil.ReadFile(fname) 24 | if err != nil { 25 | panic("could not read " + fname + ". please run: make " + fname) 26 | } 27 | } 28 | } 29 | 30 | type TC struct { 31 | cbor []byte 32 | src ipld.Node 33 | links map[string]ipld.Link 34 | typ string 35 | ctx interface{} 36 | } 37 | 38 | var testCases []TC 39 | 40 | func init() { 41 | testCases = append(testCases, TC{ 42 | []byte{}, 43 | ipld.Node{ 44 | "foo": "bar", 45 | "bar": []int{1, 2, 3}, 46 | "baz": ipld.Node{ 47 | "@type": "mlink", 48 | "hash": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo", 49 | }, 50 | }, 51 | map[string]ipld.Link{ 52 | "baz": {"@type": "mlink", "hash": ("QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo")}, 53 | }, 54 | "", 55 | nil, 56 | }) 57 | 58 | testCases = append(testCases, TC{ 59 | []byte{}, 60 | ipld.Node{ 61 | "foo": "bar", 62 | "@type": "commit", 63 | "@context": "/ipfs/QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo/mdag", 64 | "baz": ipld.Node{ 65 | "@type": "mlink", 66 | "hash": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo", 67 | }, 68 | "bazz": ipld.Node{ 69 | "@type": "mlink", 70 | "hash": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo", 71 | }, 72 | "bar": ipld.Node{ 73 | "@type": "mlinkoo", 74 | "hash": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo", 75 | }, 76 | "bar2": ipld.Node{ 77 | "foo": ipld.Node{ 78 | "@type": "mlink", 79 | "hash": "QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo", 80 | }, 81 | }, 82 | }, 83 | map[string]ipld.Link{ 84 | "baz": {"@type": "mlink", "hash": ("QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo")}, 85 | "bazz": {"@type": "mlink", "hash": ("QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo")}, 86 | "bar2/foo": {"@type": "mlink", "hash": ("QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo")}, 87 | }, 88 | "", 89 | "/ipfs/QmZku7P7KeeHAnwMr6c4HveYfMzmtVinNXzibkiNbfDbPo/mdag", 90 | }) 91 | 92 | } 93 | 94 | func TestHeaderMC(t *testing.T) { 95 | codec := Multicodec() 96 | for _, tc := range testCases { 97 | mctest.HeaderTest(t, codec, &tc.src) 98 | } 99 | } 100 | 101 | func TestRoundtripBasicMC(t *testing.T) { 102 | codec := Multicodec() 103 | for _, tca := range testCases { 104 | var tcb ipld.Node 105 | mctest.RoundTripTest(t, codec, &(tca.src), &tcb) 106 | } 107 | } 108 | 109 | // Test decoding and encoding a json and cbor file 110 | func TestCodecsDecodeEncode(t *testing.T) { 111 | for fname, testfile := range codedFiles { 112 | var n ipld.Node 113 | codec := Multicodec() 114 | 115 | if err := mc.Unmarshal(codec, testfile, &n); err != nil { 116 | t.Log(testfile) 117 | t.Error(err) 118 | continue 119 | } 120 | 121 | linksExpected := map[string]ipld.Link{ 122 | "abc": ipld.Link { 123 | "mlink": "QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V", 124 | }, 125 | } 126 | linksActual := ipld.Links(n) 127 | if !reflect.DeepEqual(linksExpected, linksActual) { 128 | t.Logf("Expected: %#v", linksExpected) 129 | t.Logf("Actual: %#v", linksActual) 130 | t.Logf("node: %#v\n", n) 131 | t.Error("Links are not expected in " + fname) 132 | continue 133 | } 134 | 135 | encoded, err := mc.Marshal(codec, &n) 136 | if err != nil { 137 | t.Error(err) 138 | return 139 | } 140 | 141 | if !bytes.Equal(testfile, encoded) { 142 | t.Error("marshalled values not equal in " + fname) 143 | t.Log(string(testfile)) 144 | t.Log(string(encoded)) 145 | t.Log(testfile) 146 | t.Log(encoded) 147 | } 148 | } 149 | } 150 | 151 | -------------------------------------------------------------------------------- /coding/pb/pbcodec.go: -------------------------------------------------------------------------------- 1 | package ipldpb 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "io" 7 | 8 | mc "github.com/jbenet/go-multicodec" 9 | mcproto "github.com/jbenet/go-multicodec/protobuf" 10 | 11 | ipld "github.com/ipfs/go-ipld" 12 | ) 13 | 14 | var Header []byte 15 | 16 | var ( 17 | errInvalidData = fmt.Errorf("invalid merkledag v1 protobuf, Data not bytes") 18 | errInvalidLink = fmt.Errorf("invalid merkledag v1 protobuf, invalid Links") 19 | ) 20 | 21 | func init() { 22 | Header = mc.Header([]byte("/mdagv1")) 23 | } 24 | 25 | type codec struct { 26 | pbc mc.Multicodec 27 | } 28 | 29 | func Multicodec() mc.Multicodec { 30 | var n *PBNode 31 | return &codec{mcproto.Multicodec(n)} 32 | } 33 | 34 | func (c *codec) Encoder(w io.Writer) mc.Encoder { 35 | return &encoder{w: w, c: c, pbe: c.pbc.Encoder(w)} 36 | } 37 | 38 | func (c *codec) Decoder(r io.Reader) mc.Decoder { 39 | return &decoder{r: r, c: c, pbd: c.pbc.Decoder(r)} 40 | } 41 | 42 | func (c *codec) Header() []byte { 43 | return Header 44 | } 45 | 46 | type encoder struct { 47 | w io.Writer 48 | c *codec 49 | pbe mc.Encoder 50 | } 51 | 52 | type decoder struct { 53 | r io.Reader 54 | c *codec 55 | pbd mc.Decoder 56 | } 57 | 58 | func (c *encoder) Encode(v interface{}) error { 59 | nv, ok := v.(*ipld.Node) 60 | if !ok { 61 | return errors.New("must encode *ipld.Node") 62 | } 63 | 64 | if _, err := c.w.Write(c.c.Header()); err != nil { 65 | return err 66 | } 67 | 68 | n, err := ld2pbNode(nv) 69 | if err != nil { 70 | return err 71 | } 72 | 73 | return c.pbe.Encode(n) 74 | } 75 | 76 | func (c *decoder) Decode(v interface{}) error { 77 | nv, ok := v.(*ipld.Node) 78 | if !ok { 79 | return errors.New("must decode to *ipld.Node") 80 | } 81 | 82 | if err := mc.ConsumeHeader(c.r, c.c.Header()); err != nil { 83 | return err 84 | } 85 | 86 | var pbn PBNode 87 | if err := c.pbd.Decode(&pbn); err != nil { 88 | return err 89 | } 90 | 91 | pb2ldNode(&pbn, nv) 92 | return nil 93 | } 94 | 95 | func ld2pbNode(in *ipld.Node) (*PBNode, error) { 96 | n := *in 97 | var pbn PBNode 98 | var attrs ipld.Node 99 | 100 | if attrsvalue, hasattrs := n["@attrs"]; hasattrs { 101 | var ok bool 102 | attrs, ok = attrsvalue.(ipld.Node) 103 | if !ok { 104 | return nil, errInvalidData 105 | } 106 | } else { 107 | return &pbn, nil 108 | } 109 | 110 | if data, hasdata := attrs["data"]; hasdata { 111 | data, ok := data.([]byte) 112 | if !ok { 113 | return nil, errInvalidData 114 | } 115 | pbn.Data = data 116 | } 117 | 118 | if links, haslinks := attrs["links"]; haslinks { 119 | links, ok := links.([]ipld.Node) 120 | if !ok { 121 | return nil, errInvalidLink 122 | } 123 | 124 | for _, link := range links { 125 | pblink := ld2pbLink(link) 126 | if pblink == nil { 127 | return nil, fmt.Errorf("%s (%s)", errInvalidLink, link["name"]) 128 | } 129 | pbn.Links = append(pbn.Links, pblink) 130 | } 131 | } 132 | return &pbn, nil 133 | } 134 | 135 | func pb2ldNode(pbn *PBNode, in *ipld.Node) { 136 | *in = make(ipld.Node) 137 | n := *in 138 | 139 | links := make([]ipld.Node, len(pbn.Links)) 140 | for i, link := range pbn.Links { 141 | links[i] = pb2ldLink(link) 142 | n[ipld.EscapePathComponent(link.GetName())] = links[i] 143 | } 144 | 145 | n["@attrs"] = ipld.Node{ 146 | "links": links, 147 | "data": pbn.Data, 148 | } 149 | } 150 | 151 | func pb2ldLink(pbl *PBLink) (link ipld.Node) { 152 | defer func() { 153 | if recover() != nil { 154 | link = nil 155 | } 156 | }() 157 | 158 | link = make(ipld.Node) 159 | link["hash"] = pbl.Hash 160 | link["name"] = *pbl.Name 161 | link["size"] = uint64(*pbl.Tsize) 162 | return link 163 | } 164 | 165 | func ld2pbLink(link ipld.Node) (pbl *PBLink) { 166 | defer func() { 167 | if recover() != nil { 168 | pbl = nil 169 | } 170 | }() 171 | 172 | hash := link["hash"].([]byte) 173 | name := link["name"].(string) 174 | size := link["size"].(uint64) 175 | 176 | pbl = &PBLink{} 177 | pbl.Hash = hash 178 | pbl.Name = &name 179 | pbl.Tsize = &size 180 | return pbl 181 | } 182 | 183 | func IsOldProtobufNode(n ipld.Node) bool { 184 | if len(n) > 2 { // short circuit 185 | return false 186 | } 187 | 188 | links, hasLinks := n["links"] 189 | _, hasData := n["data"] 190 | 191 | switch len(n) { 192 | case 2: // must be links and data 193 | if !hasLinks || !hasData { 194 | return false 195 | } 196 | case 1: // must be links or data 197 | if !(hasLinks || hasData) { 198 | return false 199 | } 200 | default: // nope. 201 | return false 202 | } 203 | 204 | if len(n) > 2 { 205 | return false // only links and data. 206 | } 207 | 208 | if hasLinks { 209 | links, ok := links.([]ipld.Node) 210 | if !ok { 211 | return false // invalid links. 212 | } 213 | 214 | // every link must be a mlink 215 | for _, link := range links { 216 | if !ipld.IsLink(link) { 217 | return false 218 | } 219 | } 220 | } 221 | 222 | return true // ok looks like an old protobuf node 223 | } 224 | -------------------------------------------------------------------------------- /ipld.go: -------------------------------------------------------------------------------- 1 | package ipld 2 | 3 | import ( 4 | "errors" 5 | "reflect" 6 | 7 | mh "github.com/jbenet/go-multihash" 8 | ) 9 | 10 | // These are the constants used in the format. 11 | const ( 12 | IDKey = "@id" // the id of the object (JSON-LD) 13 | TypeKey = "@type" // the type of the object (JSON-LD) 14 | ValueKey = "@value" // the value of the object (JSON-LD) 15 | CtxKey = "@context" // the JSON-LD style context 16 | 17 | CodecKey = "@codec" // used to determine which multicodec to use 18 | LinkKey = "mlink" // key for merkle-links 19 | ) 20 | 21 | // Node is an IPLD node. effectively, it is equivalent to a JSON-LD object. 22 | // (which is {,de}serialized to CBOR or JSON) which derives from a base 23 | // schema, the IPLD schema (@context). This allows keys to specify: 24 | // 25 | // "myfield": { "@value": "Qmabcbcbdba", "@type": "mlink" } 26 | // 27 | // "mlink" signals that "@value" is taken to be a merkle-link, which IPFS 28 | // handles specially. 29 | type Node map[string]interface{} 30 | 31 | // Get retrieves a property of the node. it uses unix path notation, 32 | // splitting on "/". 33 | func (n Node) Get(path_ string) interface{} { 34 | return GetPath(n, path_) 35 | } 36 | 37 | // Type is a convenience method to retrieve "@type", if there is one. 38 | func (d Node) Type() string { 39 | s, _ := d[TypeKey].(string) 40 | return s 41 | } 42 | 43 | // Context is a convenience method to retrieve the JSON-LD-style context. 44 | // It may be a string (link to context), a []interface (multiple contexts), 45 | // or a Node (an inline context) 46 | func (d Node) Context() interface{} { 47 | return d[CtxKey] 48 | } 49 | 50 | // Links returns all the merkle-links in the document. When the document 51 | // is parsed, all the links are identified and references are cached, so 52 | // getting the links only walks the document _once_. Note though that the 53 | // entire document must be walked. 54 | func (d Node) Links() map[string]Link { 55 | return Links(d) 56 | } 57 | 58 | // Link is a merkle-link to a target Node. The Link object is 59 | // represented by a JSON-LD style map: 60 | // 61 | // { "@type": "mlink", "@value": , ... } 62 | // 63 | // Links support adding other data, which will be 64 | // serialized and de-serialized along with the link. 65 | // This allows users to set other properties on links: 66 | // 67 | // { 68 | // "@type": "mlink", 69 | // "@value": , 70 | // "unixType": "dir", 71 | // "unixMode": "0777", 72 | // } 73 | // 74 | // looking at a whole filesystem node, we might see something like: 75 | // 76 | // { 77 | // "@context": "/ipfs/Qmf1ec6n9f8kW8JTLjqaZceJVpDpZD4L3aPoJFvssBE7Eb/merkleweb", 78 | // "foo": { 79 | // "@type": "mlink", 80 | // "@value": , 81 | // "unixType": "dir", 82 | // "unixMode": "0777", 83 | // }, 84 | // "bar": { 85 | // "@type": "mlink", 86 | // "@value": , 87 | // "unixType": "file", 88 | // "unixMode": "0755", 89 | // } 90 | // } 91 | // 92 | type Link Node 93 | 94 | // Type returns the type of the link. It should be "mlink" 95 | func (l Link) Type() string { 96 | s, _ := l[TypeKey].(string) 97 | return s 98 | } 99 | 100 | // HashStr returns the string value of l["mlink"], 101 | // which is the value we use to store hashes. 102 | func (l Link) LinkStr() string { 103 | s, _ := l[LinkKey].(string) 104 | return s 105 | } 106 | 107 | // Hash returns the multihash value of the link. 108 | func (l Link) Hash() (mh.Multihash, error) { 109 | s := l.LinkStr() 110 | if s == "" { 111 | return nil, errors.New("no hash in link") 112 | } 113 | return mh.FromB58String(s) 114 | } 115 | 116 | // Equal returns whether two Link objects are equal. 117 | // It uses reflect.DeepEqual, so beware compating 118 | // large structures. 119 | func (l Link) Equal(l2 Link) bool { 120 | return reflect.DeepEqual(l, l2) 121 | } 122 | 123 | // Links walks given node and returns all links found, 124 | // in a flattened map. the map keys use path notation, 125 | // made up of the intervening keys. For example: 126 | // 127 | // { 128 | // "foo": { 129 | // "quux": { @type: mlink, @value: Qmaaaa... }, 130 | // }, 131 | // "bar": { 132 | // "baz": { @type: mlink, @value: Qmbbbb... }, 133 | // }, 134 | // } 135 | // 136 | // would produce links: 137 | // 138 | // { 139 | // "foo/quux": { @type: mlink, @value: Qmaaaa... }, 140 | // "bar/baz": { @type: mlink, @value: Qmbbbb... }, 141 | // } 142 | // 143 | // WARNING: your nodes should not use `/` as key names. it will 144 | // confuse link parsers. thus, if we find any map keys with slash 145 | // in them, we simply ignore them. 146 | func Links(n Node) map[string]Link { 147 | m := map[string]Link{} 148 | Walk(n, func(root, curr Node, path string, err error) error { 149 | if err != nil { 150 | return err // if anything went wrong, bail. 151 | } 152 | 153 | if l, ok := LinkCast(curr); ok { 154 | m[path] = l 155 | } 156 | return nil 157 | }) 158 | return m 159 | } 160 | 161 | // checks whether a value is a link. for now we assume that all links 162 | // follow: 163 | // 164 | // { "mlink": "" } 165 | func IsLink(v interface{}) bool { 166 | vn, ok := v.(Node) 167 | if !ok { 168 | return false 169 | } 170 | 171 | _, ok = vn[LinkKey].(string) 172 | return ok; 173 | } 174 | 175 | // returns the link value of an object. for now we assume that all links 176 | // follow: 177 | // 178 | // { "mlink": "" } 179 | func LinkCast(v interface{}) (l Link, ok bool) { 180 | if !IsLink(v) { 181 | return 182 | } 183 | 184 | l = make(Link) 185 | for k, v := range v.(Node) { 186 | l[k] = v 187 | } 188 | return l, true 189 | } 190 | -------------------------------------------------------------------------------- /walk.go: -------------------------------------------------------------------------------- 1 | package ipld 2 | 3 | import ( 4 | "errors" 5 | "path" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | const pathSep = "/" 11 | 12 | // Escape path component. The special characters ("@" and "\") are escaped to 13 | // allow mixing the path component with directives (starting with "@") in IPLD 14 | // data structure. 15 | func EscapePathComponent(comp string) string { 16 | comp = strings.Replace(comp, "\\", "\\\\", -1) 17 | comp = strings.Replace(comp, "@", "\\@", -1) 18 | return comp 19 | } 20 | 21 | // Unescape path component from the IPLD data structure. Special characters are 22 | // unescaped. See also EscapePathComponent function. 23 | func UnescapePathComponent(comp string) string { 24 | comp = strings.Replace(comp, "\\@", "@", -1) 25 | comp = strings.Replace(comp, "\\\\", "\\", -1) 26 | return comp 27 | } 28 | 29 | // SkipNode is a special value used with Walk and WalkFunc. 30 | // If a WalkFunc returns SkipNode, the walk skips the curr 31 | // node and its children. It behaves like file/filepath.SkipDir 32 | var SkipNode = errors.New("skip node from Walk") 33 | 34 | // WalkFunc is the type of the function called for each node 35 | // visited by Walk. The root argument is the node from which 36 | // the Walk began. The curr argument is the currently visited 37 | // node. The path argument is the traversal path, from root 38 | // to curr. 39 | // 40 | // If there was a problem walking to curr, the err argument 41 | // will describe the problem and the function can decide 42 | // how to handle the error (and Walk _will not_ descend into 43 | // any of the children of curr). 44 | // 45 | // WalkFunc may return an error. If the error is the special 46 | // SkipNode error, the children of curr are skipped. All other 47 | // errors halt processing early. In this respect, it behaves 48 | // just like file/filepath.WalkFunc 49 | type WalkFunc func(root, curr Node, path string, err error) error 50 | 51 | // Walk traverses the given root node and all its children, calling 52 | // WalkFunc with every Node visited, including root. All errors 53 | // that arise while visiting nodes are passed to given WalkFunc. 54 | // The order in which children are visited is not deterministic. 55 | // Walk traverses sequences as well, which is to mean the nodes 56 | // below will be visted as "foo/0", "foo/1", and "foo/3": 57 | // 58 | // { "foo": [ 59 | // {"a":"aaa"}, // visited as foo/0 60 | // {"b":"bbb"}, // visited as foo/1 61 | // {"c":"ccc"}, // visited as foo/2 62 | // ]} 63 | // 64 | // Note Walk is purely local and does not traverse Links. For a 65 | // version of Walk that does traverse links, see the ipld/traverse 66 | // package. 67 | func Walk(root Node, walkFn WalkFunc) error { 68 | return walk(root, root, "", walkFn) 69 | } 70 | 71 | // WalkFrom is just like Walk, but starts the Walk at given startFrom 72 | // sub-node. It is the equivalent of a regular Walk call which skips 73 | // all nodes which do not have startFrom as a prefix. 74 | func WalkFrom(root Node, startFrom string, walkFn WalkFunc) error { 75 | start := GetPath(root, startFrom) 76 | if start == nil { 77 | return errors.New("no descendant at " + startFrom) 78 | } 79 | return walk(root, start, startFrom, walkFn) 80 | } 81 | 82 | // walk is used to implement Walk. 83 | func walk(root Node, curr interface{}, npath string, walkFunc WalkFunc) error { 84 | 85 | if nc, ok := curr.(Node); ok { // it's a node! 86 | // first, call user's WalkFunc. 87 | err := walkFunc(root, nc, npath, nil) 88 | if err == SkipNode { 89 | return nil // ok, let's skip this one. 90 | } else if err != nil { 91 | return err // something bad happened, return early. 92 | } 93 | 94 | // then recurse. 95 | for k, v := range nc { 96 | // Skip empty path components 97 | if len(k) == 0 { 98 | continue 99 | } 100 | 101 | // skip any keys which contain "/" in them. 102 | // this is explicitly disallowed. 103 | if strings.Contains(k, pathSep) { 104 | continue 105 | } 106 | 107 | // skip keys starting with "@", it is reserved for directives 108 | // It can be escaped using "\@" in which case, "@" is not the first 109 | // character 110 | if k[0] == '@' { 111 | continue 112 | } 113 | 114 | k = UnescapePathComponent(k) 115 | err := walk(root, v, path.Join(npath, k), walkFunc) 116 | if err != nil { 117 | return err 118 | } 119 | } 120 | 121 | } else if sc, ok := curr.([]interface{}); ok { // it's a slice! 122 | for i, v := range sc { 123 | k := strconv.Itoa(i) 124 | err := walk(root, v, path.Join(npath, k), walkFunc) 125 | if err != nil { 126 | return err 127 | } 128 | } 129 | 130 | } else { // it's just data. 131 | // ignore it. 132 | } 133 | return nil 134 | } 135 | 136 | // GetPath gets a descendant of root, at npath. GetPath 137 | // uses the UNIX path abstraction: components of a 138 | // path are delimited with "/". The path MUST start with "/". 139 | func GetPath(root interface{}, path_ string) interface{} { 140 | path_ = path.Clean(path_)[1:] // skip root / 141 | return GetPathCmp(root, strings.Split(path_, pathSep)) 142 | } 143 | 144 | // GetPathCmp gets a descendant of root, at npath. 145 | func GetPathCmp(root interface{}, npath []string) interface{} { 146 | if len(npath) == 0 { 147 | return root // we're done. 148 | } 149 | if root == nil { 150 | return nil // nowhere to go 151 | } 152 | 153 | k := npath[0] 154 | if vn, ok := root.(Node); ok { 155 | // if node, recurse 156 | k = EscapePathComponent(k) 157 | return GetPathCmp(vn[k], npath[1:]) 158 | 159 | } else if vs, ok := root.([]interface{}); ok { 160 | // if slice, use key as an int offset 161 | i, err := strconv.Atoi(k) 162 | if err != nil { 163 | return nil 164 | } 165 | if i < 0 || i >= len(vs) { // nothing at such offset 166 | return nil 167 | } 168 | 169 | return GetPathCmp(vs[i], npath[1:]) 170 | } 171 | 172 | return nil // cannot keep walking... 173 | } 174 | -------------------------------------------------------------------------------- /coding/pb/ipld.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-gogo. 2 | // source: merkledag.proto 3 | // DO NOT EDIT! 4 | 5 | /* 6 | Package merkledag_pb is a generated protocol buffer package. 7 | 8 | It is generated from these files: 9 | merkledag.proto 10 | 11 | It has these top-level messages: 12 | PBLink 13 | PBNode 14 | */ 15 | package ipldpb 16 | 17 | import proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" 18 | import math "math" 19 | 20 | // discarding unused import gogoproto "code.google.com/p/gogoprotobuf/gogoproto/gogo.pb" 21 | 22 | import io "io" 23 | import fmt "fmt" 24 | import github_com_gogo_protobuf_proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" 25 | 26 | import strings "strings" 27 | import reflect "reflect" 28 | 29 | import sort "sort" 30 | import strconv "strconv" 31 | 32 | import bytes "bytes" 33 | 34 | // Reference imports to suppress errors if they are not otherwise used. 35 | var _ = proto.Marshal 36 | var _ = math.Inf 37 | 38 | // An IPFS MerkleDAG Link 39 | type PBLink struct { 40 | // multihash of the target object 41 | Hash []byte `protobuf:"bytes,1,opt" json:"Hash,omitempty"` 42 | // utf string name. should be unique per object 43 | Name *string `protobuf:"bytes,2,opt" json:"Name,omitempty"` 44 | // cumulative size of target object 45 | Tsize *uint64 `protobuf:"varint,3,opt" json:"Tsize,omitempty"` 46 | XXX_unrecognized []byte `json:"-"` 47 | } 48 | 49 | func (m *PBLink) Reset() { *m = PBLink{} } 50 | func (*PBLink) ProtoMessage() {} 51 | 52 | func (m *PBLink) GetHash() []byte { 53 | if m != nil { 54 | return m.Hash 55 | } 56 | return nil 57 | } 58 | 59 | func (m *PBLink) GetName() string { 60 | if m != nil && m.Name != nil { 61 | return *m.Name 62 | } 63 | return "" 64 | } 65 | 66 | func (m *PBLink) GetTsize() uint64 { 67 | if m != nil && m.Tsize != nil { 68 | return *m.Tsize 69 | } 70 | return 0 71 | } 72 | 73 | // An IPFS MerkleDAG Node 74 | type PBNode struct { 75 | // refs to other objects 76 | Links []*PBLink `protobuf:"bytes,2,rep" json:"Links,omitempty"` 77 | // opaque user data 78 | Data []byte `protobuf:"bytes,1,opt" json:"Data,omitempty"` 79 | XXX_unrecognized []byte `json:"-"` 80 | } 81 | 82 | func (m *PBNode) Reset() { *m = PBNode{} } 83 | func (*PBNode) ProtoMessage() {} 84 | 85 | func (m *PBNode) GetLinks() []*PBLink { 86 | if m != nil { 87 | return m.Links 88 | } 89 | return nil 90 | } 91 | 92 | func (m *PBNode) GetData() []byte { 93 | if m != nil { 94 | return m.Data 95 | } 96 | return nil 97 | } 98 | 99 | func init() { 100 | } 101 | func (m *PBLink) Unmarshal(data []byte) error { 102 | l := len(data) 103 | index := 0 104 | for index < l { 105 | var wire uint64 106 | for shift := uint(0); ; shift += 7 { 107 | if index >= l { 108 | return io.ErrUnexpectedEOF 109 | } 110 | b := data[index] 111 | index++ 112 | wire |= (uint64(b) & 0x7F) << shift 113 | if b < 0x80 { 114 | break 115 | } 116 | } 117 | fieldNum := int32(wire >> 3) 118 | wireType := int(wire & 0x7) 119 | switch fieldNum { 120 | case 1: 121 | if wireType != 2 { 122 | return fmt.Errorf("proto: wrong wireType = %d for field Hash", wireType) 123 | } 124 | var byteLen int 125 | for shift := uint(0); ; shift += 7 { 126 | if index >= l { 127 | return io.ErrUnexpectedEOF 128 | } 129 | b := data[index] 130 | index++ 131 | byteLen |= (int(b) & 0x7F) << shift 132 | if b < 0x80 { 133 | break 134 | } 135 | } 136 | postIndex := index + byteLen 137 | if postIndex > l { 138 | return io.ErrUnexpectedEOF 139 | } 140 | m.Hash = append([]byte{}, data[index:postIndex]...) 141 | index = postIndex 142 | case 2: 143 | if wireType != 2 { 144 | return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) 145 | } 146 | var stringLen uint64 147 | for shift := uint(0); ; shift += 7 { 148 | if index >= l { 149 | return io.ErrUnexpectedEOF 150 | } 151 | b := data[index] 152 | index++ 153 | stringLen |= (uint64(b) & 0x7F) << shift 154 | if b < 0x80 { 155 | break 156 | } 157 | } 158 | postIndex := index + int(stringLen) 159 | if postIndex > l { 160 | return io.ErrUnexpectedEOF 161 | } 162 | s := string(data[index:postIndex]) 163 | m.Name = &s 164 | index = postIndex 165 | case 3: 166 | if wireType != 0 { 167 | return fmt.Errorf("proto: wrong wireType = %d for field Tsize", wireType) 168 | } 169 | var v uint64 170 | for shift := uint(0); ; shift += 7 { 171 | if index >= l { 172 | return io.ErrUnexpectedEOF 173 | } 174 | b := data[index] 175 | index++ 176 | v |= (uint64(b) & 0x7F) << shift 177 | if b < 0x80 { 178 | break 179 | } 180 | } 181 | m.Tsize = &v 182 | default: 183 | var sizeOfWire int 184 | for { 185 | sizeOfWire++ 186 | wire >>= 7 187 | if wire == 0 { 188 | break 189 | } 190 | } 191 | index -= sizeOfWire 192 | skippy, err := github_com_gogo_protobuf_proto.Skip(data[index:]) 193 | if err != nil { 194 | return err 195 | } 196 | if (index + skippy) > l { 197 | return io.ErrUnexpectedEOF 198 | } 199 | m.XXX_unrecognized = append(m.XXX_unrecognized, data[index:index+skippy]...) 200 | index += skippy 201 | } 202 | } 203 | return nil 204 | } 205 | func (m *PBNode) Unmarshal(data []byte) error { 206 | l := len(data) 207 | index := 0 208 | for index < l { 209 | var wire uint64 210 | for shift := uint(0); ; shift += 7 { 211 | if index >= l { 212 | return io.ErrUnexpectedEOF 213 | } 214 | b := data[index] 215 | index++ 216 | wire |= (uint64(b) & 0x7F) << shift 217 | if b < 0x80 { 218 | break 219 | } 220 | } 221 | fieldNum := int32(wire >> 3) 222 | wireType := int(wire & 0x7) 223 | switch fieldNum { 224 | case 2: 225 | if wireType != 2 { 226 | return fmt.Errorf("proto: wrong wireType = %d for field Links", wireType) 227 | } 228 | var msglen int 229 | for shift := uint(0); ; shift += 7 { 230 | if index >= l { 231 | return io.ErrUnexpectedEOF 232 | } 233 | b := data[index] 234 | index++ 235 | msglen |= (int(b) & 0x7F) << shift 236 | if b < 0x80 { 237 | break 238 | } 239 | } 240 | postIndex := index + msglen 241 | if postIndex > l { 242 | return io.ErrUnexpectedEOF 243 | } 244 | m.Links = append(m.Links, &PBLink{}) 245 | m.Links[len(m.Links)-1].Unmarshal(data[index:postIndex]) 246 | index = postIndex 247 | case 1: 248 | if wireType != 2 { 249 | return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) 250 | } 251 | var byteLen int 252 | for shift := uint(0); ; shift += 7 { 253 | if index >= l { 254 | return io.ErrUnexpectedEOF 255 | } 256 | b := data[index] 257 | index++ 258 | byteLen |= (int(b) & 0x7F) << shift 259 | if b < 0x80 { 260 | break 261 | } 262 | } 263 | postIndex := index + byteLen 264 | if postIndex > l { 265 | return io.ErrUnexpectedEOF 266 | } 267 | m.Data = append([]byte{}, data[index:postIndex]...) 268 | index = postIndex 269 | default: 270 | var sizeOfWire int 271 | for { 272 | sizeOfWire++ 273 | wire >>= 7 274 | if wire == 0 { 275 | break 276 | } 277 | } 278 | index -= sizeOfWire 279 | skippy, err := github_com_gogo_protobuf_proto.Skip(data[index:]) 280 | if err != nil { 281 | return err 282 | } 283 | if (index + skippy) > l { 284 | return io.ErrUnexpectedEOF 285 | } 286 | m.XXX_unrecognized = append(m.XXX_unrecognized, data[index:index+skippy]...) 287 | index += skippy 288 | } 289 | } 290 | return nil 291 | } 292 | func (this *PBLink) String() string { 293 | if this == nil { 294 | return "nil" 295 | } 296 | s := strings.Join([]string{`&PBLink{`, 297 | `Hash:` + valueToStringMerkledag(this.Hash) + `,`, 298 | `Name:` + valueToStringMerkledag(this.Name) + `,`, 299 | `Tsize:` + valueToStringMerkledag(this.Tsize) + `,`, 300 | `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, 301 | `}`, 302 | }, "") 303 | return s 304 | } 305 | func (this *PBNode) String() string { 306 | if this == nil { 307 | return "nil" 308 | } 309 | s := strings.Join([]string{`&PBNode{`, 310 | `Links:` + strings.Replace(fmt.Sprintf("%v", this.Links), "PBLink", "PBLink", 1) + `,`, 311 | `Data:` + valueToStringMerkledag(this.Data) + `,`, 312 | `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, 313 | `}`, 314 | }, "") 315 | return s 316 | } 317 | func valueToStringMerkledag(v interface{}) string { 318 | rv := reflect.ValueOf(v) 319 | if rv.IsNil() { 320 | return "nil" 321 | } 322 | pv := reflect.Indirect(rv).Interface() 323 | return fmt.Sprintf("*%v", pv) 324 | } 325 | func (m *PBLink) Size() (n int) { 326 | var l int 327 | _ = l 328 | if m.Hash != nil { 329 | l = len(m.Hash) 330 | n += 1 + l + sovMerkledag(uint64(l)) 331 | } 332 | if m.Name != nil { 333 | l = len(*m.Name) 334 | n += 1 + l + sovMerkledag(uint64(l)) 335 | } 336 | if m.Tsize != nil { 337 | n += 1 + sovMerkledag(uint64(*m.Tsize)) 338 | } 339 | if m.XXX_unrecognized != nil { 340 | n += len(m.XXX_unrecognized) 341 | } 342 | return n 343 | } 344 | 345 | func (m *PBNode) Size() (n int) { 346 | var l int 347 | _ = l 348 | if len(m.Links) > 0 { 349 | for _, e := range m.Links { 350 | l = e.Size() 351 | n += 1 + l + sovMerkledag(uint64(l)) 352 | } 353 | } 354 | if m.Data != nil { 355 | l = len(m.Data) 356 | n += 1 + l + sovMerkledag(uint64(l)) 357 | } 358 | if m.XXX_unrecognized != nil { 359 | n += len(m.XXX_unrecognized) 360 | } 361 | return n 362 | } 363 | 364 | func sovMerkledag(x uint64) (n int) { 365 | for { 366 | n++ 367 | x >>= 7 368 | if x == 0 { 369 | break 370 | } 371 | } 372 | return n 373 | } 374 | func sozMerkledag(x uint64) (n int) { 375 | return sovMerkledag(uint64((x << 1) ^ uint64((int64(x) >> 63)))) 376 | } 377 | func NewPopulatedPBLink(r randyMerkledag, easy bool) *PBLink { 378 | this := &PBLink{} 379 | if r.Intn(10) != 0 { 380 | v1 := r.Intn(100) 381 | this.Hash = make([]byte, v1) 382 | for i := 0; i < v1; i++ { 383 | this.Hash[i] = byte(r.Intn(256)) 384 | } 385 | } 386 | if r.Intn(10) != 0 { 387 | v2 := randStringMerkledag(r) 388 | this.Name = &v2 389 | } 390 | if r.Intn(10) != 0 { 391 | v3 := uint64(r.Uint32()) 392 | this.Tsize = &v3 393 | } 394 | if !easy && r.Intn(10) != 0 { 395 | this.XXX_unrecognized = randUnrecognizedMerkledag(r, 4) 396 | } 397 | return this 398 | } 399 | 400 | func NewPopulatedPBNode(r randyMerkledag, easy bool) *PBNode { 401 | this := &PBNode{} 402 | if r.Intn(10) != 0 { 403 | v4 := r.Intn(10) 404 | this.Links = make([]*PBLink, v4) 405 | for i := 0; i < v4; i++ { 406 | this.Links[i] = NewPopulatedPBLink(r, easy) 407 | } 408 | } 409 | if r.Intn(10) != 0 { 410 | v5 := r.Intn(100) 411 | this.Data = make([]byte, v5) 412 | for i := 0; i < v5; i++ { 413 | this.Data[i] = byte(r.Intn(256)) 414 | } 415 | } 416 | if !easy && r.Intn(10) != 0 { 417 | this.XXX_unrecognized = randUnrecognizedMerkledag(r, 3) 418 | } 419 | return this 420 | } 421 | 422 | type randyMerkledag interface { 423 | Float32() float32 424 | Float64() float64 425 | Int63() int64 426 | Int31() int32 427 | Uint32() uint32 428 | Intn(n int) int 429 | } 430 | 431 | func randUTF8RuneMerkledag(r randyMerkledag) rune { 432 | return rune(r.Intn(126-43) + 43) 433 | } 434 | func randStringMerkledag(r randyMerkledag) string { 435 | v6 := r.Intn(100) 436 | tmps := make([]rune, v6) 437 | for i := 0; i < v6; i++ { 438 | tmps[i] = randUTF8RuneMerkledag(r) 439 | } 440 | return string(tmps) 441 | } 442 | func randUnrecognizedMerkledag(r randyMerkledag, maxFieldNumber int) (data []byte) { 443 | l := r.Intn(5) 444 | for i := 0; i < l; i++ { 445 | wire := r.Intn(4) 446 | if wire == 3 { 447 | wire = 5 448 | } 449 | fieldNumber := maxFieldNumber + r.Intn(100) 450 | data = randFieldMerkledag(data, r, fieldNumber, wire) 451 | } 452 | return data 453 | } 454 | func randFieldMerkledag(data []byte, r randyMerkledag, fieldNumber int, wire int) []byte { 455 | key := uint32(fieldNumber)<<3 | uint32(wire) 456 | switch wire { 457 | case 0: 458 | data = encodeVarintPopulateMerkledag(data, uint64(key)) 459 | v7 := r.Int63() 460 | if r.Intn(2) == 0 { 461 | v7 *= -1 462 | } 463 | data = encodeVarintPopulateMerkledag(data, uint64(v7)) 464 | case 1: 465 | data = encodeVarintPopulateMerkledag(data, uint64(key)) 466 | data = append(data, byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256))) 467 | case 2: 468 | data = encodeVarintPopulateMerkledag(data, uint64(key)) 469 | ll := r.Intn(100) 470 | data = encodeVarintPopulateMerkledag(data, uint64(ll)) 471 | for j := 0; j < ll; j++ { 472 | data = append(data, byte(r.Intn(256))) 473 | } 474 | default: 475 | data = encodeVarintPopulateMerkledag(data, uint64(key)) 476 | data = append(data, byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256))) 477 | } 478 | return data 479 | } 480 | func encodeVarintPopulateMerkledag(data []byte, v uint64) []byte { 481 | for v >= 1<<7 { 482 | data = append(data, uint8(uint64(v)&0x7f|0x80)) 483 | v >>= 7 484 | } 485 | data = append(data, uint8(v)) 486 | return data 487 | } 488 | func (m *PBLink) Marshal() (data []byte, err error) { 489 | size := m.Size() 490 | data = make([]byte, size) 491 | n, err := m.MarshalTo(data) 492 | if err != nil { 493 | return nil, err 494 | } 495 | return data[:n], nil 496 | } 497 | 498 | func (m *PBLink) MarshalTo(data []byte) (n int, err error) { 499 | var i int 500 | _ = i 501 | var l int 502 | _ = l 503 | if m.Hash != nil { 504 | data[i] = 0xa 505 | i++ 506 | i = encodeVarintMerkledag(data, i, uint64(len(m.Hash))) 507 | i += copy(data[i:], m.Hash) 508 | } 509 | if m.Name != nil { 510 | data[i] = 0x12 511 | i++ 512 | i = encodeVarintMerkledag(data, i, uint64(len(*m.Name))) 513 | i += copy(data[i:], *m.Name) 514 | } 515 | if m.Tsize != nil { 516 | data[i] = 0x18 517 | i++ 518 | i = encodeVarintMerkledag(data, i, uint64(*m.Tsize)) 519 | } 520 | if m.XXX_unrecognized != nil { 521 | i += copy(data[i:], m.XXX_unrecognized) 522 | } 523 | return i, nil 524 | } 525 | 526 | func (m *PBNode) Marshal() (data []byte, err error) { 527 | size := m.Size() 528 | data = make([]byte, size) 529 | n, err := m.MarshalTo(data) 530 | if err != nil { 531 | return nil, err 532 | } 533 | return data[:n], nil 534 | } 535 | 536 | func (m *PBNode) MarshalTo(data []byte) (n int, err error) { 537 | var i int 538 | _ = i 539 | var l int 540 | _ = l 541 | if len(m.Links) > 0 { 542 | for _, msg := range m.Links { 543 | data[i] = 0x12 544 | i++ 545 | i = encodeVarintMerkledag(data, i, uint64(msg.Size())) 546 | n, err := msg.MarshalTo(data[i:]) 547 | if err != nil { 548 | return 0, err 549 | } 550 | i += n 551 | } 552 | } 553 | if m.Data != nil { 554 | data[i] = 0xa 555 | i++ 556 | i = encodeVarintMerkledag(data, i, uint64(len(m.Data))) 557 | i += copy(data[i:], m.Data) 558 | } 559 | if m.XXX_unrecognized != nil { 560 | i += copy(data[i:], m.XXX_unrecognized) 561 | } 562 | return i, nil 563 | } 564 | 565 | func encodeFixed64Merkledag(data []byte, offset int, v uint64) int { 566 | data[offset] = uint8(v) 567 | data[offset+1] = uint8(v >> 8) 568 | data[offset+2] = uint8(v >> 16) 569 | data[offset+3] = uint8(v >> 24) 570 | data[offset+4] = uint8(v >> 32) 571 | data[offset+5] = uint8(v >> 40) 572 | data[offset+6] = uint8(v >> 48) 573 | data[offset+7] = uint8(v >> 56) 574 | return offset + 8 575 | } 576 | func encodeFixed32Merkledag(data []byte, offset int, v uint32) int { 577 | data[offset] = uint8(v) 578 | data[offset+1] = uint8(v >> 8) 579 | data[offset+2] = uint8(v >> 16) 580 | data[offset+3] = uint8(v >> 24) 581 | return offset + 4 582 | } 583 | func encodeVarintMerkledag(data []byte, offset int, v uint64) int { 584 | for v >= 1<<7 { 585 | data[offset] = uint8(v&0x7f | 0x80) 586 | v >>= 7 587 | offset++ 588 | } 589 | data[offset] = uint8(v) 590 | return offset + 1 591 | } 592 | func (this *PBLink) GoString() string { 593 | if this == nil { 594 | return "nil" 595 | } 596 | s := strings.Join([]string{`&merkledag_pb.PBLink{` + 597 | `Hash:` + valueToGoStringMerkledag(this.Hash, "byte"), 598 | `Name:` + valueToGoStringMerkledag(this.Name, "string"), 599 | `Tsize:` + valueToGoStringMerkledag(this.Tsize, "uint64"), 600 | `XXX_unrecognized:` + fmt.Sprintf("%#v", this.XXX_unrecognized) + `}`}, ", ") 601 | return s 602 | } 603 | func (this *PBNode) GoString() string { 604 | if this == nil { 605 | return "nil" 606 | } 607 | s := strings.Join([]string{`&merkledag_pb.PBNode{` + 608 | `Links:` + fmt.Sprintf("%#v", this.Links), 609 | `Data:` + valueToGoStringMerkledag(this.Data, "byte"), 610 | `XXX_unrecognized:` + fmt.Sprintf("%#v", this.XXX_unrecognized) + `}`}, ", ") 611 | return s 612 | } 613 | func valueToGoStringMerkledag(v interface{}, typ string) string { 614 | rv := reflect.ValueOf(v) 615 | if rv.IsNil() { 616 | return "nil" 617 | } 618 | pv := reflect.Indirect(rv).Interface() 619 | return fmt.Sprintf("func(v %v) *%v { return &v } ( %#v )", typ, typ, pv) 620 | } 621 | func extensionToGoStringMerkledag(e map[int32]github_com_gogo_protobuf_proto.Extension) string { 622 | if e == nil { 623 | return "nil" 624 | } 625 | s := "map[int32]proto.Extension{" 626 | keys := make([]int, 0, len(e)) 627 | for k := range e { 628 | keys = append(keys, int(k)) 629 | } 630 | sort.Ints(keys) 631 | ss := []string{} 632 | for _, k := range keys { 633 | ss = append(ss, strconv.Itoa(k)+": "+e[int32(k)].GoString()) 634 | } 635 | s += strings.Join(ss, ",") + "}" 636 | return s 637 | } 638 | func (this *PBLink) VerboseEqual(that interface{}) error { 639 | if that == nil { 640 | if this == nil { 641 | return nil 642 | } 643 | return fmt.Errorf("that == nil && this != nil") 644 | } 645 | 646 | that1, ok := that.(*PBLink) 647 | if !ok { 648 | return fmt.Errorf("that is not of type *PBLink") 649 | } 650 | if that1 == nil { 651 | if this == nil { 652 | return nil 653 | } 654 | return fmt.Errorf("that is type *PBLink but is nil && this != nil") 655 | } else if this == nil { 656 | return fmt.Errorf("that is type *PBLinkbut is not nil && this == nil") 657 | } 658 | if !bytes.Equal(this.Hash, that1.Hash) { 659 | return fmt.Errorf("Hash this(%v) Not Equal that(%v)", this.Hash, that1.Hash) 660 | } 661 | if this.Name != nil && that1.Name != nil { 662 | if *this.Name != *that1.Name { 663 | return fmt.Errorf("Name this(%v) Not Equal that(%v)", *this.Name, *that1.Name) 664 | } 665 | } else if this.Name != nil { 666 | return fmt.Errorf("this.Name == nil && that.Name != nil") 667 | } else if that1.Name != nil { 668 | return fmt.Errorf("Name this(%v) Not Equal that(%v)", this.Name, that1.Name) 669 | } 670 | if this.Tsize != nil && that1.Tsize != nil { 671 | if *this.Tsize != *that1.Tsize { 672 | return fmt.Errorf("Tsize this(%v) Not Equal that(%v)", *this.Tsize, *that1.Tsize) 673 | } 674 | } else if this.Tsize != nil { 675 | return fmt.Errorf("this.Tsize == nil && that.Tsize != nil") 676 | } else if that1.Tsize != nil { 677 | return fmt.Errorf("Tsize this(%v) Not Equal that(%v)", this.Tsize, that1.Tsize) 678 | } 679 | if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) { 680 | return fmt.Errorf("XXX_unrecognized this(%v) Not Equal that(%v)", this.XXX_unrecognized, that1.XXX_unrecognized) 681 | } 682 | return nil 683 | } 684 | func (this *PBLink) Equal(that interface{}) bool { 685 | if that == nil { 686 | if this == nil { 687 | return true 688 | } 689 | return false 690 | } 691 | 692 | that1, ok := that.(*PBLink) 693 | if !ok { 694 | return false 695 | } 696 | if that1 == nil { 697 | if this == nil { 698 | return true 699 | } 700 | return false 701 | } else if this == nil { 702 | return false 703 | } 704 | if !bytes.Equal(this.Hash, that1.Hash) { 705 | return false 706 | } 707 | if this.Name != nil && that1.Name != nil { 708 | if *this.Name != *that1.Name { 709 | return false 710 | } 711 | } else if this.Name != nil { 712 | return false 713 | } else if that1.Name != nil { 714 | return false 715 | } 716 | if this.Tsize != nil && that1.Tsize != nil { 717 | if *this.Tsize != *that1.Tsize { 718 | return false 719 | } 720 | } else if this.Tsize != nil { 721 | return false 722 | } else if that1.Tsize != nil { 723 | return false 724 | } 725 | if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) { 726 | return false 727 | } 728 | return true 729 | } 730 | func (this *PBNode) VerboseEqual(that interface{}) error { 731 | if that == nil { 732 | if this == nil { 733 | return nil 734 | } 735 | return fmt.Errorf("that == nil && this != nil") 736 | } 737 | 738 | that1, ok := that.(*PBNode) 739 | if !ok { 740 | return fmt.Errorf("that is not of type *PBNode") 741 | } 742 | if that1 == nil { 743 | if this == nil { 744 | return nil 745 | } 746 | return fmt.Errorf("that is type *PBNode but is nil && this != nil") 747 | } else if this == nil { 748 | return fmt.Errorf("that is type *PBNodebut is not nil && this == nil") 749 | } 750 | if len(this.Links) != len(that1.Links) { 751 | return fmt.Errorf("Links this(%v) Not Equal that(%v)", len(this.Links), len(that1.Links)) 752 | } 753 | for i := range this.Links { 754 | if !this.Links[i].Equal(that1.Links[i]) { 755 | return fmt.Errorf("Links this[%v](%v) Not Equal that[%v](%v)", i, this.Links[i], i, that1.Links[i]) 756 | } 757 | } 758 | if !bytes.Equal(this.Data, that1.Data) { 759 | return fmt.Errorf("Data this(%v) Not Equal that(%v)", this.Data, that1.Data) 760 | } 761 | if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) { 762 | return fmt.Errorf("XXX_unrecognized this(%v) Not Equal that(%v)", this.XXX_unrecognized, that1.XXX_unrecognized) 763 | } 764 | return nil 765 | } 766 | func (this *PBNode) Equal(that interface{}) bool { 767 | if that == nil { 768 | if this == nil { 769 | return true 770 | } 771 | return false 772 | } 773 | 774 | that1, ok := that.(*PBNode) 775 | if !ok { 776 | return false 777 | } 778 | if that1 == nil { 779 | if this == nil { 780 | return true 781 | } 782 | return false 783 | } else if this == nil { 784 | return false 785 | } 786 | if len(this.Links) != len(that1.Links) { 787 | return false 788 | } 789 | for i := range this.Links { 790 | if !this.Links[i].Equal(that1.Links[i]) { 791 | return false 792 | } 793 | } 794 | if !bytes.Equal(this.Data, that1.Data) { 795 | return false 796 | } 797 | if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) { 798 | return false 799 | } 800 | return true 801 | } 802 | --------------------------------------------------------------------------------