Skip to content
This repository has been archived by the owner on Aug 9, 2018. It is now read-only.

Commit

Permalink
Add CBOR & JSON implementation for the NodeReader interface
Browse files Browse the repository at this point in the history
# Conflicts:
#	reader/reader.go
  • Loading branch information
mildred committed Jan 15, 2016
1 parent bf990de commit 49fc5bd
Show file tree
Hide file tree
Showing 9 changed files with 488 additions and 17 deletions.
24 changes: 18 additions & 6 deletions coding/Makefile
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
bin/multicodec:
mkdir -p bin
go get -d github.com/jbenet/go-multicodec/multicodec
go build -o "$@" github.com/jbenet/go-multicodec/multicodec

pb/bin/multicodec:
$(MAKE) -C pb bin/multicodec
bin/json2cbor:
mkdir -p bin
go get -d github.com/whyrusleeping/cbor/go/json2cbor
go build -o "$@" github.com/whyrusleeping/cbor/go/json2cbor

json.testfile: pb/bin/multicodec Makefile
json.testfile: bin/multicodec Makefile test1.json
: >$@
pb/bin/multicodec header /multicodec >>$@
pb/bin/multicodec header /json >>$@
echo '{"@codec":"/json","abc":{"mlink":"QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V"}}' >>$@
bin/multicodec header /multicodec >>$@
bin/multicodec header /json >>$@
cat test1.json >>$@

cbor.testfile: bin/multicodec bin/json2cbor Makefile test1.json
: >$@
bin/multicodec header /multicodec >>$@
bin/multicodec header /cbor >>$@
bin/json2cbor -i test1.json -o - >>$@

3 changes: 3 additions & 0 deletions coding/cbor.testfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/multicodec
/cbor
�cabc�emlinkx.QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39Vf@codece/json
161 changes: 161 additions & 0 deletions coding/cbor_stream.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
package ipfsld

import (
"io"
"log"
"math/big"

reader "github.com/ipfs/go-ipld/reader"
cbor "github.com/whyrusleeping/cbor/go"
)

type CBORDecoder struct {
r io.Reader
}

type cborParser struct {
reader.BaseReader
decoder *cbor.Decoder
}

func (d *CBORDecoder) Read(cb reader.ReadFun) error {
dec := cbor.NewDecoder(d.r)
return dec.DecodeAny(&cborParser{reader.CreateBaseReader(cb), dec})
}

func (p *cborParser) Prepare() error {
log.Printf("Prepare")
return nil
}

func (p *cborParser) SetBytes(buf []byte) error {
log.Printf("SetBytes")
err := p.ExecCallback(reader.TokenValue, buf)
p.Descope()
return err
}

func (p *cborParser) SetUint(i uint64) error {
log.Printf("SetUint")
err := p.ExecCallback(reader.TokenValue, i)
p.Descope()
return err
}

func (p *cborParser) SetInt(i int64) error {
log.Printf("setint")
err := p.ExecCallback(reader.TokenValue, i)
p.Descope()
return err
}

func (p *cborParser) SetFloat32(f float32) error {
log.Printf("setfloat32")
err := p.ExecCallback(reader.TokenValue, f)
p.Descope()
return err
}

func (p *cborParser) SetFloat64(f float64) error {
log.Printf("setfloat64")
err := p.ExecCallback(reader.TokenValue, f)
p.Descope()
return err
}

func (p *cborParser) SetBignum(i *big.Int) error {
log.Printf("setbignum")
err := p.ExecCallback(reader.TokenValue, i)
p.Descope()
return err
}

func (p *cborParser) SetNil() error {
log.Printf("nil")
err := p.ExecCallback(reader.TokenValue, nil)
p.Descope()
return err
}

func (p *cborParser) SetBool(b bool) error {
log.Printf("setbool")
err := p.ExecCallback(reader.TokenValue, b)
p.Descope()
return err
}

func (p *cborParser) SetString(s string) error {
log.Printf("setstring")
err := p.ExecCallback(reader.TokenValue, s)
p.Descope()
return err
}

func (p *cborParser) CreateMap() (cbor.DecodeValueMap, error) {
log.Printf("createmap")
return p, p.ExecCallback(reader.TokenNode, nil)
}

func (p *cborParser) CreateMapKey() (cbor.DecodeValue, error) {
log.Printf("createmapkey")
return cbor.NewMemoryValue(""), nil
}

func (p *cborParser) CreateMapValue(key cbor.DecodeValue) (cbor.DecodeValue, error) {
log.Printf("createmapvalue")
err := p.ExecCallback(reader.TokenKey, key.(*cbor.MemoryValue).Value)
p.Descope()
p.PushPath(key.(*cbor.MemoryValue).Value)
return p, err
}

func (p *cborParser) SetMap(key, val cbor.DecodeValue) error {
log.Printf("setmap")
p.PopPath()
return nil
}

func (p *cborParser) EndMap() error {
log.Printf("endmap")
err := p.ExecCallback(reader.TokenEndNode, nil)
p.Descope()
p.Descope()
return err
}

func (p *cborParser) CreateArray(len int) (cbor.DecodeValueArray, error) {
log.Printf("createarray")
return p, p.ExecCallback(reader.TokenArray, nil)
}

func (p *cborParser) GetArrayValue(index uint64) (cbor.DecodeValue, error) {
log.Printf("getarrvalue")
err := p.ExecCallback(reader.TokenIndex, index)
p.Descope()
p.PushPath(index)
return p, err
}

func (p *cborParser) AppendArray(val cbor.DecodeValue) error {
log.Printf("appendarray")
p.PopPath()
return nil
}

func (p *cborParser) EndArray() error {
log.Printf("endarray")
err := p.ExecCallback(reader.TokenEndArray, nil)
p.Descope()
p.Descope()
return err
}

func (p *cborParser) CreateTag(tag uint64, decoder cbor.TagDecoder) (cbor.DecodeValue, interface{}, error) {
log.Printf("createtag")
return p, nil, nil
}

func (p *cborParser) SetTag(tag uint64, decval cbor.DecodeValue, decoder cbor.TagDecoder, val interface{}) error {
log.Printf("settag")
return nil
}
42 changes: 42 additions & 0 deletions coding/coding.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
package ipfsld

import (
"fmt"
"io"

mc "github.com/jbenet/go-multicodec"
mccbor "github.com/jbenet/go-multicodec/cbor"
mcjson "github.com/jbenet/go-multicodec/json"
mcmux "github.com/jbenet/go-multicodec/mux"

ipld "github.com/ipfs/go-ipld"
pb "github.com/ipfs/go-ipld/coding/pb"
reader "github.com/ipfs/go-ipld/reader"
)

var StreamCodecs map[string]func(io.Reader) (reader.NodeReader, error) = map[string]func(io.Reader) (reader.NodeReader, error){
mcjson.HeaderPath: func(r io.Reader) (reader.NodeReader, error) {
return &JSONDecoder{r}, nil
},
mccbor.HeaderPath: func(r io.Reader) (reader.NodeReader, error) {
return &CBORDecoder{r}, nil
},
}

// defaultCodec is the default applied if user does not specify a codec.
// Most new objects will never specify a codec. We track the codecs with
// the object so that multiple people using the same object will continue
Expand All @@ -26,6 +40,14 @@ func init() {
jsonMulticodec(),
pb.Multicodec(),
}, selectCodec)
StreamCodecs = map[string]func(io.Reader) (reader.NodeReader, error){
mcjson.HeaderPath: func(r io.Reader) (reader.NodeReader, error) {
return &JSONDecoder{r}, nil
},
mccbor.HeaderPath: func(r io.Reader) (reader.NodeReader, error) {
return &CBORDecoder{r}, nil
},
}
}

// Multicodec returns a muxing codec that marshals to
Expand Down Expand Up @@ -73,3 +95,23 @@ func codecKey(n ipld.Node) (string, error) {

return chdrs, nil
}

