Commit fcd2cc2b authored by Jeromy's avatar Jeromy

first hack

parents
os:
- linux
- osx
language: go
go:
- 1.7
install: true
before_install:
- make deps
script:
- go vet
- $GOPATH/bin/goveralls -service="travis-ci"
cache:
directories:
- $GOPATH/src/gx
notifications:
email: false
The MIT License (MIT)
Copyright (c) 2016 Jeromy Johnson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
gx:
go get github.com/whyrusleeping/gx
go get github.com/whyrusleeping/gx-go
covertools:
go get github.com/mattn/goveralls
go get golang.org/x/tools/cmd/cover
deps: gx covertools
gx --verbose install --global
gx-go rewrite
publish:
gx-go rewrite --undo
go-ipld-cbor
==================
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io)
[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://libp2p.io/)
[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs)
[![Coverage Status](https://coveralls.io/repos/github/libp2p/js-libp2p-floodsub/badge.svg?branch=master)](https://coveralls.io/github/libp2p/js-libp2p-floodsub?branch=master)
[![Travis CI](https://travis-ci.org/libp2p/js-libp2p-floodsub.svg?branch=master)](https://travis-ci.org/libp2p/js-libp2p-floodsub)
> An implementation of a cbor encoded merkledag object.
## Table of Contents
- [Install](#install)
- [Usage](#usage)
- [API](#api)
- [Contribute](#contribute)
- [License](#license)
## Install
```sh
make install
```
## Contribute
PRs are welcome!
Small note: If editing the Readme, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.
## License
MIT © Jeromy Johnson
package cbornode
import (
"encoding/json"
"errors"
"fmt"
"io"
cid "github.com/ipfs/go-cid"
node "github.com/ipfs/go-ipld-node"
mh "github.com/multiformats/go-multihash"
cbor "github.com/whyrusleeping/cbor/go"
)
func Decode(b []byte) (*Node, error) {
out := new(Node)
err := cbor.Loads(b, &out.obj)
if err != nil {
return nil, err
}
return out, nil
}
func EncodeObject(obj interface{}) ([]byte, error) {
return cbor.Dumps(obj)
}
// DecodeInto decodes a serialized ipld cbor object into the given object.
func DecodeInto(b []byte, v interface{}) error {
// The cbor library really doesnt make this sort of operation easy on us when we are implementing
// the `ToCBOR` method.
var m map[interface{}]interface{}
err := cbor.Loads(b, &m)
if err != nil {
return err
}
jsonable, err := toSaneMap(m)
if err != nil {
return err
}
jsonb, err := json.Marshal(jsonable)
if err != nil {
return err
}
return json.Unmarshal(jsonb, v)
}
var ErrNoSuchLink = errors.New("no such link found")
type Node struct {
obj map[interface{}]interface{}
}
func WrapMap(m map[interface{}]interface{}) (*Node, error) {
return &Node{m}, nil
}
type Link struct {
Target *cid.Cid `json:"/" cbor:"/"`
}
func (l *Link) ToCBOR(w io.Writer, enc *cbor.Encoder) error {
obj := map[string]interface{}{
"/": l.Target.Bytes(),
}
return enc.Encode(obj)
}
func (n Node) Resolve(path []string) (interface{}, []string, error) {
cur := n.obj
for i, val := range path {
next, ok := cur[val]
if !ok {
return nil, nil, ErrNoSuchLink
}
nextmap, ok := next.(map[interface{}]interface{})
if !ok {
return nil, nil, errors.New("tried to resolve through object that had no links")
}
if lnk, ok := nextmap["/"]; ok {
out, err := linkCast(lnk)
if err != nil {
return nil, nil, err
}
out.Name = val
return out, path[i+1:], nil
}
cur = nextmap
}
return nil, nil, errors.New("could not resolve through object")
}
func (n Node) ResolveLink(path []string) (*node.Link, []string, error) {
obj, rest, err := n.Resolve(path)
if err != nil {
return nil, nil, err
}
lnk, ok := obj.(*node.Link)
if ok {
return lnk, rest, nil
}
return nil, rest, fmt.Errorf("found non-link at given path")
}
func linkCast(lnk interface{}) (*node.Link, error) {
lnkb, ok := lnk.([]byte)
if !ok {
return nil, errors.New("incorrectly formatted link")
}
c, err := cid.Cast(lnkb)
if err != nil {
return nil, err
}
return &node.Link{Cid: c}, nil
}
func (n Node) Tree() []string {
var out []string
err := traverse(n.obj, "", func(name string, val interface{}) error {
out = append(out, name)
return nil
})
if err != nil {
panic(err)
}
return out
}
func (n Node) Links() []*node.Link {
var out []*node.Link
err := traverse(n.obj, "", func(_ string, val interface{}) error {
if lnk, ok := val.(*node.Link); ok {
out = append(out, lnk)
}
return nil
})
if err != nil {
panic(err)
}
return out
}
func traverse(obj map[interface{}]interface{}, cur string, cb func(string, interface{}) error) error {
if lnk, ok := obj["/"]; ok {
l, err := linkCast(lnk)
if err != nil {
return err
}
return cb(cur, l)
}
for k, v := range obj {
ks, ok := k.(string)
if !ok {
return errors.New("map key was not a string")
}
this := cur + "/" + ks
switch v := v.(type) {
case map[interface{}]interface{}:
if err := traverse(v, this, cb); err != nil {
return err
}
default:
if err := cb(this, v); err != nil {
return err
}
}
}
return nil
}
func (n Node) RawData() []byte {
b, err := cbor.Dumps(n.obj)
if err != nil {
// not sure this can ever happen
panic(err)
}
return b
}
func (n Node) Cid() *cid.Cid {
data := n.RawData()
hash, _ := mh.Sum(data, mh.SHA2_256, -1)
return cid.NewCidV1(cid.CBOR, hash)
}
func (n Node) Loggable() map[string]interface{} {
return map[string]interface{}{
"node_type": "cbor",
"cid": n.Cid(),
}
}
func (n Node) Size() (uint64, error) {
return uint64(len(n.RawData())), nil
}
func (n Node) Stat() (*node.NodeStat, error) {
return &node.NodeStat{}, nil
}
func (n Node) String() string {
return n.Cid().String()
}
func (n Node) MarshalJSON() ([]byte, error) {
out, err := toSaneMap(n.obj)
if err != nil {
return nil, err
}
return json.Marshal(out)
}
func toSaneMap(n map[interface{}]interface{}) (interface{}, error) {
if lnk, ok := n["/"]; ok && len(n) == 1 {
lnkb, ok := lnk.([]byte)
if !ok {
return nil, fmt.Errorf("link value should have been bytes")
}
c, err := cid.Cast(lnkb)
if err != nil {
return nil, err
}
return &Link{c}, nil
}
out := make(map[string]interface{})
for k, v := range n {
ks, ok := k.(string)
if !ok {
return nil, fmt.Errorf("map keys must be strings")
}
obj, err := convertToJsonIsh(v)
if err != nil {
return nil, err
}
out[ks] = obj
}
return out, nil
}
func convertToJsonIsh(v interface{}) (interface{}, error) {
switch v := v.(type) {
case map[interface{}]interface{}:
return toSaneMap(v)
case []interface{}:
var out []interface{}
for _, i := range v {
obj, err := convertToJsonIsh(i)
if err != nil {
return nil, err
}
out = append(out, obj)
}
return out, nil
default:
return v, nil
}
}
var _ node.Node = (*Node)(nil)
package cbornode
import (
"testing"
cid "github.com/ipfs/go-cid"
u "github.com/ipfs/go-ipfs-util"
cbor "github.com/whyrusleeping/cbor/go"
)
type testObject struct {
Name string
Bar *Link
}
func TestBasicMarshal(t *testing.T) {
c := cid.NewCidV0(u.Hash([]byte("something")))
obj := testObject{
Name: "foo",
Bar: &Link{c},
}
out, err := cbor.Dumps(&obj)
if err != nil {
t.Fatal(err)
}
back, err := Decode(out)
if err != nil {
t.Fatal(err)
}
lnk, _, err := back.ResolveLink([]string{"Bar"})
if err != nil {
t.Fatal(err)
}
if !lnk.Cid.Equals(c) {
t.Fatal("expected cid to match")
}
var obj2 testObject
err = DecodeInto(out, &obj2)
if err != nil {
t.Fatal(err)
}
t.Logf("%#v", obj2)
}
{
"author": "whyrusleeping",
"bugs": {
"url": "https://github.com/ipfs/go-cbor-node"
},
"gx": {
"dvcsimport": "github.com/ipfs/go-ipld-cbor"
},
"gxDependencies": [
{
"author": "whyrusleeping",
"hash": "QmNs4rbc8bDGDXZwoQf4Rg6KCr7FhfKDG4eNra1tXELqNf",
"name": "go-ipld-node",
"version": "0.3.1"
},
{
"author": "whyrusleeping",
"hash": "QmPBa9N9MuZ16fPuKMv9KCq1aAwhkTY4G6LXQYQmWJiCrj",
"name": "go-cid",
"version": "0.7.2"
},
{
"author": "whyrusleeping",
"hash": "Qmb912gdngC1UWwTkhuW8knyRbcWeu5kqkxBpveLmW8bSr",
"name": "go-ipfs-util",
"version": "1.2.0"
},
{
"author": "whyrusleeping",
"hash": "QmPL3RCWaM6s7b82LSLS1MGX2jpxPxA1v2vmgLm15b1NcW",
"name": "cbor",
"version": "0.2.0"
}
],
"gxVersion": "0.10.0",
"language": "go",
"license": "",
"name": "go-ipld-cbor",
"releaseCmd": "git commit -a -m \"gx publish $VERSION\"",
"version": "0.0.0"
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment