mirror of
https://github.com/logos-messaging/go-multiaddr.git
synced 2026-01-02 13:03:11 +00:00
move deps from godep to gx
This commit is contained in:
parent
4a8bd8f8ba
commit
4d7e08bab8
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
bin/gx*
|
||||
*.swp
|
||||
17
.travis.yml
17
.travis.yml
@ -1,11 +1,20 @@
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
language: go
|
||||
|
||||
sudo: false
|
||||
|
||||
go:
|
||||
- 1.3
|
||||
- release
|
||||
- tip
|
||||
- 1.5.3
|
||||
|
||||
install:
|
||||
- make deps
|
||||
|
||||
script:
|
||||
- make test
|
||||
|
||||
env: TEST_VERBOSE=1
|
||||
cache:
|
||||
directories:
|
||||
- $GOPATH/src/gx
|
||||
|
||||
43
Godeps/Godeps.json
generated
43
Godeps/Godeps.json
generated
@ -1,43 +0,0 @@
|
||||
{
|
||||
"ImportPath": "github.com/jbenet/go-multiaddr-net",
|
||||
"GoVersion": "go1.4.2",
|
||||
"Packages": [
|
||||
"./..."
|
||||
],
|
||||
"Deps": [
|
||||
{
|
||||
"ImportPath": "github.com/anacrolix/jitter",
|
||||
"Rev": "2ea5c18645100745b24e9f5cfc9b3f6f7eac51ef"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/anacrolix/missinggo",
|
||||
"Rev": "4e1ca5963308863b56c31863f60c394a7365ec29"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/anacrolix/utp",
|
||||
"Rev": "0bb24de92c268452fb9106ca4fb9302442ca0dee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/bradfitz/iter",
|
||||
"Rev": "454541ec3da2a73fc34fd049b19ee5777bf19345"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/jbenet/go-base58",
|
||||
"Rev": "568a28d73fd97651d3442392036a658b6976eed5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/jbenet/go-multiaddr",
|
||||
"Comment": "0.1.2-38-gc13f11b",
|
||||
"Rev": "c13f11bbfe6439771f4df7bfb330f686826144e8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/jbenet/go-multihash",
|
||||
"Comment": "0.1.0-36-g87e53a9",
|
||||
"Rev": "87e53a9d2875a18a7863b351d22f912545e6b3a3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/sha3",
|
||||
"Rev": "1351f936d976c60a0a48d728281922cf63eafb8d"
|
||||
}
|
||||
]
|
||||
}
|
||||
5
Godeps/Readme
generated
5
Godeps/Readme
generated
@ -1,5 +0,0 @@
|
||||
This directory tree is generated automatically by godep.
|
||||
|
||||
Please do not edit.
|
||||
|
||||
See https://github.com/tools/godep for more information.
|
||||
2
Godeps/_workspace/.gitignore
generated
vendored
2
Godeps/_workspace/.gitignore
generated
vendored
@ -1,2 +0,0 @@
|
||||
/pkg
|
||||
/bin
|
||||
12
Godeps/_workspace/src/github.com/anacrolix/jitter/jitter.go
generated
vendored
12
Godeps/_workspace/src/github.com/anacrolix/jitter/jitter.go
generated
vendored
@ -1,12 +0,0 @@
|
||||
package jitter
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Duration(average, plusMinus time.Duration) (ret time.Duration) {
|
||||
ret = average - plusMinus
|
||||
ret += time.Duration(rand.Int63n(2*int64(plusMinus) + 1))
|
||||
return
|
||||
}
|
||||
72
Godeps/_workspace/src/github.com/anacrolix/missinggo/addr.go
generated
vendored
72
Godeps/_workspace/src/github.com/anacrolix/missinggo/addr.go
generated
vendored
@ -1,72 +0,0 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type HostMaybePort struct {
|
||||
Host string
|
||||
Port int
|
||||
NoPort bool
|
||||
}
|
||||
|
||||
func (me HostMaybePort) String() string {
|
||||
if me.NoPort {
|
||||
return me.Host
|
||||
}
|
||||
return net.JoinHostPort(me.Host, strconv.FormatInt(int64(me.Port), 10))
|
||||
}
|
||||
|
||||
func SplitHostPort(hostport string) (ret HostMaybePort) {
|
||||
host, port, err := net.SplitHostPort(hostport)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "missing port") {
|
||||
ret.Host = hostport
|
||||
ret.NoPort = true
|
||||
return
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
i64, err := strconv.ParseInt(port, 0, 0)
|
||||
ret.Host = host
|
||||
ret.Port = int(i64)
|
||||
if err != nil {
|
||||
ret.NoPort = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Extracts the port as an integer from an address string.
|
||||
func AddrPort(addr net.Addr) int {
|
||||
switch raw := addr.(type) {
|
||||
case *net.UDPAddr:
|
||||
return raw.Port
|
||||
default:
|
||||
_, port, err := net.SplitHostPort(addr.String())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
i64, err := strconv.ParseInt(port, 0, 0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return int(i64)
|
||||
}
|
||||
}
|
||||
|
||||
func AddrIP(addr net.Addr) net.IP {
|
||||
switch raw := addr.(type) {
|
||||
case *net.UDPAddr:
|
||||
return raw.IP
|
||||
case *net.TCPAddr:
|
||||
return raw.IP
|
||||
default:
|
||||
host, _, err := net.SplitHostPort(addr.String())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return net.ParseIP(host)
|
||||
}
|
||||
}
|
||||
17
Godeps/_workspace/src/github.com/anacrolix/missinggo/addr_test.go
generated
vendored
17
Godeps/_workspace/src/github.com/anacrolix/missinggo/addr_test.go
generated
vendored
@ -1,17 +0,0 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSplitHostPort(t *testing.T) {
|
||||
assert.EqualValues(t, HostMaybePort{"a", 1, false}, SplitHostPort("a:1"))
|
||||
assert.EqualValues(t, HostMaybePort{"a", 0, true}, SplitHostPort("a"))
|
||||
}
|
||||
|
||||
func TestHostMaybePortString(t *testing.T) {
|
||||
assert.EqualValues(t, "a:1", (HostMaybePort{"a", 1, false}).String())
|
||||
assert.EqualValues(t, "a", (HostMaybePort{"a", 0, true}).String())
|
||||
}
|
||||
15
Godeps/_workspace/src/github.com/anacrolix/missinggo/args/args.go
generated
vendored
15
Godeps/_workspace/src/github.com/anacrolix/missinggo/args/args.go
generated
vendored
@ -1,15 +0,0 @@
|
||||
package args
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func Parse() {
|
||||
flag.Parse()
|
||||
if flag.NArg() != 0 {
|
||||
fmt.Fprintf(os.Stderr, "unexpected positional arguments\n")
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
11
Godeps/_workspace/src/github.com/anacrolix/missinggo/atime.go
generated
vendored
11
Godeps/_workspace/src/github.com/anacrolix/missinggo/atime.go
generated
vendored
@ -1,11 +0,0 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Extracts the access time from the FileInfo internals.
|
||||
func FileInfoAccessTime(fi os.FileInfo) time.Time {
|
||||
return fileInfoAccessTime(fi)
|
||||
}
|
||||
12
Godeps/_workspace/src/github.com/anacrolix/missinggo/atime_darwin.go
generated
vendored
12
Godeps/_workspace/src/github.com/anacrolix/missinggo/atime_darwin.go
generated
vendored
@ -1,12 +0,0 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func fileInfoAccessTime(fi os.FileInfo) time.Time {
|
||||
ts := fi.Sys().(*syscall.Stat_t).Atimespec
|
||||
return time.Unix(int64(ts.Sec), int64(ts.Nsec))
|
||||
}
|
||||
12
Godeps/_workspace/src/github.com/anacrolix/missinggo/atime_freebsd.go
generated
vendored
12
Godeps/_workspace/src/github.com/anacrolix/missinggo/atime_freebsd.go
generated
vendored
@ -1,12 +0,0 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func fileInfoAccessTime(fi os.FileInfo) time.Time {
|
||||
ts := fi.Sys().(*syscall.Stat_t).Atimespec
|
||||
return time.Unix(int64(ts.Sec), int64(ts.Nsec))
|
||||
}
|
||||
12
Godeps/_workspace/src/github.com/anacrolix/missinggo/atime_linux.go
generated
vendored
12
Godeps/_workspace/src/github.com/anacrolix/missinggo/atime_linux.go
generated
vendored
@ -1,12 +0,0 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func fileInfoAccessTime(fi os.FileInfo) time.Time {
|
||||
ts := fi.Sys().(*syscall.Stat_t).Atim
|
||||
return time.Unix(int64(ts.Sec), int64(ts.Nsec))
|
||||
}
|
||||
12
Godeps/_workspace/src/github.com/anacrolix/missinggo/atime_windows.go
generated
vendored
12
Godeps/_workspace/src/github.com/anacrolix/missinggo/atime_windows.go
generated
vendored
@ -1,12 +0,0 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func fileInfoAccessTime(fi os.FileInfo) time.Time {
|
||||
ts := fi.Sys().(syscall.Win32FileAttributeData).LastAccessTime
|
||||
return time.Unix(0, int64(ts.Nanoseconds()))
|
||||
}
|
||||
17
Godeps/_workspace/src/github.com/anacrolix/missinggo/castslice.go
generated
vendored
17
Godeps/_workspace/src/github.com/anacrolix/missinggo/castslice.go
generated
vendored
@ -1,17 +0,0 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/bradfitz/iter"
|
||||
)
|
||||
|
||||
func ConvertToSliceOfEmptyInterface(slice interface{}) (ret []interface{}) {
|
||||
v := reflect.ValueOf(slice)
|
||||
l := v.Len()
|
||||
ret = make([]interface{}, 0, l)
|
||||
for i := range iter.N(v.Len()) {
|
||||
ret = append(ret, v.Index(i).Interface())
|
||||
}
|
||||
return
|
||||
}
|
||||
12
Godeps/_workspace/src/github.com/anacrolix/missinggo/cmd/go-env/main.go
generated
vendored
12
Godeps/_workspace/src/github.com/anacrolix/missinggo/cmd/go-env/main.go
generated
vendored
@ -1,12 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
for _, v := range os.Environ() {
|
||||
fmt.Printf("%s\n", v)
|
||||
}
|
||||
}
|
||||
3
Godeps/_workspace/src/github.com/anacrolix/missinggo/cmd/nop/main.go
generated
vendored
3
Godeps/_workspace/src/github.com/anacrolix/missinggo/cmd/nop/main.go
generated
vendored
@ -1,3 +0,0 @@
|
||||
package main
|
||||
|
||||
func main() {}
|
||||
11
Godeps/_workspace/src/github.com/anacrolix/missinggo/cmd/query-escape/main.go
generated
vendored
11
Godeps/_workspace/src/github.com/anacrolix/missinggo/cmd/query-escape/main.go
generated
vendored
@ -1,11 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(url.QueryEscape(os.Args[1]))
|
||||
}
|
||||
11
Godeps/_workspace/src/github.com/anacrolix/missinggo/cmd/query-unescape/main.go
generated
vendored
11
Godeps/_workspace/src/github.com/anacrolix/missinggo/cmd/query-unescape/main.go
generated
vendored
@ -1,11 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(url.QueryUnescape(os.Args[1]))
|
||||
}
|
||||
32
Godeps/_workspace/src/github.com/anacrolix/missinggo/copy.go
generated
vendored
32
Godeps/_workspace/src/github.com/anacrolix/missinggo/copy.go
generated
vendored
@ -1,32 +0,0 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func CopyExact(dest interface{}, src interface{}) {
|
||||
dV := reflect.ValueOf(dest)
|
||||
sV := reflect.ValueOf(src)
|
||||
if dV.Kind() == reflect.Ptr {
|
||||
dV = dV.Elem()
|
||||
}
|
||||
if dV.Kind() == reflect.Array && !dV.CanAddr() {
|
||||
panic(fmt.Sprintf("dest not addressable: %T", dest))
|
||||
}
|
||||
if sV.Kind() == reflect.Ptr {
|
||||
sV = sV.Elem()
|
||||
}
|
||||
if sV.Kind() == reflect.String {
|
||||
sV = sV.Convert(reflect.SliceOf(dV.Type().Elem()))
|
||||
}
|
||||
if !sV.IsValid() {
|
||||
panic("invalid source, probably nil")
|
||||
}
|
||||
if dV.Len() != sV.Len() {
|
||||
panic(fmt.Sprintf("dest len (%d) != src len (%d)", dV.Len(), sV.Len()))
|
||||
}
|
||||
if dV.Len() != reflect.Copy(dV, sV) {
|
||||
panic("dammit")
|
||||
}
|
||||
}
|
||||
89
Godeps/_workspace/src/github.com/anacrolix/missinggo/copy_test.go
generated
vendored
89
Godeps/_workspace/src/github.com/anacrolix/missinggo/copy_test.go
generated
vendored
@ -1,89 +0,0 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCopyToArray(t *testing.T) {
|
||||
var arr [3]byte
|
||||
bb := []byte{1, 2, 3}
|
||||
CopyExact(&arr, bb)
|
||||
if !bytes.Equal(arr[:], bb) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyToSlicedArray(t *testing.T) {
|
||||
var arr [5]byte
|
||||
CopyExact(arr[:], "hello")
|
||||
if !bytes.Equal(arr[:], []byte("hello")) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyDestNotAddr(t *testing.T) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r == nil {
|
||||
t.FailNow()
|
||||
}
|
||||
t.Log(r)
|
||||
}()
|
||||
var arr [3]byte
|
||||
CopyExact(arr, "nope")
|
||||
}
|
||||
|
||||
func TestCopyLenMismatch(t *testing.T) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r == nil {
|
||||
t.FailNow()
|
||||
}
|
||||
t.Log(r)
|
||||
}()
|
||||
CopyExact(make([]byte, 2), "abc")
|
||||
}
|
||||
|
||||
func TestCopySrcString(t *testing.T) {
|
||||
dest := make([]byte, 3)
|
||||
CopyExact(dest, "lol")
|
||||
if string(dest) != "lol" {
|
||||
t.FailNow()
|
||||
}
|
||||
func() {
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r == nil {
|
||||
t.FailNow()
|
||||
}
|
||||
}()
|
||||
CopyExact(dest, "rofl")
|
||||
}()
|
||||
var arr [5]byte
|
||||
CopyExact(&arr, interface{}("hello"))
|
||||
if string(arr[:]) != "hello" {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopySrcNilInterface(t *testing.T) {
|
||||
var arr [3]byte
|
||||
defer func() {
|
||||
r := recover().(string)
|
||||
if !strings.Contains(r, "invalid source") {
|
||||
t.FailNow()
|
||||
}
|
||||
}()
|
||||
CopyExact(&arr, nil)
|
||||
}
|
||||
|
||||
func TestCopySrcPtr(t *testing.T) {
|
||||
var bigDst [1024]byte
|
||||
var bigSrc [1024]byte = [1024]byte{'h', 'i'}
|
||||
CopyExact(&bigDst, &bigSrc)
|
||||
if !bytes.Equal(bigDst[:], bigSrc[:]) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
18
Godeps/_workspace/src/github.com/anacrolix/missinggo/croak.go
generated
vendored
18
Godeps/_workspace/src/github.com/anacrolix/missinggo/croak.go
generated
vendored
@ -1,18 +0,0 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func Unchomp(s string) string {
|
||||
if len(s) > 0 && s[len(s)-1] == '\n' {
|
||||
return s
|
||||
}
|
||||
return s + "\n"
|
||||
}
|
||||
|
||||
func Fatal(msg interface{}) {
|
||||
os.Stderr.WriteString(Unchomp(fmt.Sprint(msg)))
|
||||
os.Exit(1)
|
||||
}
|
||||
3
Godeps/_workspace/src/github.com/anacrolix/missinggo/doc.go
generated
vendored
3
Godeps/_workspace/src/github.com/anacrolix/missinggo/doc.go
generated
vendored
@ -1,3 +0,0 @@
|
||||
// Package missinggo contains miscellaneous helpers used in many of anacrolix'
|
||||
// projects.
|
||||
package missinggo
|
||||
35
Godeps/_workspace/src/github.com/anacrolix/missinggo/expvarIndentMap.go
generated
vendored
35
Godeps/_workspace/src/github.com/anacrolix/missinggo/expvarIndentMap.go
generated
vendored
@ -1,35 +0,0 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"expvar"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type IndentMap struct {
|
||||
expvar.Map
|
||||
}
|
||||
|
||||
var _ expvar.Var = &IndentMap{}
|
||||
|
||||
func NewExpvarIndentMap(name string) *IndentMap {
|
||||
v := new(IndentMap)
|
||||
v.Init()
|
||||
expvar.Publish(name, v)
|
||||
return v
|
||||
}
|
||||
|
||||
func (v *IndentMap) String() string {
|
||||
var b bytes.Buffer
|
||||
fmt.Fprintf(&b, "{")
|
||||
first := true
|
||||
v.Do(func(kv expvar.KeyValue) {
|
||||
if !first {
|
||||
fmt.Fprintf(&b, ",")
|
||||
}
|
||||
fmt.Fprintf(&b, "\n\t%q: %v", kv.Key, kv.Value)
|
||||
first = false
|
||||
})
|
||||
fmt.Fprintf(&b, "}")
|
||||
return b.String()
|
||||
}
|
||||
269
Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/cache.go
generated
vendored
269
Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/cache.go
generated
vendored
@ -1,269 +0,0 @@
|
||||
package filecache
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/anacrolix/missinggo"
|
||||
)
|
||||
|
||||
type Cache struct {
|
||||
mu sync.Mutex
|
||||
capacity int64
|
||||
filled int64
|
||||
items *lruItems
|
||||
paths map[string]ItemInfo
|
||||
root string
|
||||
}
|
||||
|
||||
type CacheInfo struct {
|
||||
Capacity int64
|
||||
Filled int64
|
||||
NumItems int
|
||||
}
|
||||
|
||||
type ItemInfo struct {
|
||||
Accessed time.Time
|
||||
Size int64
|
||||
Path string
|
||||
}
|
||||
|
||||
// Calls the function for every item known to the cache. The ItemInfo should
|
||||
// not be modified.
|
||||
func (me *Cache) WalkItems(cb func(ItemInfo)) {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
for e := me.items.Front(); e != nil; e = e.Next() {
|
||||
cb(e.Value().(ItemInfo))
|
||||
}
|
||||
}
|
||||
|
||||
func (me *Cache) Info() (ret CacheInfo) {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
ret.Capacity = me.capacity
|
||||
ret.Filled = me.filled
|
||||
ret.NumItems = len(me.paths)
|
||||
return
|
||||
}
|
||||
|
||||
func (me *Cache) SetCapacity(capacity int64) {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
me.capacity = capacity
|
||||
}
|
||||
|
||||
func NewCache(root string) (ret *Cache, err error) {
|
||||
if !filepath.IsAbs(root) {
|
||||
err = errors.New("root is not an absolute filepath")
|
||||
return
|
||||
}
|
||||
ret = &Cache{
|
||||
root: root,
|
||||
capacity: -1, // unlimited
|
||||
}
|
||||
ret.mu.Lock()
|
||||
go func() {
|
||||
defer ret.mu.Unlock()
|
||||
ret.rescan()
|
||||
}()
|
||||
return
|
||||
}
|
||||
|
||||
// An empty return path is an error.
|
||||
func sanitizePath(p string) (ret string) {
|
||||
if p == "" {
|
||||
return
|
||||
}
|
||||
ret = path.Clean("/" + p)
|
||||
if ret[0] == '/' {
|
||||
ret = ret[1:]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Leaf is a descendent of root.
|
||||
func pruneEmptyDirs(root string, leaf string) (err error) {
|
||||
rootInfo, err := os.Stat(root)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for {
|
||||
var leafInfo os.FileInfo
|
||||
leafInfo, err = os.Stat(leaf)
|
||||
if os.IsNotExist(err) {
|
||||
goto parent
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if !leafInfo.IsDir() {
|
||||
return
|
||||
}
|
||||
if os.SameFile(rootInfo, leafInfo) {
|
||||
return
|
||||
}
|
||||
if os.Remove(leaf) != nil {
|
||||
return
|
||||
}
|
||||
parent:
|
||||
leaf = filepath.Dir(leaf)
|
||||
}
|
||||
}
|
||||
|
||||
func (me *Cache) Remove(path string) (err error) {
|
||||
path = sanitizePath(path)
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
err = me.remove(path)
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
ErrBadPath = errors.New("bad path")
|
||||
ErrIsDir = errors.New("is directory")
|
||||
)
|
||||
|
||||
func (me *Cache) OpenFile(path string, flag int) (ret *File, err error) {
|
||||
path = sanitizePath(path)
|
||||
if path == "" {
|
||||
err = ErrIsDir
|
||||
return
|
||||
}
|
||||
f, err := os.OpenFile(me.realpath(path), flag, 0644)
|
||||
if flag&os.O_CREATE != 0 && os.IsNotExist(err) {
|
||||
os.MkdirAll(me.root, 0755)
|
||||
os.MkdirAll(filepath.Dir(me.realpath(path)), 0755)
|
||||
f, err = os.OpenFile(me.realpath(path), flag, 0644)
|
||||
if err != nil {
|
||||
me.pruneEmptyDirs(path)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ret = &File{
|
||||
c: me,
|
||||
path: path,
|
||||
f: f,
|
||||
}
|
||||
me.mu.Lock()
|
||||
go func() {
|
||||
defer me.mu.Unlock()
|
||||
me.statItem(path, time.Now())
|
||||
}()
|
||||
return
|
||||
}
|
||||
|
||||
func (me *Cache) rescan() {
|
||||
me.filled = 0
|
||||
me.items = newLRUItems()
|
||||
me.paths = make(map[string]ItemInfo)
|
||||
err := filepath.Walk(me.root, func(path string, info os.FileInfo, err error) error {
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
path, err = filepath.Rel(me.root, path)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return nil
|
||||
}
|
||||
me.statItem(path, time.Time{})
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (me *Cache) insertItem(i ItemInfo) {
|
||||
me.items.Insert(i)
|
||||
}
|
||||
|
||||
func (me *Cache) removeInfo(path string) (ret ItemInfo, ok bool) {
|
||||
ret, ok = me.paths[path]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if !me.items.Remove(ret) {
|
||||
panic(ret)
|
||||
}
|
||||
me.filled -= ret.Size
|
||||
delete(me.paths, path)
|
||||
return
|
||||
}
|
||||
|
||||
// Triggers the item for path to be updated. If access is non-zero, set the
|
||||
// item's access time to that value, otherwise deduce it appropriately.
|
||||
func (me *Cache) statItem(path string, access time.Time) {
|
||||
info, ok := me.removeInfo(path)
|
||||
fi, err := os.Stat(me.realpath(path))
|
||||
if os.IsNotExist(err) {
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !ok {
|
||||
info.Path = path
|
||||
}
|
||||
if !access.IsZero() {
|
||||
info.Accessed = access
|
||||
}
|
||||
if info.Accessed.IsZero() {
|
||||
info.Accessed = missinggo.FileInfoAccessTime(fi)
|
||||
}
|
||||
info.Size = fi.Size()
|
||||
me.filled += info.Size
|
||||
me.insertItem(info)
|
||||
me.paths[path] = info
|
||||
}
|
||||
|
||||
func (me *Cache) realpath(path string) string {
|
||||
return filepath.Join(me.root, filepath.FromSlash(path))
|
||||
}
|
||||
|
||||
func (me *Cache) TrimToCapacity() {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
me.trimToCapacity()
|
||||
}
|
||||
|
||||
func (me *Cache) pruneEmptyDirs(path string) {
|
||||
pruneEmptyDirs(me.root, me.realpath(path))
|
||||
}
|
||||
|
||||
func (me *Cache) remove(path string) (err error) {
|
||||
err = os.Remove(me.realpath(path))
|
||||
if os.IsNotExist(err) {
|
||||
err = nil
|
||||
}
|
||||
me.pruneEmptyDirs(path)
|
||||
me.removeInfo(path)
|
||||
return
|
||||
}
|
||||
|
||||
func (me *Cache) trimToCapacity() {
|
||||
if me.capacity < 0 {
|
||||
return
|
||||
}
|
||||
for me.filled > me.capacity {
|
||||
item := me.items.LRU()
|
||||
me.remove(item.Path)
|
||||
}
|
||||
}
|
||||
|
||||
func (me *Cache) pathInfo(p string) ItemInfo {
|
||||
return me.paths[p]
|
||||
}
|
||||
84
Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/cache_test.go
generated
vendored
84
Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/cache_test.go
generated
vendored
@ -1,84 +0,0 @@
|
||||
package filecache
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/anacrolix/missinggo"
|
||||
)
|
||||
|
||||
func TestCache(t *testing.T) {
|
||||
td, err := ioutil.TempDir("", "gotest")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(td)
|
||||
c, err := NewCache(filepath.Join(td, "cache"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.EqualValues(t, 0, c.Info().Filled)
|
||||
c.WalkItems(func(i ItemInfo) {})
|
||||
_, err = c.OpenFile("/", os.O_CREATE)
|
||||
assert.NotNil(t, err)
|
||||
_, err = c.OpenFile("", os.O_CREATE)
|
||||
assert.NotNil(t, err)
|
||||
c.WalkItems(func(i ItemInfo) {})
|
||||
require.Equal(t, 0, c.Info().NumItems)
|
||||
_, err = c.OpenFile("notexist", 0)
|
||||
assert.True(t, os.IsNotExist(err), err)
|
||||
_, err = c.OpenFile("/notexist", 0)
|
||||
assert.True(t, os.IsNotExist(err), err)
|
||||
_, err = c.OpenFile("/dir/notexist", 0)
|
||||
assert.True(t, os.IsNotExist(err), err)
|
||||
f, err := c.OpenFile("dir/blah", os.O_CREATE)
|
||||
require.NoError(t, err)
|
||||
defer f.Close()
|
||||
c.WalkItems(func(i ItemInfo) {})
|
||||
assert.True(t, missinggo.FilePathExists(filepath.Join(td, filepath.FromSlash("cache/dir/blah"))))
|
||||
assert.True(t, missinggo.FilePathExists(filepath.Join(td, filepath.FromSlash("cache/dir/"))))
|
||||
assert.Equal(t, 1, c.Info().NumItems)
|
||||
f.Remove()
|
||||
assert.False(t, missinggo.FilePathExists(filepath.Join(td, filepath.FromSlash("dir/blah"))))
|
||||
assert.False(t, missinggo.FilePathExists(filepath.Join(td, filepath.FromSlash("dir/"))))
|
||||
_, err = f.Read(nil)
|
||||
assert.NotEqual(t, io.EOF, err)
|
||||
a, err := c.OpenFile("/a", os.O_CREATE|os.O_WRONLY)
|
||||
defer a.Close()
|
||||
require.Nil(t, err)
|
||||
b, err := c.OpenFile("b", os.O_CREATE|os.O_WRONLY)
|
||||
defer b.Close()
|
||||
require.Nil(t, err)
|
||||
c.mu.Lock()
|
||||
assert.True(t, c.pathInfo("a").Accessed.Before(c.pathInfo("b").Accessed))
|
||||
c.mu.Unlock()
|
||||
n, err := a.Write([]byte("hello"))
|
||||
assert.Nil(t, err)
|
||||
assert.EqualValues(t, 5, n)
|
||||
assert.EqualValues(t, 5, c.Info().Filled)
|
||||
assert.True(t, c.pathInfo("b").Accessed.Before(c.pathInfo("a").Accessed))
|
||||
c.SetCapacity(5)
|
||||
n, err = a.Write([]byte(" world"))
|
||||
assert.NotNil(t, err)
|
||||
_, err = b.Write([]byte("boom!"))
|
||||
// "a" and "b" have been evicted.
|
||||
assert.NotNil(t, err)
|
||||
assert.EqualValues(t, 0, c.Info().Filled)
|
||||
assert.EqualValues(t, 0, c.Info().NumItems)
|
||||
_, err = a.Seek(0, os.SEEK_SET)
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestSanitizePath(t *testing.T) {
|
||||
assert.Equal(t, "", sanitizePath("////"))
|
||||
assert.Equal(t, "", sanitizePath("/../.."))
|
||||
assert.Equal(t, "a", sanitizePath("/a//b/.."))
|
||||
assert.Equal(t, "a", sanitizePath("../a"))
|
||||
assert.Equal(t, "a", sanitizePath("./a"))
|
||||
}
|
||||
117
Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/file.go
generated
vendored
117
Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/file.go
generated
vendored
@ -1,117 +0,0 @@
|
||||
package filecache
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type File struct {
|
||||
mu sync.Mutex
|
||||
c *Cache
|
||||
path string
|
||||
f *os.File
|
||||
gone bool
|
||||
}
|
||||
|
||||
func (me *File) Remove() (err error) {
|
||||
return me.c.Remove(me.path)
|
||||
}
|
||||
|
||||
func (me *File) Seek(offset int64, whence int) (ret int64, err error) {
|
||||
ret, err = me.f.Seek(offset, whence)
|
||||
return
|
||||
}
|
||||
|
||||
func (me *File) maxWrite() (max int64, err error) {
|
||||
if me.c.capacity < 0 {
|
||||
max = math.MaxInt64
|
||||
return
|
||||
}
|
||||
pos, err := me.Seek(0, os.SEEK_CUR)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
max = me.c.capacity - pos
|
||||
if max < 0 {
|
||||
max = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
ErrFileTooLarge = errors.New("file too large for cache")
|
||||
ErrFileDisappeared = errors.New("file disappeared")
|
||||
)
|
||||
|
||||
func (me *File) checkGone() {
|
||||
if me.gone {
|
||||
return
|
||||
}
|
||||
ffi, _ := me.Stat()
|
||||
fsfi, _ := os.Stat(me.c.realpath(me.path))
|
||||
me.gone = !os.SameFile(ffi, fsfi)
|
||||
}
|
||||
|
||||
func (me *File) goneErr() error {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
me.checkGone()
|
||||
if me.gone {
|
||||
me.f.Close()
|
||||
return ErrFileDisappeared
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (me *File) Write(b []byte) (n int, err error) {
|
||||
err = me.goneErr()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n, err = me.f.Write(b)
|
||||
me.c.mu.Lock()
|
||||
me.c.statItem(me.path, time.Now())
|
||||
me.c.trimToCapacity()
|
||||
me.c.mu.Unlock()
|
||||
if err == nil {
|
||||
err = me.goneErr()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (me *File) Close() error {
|
||||
return me.f.Close()
|
||||
}
|
||||
|
||||
func (me *File) Stat() (os.FileInfo, error) {
|
||||
return me.f.Stat()
|
||||
}
|
||||
|
||||
func (me *File) Read(b []byte) (n int, err error) {
|
||||
err = me.goneErr()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
me.c.mu.Lock()
|
||||
defer me.c.mu.Unlock()
|
||||
me.c.statItem(me.path, time.Now())
|
||||
}()
|
||||
return me.f.Read(b)
|
||||
}
|
||||
|
||||
func (me *File) ReadAt(b []byte, off int64) (n int, err error) {
|
||||
err = me.goneErr()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
me.c.mu.Lock()
|
||||
defer me.c.mu.Unlock()
|
||||
me.c.statItem(me.path, time.Now())
|
||||
}()
|
||||
return me.f.ReadAt(b, off)
|
||||
}
|
||||
94
Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/lruitems.go
generated
vendored
94
Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/lruitems.go
generated
vendored
@ -1,94 +0,0 @@
|
||||
package filecache
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"io"
|
||||
|
||||
"github.com/cznic/b"
|
||||
)
|
||||
|
||||
type Iterator interface {
|
||||
Next() Iterator
|
||||
Value() interface{}
|
||||
}
|
||||
|
||||
type listElementIterator struct {
|
||||
le *list.Element
|
||||
}
|
||||
|
||||
func (me listElementIterator) Next() Iterator {
|
||||
e := me.le.Next()
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
return listElementIterator{e}
|
||||
}
|
||||
|
||||
func (me listElementIterator) Value() interface{} {
|
||||
return me.le.Value
|
||||
}
|
||||
|
||||
func newLRUItems() *lruItems {
|
||||
return &lruItems{b.TreeNew(func(_a, _b interface{}) int {
|
||||
a := _a.(ItemInfo)
|
||||
b := _b.(ItemInfo)
|
||||
if a.Accessed != b.Accessed {
|
||||
if a.Accessed.Before(b.Accessed) {
|
||||
return -1
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
if a.Path == b.Path {
|
||||
return 0
|
||||
}
|
||||
if a.Path < b.Path {
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
})}
|
||||
}
|
||||
|
||||
type lruItems struct {
|
||||
tree *b.Tree
|
||||
}
|
||||
|
||||
type bEnumeratorIterator struct {
|
||||
e *b.Enumerator
|
||||
v ItemInfo
|
||||
}
|
||||
|
||||
func (me bEnumeratorIterator) Next() Iterator {
|
||||
_, v, err := me.e.Next()
|
||||
if err == io.EOF {
|
||||
return nil
|
||||
}
|
||||
return bEnumeratorIterator{me.e, v.(ItemInfo)}
|
||||
}
|
||||
|
||||
func (me bEnumeratorIterator) Value() interface{} {
|
||||
return me.v
|
||||
}
|
||||
|
||||
func (me *lruItems) Front() Iterator {
|
||||
e, _ := me.tree.SeekFirst()
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
return bEnumeratorIterator{
|
||||
e: e,
|
||||
}.Next()
|
||||
}
|
||||
|
||||
func (me *lruItems) LRU() ItemInfo {
|
||||
_, v := me.tree.First()
|
||||
return v.(ItemInfo)
|
||||
}
|
||||
|
||||
func (me *lruItems) Insert(ii ItemInfo) {
|
||||
me.tree.Set(ii, ii)
|
||||
}
|
||||
|
||||
func (me *lruItems) Remove(ii ItemInfo) bool {
|
||||
return me.tree.Delete(ii)
|
||||
}
|
||||
22
Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/lruitems_test.go
generated
vendored
22
Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/lruitems_test.go
generated
vendored
@ -1,22 +0,0 @@
|
||||
package filecache
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/bradfitz/iter"
|
||||
)
|
||||
|
||||
func BenchmarkInsert(b *testing.B) {
|
||||
for _ = range iter.N(b.N) {
|
||||
li := newLRUItems()
|
||||
for _ = range iter.N(10000) {
|
||||
r := rand.Int63()
|
||||
t := time.Unix(r/1e9, r%1e9)
|
||||
li.Insert(ItemInfo{
|
||||
Accessed: t,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
38
Godeps/_workspace/src/github.com/anacrolix/missinggo/httpcontentrange.go
generated
vendored
38
Godeps/_workspace/src/github.com/anacrolix/missinggo/httpcontentrange.go
generated
vendored
@ -1,38 +0,0 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type HTTPBytesContentRange struct {
|
||||
First, Last, Length int64
|
||||
}
|
||||
|
||||
var bytesContentRangeRegexp = regexp.MustCompile(`bytes[ =](\d+)-(\d+)/(\d+|\*)`)
|
||||
|
||||
func ParseHTTPBytesContentRange(s string) (ret HTTPBytesContentRange, ok bool) {
|
||||
ss := bytesContentRangeRegexp.FindStringSubmatch(s)
|
||||
if ss == nil {
|
||||
return
|
||||
}
|
||||
var err error
|
||||
ret.First, err = strconv.ParseInt(ss[1], 10, 64)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ret.Last, err = strconv.ParseInt(ss[2], 10, 64)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if ss[3] == "*" {
|
||||
ret.Length = -1
|
||||
} else {
|
||||
ret.Length, err = strconv.ParseInt(ss[3], 10, 64)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
27
Godeps/_workspace/src/github.com/anacrolix/missinggo/httpcontentrange_test.go
generated
vendored
27
Godeps/_workspace/src/github.com/anacrolix/missinggo/httpcontentrange_test.go
generated
vendored
@ -1,27 +0,0 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestParseHTTPContentRange(t *testing.T) {
|
||||
for _, _case := range []struct {
|
||||
h string
|
||||
cr *HTTPBytesContentRange
|
||||
}{
|
||||
{"", nil},
|
||||
{"1-2/*", nil},
|
||||
{"bytes=1-2/3", &HTTPBytesContentRange{1, 2, 3}},
|
||||
{"bytes=12-34/*", &HTTPBytesContentRange{12, 34, -1}},
|
||||
{" bytes=12-34/*", &HTTPBytesContentRange{12, 34, -1}},
|
||||
{" bytes 12-34/56", &HTTPBytesContentRange{12, 34, 56}},
|
||||
} {
|
||||
ret, ok := ParseHTTPBytesContentRange(_case.h)
|
||||
assert.Equal(t, _case.cr != nil, ok)
|
||||
if _case.cr != nil {
|
||||
assert.Equal(t, *_case.cr, ret)
|
||||
}
|
||||
}
|
||||
}
|
||||
222
Godeps/_workspace/src/github.com/anacrolix/missinggo/httpfile/httpfile.go
generated
vendored
222
Godeps/_workspace/src/github.com/anacrolix/missinggo/httpfile/httpfile.go
generated
vendored
@ -1,222 +0,0 @@
|
||||
package httpfile
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/anacrolix/missinggo"
|
||||
)
|
||||
|
||||
type File struct {
|
||||
off int64
|
||||
r io.ReadCloser
|
||||
rOff int64
|
||||
length int64
|
||||
url string
|
||||
}
|
||||
|
||||
func OpenSectionReader(url string, off, n int64) (ret io.ReadCloser, err error) {
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", off, off+n-1))
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
err = ErrNotFound
|
||||
resp.Body.Close()
|
||||
return
|
||||
}
|
||||
if resp.StatusCode != http.StatusPartialContent {
|
||||
err = fmt.Errorf("bad response status: %s", resp.Status)
|
||||
resp.Body.Close()
|
||||
return
|
||||
}
|
||||
ret = resp.Body
|
||||
return
|
||||
}
|
||||
|
||||
func Open(url string) *File {
|
||||
return &File{
|
||||
url: url,
|
||||
}
|
||||
}
|
||||
|
||||
func (me *File) prepareReader() (err error) {
|
||||
if me.r != nil && me.off != me.rOff {
|
||||
me.r.Close()
|
||||
me.r = nil
|
||||
}
|
||||
if me.r != nil {
|
||||
return nil
|
||||
}
|
||||
req, err := http.NewRequest("GET", me.url, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if me.off != 0 {
|
||||
req.Header.Set("Range", fmt.Sprintf("bytes=%d-", me.off))
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
switch resp.StatusCode {
|
||||
case http.StatusPartialContent:
|
||||
cr, ok := missinggo.ParseHTTPBytesContentRange(resp.Header.Get("Content-Range"))
|
||||
if !ok || cr.First != me.off {
|
||||
err = errors.New("bad response")
|
||||
resp.Body.Close()
|
||||
return
|
||||
}
|
||||
me.length = cr.Length
|
||||
case http.StatusOK:
|
||||
if me.off != 0 {
|
||||
err = errors.New("bad response")
|
||||
resp.Body.Close()
|
||||
return
|
||||
}
|
||||
if h := resp.Header.Get("Content-Length"); h != "" {
|
||||
var cl uint64
|
||||
cl, err = strconv.ParseUint(h, 10, 64)
|
||||
if err != nil {
|
||||
resp.Body.Close()
|
||||
return
|
||||
}
|
||||
me.length = int64(cl)
|
||||
}
|
||||
default:
|
||||
err = errors.New(resp.Status)
|
||||
resp.Body.Close()
|
||||
return
|
||||
}
|
||||
me.r = resp.Body
|
||||
me.rOff = me.off
|
||||
return
|
||||
}
|
||||
|
||||
func (me *File) Read(b []byte) (n int, err error) {
|
||||
err = me.prepareReader()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n, err = me.r.Read(b)
|
||||
me.off += int64(n)
|
||||
me.rOff += int64(n)
|
||||
return
|
||||
}
|
||||
|
||||
func instanceLength(r *http.Response) (int64, error) {
|
||||
switch r.StatusCode {
|
||||
case http.StatusOK:
|
||||
if h := r.Header.Get("Content-Length"); h != "" {
|
||||
return strconv.ParseInt(h, 10, 64)
|
||||
} else {
|
||||
return -1, nil
|
||||
}
|
||||
case http.StatusPartialContent:
|
||||
cr, ok := missinggo.ParseHTTPBytesContentRange(r.Header.Get("Content-Range"))
|
||||
if !ok {
|
||||
return -1, errors.New("bad 206 response")
|
||||
}
|
||||
return cr.Length, nil
|
||||
default:
|
||||
return -1, errors.New(r.Status)
|
||||
}
|
||||
}
|
||||
|
||||
func (me *File) Seek(offset int64, whence int) (ret int64, err error) {
|
||||
switch whence {
|
||||
case os.SEEK_SET:
|
||||
ret = offset
|
||||
case os.SEEK_CUR:
|
||||
ret = me.off + offset
|
||||
case os.SEEK_END:
|
||||
if me.length < 0 {
|
||||
err = errors.New("length unknown")
|
||||
return
|
||||
}
|
||||
ret = me.length + offset
|
||||
default:
|
||||
err = fmt.Errorf("unhandled whence: %d", whence)
|
||||
return
|
||||
}
|
||||
me.off = ret
|
||||
return
|
||||
}
|
||||
|
||||
func (me *File) Write(b []byte) (n int, err error) {
|
||||
req, err := http.NewRequest("PATCH", me.url, bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
req.Header.Set("Content-Range", fmt.Sprintf("bytes=%d-", me.off))
|
||||
req.ContentLength = int64(len(b))
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusPartialContent {
|
||||
err = errors.New(resp.Status)
|
||||
return
|
||||
}
|
||||
n = len(b)
|
||||
me.off += int64(n)
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
ErrNotFound = errors.New("not found")
|
||||
)
|
||||
|
||||
// Returns the length of the resource in bytes.
|
||||
func GetLength(url string) (ret int64, err error) {
|
||||
resp, err := http.Head(url)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
err = ErrNotFound
|
||||
return
|
||||
}
|
||||
return instanceLength(resp)
|
||||
}
|
||||
|
||||
func (me *File) Close() error {
|
||||
me.url = ""
|
||||
if me.r != nil {
|
||||
me.r.Close()
|
||||
me.r = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Delete(urlStr string) (err error) {
|
||||
req, err := http.NewRequest("DELETE", urlStr, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
err = ErrNotFound
|
||||
return
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
err = fmt.Errorf("response: %s", resp.Status)
|
||||
}
|
||||
return
|
||||
}
|
||||
47
Godeps/_workspace/src/github.com/anacrolix/missinggo/httpgzip.go
generated
vendored
47
Godeps/_workspace/src/github.com/anacrolix/missinggo/httpgzip.go
generated
vendored
@ -1,47 +0,0 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type gzipResponseWriter struct {
|
||||
io.Writer
|
||||
http.ResponseWriter
|
||||
haveWritten bool
|
||||
}
|
||||
|
||||
func (w *gzipResponseWriter) Write(b []byte) (int, error) {
|
||||
if w.haveWritten {
|
||||
goto write
|
||||
}
|
||||
w.haveWritten = true
|
||||
if w.Header().Get("Content-Type") != "" {
|
||||
goto write
|
||||
}
|
||||
if type_ := http.DetectContentType(b); type_ != "application/octet-stream" {
|
||||
w.Header().Set("Content-Type", type_)
|
||||
}
|
||||
write:
|
||||
return w.Writer.Write(b)
|
||||
}
|
||||
|
||||
// Gzips response body if the request says it'll allow it.
|
||||
func GzipHTTPHandler(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") || w.Header().Get("Content-Encoding") != "" || w.Header().Get("Vary") != "" {
|
||||
h.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Encoding", "gzip")
|
||||
w.Header().Set("Vary", "Accept-Encoding")
|
||||
gz := gzip.NewWriter(w)
|
||||
defer gz.Close()
|
||||
h.ServeHTTP(&gzipResponseWriter{
|
||||
Writer: gz,
|
||||
ResponseWriter: w,
|
||||
}, r)
|
||||
})
|
||||
}
|
||||
60
Godeps/_workspace/src/github.com/anacrolix/missinggo/httpresponsestatus.go
generated
vendored
60
Godeps/_workspace/src/github.com/anacrolix/missinggo/httpresponsestatus.go
generated
vendored
@ -1,60 +0,0 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// A http.ResponseWriter that tracks the status of the response. The status
|
||||
// code, and number of bytes written for example.
|
||||
type StatusResponseWriter struct {
|
||||
RW http.ResponseWriter
|
||||
Code int
|
||||
BytesWritten int64
|
||||
}
|
||||
|
||||
var _ http.ResponseWriter = &StatusResponseWriter{}
|
||||
|
||||
func (me *StatusResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
return me.RW.(http.Hijacker).Hijack()
|
||||
}
|
||||
|
||||
func (me *StatusResponseWriter) CloseNotify() <-chan bool {
|
||||
return me.RW.(http.CloseNotifier).CloseNotify()
|
||||
}
|
||||
|
||||
func (me *StatusResponseWriter) Flush() {
|
||||
me.RW.(http.Flusher).Flush()
|
||||
}
|
||||
|
||||
func (me *StatusResponseWriter) Header() http.Header {
|
||||
return me.RW.Header()
|
||||
}
|
||||
|
||||
func (me *StatusResponseWriter) Write(b []byte) (n int, err error) {
|
||||
if me.Code == 0 {
|
||||
me.Code = 200
|
||||
}
|
||||
n, err = me.RW.Write(b)
|
||||
me.BytesWritten += int64(n)
|
||||
return
|
||||
}
|
||||
|
||||
func (me *StatusResponseWriter) WriteHeader(code int) {
|
||||
me.RW.WriteHeader(code)
|
||||
me.Code = code
|
||||
}
|
||||
|
||||
type ReaderFromStatusResponseWriter struct {
|
||||
StatusResponseWriter
|
||||
io.ReaderFrom
|
||||
}
|
||||
|
||||
func NewReaderFromStatusResponseWriter(w http.ResponseWriter) *ReaderFromStatusResponseWriter {
|
||||
return &ReaderFromStatusResponseWriter{
|
||||
StatusResponseWriter{RW: w},
|
||||
w.(io.ReaderFrom),
|
||||
}
|
||||
}
|
||||
81
Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/groupby.go
generated
vendored
81
Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/groupby.go
generated
vendored
@ -1,81 +0,0 @@
|
||||
package itertools
|
||||
|
||||
type groupBy struct {
|
||||
curKey interface{}
|
||||
curKeyOk bool
|
||||
curValue interface{}
|
||||
keyFunc func(interface{}) interface{}
|
||||
input Iterator
|
||||
groupKey interface{}
|
||||
groupKeyOk bool
|
||||
}
|
||||
|
||||
type Group interface {
|
||||
Iterator
|
||||
Key() interface{}
|
||||
}
|
||||
|
||||
type group struct {
|
||||
gb *groupBy
|
||||
key interface{}
|
||||
first bool
|
||||
}
|
||||
|
||||
func (me *group) Next() (ok bool) {
|
||||
if me.first {
|
||||
me.first = false
|
||||
return true
|
||||
}
|
||||
me.gb.advance()
|
||||
if !me.gb.curKeyOk || me.gb.curKey != me.key {
|
||||
return
|
||||
}
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
func (me group) Value() (ret interface{}) {
|
||||
ret = me.gb.curValue
|
||||
return
|
||||
}
|
||||
|
||||
func (me group) Key() interface{} {
|
||||
return me.key
|
||||
}
|
||||
|
||||
func (me *groupBy) advance() {
|
||||
me.curKeyOk = me.input.Next()
|
||||
if me.curKeyOk {
|
||||
me.curValue = me.input.Value()
|
||||
me.curKey = me.keyFunc(me.curValue)
|
||||
}
|
||||
}
|
||||
|
||||
func (me *groupBy) Next() (ok bool) {
|
||||
for me.curKey == me.groupKey {
|
||||
ok = me.input.Next()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
me.curValue = me.input.Value()
|
||||
me.curKey = me.keyFunc(me.curValue)
|
||||
me.curKeyOk = true
|
||||
}
|
||||
me.groupKey = me.curKey
|
||||
me.groupKeyOk = true
|
||||
return true
|
||||
}
|
||||
|
||||
func (me *groupBy) Value() (ret interface{}) {
|
||||
return &group{me, me.groupKey, true}
|
||||
}
|
||||
|
||||
func GroupBy(input Iterator, keyFunc func(interface{}) interface{}) Iterator {
|
||||
if keyFunc == nil {
|
||||
keyFunc = func(a interface{}) interface{} { return a }
|
||||
}
|
||||
return &groupBy{
|
||||
input: input,
|
||||
keyFunc: keyFunc,
|
||||
}
|
||||
}
|
||||
31
Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/groupby_test.go
generated
vendored
31
Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/groupby_test.go
generated
vendored
@ -1,31 +0,0 @@
|
||||
package itertools
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGroupByKey(t *testing.T) {
|
||||
var ks []byte
|
||||
gb := GroupBy(StringIterator("AAAABBBCCDAABBB"), nil)
|
||||
for gb.Next() {
|
||||
ks = append(ks, gb.Value().(Group).Key().(byte))
|
||||
}
|
||||
t.Log(ks)
|
||||
require.EqualValues(t, "ABCDAB", ks)
|
||||
}
|
||||
|
||||
func TestGroupByList(t *testing.T) {
|
||||
var gs []string
|
||||
gb := GroupBy(StringIterator("AAAABBBCCD"), nil)
|
||||
for gb.Next() {
|
||||
i := gb.Value().(Iterator)
|
||||
var g string
|
||||
for i.Next() {
|
||||
g += string(i.Value().(byte))
|
||||
}
|
||||
gs = append(gs, g)
|
||||
}
|
||||
t.Log(gs)
|
||||
}
|
||||
41
Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/iterator.go
generated
vendored
41
Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/iterator.go
generated
vendored
@ -1,41 +0,0 @@
|
||||
package itertools
|
||||
|
||||
import "github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/anacrolix/missinggo"
|
||||
|
||||
type Iterator interface {
|
||||
Next() bool
|
||||
Value() interface{}
|
||||
}
|
||||
|
||||
type sliceIterator struct {
|
||||
slice []interface{}
|
||||
value interface{}
|
||||
ok bool
|
||||
}
|
||||
|
||||
func (me *sliceIterator) Next() bool {
|
||||
if len(me.slice) == 0 {
|
||||
return false
|
||||
}
|
||||
me.value = me.slice[0]
|
||||
me.slice = me.slice[1:]
|
||||
me.ok = true
|
||||
return true
|
||||
}
|
||||
|
||||
func (me *sliceIterator) Value() interface{} {
|
||||
if !me.ok {
|
||||
panic("no value; call Next")
|
||||
}
|
||||
return me.value
|
||||
}
|
||||
|
||||
func SliceIterator(a []interface{}) Iterator {
|
||||
return &sliceIterator{
|
||||
slice: a,
|
||||
}
|
||||
}
|
||||
|
||||
func StringIterator(a string) Iterator {
|
||||
return SliceIterator(missinggo.ConvertToSliceOfEmptyInterface(a))
|
||||
}
|
||||
17
Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/iterator_test.go
generated
vendored
17
Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/iterator_test.go
generated
vendored
@ -1,17 +0,0 @@
|
||||
package itertools
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestIterator(t *testing.T) {
|
||||
const s = "AAAABBBCCDAABBB"
|
||||
si := StringIterator(s)
|
||||
for i := range s {
|
||||
require.True(t, si.Next())
|
||||
require.Equal(t, s[i], si.Value().(byte))
|
||||
}
|
||||
require.False(t, si.Next())
|
||||
}
|
||||
26
Godeps/_workspace/src/github.com/anacrolix/missinggo/net.go
generated
vendored
26
Godeps/_workspace/src/github.com/anacrolix/missinggo/net.go
generated
vendored
@ -1,26 +0,0 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
type HostPort struct {
|
||||
Host string // Just the host, with no port.
|
||||
Port string // May be empty if no port was given.
|
||||
Err error // The error returned from net.SplitHostPort.
|
||||
}
|
||||
|
||||
// Parse a "hostport" string, a concept that floats around the stdlib a lot
|
||||
// and is painful to work with. If no port is present, what's usually present
|
||||
// is just the host.
|
||||
func ParseHostPort(hostPort string) (ret HostPort) {
|
||||
ret.Host, ret.Port, ret.Err = net.SplitHostPort(hostPort)
|
||||
if ret.Err != nil {
|
||||
ret.Host = hostPort
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (me *HostPort) Join() string {
|
||||
return net.JoinHostPort(me.Host, me.Port)
|
||||
}
|
||||
20
Godeps/_workspace/src/github.com/anacrolix/missinggo/path.go
generated
vendored
20
Godeps/_workspace/src/github.com/anacrolix/missinggo/path.go
generated
vendored
@ -1,20 +0,0 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
// Splits the pathname p into Root and Ext, such that Root+Ext==p.
|
||||
func PathSplitExt(p string) (ret struct {
|
||||
Root, Ext string
|
||||
}) {
|
||||
ret.Ext = path.Ext(p)
|
||||
ret.Root = p[:len(p)-len(ret.Ext)]
|
||||
return
|
||||
}
|
||||
|
||||
func FilePathExists(p string) bool {
|
||||
_, err := os.Stat(p)
|
||||
return err == nil
|
||||
}
|
||||
17
Godeps/_workspace/src/github.com/anacrolix/missinggo/path_test.go
generated
vendored
17
Godeps/_workspace/src/github.com/anacrolix/missinggo/path_test.go
generated
vendored
@ -1,17 +0,0 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func ExamplePathSplitExt() {
|
||||
fmt.Printf("%q\n", PathSplitExt(".cshrc"))
|
||||
fmt.Printf("%q\n", PathSplitExt("dir/a.ext"))
|
||||
fmt.Printf("%q\n", PathSplitExt("dir/.rc"))
|
||||
fmt.Printf("%q\n", PathSplitExt("home/.secret/file"))
|
||||
// Output:
|
||||
// {"" ".cshrc"}
|
||||
// {"dir/a" ".ext"}
|
||||
// {"dir/" ".rc"}
|
||||
// {"home/.secret/file" ""}
|
||||
}
|
||||
48
Godeps/_workspace/src/github.com/anacrolix/missinggo/perf/mutex.go
generated
vendored
48
Godeps/_workspace/src/github.com/anacrolix/missinggo/perf/mutex.go
generated
vendored
@ -1,48 +0,0 @@
|
||||
package perf
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/anacrolix/missinggo"
|
||||
)
|
||||
|
||||
type TimedLocker struct {
|
||||
L sync.Locker
|
||||
Desc string
|
||||
}
|
||||
|
||||
func (me *TimedLocker) Lock() {
|
||||
tr := NewTimer()
|
||||
me.L.Lock()
|
||||
tr.Stop(me.Desc)
|
||||
}
|
||||
|
||||
func (me *TimedLocker) Unlock() {
|
||||
me.L.Unlock()
|
||||
}
|
||||
|
||||
type TimedRWLocker struct {
|
||||
RWL missinggo.RWLocker
|
||||
WriteDesc string
|
||||
ReadDesc string
|
||||
}
|
||||
|
||||
func (me *TimedRWLocker) Lock() {
|
||||
tr := NewTimer()
|
||||
me.RWL.Lock()
|
||||
tr.Stop(me.WriteDesc)
|
||||
}
|
||||
|
||||
func (me *TimedRWLocker) Unlock() {
|
||||
me.RWL.Unlock()
|
||||
}
|
||||
|
||||
func (me *TimedRWLocker) RLock() {
|
||||
tr := NewTimer()
|
||||
me.RWL.RLock()
|
||||
tr.Stop(me.ReadDesc)
|
||||
}
|
||||
|
||||
func (me *TimedRWLocker) RUnlock() {
|
||||
me.RWL.RUnlock()
|
||||
}
|
||||
92
Godeps/_workspace/src/github.com/anacrolix/missinggo/perf/perf.go
generated
vendored
92
Godeps/_workspace/src/github.com/anacrolix/missinggo/perf/perf.go
generated
vendored
@ -1,92 +0,0 @@
|
||||
package perf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"expvar"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/anacrolix/missinggo"
|
||||
)
|
||||
|
||||
var (
|
||||
em = missinggo.NewExpvarIndentMap("perfBuckets")
|
||||
mu sync.RWMutex
|
||||
)
|
||||
|
||||
type Timer struct {
|
||||
started time.Time
|
||||
}
|
||||
|
||||
func NewTimer() Timer {
|
||||
return Timer{time.Now()}
|
||||
}
|
||||
|
||||
func bucketExponent(d time.Duration) int {
|
||||
e := -9
|
||||
for d != 0 {
|
||||
d /= 10
|
||||
e++
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
type buckets struct {
|
||||
mu sync.Mutex
|
||||
buckets []int64
|
||||
}
|
||||
|
||||
func (me *buckets) Add(t time.Duration) {
|
||||
e := bucketExponent(t)
|
||||
me.mu.Lock()
|
||||
for e+9 >= len(me.buckets) {
|
||||
me.buckets = append(me.buckets, 0)
|
||||
}
|
||||
me.buckets[e+9]++
|
||||
me.mu.Unlock()
|
||||
}
|
||||
|
||||
func (me *buckets) String() string {
|
||||
var b bytes.Buffer
|
||||
fmt.Fprintf(&b, "{")
|
||||
first := true
|
||||
me.mu.Lock()
|
||||
for i, count := range me.buckets {
|
||||
if first {
|
||||
if count == 0 {
|
||||
continue
|
||||
}
|
||||
first = false
|
||||
} else {
|
||||
fmt.Fprintf(&b, ", ")
|
||||
}
|
||||
key := strconv.Itoa(i - 9)
|
||||
fmt.Fprintf(&b, "%q: %d", key, count)
|
||||
}
|
||||
me.mu.Unlock()
|
||||
fmt.Fprintf(&b, "}")
|
||||
return b.String()
|
||||
}
|
||||
|
||||
var _ expvar.Var = &buckets{}
|
||||
|
||||
func (t *Timer) Stop(desc string) time.Duration {
|
||||
d := time.Since(t.started)
|
||||
mu.RLock()
|
||||
_m := em.Get(desc)
|
||||
mu.RUnlock()
|
||||
if _m == nil {
|
||||
mu.Lock()
|
||||
_m = em.Get(desc)
|
||||
if _m == nil {
|
||||
_m = new(buckets)
|
||||
em.Set(desc, _m)
|
||||
}
|
||||
mu.Unlock()
|
||||
}
|
||||
m := _m.(*buckets)
|
||||
m.Add(d)
|
||||
return d
|
||||
}
|
||||
52
Godeps/_workspace/src/github.com/anacrolix/missinggo/perf/perf_test.go
generated
vendored
52
Godeps/_workspace/src/github.com/anacrolix/missinggo/perf/perf_test.go
generated
vendored
@ -1,52 +0,0 @@
|
||||
package perf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/bradfitz/iter"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestTimer(t *testing.T) {
|
||||
tr := NewTimer()
|
||||
tr.Stop("hiyo")
|
||||
tr.Stop("hiyo")
|
||||
t.Log(em.Get("hiyo").(*buckets))
|
||||
}
|
||||
|
||||
func BenchmarkStopWarm(b *testing.B) {
|
||||
tr := NewTimer()
|
||||
for _ = range iter.N(b.N) {
|
||||
tr.Stop("a")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkStopCold(b *testing.B) {
|
||||
tr := NewTimer()
|
||||
for i := range iter.N(b.N) {
|
||||
tr.Stop(strconv.FormatInt(int64(i), 10))
|
||||
}
|
||||
}
|
||||
|
||||
func TestExponent(t *testing.T) {
|
||||
for _, c := range []struct {
|
||||
e int
|
||||
d time.Duration
|
||||
}{
|
||||
{-1, 10 * time.Millisecond},
|
||||
{-2, 5 * time.Millisecond},
|
||||
{-2, time.Millisecond},
|
||||
{-3, 500 * time.Microsecond},
|
||||
{-3, 100 * time.Microsecond},
|
||||
} {
|
||||
tr := NewTimer()
|
||||
time.Sleep(c.d)
|
||||
assert.Equal(t, c.e, bucketExponent(tr.Stop(fmt.Sprintf("%d", c.e))), "%s", c.d)
|
||||
}
|
||||
assert.Equal(t, `{"-1": 1}`, em.Get("-1").String())
|
||||
assert.Equal(t, `{"-2": 2}`, em.Get("-2").String())
|
||||
assert.Equal(t, `{"-3": 2}`, em.Get("-3").String())
|
||||
}
|
||||
92
Godeps/_workspace/src/github.com/anacrolix/missinggo/pubsub/pubsub.go
generated
vendored
92
Godeps/_workspace/src/github.com/anacrolix/missinggo/pubsub/pubsub.go
generated
vendored
@ -1,92 +0,0 @@
|
||||
package pubsub
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type PubSub struct {
|
||||
mu sync.Mutex
|
||||
next chan item
|
||||
closed bool
|
||||
}
|
||||
|
||||
type item struct {
|
||||
value interface{}
|
||||
next chan item
|
||||
}
|
||||
|
||||
type Subscription struct {
|
||||
next chan item
|
||||
Values chan interface{}
|
||||
mu sync.Mutex
|
||||
closed chan struct{}
|
||||
}
|
||||
|
||||
func NewPubSub() (ret *PubSub) {
|
||||
return &PubSub{
|
||||
next: make(chan item, 1),
|
||||
}
|
||||
}
|
||||
|
||||
func (me *PubSub) Publish(v interface{}) {
|
||||
next := make(chan item, 1)
|
||||
i := item{v, next}
|
||||
me.mu.Lock()
|
||||
me.next <- i
|
||||
me.next = next
|
||||
me.mu.Unlock()
|
||||
}
|
||||
|
||||
func (me *Subscription) Close() {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
select {
|
||||
case <-me.closed:
|
||||
default:
|
||||
close(me.closed)
|
||||
}
|
||||
}
|
||||
|
||||
func (me *Subscription) runner() {
|
||||
defer close(me.Values)
|
||||
for {
|
||||
select {
|
||||
case i, ok := <-me.next:
|
||||
if !ok {
|
||||
me.Close()
|
||||
return
|
||||
}
|
||||
me.next <- i
|
||||
me.next = i.next
|
||||
select {
|
||||
case me.Values <- i.value:
|
||||
case <-me.closed:
|
||||
return
|
||||
}
|
||||
case <-me.closed:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (me *PubSub) Subscribe() (ret *Subscription) {
|
||||
ret = &Subscription{
|
||||
closed: make(chan struct{}),
|
||||
Values: make(chan interface{}),
|
||||
}
|
||||
me.mu.Lock()
|
||||
ret.next = me.next
|
||||
me.mu.Unlock()
|
||||
go ret.runner()
|
||||
return
|
||||
}
|
||||
|
||||
func (me *PubSub) Close() {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
if me.closed {
|
||||
return
|
||||
}
|
||||
close(me.next)
|
||||
me.closed = true
|
||||
}
|
||||
74
Godeps/_workspace/src/github.com/anacrolix/missinggo/pubsub/pubsub_test.go
generated
vendored
74
Godeps/_workspace/src/github.com/anacrolix/missinggo/pubsub/pubsub_test.go
generated
vendored
@ -1,74 +0,0 @@
|
||||
package pubsub
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/bradfitz/iter"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestDoubleClose(t *testing.T) {
|
||||
ps := NewPubSub()
|
||||
ps.Close()
|
||||
ps.Close()
|
||||
}
|
||||
|
||||
func testBroadcast(t testing.TB, subs, vals int) {
|
||||
ps := NewPubSub()
|
||||
var wg sync.WaitGroup
|
||||
for _ = range iter.N(subs) {
|
||||
wg.Add(1)
|
||||
s := ps.Subscribe()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
var e int
|
||||
for i := range s.Values {
|
||||
assert.Equal(t, e, i.(int))
|
||||
e++
|
||||
}
|
||||
assert.Equal(t, vals, e)
|
||||
}()
|
||||
}
|
||||
for i := range iter.N(vals) {
|
||||
ps.Publish(i)
|
||||
}
|
||||
ps.Close()
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestBroadcast(t *testing.T) {
|
||||
testBroadcast(t, 100, 10)
|
||||
}
|
||||
|
||||
func BenchmarkBroadcast(b *testing.B) {
|
||||
for _ = range iter.N(b.N) {
|
||||
testBroadcast(b, 10, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloseSubscription(t *testing.T) {
|
||||
ps := NewPubSub()
|
||||
ps.Publish(1)
|
||||
s := ps.Subscribe()
|
||||
select {
|
||||
case <-s.Values:
|
||||
t.FailNow()
|
||||
default:
|
||||
}
|
||||
ps.Publish(2)
|
||||
s2 := ps.Subscribe()
|
||||
ps.Publish(3)
|
||||
require.Equal(t, 2, <-s.Values)
|
||||
require.EqualValues(t, 3, <-s.Values)
|
||||
s.Close()
|
||||
_, ok := <-s.Values
|
||||
require.False(t, ok)
|
||||
ps.Publish(4)
|
||||
ps.Close()
|
||||
require.Equal(t, 3, <-s2.Values)
|
||||
require.Equal(t, 4, <-s2.Values)
|
||||
require.Nil(t, <-s2.Values)
|
||||
s2.Close()
|
||||
}
|
||||
46
Godeps/_workspace/src/github.com/anacrolix/missinggo/rle.go
generated
vendored
46
Godeps/_workspace/src/github.com/anacrolix/missinggo/rle.go
generated
vendored
@ -1,46 +0,0 @@
|
||||
package missinggo
|
||||
|
||||
// A RunLengthEncoder counts successive duplicate elements and emits the
|
||||
// element and the run length when the element changes or the encoder is
|
||||
// flushed.
|
||||
type RunLengthEncoder interface {
|
||||
// Add a series of identical elements to the stream.
|
||||
Append(element interface{}, count uint64)
|
||||
// Emit the current element and its count if non-zero without waiting for
|
||||
// the element to change.
|
||||
Flush()
|
||||
}
|
||||
|
||||
type runLengthEncoder struct {
|
||||
eachRun func(element interface{}, count uint64)
|
||||
element interface{}
|
||||
count uint64
|
||||
}
|
||||
|
||||
// Creates a new RunLengthEncoder. eachRun is called when an element and its
|
||||
// count is emitted, per the RunLengthEncoder interface.
|
||||
func NewRunLengthEncoder(eachRun func(element interface{}, count uint64)) RunLengthEncoder {
|
||||
return &runLengthEncoder{
|
||||
eachRun: eachRun,
|
||||
}
|
||||
}
|
||||
|
||||
func (me *runLengthEncoder) Append(element interface{}, count uint64) {
|
||||
if element == me.element {
|
||||
me.count += count
|
||||
return
|
||||
}
|
||||
if me.count != 0 {
|
||||
me.eachRun(me.element, me.count)
|
||||
}
|
||||
me.count = count
|
||||
me.element = element
|
||||
}
|
||||
|
||||
func (me *runLengthEncoder) Flush() {
|
||||
if me.count == 0 {
|
||||
return
|
||||
}
|
||||
me.eachRun(me.element, me.count)
|
||||
me.count = 0
|
||||
}
|
||||
20
Godeps/_workspace/src/github.com/anacrolix/missinggo/rle_test.go
generated
vendored
20
Godeps/_workspace/src/github.com/anacrolix/missinggo/rle_test.go
generated
vendored
@ -1,20 +0,0 @@
|
||||
package missinggo_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/anacrolix/missinggo"
|
||||
)
|
||||
|
||||
func ExampleNewRunLengthEncoder() {
|
||||
var s string
|
||||
rle := missinggo.NewRunLengthEncoder(func(e interface{}, count uint64) {
|
||||
s += fmt.Sprintf("%d%c", count, e)
|
||||
})
|
||||
for _, e := range "WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW" {
|
||||
rle.Append(e, 1)
|
||||
}
|
||||
rle.Flush()
|
||||
fmt.Println(s)
|
||||
// Output: 12W1B12W3B24W1B14W
|
||||
}
|
||||
39
Godeps/_workspace/src/github.com/anacrolix/missinggo/singleflight.go
generated
vendored
39
Godeps/_workspace/src/github.com/anacrolix/missinggo/singleflight.go
generated
vendored
@ -1,39 +0,0 @@
|
||||
package missinggo
|
||||
|
||||
import "sync"
|
||||
|
||||
type ongoing struct {
|
||||
do sync.Mutex
|
||||
users int
|
||||
}
|
||||
|
||||
type SingleFlight struct {
|
||||
mu sync.Mutex
|
||||
ongoing map[string]*ongoing
|
||||
}
|
||||
|
||||
func (me *SingleFlight) Lock(id string) {
|
||||
me.mu.Lock()
|
||||
on, ok := me.ongoing[id]
|
||||
if !ok {
|
||||
on = new(ongoing)
|
||||
if me.ongoing == nil {
|
||||
me.ongoing = make(map[string]*ongoing)
|
||||
}
|
||||
me.ongoing[id] = on
|
||||
}
|
||||
on.users++
|
||||
me.mu.Unlock()
|
||||
on.do.Lock()
|
||||
}
|
||||
|
||||
func (me *SingleFlight) Unlock(id string) {
|
||||
me.mu.Lock()
|
||||
on := me.ongoing[id]
|
||||
on.do.Unlock()
|
||||
on.users--
|
||||
if on.users == 0 {
|
||||
delete(me.ongoing, id)
|
||||
}
|
||||
me.mu.Unlock()
|
||||
}
|
||||
11
Godeps/_workspace/src/github.com/anacrolix/missinggo/sync.go
generated
vendored
11
Godeps/_workspace/src/github.com/anacrolix/missinggo/sync.go
generated
vendored
@ -1,11 +0,0 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type RWLocker interface {
|
||||
sync.Locker
|
||||
RLock()
|
||||
RUnlock()
|
||||
}
|
||||
30
Godeps/_workspace/src/github.com/anacrolix/missinggo/url.go
generated
vendored
30
Godeps/_workspace/src/github.com/anacrolix/missinggo/url.go
generated
vendored
@ -1,30 +0,0 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// Deep copies a URL.
|
||||
func CopyURL(u *url.URL) (ret *url.URL) {
|
||||
ret = new(url.URL)
|
||||
*ret = *u
|
||||
if u.User != nil {
|
||||
ret.User = new(url.Userinfo)
|
||||
*ret.User = *u.User
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Reconstructs the URL that would have produced the given Request.
|
||||
// Request.URLs are not fully populated in http.Server handlers.
|
||||
func RequestedURL(r *http.Request) (ret *url.URL) {
|
||||
ret = CopyURL(r.URL)
|
||||
ret.Host = r.Host
|
||||
if r.TLS != nil {
|
||||
ret.Scheme = "https"
|
||||
} else {
|
||||
ret.Scheme = "http"
|
||||
}
|
||||
return
|
||||
}
|
||||
51
Godeps/_workspace/src/github.com/anacrolix/missinggo/wolf.go
generated
vendored
51
Godeps/_workspace/src/github.com/anacrolix/missinggo/wolf.go
generated
vendored
@ -1,51 +0,0 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"log"
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
const debug = false
|
||||
|
||||
// A Wolf represents some event that becomes less and less interesting as it
|
||||
// occurs. Call CryHeard to see if we should pay attention this time.
|
||||
type Wolf struct {
|
||||
cries uint64
|
||||
}
|
||||
|
||||
// Returns true less and less often. Convenient for exponentially decreasing
|
||||
// the amount of noise due to errors.
|
||||
func (me *Wolf) CryHeard() bool {
|
||||
n := atomic.AddUint64(&me.cries, 1)
|
||||
return n&(n-1) == 0
|
||||
}
|
||||
|
||||
var (
|
||||
mu sync.Mutex
|
||||
wolves map[uintptr]*Wolf
|
||||
)
|
||||
|
||||
// Calls CryHeard() on a Wolf that is unique to the callers program counter.
|
||||
// i.e. every CryHeard() expression has its own Wolf.
|
||||
func CryHeard() bool {
|
||||
pc, file, line, ok := runtime.Caller(1)
|
||||
if debug {
|
||||
log.Println(pc, file, line, ok)
|
||||
}
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
mu.Lock()
|
||||
if wolves == nil {
|
||||
wolves = make(map[uintptr]*Wolf)
|
||||
}
|
||||
w, ok := wolves[pc]
|
||||
if !ok {
|
||||
w = new(Wolf)
|
||||
wolves[pc] = w
|
||||
}
|
||||
mu.Unlock()
|
||||
return w.CryHeard()
|
||||
}
|
||||
30
Godeps/_workspace/src/github.com/anacrolix/missinggo/wolf_test.go
generated
vendored
30
Godeps/_workspace/src/github.com/anacrolix/missinggo/wolf_test.go
generated
vendored
@ -1,30 +0,0 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func cryHeard() bool {
|
||||
return CryHeard()
|
||||
}
|
||||
|
||||
func TestCrySameLocation(t *testing.T) {
|
||||
require.True(t, cryHeard())
|
||||
require.True(t, cryHeard())
|
||||
require.False(t, cryHeard())
|
||||
require.True(t, cryHeard())
|
||||
require.False(t, cryHeard())
|
||||
require.False(t, cryHeard())
|
||||
require.False(t, cryHeard())
|
||||
require.True(t, cryHeard())
|
||||
}
|
||||
|
||||
func TestCryDifferentLocations(t *testing.T) {
|
||||
require.True(t, CryHeard())
|
||||
require.True(t, CryHeard())
|
||||
require.True(t, CryHeard())
|
||||
require.True(t, CryHeard())
|
||||
require.True(t, CryHeard())
|
||||
}
|
||||
BIN
Godeps/_workspace/src/github.com/anacrolix/utp/.utp.go.swp
generated
vendored
BIN
Godeps/_workspace/src/github.com/anacrolix/utp/.utp.go.swp
generated
vendored
Binary file not shown.
362
Godeps/_workspace/src/github.com/anacrolix/utp/LICENSE
generated
vendored
362
Godeps/_workspace/src/github.com/anacrolix/utp/LICENSE
generated
vendored
@ -1,362 +0,0 @@
|
||||
Mozilla Public License, version 2.0
|
||||
|
||||
1. Definitions
|
||||
|
||||
1.1. "Contributor"
|
||||
|
||||
means each individual or legal entity that creates, contributes to the
|
||||
creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
|
||||
means the combination of the Contributions of others (if any) used by a
|
||||
Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
|
||||
means Source Code Form to which the initial Contributor has attached the
|
||||
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
||||
Modifications of such Source Code Form, in each case including portions
|
||||
thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
a. that the initial Contributor has attached the notice described in
|
||||
Exhibit B to the Covered Software; or
|
||||
|
||||
b. that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the terms of
|
||||
a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
|
||||
means a work that combines Covered Software with other material, in a
|
||||
separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
|
||||
means having the right to grant, to the maximum extent possible, whether
|
||||
at the time of the initial grant or subsequently, any and all of the
|
||||
rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
|
||||
means any of the following:
|
||||
|
||||
a. any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered Software; or
|
||||
|
||||
b. any new file in Source Code Form that contains any Covered Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the License,
|
||||
by the making, using, selling, offering for sale, having made, import,
|
||||
or transfer of either its Contributions or its Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
|
||||
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
||||
General Public License, Version 2.1, the GNU Affero General Public
|
||||
License, Version 3.0, or any later versions of those licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that controls, is
|
||||
controlled by, or is under common control with You. For purposes of this
|
||||
definition, "control" means (a) the power, direct or indirect, to cause
|
||||
the direction or management of such entity, whether by contract or
|
||||
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
||||
outstanding shares or beneficial ownership of such entity.
|
||||
|
||||
|
||||
2. License Grants and Conditions
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
a. under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
||||
sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
a. for any code that a Contributor has removed from Covered Software; or
|
||||
|
||||
b. for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
c. under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights to
|
||||
grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||
Section 2.1.
|
||||
|
||||
|
||||
3. Responsibilities
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
a. such Covered Software must also be made available in Source Code Form,
|
||||
as described in Section 3.1, and You must inform recipients of the
|
||||
Executable Form how they can obtain a copy of such Source Code Form by
|
||||
reasonable means in a timely manner, at a charge no more than the cost
|
||||
of distribution to the recipient; and
|
||||
|
||||
b. You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter the
|
||||
recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty, or
|
||||
limitations of liability) contained within the Source Code Form of the
|
||||
Covered Software, except that You may alter any license notices to the
|
||||
extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this License
|
||||
with respect to some or all of the Covered Software due to statute,
|
||||
judicial order, or regulation then You must: (a) comply with the terms of
|
||||
this License to the maximum extent possible; and (b) describe the
|
||||
limitations and the code they affect. Such description must be placed in a
|
||||
text file included with all distributions of the Covered Software under
|
||||
this License. Except to the extent prohibited by statute or regulation,
|
||||
such description must be sufficiently detailed for a recipient of ordinary
|
||||
skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically if You
|
||||
fail to comply with any of its terms. However, if You become compliant,
|
||||
then the rights granted under this License from a particular Contributor
|
||||
are reinstated (a) provisionally, unless and until such Contributor
|
||||
explicitly and finally terminates Your grants, and (b) on an ongoing
|
||||
basis, if such Contributor fails to notify You of the non-compliance by
|
||||
some reasonable means prior to 60 days after You have come back into
|
||||
compliance. Moreover, Your grants from a particular Contributor are
|
||||
reinstated on an ongoing basis if such Contributor notifies You of the
|
||||
non-compliance by some reasonable means, this is the first time You have
|
||||
received notice of non-compliance with this License from such
|
||||
Contributor, and You become compliant prior to 30 days after Your receipt
|
||||
of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
||||
license agreements (excluding distributors and resellers) which have been
|
||||
validly granted by You or Your distributors under this License prior to
|
||||
termination shall survive termination.
|
||||
|
||||
6. Disclaimer of Warranty
|
||||
|
||||
Covered Software is provided under this License on an "as is" basis,
|
||||
without warranty of any kind, either expressed, implied, or statutory,
|
||||
including, without limitation, warranties that the Covered Software is free
|
||||
of defects, merchantable, fit for a particular purpose or non-infringing.
|
||||
The entire risk as to the quality and performance of the Covered Software
|
||||
is with You. Should any Covered Software prove defective in any respect,
|
||||
You (not any Contributor) assume the cost of any necessary servicing,
|
||||
repair, or correction. This disclaimer of warranty constitutes an essential
|
||||
part of this License. No use of any Covered Software is authorized under
|
||||
this License except under this disclaimer.
|
||||
|
||||
7. Limitation of Liability
|
||||
|
||||
Under no circumstances and under no legal theory, whether tort (including
|
||||
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||
distributes Covered Software as permitted above, be liable to You for any
|
||||
direct, indirect, special, incidental, or consequential damages of any
|
||||
character including, without limitation, damages for lost profits, loss of
|
||||
goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses, even if such party shall have been
|
||||
informed of the possibility of such damages. This limitation of liability
|
||||
shall not apply to liability for death or personal injury resulting from
|
||||
such party's negligence to the extent applicable law prohibits such
|
||||
limitation. Some jurisdictions do not allow the exclusion or limitation of
|
||||
incidental or consequential damages, so this exclusion and limitation may
|
||||
not apply to You.
|
||||
|
||||
8. Litigation
|
||||
|
||||
Any litigation relating to this License may be brought only in the courts
|
||||
of a jurisdiction where the defendant maintains its principal place of
|
||||
business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions. Nothing
|
||||
in this Section shall prevent a party's ability to bring cross-claims or
|
||||
counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides that
|
||||
the language of a contract shall be construed against the drafter shall not
|
||||
be used to construe this License against a Contributor.
|
||||
|
||||
|
||||
10. Versions of the License
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses If You choose to distribute Source Code Form that is
|
||||
Incompatible With Secondary Licenses under the terms of this version of
|
||||
the License, the notice described in Exhibit B of this License must be
|
||||
attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file,
|
||||
then You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a
|
||||
notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
|
||||
This Source Code Form is "Incompatible
|
||||
With Secondary Licenses", as defined by
|
||||
the Mozilla Public License, v. 2.0.
|
||||
19
Godeps/_workspace/src/github.com/anacrolix/utp/README.md
generated
vendored
19
Godeps/_workspace/src/github.com/anacrolix/utp/README.md
generated
vendored
@ -1,19 +0,0 @@
|
||||
# utp
|
||||
[](https://godoc.org/github.com/anacrolix/utp)
|
||||
[](https://drone.io/github.com/anacrolix/utp/latest)
|
||||
|
||||
Package utp implements uTP, the micro transport protocol as used with Bittorrent. It opts for simplicity and reliability over strict adherence to the (poor) spec.
|
||||
|
||||
## Supported
|
||||
|
||||
* Multiple uTP connections switched on a single PacketConn, including those initiated locally.
|
||||
* Raw access to the PacketConn for non-uTP purposes, like sharing the PacketConn with a DHT implementation.
|
||||
|
||||
## Implementation characteristics
|
||||
|
||||
* Receive window size is used to limit out of order packets received.
|
||||
* There is no MTU path discovery. The minimum size is always used.
|
||||
* A fixed 64 slot selective ack window is used in both sending and receiving.
|
||||
* All received non-ACK packets are ACKed in response.
|
||||
|
||||
Patches welcomed.
|
||||
66
Godeps/_workspace/src/github.com/anacrolix/utp/cmd/ucat/ucat.go
generated
vendored
66
Godeps/_workspace/src/github.com/anacrolix/utp/cmd/ucat/ucat.go
generated
vendored
@ -1,66 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
|
||||
"github.com/anacrolix/envpprof"
|
||||
|
||||
"github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/anacrolix/utp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
defer envpprof.Stop()
|
||||
listen := flag.Bool("l", false, "listen")
|
||||
port := flag.Int("p", 0, "port to listen on")
|
||||
flag.Parse()
|
||||
var (
|
||||
conn net.Conn
|
||||
err error
|
||||
)
|
||||
if *listen {
|
||||
s, err := utp.NewSocket("udp", fmt.Sprintf(":%d", *port))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer s.Close()
|
||||
conn, err = s.Accept()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
conn, err = utp.Dial(net.JoinHostPort(flag.Arg(0), flag.Arg(1)))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
defer conn.Close()
|
||||
go func() {
|
||||
sig := make(chan os.Signal, 1)
|
||||
signal.Notify(sig, os.Interrupt)
|
||||
<-sig
|
||||
conn.Close()
|
||||
}()
|
||||
writerDone := make(chan struct{})
|
||||
go func() {
|
||||
defer close(writerDone)
|
||||
written, err := io.Copy(conn, os.Stdin)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
log.Fatalf("error after writing %d bytes: %s", written, err)
|
||||
}
|
||||
log.Printf("wrote %d bytes", written)
|
||||
conn.Close()
|
||||
}()
|
||||
n, err := io.Copy(os.Stdout, conn)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Printf("received %d bytes", n)
|
||||
// <-writerDone
|
||||
}
|
||||
61
Godeps/_workspace/src/github.com/anacrolix/utp/pingpong
generated
vendored
61
Godeps/_workspace/src/github.com/anacrolix/utp/pingpong
generated
vendored
@ -1,61 +0,0 @@
|
||||
# This shell script uses nc-like executables to send and receive the file at
|
||||
# $1, and prints the checksums. 3 such executables are
|
||||
# github.com/h2so5/utp/ucat, invoked as h2so5-ucat, libutp-ucat, which is the
|
||||
# ucat or ucat-static generated by the C++ libutp, and lastly, ./cmd/ucat from
|
||||
# this repository. A good file in my experiments is no more than a few 100MB,
|
||||
# or you'll be waiting a while.
|
||||
|
||||
set -eu
|
||||
# set -x
|
||||
|
||||
# Passed to invocations of godo for package ./cmd/ucat.
|
||||
#GODOFLAGS=-race
|
||||
|
||||
#export GO_UTP_PACKET_DROP=0.1
|
||||
export GOPPROF=
|
||||
|
||||
# Invokes the implementation to test against. If there's an arg, then it's
|
||||
# expected to listen.
|
||||
function other_ucat() {
|
||||
if [[ $# != 0 ]]; then
|
||||
libutp-ucat -l -p 4000
|
||||
# h2so5-ucat -l :4000
|
||||
else
|
||||
libutp-ucat localhost 4000
|
||||
# h2so5-ucat localhost:4000
|
||||
fi
|
||||
}
|
||||
|
||||
# Check what the correct result is.
|
||||
md5 "$1"
|
||||
|
||||
rate() {
|
||||
pv -a -W -b
|
||||
}
|
||||
|
||||
echo 'utp->other_ucat'
|
||||
# Send from this uTP implementation to another client.
|
||||
other_ucat -l | rate | md5 &
|
||||
# sleep 1
|
||||
godo ${GODOFLAGS-} ./cmd/ucat localhost 4000 < "$1"
|
||||
wait
|
||||
|
||||
echo 'other_ucat->utp'
|
||||
# Send from the other implementation, to this one.
|
||||
GO_UTP_LOGGING=0 GOPPROF= godo ${GODOFLAGS-} ./cmd/ucat -l -p 4000 | rate | md5 &
|
||||
# Never receive from h2so5's ucat without a small sleep first. Don't know why.
|
||||
# sleep 1
|
||||
other_ucat < "$1"
|
||||
wait
|
||||
|
||||
echo 'libutp->libutp'
|
||||
libutp-ucat -l -p 4000 | rate | md5 &
|
||||
libutp-ucat localhost 4000 < "$1"
|
||||
wait
|
||||
|
||||
echo 'utp->utp'
|
||||
godo ./cmd/ucat -l -p 4000 | rate | md5 &
|
||||
godo ./cmd/ucat localhost 4000 < "$1"
|
||||
wait
|
||||
|
||||
# Now check the hashes match (yes you).
|
||||
1461
Godeps/_workspace/src/github.com/anacrolix/utp/utp.go
generated
vendored
1461
Godeps/_workspace/src/github.com/anacrolix/utp/utp.go
generated
vendored
File diff suppressed because it is too large
Load Diff
411
Godeps/_workspace/src/github.com/anacrolix/utp/utp_test.go
generated
vendored
411
Godeps/_workspace/src/github.com/anacrolix/utp/utp_test.go
generated
vendored
@ -1,411 +0,0 @@
|
||||
package utp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"runtime"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
_ "github.com/anacrolix/envpprof"
|
||||
"github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/anacrolix/missinggo"
|
||||
"github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/bradfitz/iter"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func init() {
|
||||
log.SetFlags(log.Flags() | log.Lshortfile)
|
||||
}
|
||||
|
||||
func TestUTPPingPong(t *testing.T) {
|
||||
defer goroutineLeakCheck(t)()
|
||||
s, err := NewSocket("udp", "localhost:0")
|
||||
require.NoError(t, err)
|
||||
defer s.Close()
|
||||
pingerClosed := make(chan struct{})
|
||||
go func() {
|
||||
defer close(pingerClosed)
|
||||
b, err := Dial(s.Addr().String())
|
||||
require.NoError(t, err)
|
||||
defer b.Close()
|
||||
n, err := b.Write([]byte("ping"))
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 4, n)
|
||||
buf := make([]byte, 4)
|
||||
b.Read(buf)
|
||||
require.EqualValues(t, "pong", buf)
|
||||
log.Printf("got pong")
|
||||
}()
|
||||
a, err := s.Accept()
|
||||
require.NoError(t, err)
|
||||
defer a.Close()
|
||||
log.Printf("accepted %s", a)
|
||||
buf := make([]byte, 42)
|
||||
n, err := a.Read(buf)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, "ping", buf[:n])
|
||||
log.Print("got ping")
|
||||
n, err = a.Write([]byte("pong"))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 4, n)
|
||||
log.Print("waiting for pinger to close")
|
||||
<-pingerClosed
|
||||
}
|
||||
|
||||
func goroutineLeakCheck(t testing.TB) func() {
|
||||
if !testing.Verbose() {
|
||||
return func() {}
|
||||
}
|
||||
numStart := runtime.NumGoroutine()
|
||||
return func() {
|
||||
var numNow int
|
||||
for _ = range iter.N(1) {
|
||||
numNow = runtime.NumGoroutine()
|
||||
if numNow == numStart {
|
||||
return
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
// I'd print stacks, or treat this as fatal, but I think
|
||||
// runtime.NumGoroutine is including system routines for which we are
|
||||
// not provided the stacks, and are spawned unpredictably.
|
||||
t.Logf("have %d goroutines, started with %d", numNow, numStart)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDialTimeout(t *testing.T) {
|
||||
defer goroutineLeakCheck(t)()
|
||||
s, _ := NewSocket("udp", "localhost:0")
|
||||
defer s.Close()
|
||||
conn, err := DialTimeout(s.Addr().String(), 10*time.Millisecond)
|
||||
if err == nil {
|
||||
conn.Close()
|
||||
t.Fatal("expected timeout")
|
||||
}
|
||||
t.Log(err)
|
||||
}
|
||||
|
||||
func TestMinMaxHeaderType(t *testing.T) {
|
||||
require.Equal(t, stSyn, stMax)
|
||||
}
|
||||
|
||||
func TestUTPRawConn(t *testing.T) {
|
||||
l, err := NewSocket("udp", "")
|
||||
require.NoError(t, err)
|
||||
defer l.Close()
|
||||
go func() {
|
||||
for {
|
||||
_, err := l.Accept()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
// Connect a UTP peer to see if the RawConn will still work.
|
||||
log.Print("dialing")
|
||||
utpPeer := func() net.Conn {
|
||||
s, _ := NewSocket("udp", "")
|
||||
defer s.Close()
|
||||
ret, err := s.Dial(fmt.Sprintf("localhost:%d", missinggo.AddrPort(l.Addr())))
|
||||
require.NoError(t, err)
|
||||
return ret
|
||||
}()
|
||||
log.Print("dial returned")
|
||||
if err != nil {
|
||||
t.Fatalf("error dialing utp listener: %s", err)
|
||||
}
|
||||
defer utpPeer.Close()
|
||||
peer, err := net.ListenPacket("udp", ":0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer peer.Close()
|
||||
|
||||
msgsReceived := 0
|
||||
const N = 5000 // How many messages to send.
|
||||
readerStopped := make(chan struct{})
|
||||
// The reader goroutine.
|
||||
go func() {
|
||||
defer close(readerStopped)
|
||||
b := make([]byte, 500)
|
||||
for i := 0; i < N; i++ {
|
||||
n, _, err := l.ReadFrom(b)
|
||||
if err != nil {
|
||||
t.Fatalf("error reading from raw conn: %s", err)
|
||||
}
|
||||
msgsReceived++
|
||||
var d int
|
||||
fmt.Sscan(string(b[:n]), &d)
|
||||
if d != i {
|
||||
log.Printf("got wrong number: expected %d, got %d", i, d)
|
||||
}
|
||||
}
|
||||
}()
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("localhost:%d", missinggo.AddrPort(l.Addr())))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i := 0; i < N; i++ {
|
||||
_, err := peer.WriteTo([]byte(fmt.Sprintf("%d", i)), udpAddr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
time.Sleep(time.Microsecond)
|
||||
}
|
||||
select {
|
||||
case <-readerStopped:
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("reader timed out")
|
||||
}
|
||||
if msgsReceived != N {
|
||||
t.Fatalf("messages received: %d", msgsReceived)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnReadDeadline(t *testing.T) {
|
||||
ls, _ := NewSocket("udp", "localhost:0")
|
||||
ds, _ := NewSocket("udp", "localhost:0")
|
||||
dcReadErr := make(chan error)
|
||||
go func() {
|
||||
c, _ := ds.Dial(ls.Addr().String())
|
||||
defer c.Close()
|
||||
_, err := c.Read(nil)
|
||||
dcReadErr <- err
|
||||
}()
|
||||
c, _ := ls.Accept()
|
||||
dl := time.Now().Add(time.Millisecond)
|
||||
c.SetReadDeadline(dl)
|
||||
_, err := c.Read(nil)
|
||||
require.Equal(t, errTimeout, err)
|
||||
// The deadline has passed.
|
||||
if !time.Now().After(dl) {
|
||||
t.FailNow()
|
||||
}
|
||||
// Returns timeout on subsequent read.
|
||||
_, err = c.Read(nil)
|
||||
require.Equal(t, errTimeout, err)
|
||||
// Disable the deadline.
|
||||
c.SetReadDeadline(time.Time{})
|
||||
readReturned := make(chan struct{})
|
||||
go func() {
|
||||
c.Read(nil)
|
||||
close(readReturned)
|
||||
}()
|
||||
select {
|
||||
case <-readReturned:
|
||||
// Read returned but shouldn't have.
|
||||
t.FailNow()
|
||||
case <-time.After(time.Millisecond):
|
||||
}
|
||||
c.Close()
|
||||
select {
|
||||
case <-readReturned:
|
||||
case <-time.After(time.Millisecond):
|
||||
t.Fatal("read should return after Conn is closed")
|
||||
}
|
||||
if err := <-dcReadErr; err != io.EOF {
|
||||
t.Fatalf("dial conn read returned %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func connectSelfLots(n int, t testing.TB) {
|
||||
defer goroutineLeakCheck(t)()
|
||||
s, err := NewSocket("udp", "localhost:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
go func() {
|
||||
for _ = range iter.N(n) {
|
||||
c, err := s.Accept()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
}
|
||||
}()
|
||||
dialErr := make(chan error)
|
||||
connCh := make(chan net.Conn)
|
||||
dialSema := make(chan struct{}, backlog)
|
||||
for _ = range iter.N(n) {
|
||||
go func() {
|
||||
dialSema <- struct{}{}
|
||||
c, err := s.Dial(s.Addr().String())
|
||||
<-dialSema
|
||||
if err != nil {
|
||||
dialErr <- err
|
||||
return
|
||||
}
|
||||
connCh <- c
|
||||
}()
|
||||
}
|
||||
conns := make([]net.Conn, 0, n)
|
||||
for _ = range iter.N(n) {
|
||||
select {
|
||||
case c := <-connCh:
|
||||
conns = append(conns, c)
|
||||
case err := <-dialErr:
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
for _, c := range conns {
|
||||
if c != nil {
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
s.mu.Lock()
|
||||
for len(s.conns) != 0 {
|
||||
// log.Print(len(s.conns))
|
||||
s.event.Wait()
|
||||
}
|
||||
s.mu.Unlock()
|
||||
s.Close()
|
||||
}
|
||||
|
||||
// Connect to ourself heaps.
|
||||
func TestConnectSelf(t *testing.T) {
|
||||
// A rough guess says that at worst, I can only have 0x10000/3 connections
|
||||
// to the same socket, due to fragmentation in the assigned connection
|
||||
// IDs.
|
||||
connectSelfLots(0x1000, t)
|
||||
}
|
||||
|
||||
func BenchmarkConnectSelf(b *testing.B) {
|
||||
for _ = range iter.N(b.N) {
|
||||
connectSelfLots(2, b)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNewCloseSocket(b *testing.B) {
|
||||
for _ = range iter.N(b.N) {
|
||||
s, err := NewSocket("udp", "localhost:0")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
err = s.Close()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRejectDialBacklogFilled(t *testing.T) {
|
||||
s, err := NewSocket("udp", "localhost:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
errChan := make(chan error, 1)
|
||||
dial := func() {
|
||||
_, err := s.Dial(s.Addr().String())
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
}
|
||||
}
|
||||
// Fill the backlog.
|
||||
for _ = range iter.N(backlog + 1) {
|
||||
go dial()
|
||||
}
|
||||
s.mu.Lock()
|
||||
for len(s.backlog) < backlog {
|
||||
s.event.Wait()
|
||||
}
|
||||
s.mu.Unlock()
|
||||
select {
|
||||
case <-errChan:
|
||||
t.FailNow()
|
||||
default:
|
||||
}
|
||||
// One more connection should cause a dial attempt to get reset.
|
||||
go dial()
|
||||
err = <-errChan
|
||||
if err.Error() != "peer reset" {
|
||||
t.FailNow()
|
||||
}
|
||||
s.Close()
|
||||
}
|
||||
|
||||
// Make sure that we can reset AfterFunc timers, so we don't have to create
|
||||
// brand new ones everytime they fire. Specifically for the Conn resend timer.
|
||||
func TestResetAfterFuncTimer(t *testing.T) {
|
||||
fired := make(chan struct{})
|
||||
timer := time.AfterFunc(time.Millisecond, func() {
|
||||
fired <- struct{}{}
|
||||
})
|
||||
<-fired
|
||||
if timer.Reset(time.Millisecond) {
|
||||
// The timer should have expired
|
||||
t.FailNow()
|
||||
}
|
||||
<-fired
|
||||
}
|
||||
|
||||
func connPair() (initer, accepted net.Conn) {
|
||||
s, err := NewSocket("udp", "localhost:0")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer s.Close()
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
var err error
|
||||
initer, err = Dial(s.Addr().String())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
accepted, err = s.Accept()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
wg.Wait()
|
||||
return
|
||||
}
|
||||
|
||||
// Check that peer sending FIN doesn't cause unread data to be dropped in a
|
||||
// receiver.
|
||||
func TestReadFinishedConn(t *testing.T) {
|
||||
a, b := connPair()
|
||||
defer a.Close()
|
||||
defer b.Close()
|
||||
mu.Lock()
|
||||
originalAPDC := artificialPacketDropChance
|
||||
artificialPacketDropChance = 1
|
||||
mu.Unlock()
|
||||
n, err := a.Write([]byte("hello"))
|
||||
require.Equal(t, 5, n)
|
||||
require.NoError(t, err)
|
||||
n, err = a.Write([]byte("world"))
|
||||
require.Equal(t, 5, n)
|
||||
require.NoError(t, err)
|
||||
mu.Lock()
|
||||
artificialPacketDropChance = originalAPDC
|
||||
mu.Unlock()
|
||||
a.Close()
|
||||
all, err := ioutil.ReadAll(b)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, "helloworld", all)
|
||||
}
|
||||
|
||||
func TestCloseDetachesQuickly(t *testing.T) {
|
||||
s, _ := NewSocket("udp", "localhost:0")
|
||||
defer s.Close()
|
||||
go func() {
|
||||
a, _ := s.Dial(s.Addr().String())
|
||||
log.Print("close a")
|
||||
a.Close()
|
||||
log.Print("closed a")
|
||||
}()
|
||||
b, _ := s.Accept()
|
||||
b.Close()
|
||||
s.mu.Lock()
|
||||
for len(s.conns) != 0 {
|
||||
log.Print(len(s.conns))
|
||||
s.event.Wait()
|
||||
}
|
||||
s.mu.Unlock()
|
||||
}
|
||||
1
Godeps/_workspace/src/github.com/bradfitz/iter/.gitignore
generated
vendored
1
Godeps/_workspace/src/github.com/bradfitz/iter/.gitignore
generated
vendored
@ -1 +0,0 @@
|
||||
*~
|
||||
1
Godeps/_workspace/src/github.com/bradfitz/iter/README.txt
generated
vendored
1
Godeps/_workspace/src/github.com/bradfitz/iter/README.txt
generated
vendored
@ -1 +0,0 @@
|
||||
See http://godoc.org/github.com/bradfitz/iter
|
||||
17
Godeps/_workspace/src/github.com/bradfitz/iter/iter.go
generated
vendored
17
Godeps/_workspace/src/github.com/bradfitz/iter/iter.go
generated
vendored
@ -1,17 +0,0 @@
|
||||
// Package iter provides a syntantically different way to iterate over integers. That's it.
|
||||
package iter
|
||||
|
||||
// N returns a slice of n 0-sized elements, suitable for ranging over.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// for i := range iter.N(10) {
|
||||
// fmt.Println(i)
|
||||
// }
|
||||
//
|
||||
// ... will print 0 to 9, inclusive.
|
||||
//
|
||||
// It does not cause any allocations.
|
||||
func N(n int) []struct{} {
|
||||
return make([]struct{}, n)
|
||||
}
|
||||
29
Godeps/_workspace/src/github.com/bradfitz/iter/iter_test.go
generated
vendored
29
Godeps/_workspace/src/github.com/bradfitz/iter/iter_test.go
generated
vendored
@ -1,29 +0,0 @@
|
||||
package iter_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/bradfitz/iter"
|
||||
)
|
||||
|
||||
func ExampleN() {
|
||||
for i := range iter.N(4) {
|
||||
fmt.Println(i)
|
||||
}
|
||||
// Output:
|
||||
// 0
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
|
||||
func TestAllocs(t *testing.T) {
|
||||
var x []struct{}
|
||||
allocs := testing.AllocsPerRun(500, func() {
|
||||
x = iter.N(1e9)
|
||||
})
|
||||
if allocs > 0.1 {
|
||||
t.Errorf("allocs = %v", allocs)
|
||||
}
|
||||
}
|
||||
13
Godeps/_workspace/src/github.com/jbenet/go-base58/LICENSE
generated
vendored
13
Godeps/_workspace/src/github.com/jbenet/go-base58/LICENSE
generated
vendored
@ -1,13 +0,0 @@
|
||||
Copyright (c) 2013 Conformal Systems LLC.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
66
Godeps/_workspace/src/github.com/jbenet/go-base58/README.md
generated
vendored
66
Godeps/_workspace/src/github.com/jbenet/go-base58/README.md
generated
vendored
@ -1,66 +0,0 @@
|
||||
# go-base58
|
||||
|
||||
I extracted this package from https://github.com/conformal/btcutil to provide a simple base58 package that
|
||||
- defaults to base58-check (btc)
|
||||
- and allows using different alphabets.
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
b58 "github.com/jbenet/go-base58"
|
||||
)
|
||||
|
||||
func main() {
|
||||
buf := []byte{255, 254, 253, 252}
|
||||
fmt.Printf("buffer: %v\n", buf)
|
||||
|
||||
str := b58.Encode(buf)
|
||||
fmt.Printf("encoded: %s\n", str)
|
||||
|
||||
buf2 := b58.Decode(str)
|
||||
fmt.Printf("decoded: %v\n", buf2)
|
||||
}
|
||||
```
|
||||
|
||||
### Another alphabet
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
b58 "github.com/jbenet/go-base58"
|
||||
)
|
||||
|
||||
const BogusAlphabet = "ZYXWVUTSRQPNMLKJHGFEDCBAzyxwvutsrqponmkjihgfedcba987654321"
|
||||
|
||||
|
||||
func encdec(alphabet string) {
|
||||
fmt.Printf("using: %s\n", alphabet)
|
||||
|
||||
buf := []byte{255, 254, 253, 252}
|
||||
fmt.Printf("buffer: %v\n", buf)
|
||||
|
||||
str := b58.EncodeAlphabet(buf, alphabet)
|
||||
fmt.Printf("encoded: %s\n", str)
|
||||
|
||||
buf2 := b58.DecodeAlphabet(str, alphabet)
|
||||
fmt.Printf("decoded: %v\n\n", buf2)
|
||||
}
|
||||
|
||||
|
||||
func main() {
|
||||
encdec(b58.BTCAlphabet)
|
||||
encdec(b58.FlickrAlphabet)
|
||||
encdec(BogusAlphabet)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Package base58 (and the original btcutil) are licensed under the ISC License.
|
||||
90
Godeps/_workspace/src/github.com/jbenet/go-base58/base58.go
generated
vendored
90
Godeps/_workspace/src/github.com/jbenet/go-base58/base58.go
generated
vendored
@ -1,90 +0,0 @@
|
||||
// Copyright (c) 2013-2014 Conformal Systems LLC.
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
// Modified by Juan Benet (juan@benet.ai)
|
||||
|
||||
package base58
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// alphabet is the modified base58 alphabet used by Bitcoin.
|
||||
const BTCAlphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
||||
const FlickrAlphabet = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
|
||||
|
||||
var bigRadix = big.NewInt(58)
|
||||
var bigZero = big.NewInt(0)
|
||||
|
||||
// Decode decodes a modified base58 string to a byte slice, using BTCAlphabet
|
||||
func Decode(b string) []byte {
|
||||
return DecodeAlphabet(b, BTCAlphabet)
|
||||
}
|
||||
|
||||
// Encode encodes a byte slice to a modified base58 string, using BTCAlphabet
|
||||
func Encode(b []byte) string {
|
||||
return EncodeAlphabet(b, BTCAlphabet)
|
||||
}
|
||||
|
||||
// DecodeAlphabet decodes a modified base58 string to a byte slice, using alphabet.
|
||||
func DecodeAlphabet(b, alphabet string) []byte {
|
||||
answer := big.NewInt(0)
|
||||
j := big.NewInt(1)
|
||||
|
||||
for i := len(b) - 1; i >= 0; i-- {
|
||||
tmp := strings.IndexAny(alphabet, string(b[i]))
|
||||
if tmp == -1 {
|
||||
return []byte("")
|
||||
}
|
||||
idx := big.NewInt(int64(tmp))
|
||||
tmp1 := big.NewInt(0)
|
||||
tmp1.Mul(j, idx)
|
||||
|
||||
answer.Add(answer, tmp1)
|
||||
j.Mul(j, bigRadix)
|
||||
}
|
||||
|
||||
tmpval := answer.Bytes()
|
||||
|
||||
var numZeros int
|
||||
for numZeros = 0; numZeros < len(b); numZeros++ {
|
||||
if b[numZeros] != alphabet[0] {
|
||||
break
|
||||
}
|
||||
}
|
||||
flen := numZeros + len(tmpval)
|
||||
val := make([]byte, flen, flen)
|
||||
copy(val[numZeros:], tmpval)
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
// Encode encodes a byte slice to a modified base58 string, using alphabet
|
||||
func EncodeAlphabet(b []byte, alphabet string) string {
|
||||
x := new(big.Int)
|
||||
x.SetBytes(b)
|
||||
|
||||
answer := make([]byte, 0, len(b)*136/100)
|
||||
for x.Cmp(bigZero) > 0 {
|
||||
mod := new(big.Int)
|
||||
x.DivMod(x, bigRadix, mod)
|
||||
answer = append(answer, alphabet[mod.Int64()])
|
||||
}
|
||||
|
||||
// leading zero bytes
|
||||
for _, i := range b {
|
||||
if i != 0 {
|
||||
break
|
||||
}
|
||||
answer = append(answer, alphabet[0])
|
||||
}
|
||||
|
||||
// reverse
|
||||
alen := len(answer)
|
||||
for i := 0; i < alen/2; i++ {
|
||||
answer[i], answer[alen-1-i] = answer[alen-1-i], answer[i]
|
||||
}
|
||||
|
||||
return string(answer)
|
||||
}
|
||||
96
Godeps/_workspace/src/github.com/jbenet/go-base58/base58_test.go
generated
vendored
96
Godeps/_workspace/src/github.com/jbenet/go-base58/base58_test.go
generated
vendored
@ -1,96 +0,0 @@
|
||||
// Copyright (c) 2013-2014 Conformal Systems LLC.
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package base58
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var stringTests = []struct {
|
||||
in string
|
||||
out string
|
||||
}{
|
||||
{"", ""},
|
||||
{" ", "Z"},
|
||||
{"-", "n"},
|
||||
{"0", "q"},
|
||||
{"1", "r"},
|
||||
{"-1", "4SU"},
|
||||
{"11", "4k8"},
|
||||
{"abc", "ZiCa"},
|
||||
{"1234598760", "3mJr7AoUXx2Wqd"},
|
||||
{"abcdefghijklmnopqrstuvwxyz", "3yxU3u1igY8WkgtjK92fbJQCd4BZiiT1v25f"},
|
||||
{"00000000000000000000000000000000000000000000000000000000000000", "3sN2THZeE9Eh9eYrwkvZqNstbHGvrxSAM7gXUXvyFQP8XvQLUqNCS27icwUeDT7ckHm4FUHM2mTVh1vbLmk7y"},
|
||||
}
|
||||
|
||||
var invalidStringTests = []struct {
|
||||
in string
|
||||
out string
|
||||
}{
|
||||
{"0", ""},
|
||||
{"O", ""},
|
||||
{"I", ""},
|
||||
{"l", ""},
|
||||
{"3mJr0", ""},
|
||||
{"O3yxU", ""},
|
||||
{"3sNI", ""},
|
||||
{"4kl8", ""},
|
||||
{"0OIl", ""},
|
||||
{"!@#$%^&*()-_=+~`", ""},
|
||||
}
|
||||
|
||||
var hexTests = []struct {
|
||||
in string
|
||||
out string
|
||||
}{
|
||||
{"61", "2g"},
|
||||
{"626262", "a3gV"},
|
||||
{"636363", "aPEr"},
|
||||
{"73696d706c792061206c6f6e6720737472696e67", "2cFupjhnEsSn59qHXstmK2ffpLv2"},
|
||||
{"00eb15231dfceb60925886b67d065299925915aeb172c06647", "1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L"},
|
||||
{"516b6fcd0f", "ABnLTmg"},
|
||||
{"bf4f89001e670274dd", "3SEo3LWLoPntC"},
|
||||
{"572e4794", "3EFU7m"},
|
||||
{"ecac89cad93923c02321", "EJDM8drfXA6uyA"},
|
||||
{"10c8511e", "Rt5zm"},
|
||||
{"00000000000000000000", "1111111111"},
|
||||
}
|
||||
|
||||
func TestBase58(t *testing.T) {
|
||||
// Base58Encode tests
|
||||
for x, test := range stringTests {
|
||||
tmp := []byte(test.in)
|
||||
if res := Encode(tmp); res != test.out {
|
||||
t.Errorf("Base58Encode test #%d failed: got: %s want: %s",
|
||||
x, res, test.out)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Base58Decode tests
|
||||
for x, test := range hexTests {
|
||||
b, err := hex.DecodeString(test.in)
|
||||
if err != nil {
|
||||
t.Errorf("hex.DecodeString failed failed #%d: got: %s", x, test.in)
|
||||
continue
|
||||
}
|
||||
if res := Decode(test.out); bytes.Equal(res, b) != true {
|
||||
t.Errorf("Base58Decode test #%d failed: got: %q want: %q",
|
||||
x, res, test.in)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Base58Decode with invalid input
|
||||
for x, test := range invalidStringTests {
|
||||
if res := Decode(test.in); string(res) != test.out {
|
||||
t.Errorf("Base58Decode invalidString test #%d failed: got: %q want: %q",
|
||||
x, res, test.out)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
20
Godeps/_workspace/src/github.com/jbenet/go-base58/doc.go
generated
vendored
20
Godeps/_workspace/src/github.com/jbenet/go-base58/doc.go
generated
vendored
@ -1,20 +0,0 @@
|
||||
// Copyright (c) 2013-2014 Conformal Systems LLC.
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
Package base58 provides base58-check encoding.
|
||||
The alphabet is modifyiable for
|
||||
|
||||
Base58 Usage
|
||||
|
||||
To decode a base58 string:
|
||||
|
||||
rawData := base58.Base58Decode(encodedData)
|
||||
|
||||
Similarly, to encode the same data:
|
||||
|
||||
encodedData := base58.Base58Encode(rawData)
|
||||
|
||||
*/
|
||||
package base58
|
||||
9
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/.travis.yml
generated
vendored
9
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/.travis.yml
generated
vendored
@ -1,9 +0,0 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.3
|
||||
- release
|
||||
- tip
|
||||
|
||||
script:
|
||||
- go test -race -cpu=5 -v ./...
|
||||
21
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/LICENSE
generated
vendored
21
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/LICENSE
generated
vendored
@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Juan Batiz-Benet
|
||||
|
||||
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.
|
||||
58
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/README.md
generated
vendored
58
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/README.md
generated
vendored
@ -1,58 +0,0 @@
|
||||
# go-multiaddr
|
||||
|
||||
[multiaddr](https://github.com/jbenet/multiaddr) implementation in Go.
|
||||
|
||||
## Example
|
||||
|
||||
### Simple
|
||||
|
||||
```go
|
||||
import ma "github.com/jbenet/go-multiaddr"
|
||||
|
||||
// construct from a string (err signals parse failure)
|
||||
m1, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/1234")
|
||||
|
||||
// construct from bytes (err signals parse failure)
|
||||
m2, err := ma.NewMultiaddrBytes(m1.Bytes())
|
||||
|
||||
// true
|
||||
strings.Equal(m1.String(), "/ip4/127.0.0.1/udp/1234")
|
||||
strings.Equal(m1.String(), m2.String())
|
||||
bytes.Equal(m1.Bytes(), m2.Bytes())
|
||||
m1.Equal(m2)
|
||||
m2.Equal(m1)
|
||||
```
|
||||
|
||||
### Protocols
|
||||
|
||||
```go
|
||||
// get the multiaddr protocol description objects
|
||||
addr.Protocols()
|
||||
// []Protocol{
|
||||
// Protocol{ Code: 4, Name: 'ip4', Size: 32},
|
||||
// Protocol{ Code: 17, Name: 'udp', Size: 16},
|
||||
// }
|
||||
```
|
||||
|
||||
### En/decapsulate
|
||||
|
||||
```go
|
||||
m.Encapsulate(ma.NewMultiaddr("/sctp/5678"))
|
||||
// <Multiaddr /ip4/127.0.0.1/udp/1234/sctp/5678>
|
||||
m.Decapsulate(ma.NewMultiaddr("/udp")) // up to + inc last occurrence of subaddr
|
||||
// <Multiaddr /ip4/127.0.0.1>
|
||||
```
|
||||
|
||||
### Tunneling
|
||||
|
||||
Multiaddr allows expressing tunnels very nicely.
|
||||
|
||||
```js
|
||||
printer, _ := ma.NewMultiaddr("/ip4/192.168.0.13/tcp/80")
|
||||
proxy, _ := ma.NewMultiaddr("/ip4/10.20.30.40/tcp/443")
|
||||
printerOverProxy := proxy.Encapsulate(printer)
|
||||
// /ip4/10.20.30.40/tcp/443/ip4/192.168.0.13/tcp/80
|
||||
|
||||
proxyAgain := printerOverProxy.Decapsulate(printer)
|
||||
// /ip4/10.20.30.40/tcp/443
|
||||
```
|
||||
209
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/codec.go
generated
vendored
209
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/codec.go
generated
vendored
@ -1,209 +0,0 @@
|
||||
package multiaddr
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
mh "github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/jbenet/go-multihash"
|
||||
)
|
||||
|
||||
func stringToBytes(s string) ([]byte, error) {
|
||||
|
||||
// consume trailing slashes
|
||||
s = strings.TrimRight(s, "/")
|
||||
|
||||
b := []byte{}
|
||||
sp := strings.Split(s, "/")
|
||||
|
||||
if sp[0] != "" {
|
||||
return nil, fmt.Errorf("invalid multiaddr, must begin with /")
|
||||
}
|
||||
|
||||
// consume first empty elem
|
||||
sp = sp[1:]
|
||||
|
||||
for len(sp) > 0 {
|
||||
p := ProtocolWithName(sp[0])
|
||||
if p.Code == 0 {
|
||||
return nil, fmt.Errorf("no protocol with name %s", sp[0])
|
||||
}
|
||||
b = append(b, CodeToVarint(p.Code)...)
|
||||
sp = sp[1:]
|
||||
|
||||
if p.Size == 0 { // no length.
|
||||
continue
|
||||
}
|
||||
|
||||
if len(sp) < 1 {
|
||||
return nil, fmt.Errorf("protocol requires address, none given: %s", p.Name)
|
||||
}
|
||||
a, err := addressStringToBytes(p, sp[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse %s: %s %s", p.Name, sp[0], err)
|
||||
}
|
||||
b = append(b, a...)
|
||||
sp = sp[1:]
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func bytesToString(b []byte) (ret string, err error) {
|
||||
// panic handler, in case we try accessing bytes incorrectly.
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
ret = ""
|
||||
switch e := e.(type) {
|
||||
case error:
|
||||
err = e
|
||||
case string:
|
||||
err = errors.New(e)
|
||||
default:
|
||||
err = fmt.Errorf("%v", e)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
s := ""
|
||||
|
||||
for len(b) > 0 {
|
||||
|
||||
code, n := ReadVarintCode(b)
|
||||
b = b[n:]
|
||||
p := ProtocolWithCode(code)
|
||||
if p.Code == 0 {
|
||||
return "", fmt.Errorf("no protocol with code %d", code)
|
||||
}
|
||||
s += "/" + p.Name
|
||||
|
||||
if p.Size == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
size := sizeForAddr(p, b)
|
||||
a, err := addressBytesToString(p, b[:size])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(a) > 0 {
|
||||
s += "/" + a
|
||||
}
|
||||
b = b[size:]
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func sizeForAddr(p Protocol, b []byte) int {
|
||||
switch {
|
||||
case p.Size > 0:
|
||||
return (p.Size / 8)
|
||||
case p.Size == 0:
|
||||
return 0
|
||||
default:
|
||||
size, n := ReadVarintCode(b)
|
||||
return size + n
|
||||
}
|
||||
}
|
||||
|
||||
func bytesSplit(b []byte) (ret [][]byte, err error) {
|
||||
// panic handler, in case we try accessing bytes incorrectly.
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
ret = [][]byte{}
|
||||
err = e.(error)
|
||||
}
|
||||
}()
|
||||
|
||||
ret = [][]byte{}
|
||||
for len(b) > 0 {
|
||||
code, n := ReadVarintCode(b)
|
||||
p := ProtocolWithCode(code)
|
||||
if p.Code == 0 {
|
||||
return [][]byte{}, fmt.Errorf("no protocol with code %d", b[0])
|
||||
}
|
||||
|
||||
size := sizeForAddr(p, b[n:])
|
||||
length := n + size
|
||||
ret = append(ret, b[:length])
|
||||
b = b[length:]
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func addressStringToBytes(p Protocol, s string) ([]byte, error) {
|
||||
switch p.Code {
|
||||
|
||||
case P_IP4: // ipv4
|
||||
i := net.ParseIP(s).To4()
|
||||
if i == nil {
|
||||
return nil, fmt.Errorf("failed to parse ip4 addr: %s", s)
|
||||
}
|
||||
return i, nil
|
||||
|
||||
case P_IP6: // ipv6
|
||||
i := net.ParseIP(s).To16()
|
||||
if i == nil {
|
||||
return nil, fmt.Errorf("failed to parse ip6 addr: %s", s)
|
||||
}
|
||||
return i, nil
|
||||
|
||||
// tcp udp dccp sctp
|
||||
case P_TCP, P_UDP, P_DCCP, P_SCTP:
|
||||
i, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse %s addr: %s", p.Name, err)
|
||||
}
|
||||
if i >= 65536 {
|
||||
return nil, fmt.Errorf("failed to parse %s addr: %s", p.Name, "greater than 65536")
|
||||
}
|
||||
b := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(b, uint16(i))
|
||||
return b, nil
|
||||
|
||||
case P_IPFS: // ipfs
|
||||
// the address is a varint prefixed multihash string representation
|
||||
m, err := mh.FromB58String(s)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse ipfs addr: %s %s", s, err)
|
||||
}
|
||||
size := CodeToVarint(len(m))
|
||||
b := append(size, m...)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
return []byte{}, fmt.Errorf("failed to parse %s addr: unknown", p.Name)
|
||||
}
|
||||
|
||||
func addressBytesToString(p Protocol, b []byte) (string, error) {
|
||||
switch p.Code {
|
||||
|
||||
// ipv4,6
|
||||
case P_IP4, P_IP6:
|
||||
return net.IP(b).String(), nil
|
||||
|
||||
// tcp udp dccp sctp
|
||||
case P_TCP, P_UDP, P_DCCP, P_SCTP:
|
||||
i := binary.BigEndian.Uint16(b)
|
||||
return strconv.Itoa(int(i)), nil
|
||||
|
||||
case P_IPFS: // ipfs
|
||||
// the address is a varint-prefixed multihash string representation
|
||||
size, n := ReadVarintCode(b)
|
||||
b = b[n:]
|
||||
if len(b) != size {
|
||||
panic("inconsistent lengths")
|
||||
}
|
||||
m, err := mh.Cast(b)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return m.B58String(), nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("unknown protocol")
|
||||
}
|
||||
36
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/doc.go
generated
vendored
36
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/doc.go
generated
vendored
@ -1,36 +0,0 @@
|
||||
/*
|
||||
Package multiaddr provides an implementation of the Multiaddr network
|
||||
address format. Multiaddr emphasizes explicitness, self-description, and
|
||||
portability. It allows applications to treat addresses as opaque tokens,
|
||||
and to avoid making assumptions about the address representation (e.g. length).
|
||||
Learn more at https://github.com/jbenet/multiaddr
|
||||
|
||||
Basic Use:
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
ma "github.com/jbenet/go-multiaddr"
|
||||
)
|
||||
|
||||
// construct from a string (err signals parse failure)
|
||||
m1, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/1234")
|
||||
|
||||
// construct from bytes (err signals parse failure)
|
||||
m2, err := ma.NewMultiaddrBytes(m1.Bytes())
|
||||
|
||||
// true
|
||||
strings.Equal(m1.String(), "/ip4/127.0.0.1/udp/1234")
|
||||
strings.Equal(m1.String(), m2.String())
|
||||
bytes.Equal(m1.Bytes(), m2.Bytes())
|
||||
m1.Equal(m2)
|
||||
m2.Equal(m1)
|
||||
|
||||
// tunneling (en/decap)
|
||||
printer, _ := ma.NewMultiaddr("/ip4/192.168.0.13/tcp/80")
|
||||
proxy, _ := ma.NewMultiaddr("/ip4/10.20.30.40/tcp/443")
|
||||
printerOverProxy := proxy.Encapsulate(printer)
|
||||
proxyAgain := printerOverProxy.Decapsulate(printer)
|
||||
|
||||
*/
|
||||
package multiaddr
|
||||
42
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/interface.go
generated
vendored
42
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/interface.go
generated
vendored
@ -1,42 +0,0 @@
|
||||
package multiaddr
|
||||
|
||||
/*
|
||||
Multiaddr is a cross-protocol, cross-platform format for representing
|
||||
internet addresses. It emphasizes explicitness and self-description.
|
||||
Learn more here: https://github.com/jbenet/multiaddr
|
||||
|
||||
Multiaddrs have both a binary and string representation.
|
||||
|
||||
import ma "github.com/jbenet/go-multiaddr"
|
||||
|
||||
addr, err := ma.NewMultiaddr("/ip4/1.2.3.4/tcp/80")
|
||||
// err non-nil when parsing failed.
|
||||
|
||||
*/
|
||||
type Multiaddr interface {
|
||||
// Equal returns whether two Multiaddrs are exactly equal
|
||||
Equal(Multiaddr) bool
|
||||
|
||||
// Bytes returns the []byte representation of this Multiaddr
|
||||
Bytes() []byte
|
||||
|
||||
// String returns the string representation of this Multiaddr
|
||||
// (may panic if internal state is corrupted)
|
||||
String() string
|
||||
|
||||
// Protocols returns the list of Protocols this Multiaddr includes
|
||||
// will panic if protocol code incorrect (and bytes accessed incorrectly)
|
||||
Protocols() []Protocol
|
||||
|
||||
// Encapsulate wraps this Multiaddr around another. For example:
|
||||
//
|
||||
// /ip4/1.2.3.4 encapsulate /tcp/80 = /ip4/1.2.3.4/tcp/80
|
||||
//
|
||||
Encapsulate(Multiaddr) Multiaddr
|
||||
|
||||
// Decapsultate removes a Multiaddr wrapping. For example:
|
||||
//
|
||||
// /ip4/1.2.3.4/tcp/80 decapsulate /ip4/1.2.3.4 = /tcp/80
|
||||
//
|
||||
Decapsulate(Multiaddr) Multiaddr
|
||||
}
|
||||
115
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/multiaddr.go
generated
vendored
115
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/multiaddr.go
generated
vendored
@ -1,115 +0,0 @@
|
||||
package multiaddr
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// multiaddr is the data structure representing a Multiaddr
|
||||
type multiaddr struct {
|
||||
bytes []byte
|
||||
}
|
||||
|
||||
// NewMultiaddr parses and validates an input string, returning a *Multiaddr
|
||||
func NewMultiaddr(s string) (Multiaddr, error) {
|
||||
b, err := stringToBytes(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &multiaddr{bytes: b}, nil
|
||||
}
|
||||
|
||||
// NewMultiaddrBytes initializes a Multiaddr from a byte representation.
|
||||
// It validates it as an input string.
|
||||
func NewMultiaddrBytes(b []byte) (Multiaddr, error) {
|
||||
s, err := bytesToString(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewMultiaddr(s)
|
||||
}
|
||||
|
||||
// Equal tests whether two multiaddrs are equal
|
||||
func (m *multiaddr) Equal(m2 Multiaddr) bool {
|
||||
return bytes.Equal(m.bytes, m2.Bytes())
|
||||
}
|
||||
|
||||
// Bytes returns the []byte representation of this Multiaddr
|
||||
func (m *multiaddr) Bytes() []byte {
|
||||
// consider returning copy to prevent changing underneath us?
|
||||
cpy := make([]byte, len(m.bytes))
|
||||
copy(cpy, m.bytes)
|
||||
return cpy
|
||||
}
|
||||
|
||||
// String returns the string representation of a Multiaddr
|
||||
func (m *multiaddr) String() string {
|
||||
s, err := bytesToString(m.bytes)
|
||||
if err != nil {
|
||||
panic("multiaddr failed to convert back to string. corrupted?")
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Protocols returns the list of protocols this Multiaddr has.
|
||||
// will panic in case we access bytes incorrectly.
|
||||
func (m *multiaddr) Protocols() []Protocol {
|
||||
|
||||
// panic handler, in case we try accessing bytes incorrectly.
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
err := e.(error)
|
||||
panic("Multiaddr.Protocols error: " + err.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
size := 0
|
||||
ps := []Protocol{}
|
||||
b := m.bytes[:]
|
||||
for len(b) > 0 {
|
||||
code, n := ReadVarintCode(b)
|
||||
p := ProtocolWithCode(code)
|
||||
if p.Code == 0 {
|
||||
// this is a panic (and not returning err) because this should've been
|
||||
// caught on constructing the Multiaddr
|
||||
panic(fmt.Errorf("no protocol with code %d", b[0]))
|
||||
}
|
||||
ps = append(ps, p)
|
||||
b = b[n:]
|
||||
|
||||
size = sizeForAddr(p, b)
|
||||
b = b[size:]
|
||||
}
|
||||
return ps
|
||||
}
|
||||
|
||||
// Encapsulate wraps a given Multiaddr, returning the resulting joined Multiaddr
|
||||
func (m *multiaddr) Encapsulate(o Multiaddr) Multiaddr {
|
||||
mb := m.bytes
|
||||
ob := o.Bytes()
|
||||
|
||||
b := make([]byte, len(mb)+len(ob))
|
||||
copy(b, mb)
|
||||
copy(b[len(mb):], ob)
|
||||
return &multiaddr{bytes: b}
|
||||
}
|
||||
|
||||
// Decapsulate unwraps Multiaddr up until the given Multiaddr is found.
|
||||
func (m *multiaddr) Decapsulate(o Multiaddr) Multiaddr {
|
||||
s1 := m.String()
|
||||
s2 := o.String()
|
||||
i := strings.LastIndex(s1, s2)
|
||||
if i < 0 {
|
||||
// if multiaddr not contained, returns a copy.
|
||||
cpy := make([]byte, len(m.bytes))
|
||||
copy(cpy, m.bytes)
|
||||
return &multiaddr{bytes: cpy}
|
||||
}
|
||||
|
||||
ma, err := NewMultiaddr(s1[:i])
|
||||
if err != nil {
|
||||
panic("Multiaddr.Decapsulate incorrect byte boundaries.")
|
||||
}
|
||||
return ma
|
||||
}
|
||||
294
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/multiaddr_test.go
generated
vendored
294
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/multiaddr_test.go
generated
vendored
@ -1,294 +0,0 @@
|
||||
package multiaddr
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func newMultiaddr(t *testing.T, a string) Multiaddr {
|
||||
m, err := NewMultiaddr(a)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func TestConstructFails(t *testing.T) {
|
||||
cases := []string{
|
||||
"/ip4",
|
||||
"/ip4/::1",
|
||||
"/ip4/fdpsofodsajfdoisa",
|
||||
"/ip6",
|
||||
"/udp",
|
||||
"/tcp",
|
||||
"/sctp",
|
||||
"/udp/65536",
|
||||
"/tcp/65536",
|
||||
"/udp/1234/sctp",
|
||||
"/udp/1234/udt/1234",
|
||||
"/udp/1234/utp/1234",
|
||||
"/ip4/127.0.0.1/udp/jfodsajfidosajfoidsa",
|
||||
"/ip4/127.0.0.1/udp",
|
||||
"/ip4/127.0.0.1/tcp/jfodsajfidosajfoidsa",
|
||||
"/ip4/127.0.0.1/tcp",
|
||||
"/ip4/127.0.0.1/ipfs",
|
||||
"/ip4/127.0.0.1/ipfs/tcp",
|
||||
}
|
||||
|
||||
for _, a := range cases {
|
||||
if _, err := NewMultiaddr(a); err == nil {
|
||||
t.Errorf("should have failed: %s - %s", a, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestConstructSucceeds(t *testing.T) {
|
||||
cases := []string{
|
||||
"/ip4/1.2.3.4",
|
||||
"/ip4/0.0.0.0",
|
||||
"/ip6/::1",
|
||||
"/ip6/2601:9:4f81:9700:803e:ca65:66e8:c21",
|
||||
"/udp/0",
|
||||
"/tcp/0",
|
||||
"/sctp/0",
|
||||
"/udp/1234",
|
||||
"/tcp/1234",
|
||||
"/sctp/1234",
|
||||
"/udp/65535",
|
||||
"/tcp/65535",
|
||||
"/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
|
||||
"/udp/1234/sctp/1234",
|
||||
"/udp/1234/udt",
|
||||
"/udp/1234/utp",
|
||||
"/tcp/1234/http",
|
||||
"/tcp/1234/https",
|
||||
"/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234",
|
||||
"/ip4/127.0.0.1/udp/1234",
|
||||
"/ip4/127.0.0.1/udp/0",
|
||||
"/ip4/127.0.0.1/tcp/1234",
|
||||
"/ip4/127.0.0.1/tcp/1234/",
|
||||
"/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
|
||||
"/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234",
|
||||
}
|
||||
|
||||
for _, a := range cases {
|
||||
if _, err := NewMultiaddr(a); err != nil {
|
||||
t.Errorf("should have succeeded: %s -- %s", a, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEqual(t *testing.T) {
|
||||
m1 := newMultiaddr(t, "/ip4/127.0.0.1/udp/1234")
|
||||
m2 := newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234")
|
||||
m3 := newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234")
|
||||
m4 := newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234/")
|
||||
|
||||
if m1.Equal(m2) {
|
||||
t.Error("should not be equal")
|
||||
}
|
||||
|
||||
if m2.Equal(m1) {
|
||||
t.Error("should not be equal")
|
||||
}
|
||||
|
||||
if !m2.Equal(m3) {
|
||||
t.Error("should be equal")
|
||||
}
|
||||
|
||||
if !m3.Equal(m2) {
|
||||
t.Error("should be equal")
|
||||
}
|
||||
|
||||
if !m1.Equal(m1) {
|
||||
t.Error("should be equal")
|
||||
}
|
||||
|
||||
if !m2.Equal(m4) {
|
||||
t.Error("should be equal")
|
||||
}
|
||||
|
||||
if !m4.Equal(m3) {
|
||||
t.Error("should be equal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringToBytes(t *testing.T) {
|
||||
|
||||
testString := func(s string, h string) {
|
||||
b1, err := hex.DecodeString(h)
|
||||
if err != nil {
|
||||
t.Error("failed to decode hex", h)
|
||||
}
|
||||
|
||||
b2, err := stringToBytes(s)
|
||||
if err != nil {
|
||||
t.Error("failed to convert", s)
|
||||
}
|
||||
|
||||
if !bytes.Equal(b1, b2) {
|
||||
t.Error("failed to convert", s, "to", b1, "got", b2)
|
||||
}
|
||||
}
|
||||
|
||||
testString("/ip4/127.0.0.1/udp/1234", "047f0000011104d2")
|
||||
testString("/ip4/127.0.0.1/tcp/4321", "047f0000010610e1")
|
||||
testString("/ip4/127.0.0.1/udp/1234/ip4/127.0.0.1/tcp/4321", "047f0000011104d2047f0000010610e1")
|
||||
}
|
||||
|
||||
func TestBytesToString(t *testing.T) {
|
||||
|
||||
testString := func(s1 string, h string) {
|
||||
b, err := hex.DecodeString(h)
|
||||
if err != nil {
|
||||
t.Error("failed to decode hex", h)
|
||||
}
|
||||
|
||||
s2, err := bytesToString(b)
|
||||
if err != nil {
|
||||
t.Error("failed to convert", b)
|
||||
}
|
||||
|
||||
if s1 != s2 {
|
||||
t.Error("failed to convert", b, "to", s1, "got", s2)
|
||||
}
|
||||
}
|
||||
|
||||
testString("/ip4/127.0.0.1/udp/1234", "047f0000011104d2")
|
||||
testString("/ip4/127.0.0.1/tcp/4321", "047f0000010610e1")
|
||||
testString("/ip4/127.0.0.1/udp/1234/ip4/127.0.0.1/tcp/4321", "047f0000011104d2047f0000010610e1")
|
||||
}
|
||||
|
||||
func TestBytesSplitAndJoin(t *testing.T) {
|
||||
|
||||
testString := func(s string, res []string) {
|
||||
m, err := NewMultiaddr(s)
|
||||
if err != nil {
|
||||
t.Fatal("failed to convert", s, err)
|
||||
}
|
||||
|
||||
split := Split(m)
|
||||
if len(split) != len(res) {
|
||||
t.Error("not enough split components", split)
|
||||
return
|
||||
}
|
||||
|
||||
for i, a := range split {
|
||||
if a.String() != res[i] {
|
||||
t.Errorf("split component failed: %s != %s", a, res[i])
|
||||
}
|
||||
}
|
||||
|
||||
joined := Join(split...)
|
||||
if !m.Equal(joined) {
|
||||
t.Errorf("joined components failed: %s != %s", m, joined)
|
||||
}
|
||||
|
||||
// modifying underlying bytes is fine.
|
||||
m2 := m.(*multiaddr)
|
||||
for i := range m2.bytes {
|
||||
m2.bytes[i] = 0
|
||||
}
|
||||
|
||||
for i, a := range split {
|
||||
if a.String() != res[i] {
|
||||
t.Errorf("split component failed: %s != %s", a, res[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
testString("/ip4/1.2.3.4/udp/1234", []string{"/ip4/1.2.3.4", "/udp/1234"})
|
||||
testString("/ip4/1.2.3.4/tcp/1/ip4/2.3.4.5/udp/2",
|
||||
[]string{"/ip4/1.2.3.4", "/tcp/1", "/ip4/2.3.4.5", "/udp/2"})
|
||||
testString("/ip4/1.2.3.4/utp/ip4/2.3.4.5/udp/2/udt",
|
||||
[]string{"/ip4/1.2.3.4", "/utp", "/ip4/2.3.4.5", "/udp/2", "/udt"})
|
||||
}
|
||||
|
||||
func TestProtocols(t *testing.T) {
|
||||
m, err := NewMultiaddr("/ip4/127.0.0.1/udp/1234")
|
||||
if err != nil {
|
||||
t.Error("failed to construct", "/ip4/127.0.0.1/udp/1234")
|
||||
}
|
||||
|
||||
ps := m.Protocols()
|
||||
if ps[0].Code != ProtocolWithName("ip4").Code {
|
||||
t.Error(ps[0], ProtocolWithName("ip4"))
|
||||
t.Error("failed to get ip4 protocol")
|
||||
}
|
||||
|
||||
if ps[1].Code != ProtocolWithName("udp").Code {
|
||||
t.Error(ps[1], ProtocolWithName("udp"))
|
||||
t.Error("failed to get udp protocol")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestProtocolsWithString(t *testing.T) {
|
||||
pwn := ProtocolWithName
|
||||
good := map[string][]Protocol{
|
||||
"/ip4": []Protocol{pwn("ip4")},
|
||||
"/ip4/tcp": []Protocol{pwn("ip4"), pwn("tcp")},
|
||||
"ip4/tcp/udp/ip6": []Protocol{pwn("ip4"), pwn("tcp"), pwn("udp"), pwn("ip6")},
|
||||
"////////ip4/tcp": []Protocol{pwn("ip4"), pwn("tcp")},
|
||||
"ip4/udp/////////": []Protocol{pwn("ip4"), pwn("udp")},
|
||||
"////////ip4/tcp////////": []Protocol{pwn("ip4"), pwn("tcp")},
|
||||
}
|
||||
|
||||
for s, ps1 := range good {
|
||||
ps2, err := ProtocolsWithString(s)
|
||||
if err != nil {
|
||||
t.Error("ProtocolsWithString(%s) should have succeeded", s)
|
||||
}
|
||||
|
||||
for i, ps1p := range ps1 {
|
||||
ps2p := ps2[i]
|
||||
if ps1p.Code != ps2p.Code {
|
||||
t.Errorf("mismatch: %s != %s, %s", ps1p.Name, ps2p.Name, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bad := []string{
|
||||
"dsijafd", // bogus proto
|
||||
"/ip4/tcp/fidosafoidsa", // bogus proto
|
||||
"////////ip4/tcp/21432141/////////", // bogus proto
|
||||
"////////ip4///////tcp/////////", // empty protos in between
|
||||
}
|
||||
|
||||
for _, s := range bad {
|
||||
if _, err := ProtocolsWithString(s); err == nil {
|
||||
t.Error("ProtocolsWithString(%s) should have failed", s)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestEncapsulate(t *testing.T) {
|
||||
m, err := NewMultiaddr("/ip4/127.0.0.1/udp/1234")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
m2, err := NewMultiaddr("/udp/5678")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
b := m.Encapsulate(m2)
|
||||
if s := b.String(); s != "/ip4/127.0.0.1/udp/1234/udp/5678" {
|
||||
t.Error("encapsulate /ip4/127.0.0.1/udp/1234/udp/5678 failed.", s)
|
||||
}
|
||||
|
||||
m3, _ := NewMultiaddr("/udp/5678")
|
||||
c := b.Decapsulate(m3)
|
||||
if s := c.String(); s != "/ip4/127.0.0.1/udp/1234" {
|
||||
t.Error("decapsulate /udp failed.", "/ip4/127.0.0.1/udp/1234", s)
|
||||
}
|
||||
|
||||
m4, _ := NewMultiaddr("/ip4/127.0.0.1")
|
||||
d := c.Decapsulate(m4)
|
||||
if s := d.String(); s != "" {
|
||||
t.Error("decapsulate /ip4 failed.", "/", s)
|
||||
}
|
||||
}
|
||||
12
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/protocols.csv
generated
vendored
12
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/protocols.csv
generated
vendored
@ -1,12 +0,0 @@
|
||||
code size name
|
||||
4 32 ip4
|
||||
6 16 tcp
|
||||
17 16 udp
|
||||
33 16 dccp
|
||||
41 128 ip6
|
||||
132 16 sctp
|
||||
301 0 udt
|
||||
302 0 utp
|
||||
421 V ipfs
|
||||
480 0 http
|
||||
443 0 https
|
||||
|
116
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/protocols.go
generated
vendored
116
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/protocols.go
generated
vendored
@ -1,116 +0,0 @@
|
||||
package multiaddr
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Protocol is a Multiaddr protocol description structure.
|
||||
type Protocol struct {
|
||||
Code int
|
||||
Size int // a size of -1 indicates a length-prefixed variable size
|
||||
Name string
|
||||
VCode []byte
|
||||
}
|
||||
|
||||
// replicating table here to:
|
||||
// 1. avoid parsing the csv
|
||||
// 2. ensuring errors in the csv don't screw up code.
|
||||
// 3. changing a number has to happen in two places.
|
||||
const (
|
||||
P_IP4 = 4
|
||||
P_TCP = 6
|
||||
P_UDP = 17
|
||||
P_DCCP = 33
|
||||
P_IP6 = 41
|
||||
P_SCTP = 132
|
||||
P_UTP = 301
|
||||
P_UDT = 302
|
||||
P_IPFS = 421
|
||||
P_HTTP = 480
|
||||
P_HTTPS = 443
|
||||
)
|
||||
|
||||
// These are special sizes
|
||||
const (
|
||||
LengthPrefixedVarSize = -1
|
||||
)
|
||||
|
||||
// Protocols is the list of multiaddr protocols supported by this module.
|
||||
var Protocols = []Protocol{
|
||||
Protocol{P_IP4, 32, "ip4", CodeToVarint(P_IP4)},
|
||||
Protocol{P_TCP, 16, "tcp", CodeToVarint(P_TCP)},
|
||||
Protocol{P_UDP, 16, "udp", CodeToVarint(P_UDP)},
|
||||
Protocol{P_DCCP, 16, "dccp", CodeToVarint(P_DCCP)},
|
||||
Protocol{P_IP6, 128, "ip6", CodeToVarint(P_IP6)},
|
||||
// these require varint:
|
||||
Protocol{P_SCTP, 16, "sctp", CodeToVarint(P_SCTP)},
|
||||
Protocol{P_UTP, 0, "utp", CodeToVarint(P_UTP)},
|
||||
Protocol{P_UDT, 0, "udt", CodeToVarint(P_UDT)},
|
||||
Protocol{P_HTTP, 0, "http", CodeToVarint(P_HTTP)},
|
||||
Protocol{P_HTTPS, 0, "https", CodeToVarint(P_HTTPS)},
|
||||
Protocol{P_IPFS, LengthPrefixedVarSize, "ipfs", CodeToVarint(P_IPFS)},
|
||||
}
|
||||
|
||||
// ProtocolWithName returns the Protocol description with given string name.
|
||||
func ProtocolWithName(s string) Protocol {
|
||||
for _, p := range Protocols {
|
||||
if p.Name == s {
|
||||
return p
|
||||
}
|
||||
}
|
||||
return Protocol{}
|
||||
}
|
||||
|
||||
// ProtocolWithCode returns the Protocol description with given protocol code.
|
||||
func ProtocolWithCode(c int) Protocol {
|
||||
for _, p := range Protocols {
|
||||
if p.Code == c {
|
||||
return p
|
||||
}
|
||||
}
|
||||
return Protocol{}
|
||||
}
|
||||
|
||||
// ProtocolsWithString returns a slice of protocols matching given string.
|
||||
func ProtocolsWithString(s string) ([]Protocol, error) {
|
||||
s = strings.Trim(s, "/")
|
||||
sp := strings.Split(s, "/")
|
||||
if len(sp) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
t := make([]Protocol, len(sp))
|
||||
for i, name := range sp {
|
||||
p := ProtocolWithName(name)
|
||||
if p.Code == 0 {
|
||||
return nil, fmt.Errorf("no protocol with name: %s", name)
|
||||
}
|
||||
t[i] = p
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// CodeToVarint converts an integer to a varint-encoded []byte
|
||||
func CodeToVarint(num int) []byte {
|
||||
buf := make([]byte, (num/7)+1) // varint package is uint64
|
||||
n := binary.PutUvarint(buf, uint64(num))
|
||||
return buf[:n]
|
||||
}
|
||||
|
||||
// VarintToCode converts a varint-encoded []byte to an integer protocol code
|
||||
func VarintToCode(buf []byte) int {
|
||||
num, _ := ReadVarintCode(buf)
|
||||
return num
|
||||
}
|
||||
|
||||
// ReadVarintCode reads a varint code from the beginning of buf.
|
||||
// returns the code, and the number of bytes read.
|
||||
func ReadVarintCode(buf []byte) (int, int) {
|
||||
num, n := binary.Uvarint(buf)
|
||||
if n < 0 {
|
||||
panic("varints larger than uint64 not yet supported")
|
||||
}
|
||||
return int(num), n
|
||||
}
|
||||
56
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/util.go
generated
vendored
56
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/util.go
generated
vendored
@ -1,56 +0,0 @@
|
||||
package multiaddr
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Split returns the sub-address portions of a multiaddr.
|
||||
func Split(m Multiaddr) []Multiaddr {
|
||||
split, err := bytesSplit(m.Bytes())
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("invalid multiaddr %s", m.String()))
|
||||
}
|
||||
|
||||
addrs := make([]Multiaddr, len(split))
|
||||
for i, addr := range split {
|
||||
addrs[i] = &multiaddr{bytes: addr}
|
||||
}
|
||||
return addrs
|
||||
}
|
||||
|
||||
// Join returns a combination of addresses.
|
||||
func Join(ms ...Multiaddr) Multiaddr {
|
||||
|
||||
length := 0
|
||||
bs := make([][]byte, len(ms))
|
||||
for i, m := range ms {
|
||||
bs[i] = m.Bytes()
|
||||
length += len(bs[i])
|
||||
}
|
||||
|
||||
bidx := 0
|
||||
b := make([]byte, length)
|
||||
for _, mb := range bs {
|
||||
for i := range mb {
|
||||
b[bidx] = mb[i]
|
||||
bidx++
|
||||
}
|
||||
}
|
||||
return &multiaddr{bytes: b}
|
||||
}
|
||||
|
||||
// Cast re-casts a byte slice as a multiaddr. will panic if it fails to parse.
|
||||
func Cast(b []byte) Multiaddr {
|
||||
_, err := bytesToString(b)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("multiaddr failed to parse: %s", err))
|
||||
}
|
||||
return &multiaddr{bytes: b}
|
||||
}
|
||||
|
||||
// StringCast like Cast, but parses a string. Will also panic if it fails to parse.
|
||||
func StringCast(s string) Multiaddr {
|
||||
m, err := NewMultiaddr(s)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("multiaddr failed to parse: %s", err))
|
||||
}
|
||||
return m
|
||||
}
|
||||
11
Godeps/_workspace/src/github.com/jbenet/go-multihash/.travis.yml
generated
vendored
11
Godeps/_workspace/src/github.com/jbenet/go-multihash/.travis.yml
generated
vendored
@ -1,11 +0,0 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.3
|
||||
- release
|
||||
- tip
|
||||
|
||||
script:
|
||||
- make test
|
||||
|
||||
env: TEST_VERBOSE=1
|
||||
21
Godeps/_workspace/src/github.com/jbenet/go-multihash/LICENSE
generated
vendored
21
Godeps/_workspace/src/github.com/jbenet/go-multihash/LICENSE
generated
vendored
@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Juan Batiz-Benet
|
||||
|
||||
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.
|
||||
11
Godeps/_workspace/src/github.com/jbenet/go-multihash/Makefile
generated
vendored
11
Godeps/_workspace/src/github.com/jbenet/go-multihash/Makefile
generated
vendored
@ -1,11 +0,0 @@
|
||||
test: go_test other_tests
|
||||
|
||||
other_tests:
|
||||
cd test && make test
|
||||
|
||||
go_test: go_deps
|
||||
go test -race -cpu=5 -v ./...
|
||||
|
||||
go_deps:
|
||||
go get golang.org/x/crypto/sha3
|
||||
go get github.com/jbenet/go-base58
|
||||
45
Godeps/_workspace/src/github.com/jbenet/go-multihash/README.md
generated
vendored
45
Godeps/_workspace/src/github.com/jbenet/go-multihash/README.md
generated
vendored
@ -1,45 +0,0 @@
|
||||
# go-multihash
|
||||
|
||||

|
||||
|
||||
[multihash](//github.com/jbenet/multihash) implementation in Go.
|
||||
|
||||
## Example
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/jbenet/go-multihash"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// ignores errors for simplicity.
|
||||
// don't do that at home.
|
||||
|
||||
buf, _ := hex.DecodeString("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33")
|
||||
mhbuf, _ := multihash.EncodeName(buf, "sha1");
|
||||
mhhex := hex.EncodeToString(mhbuf)
|
||||
fmt.Printf("hex: %v\n", mhhex);
|
||||
|
||||
o, _ := multihash.Decode(mhbuf);
|
||||
mhhex = hex.EncodeToString(o.Digest);
|
||||
fmt.Printf("obj: %v 0x%x %d %s\n", o.Name, o.Code, o.Length, mhhex);
|
||||
}
|
||||
```
|
||||
|
||||
Run [test/foo.go](test/foo.go)
|
||||
|
||||
```
|
||||
> cd test/
|
||||
> go build
|
||||
> ./test
|
||||
hex: 11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33
|
||||
obj: sha1 0x11 20 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
79
Godeps/_workspace/src/github.com/jbenet/go-multihash/io.go
generated
vendored
79
Godeps/_workspace/src/github.com/jbenet/go-multihash/io.go
generated
vendored
@ -1,79 +0,0 @@
|
||||
package multihash
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Reader is an io.Reader wrapper that exposes a function
|
||||
// to read a whole multihash, parse it, and return it.
|
||||
type Reader interface {
|
||||
io.Reader
|
||||
|
||||
ReadMultihash() (Multihash, error)
|
||||
}
|
||||
|
||||
// Writer is an io.Writer wrapper that exposes a function
|
||||
// to write a whole multihash.
|
||||
type Writer interface {
|
||||
io.Writer
|
||||
|
||||
WriteMultihash(Multihash) error
|
||||
}
|
||||
|
||||
// NewReader wraps an io.Reader with a multihash.Reader
|
||||
func NewReader(r io.Reader) Reader {
|
||||
return &mhReader{r}
|
||||
}
|
||||
|
||||
// NewWriter wraps an io.Writer with a multihash.Writer
|
||||
func NewWriter(w io.Writer) Writer {
|
||||
return &mhWriter{w}
|
||||
}
|
||||
|
||||
type mhReader struct {
|
||||
r io.Reader
|
||||
}
|
||||
|
||||
func (r *mhReader) Read(buf []byte) (n int, err error) {
|
||||
return r.r.Read(buf)
|
||||
}
|
||||
|
||||
func (r *mhReader) ReadMultihash() (Multihash, error) {
|
||||
mhhdr := make([]byte, 2)
|
||||
if _, err := io.ReadFull(r.r, mhhdr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// first byte is the algo, the second is the length.
|
||||
|
||||
// (varints someday...)
|
||||
length := uint(mhhdr[1])
|
||||
|
||||
if length > 127 {
|
||||
return nil, fmt.Errorf("varints not yet supported (length is %d)", length)
|
||||
}
|
||||
|
||||
buf := make([]byte, length+2)
|
||||
buf[0] = mhhdr[0]
|
||||
buf[1] = mhhdr[1]
|
||||
|
||||
if _, err := io.ReadFull(r.r, buf[2:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return Cast(buf)
|
||||
}
|
||||
|
||||
type mhWriter struct {
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
func (w *mhWriter) Write(buf []byte) (n int, err error) {
|
||||
return w.w.Write(buf)
|
||||
}
|
||||
|
||||
func (w *mhWriter) WriteMultihash(m Multihash) error {
|
||||
_, err := w.w.Write([]byte(m))
|
||||
return err
|
||||
}
|
||||
69
Godeps/_workspace/src/github.com/jbenet/go-multihash/io_test.go
generated
vendored
69
Godeps/_workspace/src/github.com/jbenet/go-multihash/io_test.go
generated
vendored
@ -1,69 +0,0 @@
|
||||
package multihash
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReader(t *testing.T) {
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
for _, tc := range testCases {
|
||||
m, err := tc.Multihash()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
buf.Write([]byte(m))
|
||||
}
|
||||
|
||||
r := NewReader(&buf)
|
||||
|
||||
for _, tc := range testCases {
|
||||
h, err := tc.Multihash()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
h2, err := r.ReadMultihash()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !bytes.Equal(h, h2) {
|
||||
t.Error("h and h2 should be equal")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriter(t *testing.T) {
|
||||
|
||||
var buf bytes.Buffer
|
||||
w := NewWriter(&buf)
|
||||
|
||||
for _, tc := range testCases {
|
||||
m, err := tc.Multihash()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := w.WriteMultihash(m); err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
buf2 := make([]byte, len(m))
|
||||
if _, err := io.ReadFull(&buf, buf2); err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !bytes.Equal(m, buf2) {
|
||||
t.Error("m and buf2 should be equal")
|
||||
}
|
||||
}
|
||||
}
|
||||
188
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash.go
generated
vendored
188
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash.go
generated
vendored
@ -1,188 +0,0 @@
|
||||
package multihash
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
b58 "github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/jbenet/go-base58"
|
||||
)
|
||||
|
||||
// errors
|
||||
var (
|
||||
ErrUnknownCode = errors.New("unknown multihash code")
|
||||
ErrTooShort = errors.New("multihash too short. must be > 3 bytes")
|
||||
ErrTooLong = errors.New("multihash too long. must be < 129 bytes")
|
||||
ErrLenNotSupported = errors.New("multihash does not yet support digests longer than 127 bytes")
|
||||
)
|
||||
|
||||
// ErrInconsistentLen is returned when a decoded multihash has an inconsistent length
|
||||
type ErrInconsistentLen struct {
|
||||
dm *DecodedMultihash
|
||||
}
|
||||
|
||||
func (e ErrInconsistentLen) Error() string {
|
||||
return fmt.Sprintf("multihash length inconsistent: %v", e.dm)
|
||||
}
|
||||
|
||||
// constants
|
||||
const (
|
||||
SHA1 = 0x11
|
||||
SHA2_256 = 0x12
|
||||
SHA2_512 = 0x13
|
||||
SHA3 = 0x14
|
||||
BLAKE2B = 0x40
|
||||
BLAKE2S = 0x41
|
||||
)
|
||||
|
||||
// Names maps the name of a hash to the code
|
||||
var Names = map[string]int{
|
||||
"sha1": SHA1,
|
||||
"sha2-256": SHA2_256,
|
||||
"sha2-512": SHA2_512,
|
||||
"sha3": SHA3,
|
||||
"blake2b": BLAKE2B,
|
||||
"blake2s": BLAKE2S,
|
||||
}
|
||||
|
||||
// Codes maps a hash code to it's name
|
||||
var Codes = map[int]string{
|
||||
SHA1: "sha1",
|
||||
SHA2_256: "sha2-256",
|
||||
SHA2_512: "sha2-512",
|
||||
SHA3: "sha3",
|
||||
BLAKE2B: "blake2b",
|
||||
BLAKE2S: "blake2s",
|
||||
}
|
||||
|
||||
// DefaultLengths maps a hash code to it's default length
|
||||
var DefaultLengths = map[int]int{
|
||||
SHA1: 20,
|
||||
SHA2_256: 32,
|
||||
SHA2_512: 64,
|
||||
SHA3: 64,
|
||||
BLAKE2B: 64,
|
||||
BLAKE2S: 32,
|
||||
}
|
||||
|
||||
type DecodedMultihash struct {
|
||||
Code int
|
||||
Name string
|
||||
Length int
|
||||
Digest []byte
|
||||
}
|
||||
|
||||
type Multihash []byte
|
||||
|
||||
func (m *Multihash) HexString() string {
|
||||
return hex.EncodeToString([]byte(*m))
|
||||
}
|
||||
|
||||
func (m *Multihash) String() string {
|
||||
return m.HexString()
|
||||
}
|
||||
|
||||
func FromHexString(s string) (Multihash, error) {
|
||||
b, err := hex.DecodeString(s)
|
||||
if err != nil {
|
||||
return Multihash{}, err
|
||||
}
|
||||
|
||||
return Cast(b)
|
||||
}
|
||||
|
||||
func (m Multihash) B58String() string {
|
||||
return b58.Encode([]byte(m))
|
||||
}
|
||||
|
||||
func FromB58String(s string) (m Multihash, err error) {
|
||||
// panic handler, in case we try accessing bytes incorrectly.
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
m = Multihash{}
|
||||
err = e.(error)
|
||||
}
|
||||
}()
|
||||
|
||||
//b58 smells like it can panic...
|
||||
b := b58.Decode(s)
|
||||
return Cast(b)
|
||||
}
|
||||
|
||||
func Cast(buf []byte) (Multihash, error) {
|
||||
dm, err := Decode(buf)
|
||||
if err != nil {
|
||||
return Multihash{}, err
|
||||
}
|
||||
|
||||
if !ValidCode(dm.Code) {
|
||||
return Multihash{}, ErrUnknownCode
|
||||
}
|
||||
|
||||
return Multihash(buf), nil
|
||||
}
|
||||
|
||||
// Decode a hash from the given Multihash.
|
||||
func Decode(buf []byte) (*DecodedMultihash, error) {
|
||||
|
||||
if len(buf) < 3 {
|
||||
return nil, ErrTooShort
|
||||
}
|
||||
|
||||
if len(buf) > 129 {
|
||||
return nil, ErrTooLong
|
||||
}
|
||||
|
||||
dm := &DecodedMultihash{
|
||||
Code: int(uint8(buf[0])),
|
||||
Name: Codes[int(uint8(buf[0]))],
|
||||
Length: int(uint8(buf[1])),
|
||||
Digest: buf[2:],
|
||||
}
|
||||
|
||||
if len(dm.Digest) != dm.Length {
|
||||
return nil, ErrInconsistentLen{dm}
|
||||
}
|
||||
|
||||
return dm, nil
|
||||
}
|
||||
|
||||
// Encode a hash digest along with the specified function code.
|
||||
// Note: the length is derived from the length of the digest itself.
|
||||
func Encode(buf []byte, code int) ([]byte, error) {
|
||||
|
||||
if !ValidCode(code) {
|
||||
return nil, ErrUnknownCode
|
||||
}
|
||||
|
||||
if len(buf) > 127 {
|
||||
return nil, ErrLenNotSupported
|
||||
}
|
||||
|
||||
pre := make([]byte, 2)
|
||||
pre[0] = byte(uint8(code))
|
||||
pre[1] = byte(uint8(len(buf)))
|
||||
return append(pre, buf...), nil
|
||||
}
|
||||
|
||||
func EncodeName(buf []byte, name string) ([]byte, error) {
|
||||
return Encode(buf, Names[name])
|
||||
}
|
||||
|
||||
// ValidCode checks whether a multihash code is valid.
|
||||
func ValidCode(code int) bool {
|
||||
if AppCode(code) {
|
||||
return true
|
||||
}
|
||||
|
||||
if _, ok := Codes[code]; ok {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// AppCode checks whether a multihash code is part of the App range.
|
||||
func AppCode(code int) bool {
|
||||
return code >= 0 && code < 0x10
|
||||
}
|
||||
1
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash/.gitignore
generated
vendored
1
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash/.gitignore
generated
vendored
@ -1 +0,0 @@
|
||||
multihash
|
||||
116
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash/README.md
generated
vendored
116
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash/README.md
generated
vendored
@ -1,116 +0,0 @@
|
||||
# multihash tool
|
||||
|
||||
The `multihash` tool uses `go-multihash` to hash things much like `shasum`.
|
||||
|
||||
Warning: this is a **multihash** tool! Its digests follow the [multihash](https://github.com/jbenet/multihash) format.
|
||||
|
||||
### Install
|
||||
|
||||
```
|
||||
go get github.com/jbenet/go-multihash/multihash
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```sh
|
||||
> multihash -h
|
||||
usage: ./multihash [options] [FILE]
|
||||
Print or check multihash checksums.
|
||||
With no FILE, or when FILE is -, read standard input.
|
||||
|
||||
Options:
|
||||
-a="sha2-256": one of: sha1, sha2-256, sha2-512, sha3 (shorthand)
|
||||
-algorithm="sha2-256": one of: sha1, sha2-256, sha2-512, sha3
|
||||
-c="": check checksum matches (shorthand)
|
||||
-check="": check checksum matches
|
||||
-e="base58": one of: raw, hex, base58, base64 (shorthand)
|
||||
-encoding="base58": one of: raw, hex, base58, base64
|
||||
-l=-1: checksums length in bits (truncate). -1 is default (shorthand)
|
||||
-length=-1: checksums length in bits (truncate). -1 is default
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
#### Input
|
||||
|
||||
```sh
|
||||
# from stdin
|
||||
> multihash < main.go
|
||||
QmRZxt2b1FVZPNqd8hsiykDL3TdBDeTSPX9Kv46HmX4Gx8
|
||||
|
||||
# from file
|
||||
> ./multihash main.go
|
||||
QmRZxt2b1FVZPNqd8hsiykDL3TdBDeTSPX9Kv46HmX4Gx8
|
||||
|
||||
# from stdin "filename"
|
||||
> multihash - < main.go
|
||||
QmRZxt2b1FVZPNqd8hsiykDL3TdBDeTSPX9Kv46HmX4Gx8
|
||||
```
|
||||
|
||||
#### Algorithms
|
||||
|
||||
```sh
|
||||
> multihash -a ?
|
||||
error: algorithm '?' not one of: sha1, sha2-256, sha2-512, sha3
|
||||
|
||||
> multihash -a sha1 < main.go
|
||||
5drkbcqJUo6fZVvcZJeVEVWAgndvLm
|
||||
|
||||
> multihash -a sha2-256 < main.go
|
||||
QmcK3s36goo9v2HYcfTrDKKwxaxmJJ59etodQQFYsL5T5N
|
||||
|
||||
> multihash -a sha2-512 < main.go
|
||||
8VuDcW4CooyPQA8Cc4eYpwjhyDJZqu5m5ZMDFzWULYsVS8d119JaGeNWsZbZ2ZG2kPtbrMx31MidokCigaD65yUPAs
|
||||
|
||||
> multihash -a sha3 < main.go
|
||||
8tWDCTfAX24DYmzNixTj2ARJkqwRG736VHx5aJppmqRjhW9QT1EuTgKUmu9Pmunzq292jzPKxb2VxSsTXmjFY1HD3B
|
||||
```
|
||||
|
||||
#### Encodings
|
||||
|
||||
```sh
|
||||
> multihash -e raw < main.go
|
||||
Ϛ<><CF9A><EFBFBD><EFBFBD><EFBFBD>I<EFBFBD>5 S<><53>WG><3E><><EFBFBD>_<EFBFBD><5F>]g<><67><EFBFBD><EFBFBD><EFBFBD>u
|
||||
|
||||
> multihash -e hex < main.go
|
||||
1220cf9aa2b8a38b9b49d135095390059a57473e97aceb5fcae25d67a8b6feb58275
|
||||
|
||||
> multihash -e base64 < main.go
|
||||
EiDPmqK4o4ubSdE1CVOQBZpXRz6XrOtfyuJdZ6i2/rWCdQ==
|
||||
|
||||
> multihash -e base58 < main.go
|
||||
Qmf1QjEXDmqBm7RqHKqFGNUyhzUjnX7cmgKMrGzzPceZDQ
|
||||
```
|
||||
|
||||
#### Digest Length
|
||||
|
||||
```sh
|
||||
# we're outputing hex (good byte alignment) to show the codes changing
|
||||
# notice the multihash code (first 2 chars) differs!
|
||||
> multihash -e hex -a sha2-256 -l 256 < main.go
|
||||
1220cf9aa2b8a38b9b49d135095390059a57473e97aceb5fcae25d67a8b6feb58275
|
||||
> multihash -e hex -a sha2-512 -l 256 < main.go
|
||||
132047a4b6c629f5545f529b0ff461dc09119969f3593186277a1cc7a8ea3560a6f1
|
||||
> multihash -e hex -a sha3 -l 256 < main.go
|
||||
14206b9222a1a47939e665261bd2b5573e55e7988675223adde73c1011066ad66335
|
||||
|
||||
# notice the multihash length (next 2 chars) differs!
|
||||
> multihash -e hex -a sha2-256 -l 256 < main.go
|
||||
1220cf9aa2b8a38b9b49d135095390059a57473e97aceb5fcae25d67a8b6feb58275
|
||||
> multihash -e hex -a sha2-256 -l 200 < main.go
|
||||
1219cf9aa2b8a38b9b49d135095390059a57473e97aceb5fcae25d
|
||||
```
|
||||
|
||||
#### Verify Checksum
|
||||
|
||||
```sh
|
||||
> multihash -c QmRZxt2b1FVZPNqd8hsiykDL3TdBDeTSPX9Kv46HmX4Gx8 < main.go
|
||||
OK checksums match (-q for no output)
|
||||
|
||||
> multihash -c QmcKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa < main.go
|
||||
error: computed checksum did not match (-q for no output)
|
||||
|
||||
# works with other arguments too
|
||||
> multihash -e hex -l 128 -c "12102ffc284a1e82bf51e567c75b2ae6edb9" < main.go
|
||||
OK checksums match (-q for no output)
|
||||
```
|
||||
40
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash/coding.go
generated
vendored
40
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash/coding.go
generated
vendored
@ -1,40 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
base58 "github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/jbenet/go-base58"
|
||||
mh "github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/jbenet/go-multihash"
|
||||
)
|
||||
|
||||
func Decode(encoding, digest string) (mh.Multihash, error) {
|
||||
switch encoding {
|
||||
case "raw":
|
||||
return mh.Cast([]byte(digest))
|
||||
case "hex":
|
||||
return hex.DecodeString(digest)
|
||||
case "base58":
|
||||
return base58.Decode(digest), nil
|
||||
case "base64":
|
||||
return base64.StdEncoding.DecodeString(digest)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown encoding: %s", encoding)
|
||||
}
|
||||
}
|
||||
|
||||
func Encode(encoding string, hash mh.Multihash) (string, error) {
|
||||
switch encoding {
|
||||
case "raw":
|
||||
return string(hash), nil
|
||||
case "hex":
|
||||
return hex.EncodeToString(hash), nil
|
||||
case "base58":
|
||||
return base58.Encode(hash), nil
|
||||
case "base64":
|
||||
return base64.StdEncoding.EncodeToString(hash), nil
|
||||
default:
|
||||
return "", fmt.Errorf("unknown encoding: %s", encoding)
|
||||
}
|
||||
}
|
||||
208
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash/main.go
generated
vendored
208
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash/main.go
generated
vendored
@ -1,208 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
mh "github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/jbenet/go-multihash"
|
||||
)
|
||||
|
||||
var usage = `usage: %s [options] [FILE]
|
||||
Print or check multihash checksums.
|
||||
With no FILE, or when FILE is -, read standard input.
|
||||
|
||||
Options:
|
||||
`
|
||||
|
||||
// flags
|
||||
var encodings = []string{"raw", "hex", "base58", "base64"}
|
||||
var algorithms = []string{"sha1", "sha2-256", "sha2-512", "sha3"}
|
||||
var encoding string
|
||||
var algorithm string
|
||||
var algorithmCode int
|
||||
var length int
|
||||
var checkRaw string
|
||||
var checkMh mh.Multihash
|
||||
var inputFilename string
|
||||
var quiet bool
|
||||
|
||||
// joined names
|
||||
var algoStr string
|
||||
var encStr string
|
||||
|
||||
func init() {
|
||||
flag.Usage = func() {
|
||||
fmt.Fprintf(os.Stderr, usage, os.Args[0])
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
|
||||
algoStr = "one of: " + strings.Join(algorithms, ", ")
|
||||
flag.StringVar(&algorithm, "algorithm", "sha2-256", algoStr)
|
||||
flag.StringVar(&algorithm, "a", "sha2-256", algoStr+" (shorthand)")
|
||||
|
||||
encStr = "one of: " + strings.Join(encodings, ", ")
|
||||
flag.StringVar(&encoding, "encoding", "base58", encStr)
|
||||
flag.StringVar(&encoding, "e", "base58", encStr+" (shorthand)")
|
||||
|
||||
checkStr := "check checksum matches"
|
||||
flag.StringVar(&checkRaw, "check", "", checkStr)
|
||||
flag.StringVar(&checkRaw, "c", "", checkStr+" (shorthand)")
|
||||
|
||||
lengthStr := "checksums length in bits (truncate). -1 is default"
|
||||
flag.IntVar(&length, "length", -1, lengthStr)
|
||||
flag.IntVar(&length, "l", -1, lengthStr+" (shorthand)")
|
||||
|
||||
quietStr := "quiet output (no newline on checksum, no error text)"
|
||||
flag.BoolVar(&quiet, "quiet", false, quietStr)
|
||||
flag.BoolVar(&quiet, "q", false, quietStr+" (shorthand)")
|
||||
}
|
||||
|
||||
func strIn(a string, set []string) bool {
|
||||
for _, s := range set {
|
||||
if s == a {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func parseFlags() error {
|
||||
flag.Parse()
|
||||
|
||||
if !strIn(algorithm, algorithms) {
|
||||
return fmt.Errorf("algorithm '%s' not %s", algorithm, algoStr)
|
||||
}
|
||||
var found bool
|
||||
algorithmCode, found = mh.Names[algorithm]
|
||||
if !found {
|
||||
return fmt.Errorf("algorithm '%s' not found (lib error, pls report).")
|
||||
}
|
||||
|
||||
if !strIn(encoding, encodings) {
|
||||
return fmt.Errorf("encoding '%s' not %s", encoding, encStr)
|
||||
}
|
||||
|
||||
if checkRaw != "" {
|
||||
var err error
|
||||
checkMh, err = Decode(encoding, checkRaw)
|
||||
if err != nil {
|
||||
return fmt.Errorf("fail to decode check '%s': %s", checkRaw, err)
|
||||
}
|
||||
}
|
||||
|
||||
if length >= 0 {
|
||||
if length%8 != 0 {
|
||||
return fmt.Errorf("length must be multiple of 8")
|
||||
}
|
||||
length = length / 8
|
||||
|
||||
if length > mh.DefaultLengths[algorithmCode] {
|
||||
length = mh.DefaultLengths[algorithmCode]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getInput() (io.ReadCloser, error) {
|
||||
args := flag.Args()
|
||||
|
||||
switch {
|
||||
case len(args) < 1:
|
||||
inputFilename = "-"
|
||||
return os.Stdin, nil
|
||||
case args[0] == "-":
|
||||
inputFilename = "-"
|
||||
return os.Stdin, nil
|
||||
default:
|
||||
inputFilename = args[0]
|
||||
f, err := os.Open(args[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open '%s': %s", args[0], err)
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
}
|
||||
|
||||
func check(h1 mh.Multihash, r io.Reader) error {
|
||||
h2, err := hash(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !bytes.Equal(h1, h2) {
|
||||
if quiet {
|
||||
os.Exit(1)
|
||||
}
|
||||
return fmt.Errorf("computed checksum did not match (-q for no output)")
|
||||
}
|
||||
|
||||
if !quiet {
|
||||
fmt.Println("OK checksums match (-q for no output)")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func hash(r io.Reader) (mh.Multihash, error) {
|
||||
b, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mh.Sum(b, algorithmCode, length)
|
||||
}
|
||||
|
||||
func printHash(r io.Reader) error {
|
||||
h, err := hash(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s, err := Encode(encoding, h)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if quiet {
|
||||
fmt.Print(s)
|
||||
} else {
|
||||
fmt.Println(s)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
checkErr := func(err error) {
|
||||
if err != nil {
|
||||
die("error: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
err := parseFlags()
|
||||
checkErr(err)
|
||||
|
||||
inp, err := getInput()
|
||||
checkErr(err)
|
||||
|
||||
if checkMh != nil {
|
||||
err = check(checkMh, inp)
|
||||
checkErr(err)
|
||||
} else {
|
||||
err = printHash(inp)
|
||||
checkErr(err)
|
||||
}
|
||||
inp.Close()
|
||||
}
|
||||
|
||||
func die(v ...interface{}) {
|
||||
if !quiet {
|
||||
fmt.Fprint(os.Stderr, v...)
|
||||
fmt.Fprint(os.Stderr, "\n")
|
||||
}
|
||||
// flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
270
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash_test.go
generated
vendored
270
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash_test.go
generated
vendored
@ -1,270 +0,0 @@
|
||||
package multihash
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// maybe silly, but makes it so changing
|
||||
// the table accidentally has to happen twice.
|
||||
var tCodes = map[int]string{
|
||||
0x11: "sha1",
|
||||
0x12: "sha2-256",
|
||||
0x13: "sha2-512",
|
||||
0x14: "sha3",
|
||||
0x40: "blake2b",
|
||||
0x41: "blake2s",
|
||||
}
|
||||
|
||||
type TestCase struct {
|
||||
hex string
|
||||
code int
|
||||
name string
|
||||
}
|
||||
|
||||
var testCases = []TestCase{
|
||||
TestCase{"0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33", 0x11, "sha1"},
|
||||
TestCase{"0beec7b5", 0x11, "sha1"},
|
||||
TestCase{"2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae", 0x12, "sha2-256"},
|
||||
TestCase{"2c26b46b", 0x12, "sha2-256"},
|
||||
TestCase{"0beec7b5ea3f0fdbc9", 0x40, "blake2b"},
|
||||
}
|
||||
|
||||
func (tc TestCase) Multihash() (Multihash, error) {
|
||||
ob, err := hex.DecodeString(tc.hex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b := make([]byte, 2+len(ob))
|
||||
b[0] = byte(uint8(tc.code))
|
||||
b[1] = byte(uint8(len(ob)))
|
||||
copy(b[2:], ob)
|
||||
return Cast(b)
|
||||
}
|
||||
|
||||
func TestEncode(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
ob, err := hex.DecodeString(tc.hex)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
pre := make([]byte, 2)
|
||||
pre[0] = byte(uint8(tc.code))
|
||||
pre[1] = byte(uint8(len(ob)))
|
||||
nb := append(pre, ob...)
|
||||
|
||||
encC, err := Encode(ob, tc.code)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !bytes.Equal(encC, nb) {
|
||||
t.Error("encoded byte mismatch: ", encC, nb)
|
||||
}
|
||||
|
||||
encN, err := EncodeName(ob, tc.name)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !bytes.Equal(encN, nb) {
|
||||
t.Error("encoded byte mismatch: ", encN, nb)
|
||||
}
|
||||
|
||||
h, err := tc.Multihash()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !bytes.Equal(h, nb) {
|
||||
t.Error("Multihash func mismatch.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleEncodeName() {
|
||||
// ignores errors for simplicity - don't do that at home.
|
||||
buf, _ := hex.DecodeString("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33")
|
||||
mhbuf, _ := EncodeName(buf, "sha1")
|
||||
mhhex := hex.EncodeToString(mhbuf)
|
||||
fmt.Printf("hex: %v\n", mhhex)
|
||||
|
||||
// Output:
|
||||
// hex: 11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33
|
||||
}
|
||||
|
||||
func TestDecode(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
ob, err := hex.DecodeString(tc.hex)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
pre := make([]byte, 2)
|
||||
pre[0] = byte(uint8(tc.code))
|
||||
pre[1] = byte(uint8(len(ob)))
|
||||
nb := append(pre, ob...)
|
||||
|
||||
dec, err := Decode(nb)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
if dec.Code != tc.code {
|
||||
t.Error("decoded code mismatch: ", dec.Code, tc.code)
|
||||
}
|
||||
|
||||
if dec.Name != tc.name {
|
||||
t.Error("decoded name mismatch: ", dec.Name, tc.name)
|
||||
}
|
||||
|
||||
if dec.Length != len(ob) {
|
||||
t.Error("decoded length mismatch: ", dec.Length, len(ob))
|
||||
}
|
||||
|
||||
if !bytes.Equal(dec.Digest, ob) {
|
||||
t.Error("decoded byte mismatch: ", dec.Digest, ob)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTable(t *testing.T) {
|
||||
for k, v := range tCodes {
|
||||
if Codes[k] != v {
|
||||
t.Error("Table mismatch: ", Codes[k], v)
|
||||
}
|
||||
if Names[v] != k {
|
||||
t.Error("Table mismatch: ", Names[v], k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleDecode() {
|
||||
// ignores errors for simplicity - don't do that at home.
|
||||
buf, _ := hex.DecodeString("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33")
|
||||
mhbuf, _ := EncodeName(buf, "sha1")
|
||||
o, _ := Decode(mhbuf)
|
||||
mhhex := hex.EncodeToString(o.Digest)
|
||||
fmt.Printf("obj: %v 0x%x %d %s\n", o.Name, o.Code, o.Length, mhhex)
|
||||
|
||||
// Output:
|
||||
// obj: sha1 0x11 20 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33
|
||||
}
|
||||
|
||||
func TestValidCode(t *testing.T) {
|
||||
for i := 0; i < 0xff; i++ {
|
||||
_, ok := tCodes[i]
|
||||
b := AppCode(i) || ok
|
||||
|
||||
if ValidCode(i) != b {
|
||||
t.Error("ValidCode incorrect for: ", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppCode(t *testing.T) {
|
||||
for i := 0; i < 0xff; i++ {
|
||||
b := i >= 0 && i < 0x10
|
||||
if AppCode(i) != b {
|
||||
t.Error("AppCode incorrect for: ", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCast(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
ob, err := hex.DecodeString(tc.hex)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
pre := make([]byte, 2)
|
||||
pre[0] = byte(uint8(tc.code))
|
||||
pre[1] = byte(uint8(len(ob)))
|
||||
nb := append(pre, ob...)
|
||||
|
||||
if _, err := Cast(nb); err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
if _, err = Cast(ob); err == nil {
|
||||
t.Error("cast failed to detect non-multihash")
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHex(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
ob, err := hex.DecodeString(tc.hex)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
pre := make([]byte, 2)
|
||||
pre[0] = byte(uint8(tc.code))
|
||||
pre[1] = byte(uint8(len(ob)))
|
||||
nb := append(pre, ob...)
|
||||
|
||||
hs := hex.EncodeToString(nb)
|
||||
mh, err := FromHexString(hs)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !bytes.Equal(mh, nb) {
|
||||
t.Error("FromHexString failed", nb, mh)
|
||||
continue
|
||||
}
|
||||
|
||||
if mh.HexString() != hs {
|
||||
t.Error("Multihash.HexString failed", hs, mh.HexString)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncode(b *testing.B) {
|
||||
tc := testCases[0]
|
||||
ob, err := hex.DecodeString(tc.hex)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Encode(ob, tc.code)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDecode(b *testing.B) {
|
||||
tc := testCases[0]
|
||||
ob, err := hex.DecodeString(tc.hex)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
pre := make([]byte, 2)
|
||||
pre[0] = byte(uint8(tc.code))
|
||||
pre[1] = byte(uint8(len(ob)))
|
||||
nb := append(pre, ob...)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Decode(nb)
|
||||
}
|
||||
}
|
||||
72
Godeps/_workspace/src/github.com/jbenet/go-multihash/sum.go
generated
vendored
72
Godeps/_workspace/src/github.com/jbenet/go-multihash/sum.go
generated
vendored
@ -1,72 +0,0 @@
|
||||
package multihash
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
sha3 "github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
var ErrSumNotSupported = errors.New("Function not implemented. Complain to lib maintainer.")
|
||||
|
||||
func Sum(data []byte, code int, length int) (Multihash, error) {
|
||||
m := Multihash{}
|
||||
err := error(nil)
|
||||
if !ValidCode(code) {
|
||||
return m, fmt.Errorf("invalid multihash code %d", code)
|
||||
}
|
||||
|
||||
var d []byte
|
||||
switch code {
|
||||
case SHA1:
|
||||
d = sumSHA1(data)
|
||||
case SHA2_256:
|
||||
d = sumSHA256(data)
|
||||
case SHA2_512:
|
||||
d = sumSHA512(data)
|
||||
case SHA3:
|
||||
d, err = sumSHA3(data)
|
||||
default:
|
||||
return m, ErrSumNotSupported
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return m, err
|
||||
}
|
||||
|
||||
if length < 0 {
|
||||
var ok bool
|
||||
length, ok = DefaultLengths[code]
|
||||
if !ok {
|
||||
return m, fmt.Errorf("no default length for code %d", code)
|
||||
}
|
||||
}
|
||||
|
||||
return Encode(d[0:length], code)
|
||||
}
|
||||
|
||||
func sumSHA1(data []byte) []byte {
|
||||
a := sha1.Sum(data)
|
||||
return a[0:20]
|
||||
}
|
||||
|
||||
func sumSHA256(data []byte) []byte {
|
||||
a := sha256.Sum256(data)
|
||||
return a[0:32]
|
||||
}
|
||||
|
||||
func sumSHA512(data []byte) []byte {
|
||||
a := sha512.Sum512(data)
|
||||
return a[0:64]
|
||||
}
|
||||
|
||||
func sumSHA3(data []byte) ([]byte, error) {
|
||||
h := sha3.New512()
|
||||
if _, err := h.Write(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return h.Sum(nil), nil
|
||||
}
|
||||
66
Godeps/_workspace/src/github.com/jbenet/go-multihash/sum_test.go
generated
vendored
66
Godeps/_workspace/src/github.com/jbenet/go-multihash/sum_test.go
generated
vendored
@ -1,66 +0,0 @@
|
||||
package multihash
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type SumTestCase struct {
|
||||
code int
|
||||
length int
|
||||
input string
|
||||
hex string
|
||||
}
|
||||
|
||||
var sumTestCases = []SumTestCase{
|
||||
SumTestCase{SHA1, -1, "foo", "11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"},
|
||||
SumTestCase{SHA1, 10, "foo", "110a0beec7b5ea3f0fdbc95d"},
|
||||
SumTestCase{SHA2_256, -1, "foo", "12202c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"},
|
||||
SumTestCase{SHA2_256, 16, "foo", "12102c26b46b68ffc68ff99b453c1d304134"},
|
||||
SumTestCase{SHA2_512, -1, "foo", "1340f7fbba6e0636f890e56fbbf3283e524c6fa3204ae298382d624741d0dc6638326e282c41be5e4254d8820772c5518a2c5a8c0c7f7eda19594a7eb539453e1ed7"},
|
||||
SumTestCase{SHA2_512, 32, "foo", "1320f7fbba6e0636f890e56fbbf3283e524c6fa3204ae298382d624741d0dc663832"},
|
||||
}
|
||||
|
||||
func TestSum(t *testing.T) {
|
||||
|
||||
for _, tc := range sumTestCases {
|
||||
|
||||
m1, err := FromHexString(tc.hex)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
m2, err := Sum([]byte(tc.input), tc.code, tc.length)
|
||||
if err != nil {
|
||||
t.Error(tc.code, "sum failed.", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !bytes.Equal(m1, m2) {
|
||||
t.Error(tc.code, "sum failed.", m1, m2)
|
||||
}
|
||||
|
||||
s1 := m1.HexString()
|
||||
if s1 != tc.hex {
|
||||
t.Error("hex strings not the same")
|
||||
}
|
||||
|
||||
s2 := m1.B58String()
|
||||
m3, err := FromB58String(s2)
|
||||
if err != nil {
|
||||
t.Error("failed to decode b58")
|
||||
} else if !bytes.Equal(m3, m1) {
|
||||
t.Error("b58 failing bytes")
|
||||
} else if s2 != m3.B58String() {
|
||||
t.Error("b58 failing string")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSum(b *testing.B) {
|
||||
tc := sumTestCases[0]
|
||||
for i := 0; i < b.N; i++ {
|
||||
Sum([]byte(tc.input), tc.code, tc.length)
|
||||
}
|
||||
}
|
||||
1
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/.gitignore
generated
vendored
1
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/.gitignore
generated
vendored
@ -1 +0,0 @@
|
||||
bin/multihash
|
||||
25
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/Makefile
generated
vendored
25
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/Makefile
generated
vendored
@ -1,25 +0,0 @@
|
||||
BINS = bin/multihash
|
||||
MULTIHASH_ROOT = ../
|
||||
MULTIHASH_CMD = ../multihash
|
||||
|
||||
all: deps
|
||||
|
||||
deps: bins
|
||||
|
||||
clean:
|
||||
rm $(BINS)
|
||||
|
||||
bins: $(BINS)
|
||||
|
||||
bin/multihash: $(MULTIHASH_ROOT)/**/*.go
|
||||
go build -o bin/multihash $(MULTIHASH_CMD)
|
||||
|
||||
test: test_expensive
|
||||
|
||||
test_expensive:
|
||||
cd sharness && make TEST_EXPENSIVE=1
|
||||
|
||||
test_cheap:
|
||||
cd sharness && make
|
||||
|
||||
.PHONY: all clean
|
||||
3
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/sharness/.gitignore
generated
vendored
3
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/sharness/.gitignore
generated
vendored
@ -1,3 +0,0 @@
|
||||
lib/sharness/
|
||||
test-results/
|
||||
trash directory.*.sh/
|
||||
37
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/sharness/Makefile
generated
vendored
37
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/sharness/Makefile
generated
vendored
@ -1,37 +0,0 @@
|
||||
# Run tests
|
||||
#
|
||||
# Copyright (c) 2014 Christian Couder
|
||||
# MIT Licensed; see the LICENSE file in this repository.
|
||||
#
|
||||
|
||||
# NOTE: run with TEST_VERBOSE=1 for verbose sharness tests.
|
||||
|
||||
T = $(sort $(wildcard t[0-9][0-9][0-9][0-9]-*.sh))
|
||||
BINS = bin/multihash
|
||||
SHARNESS = lib/sharness/sharness.sh
|
||||
|
||||
all: clean deps $(T) aggregate
|
||||
|
||||
clean:
|
||||
@echo "*** $@ ***"
|
||||
-rm -rf test-results
|
||||
|
||||
$(T):
|
||||
@echo "*** $@ ***"
|
||||
./$@
|
||||
|
||||
aggregate:
|
||||
@echo "*** $@ ***"
|
||||
lib/test-aggregate-results.sh
|
||||
|
||||
deps: $(SHARNESS) $(BINS)
|
||||
|
||||
$(SHARNESS):
|
||||
@echo "*** installing $@ ***"
|
||||
lib/install-sharness.sh
|
||||
|
||||
bin/%:
|
||||
@echo "*** installing $@ ***"
|
||||
cd .. && make $@
|
||||
|
||||
.PHONY: all clean $(T) aggregate
|
||||
1
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/sharness/bin
generated
vendored
1
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/sharness/bin
generated
vendored
@ -1 +0,0 @@
|
||||
../bin
|
||||
@ -1,26 +0,0 @@
|
||||
#!/bin/sh
|
||||
# install sharness.sh
|
||||
#
|
||||
# Copyright (c) 2014 Juan Batiz-Benet
|
||||
# MIT Licensed; see the LICENSE file in this repository.
|
||||
#
|
||||
|
||||
# settings
|
||||
version=50229a79ba22b2f13ccd82451d86570fecbd194c
|
||||
urlprefix=https://github.com/mlafeldt/sharness.git
|
||||
clonedir=lib
|
||||
sharnessdir=sharness
|
||||
|
||||
die() {
|
||||
echo >&2 "$@"
|
||||
exit 1
|
||||
}
|
||||
|
||||
mkdir -p "$clonedir" || die "Could not create '$clonedir' directory"
|
||||
cd "$clonedir" || die "Could not cd into '$clonedir' directory"
|
||||
|
||||
git clone "$urlprefix" || die "Could not clone '$urlprefix'"
|
||||
cd "$sharnessdir" || die "Could not cd into '$sharnessdir' directory"
|
||||
git checkout "$version" || die "Could not checkout '$version'"
|
||||
|
||||
exit 0
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user