func Decode(r io.Reader) (reader.NodeReader, error) {
if err := mc.ConsumeHeader(r, mcmux.Header); err != nil {
return nil, err
}

// get next header, to select codec
hdr, err := mc.ReadHeader(r)
if err != nil {
return nil, err
}

hdrPath := string(mc.HeaderPath(hdr))

fun, ok := StreamCodecs[hdrPath]
if !ok {
return nil, fmt.Errorf("no codec for %s", hdr)
}
return fun(r)
}
48 changes: 45 additions & 3 deletions coding/coding_test.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,33 @@
package ipfsld

import (
"bytes"
"io/ioutil"
"testing"
"reflect"
"bytes"
"testing"

ipld "github.com/ipfs/go-ipld"
reader "github.com/ipfs/go-ipld/reader"
readertest "github.com/ipfs/go-ipld/reader/test"

mc "github.com/jbenet/go-multicodec"
mctest "github.com/jbenet/go-multicodec/test"
assrt "github.com/mildred/assrt"
)

var json_testfile []byte
var cbor_testfile []byte

func init() {
var err error
json_testfile, err = ioutil.ReadFile("json.testfile")
if err != nil {
panic("could not read json.testfile. please run: make json.testfile")
}
cbor_testfile, err = ioutil.ReadFile("cbor.testfile")
if err != nil {
panic("could not read cbor.testfile. please run: make cbor.testfile")
}
}

type TC struct {
Expand Down Expand Up @@ -113,7 +121,7 @@ func TestJsonDecodeEncode(t *testing.T) {
}

linksExpected := map[string]ipld.Link{
"abc": ipld.Link {
"abc": ipld.Link{
"mlink": "QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V",
},
}
Expand All @@ -140,3 +148,37 @@ func TestJsonDecodeEncode(t *testing.T) {
}
}

func TestStream(t *testing.T) {
a := assrt.NewAssert(t)
json, err := Decode(bytes.NewReader(json_testfile))
a.MustNil(err)

t.Logf("Reading json.testfile")
readertest.CheckReader(t, json, []readertest.Callback{
readertest.Callback{[]interface{}{}, reader.TokenNode, nil},
readertest.Callback{[]interface{}{}, reader.TokenKey, "@codec"},
readertest.Callback{[]interface{}{"@codec"}, reader.TokenValue, "/json"},
readertest.Callback{[]interface{}{}, reader.TokenKey, "abc"},
readertest.Callback{[]interface{}{"abc"}, reader.TokenNode, nil},
readertest.Callback{[]interface{}{"abc"}, reader.TokenKey, "mlink"},
readertest.Callback{[]interface{}{"abc", "mlink"}, reader.TokenValue, "QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V"},
readertest.Callback{[]interface{}{"abc"}, reader.TokenEndNode, nil},
readertest.Callback{[]interface{}{}, reader.TokenEndNode, nil},
})

cbor, err := Decode(bytes.NewReader(cbor_testfile))
a.MustNil(err)

t.Logf("Reading cbor.testfile")
readertest.CheckReader(t, cbor, []readertest.Callback{
readertest.Callback{[]interface{}{}, reader.TokenNode, nil},
readertest.Callback{[]interface{}{}, reader.TokenKey, "abc"},
readertest.Callback{[]interface{}{"abc"}, reader.TokenNode, nil},
readertest.Callback{[]interface{}{"abc"}, reader.TokenKey, "mlink"},
readertest.Callback{[]interface{}{"abc", "mlink"}, reader.TokenValue, "QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V"},
readertest.Callback{[]interface{}{"abc"}, reader.TokenEndNode, nil},
readertest.Callback{[]interface{}{}, reader.TokenKey, "@codec"},
readertest.Callback{[]interface{}{"@codec"}, reader.TokenValue, "/json"},
readertest.Callback{[]interface{}{}, reader.TokenEndNode, nil},
})
}
Loading

0 comments on commit 49fc5bd

Please sign in to comment.